@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
@@ -0,0 +1,272 @@
1
+ import { Box, Text, useInput } from "ink";
2
+ import * as React from "react";
3
+ import { useMemo, useState } from "react";
4
+ import figures from "figures";
5
+ import { basename } from "path";
6
+ import { BRAND_GRADIENT, SEMANTIC_COLORS } from "../constants/colors.js";
7
+ import { t } from "../i18n/index.js";
8
+ const FILE_TOOLS = /* @__PURE__ */ new Set(["Write", "Edit", "MultiEdit", "NotebookEdit"]);
9
+ function extractFileChangesForTurn(messages, fromIndex, toIndex) {
10
+ const files = /* @__PURE__ */ new Set();
11
+ for (let i = fromIndex; i < toIndex; i++) {
12
+ const msg = messages[i];
13
+ if (!msg || msg.type !== "assistant") continue;
14
+ const content = msg.message.content;
15
+ if (!Array.isArray(content)) continue;
16
+ for (const block of content) {
17
+ if (block.type !== "tool_use") continue;
18
+ if (!FILE_TOOLS.has(block.name)) continue;
19
+ const input = block.input;
20
+ const filePath = input?.file_path ?? input?.notebook_path;
21
+ if (typeof filePath === "string") {
22
+ files.add(basename(filePath));
23
+ }
24
+ }
25
+ }
26
+ return Array.from(files);
27
+ }
28
+ function stripXmlForDisplay(raw) {
29
+ if (raw.includes("<command-name>") || raw.includes("<command-message>")) {
30
+ const cmdMatch = raw.match(/<command-message>([\s\S]*?)<\/command-message>/);
31
+ const argsMatch = raw.match(/<command-args>([\s\S]*?)<\/command-args>/);
32
+ const cmd = cmdMatch?.[1]?.trim() ?? "";
33
+ const args = argsMatch?.[1]?.trim() ?? "";
34
+ return cmd ? `/${cmd}${args ? " " + args : ""}` : "";
35
+ }
36
+ return raw.replace(/<system-reminder>[\s\S]*?<\/system-reminder>\s*/g, "").replace(/<local-command-caveat>[\s\S]*?<\/local-command-caveat>\s*/g, "").replace(/<local-command-stdout>[\s\S]*?<\/local-command-stdout>\s*/g, "").replace(/<task-notification>[\s\S]*?<\/task-notification>\s*/g, "").replace(/<user-guidance>\n?([\s\S]*?)\n?<\/user-guidance>/g, "$1").replace(/<team-message\s+[^>]*>([\s\S]*?)<\/team-message>/g, "").replace(/<bash-input>[\s\S]*?<\/bash-input>\s*/g, "").replace(/<koding-input>[\s\S]*?<\/koding-input>\s*/g, "").replace(
37
+ /<available-deferred-tools>[\s\S]*?<\/available-deferred-tools>\s*/g,
38
+ ""
39
+ ).replace(/<command-name>[\s\S]*?<\/command-name>\s*/g, "").replace(/<command-message>[\s\S]*?<\/command-message>\s*/g, "").replace(/<command-args>[\s\S]*?<\/command-args>\s*/g, "").trim();
40
+ }
41
+ function getUserText(msg) {
42
+ const content = msg.message.content;
43
+ if (typeof content === "string") return stripXmlForDisplay(content);
44
+ if (Array.isArray(content)) {
45
+ for (const block of content) {
46
+ if (block.type === "text") return stripXmlForDisplay(block.text);
47
+ }
48
+ }
49
+ return "";
50
+ }
51
+ function getRewindPoints(messages) {
52
+ const points = [];
53
+ const userIndices = [];
54
+ for (let i = 0; i < messages.length; i++) {
55
+ const msg = messages[i];
56
+ if (msg?.type === "user" && !(Array.isArray(msg.message.content) && msg.message.content[0]?.type === "tool_result")) {
57
+ userIndices.push(i);
58
+ }
59
+ }
60
+ for (let i = 0; i < userIndices.length; i++) {
61
+ const idx = userIndices[i];
62
+ const msg = messages[idx];
63
+ const nextIdx = i + 1 < userIndices.length ? userIndices[i + 1] : messages.length;
64
+ points.push({
65
+ userMessage: msg,
66
+ messageIndex: idx,
67
+ userText: getUserText(msg),
68
+ changedFiles: extractFileChangesForTurn(messages, idx, nextIdx)
69
+ });
70
+ }
71
+ return points;
72
+ }
73
+ const MAX_VISIBLE = 8;
74
+ const MAX_TEXT_LENGTH = 120;
75
+ function RewindPanel({
76
+ messages,
77
+ onAction,
78
+ onEscape
79
+ }) {
80
+ const rewindPoints = useMemo(() => getRewindPoints(messages), [messages]);
81
+ const [phase, setPhase] = useState(
82
+ "message_select"
83
+ );
84
+ const totalItems = rewindPoints.length + 1;
85
+ const [selectedIndex, setSelectedIndex] = useState(rewindPoints.length);
86
+ const [actionIndex, setActionIndex] = useState(0);
87
+ const [selectedPoint, setSelectedPoint] = useState(null);
88
+ useInput((input, key) => {
89
+ if (phase === "message_select") {
90
+ if (key.escape) {
91
+ onEscape();
92
+ return;
93
+ }
94
+ if (key.upArrow) {
95
+ setSelectedIndex((prev) => Math.max(0, prev - 1));
96
+ return;
97
+ }
98
+ if (key.downArrow) {
99
+ setSelectedIndex((prev) => Math.min(totalItems - 1, prev + 1));
100
+ return;
101
+ }
102
+ if (key.return) {
103
+ if (selectedIndex >= rewindPoints.length) {
104
+ onEscape();
105
+ return;
106
+ }
107
+ const point = rewindPoints[selectedIndex];
108
+ if (point) {
109
+ setSelectedPoint(point);
110
+ setPhase("action_select");
111
+ setActionIndex(0);
112
+ }
113
+ return;
114
+ }
115
+ } else if (phase === "action_select") {
116
+ if (key.escape) {
117
+ setPhase("message_select");
118
+ return;
119
+ }
120
+ if (key.upArrow) {
121
+ setActionIndex((prev) => Math.max(0, prev - 1));
122
+ return;
123
+ }
124
+ if (key.downArrow) {
125
+ setActionIndex((prev) => Math.min(4, prev + 1));
126
+ return;
127
+ }
128
+ if (key.return && selectedPoint) {
129
+ const actions = [
130
+ "restore_code_and_conversation",
131
+ "restore_conversation",
132
+ "restore_code",
133
+ "summarize_from_here",
134
+ "never_mind"
135
+ ];
136
+ onAction(actions[actionIndex], selectedPoint);
137
+ return;
138
+ }
139
+ const num = Number(input);
140
+ if (num >= 1 && num <= 5 && selectedPoint) {
141
+ const actions = [
142
+ "restore_code_and_conversation",
143
+ "restore_conversation",
144
+ "restore_code",
145
+ "summarize_from_here",
146
+ "never_mind"
147
+ ];
148
+ onAction(actions[num - 1], selectedPoint);
149
+ return;
150
+ }
151
+ }
152
+ });
153
+ if (phase === "message_select") {
154
+ const firstVisible = Math.max(
155
+ 0,
156
+ Math.min(
157
+ selectedIndex - Math.floor(MAX_VISIBLE / 2),
158
+ totalItems - MAX_VISIBLE
159
+ )
160
+ );
161
+ const lastVisible = Math.min(totalItems, firstVisible + MAX_VISIBLE);
162
+ return /* @__PURE__ */ React.createElement(
163
+ Box,
164
+ {
165
+ flexDirection: "column",
166
+ borderStyle: "round",
167
+ borderColor: BRAND_GRADIENT.START,
168
+ paddingX: 1,
169
+ paddingY: 1
170
+ },
171
+ /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: BRAND_GRADIENT.START }, t("rewind.title")), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, t("rewind.selectMessage"))),
172
+ Array.from({ length: lastVisible - firstVisible }, (_, i) => {
173
+ const itemIndex = firstVisible + i;
174
+ const isSelected = itemIndex === selectedIndex;
175
+ const isCurrent = itemIndex >= rewindPoints.length;
176
+ if (isCurrent) {
177
+ return /* @__PURE__ */ React.createElement(Box, { key: "current", marginBottom: 0 }, /* @__PURE__ */ React.createElement(
178
+ Text,
179
+ {
180
+ color: isSelected ? BRAND_GRADIENT.START : SEMANTIC_COLORS.dim,
181
+ bold: isSelected
182
+ },
183
+ isSelected ? `${figures.pointer} ` : " "
184
+ ), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim, italic: true }, t("dialog.current")));
185
+ }
186
+ const point = rewindPoints[itemIndex];
187
+ if (!point) return null;
188
+ const displayText = point.userText.replace(/\n/g, " ").slice(0, MAX_TEXT_LENGTH);
189
+ const truncated = point.userText.length > MAX_TEXT_LENGTH ? displayText + "\u2026" : displayText;
190
+ return /* @__PURE__ */ React.createElement(
191
+ Box,
192
+ {
193
+ key: point.userMessage.uuid,
194
+ flexDirection: "column",
195
+ marginBottom: 0
196
+ },
197
+ /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(
198
+ Text,
199
+ {
200
+ color: isSelected ? BRAND_GRADIENT.START : void 0,
201
+ bold: isSelected
202
+ },
203
+ isSelected ? `${figures.pointer} ` : " "
204
+ ), /* @__PURE__ */ React.createElement(
205
+ Text,
206
+ {
207
+ color: isSelected ? BRAND_GRADIENT.START : void 0,
208
+ wrap: "truncate"
209
+ },
210
+ truncated || t("dialog.emptyMessage")
211
+ )),
212
+ /* @__PURE__ */ React.createElement(Box, { marginLeft: 3 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, point.changedFiles.length === 0 ? t("rewind.noCodeChanges") : point.changedFiles.join(", ")))
213
+ );
214
+ }),
215
+ firstVisible > 0 && /* @__PURE__ */ React.createElement(Box, { marginLeft: 2 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, figures.arrowUp, " ", t("rewind.moreAbove"))),
216
+ lastVisible < totalItems && /* @__PURE__ */ React.createElement(Box, { marginLeft: 2 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, figures.arrowDown, " ", t("rewind.moreBelow"))),
217
+ /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, t("rewind.enterToContinue"), " \xB7 ", t("rewind.escToExit")))
218
+ );
219
+ }
220
+ if (!selectedPoint) return null;
221
+ const confirmText = selectedPoint.userText.replace(/\n/g, " ").slice(0, 100);
222
+ const confirmDisplay = selectedPoint.userText.length > 100 ? confirmText + "\u2026" : confirmText;
223
+ const actionLabels = [
224
+ t("rewind.action.restoreCodeAndConversation"),
225
+ t("rewind.action.restoreConversation"),
226
+ t("rewind.action.restoreCode"),
227
+ t("rewind.action.summarizeFromHere"),
228
+ t("rewind.action.neverMind")
229
+ ];
230
+ return /* @__PURE__ */ React.createElement(
231
+ Box,
232
+ {
233
+ flexDirection: "column",
234
+ borderStyle: "round",
235
+ borderColor: BRAND_GRADIENT.START,
236
+ paddingX: 1,
237
+ paddingY: 1
238
+ },
239
+ /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: BRAND_GRADIENT.START }, t("rewind.title")), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, t("rewind.confirmRestore"))),
240
+ /* @__PURE__ */ React.createElement(Box, { marginBottom: 1, marginLeft: 1 }, /* @__PURE__ */ React.createElement(
241
+ Box,
242
+ {
243
+ borderStyle: "single",
244
+ borderColor: SEMANTIC_COLORS.dim,
245
+ borderLeft: true,
246
+ borderRight: false,
247
+ borderTop: false,
248
+ borderBottom: false,
249
+ paddingLeft: 1
250
+ },
251
+ /* @__PURE__ */ React.createElement(Text, null, confirmDisplay)
252
+ )),
253
+ /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginBottom: 1, marginLeft: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, t("rewind.conversationWillBeForked")), selectedPoint.changedFiles.length > 0 ? /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, t("rewind.codeWillBeRestored"), " ", selectedPoint.changedFiles.join(", "), ".") : /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, t("rewind.noCodeChanges"))),
254
+ actionLabels.map((label, i) => /* @__PURE__ */ React.createElement(Box, { key: i }, /* @__PURE__ */ React.createElement(
255
+ Text,
256
+ {
257
+ color: i === actionIndex ? BRAND_GRADIENT.START : void 0,
258
+ bold: i === actionIndex
259
+ },
260
+ i === actionIndex ? `${figures.pointer} ` : " ",
261
+ i + 1,
262
+ ". ",
263
+ label
264
+ ))),
265
+ /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.error }, t("rewind.bashWarning")))
266
+ );
267
+ }
268
+ export {
269
+ RewindPanel,
270
+ getRewindPoints
271
+ };
272
+ //# sourceMappingURL=RewindPanel.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/components/RewindPanel.tsx"],
4
+ "sourcesContent": ["/**\n * RewindPanel \u2014 CC-compatible Rewind/Checkpoint UI\n *\n * Two-phase overlay:\n * 1. Message Select: scrollable list of user prompts with file change summaries\n * 2. Action Select: 5 options (restore code+convo, convo only, code only, summarize, cancel)\n *\n * Activation: Double-Esc or /rewind command\n * Boundaries: Only shows messages since last /clear or /compact (naturally enforced\n * because those operations truncate the messages array).\n */\n\nimport { Box, Text, useInput } from 'ink'\nimport * as React from 'react'\nimport { useMemo, useState } from 'react'\nimport figures from 'figures'\nimport { basename } from 'path'\nimport { BRAND_GRADIENT, SEMANTIC_COLORS } from '@constants/colors'\nimport { t } from '@i18n'\nimport type { Message, UserMessage } from '@query'\n\n// \u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface RewindPoint {\n /** The original user message */\n userMessage: UserMessage\n /** Index in the messages array */\n messageIndex: number\n /** Plain text of the user prompt (for display) */\n userText: string\n /** File paths modified in this turn (basename only) */\n changedFiles: string[]\n}\n\nexport type RewindAction =\n | 'restore_code_and_conversation'\n | 'restore_conversation'\n | 'restore_code'\n | 'summarize_from_here'\n | 'never_mind'\n\ninterface Props {\n messages: Message[]\n onAction: (action: RewindAction, point: RewindPoint) => void\n onEscape: () => void\n}\n\n// \u2500\u2500 Utilities \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Tool names that modify files on disk */\nconst FILE_TOOLS = new Set(['Write', 'Edit', 'MultiEdit', 'NotebookEdit'])\n\n/**\n * Extract file paths changed between two message indices.\n * Scans assistant messages for file-modifying tool_use blocks.\n */\nfunction extractFileChangesForTurn(\n messages: Message[],\n fromIndex: number,\n toIndex: number,\n): string[] {\n const files = new Set<string>()\n\n for (let i = fromIndex; i < toIndex; i++) {\n const msg = messages[i]\n if (!msg || msg.type !== 'assistant') continue\n\n const content = msg.message.content\n if (!Array.isArray(content)) continue\n\n for (const block of content) {\n if (block.type !== 'tool_use') continue\n if (!FILE_TOOLS.has(block.name)) continue\n\n const input = block.input as Record<string, unknown>\n const filePath = (input?.file_path ?? input?.notebook_path) as\n | string\n | undefined\n if (typeof filePath === 'string') {\n files.add(basename(filePath))\n }\n }\n }\n\n return Array.from(files)\n}\n\n/** Strip XML tags to extract display-friendly text, mirroring REPL rendering */\nfunction stripXmlForDisplay(raw: string): string {\n // Command messages \u2192 show as \"/<command> <args>\"\n if (raw.includes('<command-name>') || raw.includes('<command-message>')) {\n const cmdMatch = raw.match(/<command-message>([\\s\\S]*?)<\\/command-message>/)\n const argsMatch = raw.match(/<command-args>([\\s\\S]*?)<\\/command-args>/)\n const cmd = cmdMatch?.[1]?.trim() ?? ''\n const args = argsMatch?.[1]?.trim() ?? ''\n return cmd ? `/${cmd}${args ? ' ' + args : ''}` : ''\n }\n\n // Strip all known system/protocol XML tags, keep remaining plain text\n return raw\n .replace(/<system-reminder>[\\s\\S]*?<\\/system-reminder>\\s*/g, '')\n .replace(/<local-command-caveat>[\\s\\S]*?<\\/local-command-caveat>\\s*/g, '')\n .replace(/<local-command-stdout>[\\s\\S]*?<\\/local-command-stdout>\\s*/g, '')\n .replace(/<task-notification>[\\s\\S]*?<\\/task-notification>\\s*/g, '')\n .replace(/<user-guidance>\\n?([\\s\\S]*?)\\n?<\\/user-guidance>/g, '$1')\n .replace(/<team-message\\s+[^>]*>([\\s\\S]*?)<\\/team-message>/g, '')\n .replace(/<bash-input>[\\s\\S]*?<\\/bash-input>\\s*/g, '')\n .replace(/<koding-input>[\\s\\S]*?<\\/koding-input>\\s*/g, '')\n .replace(\n /<available-deferred-tools>[\\s\\S]*?<\\/available-deferred-tools>\\s*/g,\n '',\n )\n .replace(/<command-name>[\\s\\S]*?<\\/command-name>\\s*/g, '')\n .replace(/<command-message>[\\s\\S]*?<\\/command-message>\\s*/g, '')\n .replace(/<command-args>[\\s\\S]*?<\\/command-args>\\s*/g, '')\n .trim()\n}\n\n/** Extract plain text from a user message */\nfunction getUserText(msg: UserMessage): string {\n const content = msg.message.content\n if (typeof content === 'string') return stripXmlForDisplay(content)\n if (Array.isArray(content)) {\n for (const block of content) {\n if (block.type === 'text') return stripXmlForDisplay(block.text)\n }\n }\n return ''\n}\n\n/**\n * Build rewind points from the messages array.\n * Each point is a user prompt (excluding tool results) with its\n * associated file changes extracted from the following assistant turn.\n */\nexport function getRewindPoints(messages: Message[]): RewindPoint[] {\n const points: RewindPoint[] = []\n\n // Collect indices of user messages (skip tool_result messages)\n const userIndices: number[] = []\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i]\n if (\n msg?.type === 'user' &&\n !(\n Array.isArray(msg.message.content) &&\n msg.message.content[0]?.type === 'tool_result'\n )\n ) {\n userIndices.push(i)\n }\n }\n\n for (let i = 0; i < userIndices.length; i++) {\n const idx = userIndices[i]!\n const msg = messages[idx] as UserMessage\n const nextIdx =\n i + 1 < userIndices.length ? userIndices[i + 1]! : messages.length\n\n points.push({\n userMessage: msg,\n messageIndex: idx,\n userText: getUserText(msg),\n changedFiles: extractFileChangesForTurn(messages, idx, nextIdx),\n })\n }\n\n return points\n}\n\n// \u2500\u2500 Constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst MAX_VISIBLE = 8\nconst MAX_TEXT_LENGTH = 120\n\n// \u2500\u2500 Component \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function RewindPanel({\n messages,\n onAction,\n onEscape,\n}: Props): React.ReactNode {\n const rewindPoints = useMemo(() => getRewindPoints(messages), [messages])\n\n const [phase, setPhase] = useState<'message_select' | 'action_select'>(\n 'message_select',\n )\n // Total items = rewindPoints + 1 (current). Default selection: (current)\n const totalItems = rewindPoints.length + 1\n const [selectedIndex, setSelectedIndex] = useState(rewindPoints.length)\n const [actionIndex, setActionIndex] = useState(0)\n const [selectedPoint, setSelectedPoint] = useState<RewindPoint | null>(null)\n\n useInput((input, key) => {\n if (phase === 'message_select') {\n if (key.escape) {\n onEscape()\n return\n }\n if (key.upArrow) {\n setSelectedIndex(prev => Math.max(0, prev - 1))\n return\n }\n if (key.downArrow) {\n setSelectedIndex(prev => Math.min(totalItems - 1, prev + 1))\n return\n }\n if (key.return) {\n // (current) = do nothing\n if (selectedIndex >= rewindPoints.length) {\n onEscape()\n return\n }\n const point = rewindPoints[selectedIndex]\n if (point) {\n setSelectedPoint(point)\n setPhase('action_select')\n setActionIndex(0)\n }\n return\n }\n } else if (phase === 'action_select') {\n if (key.escape) {\n setPhase('message_select')\n return\n }\n if (key.upArrow) {\n setActionIndex(prev => Math.max(0, prev - 1))\n return\n }\n if (key.downArrow) {\n setActionIndex(prev => Math.min(4, prev + 1))\n return\n }\n if (key.return && selectedPoint) {\n const actions: RewindAction[] = [\n 'restore_code_and_conversation',\n 'restore_conversation',\n 'restore_code',\n 'summarize_from_here',\n 'never_mind',\n ]\n onAction(actions[actionIndex]!, selectedPoint)\n return\n }\n // Number keys 1-5\n const num = Number(input)\n if (num >= 1 && num <= 5 && selectedPoint) {\n const actions: RewindAction[] = [\n 'restore_code_and_conversation',\n 'restore_conversation',\n 'restore_code',\n 'summarize_from_here',\n 'never_mind',\n ]\n onAction(actions[num - 1]!, selectedPoint)\n return\n }\n }\n })\n\n // \u2500\u2500 Phase 1: Message Select \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n if (phase === 'message_select') {\n const firstVisible = Math.max(\n 0,\n Math.min(\n selectedIndex - Math.floor(MAX_VISIBLE / 2),\n totalItems - MAX_VISIBLE,\n ),\n )\n const lastVisible = Math.min(totalItems, firstVisible + MAX_VISIBLE)\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={BRAND_GRADIENT.START}\n paddingX={1}\n paddingY={1}\n >\n {/* Header */}\n <Box flexDirection=\"column\" marginBottom={1}>\n <Text bold color={BRAND_GRADIENT.START}>\n {t('rewind.title')}\n </Text>\n <Text color={SEMANTIC_COLORS.secondary}>\n {t('rewind.selectMessage')}\n </Text>\n </Box>\n\n {/* Message list */}\n {Array.from({ length: lastVisible - firstVisible }, (_, i) => {\n const itemIndex = firstVisible + i\n const isSelected = itemIndex === selectedIndex\n const isCurrent = itemIndex >= rewindPoints.length\n\n if (isCurrent) {\n return (\n <Box key=\"current\" marginBottom={0}>\n <Text\n color={\n isSelected ? BRAND_GRADIENT.START : SEMANTIC_COLORS.dim\n }\n bold={isSelected}\n >\n {isSelected ? `${figures.pointer} ` : ' '}\n </Text>\n <Text color={SEMANTIC_COLORS.dim} italic>\n {t('dialog.current')}\n </Text>\n </Box>\n )\n }\n\n const point = rewindPoints[itemIndex]\n if (!point) return null\n\n const displayText = point.userText\n .replace(/\\n/g, ' ')\n .slice(0, MAX_TEXT_LENGTH)\n const truncated =\n point.userText.length > MAX_TEXT_LENGTH\n ? displayText + '\u2026'\n : displayText\n\n return (\n <Box\n key={point.userMessage.uuid}\n flexDirection=\"column\"\n marginBottom={0}\n >\n <Box>\n <Text\n color={isSelected ? BRAND_GRADIENT.START : undefined}\n bold={isSelected}\n >\n {isSelected ? `${figures.pointer} ` : ' '}\n </Text>\n <Text\n color={isSelected ? BRAND_GRADIENT.START : undefined}\n wrap=\"truncate\"\n >\n {truncated || t('dialog.emptyMessage')}\n </Text>\n </Box>\n <Box marginLeft={3}>\n <Text color={SEMANTIC_COLORS.dim}>\n {point.changedFiles.length === 0\n ? t('rewind.noCodeChanges')\n : point.changedFiles.join(', ')}\n </Text>\n </Box>\n </Box>\n )\n })}\n\n {/* Scroll indicators */}\n {firstVisible > 0 && (\n <Box marginLeft={2}>\n <Text color={SEMANTIC_COLORS.dim}>\n {figures.arrowUp} {t('rewind.moreAbove')}\n </Text>\n </Box>\n )}\n {lastVisible < totalItems && (\n <Box marginLeft={2}>\n <Text color={SEMANTIC_COLORS.dim}>\n {figures.arrowDown} {t('rewind.moreBelow')}\n </Text>\n </Box>\n )}\n\n {/* Footer */}\n <Box marginTop={1}>\n <Text color={SEMANTIC_COLORS.dim}>\n {t('rewind.enterToContinue')} \u00B7 {t('rewind.escToExit')}\n </Text>\n </Box>\n </Box>\n )\n }\n\n // \u2500\u2500 Phase 2: Action Select \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n if (!selectedPoint) return null\n\n const confirmText = selectedPoint.userText.replace(/\\n/g, ' ').slice(0, 100)\n const confirmDisplay =\n selectedPoint.userText.length > 100 ? confirmText + '\u2026' : confirmText\n\n const actionLabels = [\n t('rewind.action.restoreCodeAndConversation'),\n t('rewind.action.restoreConversation'),\n t('rewind.action.restoreCode'),\n t('rewind.action.summarizeFromHere'),\n t('rewind.action.neverMind'),\n ]\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={BRAND_GRADIENT.START}\n paddingX={1}\n paddingY={1}\n >\n {/* Header */}\n <Box flexDirection=\"column\" marginBottom={1}>\n <Text bold color={BRAND_GRADIENT.START}>\n {t('rewind.title')}\n </Text>\n <Text color={SEMANTIC_COLORS.secondary}>\n {t('rewind.confirmRestore')}\n </Text>\n </Box>\n\n {/* Selected message preview (quoted) */}\n <Box marginBottom={1} marginLeft={1}>\n <Box\n borderStyle=\"single\"\n borderColor={SEMANTIC_COLORS.dim}\n borderLeft={true}\n borderRight={false}\n borderTop={false}\n borderBottom={false}\n paddingLeft={1}\n >\n <Text>{confirmDisplay}</Text>\n </Box>\n </Box>\n\n {/* Change summary */}\n <Box flexDirection=\"column\" marginBottom={1} marginLeft={1}>\n <Text color={SEMANTIC_COLORS.secondary}>\n {t('rewind.conversationWillBeForked')}\n </Text>\n {selectedPoint.changedFiles.length > 0 ? (\n <Text color={SEMANTIC_COLORS.secondary}>\n {t('rewind.codeWillBeRestored')}{' '}\n {selectedPoint.changedFiles.join(', ')}.\n </Text>\n ) : (\n <Text color={SEMANTIC_COLORS.dim}>{t('rewind.noCodeChanges')}</Text>\n )}\n </Box>\n\n {/* 5 action options */}\n {actionLabels.map((label, i) => (\n <Box key={i}>\n <Text\n color={i === actionIndex ? BRAND_GRADIENT.START : undefined}\n bold={i === actionIndex}\n >\n {i === actionIndex ? `${figures.pointer} ` : ' '}\n {i + 1}. {label}\n </Text>\n </Box>\n ))}\n\n {/* Warning footer */}\n <Box marginTop={1}>\n <Text color={SEMANTIC_COLORS.error}>{t('rewind.bashWarning')}</Text>\n </Box>\n </Box>\n )\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -5,7 +5,8 @@ import { getTheme } from "../utils/theme.js";
5
5
  import { sample } from "lodash-es";
6
6
  import { getSessionState } from "../utils/sessionState.js";
7
7
  import { useUnifiedAnimation } from "../utils/animationManager.js";
8
- import { formatNumber, formatTokenUsage } from "../utils/format.js";
8
+ import { formatNumber } from "../utils/format.js";
9
+ import { getTokenDisplay } from "../utils/tokenProgress.js";
9
10
  import { BRAND_GRADIENT, SEMANTIC_COLORS } from "../constants/colors.js";
10
11
  import {
11
12
  getCurrentAgentContext,
@@ -82,13 +83,13 @@ function Spinner({ isActive = true }) {
82
83
  const message = useRef(sample(MESSAGES));
83
84
  const startTime = useRef(Date.now());
84
85
  const theme = getTheme();
85
- const { spinnerFrame, elapsedTime } = useUnifiedAnimation({
86
+ const { spinnerFrame, elapsedTime, dataTick } = useUnifiedAnimation({
86
87
  enabled: isActive,
87
88
  startTime: startTime.current,
88
89
  spinnerFrameCount: frames.length,
89
90
  componentId: "main-spinner"
90
91
  });
91
- const streamState = useMemo(() => getMainStreamingState2(), [spinnerFrame]);
92
+ const streamState = useMemo(() => getMainStreamingState2(), [dataTick]);
92
93
  const getPhaseDisplay = () => {
93
94
  switch (streamState.phase) {
94
95
  case "deep_thinking": {
@@ -99,8 +100,10 @@ function Spinner({ isActive = true }) {
99
100
  }
100
101
  return `Deep thinking (${elapsed}s${charInfo ? " \xB7 " + charInfo : ""})`;
101
102
  }
102
- case "retrying":
103
- return streamState.retryCount && streamState.maxRetries ? `Retrying (${streamState.retryCount}/${streamState.maxRetries})${streamState.errorName ? ` \xB7 ${streamState.errorName}` : ""}` : streamState.errorName ? `Retrying \xB7 ${streamState.errorName}` : "Retrying...";
103
+ case "retrying": {
104
+ const delayInfo = streamState.retryDelayMs ? ` \xB7 next in ${Math.ceil(streamState.retryDelayMs / 1e3)}s` : "";
105
+ return streamState.retryCount && streamState.maxRetries ? `Retrying (${streamState.retryCount}/${streamState.maxRetries})${streamState.errorName ? ` \xB7 ${streamState.errorName}` : ""}${delayInfo}` : streamState.errorName ? `Retrying \xB7 ${streamState.errorName}${delayInfo}` : `Retrying...${delayInfo}`;
106
+ }
104
107
  case "permission":
105
108
  return "Waiting for permission...";
106
109
  case "compacting":
@@ -138,23 +141,9 @@ function Spinner({ isActive = true }) {
138
141
  concurrent: SEMANTIC_COLORS.success
139
142
  // 绿色 - 并发
140
143
  };
141
- const getTokenDisplay = () => {
142
- if (streamState.inputTokens || streamState.outputTokens) {
143
- return formatTokenUsage(streamState.inputTokens, streamState.outputTokens);
144
- }
145
- if (streamState.receivedChars && streamState.receivedChars > 0) {
146
- const approxOutputTokens = Math.round(streamState.receivedChars / 3);
147
- if (streamState.sentChars && streamState.sentChars > 0) {
148
- const approxInputTokens = Math.round(streamState.sentChars / 3);
149
- return `\u2191 ~${formatNumber(approxInputTokens)} \xB7 \u2193 ~${formatNumber(approxOutputTokens)}`;
150
- }
151
- return `\u2193 ~${formatNumber(approxOutputTokens)}`;
152
- }
153
- return "";
154
- };
155
- const tokenUsage = getTokenDisplay();
144
+ const { formatted: tokenUsage } = getTokenDisplay();
156
145
  const thinkingDuration = streamState.thinkingDurationMs ? Math.floor(streamState.thinkingDurationMs / 1e3) : null;
157
- return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", marginTop: 1 }, /* @__PURE__ */ React.createElement(Box, { flexWrap: "nowrap", height: 1, width: 2 }, /* @__PURE__ */ React.createElement(Text, { color: phaseColors[streamState.phase] }, frames[spinnerFrame])), /* @__PURE__ */ React.createElement(Text, { color: phaseColors[streamState.phase] }, getPhaseDisplay(), "\u2026 "), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "(", /* @__PURE__ */ React.createElement(Text, { bold: true }, "esc esc"), " to cancel \xB7 ", elapsedTime, "s", tokenUsage && /* @__PURE__ */ React.createElement(Text, null, " \xB7 ", tokenUsage), thinkingDuration !== null && thinkingDuration > 0 && /* @__PURE__ */ React.createElement(Text, null, " \xB7 thinking ", thinkingDuration, "s"), ")"), getSessionState("currentError") && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "\xB7 ", getSessionState("currentError")));
146
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", marginTop: 1 }, /* @__PURE__ */ React.createElement(Box, { flexWrap: "nowrap", height: 1, width: 2 }, /* @__PURE__ */ React.createElement(Text, { color: phaseColors[streamState.phase] }, frames[spinnerFrame])), /* @__PURE__ */ React.createElement(Text, { color: phaseColors[streamState.phase] }, getPhaseDisplay(), "\u2026 "), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "(", /* @__PURE__ */ React.createElement(Text, { bold: true }, "esc"), " to cancel \xB7 ", elapsedTime, "s", tokenUsage && /* @__PURE__ */ React.createElement(Text, null, " \xB7 ", tokenUsage), streamState.phase === "thinking" && /* @__PURE__ */ React.createElement(Text, null, " \xB7 thinking"), thinkingDuration !== null && thinkingDuration > 0 && /* @__PURE__ */ React.createElement(Text, null, " \xB7 thinking ", thinkingDuration, "s"), ")"), getSessionState("currentError") && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "\xB7 ", getSessionState("currentError")));
158
147
  }
159
148
  function SimpleSpinner({
160
149
  isActive = true,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/Spinner.tsx"],
4
- "sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { useRef, useMemo } from 'react'\nimport { getTheme } from '@utils/theme'\nimport { sample } from 'lodash-es'\nimport { getSessionState } from '@utils/sessionState'\nimport { useUnifiedAnimation } from '@utils/animationManager'\nimport { formatNumber, formatTokenUsage } from '@utils/format'\nimport { BRAND_GRADIENT, SEMANTIC_COLORS } from '@constants/colors'\n\n// Re-export streaming state from canonical location for backward compatibility\nexport {\n type StreamingPhase,\n type StreamingStateData,\n getCurrentAgentContext,\n pushAgentContext,\n popAgentContext,\n setStreamingState,\n resetStreamingState,\n getStreamingState,\n getMainStreamingState,\n cleanupAgentStreamingState,\n} from '@utils/streamingState'\n\nimport { getMainStreamingState } from '@utils/streamingState'\nimport type { StreamingPhase } from '@utils/streamingState'\n\n// NB: The third character in this string is an emoji that\n// renders on Windows consoles with a green background\nconst CHARACTERS =\n process.platform === 'darwin'\n ? ['\u00B7', '\u2722', '\u2733', '\u2217', '\u273B', '\u273D']\n : ['\u00B7', '\u2722', '*', '\u2217', '\u273B', '\u273D']\n\nconst MESSAGES = [\n 'Accomplishing',\n 'Actioning',\n 'Actualizing',\n 'Baking',\n 'Brewing',\n 'Calculating',\n 'Cerebrating',\n 'Churning',\n 'Coding',\n 'Coalescing',\n 'Cogitating',\n 'Computing',\n 'Conjuring',\n 'Considering',\n 'Cooking',\n 'Crafting',\n 'Creating',\n 'Crunching',\n 'Deliberating',\n 'Determining',\n 'Doing',\n 'Effecting',\n 'Finagling',\n 'Forging',\n 'Forming',\n 'Generating',\n 'Hatching',\n 'Herding',\n 'Honking',\n 'Hustling',\n 'Ideating',\n 'Inferring',\n 'Manifesting',\n 'Marinating',\n 'Moseying',\n 'Mulling',\n 'Mustering',\n 'Musing',\n 'Noodling',\n 'Percolating',\n 'Pondering',\n 'Processing',\n 'Puttering',\n 'Reticulating',\n 'Ruminating',\n 'Schlepping',\n 'Shucking',\n 'Simmering',\n 'Smooshing',\n 'Spinning',\n 'Stewing',\n 'Synthesizing',\n 'Thinking',\n 'Transmuting',\n 'Vibing',\n 'Working',\n]\n\ninterface SpinnerProps {\n /** Whether the spinner should be active (animating) */\n isActive?: boolean\n}\n\nexport function Spinner({ isActive = true }: SpinnerProps): React.ReactNode {\n const frames = [...CHARACTERS, ...[...CHARACTERS].reverse()]\n const message = useRef(sample(MESSAGES))\n const startTime = useRef(Date.now())\n const theme = getTheme()\n\n // Use unified animation manager instead of separate setInterval timers\n const { spinnerFrame, elapsedTime } = useUnifiedAnimation({\n enabled: isActive,\n startTime: startTime.current,\n spinnerFrameCount: frames.length,\n componentId: 'main-spinner',\n })\n\n // Get main streaming state on each render (updates when spinnerFrame changes)\n // Use getMainStreamingState to avoid subagent interference\n const streamState = useMemo(() => getMainStreamingState(), [spinnerFrame])\n\n // Get phase-specific display\n const getPhaseDisplay = () => {\n switch (streamState.phase) {\n case 'deep_thinking': {\n // Show elapsed time and char count for thinking phase\n const elapsed = streamState.thinkingStartTime\n ? Math.floor((Date.now() - streamState.thinkingStartTime) / 1000)\n : 0\n const charInfo = streamState.tokenCount\n ? `${formatNumber(streamState.tokenCount)} chars`\n : ''\n\n if (streamState.thinkingMaxTokens && streamState.tokenCount) {\n return `Deep thinking (${elapsed}s \u00B7 ${charInfo} / ${formatNumber(streamState.thinkingMaxTokens)})`\n }\n return `Deep thinking (${elapsed}s${charInfo ? ' \u00B7 ' + charInfo : ''})`\n }\n\n case 'retrying':\n return streamState.retryCount && streamState.maxRetries\n ? `Retrying (${streamState.retryCount}/${streamState.maxRetries})${streamState.errorName ? ` \u00B7 ${streamState.errorName}` : ''}`\n : streamState.errorName\n ? `Retrying \u00B7 ${streamState.errorName}`\n : 'Retrying...'\n\n case 'permission':\n return 'Waiting for permission...'\n\n case 'compacting':\n return 'Compacting context...'\n\n case 'concurrent':\n return streamState.concurrentCount\n ? `Running ${streamState.concurrentCount} concurrent tasks...`\n : 'Running concurrent tasks...'\n\n case 'tool_use':\n return streamState.toolName\n ? `Using ${streamState.toolName}`\n : 'Executing tool'\n\n case 'generating':\n return 'Receiving'\n\n case 'waiting':\n return 'Waiting for response'\n\n case 'thinking':\n default:\n return message.current\n }\n }\n\n // \u4F7F\u7528\u8BED\u4E49\u989C\u8272\u7CFB\u7EDF\uFF0C\u54C1\u724C\u8272\u7528\u4E8E\u601D\u8003\uFF0C\u72B6\u6001\u8272\u7528\u4E8E\u5404\u9636\u6BB5\n const phaseColors: Record<StreamingPhase, string> = {\n thinking: BRAND_GRADIENT.MIDDLE, // \u7C89\u7D2B - \u601D\u8003\u4E2D\n deep_thinking: BRAND_GRADIENT.START, // \u7D2B\u84DD - \u6DF1\u5EA6\u601D\u8003\n generating: SEMANTIC_COLORS.success, // \u7EFF\u8272 - \u751F\u6210\u4E2D\n tool_use: SEMANTIC_COLORS.running, // \u7C89\u7D2B - \u5DE5\u5177\u6267\u884C\n waiting: SEMANTIC_COLORS.dim, // \u7070\u8272 - \u7B49\u5F85\n retrying: SEMANTIC_COLORS.error, // \u7EA2\u8272 - \u91CD\u8BD5\n permission: SEMANTIC_COLORS.info, // \u84DD\u8272 - \u6743\u9650\n compacting: SEMANTIC_COLORS.info, // \u84DD\u8272 - \u538B\u7F29\n concurrent: SEMANTIC_COLORS.success, // \u7EFF\u8272 - \u5E76\u53D1\n }\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 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\" marginTop={1}>\n <Box flexWrap=\"nowrap\" height={1} width={2}>\n <Text color={phaseColors[streamState.phase]}>\n {frames[spinnerFrame]}\n </Text>\n </Box>\n <Text color={phaseColors[streamState.phase]}>{getPhaseDisplay()}\u2026 </Text>\n <Text color={SEMANTIC_COLORS.dim}>\n (<Text bold>esc esc</Text> to cancel \u00B7 {elapsedTime}s\n {tokenUsage && <Text> \u00B7 {tokenUsage}</Text>}\n {thinkingDuration !== null && thinkingDuration > 0 && (\n <Text> \u00B7 thinking {thinkingDuration}s</Text>\n )}\n )\n </Text>\n {getSessionState('currentError') && (\n <Text color={SEMANTIC_COLORS.dim}>\n \u00B7 {getSessionState('currentError')}\n </Text>\n )}\n </Box>\n )\n}\n\ninterface SimpleSpinnerProps {\n /** Whether the spinner should be active (animating) */\n isActive?: boolean\n /** Optional label to display next to spinner */\n label?: string\n}\n\nexport function SimpleSpinner({\n isActive = true,\n label,\n}: SimpleSpinnerProps): React.ReactNode {\n const frames = [...CHARACTERS, ...[...CHARACTERS].reverse()]\n const startTime = useRef(Date.now())\n\n // Use unified animation manager\n const { spinnerFrame } = useUnifiedAnimation({\n enabled: isActive,\n startTime: startTime.current,\n spinnerFrameCount: frames.length,\n componentId: 'simple-spinner',\n })\n\n return (\n <Box flexDirection=\"row\">\n <Box flexWrap=\"nowrap\" height={1} width={2}>\n <Text color={BRAND_GRADIENT.MIDDLE}>{frames[spinnerFrame]}</Text>\n </Box>\n {label && <Text color={SEMANTIC_COLORS.dim}> {label}</Text>}\n </Box>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { useRef, useMemo } from 'react'\nimport { getTheme } from '@utils/theme'\nimport { sample } from 'lodash-es'\nimport { getSessionState } from '@utils/sessionState'\nimport { useUnifiedAnimation } from '@utils/animationManager'\nimport { formatNumber } from '@utils/format'\nimport { getTokenDisplay } from '@utils/tokenProgress'\nimport { BRAND_GRADIENT, SEMANTIC_COLORS } from '@constants/colors'\n\n// Re-export streaming state from canonical location for backward compatibility\nexport {\n type StreamingPhase,\n type StreamingStateData,\n getCurrentAgentContext,\n pushAgentContext,\n popAgentContext,\n setStreamingState,\n resetStreamingState,\n getStreamingState,\n getMainStreamingState,\n cleanupAgentStreamingState,\n} from '@utils/streamingState'\n\nimport { getMainStreamingState } from '@utils/streamingState'\nimport type { StreamingPhase } from '@utils/streamingState'\n\n// NB: The third character in this string is an emoji that\n// renders on Windows consoles with a green background\nconst CHARACTERS =\n process.platform === 'darwin'\n ? ['\u00B7', '\u2722', '\u2733', '\u2217', '\u273B', '\u273D']\n : ['\u00B7', '\u2722', '*', '\u2217', '\u273B', '\u273D']\n\nconst MESSAGES = [\n 'Accomplishing',\n 'Actioning',\n 'Actualizing',\n 'Baking',\n 'Brewing',\n 'Calculating',\n 'Cerebrating',\n 'Churning',\n 'Coding',\n 'Coalescing',\n 'Cogitating',\n 'Computing',\n 'Conjuring',\n 'Considering',\n 'Cooking',\n 'Crafting',\n 'Creating',\n 'Crunching',\n 'Deliberating',\n 'Determining',\n 'Doing',\n 'Effecting',\n 'Finagling',\n 'Forging',\n 'Forming',\n 'Generating',\n 'Hatching',\n 'Herding',\n 'Honking',\n 'Hustling',\n 'Ideating',\n 'Inferring',\n 'Manifesting',\n 'Marinating',\n 'Moseying',\n 'Mulling',\n 'Mustering',\n 'Musing',\n 'Noodling',\n 'Percolating',\n 'Pondering',\n 'Processing',\n 'Puttering',\n 'Reticulating',\n 'Ruminating',\n 'Schlepping',\n 'Shucking',\n 'Simmering',\n 'Smooshing',\n 'Spinning',\n 'Stewing',\n 'Synthesizing',\n 'Thinking',\n 'Transmuting',\n 'Vibing',\n 'Working',\n]\n\ninterface SpinnerProps {\n /** Whether the spinner should be active (animating) */\n isActive?: boolean\n}\n\nexport function Spinner({ isActive = true }: SpinnerProps): React.ReactNode {\n const frames = [...CHARACTERS, ...[...CHARACTERS].reverse()]\n const message = useRef(sample(MESSAGES))\n const startTime = useRef(Date.now())\n const theme = getTheme()\n\n // Use unified animation manager instead of separate setInterval timers\n const { spinnerFrame, elapsedTime, dataTick } = useUnifiedAnimation({\n enabled: isActive,\n startTime: startTime.current,\n spinnerFrameCount: frames.length,\n componentId: 'main-spinner',\n })\n\n // Get main streaming state on each render (updates at 100ms via dataTick)\n // Use getMainStreamingState to avoid subagent interference\n const streamState = useMemo(() => getMainStreamingState(), [dataTick])\n\n // Get phase-specific display\n const getPhaseDisplay = () => {\n switch (streamState.phase) {\n case 'deep_thinking': {\n // Show elapsed time and char count for thinking phase\n const elapsed = streamState.thinkingStartTime\n ? Math.floor((Date.now() - streamState.thinkingStartTime) / 1000)\n : 0\n const charInfo = streamState.tokenCount\n ? `${formatNumber(streamState.tokenCount)} chars`\n : ''\n\n if (streamState.thinkingMaxTokens && streamState.tokenCount) {\n return `Deep thinking (${elapsed}s \u00B7 ${charInfo} / ${formatNumber(streamState.thinkingMaxTokens)})`\n }\n return `Deep thinking (${elapsed}s${charInfo ? ' \u00B7 ' + charInfo : ''})`\n }\n\n case 'retrying': {\n const delayInfo = streamState.retryDelayMs\n ? ` \u00B7 next in ${Math.ceil(streamState.retryDelayMs / 1000)}s`\n : ''\n return streamState.retryCount && streamState.maxRetries\n ? `Retrying (${streamState.retryCount}/${streamState.maxRetries})${streamState.errorName ? ` \u00B7 ${streamState.errorName}` : ''}${delayInfo}`\n : streamState.errorName\n ? `Retrying \u00B7 ${streamState.errorName}${delayInfo}`\n : `Retrying...${delayInfo}`\n }\n\n case 'permission':\n return 'Waiting for permission...'\n\n case 'compacting':\n return 'Compacting context...'\n\n case 'concurrent':\n return streamState.concurrentCount\n ? `Running ${streamState.concurrentCount} concurrent tasks...`\n : 'Running concurrent tasks...'\n\n case 'tool_use':\n return streamState.toolName\n ? `Using ${streamState.toolName}`\n : 'Executing tool'\n\n case 'generating':\n return 'Receiving'\n\n case 'waiting':\n return 'Waiting for response'\n\n case 'thinking':\n default:\n return message.current\n }\n }\n\n // \u4F7F\u7528\u8BED\u4E49\u989C\u8272\u7CFB\u7EDF\uFF0C\u54C1\u724C\u8272\u7528\u4E8E\u601D\u8003\uFF0C\u72B6\u6001\u8272\u7528\u4E8E\u5404\u9636\u6BB5\n const phaseColors: Record<StreamingPhase, string> = {\n thinking: BRAND_GRADIENT.MIDDLE, // \u7C89\u7D2B - \u601D\u8003\u4E2D\n deep_thinking: BRAND_GRADIENT.START, // \u7D2B\u84DD - \u6DF1\u5EA6\u601D\u8003\n generating: SEMANTIC_COLORS.success, // \u7EFF\u8272 - \u751F\u6210\u4E2D\n tool_use: SEMANTIC_COLORS.running, // \u7C89\u7D2B - \u5DE5\u5177\u6267\u884C\n waiting: SEMANTIC_COLORS.dim, // \u7070\u8272 - \u7B49\u5F85\n retrying: SEMANTIC_COLORS.error, // \u7EA2\u8272 - \u91CD\u8BD5\n permission: SEMANTIC_COLORS.info, // \u84DD\u8272 - \u6743\u9650\n compacting: SEMANTIC_COLORS.info, // \u84DD\u8272 - \u538B\u7F29\n concurrent: SEMANTIC_COLORS.success, // \u7EFF\u8272 - \u5E76\u53D1\n }\n\n const { formatted: 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\" marginTop={1}>\n <Box flexWrap=\"nowrap\" height={1} width={2}>\n <Text color={phaseColors[streamState.phase]}>\n {frames[spinnerFrame]}\n </Text>\n </Box>\n <Text color={phaseColors[streamState.phase]}>{getPhaseDisplay()}\u2026 </Text>\n <Text color={SEMANTIC_COLORS.dim}>\n (<Text bold>esc</Text> to cancel \u00B7 {elapsedTime}s\n {tokenUsage && <Text> \u00B7 {tokenUsage}</Text>}\n {streamState.phase === 'thinking' && <Text> \u00B7 thinking</Text>}\n {thinkingDuration !== null && thinkingDuration > 0 && (\n <Text> \u00B7 thinking {thinkingDuration}s</Text>\n )}\n )\n </Text>\n {getSessionState('currentError') && (\n <Text color={SEMANTIC_COLORS.dim}>\n \u00B7 {getSessionState('currentError')}\n </Text>\n )}\n </Box>\n )\n}\n\ninterface SimpleSpinnerProps {\n /** Whether the spinner should be active (animating) */\n isActive?: boolean\n /** Optional label to display next to spinner */\n label?: string\n}\n\nexport function SimpleSpinner({\n isActive = true,\n label,\n}: SimpleSpinnerProps): React.ReactNode {\n const frames = [...CHARACTERS, ...[...CHARACTERS].reverse()]\n const startTime = useRef(Date.now())\n\n // Use unified animation manager\n const { spinnerFrame } = useUnifiedAnimation({\n enabled: isActive,\n startTime: startTime.current,\n spinnerFrameCount: frames.length,\n componentId: 'simple-spinner',\n })\n\n return (\n <Box flexDirection=\"row\">\n <Box flexWrap=\"nowrap\" height={1} width={2}>\n <Text color={BRAND_GRADIENT.MIDDLE}>{frames[spinnerFrame]}</Text>\n </Box>\n {label && <Text color={SEMANTIC_COLORS.dim}> {label}</Text>}\n </Box>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["getMainStreamingState"]
7
7
  }
@@ -0,0 +1,29 @@
1
+ import { Box, Text } from "ink";
2
+ import * as React from "react";
3
+ import { useMemo } from "react";
4
+ import { getMainStreamingState } from "../utils/streamingState.js";
5
+ import { applyMarkdown } from "../utils/markdown.js";
6
+ import { useUnifiedAnimation } from "../utils/animationManager.js";
7
+ import { useTerminalSize } from "../hooks/useTerminalSize.js";
8
+ import { SEMANTIC_COLORS } from "../constants/colors.js";
9
+ function StreamingTextPreview() {
10
+ const { columns } = useTerminalSize();
11
+ const { dataTick } = useUnifiedAnimation({
12
+ enabled: true,
13
+ startTime: Date.now(),
14
+ spinnerFrameCount: 1,
15
+ componentId: "streaming-text-preview"
16
+ });
17
+ const streamingText = useMemo(
18
+ () => getMainStreamingState().streamingText,
19
+ [dataTick]
20
+ );
21
+ if (!streamingText) return null;
22
+ const rendered = applyMarkdown(streamingText);
23
+ if (!rendered) return null;
24
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", width: columns - 6, marginLeft: 2 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.primary }, rendered));
25
+ }
26
+ export {
27
+ StreamingTextPreview
28
+ };
29
+ //# sourceMappingURL=StreamingTextPreview.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/components/StreamingTextPreview.tsx"],
4
+ "sourcesContent": ["/**\n * StreamingTextPreview \u2014 Typewriter-style progressive text rendering\n *\n * Reads streaming text from the global streaming state and renders it\n * in real-time as the LLM generates content. Updates at 100ms intervals\n * via the unified animation manager's dataTick.\n *\n * Displayed in the REPL's dynamic section while the model is generating.\n * Cleared when the complete message is yielded and rendered normally.\n */\n\nimport { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { useMemo } from 'react'\nimport { getMainStreamingState } from '@utils/streamingState'\nimport { applyMarkdown } from '@utils/markdown'\nimport { useUnifiedAnimation } from '@utils/animationManager'\nimport { useTerminalSize } from '@hooks/useTerminalSize'\nimport { SEMANTIC_COLORS } from '@constants/colors'\n\nexport function StreamingTextPreview(): React.ReactNode {\n const { columns } = useTerminalSize()\n\n // Subscribe to animation tick for 100ms refresh\n const { dataTick } = useUnifiedAnimation({\n enabled: true,\n startTime: Date.now(),\n spinnerFrameCount: 1,\n componentId: 'streaming-text-preview',\n })\n\n const streamingText = useMemo(\n () => getMainStreamingState().streamingText,\n [dataTick],\n )\n\n if (!streamingText) return null\n\n // Apply markdown formatting to the accumulated text\n const rendered = applyMarkdown(streamingText)\n if (!rendered) return null\n\n return (\n <Box flexDirection=\"column\" width={columns - 6} marginLeft={2}>\n <Text color={SEMANTIC_COLORS.primary}>{rendered}</Text>\n </Box>\n )\n}\n"],
5
+ "mappings": "AAWA,SAAS,KAAK,YAAY;AAC1B,YAAY,WAAW;AACvB,SAAS,eAAe;AACxB,SAAS,6BAA6B;AACtC,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AACpC,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAEzB,SAAS,uBAAwC;AACtD,QAAM,EAAE,QAAQ,IAAI,gBAAgB;AAGpC,QAAM,EAAE,SAAS,IAAI,oBAAoB;AAAA,IACvC,SAAS;AAAA,IACT,WAAW,KAAK,IAAI;AAAA,IACpB,mBAAmB;AAAA,IACnB,aAAa;AAAA,EACf,CAAC;AAED,QAAM,gBAAgB;AAAA,IACpB,MAAM,sBAAsB,EAAE;AAAA,IAC9B,CAAC,QAAQ;AAAA,EACX;AAEA,MAAI,CAAC,cAAe,QAAO;AAG3B,QAAM,WAAW,cAAc,aAAa;AAC5C,MAAI,CAAC,SAAU,QAAO;AAEtB,SACE,oCAAC,OAAI,eAAc,UAAS,OAAO,UAAU,GAAG,YAAY,KAC1D,oCAAC,QAAK,OAAO,gBAAgB,WAAU,QAAS,CAClD;AAEJ;",
6
+ "names": []
7
+ }
@@ -1,11 +1,12 @@
1
1
  import React, { useState } from "react";
2
2
  import { Box, Text } from "ink";
3
3
  import { getTheme } from "../utils/theme.js";
4
+ import { formatNumber } from "../utils/format.js";
4
5
  import { getTodoStatusSymbol } from "../constants/symbols.js";
5
6
  import { AgentThinkingBlock } from "./AgentThinkingBlock.js";
6
7
  import { ToolExecutionBlock } from "./ToolExecutionBlock.js";
7
8
  import { AgentResponseBlock } from "./AgentResponseBlock.js";
8
- import { useAgentTokenStats, formatTokenCount } from "../hooks/useAgentTokenStats.js";
9
+ import { useAgentTokenStats } from "../hooks/useAgentTokenStats.js";
9
10
  function SubagentBlock({
10
11
  subagent,
11
12
  indent = 0,
@@ -40,7 +41,7 @@ function SubagentBlock({
40
41
  indent: 0,
41
42
  isSubagent: true
42
43
  }
43
- )), /* @__PURE__ */ React.createElement(Text, { color: theme.dimmedText }, "\u2502")), /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", marginLeft: 2 }, /* @__PURE__ */ React.createElement(Text, { color: theme.dimmedText }, "\u2514\u2500 "), /* @__PURE__ */ React.createElement(Text, { color: statusColor }, statusIndicator, " ", getStatusLabel(subagent.status)), subagent.status === "completed" && /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, " ", "(", duration, "s, ", formatTokenCount(tokenCount), " tokens)")), !expanded && /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", marginLeft: 4 }, /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, "Press ", /* @__PURE__ */ React.createElement(Text, { bold: true }, "Ctrl+O"), " to expand details")));
44
+ )), /* @__PURE__ */ React.createElement(Text, { color: theme.dimmedText }, "\u2502")), /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", marginLeft: 2 }, /* @__PURE__ */ React.createElement(Text, { color: theme.dimmedText }, "\u2514\u2500 "), /* @__PURE__ */ React.createElement(Text, { color: statusColor }, statusIndicator, " ", getStatusLabel(subagent.status)), subagent.status === "completed" && /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, " ", "(", duration, "s, ", formatNumber(tokenCount), " tokens)")), !expanded && /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", marginLeft: 4 }, /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, "Press ", /* @__PURE__ */ React.createElement(Text, { bold: true }, "Ctrl+O"), " to expand details")));
44
45
  }
45
46
  function SubagentTodosSection({
46
47
  todos,