@within-7/minto 0.4.0 → 0.4.2

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 (391) hide show
  1. package/dist/Tool.js +7 -0
  2. package/dist/Tool.js.map +2 -2
  3. package/dist/commands/agents/AgentsCommand.js +1 -1
  4. package/dist/commands/agents/AgentsCommand.js.map +2 -2
  5. package/dist/commands/agents/constants.js +2 -2
  6. package/dist/commands/agents/constants.js.map +2 -2
  7. package/dist/commands/clear.js +4 -3
  8. package/dist/commands/clear.js.map +2 -2
  9. package/dist/commands/compact.js +2 -2
  10. package/dist/commands/compact.js.map +1 -1
  11. package/dist/commands/context.js +3 -1
  12. package/dist/commands/context.js.map +2 -2
  13. package/dist/commands/login.js +128 -0
  14. package/dist/commands/login.js.map +7 -0
  15. package/dist/commands/memory.js +33 -82
  16. package/dist/commands/memory.js.map +2 -2
  17. package/dist/commands/quit.js +3 -1
  18. package/dist/commands/quit.js.map +2 -2
  19. package/dist/commands/resume.js +39 -239
  20. package/dist/commands/resume.js.map +2 -2
  21. package/dist/commands/tasks.js +1 -1
  22. package/dist/commands/tasks.js.map +2 -2
  23. package/dist/commands/terminalSetup.js +6 -2
  24. package/dist/commands/terminalSetup.js.map +2 -2
  25. package/dist/commands.js +2 -0
  26. package/dist/commands.js.map +2 -2
  27. package/dist/components/AgentDetailView.js +126 -0
  28. package/dist/components/AgentDetailView.js.map +7 -0
  29. package/dist/components/AgentThinkingBlock.js +1 -1
  30. package/dist/components/AgentThinkingBlock.js.map +2 -2
  31. package/dist/components/AgentViewBanner.js +22 -0
  32. package/dist/components/AgentViewBanner.js.map +7 -0
  33. package/dist/components/HeaderBar.js +1 -1
  34. package/dist/components/HeaderBar.js.map +2 -2
  35. package/dist/components/Help.js +8 -1
  36. package/dist/components/Help.js.map +2 -2
  37. package/dist/components/HotkeyHelpPanel.js +26 -8
  38. package/dist/components/HotkeyHelpPanel.js.map +2 -2
  39. package/dist/components/IdleNotificationBar.js +10 -0
  40. package/dist/components/IdleNotificationBar.js.map +7 -0
  41. package/dist/components/ModelSelector/ModelSelector.js +55 -20
  42. package/dist/components/ModelSelector/ModelSelector.js.map +2 -2
  43. package/dist/components/PromptInput.js +186 -115
  44. package/dist/components/PromptInput.js.map +2 -2
  45. package/dist/components/RewindPanel.js +272 -0
  46. package/dist/components/RewindPanel.js.map +7 -0
  47. package/dist/components/Spinner.js +10 -21
  48. package/dist/components/Spinner.js.map +2 -2
  49. package/dist/components/StreamingTextPreview.js +29 -0
  50. package/dist/components/StreamingTextPreview.js.map +7 -0
  51. package/dist/components/SubagentBlock.js +3 -2
  52. package/dist/components/SubagentBlock.js.map +2 -2
  53. package/dist/components/SubagentProgress.js +4 -4
  54. package/dist/components/SubagentProgress.js.map +2 -2
  55. package/dist/components/TabbedListView/SearchInput.js +1 -1
  56. package/dist/components/TabbedListView/SearchInput.js.map +2 -2
  57. package/dist/components/TabbedListView/TabbedListView.js +87 -41
  58. package/dist/components/TabbedListView/TabbedListView.js.map +2 -2
  59. package/dist/components/TaskCard.js +4 -4
  60. package/dist/components/TaskCard.js.map +2 -2
  61. package/dist/components/TeamMemberPanel.js +107 -0
  62. package/dist/components/TeamMemberPanel.js.map +7 -0
  63. package/dist/components/ThinkingSelector.js +84 -0
  64. package/dist/components/ThinkingSelector.js.map +7 -0
  65. package/dist/components/TitledDivider.js +26 -0
  66. package/dist/components/TitledDivider.js.map +7 -0
  67. package/dist/components/TodoPanel.js +31 -30
  68. package/dist/components/TodoPanel.js.map +2 -2
  69. package/dist/components/TokenWarning.js +28 -7
  70. package/dist/components/TokenWarning.js.map +2 -2
  71. package/dist/components/messages/AssistantTextMessage.js +5 -2
  72. package/dist/components/messages/AssistantTextMessage.js.map +2 -2
  73. package/dist/components/messages/AssistantToolUseMessage.js +9 -1
  74. package/dist/components/messages/AssistantToolUseMessage.js.map +2 -2
  75. package/dist/components/messages/DefaultToolResultFallback.js +11 -0
  76. package/dist/components/messages/DefaultToolResultFallback.js.map +7 -0
  77. package/dist/components/messages/ParallelTasksGroupView.js +14 -6
  78. package/dist/components/messages/ParallelTasksGroupView.js.map +2 -2
  79. package/dist/components/messages/TaskInModuleView.js +27 -27
  80. package/dist/components/messages/TaskInModuleView.js.map +2 -2
  81. package/dist/components/messages/UserGuidanceMessage.js +26 -0
  82. package/dist/components/messages/UserGuidanceMessage.js.map +7 -0
  83. package/dist/components/messages/UserPromptMessage.js +2 -1
  84. package/dist/components/messages/UserPromptMessage.js.map +2 -2
  85. package/dist/components/messages/UserTeamNotificationMessage.js +91 -0
  86. package/dist/components/messages/UserTeamNotificationMessage.js.map +7 -0
  87. package/dist/components/messages/UserTextMessage.js +8 -0
  88. package/dist/components/messages/UserTextMessage.js.map +2 -2
  89. package/dist/components/messages/UserToolResultMessage/UserToolRejectMessage.js +4 -2
  90. package/dist/components/messages/UserToolResultMessage/UserToolRejectMessage.js.map +2 -2
  91. package/dist/components/messages/UserToolResultMessage/UserToolResultMessage.js +18 -1
  92. package/dist/components/messages/UserToolResultMessage/UserToolResultMessage.js.map +2 -2
  93. package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js +12 -1
  94. package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js.map +2 -2
  95. package/dist/components/permissions/PermissionRequest.js +4 -0
  96. package/dist/components/permissions/PermissionRequest.js.map +2 -2
  97. package/dist/components/permissions/PlanApprovalRequest.js +164 -0
  98. package/dist/components/permissions/PlanApprovalRequest.js.map +7 -0
  99. package/dist/constants/agentTeams.js +17 -0
  100. package/dist/constants/agentTeams.js.map +7 -0
  101. package/dist/constants/macros.js +2 -1
  102. package/dist/constants/macros.js.map +2 -2
  103. package/dist/constants/prompts/agentPrompt.js +1 -0
  104. package/dist/constants/prompts/agentPrompt.js.map +2 -2
  105. package/dist/constants/prompts/autoMemory.js +39 -0
  106. package/dist/constants/prompts/autoMemory.js.map +7 -0
  107. package/dist/constants/prompts/codeConventions.js +1 -13
  108. package/dist/constants/prompts/codeConventions.js.map +2 -2
  109. package/dist/constants/prompts/doingTasks.js +21 -2
  110. package/dist/constants/prompts/doingTasks.js.map +2 -2
  111. package/dist/constants/prompts/envInfo.js +6 -7
  112. package/dist/constants/prompts/envInfo.js.map +2 -2
  113. package/dist/constants/prompts/index.js +27 -5
  114. package/dist/constants/prompts/index.js.map +2 -2
  115. package/dist/constants/prompts/taskManagement.js +2 -43
  116. package/dist/constants/prompts/taskManagement.js.map +2 -2
  117. package/dist/constants/prompts/teamOverlays.js +50 -0
  118. package/dist/constants/prompts/teamOverlays.js.map +7 -0
  119. package/dist/constants/prompts/toneAndStyle.js +4 -29
  120. package/dist/constants/prompts/toneAndStyle.js.map +2 -2
  121. package/dist/constants/prompts/toolUsagePolicy.js +7 -22
  122. package/dist/constants/prompts/toolUsagePolicy.js.map +2 -2
  123. package/dist/constants/toolInputExamples.js +2 -2
  124. package/dist/constants/toolInputExamples.js.map +2 -2
  125. package/dist/context.js +39 -6
  126. package/dist/context.js.map +2 -2
  127. package/dist/core/backupManager.js +1 -1
  128. package/dist/core/backupManager.js.map +2 -2
  129. package/dist/core/permissions/rules/planModeRule.js +1 -1
  130. package/dist/core/permissions/rules/planModeRule.js.map +1 -1
  131. package/dist/core/permissions/rules/safeModeRule.js +1 -1
  132. package/dist/core/permissions/rules/safeModeRule.js.map +1 -1
  133. package/dist/engine/AgentEngine.js +902 -0
  134. package/dist/engine/AgentEngine.js.map +7 -0
  135. package/dist/engine/EngineRegistry.js +89 -0
  136. package/dist/engine/EngineRegistry.js.map +7 -0
  137. package/dist/engine/foregroundAdapter.js +191 -0
  138. package/dist/engine/foregroundAdapter.js.map +7 -0
  139. package/dist/engine/index.js +15 -0
  140. package/dist/engine/index.js.map +7 -0
  141. package/dist/engine/types.js +1 -0
  142. package/dist/engine/types.js.map +7 -0
  143. package/dist/entrypoints/cli.js +410 -79
  144. package/dist/entrypoints/cli.js.map +3 -3
  145. package/dist/hooks/useAgentEngine.js +129 -0
  146. package/dist/hooks/useAgentEngine.js.map +7 -0
  147. package/dist/hooks/useAgentTokenStats.js +0 -16
  148. package/dist/hooks/useAgentTokenStats.js.map +2 -2
  149. package/dist/hooks/useCanUseTool.js +47 -2
  150. package/dist/hooks/useCanUseTool.js.map +2 -2
  151. package/dist/hooks/useDeferredLoading.js +4 -1
  152. package/dist/hooks/useDeferredLoading.js.map +2 -2
  153. package/dist/hooks/useIdleNotifications.js +66 -0
  154. package/dist/hooks/useIdleNotifications.js.map +7 -0
  155. package/dist/hooks/useSessionTracking.js +9 -7
  156. package/dist/hooks/useSessionTracking.js.map +2 -2
  157. package/dist/hooks/useTeamMembers.js +51 -0
  158. package/dist/hooks/useTeamMembers.js.map +7 -0
  159. package/dist/i18n/locales/en.js +77 -12
  160. package/dist/i18n/locales/en.js.map +2 -2
  161. package/dist/i18n/locales/zh-CN.js +77 -12
  162. package/dist/i18n/locales/zh-CN.js.map +2 -2
  163. package/dist/i18n/types.js.map +1 -1
  164. package/dist/messages.js.map +2 -2
  165. package/dist/permissions.js +113 -7
  166. package/dist/permissions.js.map +2 -2
  167. package/dist/query.js +135 -37
  168. package/dist/query.js.map +2 -2
  169. package/dist/screens/REPL.js +504 -361
  170. package/dist/screens/REPL.js.map +3 -3
  171. package/dist/screens/ResumeConversation.js +199 -14
  172. package/dist/screens/ResumeConversation.js.map +2 -2
  173. package/dist/services/adapters/base.js.map +1 -1
  174. package/dist/services/agentTeams/backends/headless.js +108 -0
  175. package/dist/services/agentTeams/backends/headless.js.map +7 -0
  176. package/dist/services/agentTeams/backends/inProcess.js +102 -0
  177. package/dist/services/agentTeams/backends/inProcess.js.map +7 -0
  178. package/dist/services/agentTeams/backends/resolver.js +18 -0
  179. package/dist/services/agentTeams/backends/resolver.js.map +7 -0
  180. package/dist/services/agentTeams/backends/tmux.js +168 -0
  181. package/dist/services/agentTeams/backends/tmux.js.map +7 -0
  182. package/dist/services/agentTeams/backends/types.js +1 -0
  183. package/dist/services/agentTeams/backends/types.js.map +7 -0
  184. package/dist/services/agentTeams/heartbeat.js +88 -0
  185. package/dist/services/agentTeams/heartbeat.js.map +7 -0
  186. package/dist/services/agentTeams/index.js +42 -2
  187. package/dist/services/agentTeams/index.js.map +2 -2
  188. package/dist/services/agentTeams/injectionChannel.js +105 -0
  189. package/dist/services/agentTeams/injectionChannel.js.map +7 -0
  190. package/dist/services/agentTeams/mailbox.js +410 -30
  191. package/dist/services/agentTeams/mailbox.js.map +2 -2
  192. package/dist/services/agentTeams/messageFormatter.js +80 -0
  193. package/dist/services/agentTeams/messageFormatter.js.map +7 -0
  194. package/dist/services/agentTeams/permissionDelegation.js +71 -0
  195. package/dist/services/agentTeams/permissionDelegation.js.map +7 -0
  196. package/dist/services/agentTeams/teamEvents.js +45 -0
  197. package/dist/services/agentTeams/teamEvents.js.map +7 -0
  198. package/dist/services/agentTeams/teamManager.js +251 -34
  199. package/dist/services/agentTeams/teamManager.js.map +2 -2
  200. package/dist/services/agentTeams/teamTaskStore.js +290 -61
  201. package/dist/services/agentTeams/teamTaskStore.js.map +2 -2
  202. package/dist/services/agentTeams/teammateSpawner.js +99 -18
  203. package/dist/services/agentTeams/teammateSpawner.js.map +2 -2
  204. package/dist/services/hookExecutor.js +51 -8
  205. package/dist/services/hookExecutor.js.map +2 -2
  206. package/dist/services/llm/anthropicProvider.js +56 -59
  207. package/dist/services/llm/anthropicProvider.js.map +2 -2
  208. package/dist/services/llm/dispatch.js +24 -5
  209. package/dist/services/llm/dispatch.js.map +2 -2
  210. package/dist/services/llm/openaiProvider.js +115 -136
  211. package/dist/services/llm/openaiProvider.js.map +3 -3
  212. package/dist/services/llm/types.js +89 -15
  213. package/dist/services/llm/types.js.map +2 -2
  214. package/dist/services/mcpClient.js +80 -4
  215. package/dist/services/mcpClient.js.map +2 -2
  216. package/dist/services/mintoAuth.js +299 -0
  217. package/dist/services/mintoAuth.js.map +7 -0
  218. package/dist/services/oauth.js +3 -3
  219. package/dist/services/oauth.js.map +2 -2
  220. package/dist/services/openai.js +91 -20
  221. package/dist/services/openai.js.map +2 -2
  222. package/dist/services/plugins/pluginRuntime.js +11 -5
  223. package/dist/services/plugins/pluginRuntime.js.map +2 -2
  224. package/dist/services/plugins/pluginValidation.js +4 -2
  225. package/dist/services/plugins/pluginValidation.js.map +2 -2
  226. package/dist/services/sandbox/sandboxController.js +11 -3
  227. package/dist/services/sandbox/sandboxController.js.map +2 -2
  228. package/dist/services/sessionMemoryInjector.js +77 -0
  229. package/dist/services/sessionMemoryInjector.js.map +7 -0
  230. package/dist/services/systemReminder.js +130 -8
  231. package/dist/services/systemReminder.js.map +2 -2
  232. package/dist/services/taskStore.js +199 -8
  233. package/dist/services/taskStore.js.map +3 -3
  234. package/dist/services/topicDetector.js +169 -0
  235. package/dist/services/topicDetector.js.map +7 -0
  236. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js +0 -13
  237. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js.map +2 -2
  238. package/dist/tools/BashTool/BashTool.js +51 -28
  239. package/dist/tools/BashTool/BashTool.js.map +2 -2
  240. package/dist/tools/BashTool/prompt.js +95 -118
  241. package/dist/tools/BashTool/prompt.js.map +2 -2
  242. package/dist/tools/BashTool/utils.js +39 -1
  243. package/dist/tools/BashTool/utils.js.map +2 -2
  244. package/dist/tools/EnterWorktreeTool/EnterWorktreeTool.js +121 -0
  245. package/dist/tools/EnterWorktreeTool/EnterWorktreeTool.js.map +7 -0
  246. package/dist/tools/EnterWorktreeTool/prompt.js +22 -0
  247. package/dist/tools/EnterWorktreeTool/prompt.js.map +7 -0
  248. package/dist/tools/FileEditTool/FileEditTool.js +9 -4
  249. package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
  250. package/dist/tools/FileEditTool/prompt.js +3 -7
  251. package/dist/tools/FileEditTool/prompt.js.map +2 -2
  252. package/dist/tools/FileReadTool/FileReadTool.js +125 -3
  253. package/dist/tools/FileReadTool/FileReadTool.js.map +2 -2
  254. package/dist/tools/FileReadTool/prompt.js +1 -2
  255. package/dist/tools/FileReadTool/prompt.js.map +2 -2
  256. package/dist/tools/FileWriteTool/prompt.js +3 -5
  257. package/dist/tools/FileWriteTool/prompt.js.map +2 -2
  258. package/dist/tools/GlobTool/GlobTool.js +3 -2
  259. package/dist/tools/GlobTool/GlobTool.js.map +2 -2
  260. package/dist/tools/GrepTool/GrepTool.js +16 -5
  261. package/dist/tools/GrepTool/GrepTool.js.map +2 -2
  262. package/dist/tools/ListMcpResourcesTool/ListMcpResourcesTool.js.map +2 -2
  263. package/dist/tools/MCPSearchTool/MCPSearchTool.js +172 -0
  264. package/dist/tools/MCPSearchTool/MCPSearchTool.js.map +7 -0
  265. package/dist/tools/MCPSearchTool/prompt.js +77 -0
  266. package/dist/tools/MCPSearchTool/prompt.js.map +7 -0
  267. package/dist/tools/MultiEditTool/prompt.js +4 -7
  268. package/dist/tools/MultiEditTool/prompt.js.map +2 -2
  269. package/dist/tools/PlanModeTool/EnterPlanModeTool.js +12 -8
  270. package/dist/tools/PlanModeTool/EnterPlanModeTool.js.map +2 -2
  271. package/dist/tools/PlanModeTool/ExitPlanModeTool.js +54 -1
  272. package/dist/tools/PlanModeTool/ExitPlanModeTool.js.map +2 -2
  273. package/dist/tools/PlanModeTool/prompt.js +23 -74
  274. package/dist/tools/PlanModeTool/prompt.js.map +2 -2
  275. package/dist/tools/SendMessageTool/SendMessageTool.js +341 -0
  276. package/dist/tools/SendMessageTool/SendMessageTool.js.map +7 -0
  277. package/dist/tools/SendMessageTool/prompt.js +44 -0
  278. package/dist/tools/SendMessageTool/prompt.js.map +7 -0
  279. package/dist/tools/TaskCreateTool/prompt.js +15 -4
  280. package/dist/tools/TaskCreateTool/prompt.js.map +2 -2
  281. package/dist/tools/TaskListTool/prompt.js +18 -3
  282. package/dist/tools/TaskListTool/prompt.js.map +2 -2
  283. package/dist/tools/TaskOutputTool/prompt.js +4 -3
  284. package/dist/tools/TaskOutputTool/prompt.js.map +2 -2
  285. package/dist/tools/TaskTool/TaskTool.js +762 -98
  286. package/dist/tools/TaskTool/TaskTool.js.map +3 -3
  287. package/dist/tools/TaskTool/constants.js +8 -2
  288. package/dist/tools/TaskTool/constants.js.map +2 -2
  289. package/dist/tools/TaskTool/prompt.js +74 -70
  290. package/dist/tools/TaskTool/prompt.js.map +2 -2
  291. package/dist/tools/TaskUpdateTool/TaskUpdateTool.js +15 -1
  292. package/dist/tools/TaskUpdateTool/TaskUpdateTool.js.map +2 -2
  293. package/dist/tools/TeamCreateTool/TeamCreateTool.js +129 -0
  294. package/dist/tools/TeamCreateTool/TeamCreateTool.js.map +7 -0
  295. package/dist/tools/TeamCreateTool/prompt.js +58 -0
  296. package/dist/tools/TeamCreateTool/prompt.js.map +7 -0
  297. package/dist/tools/TeamDeleteTool/TeamDeleteTool.js +151 -0
  298. package/dist/tools/TeamDeleteTool/TeamDeleteTool.js.map +7 -0
  299. package/dist/tools/TeamDeleteTool/prompt.js +16 -0
  300. package/dist/tools/TeamDeleteTool/prompt.js.map +7 -0
  301. package/dist/tools/URLFetcherTool/URLFetcherTool.js +106 -15
  302. package/dist/tools/URLFetcherTool/URLFetcherTool.js.map +2 -2
  303. package/dist/tools/URLFetcherTool/prompt.js +3 -2
  304. package/dist/tools/URLFetcherTool/prompt.js.map +2 -2
  305. package/dist/tools/WebSearchTool/WebSearchTool.js +2 -1
  306. package/dist/tools/WebSearchTool/WebSearchTool.js.map +2 -2
  307. package/dist/tools/WebSearchTool/prompt.js +5 -4
  308. package/dist/tools/WebSearchTool/prompt.js.map +2 -2
  309. package/dist/tools.js +100 -20
  310. package/dist/tools.js.map +2 -2
  311. package/dist/types/PermissionMode.js +35 -6
  312. package/dist/types/PermissionMode.js.map +2 -2
  313. package/dist/types/hooks.js +2 -0
  314. package/dist/types/hooks.js.map +2 -2
  315. package/dist/types/plugin.js +2 -0
  316. package/dist/types/plugin.js.map +3 -3
  317. package/dist/utils/CircuitBreaker.js +15 -9
  318. package/dist/utils/CircuitBreaker.js.map +2 -2
  319. package/dist/utils/agentLoader.js +249 -112
  320. package/dist/utils/agentLoader.js.map +2 -2
  321. package/dist/utils/animationManager.js +40 -3
  322. package/dist/utils/animationManager.js.map +2 -2
  323. package/dist/utils/ask.js +7 -6
  324. package/dist/utils/ask.js.map +2 -2
  325. package/dist/utils/atomicWrite.js +23 -0
  326. package/dist/utils/atomicWrite.js.map +7 -0
  327. package/dist/utils/autoCompactCore.js +73 -56
  328. package/dist/utils/autoCompactCore.js.map +2 -2
  329. package/dist/utils/autoMemoryPaths.js +89 -0
  330. package/dist/utils/autoMemoryPaths.js.map +7 -0
  331. package/dist/utils/config.js +63 -38
  332. package/dist/utils/config.js.map +2 -2
  333. package/dist/utils/configSchema.js +13 -8
  334. package/dist/utils/configSchema.js.map +2 -2
  335. package/dist/utils/credentials/index.js +14 -0
  336. package/dist/utils/credentials/index.js.map +2 -2
  337. package/dist/utils/dualPath.js +24 -0
  338. package/dist/utils/dualPath.js.map +7 -0
  339. package/dist/utils/exit.js +66 -7
  340. package/dist/utils/exit.js.map +2 -2
  341. package/dist/utils/externalEditor.js +155 -0
  342. package/dist/utils/externalEditor.js.map +7 -0
  343. package/dist/utils/fileLock.js +67 -0
  344. package/dist/utils/fileLock.js.map +7 -0
  345. package/dist/utils/format.js +24 -14
  346. package/dist/utils/format.js.map +2 -2
  347. package/dist/utils/globalErrorHandler.js +5 -96
  348. package/dist/utils/globalErrorHandler.js.map +3 -3
  349. package/dist/utils/groupHandlers/parallelTasksHandler.js +5 -3
  350. package/dist/utils/groupHandlers/parallelTasksHandler.js.map +2 -2
  351. package/dist/utils/groupHandlers/taskHandler.js +2 -2
  352. package/dist/utils/groupHandlers/taskHandler.js.map +2 -2
  353. package/dist/utils/hookManager.js +64 -6
  354. package/dist/utils/hookManager.js.map +2 -2
  355. package/dist/utils/log.js +6 -2
  356. package/dist/utils/log.js.map +2 -2
  357. package/dist/utils/markdown.js +237 -19
  358. package/dist/utils/markdown.js.map +2 -2
  359. package/dist/utils/messageContextManager.js +18 -5
  360. package/dist/utils/messageContextManager.js.map +2 -2
  361. package/dist/utils/messageGroupManager.js +1 -1
  362. package/dist/utils/messageGroupManager.js.map +2 -2
  363. package/dist/utils/messages.js +104 -46
  364. package/dist/utils/messages.js.map +2 -2
  365. package/dist/utils/model.js +2 -2
  366. package/dist/utils/model.js.map +2 -2
  367. package/dist/utils/pasteCache.js +8 -4
  368. package/dist/utils/pasteCache.js.map +2 -2
  369. package/dist/utils/pluginLoader.js +18 -0
  370. package/dist/utils/pluginLoader.js.map +2 -2
  371. package/dist/utils/secureKeyStorage.js +36 -7
  372. package/dist/utils/secureKeyStorage.js.map +2 -2
  373. package/dist/utils/simpleMode.js +7 -0
  374. package/dist/utils/simpleMode.js.map +7 -0
  375. package/dist/utils/streamingState.js +11 -1
  376. package/dist/utils/streamingState.js.map +2 -2
  377. package/dist/utils/taskDisplayUtils.js +2 -1
  378. package/dist/utils/taskDisplayUtils.js.map +2 -2
  379. package/dist/utils/teamConfig.js +2 -2
  380. package/dist/utils/teamConfig.js.map +2 -2
  381. package/dist/utils/thinking.js +6 -2
  382. package/dist/utils/thinking.js.map +3 -3
  383. package/dist/utils/tokenProgress.js +55 -0
  384. package/dist/utils/tokenProgress.js.map +7 -0
  385. package/dist/utils/toolRiskClassification.js +26 -17
  386. package/dist/utils/toolRiskClassification.js.map +2 -2
  387. package/dist/utils/tooling/toolError.js +12 -0
  388. package/dist/utils/tooling/toolError.js.map +7 -0
  389. package/dist/version.js +2 -2
  390. package/dist/version.js.map +1 -1
  391. package/package.json +10 -8
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/TodoPanel.tsx"],
4
- "sourcesContent": ["import React, { useRef, useMemo, memo } from 'react'\nimport { Box, Text } from 'ink'\nimport { getTheme } from '@utils/theme'\nimport { SYMBOLS, getTodoStatusSymbol } from '@constants/symbols'\nimport { formatNumber, formatTokenUsage } from '@utils/format'\nimport type { TodoItem as TodoItemType } from '@utils/todoStorage'\nimport { sample } from 'lodash-es'\nimport { getMainStreamingState } from '@utils/streamingState'\nimport { getSessionState } from '@utils/sessionState'\nimport { useUnifiedAnimation } from '@utils/animationManager'\nimport {\n SEMANTIC_COLORS,\n BRAND_GRADIENT,\n SYMBOL_COLORS,\n} from '@constants/colors'\nimport { getIndent } from '@constants/formatRules'\nimport { t } from '@i18n'\n\n/**\n * Isolated Spinner component to prevent animation updates from re-rendering the entire panel\n * This component handles all animation state internally\n */\ninterface SpinnerLineProps {\n currentTaskActiveForm?: string\n todos: TodoItemType[]\n shouldShowTodos: boolean\n fallbackMessage: string\n}\n\n/**\n * Shimmer effect colors - creates a light sweep animation across text\n * Uses brand gradient colors cycling through: purple-blue \u2192 pink-purple \u2192 coral \u2192 pink-purple \u2192 purple-blue\n */\nconst SHIMMER_COLORS = [\n BRAND_GRADIENT.START, // #667EEA purple-blue\n '#8673D9', // blend\n BRAND_GRADIENT.MIDDLE, // #B668C8 pink-purple\n '#D560A0', // blend\n BRAND_GRADIENT.END, // #F5576C coral\n '#D560A0', // blend back\n BRAND_GRADIENT.MIDDLE, // #B668C8\n '#8673D9', // blend back\n] as const\n\n/**\n * Get shimmer color based on animation frame\n * Creates a smooth color transition effect\n */\nfunction getShimmerColor(frame: number): string {\n return SHIMMER_COLORS[frame % SHIMMER_COLORS.length]!\n}\n\nconst SpinnerLine = memo(function SpinnerLine({\n currentTaskActiveForm,\n todos,\n shouldShowTodos,\n fallbackMessage,\n}: SpinnerLineProps) {\n const theme = getTheme()\n const startTimeRef = useRef(Date.now())\n\n // Animation state is isolated in this component\n // Use 8 frames for shimmer effect (matching SHIMMER_COLORS length)\n const { spinnerFrame, elapsedTime } = useUnifiedAnimation({\n enabled: true,\n startTime: startTimeRef.current,\n spinnerFrameCount: SHIMMER_COLORS.length,\n componentId: 'todo-panel-spinner',\n })\n\n // Get streaming state - only updates when this component re-renders\n // Use main streaming state to avoid subagent interference\n const streamState = useMemo(() => getMainStreamingState(), [spinnerFrame])\n\n // Get current task display\n const getCurrentTaskDisplay = (): string => {\n if (currentTaskActiveForm) {\n return currentTaskActiveForm\n }\n const inProgressTodo = todos.find(t => t.status === 'in_progress')\n if (inProgressTodo?.activeForm) {\n return inProgressTodo.activeForm\n }\n switch (streamState.phase) {\n case 'tool_use':\n return streamState.toolName\n ? `Using ${streamState.toolName}`\n : 'Executing tool'\n case 'generating':\n return 'Generating response'\n case 'waiting':\n return 'Waiting for response'\n case 'thinking':\n default:\n return fallbackMessage || 'Thinking'\n }\n }\n\n // Format time display\n const formatTime = (seconds: number): string => {\n if (seconds < 60) return `${seconds}s`\n const mins = Math.floor(seconds / 60)\n const secs = seconds % 60\n return secs > 0 ? `${mins}m ${secs}s` : `${mins}m`\n }\n\n // Get shimmer color for the main text (light sweep effect)\n const shimmerColor = getShimmerColor(spinnerFrame)\n\n // Spinner icon uses thinking frames\n const spinnerIconFrame = spinnerFrame % SYMBOLS.THINKING_FRAMES.length\n\n // Get token usage from streaming state (API values or approximate from chars)\n const getTokenDisplay = () => {\n // Prefer API-provided token counts - always show bidirectional if available\n if (streamState.inputTokens || streamState.outputTokens) {\n return formatTokenUsage(streamState.inputTokens, streamState.outputTokens)\n }\n // Fallback: approximate from received characters (~3 chars per token for mixed content)\n // Only show output approximation since we don't have input char count in this path\n if (streamState.receivedChars && streamState.receivedChars > 0) {\n const approxOutputTokens = Math.round(streamState.receivedChars / 3)\n // If we have sentChars, show both directions\n if (streamState.sentChars && streamState.sentChars > 0) {\n const approxInputTokens = Math.round(streamState.sentChars / 3)\n return `\u2191 ~${formatNumber(approxInputTokens)} \u00B7 \u2193 ~${formatNumber(approxOutputTokens)}`\n }\n return `\u2193 ~${formatNumber(approxOutputTokens)}`\n }\n return ''\n }\n\n const tokenUsage = getTokenDisplay()\n\n // Get thinking duration if available\n const thinkingDuration = streamState.thinkingDurationMs\n ? Math.floor(streamState.thinkingDurationMs / 1000)\n : null\n\n return (\n <Box flexDirection=\"row\" flexWrap=\"nowrap\">\n {/* Spinner icon with shimmer effect */}\n <Text color={shimmerColor}>\n {SYMBOLS.THINKING_FRAMES[spinnerIconFrame]}{' '}\n </Text>\n {/* Main task description with shimmer effect */}\n <Text color={shimmerColor} bold>\n {getCurrentTaskDisplay()}\n </Text>\n <Text color={shimmerColor}>\u2026 </Text>\n {/* Meta info with brand gradient accent */}\n <Text color={BRAND_GRADIENT.START}>\n (<Text color={SEMANTIC_COLORS.secondary}>esc esc</Text> to cancel \u00B7{' '}\n <Text color={SEMANTIC_COLORS.secondary}>{formatTime(elapsedTime)}</Text>\n {tokenUsage && (\n <Text color={SEMANTIC_COLORS.secondary}> \u00B7 {tokenUsage}</Text>\n )}\n {thinkingDuration !== null && thinkingDuration > 0 && (\n <Text color={SEMANTIC_COLORS.secondary}>\n {' '}\n \u00B7 thinking {thinkingDuration}s\n </Text>\n )}\n {shouldShowTodos && (\n <Text color={SEMANTIC_COLORS.secondary}>\n {' '}\n \u00B7 <Text color={SEMANTIC_COLORS.secondary}>ctrl+t</Text> to hide\n </Text>\n )}\n )\n </Text>\n {getSessionState('currentError') && (\n <Text color={SYMBOL_COLORS.error}>\n {' '}\n \u00B7 {getSessionState('currentError')}\n </Text>\n )}\n </Box>\n )\n})\n\n// Spinner messages for fallback when no todos\nconst SPINNER_MESSAGES = [\n 'Thinking',\n 'Processing',\n 'Working',\n 'Computing',\n 'Analyzing',\n 'Generating',\n 'Executing',\n 'Preparing',\n]\n\ninterface TodoPanelProps {\n /** TODO \u5217\u8868 */\n todos: TodoItemType[]\n /** \u662F\u5426\u663E\u793A\u9762\u677F\uFF08\u7531 Ctrl+T \u63A7\u5236\uFF09 */\n isVisible: boolean\n /** \u5F53\u524D\u4E3B\u4EFB\u52A1\u7684 activeForm\uFF08\u8FDB\u884C\u4E2D\u7684\u4EFB\u52A1\u63CF\u8FF0\uFF09 */\n currentTaskActiveForm?: string\n /** \u8FD0\u884C\u65F6\u95F4\uFF08\u79D2\uFF09 */\n elapsedTime?: number\n /** \u662F\u5426\u6B63\u5728\u52A0\u8F7D\uFF08\u63A7\u5236\u52A8\u753B\uFF09 */\n isLoading?: boolean\n /** \u662F\u5426\u663E\u793A\u4EFB\u52A1\u5217\u8868\u8BE6\u60C5 */\n showTodoList?: boolean\n}\n\n/**\n * \u7EDF\u4E00\u7684 Spinner + TODO \u9762\u677F\u7EC4\u4EF6 - Claude Code CLI \u98CE\u683C\n *\n * \u5F53\u6709 TODO \u65F6\u663E\u793A\uFF1A\n * ```\n * \u273D Fixing async tool description bug\u2026 (esc to interrupt \u00B7 ctrl+t to hide todos \u00B7 2m 52s \u00B7 \u2191 5.1k tokens)\n * \u23BF \u2610 Phase 1.1: Fix async tool description bug\n * \u2610 Phase 1.2: Add memory safety fixes\n * ```\n *\n * \u65E0 TODO \u65F6\u663E\u793A\u666E\u901A Spinner\uFF1A\n * ```\n * \u273D Thinking\u2026 (3s \u00B7 esc to interrupt)\n * ```\n *\n * Performance optimization: Animation is isolated in SpinnerLine component\n * to prevent the entire panel from re-rendering on each animation frame.\n */\nexport const TodoPanel = memo(function TodoPanel({\n todos,\n isVisible,\n currentTaskActiveForm,\n elapsedTime: initialElapsedTime = 0,\n isLoading = true,\n showTodoList = true,\n}: TodoPanelProps) {\n const theme = getTheme()\n const fallbackMessage = useRef(sample(SPINNER_MESSAGES) || 'Thinking')\n\n // \u5224\u65AD\u662F\u5426\u6709\u5F85\u529E\u4E8B\u9879\n const hasTodos = todos.length > 0\n const hasIncompleteTasks = todos.some(t => t.status !== 'completed')\n const shouldShowTodos =\n hasTodos && hasIncompleteTasks && isVisible && showTodoList\n\n // \u5982\u679C\u4E0D\u5728\u52A0\u8F7D\u72B6\u6001\uFF0C\u53EA\u663E\u793A todo \u5217\u8868\uFF08\u5982\u679C\u6709\u672A\u5B8C\u6210\u4EFB\u52A1\uFF09\n if (!isLoading) {\n // \u5373\u4F7F\u4E0D\u5728\u52A0\u8F7D\u4E2D\uFF0C\u5982\u679C\u6709\u672A\u5B8C\u6210\u7684\u4EFB\u52A1\u4E5F\u663E\u793A\u5217\u8868\n if (shouldShowTodos) {\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n {/* \u9759\u6001\u6807\u9898 - \u663E\u793A\u8FD8\u6709\u672A\u5B8C\u6210\u4EFB\u52A1 */}\n <Box flexDirection=\"row\">\n <Text color={SEMANTIC_COLORS.dim}>\u25CB </Text>\n <Text color={SEMANTIC_COLORS.dim}>\n {hasIncompleteTasks\n ? t('ui.todo.tasksRemaining', {\n count: todos.filter(todo => todo.status !== 'completed')\n .length,\n })\n : t('ui.todo.allDone')}\n </Text>\n </Box>\n {/* TODO \u5217\u8868 */}\n <Box flexDirection=\"column\">\n {todos.map((todo, idx) => (\n <React.Fragment key={`todo-${idx}-${todo.content.slice(0, 20)}`}>\n <TodoItemClaudeStyle\n todo={todo}\n theme={theme}\n isFirst={idx === 0}\n />\n </React.Fragment>\n ))}\n </Box>\n </Box>\n )\n }\n return null\n }\n\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n {/* \u7B2C\u4E00\u884C\uFF1A\u52A8\u753B + \u5F53\u524D\u4EFB\u52A1 + \u7EDF\u8BA1\u4FE1\u606F - \u9694\u79BB\u5728 SpinnerLine \u7EC4\u4EF6\u4E2D */}\n <SpinnerLine\n currentTaskActiveForm={currentTaskActiveForm}\n todos={todos}\n shouldShowTodos={shouldShowTodos}\n fallbackMessage={fallbackMessage.current}\n />\n\n {/* TODO \u5217\u8868 - \u4EC5\u5F53\u53EF\u89C1\u4E14\u6709\u672A\u5B8C\u6210\u4EFB\u52A1\u65F6\u663E\u793A */}\n {shouldShowTodos && <TodoList todos={todos} theme={theme} />}\n </Box>\n )\n})\n\n/**\n * Memoized TODO list to prevent re-rendering when only the spinner updates\n */\ninterface TodoListProps {\n todos: TodoItemType[]\n theme: ReturnType<typeof getTheme>\n}\n\nconst TodoList = memo(function TodoList({ todos, theme }: TodoListProps) {\n return (\n <Box flexDirection=\"column\">\n {todos.map((todo, idx) => (\n <React.Fragment key={`todo-${idx}-${todo.content.slice(0, 20)}`}>\n <TodoItemClaudeStyle todo={todo} theme={theme} isFirst={idx === 0} />\n </React.Fragment>\n ))}\n </Box>\n )\n})\n\n/**\n * Claude Code \u98CE\u683C\u7684 TODO \u9879\n *\n * \u683C\u5F0F\uFF1A\n * ```\n * \u23BF \u2612 \u5DF2\u5B8C\u6210\u4EFB\u52A1 (\u7070\u8272 + \u5220\u9664\u7EBF)\n * \u2610 \u5F85\u5B8C\u6210\u4EFB\u52A1\n * ```\n */\ninterface TodoItemClaudeStyleProps {\n todo: TodoItemType\n theme: ReturnType<typeof getTheme>\n isFirst: boolean\n}\n\n/**\n * Memoized TODO item component with brand-consistent colors\n */\nconst TodoItemClaudeStyle = memo(function TodoItemClaudeStyle({\n todo,\n theme,\n isFirst,\n}: TodoItemClaudeStyleProps) {\n const isCompleted = todo.status === 'completed'\n const isInProgress = todo.status === 'in_progress'\n\n // \u7B26\u53F7\uFF1A\u2610 \u672A\u5B8C\u6210 / \u2612 \u5DF2\u5B8C\u6210\n const symbol = getTodoStatusSymbol(todo.status)\n\n // \u4F7F\u7528\u54C1\u724C\u914D\u8272\uFF1A\n // - \u5DF2\u5B8C\u6210\uFF1Adim \u7070\u8272\n // - \u8FDB\u884C\u4E2D\uFF1A\u54C1\u724C\u4E2D\u95F4\u8272\uFF08\u7C89\u7D2B\uFF09\n // - \u5F85\u5904\u7406\uFF1A\u54C1\u724C\u8D77\u59CB\u8272\uFF08\u7D2B\u84DD\uFF09\n const symbolColor = isCompleted\n ? SEMANTIC_COLORS.dim\n : isInProgress\n ? BRAND_GRADIENT.MIDDLE\n : BRAND_GRADIENT.START\n\n const textColor = isCompleted\n ? SEMANTIC_COLORS.dim\n : SEMANTIC_COLORS.secondary\n\n // \u4F7F\u7528 REPL \u89C4\u8303\u5B9A\u4E49\u7684\u7ED3\u6784\u7B26\u53F7\uFF1A\u7B2C\u4E00\u4E2A\u7528 \" \u23BF \"\uFF0C\u5176\u4ED6\u7528\u7F29\u8FDB\u5BF9\u9F50\n const indent = isFirst\n ? `${getIndent('L1')}${SYMBOLS.CHILD_OUTPUT} `\n : `${getIndent('L1')} `\n\n return (\n <Box flexDirection=\"row\">\n {/* \u7F29\u8FDB - \u4F7F\u7528\u54C1\u724C\u8272 */}\n <Text color={SYMBOL_COLORS.child}>{indent}</Text>\n\n {/* \u72B6\u6001\u7B26\u53F7 - \u4F7F\u7528\u54C1\u724C\u914D\u8272 */}\n <Text color={symbolColor}>{symbol} </Text>\n\n {/* \u4EFB\u52A1\u63CF\u8FF0 */}\n <Text color={textColor} strikethrough={isCompleted}>\n {todo.content}\n </Text>\n </Box>\n )\n})\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import React, { useRef, useMemo, memo } from 'react'\nimport { Box, Text } from 'ink'\nimport { getTheme } from '@utils/theme'\nimport { SYMBOLS, getTodoStatusSymbol } from '@constants/symbols'\nimport { getTokenDisplay } from '@utils/tokenProgress'\nimport type { TodoItem as TodoItemType } from '@utils/todoStorage'\nimport { sample } from 'lodash-es'\nimport { getMainStreamingState, getStreamingState } from '@utils/streamingState'\nimport { getSessionState } from '@utils/sessionState'\nimport { useUnifiedAnimation } from '@utils/animationManager'\nimport {\n SEMANTIC_COLORS,\n BRAND_GRADIENT,\n SYMBOL_COLORS,\n} from '@constants/colors'\nimport { getIndent } from '@constants/formatRules'\nimport { t } from '@i18n'\n\n/**\n * Isolated Spinner component to prevent animation updates from re-rendering the entire panel\n * This component handles all animation state internally\n */\ninterface SpinnerLineProps {\n currentTaskActiveForm?: string\n todos: TodoItemType[]\n shouldShowTodos: boolean\n fallbackMessage: string\n /** Agent ID to read streaming state from (defaults to __main__) */\n focusedAgentId?: string | null\n}\n\n/**\n * Shimmer effect colors - creates a light sweep animation across text\n * Uses brand gradient colors cycling through: purple-blue \u2192 pink-purple \u2192 coral \u2192 pink-purple \u2192 purple-blue\n */\nconst SHIMMER_COLORS = [\n BRAND_GRADIENT.START, // #667EEA purple-blue\n '#8673D9', // blend\n BRAND_GRADIENT.MIDDLE, // #B668C8 pink-purple\n '#D560A0', // blend\n BRAND_GRADIENT.END, // #F5576C coral\n '#D560A0', // blend back\n BRAND_GRADIENT.MIDDLE, // #B668C8\n '#8673D9', // blend back\n] as const\n\n/**\n * Get shimmer color based on animation frame\n * Creates a smooth color transition effect\n */\nfunction getShimmerColor(frame: number): string {\n return SHIMMER_COLORS[frame % SHIMMER_COLORS.length]!\n}\n\nconst SpinnerLine = memo(function SpinnerLine({\n currentTaskActiveForm,\n todos,\n shouldShowTodos,\n fallbackMessage,\n focusedAgentId,\n}: SpinnerLineProps) {\n const theme = getTheme()\n const fallbackStartRef = useRef(Date.now())\n\n // Use a counter to drive re-reads of streaming state on each animation tick.\n // We read streaming state once per frame; turnStartedAt from the state\n // persists across component remounts so the timer doesn't reset on view switch.\n const tickRef = useRef(0)\n const { spinnerFrame, dataTick } = useUnifiedAnimation({\n enabled: true,\n // startTime is updated below after reading streaming state\n startTime: fallbackStartRef.current,\n spinnerFrameCount: SHIMMER_COLORS.length,\n componentId: 'todo-panel-spinner',\n })\n\n // Read streaming state on each data tick (100ms) for smooth token updates\n tickRef.current = spinnerFrame\n const latestStreamState = useMemo(\n () =>\n focusedAgentId\n ? getStreamingState(focusedAgentId)\n : getMainStreamingState(),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [focusedAgentId, dataTick],\n )\n\n // Use agent's turn start time from streaming state (survives component remounts)\n const startTime = latestStreamState.turnStartedAt ?? fallbackStartRef.current\n // Recalculate elapsed time using the correct start time\n const correctedElapsed = Math.max(\n 0,\n Math.floor((Date.now() - startTime) / 1000),\n )\n\n // Get current task display\n const getCurrentTaskDisplay = (): string => {\n if (currentTaskActiveForm) {\n return currentTaskActiveForm\n }\n const inProgressTodo = todos.find(t => t.status === 'in_progress')\n if (inProgressTodo?.activeForm) {\n return inProgressTodo.activeForm\n }\n switch (latestStreamState.phase) {\n case 'tool_use':\n return latestStreamState.toolName\n ? `Using ${latestStreamState.toolName}`\n : 'Executing tool'\n case 'generating':\n return 'Generating response'\n case 'waiting':\n return 'Waiting for response'\n case 'thinking':\n default:\n return fallbackMessage || 'Thinking'\n }\n }\n\n // Format time display\n const formatTime = (seconds: number): string => {\n if (seconds < 60) return `${seconds}s`\n const mins = Math.floor(seconds / 60)\n const secs = seconds % 60\n return secs > 0 ? `${mins}m ${secs}s` : `${mins}m`\n }\n\n // Get shimmer color for the main text (light sweep effect)\n const shimmerColor = getShimmerColor(spinnerFrame)\n\n // Spinner icon uses thinking frames\n const spinnerIconFrame = spinnerFrame % SYMBOLS.THINKING_FRAMES.length\n\n const { formatted: tokenUsage } = getTokenDisplay(focusedAgentId)\n\n // Get thinking duration if available\n const thinkingDuration = latestStreamState.thinkingDurationMs\n ? Math.floor(latestStreamState.thinkingDurationMs / 1000)\n : null\n\n return (\n <Box flexDirection=\"row\" flexWrap=\"nowrap\">\n {/* Spinner icon with shimmer effect */}\n <Text color={shimmerColor}>\n {SYMBOLS.THINKING_FRAMES[spinnerIconFrame]}{' '}\n </Text>\n {/* Main task description with shimmer effect */}\n <Text color={shimmerColor} bold>\n {getCurrentTaskDisplay()}\n </Text>\n <Text color={shimmerColor}>\u2026 </Text>\n {/* Meta info with brand gradient accent */}\n <Text color={BRAND_GRADIENT.START}>\n (<Text color={SEMANTIC_COLORS.secondary}>esc</Text> to cancel \u00B7{' '}\n <Text color={SEMANTIC_COLORS.secondary}>\n {formatTime(correctedElapsed)}\n </Text>\n {tokenUsage && (\n <Text color={SEMANTIC_COLORS.secondary}> \u00B7 {tokenUsage}</Text>\n )}\n {latestStreamState.phase === 'thinking' && (\n <Text color={SEMANTIC_COLORS.secondary}> \u00B7 thinking</Text>\n )}\n {thinkingDuration !== null && thinkingDuration > 0 && (\n <Text color={SEMANTIC_COLORS.secondary}>\n {' '}\n \u00B7 thinking {thinkingDuration}s\n </Text>\n )}\n {shouldShowTodos && (\n <Text color={SEMANTIC_COLORS.secondary}>\n {' '}\n \u00B7 <Text color={SEMANTIC_COLORS.secondary}>ctrl+t</Text> to hide\n </Text>\n )}\n )\n </Text>\n {getSessionState('currentError') && (\n <Text color={SYMBOL_COLORS.error}>\n {' '}\n \u00B7 {getSessionState('currentError')}\n </Text>\n )}\n </Box>\n )\n})\n\n// Spinner messages for fallback when no todos\nconst SPINNER_MESSAGES = [\n 'Thinking',\n 'Processing',\n 'Working',\n 'Computing',\n 'Analyzing',\n 'Generating',\n 'Executing',\n 'Preparing',\n]\n\ninterface TodoPanelProps {\n /** TODO \u5217\u8868 */\n todos: TodoItemType[]\n /** \u662F\u5426\u663E\u793A\u9762\u677F\uFF08\u7531 Ctrl+T \u63A7\u5236\uFF09 */\n isVisible: boolean\n /** \u5F53\u524D\u4E3B\u4EFB\u52A1\u7684 activeForm\uFF08\u8FDB\u884C\u4E2D\u7684\u4EFB\u52A1\u63CF\u8FF0\uFF09 */\n currentTaskActiveForm?: string\n /** \u8FD0\u884C\u65F6\u95F4\uFF08\u79D2\uFF09 */\n elapsedTime?: number\n /** \u662F\u5426\u6B63\u5728\u52A0\u8F7D\uFF08\u63A7\u5236\u52A8\u753B\uFF09 */\n isLoading?: boolean\n /** \u662F\u5426\u663E\u793A\u4EFB\u52A1\u5217\u8868\u8BE6\u60C5 */\n showTodoList?: boolean\n /** Focused agent ID for per-agent streaming state */\n focusedAgentId?: string | null\n}\n\n/**\n * \u7EDF\u4E00\u7684 Spinner + TODO \u9762\u677F\u7EC4\u4EF6 - Claude Code CLI \u98CE\u683C\n *\n * \u5F53\u6709 TODO \u65F6\u663E\u793A\uFF1A\n * ```\n * \u273D Fixing async tool description bug\u2026 (esc to interrupt \u00B7 ctrl+t to hide todos \u00B7 2m 52s \u00B7 \u2191 5.1k tokens)\n * \u23BF \u2610 Phase 1.1: Fix async tool description bug\n * \u2610 Phase 1.2: Add memory safety fixes\n * ```\n *\n * \u65E0 TODO \u65F6\u663E\u793A\u666E\u901A Spinner\uFF1A\n * ```\n * \u273D Thinking\u2026 (3s \u00B7 esc to interrupt)\n * ```\n *\n * Performance optimization: Animation is isolated in SpinnerLine component\n * to prevent the entire panel from re-rendering on each animation frame.\n */\nexport const TodoPanel = memo(function TodoPanel({\n todos,\n isVisible,\n currentTaskActiveForm,\n elapsedTime: initialElapsedTime = 0,\n isLoading = true,\n showTodoList = true,\n focusedAgentId,\n}: TodoPanelProps) {\n const theme = getTheme()\n const fallbackMessage = useRef(sample(SPINNER_MESSAGES) || 'Thinking')\n\n // \u5224\u65AD\u662F\u5426\u6709\u5F85\u529E\u4E8B\u9879\n const hasTodos = todos.length > 0\n const hasIncompleteTasks = todos.some(t => t.status !== 'completed')\n const shouldShowTodos =\n hasTodos && hasIncompleteTasks && isVisible && showTodoList\n\n // \u5982\u679C\u4E0D\u5728\u52A0\u8F7D\u72B6\u6001\uFF0C\u53EA\u663E\u793A todo \u5217\u8868\uFF08\u5982\u679C\u6709\u672A\u5B8C\u6210\u4EFB\u52A1\uFF09\n if (!isLoading) {\n // \u5373\u4F7F\u4E0D\u5728\u52A0\u8F7D\u4E2D\uFF0C\u5982\u679C\u6709\u672A\u5B8C\u6210\u7684\u4EFB\u52A1\u4E5F\u663E\u793A\u5217\u8868\n if (shouldShowTodos) {\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n {/* \u9759\u6001\u6807\u9898 - \u663E\u793A\u8FD8\u6709\u672A\u5B8C\u6210\u4EFB\u52A1 */}\n <Box flexDirection=\"row\">\n <Text color={SEMANTIC_COLORS.dim}>\u25CB </Text>\n <Text color={SEMANTIC_COLORS.dim}>\n {hasIncompleteTasks\n ? t('ui.todo.tasksRemaining', {\n count: todos.filter(todo => todo.status !== 'completed')\n .length,\n })\n : t('ui.todo.allDone')}\n </Text>\n </Box>\n {/* TODO \u5217\u8868 */}\n <Box flexDirection=\"column\">\n {todos.map((todo, idx) => (\n <React.Fragment key={todo.id}>\n <TodoItemClaudeStyle\n todo={todo}\n theme={theme}\n isFirst={idx === 0}\n />\n </React.Fragment>\n ))}\n </Box>\n </Box>\n )\n }\n return null\n }\n\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n {/* \u7B2C\u4E00\u884C\uFF1A\u52A8\u753B + \u5F53\u524D\u4EFB\u52A1 + \u7EDF\u8BA1\u4FE1\u606F - \u9694\u79BB\u5728 SpinnerLine \u7EC4\u4EF6\u4E2D */}\n <SpinnerLine\n currentTaskActiveForm={currentTaskActiveForm}\n todos={todos}\n shouldShowTodos={shouldShowTodos}\n fallbackMessage={fallbackMessage.current}\n focusedAgentId={focusedAgentId}\n />\n\n {/* TODO \u5217\u8868 - \u4EC5\u5F53\u53EF\u89C1\u4E14\u6709\u672A\u5B8C\u6210\u4EFB\u52A1\u65F6\u663E\u793A */}\n {shouldShowTodos && <TodoList todos={todos} theme={theme} />}\n </Box>\n )\n})\n\n/**\n * Memoized TODO list to prevent re-rendering when only the spinner updates\n */\ninterface TodoListProps {\n todos: TodoItemType[]\n theme: ReturnType<typeof getTheme>\n}\n\nconst TodoList = memo(function TodoList({ todos, theme }: TodoListProps) {\n return (\n <Box flexDirection=\"column\">\n {todos.map((todo, idx) => (\n <React.Fragment key={todo.id}>\n <TodoItemClaudeStyle todo={todo} theme={theme} isFirst={idx === 0} />\n </React.Fragment>\n ))}\n </Box>\n )\n})\n\n/**\n * Claude Code \u98CE\u683C\u7684 TODO \u9879\n *\n * \u683C\u5F0F\uFF1A\n * ```\n * \u23BF \u2612 \u5DF2\u5B8C\u6210\u4EFB\u52A1 (\u7070\u8272 + \u5220\u9664\u7EBF)\n * \u2610 \u5F85\u5B8C\u6210\u4EFB\u52A1\n * ```\n */\ninterface TodoItemClaudeStyleProps {\n todo: TodoItemType\n theme: ReturnType<typeof getTheme>\n isFirst: boolean\n}\n\n/**\n * Memoized TODO item component with brand-consistent colors\n */\nconst TodoItemClaudeStyle = memo(function TodoItemClaudeStyle({\n todo,\n theme,\n isFirst,\n}: TodoItemClaudeStyleProps) {\n const isCompleted = todo.status === 'completed'\n const isInProgress = todo.status === 'in_progress'\n\n // \u7B26\u53F7\uFF1A\u2610 \u672A\u5B8C\u6210 / \u2612 \u5DF2\u5B8C\u6210\n const symbol = getTodoStatusSymbol(todo.status)\n\n // \u4F7F\u7528\u54C1\u724C\u914D\u8272\uFF1A\n // - \u5DF2\u5B8C\u6210\uFF1Adim \u7070\u8272\n // - \u8FDB\u884C\u4E2D\uFF1A\u54C1\u724C\u4E2D\u95F4\u8272\uFF08\u7C89\u7D2B\uFF09\n // - \u5F85\u5904\u7406\uFF1A\u54C1\u724C\u8D77\u59CB\u8272\uFF08\u7D2B\u84DD\uFF09\n const symbolColor = isCompleted\n ? SEMANTIC_COLORS.dim\n : isInProgress\n ? BRAND_GRADIENT.MIDDLE\n : BRAND_GRADIENT.START\n\n const textColor = isCompleted\n ? SEMANTIC_COLORS.dim\n : SEMANTIC_COLORS.secondary\n\n // \u4F7F\u7528 REPL \u89C4\u8303\u5B9A\u4E49\u7684\u7ED3\u6784\u7B26\u53F7\uFF1A\u7B2C\u4E00\u4E2A\u7528 \" \u23BF \"\uFF0C\u5176\u4ED6\u7528\u7F29\u8FDB\u5BF9\u9F50\n const indent = isFirst\n ? `${getIndent('L1')}${SYMBOLS.CHILD_OUTPUT} `\n : `${getIndent('L1')} `\n\n return (\n <Box flexDirection=\"row\">\n {/* \u7F29\u8FDB - \u4F7F\u7528\u54C1\u724C\u8272 */}\n <Text color={SYMBOL_COLORS.child}>{indent}</Text>\n\n {/* \u72B6\u6001\u7B26\u53F7 - \u4F7F\u7528\u54C1\u724C\u914D\u8272 */}\n <Text color={symbolColor}>{symbol} </Text>\n\n {/* \u4EFB\u52A1\u63CF\u8FF0 */}\n <Text color={textColor} strikethrough={isCompleted}>\n {todo.content}\n </Text>\n </Box>\n )\n})\n"],
5
+ "mappings": "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",
6
6
  "names": ["SpinnerLine", "t", "TodoPanel", "TodoList", "TodoItemClaudeStyle"]
7
7
  }
@@ -1,20 +1,41 @@
1
1
  import { Box, Text } from "ink";
2
2
  import * as React from "react";
3
3
  import { getTheme } from "../utils/theme.js";
4
- const MAX_TOKENS = 19e4;
5
- const WARNING_THRESHOLD = MAX_TOKENS * 0.6;
6
- const ERROR_THRESHOLD = MAX_TOKENS * 0.8;
4
+ import { getModelManager } from "../utils/model.js";
5
+ const FALLBACK_MAX_TOKENS = 2e5;
6
+ function getMaxTokens() {
7
+ try {
8
+ const model = getModelManager().getModel("main");
9
+ return model?.contextLength && model.contextLength > 0 ? model.contextLength : FALLBACK_MAX_TOKENS;
10
+ } catch {
11
+ return FALLBACK_MAX_TOKENS;
12
+ }
13
+ }
14
+ const WARNING_THRESHOLD = FALLBACK_MAX_TOKENS * 0.6;
15
+ function getWarningThreshold() {
16
+ return getMaxTokens() * 0.6;
17
+ }
18
+ const WARNING_RATIO = 0.6;
19
+ const ERROR_RATIO = 0.8;
7
20
  function TokenWarning({ tokenUsage }) {
8
21
  const theme = getTheme();
9
- if (tokenUsage < WARNING_THRESHOLD) {
22
+ const maxTokens = getMaxTokens();
23
+ const warningThreshold = maxTokens * WARNING_RATIO;
24
+ const errorThreshold = maxTokens * ERROR_RATIO;
25
+ if (tokenUsage < warningThreshold) {
10
26
  return null;
11
27
  }
12
- const isError = tokenUsage >= ERROR_THRESHOLD;
28
+ const isError = tokenUsage >= errorThreshold;
13
29
  const emoji = isError ? "\u{1F534}" : "\u26A0\uFE0F";
14
- return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, { color: isError ? theme.error : theme.warning }, emoji, " Context low (", Math.max(0, 100 - Math.round(tokenUsage / MAX_TOKENS * 100)), "% remaining) \xB7 Run /compact to compact & continue"));
30
+ const remaining = Math.max(
31
+ 0,
32
+ 100 - Math.round(tokenUsage / maxTokens * 100)
33
+ );
34
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, { color: isError ? theme.error : theme.warning }, emoji, " Context low (", remaining, "% remaining) \xB7 Run /compact to compact & continue"));
15
35
  }
16
36
  export {
17
37
  TokenWarning,
18
- WARNING_THRESHOLD
38
+ WARNING_THRESHOLD,
39
+ getWarningThreshold
19
40
  };
20
41
  //# sourceMappingURL=TokenWarning.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/TokenWarning.tsx"],
4
- "sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { getTheme } from '@utils/theme'\n\ntype Props = {\n tokenUsage: number\n}\n\nconst MAX_TOKENS = 190_000\nexport const WARNING_THRESHOLD = MAX_TOKENS * 0.6\nconst ERROR_THRESHOLD = MAX_TOKENS * 0.8\n\nexport function TokenWarning({ tokenUsage }: Props): React.ReactNode {\n const theme = getTheme()\n\n if (tokenUsage < WARNING_THRESHOLD) {\n return null\n }\n\n const isError = tokenUsage >= ERROR_THRESHOLD\n\n const emoji = isError ? '\uD83D\uDD34' : '\u26A0\uFE0F'\n\n return (\n <Box flexDirection=\"row\">\n <Text color={isError ? theme.error : theme.warning}>\n {emoji} Context low (\n {Math.max(0, 100 - Math.round((tokenUsage / MAX_TOKENS) * 100))}%\n remaining) \u00B7 Run /compact to compact & continue\n </Text>\n </Box>\n )\n}\n"],
5
- "mappings": "AAAA,SAAS,KAAK,YAAY;AAC1B,YAAY,WAAW;AACvB,SAAS,gBAAgB;AAMzB,MAAM,aAAa;AACZ,MAAM,oBAAoB,aAAa;AAC9C,MAAM,kBAAkB,aAAa;AAE9B,SAAS,aAAa,EAAE,WAAW,GAA2B;AACnE,QAAM,QAAQ,SAAS;AAEvB,MAAI,aAAa,mBAAmB;AAClC,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,cAAc;AAE9B,QAAM,QAAQ,UAAU,cAAO;AAE/B,SACE,oCAAC,OAAI,eAAc,SACjB,oCAAC,QAAK,OAAO,UAAU,MAAM,QAAQ,MAAM,WACxC,OAAM,kBACN,KAAK,IAAI,GAAG,MAAM,KAAK,MAAO,aAAa,aAAc,GAAG,CAAC,GAAE,sDAElE,CACF;AAEJ;",
4
+ "sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { getTheme } from '@utils/theme'\nimport { getModelManager } from '@utils/model'\n\ntype Props = {\n tokenUsage: number\n}\n\nconst FALLBACK_MAX_TOKENS = 200_000\n\nfunction getMaxTokens(): number {\n try {\n const model = getModelManager().getModel('main')\n return model?.contextLength && model.contextLength > 0\n ? model.contextLength\n : FALLBACK_MAX_TOKENS\n } catch {\n return FALLBACK_MAX_TOKENS\n }\n}\n\n/** @deprecated Use getWarningThreshold() for dynamic threshold based on actual model context */\nexport const WARNING_THRESHOLD = FALLBACK_MAX_TOKENS * 0.6\nexport function getWarningThreshold(): number {\n return getMaxTokens() * 0.6\n}\nconst WARNING_RATIO = 0.6\nconst ERROR_RATIO = 0.8\n\nexport function TokenWarning({ tokenUsage }: Props): React.ReactNode {\n const theme = getTheme()\n const maxTokens = getMaxTokens()\n\n const warningThreshold = maxTokens * WARNING_RATIO\n const errorThreshold = maxTokens * ERROR_RATIO\n\n if (tokenUsage < warningThreshold) {\n return null\n }\n\n const isError = tokenUsage >= errorThreshold\n\n const emoji = isError ? '\uD83D\uDD34' : '\u26A0\uFE0F'\n const remaining = Math.max(\n 0,\n 100 - Math.round((tokenUsage / maxTokens) * 100),\n )\n\n return (\n <Box flexDirection=\"row\">\n <Text color={isError ? theme.error : theme.warning}>\n {emoji} Context low ({remaining}% remaining) \u00B7 Run /compact to compact &\n continue\n </Text>\n </Box>\n )\n}\n"],
5
+ "mappings": "AAAA,SAAS,KAAK,YAAY;AAC1B,YAAY,WAAW;AACvB,SAAS,gBAAgB;AACzB,SAAS,uBAAuB;AAMhC,MAAM,sBAAsB;AAE5B,SAAS,eAAuB;AAC9B,MAAI;AACF,UAAM,QAAQ,gBAAgB,EAAE,SAAS,MAAM;AAC/C,WAAO,OAAO,iBAAiB,MAAM,gBAAgB,IACjD,MAAM,gBACN;AAAA,EACN,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,MAAM,oBAAoB,sBAAsB;AAChD,SAAS,sBAA8B;AAC5C,SAAO,aAAa,IAAI;AAC1B;AACA,MAAM,gBAAgB;AACtB,MAAM,cAAc;AAEb,SAAS,aAAa,EAAE,WAAW,GAA2B;AACnE,QAAM,QAAQ,SAAS;AACvB,QAAM,YAAY,aAAa;AAE/B,QAAM,mBAAmB,YAAY;AACrC,QAAM,iBAAiB,YAAY;AAEnC,MAAI,aAAa,kBAAkB;AACjC,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,cAAc;AAE9B,QAAM,QAAQ,UAAU,cAAO;AAC/B,QAAM,YAAY,KAAK;AAAA,IACrB;AAAA,IACA,MAAM,KAAK,MAAO,aAAa,YAAa,GAAG;AAAA,EACjD;AAEA,SACE,oCAAC,OAAI,eAAc,SACjB,oCAAC,QAAK,OAAO,UAAU,MAAM,QAAQ,MAAM,WACxC,OAAM,kBAAe,WAAU,sDAElC,CACF;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -64,7 +64,9 @@ function AssistantTextMessage({
64
64
  return /* @__PURE__ */ React.createElement(Text, null, "\xA0\xA0\u23BF \xA0", /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.error }, "Insufficient credits \xB7 Top up: https://console.anthropic.com/settings/billing"));
65
65
  case INVALID_API_KEY_ERROR_MESSAGE:
66
66
  return /* @__PURE__ */ React.createElement(Text, null, "\xA0\xA0\u23BF \xA0", /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.error }, "Invalid API key"));
67
- default:
67
+ default: {
68
+ const rendered = applyMarkdown(text);
69
+ if (!rendered) return null;
68
70
  return /* @__PURE__ */ React.createElement(
69
71
  Box,
70
72
  {
@@ -74,13 +76,14 @@ function AssistantTextMessage({
74
76
  marginTop: addMargin ? 1 : 0,
75
77
  width: "100%"
76
78
  },
77
- /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, shouldShowDot && /* @__PURE__ */ React.createElement(Box, { minWidth: 2 }, /* @__PURE__ */ React.createElement(Text, { color: SYMBOL_COLORS.success }, BLACK_CIRCLE)), /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", width: columns - 6 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.primary }, applyMarkdown(text)))),
79
+ /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, shouldShowDot && /* @__PURE__ */ React.createElement(Box, { minWidth: 2 }, /* @__PURE__ */ React.createElement(Text, { color: SYMBOL_COLORS.success }, BLACK_CIRCLE)), /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", width: columns - 6 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.primary }, rendered))),
78
80
  /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", alignItems: "flex-end" }, /* @__PURE__ */ React.createElement(Cost, { costUSD, durationMs, debug }), verbose && (timestamp || modelId || durationMs > 0) && /* @__PURE__ */ React.createElement(Text, { color: VALUE_TIER_COLORS.meta }, formatMetaInfo({
79
81
  duration: durationMs > 0 ? durationMs : void 0,
80
82
  model: modelId,
81
83
  timestamp
82
84
  })))
83
85
  );
86
+ }
84
87
  }
85
88
  }
86
89
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/messages/AssistantTextMessage.tsx"],
4
- "sourcesContent": ["import { TextBlockParam } from '@anthropic-ai/sdk/resources/index.mjs'\nimport React from 'react'\nimport { AssistantBashOutputMessage } from './AssistantBashOutputMessage'\nimport { AssistantLocalCommandOutputMessage } from './AssistantLocalCommandOutputMessage'\nimport { getTheme } from '@utils/theme'\nimport { Box, Text } from 'ink'\nimport { Cost } from '@components/Cost'\nimport {\n API_ERROR_MESSAGE_PREFIX,\n CREDIT_BALANCE_TOO_LOW_ERROR_MESSAGE,\n INVALID_API_KEY_ERROR_MESSAGE,\n PROMPT_TOO_LONG_ERROR_MESSAGE,\n} from '@services/claude'\nimport {\n CANCEL_MESSAGE,\n INTERRUPT_MESSAGE,\n INTERRUPT_MESSAGE_FOR_TOOL_USE,\n isEmptyMessageText,\n NO_RESPONSE_REQUESTED,\n} from '@utils/messages'\nimport { BLACK_CIRCLE } from '@constants/figures'\nimport { applyMarkdown } from '@utils/markdown'\nimport { useTerminalSize } from '@hooks/useTerminalSize'\nimport { formatMetaInfo } from '@utils/taskDisplayUtils'\nimport {\n SEMANTIC_COLORS,\n SYMBOL_COLORS,\n VALUE_TIER_COLORS,\n} from '@constants/colors'\n\ntype Props = {\n param: TextBlockParam\n costUSD: number\n durationMs: number\n debug: boolean\n addMargin: boolean\n shouldShowDot: boolean\n verbose?: boolean\n width?: number | string\n /** Timestamp for verbose mode display */\n timestamp?: number\n /** Model ID for verbose mode display */\n modelId?: string\n}\n\nexport function AssistantTextMessage({\n param: { text },\n costUSD,\n durationMs,\n debug,\n addMargin,\n shouldShowDot,\n verbose,\n timestamp,\n modelId,\n}: Props): React.ReactNode {\n const { columns } = useTerminalSize()\n if (isEmptyMessageText(text)) {\n return null\n }\n\n // Show bash output\n if (text.startsWith('<bash-stdout') || text.startsWith('<bash-stderr')) {\n return <AssistantBashOutputMessage content={text} verbose={verbose} />\n }\n\n // Show command output\n if (\n text.startsWith('<local-command-stdout') ||\n text.startsWith('<local-command-stderr')\n ) {\n return <AssistantLocalCommandOutputMessage content={text} />\n }\n\n if (text.startsWith(API_ERROR_MESSAGE_PREFIX)) {\n return (\n <Text>\n &nbsp;&nbsp;\u23BF &nbsp;\n <Text color={SEMANTIC_COLORS.error}>\n {text === API_ERROR_MESSAGE_PREFIX\n ? `${API_ERROR_MESSAGE_PREFIX}: Please try again`\n : text}\n </Text>\n </Text>\n )\n }\n\n switch (text) {\n // Local JSX commands don't need a response, but we still want the assistant to see them\n // Tool results render their own interrupt messages\n case NO_RESPONSE_REQUESTED:\n case INTERRUPT_MESSAGE_FOR_TOOL_USE:\n return null\n\n case INTERRUPT_MESSAGE:\n case CANCEL_MESSAGE:\n return (\n <Text>\n &nbsp;&nbsp;\u23BF &nbsp;\n <Text color={SEMANTIC_COLORS.error}>Cancelled</Text>\n </Text>\n )\n\n case PROMPT_TOO_LONG_ERROR_MESSAGE:\n return (\n <Text>\n &nbsp;&nbsp;\u23BF &nbsp;\n <Text color={SEMANTIC_COLORS.error}>\n Context too long \u00B7 Run /compact to continue\n </Text>\n </Text>\n )\n\n case CREDIT_BALANCE_TOO_LOW_ERROR_MESSAGE:\n return (\n <Text>\n &nbsp;&nbsp;\u23BF &nbsp;\n <Text color={SEMANTIC_COLORS.error}>\n Insufficient credits \u00B7 Top up:\n https://console.anthropic.com/settings/billing\n </Text>\n </Text>\n )\n\n case INVALID_API_KEY_ERROR_MESSAGE:\n return (\n <Text>\n &nbsp;&nbsp;\u23BF &nbsp;\n <Text color={SEMANTIC_COLORS.error}>Invalid API key</Text>\n </Text>\n )\n\n default:\n return (\n <Box\n alignItems=\"flex-start\"\n flexDirection=\"row\"\n justifyContent=\"space-between\"\n marginTop={addMargin ? 1 : 0}\n width=\"100%\"\n >\n <Box flexDirection=\"row\">\n {shouldShowDot && (\n <Box minWidth={2}>\n <Text color={SYMBOL_COLORS.success}>{BLACK_CIRCLE}</Text>\n </Box>\n )}\n <Box flexDirection=\"column\" width={columns - 6}>\n <Text color={SEMANTIC_COLORS.primary}>{applyMarkdown(text)}</Text>\n </Box>\n </Box>\n <Box flexDirection=\"column\" alignItems=\"flex-end\">\n <Cost costUSD={costUSD} durationMs={durationMs} debug={debug} />\n {/* Verbose mode: duration \u00B7 model \u00B7 time */}\n {verbose && (timestamp || modelId || durationMs > 0) && (\n <Text color={VALUE_TIER_COLORS.meta}>\n {formatMetaInfo({\n duration: durationMs > 0 ? durationMs : undefined,\n model: modelId,\n timestamp: timestamp,\n })}\n </Text>\n )}\n </Box>\n </Box>\n )\n }\n}\n"],
5
- "mappings": "AACA,OAAO,WAAW;AAClB,SAAS,kCAAkC;AAC3C,SAAS,0CAA0C;AAEnD,SAAS,KAAK,YAAY;AAC1B,SAAS,YAAY;AACrB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAC9B,SAAS,uBAAuB;AAChC,SAAS,sBAAsB;AAC/B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAiBA,SAAS,qBAAqB;AAAA,EACnC,OAAO,EAAE,KAAK;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA2B;AACzB,QAAM,EAAE,QAAQ,IAAI,gBAAgB;AACpC,MAAI,mBAAmB,IAAI,GAAG;AAC5B,WAAO;AAAA,EACT;AAGA,MAAI,KAAK,WAAW,cAAc,KAAK,KAAK,WAAW,cAAc,GAAG;AACtE,WAAO,oCAAC,8BAA2B,SAAS,MAAM,SAAkB;AAAA,EACtE;AAGA,MACE,KAAK,WAAW,uBAAuB,KACvC,KAAK,WAAW,uBAAuB,GACvC;AACA,WAAO,oCAAC,sCAAmC,SAAS,MAAM;AAAA,EAC5D;AAEA,MAAI,KAAK,WAAW,wBAAwB,GAAG;AAC7C,WACE,oCAAC,YAAK,uBAEJ,oCAAC,QAAK,OAAO,gBAAgB,SAC1B,SAAS,2BACN,GAAG,wBAAwB,uBAC3B,IACN,CACF;AAAA,EAEJ;AAEA,UAAQ,MAAM;AAAA;AAAA;AAAA,IAGZ,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IAET,KAAK;AAAA,IACL,KAAK;AACH,aACE,oCAAC,YAAK,uBAEJ,oCAAC,QAAK,OAAO,gBAAgB,SAAO,WAAS,CAC/C;AAAA,IAGJ,KAAK;AACH,aACE,oCAAC,YAAK,uBAEJ,oCAAC,QAAK,OAAO,gBAAgB,SAAO,gDAEpC,CACF;AAAA,IAGJ,KAAK;AACH,aACE,oCAAC,YAAK,uBAEJ,oCAAC,QAAK,OAAO,gBAAgB,SAAO,kFAGpC,CACF;AAAA,IAGJ,KAAK;AACH,aACE,oCAAC,YAAK,uBAEJ,oCAAC,QAAK,OAAO,gBAAgB,SAAO,iBAAe,CACrD;AAAA,IAGJ;AACE,aACE;AAAA,QAAC;AAAA;AAAA,UACC,YAAW;AAAA,UACX,eAAc;AAAA,UACd,gBAAe;AAAA,UACf,WAAW,YAAY,IAAI;AAAA,UAC3B,OAAM;AAAA;AAAA,QAEN,oCAAC,OAAI,eAAc,SAChB,iBACC,oCAAC,OAAI,UAAU,KACb,oCAAC,QAAK,OAAO,cAAc,WAAU,YAAa,CACpD,GAEF,oCAAC,OAAI,eAAc,UAAS,OAAO,UAAU,KAC3C,oCAAC,QAAK,OAAO,gBAAgB,WAAU,cAAc,IAAI,CAAE,CAC7D,CACF;AAAA,QACA,oCAAC,OAAI,eAAc,UAAS,YAAW,cACrC,oCAAC,QAAK,SAAkB,YAAwB,OAAc,GAE7D,YAAY,aAAa,WAAW,aAAa,MAChD,oCAAC,QAAK,OAAO,kBAAkB,QAC5B,eAAe;AAAA,UACd,UAAU,aAAa,IAAI,aAAa;AAAA,UACxC,OAAO;AAAA,UACP;AAAA,QACF,CAAC,CACH,CAEJ;AAAA,MACF;AAAA,EAEN;AACF;",
4
+ "sourcesContent": ["import { TextBlockParam } from '@anthropic-ai/sdk/resources/index.mjs'\nimport React from 'react'\nimport { AssistantBashOutputMessage } from './AssistantBashOutputMessage'\nimport { AssistantLocalCommandOutputMessage } from './AssistantLocalCommandOutputMessage'\nimport { getTheme } from '@utils/theme'\nimport { Box, Text } from 'ink'\nimport { Cost } from '@components/Cost'\nimport {\n API_ERROR_MESSAGE_PREFIX,\n CREDIT_BALANCE_TOO_LOW_ERROR_MESSAGE,\n INVALID_API_KEY_ERROR_MESSAGE,\n PROMPT_TOO_LONG_ERROR_MESSAGE,\n} from '@services/claude'\nimport {\n CANCEL_MESSAGE,\n INTERRUPT_MESSAGE,\n INTERRUPT_MESSAGE_FOR_TOOL_USE,\n isEmptyMessageText,\n NO_RESPONSE_REQUESTED,\n} from '@utils/messages'\nimport { BLACK_CIRCLE } from '@constants/figures'\nimport { applyMarkdown } from '@utils/markdown'\nimport { useTerminalSize } from '@hooks/useTerminalSize'\nimport { formatMetaInfo } from '@utils/taskDisplayUtils'\nimport {\n SEMANTIC_COLORS,\n SYMBOL_COLORS,\n VALUE_TIER_COLORS,\n} from '@constants/colors'\n\ntype Props = {\n param: TextBlockParam\n costUSD: number\n durationMs: number\n debug: boolean\n addMargin: boolean\n shouldShowDot: boolean\n verbose?: boolean\n width?: number | string\n /** Timestamp for verbose mode display */\n timestamp?: number\n /** Model ID for verbose mode display */\n modelId?: string\n}\n\nexport function AssistantTextMessage({\n param: { text },\n costUSD,\n durationMs,\n debug,\n addMargin,\n shouldShowDot,\n verbose,\n timestamp,\n modelId,\n}: Props): React.ReactNode {\n const { columns } = useTerminalSize()\n if (isEmptyMessageText(text)) {\n return null\n }\n\n // Show bash output\n if (text.startsWith('<bash-stdout') || text.startsWith('<bash-stderr')) {\n return <AssistantBashOutputMessage content={text} verbose={verbose} />\n }\n\n // Show command output\n if (\n text.startsWith('<local-command-stdout') ||\n text.startsWith('<local-command-stderr')\n ) {\n return <AssistantLocalCommandOutputMessage content={text} />\n }\n\n if (text.startsWith(API_ERROR_MESSAGE_PREFIX)) {\n return (\n <Text>\n &nbsp;&nbsp;\u23BF &nbsp;\n <Text color={SEMANTIC_COLORS.error}>\n {text === API_ERROR_MESSAGE_PREFIX\n ? `${API_ERROR_MESSAGE_PREFIX}: Please try again`\n : text}\n </Text>\n </Text>\n )\n }\n\n switch (text) {\n // Local JSX commands don't need a response, but we still want the assistant to see them\n // Tool results render their own interrupt messages\n case NO_RESPONSE_REQUESTED:\n case INTERRUPT_MESSAGE_FOR_TOOL_USE:\n return null\n\n case INTERRUPT_MESSAGE:\n case CANCEL_MESSAGE:\n return (\n <Text>\n &nbsp;&nbsp;\u23BF &nbsp;\n <Text color={SEMANTIC_COLORS.error}>Cancelled</Text>\n </Text>\n )\n\n case PROMPT_TOO_LONG_ERROR_MESSAGE:\n return (\n <Text>\n &nbsp;&nbsp;\u23BF &nbsp;\n <Text color={SEMANTIC_COLORS.error}>\n Context too long \u00B7 Run /compact to continue\n </Text>\n </Text>\n )\n\n case CREDIT_BALANCE_TOO_LOW_ERROR_MESSAGE:\n return (\n <Text>\n &nbsp;&nbsp;\u23BF &nbsp;\n <Text color={SEMANTIC_COLORS.error}>\n Insufficient credits \u00B7 Top up:\n https://console.anthropic.com/settings/billing\n </Text>\n </Text>\n )\n\n case INVALID_API_KEY_ERROR_MESSAGE:\n return (\n <Text>\n &nbsp;&nbsp;\u23BF &nbsp;\n <Text color={SEMANTIC_COLORS.error}>Invalid API key</Text>\n </Text>\n )\n\n default: {\n // Defense-in-depth: check rendered output to catch text that passes\n // isEmptyMessageText but renders empty after markdown processing\n // (e.g., system-reminder tags, unhandled HTML, zero-width characters)\n const rendered = applyMarkdown(text)\n if (!rendered) return null\n\n return (\n <Box\n alignItems=\"flex-start\"\n flexDirection=\"row\"\n justifyContent=\"space-between\"\n marginTop={addMargin ? 1 : 0}\n width=\"100%\"\n >\n <Box flexDirection=\"row\">\n {shouldShowDot && (\n <Box minWidth={2}>\n <Text color={SYMBOL_COLORS.success}>{BLACK_CIRCLE}</Text>\n </Box>\n )}\n <Box flexDirection=\"column\" width={columns - 6}>\n <Text color={SEMANTIC_COLORS.primary}>{rendered}</Text>\n </Box>\n </Box>\n <Box flexDirection=\"column\" alignItems=\"flex-end\">\n <Cost costUSD={costUSD} durationMs={durationMs} debug={debug} />\n {/* Verbose mode: duration \u00B7 model \u00B7 time */}\n {verbose && (timestamp || modelId || durationMs > 0) && (\n <Text color={VALUE_TIER_COLORS.meta}>\n {formatMetaInfo({\n duration: durationMs > 0 ? durationMs : undefined,\n model: modelId,\n timestamp: timestamp,\n })}\n </Text>\n )}\n </Box>\n </Box>\n )\n }\n }\n}\n"],
5
+ "mappings": "AACA,OAAO,WAAW;AAClB,SAAS,kCAAkC;AAC3C,SAAS,0CAA0C;AAEnD,SAAS,KAAK,YAAY;AAC1B,SAAS,YAAY;AACrB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAC9B,SAAS,uBAAuB;AAChC,SAAS,sBAAsB;AAC/B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAiBA,SAAS,qBAAqB;AAAA,EACnC,OAAO,EAAE,KAAK;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA2B;AACzB,QAAM,EAAE,QAAQ,IAAI,gBAAgB;AACpC,MAAI,mBAAmB,IAAI,GAAG;AAC5B,WAAO;AAAA,EACT;AAGA,MAAI,KAAK,WAAW,cAAc,KAAK,KAAK,WAAW,cAAc,GAAG;AACtE,WAAO,oCAAC,8BAA2B,SAAS,MAAM,SAAkB;AAAA,EACtE;AAGA,MACE,KAAK,WAAW,uBAAuB,KACvC,KAAK,WAAW,uBAAuB,GACvC;AACA,WAAO,oCAAC,sCAAmC,SAAS,MAAM;AAAA,EAC5D;AAEA,MAAI,KAAK,WAAW,wBAAwB,GAAG;AAC7C,WACE,oCAAC,YAAK,uBAEJ,oCAAC,QAAK,OAAO,gBAAgB,SAC1B,SAAS,2BACN,GAAG,wBAAwB,uBAC3B,IACN,CACF;AAAA,EAEJ;AAEA,UAAQ,MAAM;AAAA;AAAA;AAAA,IAGZ,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IAET,KAAK;AAAA,IACL,KAAK;AACH,aACE,oCAAC,YAAK,uBAEJ,oCAAC,QAAK,OAAO,gBAAgB,SAAO,WAAS,CAC/C;AAAA,IAGJ,KAAK;AACH,aACE,oCAAC,YAAK,uBAEJ,oCAAC,QAAK,OAAO,gBAAgB,SAAO,gDAEpC,CACF;AAAA,IAGJ,KAAK;AACH,aACE,oCAAC,YAAK,uBAEJ,oCAAC,QAAK,OAAO,gBAAgB,SAAO,kFAGpC,CACF;AAAA,IAGJ,KAAK;AACH,aACE,oCAAC,YAAK,uBAEJ,oCAAC,QAAK,OAAO,gBAAgB,SAAO,iBAAe,CACrD;AAAA,IAGJ,SAAS;AAIP,YAAM,WAAW,cAAc,IAAI;AACnC,UAAI,CAAC,SAAU,QAAO;AAEtB,aACE;AAAA,QAAC;AAAA;AAAA,UACC,YAAW;AAAA,UACX,eAAc;AAAA,UACd,gBAAe;AAAA,UACf,WAAW,YAAY,IAAI;AAAA,UAC3B,OAAM;AAAA;AAAA,QAEN,oCAAC,OAAI,eAAc,SAChB,iBACC,oCAAC,OAAI,UAAU,KACb,oCAAC,QAAK,OAAO,cAAc,WAAU,YAAa,CACpD,GAEF,oCAAC,OAAI,eAAc,UAAS,OAAO,UAAU,KAC3C,oCAAC,QAAK,OAAO,gBAAgB,WAAU,QAAS,CAClD,CACF;AAAA,QACA,oCAAC,OAAI,eAAc,UAAS,YAAW,cACrC,oCAAC,QAAK,SAAkB,YAAwB,OAAc,GAE7D,YAAY,aAAa,WAAW,aAAa,MAChD,oCAAC,QAAK,OAAO,kBAAkB,QAC5B,eAAe;AAAA,UACd,UAAU,aAAa,IAAI,aAAa;AAAA,UACxC,OAAO;AAAA,UACP;AAAA,QACF,CAAC,CACH,CAEJ;AAAA,MACF;AAAA,IAEJ;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -5,6 +5,7 @@ import { Cost } from "../Cost.js";
5
5
  import { ToolUseLoader } from "../ToolUseLoader.js";
6
6
  import { BLACK_CIRCLE } from "../../constants/figures.js";
7
7
  import { ThinkTool } from "../../tools/ThinkTool/ThinkTool.js";
8
+ import { isAgentToolName } from "../../tools/TaskTool/constants.js";
8
9
  import { AssistantThinkingMessage } from "./AssistantThinkingMessage.js";
9
10
  import { TaskToolMessage } from "./TaskToolMessage.js";
10
11
  import { safeRenderToolUseMessage } from "../../utils/tooling/safeRender.js";
@@ -32,6 +33,13 @@ function AssistantToolUseMessage({
32
33
  }
33
34
  const isQueued = !inProgressToolUseIDs.has(param.id) && unresolvedToolUseIDs.has(param.id);
34
35
  const color = isQueued ? SEMANTIC_COLORS.dim : void 0;
36
+ if (param.name === "SendMessage" && !verbose) {
37
+ const input = param.input;
38
+ const msgType = input?.type;
39
+ if (msgType === "shutdown_request" || msgType === "shutdown_response") {
40
+ return null;
41
+ }
42
+ }
35
43
  if (tool === ThinkTool) {
36
44
  const { thought } = ThinkTool.inputSchema.parse(param.input);
37
45
  return /* @__PURE__ */ React.createElement(
@@ -65,7 +73,7 @@ function AssistantToolUseMessage({
65
73
  isError: erroredToolUseIDs.has(param.id)
66
74
  }
67
75
  )),
68
- tool.name === "Task" && param.input ? /* @__PURE__ */ React.createElement(
76
+ isAgentToolName(tool.name) && param.input ? /* @__PURE__ */ React.createElement(
69
77
  TaskToolMessage,
70
78
  {
71
79
  agentType: String(
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/messages/AssistantToolUseMessage.tsx"],
4
- "sourcesContent": ["import { Box, Text } from 'ink'\nimport React from 'react'\nimport { logError } from '@utils/log'\nimport { ToolUseBlockParam } from '@anthropic-ai/sdk/resources/index.mjs'\nimport { Tool } from '@tool'\nimport { Cost } from '@components/Cost'\nimport { ToolUseLoader } from '@components/ToolUseLoader'\nimport { BLACK_CIRCLE } from '@constants/figures'\nimport { ThinkTool } from '@tools/ThinkTool/ThinkTool'\nimport { AssistantThinkingMessage } from './AssistantThinkingMessage'\nimport { TaskToolMessage } from './TaskToolMessage'\nimport { safeRenderToolUseMessage } from '@utils/tooling/safeRender'\nimport { formatMetaInfo } from '@utils/taskDisplayUtils'\nimport { SEMANTIC_COLORS, VALUE_TIER_COLORS } from '@constants/colors'\n\ntype Props = {\n param: ToolUseBlockParam\n costUSD: number\n durationMs: number\n addMargin: boolean\n tools: Tool[]\n debug: boolean\n verbose: boolean\n erroredToolUseIDs: Set<string>\n inProgressToolUseIDs: Set<string>\n unresolvedToolUseIDs: Set<string>\n shouldAnimate: boolean\n shouldShowDot: boolean\n /** Model ID for verbose mode display */\n modelId?: string\n}\n\nexport function AssistantToolUseMessage({\n param,\n costUSD,\n durationMs,\n addMargin,\n tools,\n debug,\n verbose,\n erroredToolUseIDs,\n inProgressToolUseIDs,\n unresolvedToolUseIDs,\n shouldAnimate,\n shouldShowDot,\n modelId,\n}: Props): React.ReactNode {\n const tool = tools.find(_ => _.name === param.name)\n if (!tool) {\n logError(`Tool ${param.name} not found`)\n return null\n }\n const isQueued =\n !inProgressToolUseIDs.has(param.id) && unresolvedToolUseIDs.has(param.id)\n // \u4F7F\u7528\u8BED\u4E49\u989C\u8272\uFF1A\u6392\u961F\u4E2D\u7528 dim\uFF0C\u8FDB\u884C\u4E2D\u7528\u9ED8\u8BA4\n const color = isQueued ? SEMANTIC_COLORS.dim : undefined\n\n // Handle thinking tool with specialized rendering\n if (tool === ThinkTool) {\n const { thought } = ThinkTool.inputSchema.parse(param.input)\n return (\n <AssistantThinkingMessage\n param={{ thinking: thought, signature: '', type: 'thinking' }}\n addMargin={addMargin}\n />\n )\n }\n\n const userFacingToolName = tool.userFacingName\n ? tool.userFacingName()\n : tool.name\n return (\n <Box\n flexDirection=\"row\"\n justifyContent=\"space-between\"\n marginTop={addMargin ? 1 : 0}\n width=\"100%\"\n >\n <Box>\n <Box\n flexWrap=\"nowrap\"\n minWidth={userFacingToolName.length + (shouldShowDot ? 2 : 0)}\n >\n {shouldShowDot &&\n (isQueued ? (\n <Box minWidth={2}>\n <Text color={color}>{BLACK_CIRCLE}</Text>\n </Box>\n ) : (\n <ToolUseLoader\n shouldAnimate={shouldAnimate}\n isUnresolved={unresolvedToolUseIDs.has(param.id)}\n isError={erroredToolUseIDs.has(param.id)}\n />\n ))}\n {tool.name === 'Task' && param.input ? (\n <TaskToolMessage\n agentType={String(\n (param.input as any).subagent_type || 'general-purpose',\n )}\n bold={Boolean(!isQueued)}\n children={String(userFacingToolName || '')}\n />\n ) : (\n <Text color={color} bold={!isQueued}>\n {userFacingToolName}\n </Text>\n )}\n </Box>\n <Box flexWrap=\"nowrap\">\n {Object.keys(param.input as { [key: string]: unknown }).length > 0 &&\n (() => {\n const toolMessage = safeRenderToolUseMessage(tool, param.input, {\n verbose,\n })\n\n // TodoWriteTool: Special formatting - message already includes parentheses and formatting\n // Format: \" (1 running, 2 pending): taskName\" (note leading space, parens around stats only)\n if (tool.name === 'TodoWrite') {\n return <Text color={color}>{toolMessage}</Text>\n }\n\n // If the tool returns a React component, render it directly\n if (React.isValidElement(toolMessage)) {\n return (\n <Box flexDirection=\"row\">\n <Text color={color}>(</Text>\n {toolMessage}\n <Text color={color}>)</Text>\n </Box>\n )\n }\n\n // If it's a string, wrap it in Text\n return <Text color={color}>({toolMessage})</Text>\n })()}\n <Text color={color}>\u2026</Text>\n </Box>\n </Box>\n <Box flexDirection=\"column\" alignItems=\"flex-end\">\n <Cost costUSD={costUSD} durationMs={durationMs} debug={debug} />\n {/* Verbose mode: duration \u00B7 model \u00B7 time */}\n {verbose && (\n <Text color={VALUE_TIER_COLORS.meta}>\n {formatMetaInfo({\n duration: durationMs > 0 ? durationMs : undefined,\n model: modelId,\n timestamp: Date.now(),\n })}\n </Text>\n )}\n </Box>\n </Box>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Box, Text } from 'ink'\nimport React from 'react'\nimport { logError } from '@utils/log'\nimport { ToolUseBlockParam } from '@anthropic-ai/sdk/resources/index.mjs'\nimport { Tool } from '@tool'\nimport { Cost } from '@components/Cost'\nimport { ToolUseLoader } from '@components/ToolUseLoader'\nimport { BLACK_CIRCLE } from '@constants/figures'\nimport { ThinkTool } from '@tools/ThinkTool/ThinkTool'\nimport { isAgentToolName } from '@tools/TaskTool/constants'\nimport { AssistantThinkingMessage } from './AssistantThinkingMessage'\nimport { TaskToolMessage } from './TaskToolMessage'\nimport { safeRenderToolUseMessage } from '@utils/tooling/safeRender'\nimport { formatMetaInfo } from '@utils/taskDisplayUtils'\nimport { SEMANTIC_COLORS, VALUE_TIER_COLORS } from '@constants/colors'\n\ntype Props = {\n param: ToolUseBlockParam\n costUSD: number\n durationMs: number\n addMargin: boolean\n tools: Tool[]\n debug: boolean\n verbose: boolean\n erroredToolUseIDs: Set<string>\n inProgressToolUseIDs: Set<string>\n unresolvedToolUseIDs: Set<string>\n shouldAnimate: boolean\n shouldShowDot: boolean\n /** Model ID for verbose mode display */\n modelId?: string\n}\n\nexport function AssistantToolUseMessage({\n param,\n costUSD,\n durationMs,\n addMargin,\n tools,\n debug,\n verbose,\n erroredToolUseIDs,\n inProgressToolUseIDs,\n unresolvedToolUseIDs,\n shouldAnimate,\n shouldShowDot,\n modelId,\n}: Props): React.ReactNode {\n const tool = tools.find(_ => _.name === param.name)\n if (!tool) {\n logError(`Tool ${param.name} not found`)\n return null\n }\n const isQueued =\n !inProgressToolUseIDs.has(param.id) && unresolvedToolUseIDs.has(param.id)\n // \u4F7F\u7528\u8BED\u4E49\u989C\u8272\uFF1A\u6392\u961F\u4E2D\u7528 dim\uFF0C\u8FDB\u884C\u4E2D\u7528\u9ED8\u8BA4\n const color = isQueued ? SEMANTIC_COLORS.dim : undefined\n\n // Suppress team protocol messages (shutdown/internal) in non-verbose mode\n if (param.name === 'SendMessage' && !verbose) {\n const input = param.input as Record<string, unknown>\n const msgType = input?.type as string\n if (msgType === 'shutdown_request' || msgType === 'shutdown_response') {\n return null\n }\n }\n\n // Handle thinking tool with specialized rendering\n if (tool === ThinkTool) {\n const { thought } = ThinkTool.inputSchema.parse(param.input)\n return (\n <AssistantThinkingMessage\n param={{ thinking: thought, signature: '', type: 'thinking' }}\n addMargin={addMargin}\n />\n )\n }\n\n const userFacingToolName = tool.userFacingName\n ? tool.userFacingName()\n : tool.name\n return (\n <Box\n flexDirection=\"row\"\n justifyContent=\"space-between\"\n marginTop={addMargin ? 1 : 0}\n width=\"100%\"\n >\n <Box>\n <Box\n flexWrap=\"nowrap\"\n minWidth={userFacingToolName.length + (shouldShowDot ? 2 : 0)}\n >\n {shouldShowDot &&\n (isQueued ? (\n <Box minWidth={2}>\n <Text color={color}>{BLACK_CIRCLE}</Text>\n </Box>\n ) : (\n <ToolUseLoader\n shouldAnimate={shouldAnimate}\n isUnresolved={unresolvedToolUseIDs.has(param.id)}\n isError={erroredToolUseIDs.has(param.id)}\n />\n ))}\n {isAgentToolName(tool.name) && param.input ? (\n <TaskToolMessage\n agentType={String(\n (param.input as any).subagent_type || 'general-purpose',\n )}\n bold={Boolean(!isQueued)}\n children={String(userFacingToolName || '')}\n />\n ) : (\n <Text color={color} bold={!isQueued}>\n {userFacingToolName}\n </Text>\n )}\n </Box>\n <Box flexWrap=\"nowrap\">\n {Object.keys(param.input as { [key: string]: unknown }).length > 0 &&\n (() => {\n const toolMessage = safeRenderToolUseMessage(tool, param.input, {\n verbose,\n })\n\n // TodoWriteTool: Special formatting - message already includes parentheses and formatting\n // Format: \" (1 running, 2 pending): taskName\" (note leading space, parens around stats only)\n if (tool.name === 'TodoWrite') {\n return <Text color={color}>{toolMessage}</Text>\n }\n\n // If the tool returns a React component, render it directly\n if (React.isValidElement(toolMessage)) {\n return (\n <Box flexDirection=\"row\">\n <Text color={color}>(</Text>\n {toolMessage}\n <Text color={color}>)</Text>\n </Box>\n )\n }\n\n // If it's a string, wrap it in Text\n return <Text color={color}>({toolMessage})</Text>\n })()}\n <Text color={color}>\u2026</Text>\n </Box>\n </Box>\n <Box flexDirection=\"column\" alignItems=\"flex-end\">\n <Cost costUSD={costUSD} durationMs={durationMs} debug={debug} />\n {/* Verbose mode: duration \u00B7 model \u00B7 time */}\n {verbose && (\n <Text color={VALUE_TIER_COLORS.meta}>\n {formatMetaInfo({\n duration: durationMs > 0 ? durationMs : undefined,\n model: modelId,\n timestamp: Date.now(),\n })}\n </Text>\n )}\n </Box>\n </Box>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,11 @@
1
+ import * as React from "react";
2
+ import { Box, Text } from "ink";
3
+ function DefaultToolResultFallback({
4
+ toolName
5
+ }) {
6
+ return /* @__PURE__ */ React.createElement(Box, { justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, null, "\xA0\xA0\u23BF \xA0", toolName, " completed")));
7
+ }
8
+ export {
9
+ DefaultToolResultFallback
10
+ };
11
+ //# sourceMappingURL=DefaultToolResultFallback.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/components/messages/DefaultToolResultFallback.tsx"],
4
+ "sourcesContent": ["import * as React from 'react'\nimport { Box, Text } from 'ink'\n\n/**\n * Default fallback for tool result rendering.\n * Used when the output is null/undefined or cannot be parsed.\n */\nexport function DefaultToolResultFallback({\n toolName,\n}: {\n toolName: string\n}): React.ReactElement {\n return (\n <Box justifyContent=\"space-between\" width=\"100%\">\n <Box flexDirection=\"row\">\n <Text>&nbsp;&nbsp;\u23BF &nbsp;{toolName} completed</Text>\n </Box>\n </Box>\n )\n}\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;AACvB,SAAS,KAAK,YAAY;AAMnB,SAAS,0BAA0B;AAAA,EACxC;AACF,GAEuB;AACrB,SACE,oCAAC,OAAI,gBAAe,iBAAgB,OAAM,UACxC,oCAAC,OAAI,eAAc,SACjB,oCAAC,YAAK,uBAAqB,UAAS,YAAU,CAChD,CACF;AAEJ;",
6
+ "names": []
7
+ }
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
  import { Box, Text } from "ink";
3
- import { TreeConnector } from "../TreeConnector.js";
3
+ import { ToolUseLoader } from "../ToolUseLoader.js";
4
4
  import { CollapsibleHint } from "../CollapsibleHint.js";
5
5
  import { TaskInModuleView } from "./TaskInModuleView.js";
6
6
  import { ParallelTasksHandler } from "../../utils/groupHandlers/parallelTasksHandler.js";
@@ -26,6 +26,7 @@ function ParallelTasksGroupView({
26
26
  return getTranscript?.(agentId) ?? transcripts.get(agentId) ?? null;
27
27
  };
28
28
  const memberInfos = ParallelTasksHandler.getMemberTaskInfo(group, messages);
29
+ const isTeamGroup = memberInfos.some((info) => !!info.teamName);
29
30
  const completedCount = memberInfos.filter((info) => {
30
31
  const output = outputs.get(info.toolUseId);
31
32
  if (output) return true;
@@ -36,7 +37,6 @@ function ParallelTasksGroupView({
36
37
  const totalCount = memberInfos.length;
37
38
  const isCompleted = completedCount === totalCount && totalCount > 0;
38
39
  const statusColor = isCompleted ? SYMBOL_COLORS.success : group.status === "running" ? SYMBOL_COLORS.running : SYMBOL_COLORS.pending;
39
- const groupSymbol = isCompleted ? SYMBOLS.TOOL_SUCCESS : SYMBOLS.PARALLEL_GROUP;
40
40
  const groupMetaInfo = (() => {
41
41
  if (!isCompleted) return null;
42
42
  const completedTranscripts = [];
@@ -59,23 +59,31 @@ function ParallelTasksGroupView({
59
59
  timestamp: latestEnd
60
60
  };
61
61
  })();
62
- return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", width: "100%", marginTop: MARGIN_BEFORE_MODULE }, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, { color: statusColor }, groupSymbol, " "), /* @__PURE__ */ React.createElement(Text, { bold: true, color: SEMANTIC_COLORS.secondary }, "Parallel Tasks"), /* @__PURE__ */ React.createElement(Text, null, " "), /* @__PURE__ */ React.createElement(Text, null, "("), /* @__PURE__ */ React.createElement(Text, { color: SYMBOL_COLORS.success }, completedCount), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "/", totalCount), /* @__PURE__ */ React.createElement(Text, null, " finished)"), displayConfig.showMetaInfo && groupMetaInfo && /* @__PURE__ */ React.createElement(Text, { color: VALUE_TIER_COLORS.meta }, " ", formatMetaInfo({
62
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", width: "100%", marginTop: MARGIN_BEFORE_MODULE }, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, isCompleted ? /* @__PURE__ */ React.createElement(Text, { color: SYMBOL_COLORS.success }, SYMBOLS.TOOL_SUCCESS, " ") : /* @__PURE__ */ React.createElement(
63
+ ToolUseLoader,
64
+ {
65
+ shouldAnimate,
66
+ isUnresolved: true,
67
+ isError: false
68
+ }
69
+ ), isTeamGroup ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Text, { bold: true, color: SEMANTIC_COLORS.secondary }, totalCount, " agent", totalCount !== 1 ? "s" : "", " working"), !isCompleted && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Text, null, " "), /* @__PURE__ */ React.createElement(Text, null, "("), /* @__PURE__ */ React.createElement(Text, { color: SYMBOL_COLORS.success }, completedCount), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "/", totalCount), /* @__PURE__ */ React.createElement(Text, null, " done)"))) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Text, { bold: true, color: SEMANTIC_COLORS.secondary }, "Parallel Tasks"), /* @__PURE__ */ React.createElement(Text, null, " "), /* @__PURE__ */ React.createElement(Text, null, "("), /* @__PURE__ */ React.createElement(Text, { color: SYMBOL_COLORS.success }, completedCount), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "/", totalCount), /* @__PURE__ */ React.createElement(Text, null, " done)")), displayConfig.showMetaInfo && groupMetaInfo && /* @__PURE__ */ React.createElement(Text, { color: VALUE_TIER_COLORS.meta }, " ", formatMetaInfo({
63
70
  duration: groupMetaInfo.duration,
64
71
  timestamp: groupMetaInfo.timestamp
65
72
  })), /* @__PURE__ */ React.createElement(
66
73
  CollapsibleHint,
67
74
  {
68
- canExpand: isCompleted && !displayConfig.showAllChildren
75
+ canExpand: isCompleted && !displayConfig.showAllChildren,
76
+ shortcut: void 0
69
77
  }
70
78
  )), /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginLeft: INDENT_LEVELS.L1 }, memberInfos.map((info, index) => {
71
79
  const isLast = index === memberInfos.length - 1;
72
80
  const transcript = info.agentId ? getTranscriptForAgent(info.agentId) : null;
73
81
  const output = outputs.get(info.toolUseId);
74
- return /* @__PURE__ */ React.createElement(Box, { key: info.toolUseId, flexDirection: "row" }, /* @__PURE__ */ React.createElement(TreeConnector, { isLast }), /* @__PURE__ */ React.createElement(
82
+ return /* @__PURE__ */ React.createElement(Box, { key: info.toolUseId, flexDirection: "column" }, /* @__PURE__ */ React.createElement(
75
83
  TaskInModuleView,
76
84
  {
77
85
  toolUseId: info.toolUseId,
78
- description: info.description,
86
+ description: isTeamGroup && info.teammateName ? `@${info.teammateName}` : info.description,
79
87
  agentType: info.agentType,
80
88
  transcript,
81
89
  output: output || null,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/messages/ParallelTasksGroupView.tsx"],
4
- "sourcesContent": ["/**\n * Parallel Tasks Group View\n *\n * Renders a group of concurrent tasks as a unified module.\n * Displays completion progress and individual task status.\n */\n\nimport React from 'react'\nimport { Box, Text } from 'ink'\nimport type { ToolResultBlockParam } from '@anthropic-ai/sdk/resources/index.mjs'\nimport type { MessageGroup, DisplayConfig } from '@minto-types/messageGroup'\nimport type { AgentTranscript } from '@utils/agentTranscripts'\nimport type { NormalizedMessage } from '@utils/messages'\nimport { ToolUseLoader } from '@components/ToolUseLoader'\nimport { TreeConnector, TreeContinuation } from '@components/TreeConnector'\nimport { CollapsibleHint } from '@components/CollapsibleHint'\nimport { TaskInModuleView } from './TaskInModuleView'\nimport { ParallelTasksHandler } from '@utils/groupHandlers/parallelTasksHandler'\nimport { MARGIN_BEFORE_MODULE, INDENT_LEVELS } from '@constants/formatRules'\nimport { SYMBOLS } from '@constants/symbols'\nimport {\n SEMANTIC_COLORS,\n STATUS_COLORS,\n VALUE_TIER_COLORS,\n SYMBOL_COLORS,\n} from '@constants/colors'\nimport { formatMetaInfo } from '@utils/taskDisplayUtils'\n\ninterface Props {\n /** The parallel tasks group */\n group: MessageGroup\n /** Normalized messages for looking up task info */\n messages: NormalizedMessage[]\n /** Transcripts by agentId */\n transcripts: Map<string, AgentTranscript>\n /** Outputs by toolUseId */\n outputs: Map<string, ToolResultBlockParam>\n /** Display configuration */\n displayConfig: DisplayConfig\n /** Whether to animate */\n shouldAnimate: boolean\n /**\n * Function to get transcript by agentId with lazy loading from disk.\n * Essential for loading historical transcripts that aren't in memory.\n */\n getTranscript?: (agentId: string) => AgentTranscript | null\n}\n\nexport function ParallelTasksGroupView({\n group,\n messages,\n transcripts,\n outputs,\n displayConfig,\n shouldAnimate,\n getTranscript,\n}: Props): React.ReactNode {\n const memberIds = (group.metadata.siblingToolUseIds as string[]) || []\n\n // Helper to get transcript - use getTranscript for lazy loading, fallback to Map\n const getTranscriptForAgent = (agentId: string): AgentTranscript | null => {\n return getTranscript?.(agentId) ?? transcripts.get(agentId) ?? null\n }\n\n // Get task info for each member\n const memberInfos = ParallelTasksHandler.getMemberTaskInfo(group, messages)\n\n // Count completions - check both transcript status AND output existence\n const completedCount = memberInfos.filter(info => {\n // Check if output exists (definitive completion signal)\n const output = outputs.get(info.toolUseId)\n if (output) return true\n\n // Fallback to transcript status\n if (!info.agentId) return false\n const transcript = getTranscriptForAgent(info.agentId)\n return transcript?.status === 'completed'\n }).length\n\n const totalCount = memberInfos.length\n\n // Determine completion status - use actual completion count as primary signal\n // This is more reliable than group.status which may have timing issues\n const isCompleted = completedCount === totalCount && totalCount > 0\n\n // \u4F7F\u7528 SYMBOL_COLORS \u4E0E Logo \u54C1\u724C\u914D\u8272\u4FDD\u6301\u4E00\u81F4\n const statusColor = isCompleted\n ? SYMBOL_COLORS.success\n : group.status === 'running'\n ? SYMBOL_COLORS.running\n : SYMBOL_COLORS.pending\n\n // \u4F7F\u7528 REPL \u89C4\u8303\u5B9A\u4E49\u7684\u7B26\u53F7\uFF1A\u5E76\u884C\u4EFB\u52A1\u7EC4 \u25C8\n const groupSymbol = isCompleted\n ? SYMBOLS.TOOL_SUCCESS\n : SYMBOLS.PARALLEL_GROUP\n\n // \u8BA1\u7B97\u7EC4\u7EA7\u522B\u7684\u5143\u4FE1\u606F\uFF08\u7528\u4E8E verbose \u6A21\u5F0F\uFF09\n const groupMetaInfo = (() => {\n if (!isCompleted) return null\n\n // \u83B7\u53D6\u6240\u6709\u5DF2\u5B8C\u6210\u4EFB\u52A1\u7684 transcript\n const completedTranscripts: AgentTranscript[] = []\n for (const info of memberInfos) {\n if (info.agentId) {\n const transcript = getTranscriptForAgent(info.agentId)\n if (transcript?.endTime) {\n completedTranscripts.push(transcript)\n }\n }\n }\n\n if (completedTranscripts.length === 0) return null\n\n // \u8BA1\u7B97\u603B\u8017\u65F6\uFF08\u4ECE\u6700\u65E9\u5F00\u59CB\u5230\u6700\u665A\u7ED3\u675F\uFF09\n const startTimes = completedTranscripts.map(t => t.startTime)\n const endTimes = completedTranscripts.map(t => t.endTime!)\n const earliestStart = Math.min(...startTimes)\n const latestEnd = Math.max(...endTimes)\n const totalDuration = latestEnd - earliestStart\n\n return {\n duration: totalDuration,\n timestamp: latestEnd,\n }\n })()\n\n return (\n <Box flexDirection=\"column\" width=\"100%\" marginTop={MARGIN_BEFORE_MODULE}>\n {/* Module header - \u4F7F\u7528 REPL \u89C4\u8303\u7B26\u53F7 */}\n <Box flexDirection=\"row\">\n {/* \u4F7F\u7528 \u25C8 \u4F5C\u4E3A\u5E76\u884C\u4EFB\u52A1\u7EC4\u7B26\u53F7\uFF0C\u5B8C\u6210\u65F6\u4F7F\u7528 \u2713 */}\n <Text color={statusColor}>{groupSymbol} </Text>\n <Text bold color={SEMANTIC_COLORS.secondary}>\n Parallel Tasks\n </Text>\n <Text> </Text>\n {/* \u8FDB\u5EA6\u6570\u5B57\uFF1A\u5B8C\u6210\u6570\u7528 success \u8272\uFF0C\u603B\u6570\u7528 dim \u8272 */}\n <Text>(</Text>\n <Text color={SYMBOL_COLORS.success}>{completedCount}</Text>\n <Text color={SEMANTIC_COLORS.dim}>/{totalCount}</Text>\n <Text> finished)</Text>\n {/* Verbose mode: \u663E\u793A\u7EC4\u7EA7\u522B\u7684\u5143\u4FE1\u606F */}\n {displayConfig.showMetaInfo && groupMetaInfo && (\n <Text color={VALUE_TIER_COLORS.meta}>\n {' '}\n {formatMetaInfo({\n duration: groupMetaInfo.duration,\n timestamp: groupMetaInfo.timestamp,\n })}\n </Text>\n )}\n {/* Show expand hint in normal mode when completed */}\n <CollapsibleHint\n canExpand={isCompleted && !displayConfig.showAllChildren}\n />\n </Box>\n\n {/* Member tasks - \u4F7F\u7528 REPL \u89C4\u8303\u5B9A\u4E49\u7684\u7F29\u8FDB\u5C42\u7EA7 L1 */}\n <Box flexDirection=\"column\" marginLeft={INDENT_LEVELS.L1}>\n {memberInfos.map((info, index) => {\n const isLast = index === memberInfos.length - 1\n const transcript = info.agentId\n ? getTranscriptForAgent(info.agentId)\n : null\n const output = outputs.get(info.toolUseId)\n\n return (\n <Box key={info.toolUseId} flexDirection=\"row\">\n {/* Tree connector */}\n <TreeConnector isLast={isLast} />\n\n {/* Task content */}\n <TaskInModuleView\n toolUseId={info.toolUseId}\n description={info.description}\n agentType={info.agentType}\n transcript={transcript}\n output={output || null}\n config={displayConfig}\n shouldAnimate={shouldAnimate}\n inModule={true}\n isLastInModule={isLast}\n />\n </Box>\n )\n })}\n </Box>\n </Box>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Parallel Tasks Group View\n *\n * Renders a group of concurrent tasks as a unified module.\n * Displays completion progress and individual task status.\n */\n\nimport React from 'react'\nimport { Box, Text } from 'ink'\nimport type { ToolResultBlockParam } from '@anthropic-ai/sdk/resources/index.mjs'\nimport type { MessageGroup, DisplayConfig } from '@minto-types/messageGroup'\nimport type { AgentTranscript } from '@utils/agentTranscripts'\nimport type { NormalizedMessage } from '@utils/messages'\nimport { ToolUseLoader } from '@components/ToolUseLoader'\nimport { CollapsibleHint } from '@components/CollapsibleHint'\nimport { TaskInModuleView } from './TaskInModuleView'\nimport { ParallelTasksHandler } from '@utils/groupHandlers/parallelTasksHandler'\nimport { MARGIN_BEFORE_MODULE, INDENT_LEVELS } from '@constants/formatRules'\nimport { SYMBOLS } from '@constants/symbols'\nimport {\n SEMANTIC_COLORS,\n STATUS_COLORS,\n VALUE_TIER_COLORS,\n SYMBOL_COLORS,\n} from '@constants/colors'\nimport { formatMetaInfo } from '@utils/taskDisplayUtils'\n\ninterface Props {\n /** The parallel tasks group */\n group: MessageGroup\n /** Normalized messages for looking up task info */\n messages: NormalizedMessage[]\n /** Transcripts by agentId */\n transcripts: Map<string, AgentTranscript>\n /** Outputs by toolUseId */\n outputs: Map<string, ToolResultBlockParam>\n /** Display configuration */\n displayConfig: DisplayConfig\n /** Whether to animate */\n shouldAnimate: boolean\n /**\n * Function to get transcript by agentId with lazy loading from disk.\n * Essential for loading historical transcripts that aren't in memory.\n */\n getTranscript?: (agentId: string) => AgentTranscript | null\n}\n\nexport function ParallelTasksGroupView({\n group,\n messages,\n transcripts,\n outputs,\n displayConfig,\n shouldAnimate,\n getTranscript,\n}: Props): React.ReactNode {\n const memberIds = (group.metadata.siblingToolUseIds as string[]) || []\n\n // Helper to get transcript - use getTranscript for lazy loading, fallback to Map\n const getTranscriptForAgent = (agentId: string): AgentTranscript | null => {\n return getTranscript?.(agentId) ?? transcripts.get(agentId) ?? null\n }\n\n // Get task info for each member\n const memberInfos = ParallelTasksHandler.getMemberTaskInfo(group, messages)\n\n // Detect if this is a team agent group (vs regular parallel tasks)\n const isTeamGroup = memberInfos.some(info => !!info.teamName)\n\n // Count completions - check both transcript status AND output existence\n const completedCount = memberInfos.filter(info => {\n // Check if output exists (definitive completion signal)\n const output = outputs.get(info.toolUseId)\n if (output) return true\n\n // Fallback to transcript status\n if (!info.agentId) return false\n const transcript = getTranscriptForAgent(info.agentId)\n return transcript?.status === 'completed'\n }).length\n\n const totalCount = memberInfos.length\n\n // Determine completion status - use actual completion count as primary signal\n // This is more reliable than group.status which may have timing issues\n const isCompleted = completedCount === totalCount && totalCount > 0\n\n // \u4F7F\u7528 SYMBOL_COLORS \u4E0E Logo \u54C1\u724C\u914D\u8272\u4FDD\u6301\u4E00\u81F4\n const statusColor = isCompleted\n ? SYMBOL_COLORS.success\n : group.status === 'running'\n ? SYMBOL_COLORS.running\n : SYMBOL_COLORS.pending\n\n // \u8BA1\u7B97\u7EC4\u7EA7\u522B\u7684\u5143\u4FE1\u606F\uFF08\u7528\u4E8E verbose \u6A21\u5F0F\uFF09\n const groupMetaInfo = (() => {\n if (!isCompleted) return null\n\n // \u83B7\u53D6\u6240\u6709\u5DF2\u5B8C\u6210\u4EFB\u52A1\u7684 transcript\n const completedTranscripts: AgentTranscript[] = []\n for (const info of memberInfos) {\n if (info.agentId) {\n const transcript = getTranscriptForAgent(info.agentId)\n if (transcript?.endTime) {\n completedTranscripts.push(transcript)\n }\n }\n }\n\n if (completedTranscripts.length === 0) return null\n\n // \u8BA1\u7B97\u603B\u8017\u65F6\uFF08\u4ECE\u6700\u65E9\u5F00\u59CB\u5230\u6700\u665A\u7ED3\u675F\uFF09\n const startTimes = completedTranscripts.map(t => t.startTime)\n const endTimes = completedTranscripts.map(t => t.endTime!)\n const earliestStart = Math.min(...startTimes)\n const latestEnd = Math.max(...endTimes)\n const totalDuration = latestEnd - earliestStart\n\n return {\n duration: totalDuration,\n timestamp: latestEnd,\n }\n })()\n\n return (\n <Box flexDirection=\"column\" width=\"100%\" marginTop={MARGIN_BEFORE_MODULE}>\n {/* Module header - animated spinner when running, \u2713 when done */}\n <Box flexDirection=\"row\">\n {isCompleted ? (\n <Text color={SYMBOL_COLORS.success}>{SYMBOLS.TOOL_SUCCESS} </Text>\n ) : (\n <ToolUseLoader\n shouldAnimate={shouldAnimate}\n isUnresolved={true}\n isError={false}\n />\n )}\n {isTeamGroup ? (\n <>\n <Text bold color={SEMANTIC_COLORS.secondary}>\n {totalCount} agent{totalCount !== 1 ? 's' : ''} working\n </Text>\n {!isCompleted && (\n <>\n <Text> </Text>\n <Text>(</Text>\n <Text color={SYMBOL_COLORS.success}>{completedCount}</Text>\n <Text color={SEMANTIC_COLORS.dim}>/{totalCount}</Text>\n <Text> done)</Text>\n </>\n )}\n </>\n ) : (\n <>\n <Text bold color={SEMANTIC_COLORS.secondary}>\n Parallel Tasks\n </Text>\n <Text> </Text>\n <Text>(</Text>\n <Text color={SYMBOL_COLORS.success}>{completedCount}</Text>\n <Text color={SEMANTIC_COLORS.dim}>/{totalCount}</Text>\n <Text> done)</Text>\n </>\n )}\n {/* Verbose mode: \u663E\u793A\u7EC4\u7EA7\u522B\u7684\u5143\u4FE1\u606F */}\n {displayConfig.showMetaInfo && groupMetaInfo && (\n <Text color={VALUE_TIER_COLORS.meta}>\n {' '}\n {formatMetaInfo({\n duration: groupMetaInfo.duration,\n timestamp: groupMetaInfo.timestamp,\n })}\n </Text>\n )}\n {/* Show expand hint in normal mode when completed */}\n <CollapsibleHint\n canExpand={isCompleted && !displayConfig.showAllChildren}\n shortcut={undefined}\n />\n </Box>\n\n {/* Member tasks - \u4F7F\u7528 REPL \u89C4\u8303\u5B9A\u4E49\u7684\u7F29\u8FDB\u5C42\u7EA7 L1 */}\n <Box flexDirection=\"column\" marginLeft={INDENT_LEVELS.L1}>\n {memberInfos.map((info, index) => {\n const isLast = index === memberInfos.length - 1\n const transcript = info.agentId\n ? getTranscriptForAgent(info.agentId)\n : null\n const output = outputs.get(info.toolUseId)\n\n return (\n <Box key={info.toolUseId} flexDirection=\"column\">\n <TaskInModuleView\n toolUseId={info.toolUseId}\n description={\n isTeamGroup && info.teammateName\n ? `@${info.teammateName}`\n : info.description\n }\n agentType={info.agentType}\n transcript={transcript}\n output={output || null}\n config={displayConfig}\n shouldAnimate={shouldAnimate}\n inModule={true}\n isLastInModule={isLast}\n />\n </Box>\n )\n })}\n </Box>\n </Box>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  import React, { useState, useEffect } from "react";
2
2
  import { Box, Text } from "ink";
3
3
  import { ToolUseLoader } from "../ToolUseLoader.js";
4
- import { TreeContinuation } from "../TreeConnector.js";
4
+ import { TreeConnector, TreeContinuation } from "../TreeConnector.js";
5
5
  import { TaskToolMessage } from "./TaskToolMessage.js";
6
6
  import {
7
7
  getTaskDisplayContent,
@@ -12,7 +12,11 @@ import {
12
12
  truncate,
13
13
  formatMetaInfo
14
14
  } from "../../utils/taskDisplayUtils.js";
15
- import { formatDuration } from "../../utils/format.js";
15
+ import {
16
+ formatDuration,
17
+ formatBidirectionalTokens,
18
+ formatNumber
19
+ } from "../../utils/format.js";
16
20
  import { NestedTasksPreview } from "./NestedTasksPreview.js";
17
21
  import { TaskOutputContent, TaskOutputSummary } from "./TaskOutputContent.js";
18
22
  import { CollapsibleHint } from "../CollapsibleHint.js";
@@ -23,22 +27,6 @@ import {
23
27
  VALUE_TIER_COLORS,
24
28
  SYMBOL_COLORS
25
29
  } from "../../constants/colors.js";
26
- function formatTokens(count) {
27
- if (count >= 1e3) {
28
- return `${(count / 1e3).toFixed(1)}k`;
29
- }
30
- return String(count);
31
- }
32
- function formatBidirectionalTokens(inputTokens, outputTokens) {
33
- const parts = [];
34
- if (inputTokens > 0) {
35
- parts.push(`\u2191${formatTokens(inputTokens)}`);
36
- }
37
- if (outputTokens > 0) {
38
- parts.push(`\u2193${formatTokens(outputTokens)}`);
39
- }
40
- return parts.join(" ");
41
- }
42
30
  function ToolUseHistoryDisplay({
43
31
  transcript,
44
32
  config,
@@ -93,6 +81,18 @@ function TaskInModuleView({
93
81
  inModule = false,
94
82
  isLastInModule = false
95
83
  }) {
84
+ const isBackgroundAgent = (() => {
85
+ if (transcript?.metadata?.isBackground) return true;
86
+ const content = output?.content;
87
+ if (typeof content === "string")
88
+ return content.includes("running in background");
89
+ if (Array.isArray(content)) {
90
+ return content.some(
91
+ (c) => c.type === "text" && typeof c.text === "string" && c.text.includes("running in background")
92
+ );
93
+ }
94
+ return false;
95
+ })();
96
96
  const transcriptStatus = transcript?.status || "pending";
97
97
  const status = output && transcriptStatus === "pending" ? "completed" : transcriptStatus;
98
98
  const statusIcon = getStatusIcon(status);
@@ -135,14 +135,14 @@ function TaskInModuleView({
135
135
  isUnresolved: !isCompleted,
136
136
  isError
137
137
  }
138
- ), inModule && /* @__PURE__ */ React.createElement(Text, { color: statusColor }, statusIcon, " "), /* @__PURE__ */ React.createElement(
138
+ ), inModule && /* @__PURE__ */ React.createElement(TreeConnector, { isLast: isLastInModule }), inModule && /* @__PURE__ */ React.createElement(Text, { color: statusColor }, statusIcon, " "), /* @__PURE__ */ React.createElement(
139
139
  TaskToolMessage,
140
140
  {
141
141
  agentType,
142
142
  bold: true,
143
143
  children: description
144
144
  }
145
- ), inModule && isCompleted && transcript && /* @__PURE__ */ React.createElement(React.Fragment, null, config.showMetaInfo ? (
145
+ ), inModule && isCompleted && transcript && !isBackgroundAgent && /* @__PURE__ */ React.createElement(React.Fragment, null, config.showMetaInfo ? (
146
146
  // Verbose mode: 使用 formatMetaInfo 显示 "耗时 · 模型 · 时间"
147
147
  /* @__PURE__ */ React.createElement(Text, { color: VALUE_TIER_COLORS.meta }, " ", "(", formatMetaInfo({
148
148
  duration: transcript.endTime ? transcript.endTime - transcript.startTime : void 0,
@@ -150,7 +150,7 @@ function TaskInModuleView({
150
150
  timestamp: transcript.endTime
151
151
  }), transcript.toolUseCount > 0 && ` \xB7 ${formatCount(transcript.toolUseCount, "tool")}`, ")")
152
152
  ) : (
153
- // Normal mode: compact stats with bidirectional tokens
153
+ // Normal mode: compact stats with output tokens
154
154
  /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " ", "(", formatStats([
155
155
  formatCount(transcript.toolUseCount, "tool"),
156
156
  formatBidirectionalTokens(
@@ -159,13 +159,13 @@ function TaskInModuleView({
159
159
  ),
160
160
  duration
161
161
  ]), ")")
162
- )), inModule && status === "running" && transcript && /* @__PURE__ */ React.createElement(Text, { color: VALUE_TIER_COLORS.meta }, " ", "(", config.showMetaInfo ? formatMetaInfo({
162
+ )), inModule && status === "running" && transcript && !isBackgroundAgent && /* @__PURE__ */ React.createElement(Text, { color: VALUE_TIER_COLORS.meta }, " ", "(", config.showMetaInfo ? formatMetaInfo({
163
163
  model: transcript.model,
164
164
  timestamp: Date.now()
165
165
  }) : formatStats([
166
166
  transcript.toolUseCount > 0 ? formatCount(transcript.toolUseCount, "tool") : null,
167
167
  duration,
168
- // Show bidirectional tokens: ↑input ↓output
168
+ // Show output tokens: X tokens
169
169
  formatBidirectionalTokens(
170
170
  transcript.tokenUsage.inputTokens,
171
171
  transcript.tokenUsage.outputTokens
@@ -176,14 +176,14 @@ function TaskInModuleView({
176
176
  duration: transcript.endTime ? transcript.endTime - transcript.startTime : void 0,
177
177
  model: transcript.model,
178
178
  timestamp: transcript.endTime || Date.now()
179
- }), " \xB7 ", "Tools: ", transcript.toolUseCount, " \xB7 Tokens:", " ", formatTokens(totalTokens))
179
+ }), " \xB7 ", "Tools: ", transcript.toolUseCount, " \xB7 Tokens:", " ", formatNumber(totalTokens))
180
180
  ) : (
181
- // Normal mode: compact display with bidirectional tokens
181
+ // Normal mode: compact display with output tokens
182
182
  /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, status === "completed" ? "\u2713" : "\u22EF", " Tools:", " ", transcript.toolUseCount, " |", " ", formatBidirectionalTokens(
183
183
  transcript.tokenUsage.inputTokens,
184
184
  transcript.tokenUsage.outputTokens
185
185
  ), duration ? ` | ${duration}` : "")
186
- )), transcript && /* @__PURE__ */ React.createElement(
186
+ )), transcript && (!isBackgroundAgent || config.showAllChildren) && /* @__PURE__ */ React.createElement(
187
187
  ToolUseHistoryDisplay,
188
188
  {
189
189
  transcript,
@@ -198,7 +198,7 @@ function TaskInModuleView({
198
198
  tasks: displayContent.children || [],
199
199
  hiddenCount: displayContent.hiddenCount || 0
200
200
  }
201
- ))), output && isCompleted && /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, inModule && /* @__PURE__ */ React.createElement(TreeContinuation, { parentIsLast: isLastInModule }), !inModule && /* @__PURE__ */ React.createElement(Box, { minWidth: 4 }), /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, config.showAllChildren ? (
201
+ ))), output && isCompleted && !isBackgroundAgent && /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, inModule && /* @__PURE__ */ React.createElement(TreeContinuation, { parentIsLast: isLastInModule }), !inModule && /* @__PURE__ */ React.createElement(Box, { minWidth: 4 }), /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, config.showAllChildren ? (
202
202
  // Verbose mode: show full output with header
203
203
  /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "Output \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"), /* @__PURE__ */ React.createElement(Box, { marginLeft: 2 }, /* @__PURE__ */ React.createElement(TaskOutputContent, { content: output.content })))
204
204
  ) : (