@machina.ai/cell-cli 1.36.0-rc1 → 1.38.1-rc2

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 (580) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.js +1 -1
  3. package/dist/package.json +4 -4
  4. package/dist/src/acp/acpClient.js +297 -32
  5. package/dist/src/acp/acpClient.js.map +1 -1
  6. package/dist/src/acp/acpClient.test.js +419 -19
  7. package/dist/src/acp/acpClient.test.js.map +1 -1
  8. package/dist/src/acp/acpResume.test.js +8 -0
  9. package/dist/src/acp/acpResume.test.js.map +1 -1
  10. package/dist/src/acp/commandHandler.js +4 -0
  11. package/dist/src/acp/commandHandler.js.map +1 -1
  12. package/dist/src/acp/commandHandler.test.js +4 -0
  13. package/dist/src/acp/commandHandler.test.js.map +1 -1
  14. package/dist/src/acp/commands/about.d.ts +11 -0
  15. package/dist/src/acp/commands/about.js +53 -0
  16. package/dist/src/acp/commands/about.js.map +1 -0
  17. package/dist/src/acp/commands/extensions.js +1 -1
  18. package/dist/src/acp/commands/extensions.js.map +1 -1
  19. package/dist/src/acp/commands/help.d.ts +14 -0
  20. package/dist/src/acp/commands/help.js +35 -0
  21. package/dist/src/acp/commands/help.js.map +1 -0
  22. package/dist/src/acp/commands/help.test.d.ts +6 -0
  23. package/dist/src/acp/commands/help.test.js +40 -0
  24. package/dist/src/acp/commands/help.test.js.map +1 -0
  25. package/dist/src/acp/commands/restore.js +2 -2
  26. package/dist/src/acp/commands/restore.js.map +1 -1
  27. package/dist/src/commands/extensions/new.js +1 -1
  28. package/dist/src/commands/extensions/new.js.map +1 -1
  29. package/dist/src/commands/mcp/list.js +2 -2
  30. package/dist/src/commands/mcp/list.js.map +1 -1
  31. package/dist/src/commands/mcp.test.js +1 -1
  32. package/dist/src/commands/mcp.test.js.map +1 -1
  33. package/dist/src/commands/skills/list.js +5 -8
  34. package/dist/src/commands/skills/list.js.map +1 -1
  35. package/dist/src/commands/skills/list.test.js +17 -13
  36. package/dist/src/commands/skills/list.test.js.map +1 -1
  37. package/dist/src/config/config.js +22 -9
  38. package/dist/src/config/config.js.map +1 -1
  39. package/dist/src/config/config.test.js +121 -36
  40. package/dist/src/config/config.test.js.map +1 -1
  41. package/dist/src/config/extension-manager-permissions.test.js +1 -1
  42. package/dist/src/config/extension-manager-permissions.test.js.map +1 -1
  43. package/dist/src/config/extension-manager-themes.spec.js +1 -0
  44. package/dist/src/config/extension-manager-themes.spec.js.map +1 -1
  45. package/dist/src/config/extension-manager.test.js +1 -1
  46. package/dist/src/config/extension-manager.test.js.map +1 -1
  47. package/dist/src/config/extension.js +1 -1
  48. package/dist/src/config/extension.js.map +1 -1
  49. package/dist/src/config/extensions/github.js +1 -1
  50. package/dist/src/config/extensions/github.js.map +1 -1
  51. package/dist/src/config/footerItems.d.ts +4 -0
  52. package/dist/src/config/footerItems.js +12 -2
  53. package/dist/src/config/footerItems.js.map +1 -1
  54. package/dist/src/config/footerItems.test.js +129 -72
  55. package/dist/src/config/footerItems.test.js.map +1 -1
  56. package/dist/src/config/policy-engine.integration.test.js +1 -3
  57. package/dist/src/config/policy-engine.integration.test.js.map +1 -1
  58. package/dist/src/config/policy.d.ts +1 -1
  59. package/dist/src/config/policy.js +2 -2
  60. package/dist/src/config/policy.js.map +1 -1
  61. package/dist/src/config/settings.js +19 -3
  62. package/dist/src/config/settings.js.map +1 -1
  63. package/dist/src/config/settingsSchema.d.ts +272 -53
  64. package/dist/src/config/settingsSchema.js +262 -48
  65. package/dist/src/config/settingsSchema.js.map +1 -1
  66. package/dist/src/config/settingsSchema.test.js +22 -4
  67. package/dist/src/config/settingsSchema.test.js.map +1 -1
  68. package/dist/src/config/workspace-policy-cli.test.js +7 -7
  69. package/dist/src/config/workspace-policy-cli.test.js.map +1 -1
  70. package/dist/src/gemini.js +24 -7
  71. package/dist/src/gemini.js.map +1 -1
  72. package/dist/src/gemini.test.js +74 -4
  73. package/dist/src/gemini.test.js.map +1 -1
  74. package/dist/src/gemini_cleanup.test.js +69 -4
  75. package/dist/src/gemini_cleanup.test.js.map +1 -1
  76. package/dist/src/generated/git-commit.d.ts +2 -2
  77. package/dist/src/generated/git-commit.js +2 -2
  78. package/dist/src/integration-tests/modelSteering.test.js +1 -1
  79. package/dist/src/integration-tests/modelSteering.test.js.map +1 -1
  80. package/dist/src/interactiveCli.js +4 -2
  81. package/dist/src/interactiveCli.js.map +1 -1
  82. package/dist/src/nonInteractiveCli.d.ts +1 -1
  83. package/dist/src/nonInteractiveCli.js +11 -2
  84. package/dist/src/nonInteractiveCli.js.map +1 -1
  85. package/dist/src/nonInteractiveCli.test.js +4 -2
  86. package/dist/src/nonInteractiveCli.test.js.map +1 -1
  87. package/dist/src/nonInteractiveCliAgentSession.d.ts +16 -0
  88. package/dist/src/nonInteractiveCliAgentSession.js +484 -0
  89. package/dist/src/nonInteractiveCliAgentSession.js.map +1 -0
  90. package/dist/src/nonInteractiveCliAgentSession.test.js +1837 -0
  91. package/dist/src/nonInteractiveCliAgentSession.test.js.map +1 -0
  92. package/dist/src/services/BuiltinCommandLoader.js +4 -2
  93. package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
  94. package/dist/src/test-utils/mockCommandContext.js +1 -0
  95. package/dist/src/test-utils/mockCommandContext.js.map +1 -1
  96. package/dist/src/test-utils/mockConfig.js +16 -0
  97. package/dist/src/test-utils/mockConfig.js.map +1 -1
  98. package/dist/src/test-utils/mockSpinner.d.ts +6 -0
  99. package/dist/src/test-utils/mockSpinner.js +21 -0
  100. package/dist/src/test-utils/mockSpinner.js.map +1 -0
  101. package/dist/src/test-utils/render.d.ts +8 -1
  102. package/dist/src/test-utils/render.js +37 -11
  103. package/dist/src/test-utils/render.js.map +1 -1
  104. package/dist/src/ui/App.test.js +1 -1
  105. package/dist/src/ui/App.test.js.map +1 -1
  106. package/dist/src/ui/AppContainer.js +225 -99
  107. package/dist/src/ui/AppContainer.js.map +1 -1
  108. package/dist/src/ui/AppContainer.test.js +50 -38
  109. package/dist/src/ui/AppContainer.test.js.map +1 -1
  110. package/dist/src/ui/commands/chatCommand.js +15 -5
  111. package/dist/src/ui/commands/chatCommand.js.map +1 -1
  112. package/dist/src/ui/commands/clearCommand.js +3 -1
  113. package/dist/src/ui/commands/clearCommand.js.map +1 -1
  114. package/dist/src/ui/commands/directoryCommand.js +1 -1
  115. package/dist/src/ui/commands/directoryCommand.js.map +1 -1
  116. package/dist/src/ui/commands/extensionsCommand.js +22 -11
  117. package/dist/src/ui/commands/extensionsCommand.js.map +1 -1
  118. package/dist/src/ui/commands/marketplaceCommand.d.ts +7 -0
  119. package/dist/src/ui/commands/marketplaceCommand.js +135 -0
  120. package/dist/src/ui/commands/marketplaceCommand.js.map +1 -0
  121. package/dist/src/ui/commands/mcpCommand.js +26 -7
  122. package/dist/src/ui/commands/mcpCommand.js.map +1 -1
  123. package/dist/src/ui/commands/mcpCommand.test.js +26 -0
  124. package/dist/src/ui/commands/mcpCommand.test.js.map +1 -1
  125. package/dist/src/ui/commands/planCommand.js +9 -0
  126. package/dist/src/ui/commands/planCommand.js.map +1 -1
  127. package/dist/src/ui/commands/planCommand.test.js +29 -0
  128. package/dist/src/ui/commands/planCommand.test.js.map +1 -1
  129. package/dist/src/ui/commands/restoreCommand.js +1 -1
  130. package/dist/src/ui/commands/restoreCommand.js.map +1 -1
  131. package/dist/src/ui/commands/rewindCommand.js +3 -1
  132. package/dist/src/ui/commands/rewindCommand.js.map +1 -1
  133. package/dist/src/ui/commands/rewindCommand.test.js +1 -1
  134. package/dist/src/ui/commands/rewindCommand.test.js.map +1 -1
  135. package/dist/src/ui/commands/setupGithubCommand.js +5 -5
  136. package/dist/src/ui/commands/setupGithubCommand.js.map +1 -1
  137. package/dist/src/ui/commands/skillsCommand.js +11 -1
  138. package/dist/src/ui/commands/skillsCommand.js.map +1 -1
  139. package/dist/src/ui/commands/skillsCommand.test.js +1 -0
  140. package/dist/src/ui/commands/skillsCommand.test.js.map +1 -1
  141. package/dist/src/ui/commands/{shellsCommand.d.ts → tasksCommand.d.ts} +1 -1
  142. package/dist/src/ui/commands/{shellsCommand.js → tasksCommand.js} +6 -6
  143. package/dist/src/ui/commands/tasksCommand.js.map +1 -0
  144. package/dist/src/ui/commands/tasksCommand.test.js +30 -0
  145. package/dist/src/ui/commands/tasksCommand.test.js.map +1 -0
  146. package/dist/src/ui/commands/types.d.ts +9 -1
  147. package/dist/src/ui/components/AnsiOutput.js +7 -5
  148. package/dist/src/ui/components/AnsiOutput.js.map +1 -1
  149. package/dist/src/ui/components/AnsiOutput.test.js +13 -0
  150. package/dist/src/ui/components/AnsiOutput.test.js.map +1 -1
  151. package/dist/src/ui/components/AppHeader.js +11 -11
  152. package/dist/src/ui/components/AppHeader.js.map +1 -1
  153. package/dist/src/ui/components/AppHeader.test.js +6 -2
  154. package/dist/src/ui/components/AppHeader.test.js.map +1 -1
  155. package/dist/src/ui/components/AsciiArt.d.ts +6 -6
  156. package/dist/src/ui/components/AsciiArt.js +6 -6
  157. package/dist/src/ui/components/AskUserDialog.js +13 -13
  158. package/dist/src/ui/components/AskUserDialog.js.map +1 -1
  159. package/dist/src/ui/components/AskUserDialog.test.js +31 -0
  160. package/dist/src/ui/components/AskUserDialog.test.js.map +1 -1
  161. package/dist/src/ui/components/BackgroundTaskDisplay.d.ts +16 -0
  162. package/dist/src/ui/components/{BackgroundShellDisplay.js → BackgroundTaskDisplay.js} +12 -12
  163. package/dist/src/ui/components/BackgroundTaskDisplay.js.map +1 -0
  164. package/dist/src/ui/components/{BackgroundShellDisplay.test.js → BackgroundTaskDisplay.test.js} +26 -26
  165. package/dist/src/ui/components/BackgroundTaskDisplay.test.js.map +1 -0
  166. package/dist/src/ui/components/Composer.js +20 -208
  167. package/dist/src/ui/components/Composer.js.map +1 -1
  168. package/dist/src/ui/components/Composer.test.js +22 -17
  169. package/dist/src/ui/components/Composer.test.js.map +1 -1
  170. package/dist/src/ui/components/ContextSummaryDisplay.js +3 -1
  171. package/dist/src/ui/components/ContextSummaryDisplay.js.map +1 -1
  172. package/dist/src/ui/components/CopyModeWarning.js +3 -6
  173. package/dist/src/ui/components/CopyModeWarning.js.map +1 -1
  174. package/dist/src/ui/components/CopyModeWarning.test.js +7 -8
  175. package/dist/src/ui/components/CopyModeWarning.test.js.map +1 -1
  176. package/dist/src/ui/components/ExitPlanModeDialog.js +9 -0
  177. package/dist/src/ui/components/ExitPlanModeDialog.js.map +1 -1
  178. package/dist/src/ui/components/ExitPlanModeDialog.test.js +15 -3
  179. package/dist/src/ui/components/ExitPlanModeDialog.test.js.map +1 -1
  180. package/dist/src/ui/components/FolderTrustDialog.test.js +7 -8
  181. package/dist/src/ui/components/FolderTrustDialog.test.js.map +1 -1
  182. package/dist/src/ui/components/Footer.js +36 -9
  183. package/dist/src/ui/components/Footer.js.map +1 -1
  184. package/dist/src/ui/components/Footer.test.js +85 -6
  185. package/dist/src/ui/components/Footer.test.js.map +1 -1
  186. package/dist/src/ui/components/FooterConfigDialog.js +1 -0
  187. package/dist/src/ui/components/FooterConfigDialog.js.map +1 -1
  188. package/dist/src/ui/components/FooterConfigDialog.test.js +1 -1
  189. package/dist/src/ui/components/Help.test.js +1 -1
  190. package/dist/src/ui/components/Help.test.js.map +1 -1
  191. package/dist/src/ui/components/HistoryItemDisplay.d.ts +2 -0
  192. package/dist/src/ui/components/HistoryItemDisplay.js +14 -12
  193. package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -1
  194. package/dist/src/ui/components/InputPrompt.d.ts +10 -5
  195. package/dist/src/ui/components/InputPrompt.js +195 -90
  196. package/dist/src/ui/components/InputPrompt.js.map +1 -1
  197. package/dist/src/ui/components/InputPrompt.test.d.ts +12 -1
  198. package/dist/src/ui/components/InputPrompt.test.js +370 -160
  199. package/dist/src/ui/components/InputPrompt.test.js.map +1 -1
  200. package/dist/src/ui/components/LoadingIndicator.js +1 -2
  201. package/dist/src/ui/components/LoadingIndicator.js.map +1 -1
  202. package/dist/src/ui/components/LoadingIndicator.test.js +7 -0
  203. package/dist/src/ui/components/LoadingIndicator.test.js.map +1 -1
  204. package/dist/src/ui/components/MainContent.d.ts +1 -1
  205. package/dist/src/ui/components/MainContent.js +105 -34
  206. package/dist/src/ui/components/MainContent.js.map +1 -1
  207. package/dist/src/ui/components/MainContent.test.js +12 -9
  208. package/dist/src/ui/components/MainContent.test.js.map +1 -1
  209. package/dist/src/ui/components/MemoryUsageDisplay.d.ts +1 -0
  210. package/dist/src/ui/components/MemoryUsageDisplay.js +5 -2
  211. package/dist/src/ui/components/MemoryUsageDisplay.js.map +1 -1
  212. package/dist/src/ui/components/ModelDialog.js +50 -72
  213. package/dist/src/ui/components/ModelDialog.js.map +1 -1
  214. package/dist/src/ui/components/ModelDialog.test.js +1 -0
  215. package/dist/src/ui/components/ModelDialog.test.js.map +1 -1
  216. package/dist/src/ui/components/ModelQuotaDisplay.d.ts +18 -0
  217. package/dist/src/ui/components/ModelQuotaDisplay.js +104 -0
  218. package/dist/src/ui/components/ModelQuotaDisplay.js.map +1 -0
  219. package/dist/src/ui/components/ModelQuotaDisplay.test.d.ts +6 -0
  220. package/dist/src/ui/components/ModelQuotaDisplay.test.js +62 -0
  221. package/dist/src/ui/components/ModelQuotaDisplay.test.js.map +1 -0
  222. package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js +1 -1
  223. package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js.map +1 -1
  224. package/dist/src/ui/components/ProgressBar.d.ts +13 -0
  225. package/dist/src/ui/components/ProgressBar.js +17 -0
  226. package/dist/src/ui/components/ProgressBar.js.map +1 -0
  227. package/dist/src/ui/components/ProgressBar.test.d.ts +6 -0
  228. package/dist/src/ui/components/ProgressBar.test.js +28 -0
  229. package/dist/src/ui/components/ProgressBar.test.js.map +1 -0
  230. package/dist/src/ui/components/StatsDisplay.d.ts +2 -2
  231. package/dist/src/ui/components/StatsDisplay.js +47 -128
  232. package/dist/src/ui/components/StatsDisplay.js.map +1 -1
  233. package/dist/src/ui/components/StatsDisplay.test.js +65 -136
  234. package/dist/src/ui/components/StatsDisplay.test.js.map +1 -1
  235. package/dist/src/ui/components/StatusDisplay.js +1 -1
  236. package/dist/src/ui/components/StatusDisplay.js.map +1 -1
  237. package/dist/src/ui/components/StatusDisplay.test.js +3 -3
  238. package/dist/src/ui/components/StatusDisplay.test.js.map +1 -1
  239. package/dist/src/ui/components/StatusRow.d.ts +32 -0
  240. package/dist/src/ui/components/StatusRow.js +180 -0
  241. package/dist/src/ui/components/StatusRow.js.map +1 -0
  242. package/dist/src/ui/components/StatusRow.test.d.ts +6 -0
  243. package/dist/src/ui/components/StatusRow.test.js +99 -0
  244. package/dist/src/ui/components/StatusRow.test.js.map +1 -0
  245. package/dist/src/ui/components/ToastDisplay.d.ts +2 -1
  246. package/dist/src/ui/components/ToastDisplay.js +7 -5
  247. package/dist/src/ui/components/ToastDisplay.js.map +1 -1
  248. package/dist/src/ui/components/ToastDisplay.test.js +34 -20
  249. package/dist/src/ui/components/ToastDisplay.test.js.map +1 -1
  250. package/dist/src/ui/components/ToolConfirmationQueue.js +24 -9
  251. package/dist/src/ui/components/ToolConfirmationQueue.js.map +1 -1
  252. package/dist/src/ui/components/ToolConfirmationQueue.test.js +4 -6
  253. package/dist/src/ui/components/ToolConfirmationQueue.test.js.map +1 -1
  254. package/dist/src/ui/components/UserIdentity.js +8 -5
  255. package/dist/src/ui/components/UserIdentity.js.map +1 -1
  256. package/dist/src/ui/components/messages/DenseToolMessage.d.ts +13 -0
  257. package/dist/src/ui/components/messages/DenseToolMessage.js +270 -0
  258. package/dist/src/ui/components/messages/DenseToolMessage.js.map +1 -0
  259. package/dist/src/ui/components/messages/DenseToolMessage.test.d.ts +6 -0
  260. package/dist/src/ui/components/messages/DenseToolMessage.test.js +383 -0
  261. package/dist/src/ui/components/messages/DenseToolMessage.test.js.map +1 -0
  262. package/dist/src/ui/components/messages/DiffRenderer.d.ts +18 -0
  263. package/dist/src/ui/components/messages/DiffRenderer.js +54 -34
  264. package/dist/src/ui/components/messages/DiffRenderer.js.map +1 -1
  265. package/dist/src/ui/components/messages/DiffRenderer.test.js +12 -6
  266. package/dist/src/ui/components/messages/DiffRenderer.test.js.map +1 -1
  267. package/dist/src/ui/components/messages/InfoMessage.d.ts +1 -0
  268. package/dist/src/ui/components/messages/InfoMessage.js +2 -2
  269. package/dist/src/ui/components/messages/InfoMessage.js.map +1 -1
  270. package/dist/src/ui/components/messages/RedirectionConfirmation.test.js +1 -1
  271. package/dist/src/ui/components/messages/RedirectionConfirmation.test.js.map +1 -1
  272. package/dist/src/ui/components/messages/ShellToolMessage.test.js +44 -33
  273. package/dist/src/ui/components/messages/ShellToolMessage.test.js.map +1 -1
  274. package/dist/src/ui/components/messages/SubagentGroupDisplay.js +3 -2
  275. package/dist/src/ui/components/messages/SubagentGroupDisplay.js.map +1 -1
  276. package/dist/src/ui/components/messages/SubagentGroupDisplay.test.js +1 -1
  277. package/dist/src/ui/components/messages/SubagentGroupDisplay.test.js.map +1 -1
  278. package/dist/src/ui/components/messages/SubagentHistoryMessage.d.ts +13 -0
  279. package/dist/src/ui/components/messages/SubagentHistoryMessage.js +4 -0
  280. package/dist/src/ui/components/messages/SubagentHistoryMessage.js.map +1 -0
  281. package/dist/src/ui/components/messages/SubagentHistoryMessage.test.d.ts +6 -0
  282. package/dist/src/ui/components/messages/SubagentHistoryMessage.test.js +68 -0
  283. package/dist/src/ui/components/messages/SubagentHistoryMessage.test.js.map +1 -0
  284. package/dist/src/ui/components/messages/SubagentProgressDisplay.d.ts +2 -1
  285. package/dist/src/ui/components/messages/SubagentProgressDisplay.js +2 -2
  286. package/dist/src/ui/components/messages/SubagentProgressDisplay.js.map +1 -1
  287. package/dist/src/ui/components/messages/SubagentProgressDisplay.test.js +0 -4
  288. package/dist/src/ui/components/messages/SubagentProgressDisplay.test.js.map +1 -1
  289. package/dist/src/ui/components/messages/ToolConfirmationMessage.d.ts +1 -0
  290. package/dist/src/ui/components/messages/ToolConfirmationMessage.js +108 -70
  291. package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
  292. package/dist/src/ui/components/messages/ToolConfirmationMessage.test.js +40 -25
  293. package/dist/src/ui/components/messages/ToolConfirmationMessage.test.js.map +1 -1
  294. package/dist/src/ui/components/messages/ToolGroupMessage.compact.test.d.ts +6 -0
  295. package/dist/src/ui/components/messages/ToolGroupMessage.compact.test.js +147 -0
  296. package/dist/src/ui/components/messages/ToolGroupMessage.compact.test.js.map +1 -0
  297. package/dist/src/ui/components/messages/ToolGroupMessage.d.ts +3 -0
  298. package/dist/src/ui/components/messages/ToolGroupMessage.js +219 -52
  299. package/dist/src/ui/components/messages/ToolGroupMessage.js.map +1 -1
  300. package/dist/src/ui/components/messages/ToolGroupMessage.test.js +55 -3
  301. package/dist/src/ui/components/messages/ToolGroupMessage.test.js.map +1 -1
  302. package/dist/src/ui/components/messages/ToolMessage.test.js +8 -7
  303. package/dist/src/ui/components/messages/ToolMessage.test.js.map +1 -1
  304. package/dist/src/ui/components/messages/ToolOverflowConsistencyChecks.test.js +1 -1
  305. package/dist/src/ui/components/messages/ToolOverflowConsistencyChecks.test.js.map +1 -1
  306. package/dist/src/ui/components/messages/ToolResultDisplay.js +57 -15
  307. package/dist/src/ui/components/messages/ToolResultDisplay.js.map +1 -1
  308. package/dist/src/ui/components/messages/ToolResultDisplay.test.js +66 -3
  309. package/dist/src/ui/components/messages/ToolResultDisplay.test.js.map +1 -1
  310. package/dist/src/ui/components/messages/ToolResultDisplayOverflow.test.js +5 -4
  311. package/dist/src/ui/components/messages/ToolResultDisplayOverflow.test.js.map +1 -1
  312. package/dist/src/ui/components/messages/ToolStickyHeaderRegression.test.js +3 -3
  313. package/dist/src/ui/components/messages/ToolStickyHeaderRegression.test.js.map +1 -1
  314. package/dist/src/ui/components/messages/TopicMessage.d.ts +15 -0
  315. package/dist/src/ui/components/messages/TopicMessage.js +56 -0
  316. package/dist/src/ui/components/messages/TopicMessage.js.map +1 -0
  317. package/dist/src/ui/components/messages/TopicMessage.test.d.ts +6 -0
  318. package/dist/src/ui/components/messages/TopicMessage.test.js +77 -0
  319. package/dist/src/ui/components/messages/TopicMessage.test.js.map +1 -0
  320. package/dist/src/ui/components/shared/MaxSizedBox.d.ts +1 -0
  321. package/dist/src/ui/components/shared/MaxSizedBox.js +10 -7
  322. package/dist/src/ui/components/shared/MaxSizedBox.js.map +1 -1
  323. package/dist/src/ui/components/shared/Scrollable.d.ts +3 -0
  324. package/dist/src/ui/components/shared/Scrollable.js +6 -2
  325. package/dist/src/ui/components/shared/Scrollable.js.map +1 -1
  326. package/dist/src/ui/components/shared/ScrollableList.d.ts +9 -12
  327. package/dist/src/ui/components/shared/ScrollableList.js +2 -2
  328. package/dist/src/ui/components/shared/ScrollableList.js.map +1 -1
  329. package/dist/src/ui/components/shared/VirtualizedList.d.ts +13 -1
  330. package/dist/src/ui/components/shared/VirtualizedList.js +148 -37
  331. package/dist/src/ui/components/shared/VirtualizedList.js.map +1 -1
  332. package/dist/src/ui/components/shared/VirtualizedList.test.js +1 -10
  333. package/dist/src/ui/components/shared/VirtualizedList.test.js.map +1 -1
  334. package/dist/src/ui/components/shared/text-buffer.d.ts +1 -0
  335. package/dist/src/ui/components/shared/text-buffer.js +19 -21
  336. package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
  337. package/dist/src/ui/components/views/ExtensionDetails.d.ts +4 -1
  338. package/dist/src/ui/components/views/ExtensionDetails.js +14 -4
  339. package/dist/src/ui/components/views/ExtensionDetails.js.map +1 -1
  340. package/dist/src/ui/components/views/ExtensionDetails.test.js +25 -1
  341. package/dist/src/ui/components/views/ExtensionDetails.test.js.map +1 -1
  342. package/dist/src/ui/components/views/ExtensionRegistryView.js +19 -5
  343. package/dist/src/ui/components/views/ExtensionRegistryView.js.map +1 -1
  344. package/dist/src/ui/components/views/ExtensionRegistryView.test.js +38 -0
  345. package/dist/src/ui/components/views/ExtensionRegistryView.test.js.map +1 -1
  346. package/dist/src/ui/components/views/SkillsList.js +2 -1
  347. package/dist/src/ui/components/views/SkillsList.js.map +1 -1
  348. package/dist/src/ui/components/views/SkillsList.test.js +3 -1
  349. package/dist/src/ui/components/views/SkillsList.test.js.map +1 -1
  350. package/dist/src/ui/constants/tips.js +2 -2
  351. package/dist/src/ui/constants/tips.js.map +1 -1
  352. package/dist/src/ui/constants.d.ts +6 -0
  353. package/dist/src/ui/constants.js +15 -0
  354. package/dist/src/ui/constants.js.map +1 -1
  355. package/dist/src/ui/contexts/InputContext.d.ts +17 -0
  356. package/dist/src/ui/contexts/InputContext.js +15 -0
  357. package/dist/src/ui/contexts/InputContext.js.map +1 -0
  358. package/dist/src/ui/contexts/KeypressContext.js +1 -1
  359. package/dist/src/ui/contexts/KeypressContext.js.map +1 -1
  360. package/dist/src/ui/contexts/KeypressContext.test.js +25 -1
  361. package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
  362. package/dist/src/ui/contexts/ScrollProvider.js +25 -3
  363. package/dist/src/ui/contexts/ScrollProvider.js.map +1 -1
  364. package/dist/src/ui/contexts/ScrollProvider.test.js +100 -0
  365. package/dist/src/ui/contexts/ScrollProvider.test.js.map +1 -1
  366. package/dist/src/ui/contexts/SessionContext.d.ts +2 -2
  367. package/dist/src/ui/contexts/SessionContext.js.map +1 -1
  368. package/dist/src/ui/contexts/ToolActionsContext.d.ts +6 -0
  369. package/dist/src/ui/contexts/ToolActionsContext.js +19 -11
  370. package/dist/src/ui/contexts/ToolActionsContext.js.map +1 -1
  371. package/dist/src/ui/contexts/ToolActionsContext.test.js +90 -7
  372. package/dist/src/ui/contexts/ToolActionsContext.test.js.map +1 -1
  373. package/dist/src/ui/contexts/UIActionsContext.d.ts +4 -3
  374. package/dist/src/ui/contexts/UIActionsContext.js.map +1 -1
  375. package/dist/src/ui/contexts/UIStateContext.d.ts +10 -16
  376. package/dist/src/ui/contexts/UIStateContext.js.map +1 -1
  377. package/dist/src/ui/hooks/atCommandProcessor.test.js +2 -1
  378. package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -1
  379. package/dist/src/ui/hooks/atCommandProcessor_agents.test.js +2 -1
  380. package/dist/src/ui/hooks/atCommandProcessor_agents.test.js.map +1 -1
  381. package/dist/src/ui/hooks/shellReducer.d.ts +12 -10
  382. package/dist/src/ui/hooks/shellReducer.js +67 -37
  383. package/dist/src/ui/hooks/shellReducer.js.map +1 -1
  384. package/dist/src/ui/hooks/shellReducer.test.js +207 -36
  385. package/dist/src/ui/hooks/shellReducer.test.js.map +1 -1
  386. package/dist/src/ui/hooks/slashCommandProcessor.d.ts +1 -1
  387. package/dist/src/ui/hooks/slashCommandProcessor.js +1 -1
  388. package/dist/src/ui/hooks/slashCommandProcessor.test.js +1 -1
  389. package/dist/src/ui/hooks/toolMapping.js +7 -0
  390. package/dist/src/ui/hooks/toolMapping.js.map +1 -1
  391. package/dist/src/ui/hooks/useAlternateBuffer.js +6 -1
  392. package/dist/src/ui/hooks/useAlternateBuffer.js.map +1 -1
  393. package/dist/src/ui/hooks/useAlternateBuffer.test.js +5 -0
  394. package/dist/src/ui/hooks/useAlternateBuffer.test.js.map +1 -1
  395. package/dist/src/ui/hooks/useAnimatedScrollbar.js +2 -2
  396. package/dist/src/ui/hooks/useAnimatedScrollbar.js.map +1 -1
  397. package/dist/src/ui/hooks/useAtCompletion.js +1 -1
  398. package/dist/src/ui/hooks/useAtCompletion.js.map +1 -1
  399. package/dist/src/ui/hooks/useBackgroundTaskManager.d.ts +22 -0
  400. package/dist/src/ui/hooks/useBackgroundTaskManager.js +58 -0
  401. package/dist/src/ui/hooks/useBackgroundTaskManager.js.map +1 -0
  402. package/dist/src/ui/hooks/{useBackgroundShellManager.test.js → useBackgroundTaskManager.test.js} +50 -50
  403. package/dist/src/ui/hooks/useBackgroundTaskManager.test.js.map +1 -0
  404. package/dist/src/ui/hooks/useBanner.d.ts +1 -0
  405. package/dist/src/ui/hooks/useBanner.js +16 -9
  406. package/dist/src/ui/hooks/useBanner.js.map +1 -1
  407. package/dist/src/ui/hooks/useBanner.test.js +7 -4
  408. package/dist/src/ui/hooks/useBanner.test.js.map +1 -1
  409. package/dist/src/ui/hooks/useBatchedScroll.js +2 -2
  410. package/dist/src/ui/hooks/useBatchedScroll.js.map +1 -1
  411. package/dist/src/ui/hooks/useCommandCompletion.d.ts +2 -1
  412. package/dist/src/ui/hooks/useCommandCompletion.js +13 -3
  413. package/dist/src/ui/hooks/useCommandCompletion.js.map +1 -1
  414. package/dist/src/ui/hooks/useCommandCompletion.test.d.ts +1 -1
  415. package/dist/src/ui/hooks/useCommandCompletion.test.js +82 -6
  416. package/dist/src/ui/hooks/useCommandCompletion.test.js.map +1 -1
  417. package/dist/src/ui/hooks/useComposerStatus.d.ts +21 -0
  418. package/dist/src/ui/hooks/useComposerStatus.js +78 -0
  419. package/dist/src/ui/hooks/useComposerStatus.js.map +1 -0
  420. package/dist/src/ui/hooks/useConsoleMessages.test.js +2 -2
  421. package/dist/src/ui/hooks/useConsoleMessages.test.js.map +1 -1
  422. package/dist/src/ui/hooks/useExecutionLifecycle.d.ts +28 -0
  423. package/dist/src/ui/hooks/{shellCommandProcessor.js → useExecutionLifecycle.js} +140 -58
  424. package/dist/src/ui/hooks/useExecutionLifecycle.js.map +1 -0
  425. package/dist/src/ui/hooks/useExecutionLifecycle.test.d.ts +6 -0
  426. package/dist/src/ui/hooks/{shellCommandProcessor.test.js → useExecutionLifecycle.test.js} +123 -81
  427. package/dist/src/ui/hooks/useExecutionLifecycle.test.js.map +1 -0
  428. package/dist/src/ui/hooks/useFolderTrust.js +1 -1
  429. package/dist/src/ui/hooks/useFolderTrust.js.map +1 -1
  430. package/dist/src/ui/hooks/useFolderTrust.test.js +1 -1
  431. package/dist/src/ui/hooks/useFolderTrust.test.js.map +1 -1
  432. package/dist/src/ui/hooks/useGeminiStream.d.ts +6 -6
  433. package/dist/src/ui/hooks/useGeminiStream.js +140 -38
  434. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  435. package/dist/src/ui/hooks/useGeminiStream.test.js +176 -22
  436. package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -1
  437. package/dist/src/ui/hooks/useGitBranchName.js +2 -2
  438. package/dist/src/ui/hooks/useGitBranchName.js.map +1 -1
  439. package/dist/src/ui/hooks/useLoadingIndicator.js +1 -1
  440. package/dist/src/ui/hooks/useLoadingIndicator.js.map +1 -1
  441. package/dist/src/ui/hooks/useLoadingIndicator.test.js +10 -0
  442. package/dist/src/ui/hooks/useLoadingIndicator.test.js.map +1 -1
  443. package/dist/src/ui/hooks/usePermissionsModifyTrust.js +2 -2
  444. package/dist/src/ui/hooks/usePermissionsModifyTrust.js.map +1 -1
  445. package/dist/src/ui/hooks/usePermissionsModifyTrust.test.js +1 -1
  446. package/dist/src/ui/hooks/usePermissionsModifyTrust.test.js.map +1 -1
  447. package/dist/src/ui/hooks/usePhraseCycler.js +4 -2
  448. package/dist/src/ui/hooks/usePhraseCycler.js.map +1 -1
  449. package/dist/src/ui/hooks/useSessionBrowser.d.ts +1 -1
  450. package/dist/src/ui/hooks/useSessionBrowser.js +2 -2
  451. package/dist/src/ui/hooks/useSessionBrowser.js.map +1 -1
  452. package/dist/src/ui/hooks/useSlashCompletion.d.ts +1 -1
  453. package/dist/src/ui/hooks/useSlashCompletion.js +37 -63
  454. package/dist/src/ui/hooks/useSlashCompletion.js.map +1 -1
  455. package/dist/src/ui/hooks/useSlashCompletion.test.d.ts +1 -1
  456. package/dist/src/ui/hooks/useSlashCompletion.test.js +57 -47
  457. package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
  458. package/dist/src/ui/hooks/useToolScheduler.d.ts +2 -1
  459. package/dist/src/ui/hooks/useToolScheduler.js +55 -1
  460. package/dist/src/ui/hooks/useToolScheduler.js.map +1 -1
  461. package/dist/src/ui/hooks/useToolScheduler.test.js +107 -9
  462. package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
  463. package/dist/src/ui/key/keyBindings.d.ts +9 -1
  464. package/dist/src/ui/key/keyBindings.js +40 -3
  465. package/dist/src/ui/key/keyBindings.js.map +1 -1
  466. package/dist/src/ui/key/keyMatchers.test.js +12 -2
  467. package/dist/src/ui/key/keyMatchers.test.js.map +1 -1
  468. package/dist/src/ui/layouts/DefaultAppLayout.js +8 -6
  469. package/dist/src/ui/layouts/DefaultAppLayout.js.map +1 -1
  470. package/dist/src/ui/layouts/DefaultAppLayout.test.js +27 -22
  471. package/dist/src/ui/layouts/DefaultAppLayout.test.js.map +1 -1
  472. package/dist/src/ui/noninteractive/nonInteractiveUi.js +1 -1
  473. package/dist/src/ui/themes/builtin/dark/tokyonight-dark.d.ts +7 -0
  474. package/dist/src/ui/themes/builtin/dark/tokyonight-dark.js +147 -0
  475. package/dist/src/ui/themes/builtin/dark/tokyonight-dark.js.map +1 -0
  476. package/dist/src/ui/themes/theme-manager.js +2 -0
  477. package/dist/src/ui/themes/theme-manager.js.map +1 -1
  478. package/dist/src/ui/themes/theme.js +1 -1
  479. package/dist/src/ui/themes/theme.js.map +1 -1
  480. package/dist/src/ui/types.d.ts +10 -2
  481. package/dist/src/ui/types.js.map +1 -1
  482. package/dist/src/ui/utils/CodeColorizer.d.ts +1 -0
  483. package/dist/src/ui/utils/CodeColorizer.js +17 -18
  484. package/dist/src/ui/utils/CodeColorizer.js.map +1 -1
  485. package/dist/src/ui/utils/ConsolePatcher.d.ts +1 -0
  486. package/dist/src/ui/utils/ConsolePatcher.js +12 -5
  487. package/dist/src/ui/utils/ConsolePatcher.js.map +1 -1
  488. package/dist/src/ui/utils/ConsolePatcher.test.d.ts +6 -0
  489. package/dist/src/ui/utils/ConsolePatcher.test.js +199 -0
  490. package/dist/src/ui/utils/ConsolePatcher.test.js.map +1 -0
  491. package/dist/src/ui/utils/TableRenderer.js +3 -3
  492. package/dist/src/ui/utils/TableRenderer.js.map +1 -1
  493. package/dist/src/ui/utils/borderStyles.d.ts +2 -2
  494. package/dist/src/ui/utils/borderStyles.js +2 -2
  495. package/dist/src/ui/utils/borderStyles.js.map +1 -1
  496. package/dist/src/ui/utils/directoryUtils.js +1 -1
  497. package/dist/src/ui/utils/directoryUtils.js.map +1 -1
  498. package/dist/src/ui/utils/fileUtils.d.ts +10 -0
  499. package/dist/src/ui/utils/fileUtils.js +17 -0
  500. package/dist/src/ui/utils/fileUtils.js.map +1 -0
  501. package/dist/src/ui/utils/terminalCapabilityManager.d.ts +1 -0
  502. package/dist/src/ui/utils/terminalCapabilityManager.js +8 -0
  503. package/dist/src/ui/utils/terminalCapabilityManager.js.map +1 -1
  504. package/dist/src/ui/utils/terminalCapabilityManager.test.js +38 -0
  505. package/dist/src/ui/utils/terminalCapabilityManager.test.js.map +1 -1
  506. package/dist/src/ui/utils/toolLayoutUtils.d.ts +1 -1
  507. package/dist/src/ui/utils/toolLayoutUtils.js +1 -1
  508. package/dist/src/ui/utils/ui-sizing.test.js +1 -0
  509. package/dist/src/ui/utils/ui-sizing.test.js.map +1 -1
  510. package/dist/src/ui/utils/updateCheck.d.ts +1 -0
  511. package/dist/src/ui/utils/updateCheck.js.map +1 -1
  512. package/dist/src/utils/activityLogger.js +16 -0
  513. package/dist/src/utils/activityLogger.js.map +1 -1
  514. package/dist/src/utils/cleanup.js +12 -5
  515. package/dist/src/utils/cleanup.js.map +1 -1
  516. package/dist/src/utils/commands.js +15 -0
  517. package/dist/src/utils/commands.js.map +1 -1
  518. package/dist/src/utils/commands.test.js +79 -0
  519. package/dist/src/utils/commands.test.js.map +1 -1
  520. package/dist/src/utils/envVarResolver.d.ts +5 -2
  521. package/dist/src/utils/envVarResolver.js +15 -6
  522. package/dist/src/utils/envVarResolver.js.map +1 -1
  523. package/dist/src/utils/envVarResolver.test.js +41 -24
  524. package/dist/src/utils/envVarResolver.test.js.map +1 -1
  525. package/dist/src/utils/errors.js +4 -4
  526. package/dist/src/utils/errors.js.map +1 -1
  527. package/dist/src/utils/events.d.ts +3 -1
  528. package/dist/src/utils/events.js +1 -0
  529. package/dist/src/utils/events.js.map +1 -1
  530. package/dist/src/utils/gitUtils.js +4 -4
  531. package/dist/src/utils/gitUtils.js.map +1 -1
  532. package/dist/src/utils/handleAutoUpdate.js +10 -3
  533. package/dist/src/utils/handleAutoUpdate.js.map +1 -1
  534. package/dist/src/utils/handleAutoUpdate.test.js +8 -2
  535. package/dist/src/utils/handleAutoUpdate.test.js.map +1 -1
  536. package/dist/src/utils/installationInfo.js +1 -1
  537. package/dist/src/utils/installationInfo.js.map +1 -1
  538. package/dist/src/utils/jsonoutput.js +1 -1
  539. package/dist/src/utils/jsonoutput.js.map +1 -1
  540. package/dist/src/utils/sandboxUtils.js +1 -1
  541. package/dist/src/utils/sandboxUtils.js.map +1 -1
  542. package/dist/src/utils/sessionCleanup.js +7 -30
  543. package/dist/src/utils/sessionCleanup.js.map +1 -1
  544. package/dist/src/utils/sessionCleanup.test.js +3 -0
  545. package/dist/src/utils/sessionCleanup.test.js.map +1 -1
  546. package/dist/src/utils/sessionUtils.js +1 -0
  547. package/dist/src/utils/sessionUtils.js.map +1 -1
  548. package/dist/src/utils/sessionUtils.test.js +179 -3
  549. package/dist/src/utils/sessionUtils.test.js.map +1 -1
  550. package/dist/src/utils/sessions.js +1 -1
  551. package/dist/src/utils/sessions.js.map +1 -1
  552. package/dist/src/utils/skillUtils.js +3 -1
  553. package/dist/src/utils/skillUtils.js.map +1 -1
  554. package/dist/src/utils/skillUtils.test.js +4 -6
  555. package/dist/src/utils/skillUtils.test.js.map +1 -1
  556. package/dist/src/utils/terminalNotifications.js +2 -4
  557. package/dist/src/utils/terminalNotifications.js.map +1 -1
  558. package/dist/src/utils/terminalNotifications.test.js +5 -3
  559. package/dist/src/utils/terminalNotifications.test.js.map +1 -1
  560. package/dist/src/utils/userStartupWarnings.js +2 -2
  561. package/dist/src/utils/userStartupWarnings.js.map +1 -1
  562. package/dist/tsconfig.tsbuildinfo +1 -1
  563. package/package.json +4 -4
  564. package/dist/src/ui/commands/shellsCommand.js.map +0 -1
  565. package/dist/src/ui/commands/shellsCommand.test.js +0 -29
  566. package/dist/src/ui/commands/shellsCommand.test.js.map +0 -1
  567. package/dist/src/ui/components/BackgroundShellDisplay.d.ts +0 -16
  568. package/dist/src/ui/components/BackgroundShellDisplay.js.map +0 -1
  569. package/dist/src/ui/components/BackgroundShellDisplay.test.js.map +0 -1
  570. package/dist/src/ui/hooks/shellCommandProcessor.d.ts +0 -28
  571. package/dist/src/ui/hooks/shellCommandProcessor.js.map +0 -1
  572. package/dist/src/ui/hooks/shellCommandProcessor.test.js.map +0 -1
  573. package/dist/src/ui/hooks/useBackgroundShellManager.d.ts +0 -22
  574. package/dist/src/ui/hooks/useBackgroundShellManager.js +0 -58
  575. package/dist/src/ui/hooks/useBackgroundShellManager.js.map +0 -1
  576. package/dist/src/ui/hooks/useBackgroundShellManager.test.js.map +0 -1
  577. /package/dist/src/{ui/commands/shellsCommand.test.d.ts → nonInteractiveCliAgentSession.test.d.ts} +0 -0
  578. /package/dist/src/ui/{components/BackgroundShellDisplay.test.d.ts → commands/tasksCommand.test.d.ts} +0 -0
  579. /package/dist/src/ui/{hooks/shellCommandProcessor.test.d.ts → components/BackgroundTaskDisplay.test.d.ts} +0 -0
  580. /package/dist/src/ui/hooks/{useBackgroundShellManager.test.d.ts → useBackgroundTaskManager.test.d.ts} +0 -0
@@ -1,17 +1,18 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  /**
3
3
  * @license
4
4
  * Copyright 2025 Google LLC
5
5
  * SPDX-License-Identifier: Apache-2.0
6
6
  */
7
- import { renderWithProviders } from '../../test-utils/render.js';
7
+ import { renderWithProviders, cleanup } from '../../test-utils/render.js';
8
8
  import { createMockSettings } from '../../test-utils/settings.js';
9
9
  import { makeFakeConfig } from '@google/gemini-cli-core';
10
10
  import { waitFor } from '../../test-utils/async.js';
11
- import { act, useState } from 'react';
11
+ import { act, useState, useMemo } from 'react';
12
12
  import { InputPrompt, tryTogglePasteExpansion, } from './InputPrompt.js';
13
+ import { InputContext } from '../contexts/InputContext.js';
13
14
  import { calculateTransformationsForLine, calculateTransformedLine, } from './shared/text-buffer.js';
14
- import { ApprovalMode, debugLogger, } from '@google/gemini-cli-core';
15
+ import { ApprovalMode, debugLogger, coreEvents, } from '@google/gemini-cli-core';
15
16
  import * as path from 'node:path';
16
17
  import { CommandKind, } from '../commands/types.js';
17
18
  import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
@@ -31,7 +32,9 @@ import { terminalCapabilityManager } from '../utils/terminalCapabilityManager.js
31
32
  import { isLowColorDepth } from '../utils/terminalUtils.js';
32
33
  import { cpLen } from '../utils/textUtils.js';
33
34
  import { defaultKeyMatchers, Command } from '../key/keyMatchers.js';
35
+ import { useKeypress } from '../hooks/useKeypress.js';
34
36
  import { appEvents, AppEvent, TransientMessageType, } from '../../utils/events.js';
37
+ import '../../test-utils/customMatchers.js';
35
38
  vi.mock('../hooks/useShellHistory.js');
36
39
  vi.mock('../hooks/useCommandCompletion.js');
37
40
  vi.mock('../hooks/useInputHistory.js');
@@ -52,6 +55,8 @@ vi.mock('ink', async (importOriginal) => {
52
55
  });
53
56
  afterEach(() => {
54
57
  vi.restoreAllMocks();
58
+ vi.useRealTimers();
59
+ cleanup();
55
60
  });
56
61
  const mockSlashCommands = [
57
62
  {
@@ -112,6 +117,26 @@ const mockSlashCommands = [
112
117
  action: vi.fn(),
113
118
  },
114
119
  ];
120
+ const TestInputPrompt = (props) => {
121
+ const contextValue = useMemo(() => ({
122
+ buffer: props.buffer,
123
+ userMessages: props.userMessages,
124
+ shellModeActive: props.shellModeActive,
125
+ copyModeEnabled: props.copyModeEnabled,
126
+ showEscapePrompt: props.showEscapePrompt || false,
127
+ inputWidth: props.inputWidth,
128
+ suggestionsWidth: props.suggestionsWidth,
129
+ }), [
130
+ props.buffer,
131
+ props.userMessages,
132
+ props.shellModeActive,
133
+ props.copyModeEnabled,
134
+ props.showEscapePrompt,
135
+ props.inputWidth,
136
+ props.suggestionsWidth,
137
+ ]);
138
+ return (_jsx(InputContext.Provider, { value: contextValue, children: _jsx(InputPrompt, { ...props }) }));
139
+ };
115
140
  describe('InputPrompt', () => {
116
141
  let props;
117
142
  let mockShellHistory;
@@ -120,6 +145,15 @@ describe('InputPrompt', () => {
120
145
  let mockReverseSearchCompletion;
121
146
  let mockBuffer;
122
147
  let mockCommandContext;
148
+ const GlobalEscapeHandler = ({ onEscape }) => {
149
+ useKeypress((key) => {
150
+ if (key.name !== 'escape')
151
+ return false;
152
+ onEscape();
153
+ return true;
154
+ }, { isActive: true, priority: false });
155
+ return null;
156
+ };
123
157
  const mockedUseShellHistory = vi.mocked(useShellHistory);
124
158
  const mockedUseCommandCompletion = vi.mocked(useCommandCompletion);
125
159
  const mockedUseInputHistory = vi.mocked(useInputHistory);
@@ -134,9 +168,11 @@ describe('InputPrompt', () => {
134
168
  setCleanUiDetailsVisible: mockSetCleanUiDetailsVisible,
135
169
  toggleCleanUiDetailsVisible: mockToggleCleanUiDetailsVisible,
136
170
  revealCleanUiDetailsTemporarily: mockRevealCleanUiDetailsTemporarily,
171
+ addMessage: vi.fn(),
137
172
  };
138
173
  beforeEach(() => {
139
174
  vi.resetAllMocks();
175
+ coreEvents.removeAllListeners();
140
176
  vi.spyOn(terminalCapabilityManager, 'isKittyProtocolEnabled').mockReturnValue(true);
141
177
  mockCommandContext = createMockCommandContext();
142
178
  mockBuffer = {
@@ -145,7 +181,7 @@ describe('InputPrompt', () => {
145
181
  lines: [''],
146
182
  setText: vi.fn((newText, cursorPosition) => {
147
183
  mockBuffer.text = newText;
148
- mockBuffer.lines = [newText];
184
+ mockBuffer.lines = newText.split('\n');
149
185
  let col = 0;
150
186
  if (typeof cursorPosition === 'number') {
151
187
  col = cursorPosition;
@@ -157,16 +193,25 @@ describe('InputPrompt', () => {
157
193
  col = newText.length;
158
194
  }
159
195
  mockBuffer.cursor = [0, col];
160
- mockBuffer.viewportVisualLines = [newText];
161
- mockBuffer.allVisualLines = [newText];
162
- mockBuffer.visualToLogicalMap = [[0, 0]];
196
+ mockBuffer.allVisualLines = newText.split('\n');
197
+ mockBuffer.viewportVisualLines = newText.split('\n');
198
+ mockBuffer.visualToLogicalMap = newText
199
+ .split('\n')
200
+ .map((_, i) => [i, 0]);
163
201
  mockBuffer.visualCursor = [0, col];
202
+ mockBuffer.visualScrollRow = 0;
203
+ mockBuffer.viewportHeight = 10;
204
+ mockBuffer.visualToTransformedMap = newText
205
+ .split('\n')
206
+ .map((_, i) => i);
207
+ mockBuffer.transformationsByLine = newText.split('\n').map(() => []);
164
208
  }),
165
209
  replaceRangeByOffset: vi.fn(),
166
210
  viewportVisualLines: [''],
167
211
  allVisualLines: [''],
168
212
  visualCursor: [0, 0],
169
213
  visualScrollRow: 0,
214
+ viewportHeight: 10,
170
215
  handleInput: vi.fn((key) => {
171
216
  if (defaultKeyMatchers[Command.CLEAR_INPUT](key)) {
172
217
  if (mockBuffer.text.length > 0) {
@@ -280,6 +325,7 @@ describe('InputPrompt', () => {
280
325
  });
281
326
  vi.mocked(clipboardy.read).mockResolvedValue('');
282
327
  props = {
328
+ onQueueMessage: vi.fn(),
283
329
  buffer: mockBuffer,
284
330
  onSubmit: vi.fn(),
285
331
  userMessages: [],
@@ -289,6 +335,7 @@ describe('InputPrompt', () => {
289
335
  getTargetDir: () => path.join('test', 'project', 'src'),
290
336
  getVimMode: () => false,
291
337
  getUseBackgroundColor: () => true,
338
+ getUseTerminalBuffer: () => false,
292
339
  getTerminalBackground: () => undefined,
293
340
  getWorkspaceContext: () => ({
294
341
  getDirectories: () => ['/test/project/src'],
@@ -309,7 +356,7 @@ describe('InputPrompt', () => {
309
356
  });
310
357
  it('should call shellHistory.getPreviousCommand on up arrow in shell mode', async () => {
311
358
  props.shellModeActive = true;
312
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
359
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
313
360
  uiActions,
314
361
  });
315
362
  await act(async () => {
@@ -320,7 +367,7 @@ describe('InputPrompt', () => {
320
367
  });
321
368
  it('should call shellHistory.getNextCommand on down arrow in shell mode', async () => {
322
369
  props.shellModeActive = true;
323
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
370
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
324
371
  uiActions,
325
372
  });
326
373
  await act(async () => {
@@ -332,7 +379,7 @@ describe('InputPrompt', () => {
332
379
  it('should set the buffer text when a shell history command is retrieved', async () => {
333
380
  props.shellModeActive = true;
334
381
  vi.mocked(mockShellHistory.getPreviousCommand).mockReturnValue('previous command');
335
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
382
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
336
383
  uiActions,
337
384
  });
338
385
  await act(async () => {
@@ -347,7 +394,7 @@ describe('InputPrompt', () => {
347
394
  it('should call shellHistory.addCommandToHistory on submit in shell mode', async () => {
348
395
  props.shellModeActive = true;
349
396
  props.buffer.setText('ls -l');
350
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
397
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
351
398
  uiActions,
352
399
  });
353
400
  await act(async () => {
@@ -371,7 +418,7 @@ describe('InputPrompt', () => {
371
418
  ],
372
419
  activeSuggestionIndex: 0,
373
420
  });
374
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
421
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
375
422
  uiActions,
376
423
  });
377
424
  // Press Enter without navigating — should dismiss suggestions and fall
@@ -398,7 +445,7 @@ describe('InputPrompt', () => {
398
445
  ],
399
446
  activeSuggestionIndex: 1,
400
447
  });
401
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
448
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
402
449
  uiActions,
403
450
  });
404
451
  // Press ArrowDown to navigate, then Enter to accept
@@ -417,7 +464,7 @@ describe('InputPrompt', () => {
417
464
  });
418
465
  it('should NOT call shell history methods when not in shell mode', async () => {
419
466
  props.buffer.setText('some text');
420
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
467
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
421
468
  uiActions,
422
469
  });
423
470
  await act(async () => {
@@ -442,7 +489,7 @@ describe('InputPrompt', () => {
442
489
  mockBuffer.allVisualLines = ['line 1', 'line 2'];
443
490
  mockBuffer.visualCursor = [0, 5]; // First line, not at start
444
491
  mockBuffer.visualScrollRow = 0;
445
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
492
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
446
493
  uiActions,
447
494
  });
448
495
  await act(async () => {
@@ -458,7 +505,7 @@ describe('InputPrompt', () => {
458
505
  mockBuffer.allVisualLines = ['line 1', 'line 2'];
459
506
  mockBuffer.visualCursor = [0, 0]; // First line, at start
460
507
  mockBuffer.visualScrollRow = 0;
461
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
508
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
462
509
  uiActions,
463
510
  });
464
511
  await act(async () => {
@@ -474,7 +521,7 @@ describe('InputPrompt', () => {
474
521
  mockBuffer.allVisualLines = ['line 1', 'line 2'];
475
522
  mockBuffer.visualCursor = [1, 0]; // Last line, not at end
476
523
  mockBuffer.visualScrollRow = 0;
477
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
524
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
478
525
  uiActions,
479
526
  });
480
527
  await act(async () => {
@@ -490,7 +537,7 @@ describe('InputPrompt', () => {
490
537
  mockBuffer.allVisualLines = ['line 1', 'line 2'];
491
538
  mockBuffer.visualCursor = [1, 6]; // Last line, at end ("line 2" is length 6)
492
539
  mockBuffer.visualScrollRow = 0;
493
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
540
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
494
541
  uiActions,
495
542
  });
496
543
  await act(async () => {
@@ -513,7 +560,7 @@ describe('InputPrompt', () => {
513
560
  ],
514
561
  });
515
562
  props.buffer.setText('/mem');
516
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
563
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
517
564
  uiActions,
518
565
  });
519
566
  // Test up arrow
@@ -538,7 +585,7 @@ describe('InputPrompt', () => {
538
585
  ],
539
586
  });
540
587
  props.buffer.setText('/mem');
541
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
588
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
542
589
  uiActions,
543
590
  });
544
591
  // Test down arrow
@@ -559,7 +606,7 @@ describe('InputPrompt', () => {
559
606
  showSuggestions: false,
560
607
  });
561
608
  props.buffer.setText('some text');
562
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
609
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
563
610
  uiActions,
564
611
  });
565
612
  await act(async () => {
@@ -584,7 +631,7 @@ describe('InputPrompt', () => {
584
631
  });
585
632
  it('should clear the buffer and reset completion on Ctrl+C', async () => {
586
633
  mockBuffer.text = 'some text';
587
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
634
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
588
635
  uiActions,
589
636
  });
590
637
  await act(async () => {
@@ -605,7 +652,7 @@ describe('InputPrompt', () => {
605
652
  it('should handle Ctrl+V when clipboard has an image', async () => {
606
653
  vi.mocked(clipboardUtils.clipboardHasImage).mockResolvedValue(true);
607
654
  vi.mocked(clipboardUtils.saveClipboardImage).mockResolvedValue('/test/.cell-cli-clipboard/clipboard-123.png');
608
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
655
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
609
656
  // Send Ctrl+V
610
657
  await act(async () => {
611
658
  stdin.write('\x16'); // Ctrl+V
@@ -620,7 +667,7 @@ describe('InputPrompt', () => {
620
667
  });
621
668
  it('should not insert anything when clipboard has no image', async () => {
622
669
  vi.mocked(clipboardUtils.clipboardHasImage).mockResolvedValue(false);
623
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
670
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
624
671
  await act(async () => {
625
672
  stdin.write('\x16'); // Ctrl+V
626
673
  });
@@ -634,7 +681,7 @@ describe('InputPrompt', () => {
634
681
  it('should handle image save failure gracefully', async () => {
635
682
  vi.mocked(clipboardUtils.clipboardHasImage).mockResolvedValue(true);
636
683
  vi.mocked(clipboardUtils.saveClipboardImage).mockResolvedValue(null);
637
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
684
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
638
685
  await act(async () => {
639
686
  stdin.write('\x16'); // Ctrl+V
640
687
  });
@@ -654,7 +701,7 @@ describe('InputPrompt', () => {
654
701
  vi.mocked(mockBuffer.getOffset).mockReturnValue(5);
655
702
  mockBuffer.lines = ['Hello world'];
656
703
  mockBuffer.replaceRangeByOffset = vi.fn();
657
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
704
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
658
705
  await act(async () => {
659
706
  stdin.write('\x16'); // Ctrl+V
660
707
  });
@@ -675,7 +722,7 @@ describe('InputPrompt', () => {
675
722
  .spyOn(debugLogger, 'error')
676
723
  .mockImplementation(() => { });
677
724
  vi.mocked(clipboardUtils.clipboardHasImage).mockRejectedValue(new Error('Clipboard error'));
678
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
725
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
679
726
  await act(async () => {
680
727
  stdin.write('\x16'); // Ctrl+V
681
728
  });
@@ -692,7 +739,7 @@ describe('InputPrompt', () => {
692
739
  vi.mocked(clipboardUtils.clipboardHasImage).mockResolvedValue(false);
693
740
  vi.mocked(clipboardy.read).mockResolvedValue('pasted text');
694
741
  vi.mocked(mockBuffer.replaceRangeByOffset).mockClear();
695
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
742
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
696
743
  await act(async () => {
697
744
  stdin.write('\x16'); // Ctrl+V
698
745
  });
@@ -707,7 +754,7 @@ describe('InputPrompt', () => {
707
754
  const settings = createMockSettings({
708
755
  experimental: { useOSC52Paste: true },
709
756
  });
710
- const { stdout, stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), { settings });
757
+ const { stdout, stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), { settings });
711
758
  const writeSpy = vi.spyOn(stdout, 'write');
712
759
  await act(async () => {
713
760
  stdin.write('\x16'); // Ctrl+V
@@ -759,7 +806,7 @@ describe('InputPrompt', () => {
759
806
  activeSuggestionIndex: activeIndex,
760
807
  });
761
808
  props.buffer.setText(bufferText);
762
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
809
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
763
810
  uiActions,
764
811
  });
765
812
  await act(async () => stdin.write('\t'));
@@ -774,7 +821,7 @@ describe('InputPrompt', () => {
774
821
  activeSuggestionIndex: 0,
775
822
  });
776
823
  props.buffer.setText('/mem');
777
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
824
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
778
825
  uiActions,
779
826
  });
780
827
  await act(async () => {
@@ -803,7 +850,7 @@ describe('InputPrompt', () => {
803
850
  activeSuggestionIndex: 0,
804
851
  });
805
852
  props.buffer.setText('/?');
806
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
853
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
807
854
  uiActions,
808
855
  });
809
856
  await act(async () => {
@@ -812,9 +859,55 @@ describe('InputPrompt', () => {
812
859
  await waitFor(() => expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0));
813
860
  unmount();
814
861
  });
862
+ it('queues a message when Tab is pressed during generation', async () => {
863
+ props.buffer.setText('A new prompt');
864
+ props.streamingState = StreamingState.Responding;
865
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
866
+ uiActions,
867
+ });
868
+ await act(async () => {
869
+ stdin.write('\t');
870
+ });
871
+ await waitFor(() => {
872
+ expect(props.onQueueMessage).toHaveBeenCalledWith('A new prompt');
873
+ expect(props.buffer.text).toBe('');
874
+ });
875
+ unmount();
876
+ });
877
+ it('shows an error when attempting to queue a slash command', async () => {
878
+ props.buffer.setText('/clear');
879
+ props.streamingState = StreamingState.Responding;
880
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
881
+ uiActions,
882
+ });
883
+ await act(async () => {
884
+ stdin.write('\t');
885
+ });
886
+ await waitFor(() => {
887
+ expect(props.setQueueErrorMessage).toHaveBeenCalledWith('Slash commands cannot be queued');
888
+ expect(props.onQueueMessage).not.toHaveBeenCalled();
889
+ });
890
+ unmount();
891
+ });
892
+ it('shows an error when attempting to queue a shell command', async () => {
893
+ props.shellModeActive = true;
894
+ props.buffer.setText('ls');
895
+ props.streamingState = StreamingState.Responding;
896
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
897
+ uiActions,
898
+ });
899
+ await act(async () => {
900
+ stdin.write('\t');
901
+ });
902
+ await waitFor(() => {
903
+ expect(props.setQueueErrorMessage).toHaveBeenCalledWith('Shell commands cannot be queued');
904
+ expect(props.onQueueMessage).not.toHaveBeenCalled();
905
+ });
906
+ unmount();
907
+ });
815
908
  it('should not submit on Enter when the buffer is empty or only contains whitespace', async () => {
816
909
  props.buffer.setText(' '); // Set buffer to whitespace
817
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
910
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
818
911
  uiActions,
819
912
  });
820
913
  await act(async () => {
@@ -832,7 +925,7 @@ describe('InputPrompt', () => {
832
925
  isPerfectMatch: true,
833
926
  });
834
927
  props.buffer.setText('/clear');
835
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
928
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
836
929
  uiActions,
837
930
  });
838
931
  await act(async () => {
@@ -853,7 +946,7 @@ describe('InputPrompt', () => {
853
946
  isPerfectMatch: true,
854
947
  });
855
948
  props.buffer.text = '/review';
856
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
949
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
857
950
  uiActions,
858
951
  });
859
952
  await act(async () => {
@@ -876,7 +969,7 @@ describe('InputPrompt', () => {
876
969
  isPerfectMatch: true, // /review is a perfect match
877
970
  });
878
971
  props.buffer.text = '/review';
879
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
972
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
880
973
  uiActions,
881
974
  });
882
975
  await act(async () => {
@@ -897,7 +990,7 @@ describe('InputPrompt', () => {
897
990
  isPerfectMatch: false, // Added explicit isPerfectMatch false
898
991
  });
899
992
  props.buffer.setText('/clear');
900
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
993
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
901
994
  uiActions,
902
995
  });
903
996
  await act(async () => {
@@ -916,7 +1009,7 @@ describe('InputPrompt', () => {
916
1009
  completionMode: CompletionMode.AT,
917
1010
  });
918
1011
  props.buffer.text = '@file.txt';
919
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
1012
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
920
1013
  uiActions,
921
1014
  });
922
1015
  await act(async () => {
@@ -938,7 +1031,7 @@ describe('InputPrompt', () => {
938
1031
  completionMode: CompletionMode.AT,
939
1032
  });
940
1033
  props.buffer.text = '@file.txt';
941
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
1034
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
942
1035
  uiActions,
943
1036
  });
944
1037
  await act(async () => {
@@ -978,7 +1071,7 @@ describe('InputPrompt', () => {
978
1071
  props.buffer.setText('/ab');
979
1072
  props.buffer.lines = ['/ab'];
980
1073
  props.buffer.cursor = [0, 3];
981
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
1074
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
982
1075
  uiActions,
983
1076
  });
984
1077
  await act(async () => {
@@ -1012,7 +1105,7 @@ describe('InputPrompt', () => {
1012
1105
  props.buffer.setText('/sh');
1013
1106
  props.buffer.lines = ['/sh'];
1014
1107
  props.buffer.cursor = [0, 3];
1015
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
1108
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
1016
1109
  uiActions,
1017
1110
  });
1018
1111
  await act(async () => {
@@ -1045,7 +1138,7 @@ describe('InputPrompt', () => {
1045
1138
  props.buffer.setText('/ab');
1046
1139
  props.buffer.lines = ['/ab'];
1047
1140
  props.buffer.cursor = [0, 3];
1048
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
1141
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
1049
1142
  uiActions,
1050
1143
  });
1051
1144
  await act(async () => {
@@ -1070,7 +1163,7 @@ describe('InputPrompt', () => {
1070
1163
  props.buffer.setText('/ab');
1071
1164
  props.buffer.lines = ['/ab'];
1072
1165
  props.buffer.cursor = [0, 3];
1073
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
1166
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
1074
1167
  uiActions,
1075
1168
  });
1076
1169
  await act(async () => {
@@ -1101,7 +1194,7 @@ describe('InputPrompt', () => {
1101
1194
  props.buffer.setText('/find');
1102
1195
  props.buffer.lines = ['/find'];
1103
1196
  props.buffer.cursor = [0, 5];
1104
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
1197
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
1105
1198
  uiActions,
1106
1199
  });
1107
1200
  await act(async () => {
@@ -1143,7 +1236,7 @@ describe('InputPrompt', () => {
1143
1236
  props.buffer.setText('/mcp auth ');
1144
1237
  props.buffer.lines = ['/mcp auth '];
1145
1238
  props.buffer.cursor = [0, 10];
1146
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
1239
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
1147
1240
  uiActions,
1148
1241
  });
1149
1242
  await act(async () => {
@@ -1190,7 +1283,7 @@ describe('InputPrompt', () => {
1190
1283
  props.buffer.setText('/extensions enable ');
1191
1284
  props.buffer.lines = ['/extensions enable '];
1192
1285
  props.buffer.cursor = [0, 19];
1193
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
1286
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
1194
1287
  uiActions,
1195
1288
  });
1196
1289
  await act(async () => {
@@ -1232,7 +1325,7 @@ describe('InputPrompt', () => {
1232
1325
  props.buffer.setText('/chat resu');
1233
1326
  props.buffer.lines = ['/chat resu'];
1234
1327
  props.buffer.cursor = [0, 10];
1235
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
1328
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
1236
1329
  uiActions,
1237
1330
  });
1238
1331
  await act(async () => {
@@ -1253,7 +1346,7 @@ describe('InputPrompt', () => {
1253
1346
  activeSuggestionIndex: 0,
1254
1347
  });
1255
1348
  props.buffer.setText('@src/components/');
1256
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
1349
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
1257
1350
  uiActions,
1258
1351
  });
1259
1352
  await act(async () => {
@@ -1268,7 +1361,7 @@ describe('InputPrompt', () => {
1268
1361
  mockBuffer.text = 'first line\\';
1269
1362
  mockBuffer.cursor = [0, 11];
1270
1363
  mockBuffer.lines = ['first line\\'];
1271
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
1364
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
1272
1365
  uiActions,
1273
1366
  });
1274
1367
  await act(async () => {
@@ -1285,7 +1378,7 @@ describe('InputPrompt', () => {
1285
1378
  await act(async () => {
1286
1379
  props.buffer.setText('some text to clear');
1287
1380
  });
1288
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
1381
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
1289
1382
  uiActions,
1290
1383
  });
1291
1384
  await act(async () => {
@@ -1300,7 +1393,7 @@ describe('InputPrompt', () => {
1300
1393
  });
1301
1394
  it('should render correctly in plan mode', async () => {
1302
1395
  props.approvalMode = ApprovalMode.PLAN;
1303
- const { stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
1396
+ const { stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
1304
1397
  await waitFor(() => {
1305
1398
  const frame = stdout.lastFrameRaw();
1306
1399
  // In plan mode it uses '>' but with success color.
@@ -1313,7 +1406,7 @@ describe('InputPrompt', () => {
1313
1406
  });
1314
1407
  it('should NOT clear the buffer on Ctrl+C if it is empty', async () => {
1315
1408
  props.buffer.text = '';
1316
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
1409
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
1317
1410
  uiActions,
1318
1411
  });
1319
1412
  await act(async () => {
@@ -1325,7 +1418,7 @@ describe('InputPrompt', () => {
1325
1418
  unmount();
1326
1419
  });
1327
1420
  it('should call setBannerVisible(false) when clear screen key is pressed', async () => {
1328
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
1421
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
1329
1422
  uiActions,
1330
1423
  });
1331
1424
  await act(async () => {
@@ -1344,7 +1437,7 @@ describe('InputPrompt', () => {
1344
1437
  vi.restoreAllMocks();
1345
1438
  });
1346
1439
  it('should render with background color by default', async () => {
1347
- const { stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
1440
+ const { stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
1348
1441
  await waitFor(() => {
1349
1442
  const frame = stdout.lastFrameRaw();
1350
1443
  expect(frame).toContain('▀');
@@ -1361,7 +1454,7 @@ describe('InputPrompt', () => {
1361
1454
  { color: '#fff', name: '#fff' },
1362
1455
  ])('should render with safe grey background but NO side borders in 8-bit mode when background is $name', async ({ color }) => {
1363
1456
  vi.mocked(isLowColorDepth).mockReturnValue(true);
1364
- const { stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
1457
+ const { stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
1365
1458
  uiState: {
1366
1459
  terminalBackgroundColor: color,
1367
1460
  },
@@ -1385,7 +1478,7 @@ describe('InputPrompt', () => {
1385
1478
  });
1386
1479
  it('should NOT render with background color but SHOULD render horizontal lines when color depth is < 24 and background is NOT black', async () => {
1387
1480
  vi.mocked(isLowColorDepth).mockReturnValue(true);
1388
- const { stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
1481
+ const { stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
1389
1482
  uiState: {
1390
1483
  terminalBackgroundColor: '#333333',
1391
1484
  },
@@ -1403,7 +1496,7 @@ describe('InputPrompt', () => {
1403
1496
  });
1404
1497
  it('should handle 4-bit color mode (16 colors) as low color depth', async () => {
1405
1498
  vi.mocked(isLowColorDepth).mockReturnValue(true);
1406
- const { stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
1499
+ const { stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
1407
1500
  uiState: {
1408
1501
  terminalBackgroundColor: 'black',
1409
1502
  },
@@ -1417,7 +1510,7 @@ describe('InputPrompt', () => {
1417
1510
  });
1418
1511
  it('should render horizontal lines (but NO background) in 8-bit mode when background is blue', async () => {
1419
1512
  vi.mocked(isLowColorDepth).mockReturnValue(true);
1420
- const { stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
1513
+ const { stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
1421
1514
  uiState: {
1422
1515
  terminalBackgroundColor: 'blue',
1423
1516
  },
@@ -1437,7 +1530,7 @@ describe('InputPrompt', () => {
1437
1530
  });
1438
1531
  it('should render with plain borders when useBackgroundColor is false', async () => {
1439
1532
  props.config.getUseBackgroundColor = () => false;
1440
- const { stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
1533
+ const { stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
1441
1534
  await waitFor(() => {
1442
1535
  const frame = stdout.lastFrameRaw();
1443
1536
  expect(frame).not.toContain('▀');
@@ -1539,7 +1632,7 @@ describe('InputPrompt', () => {
1539
1632
  ? [{ label: 'suggestion', value: 'suggestion' }]
1540
1633
  : [],
1541
1634
  });
1542
- const { unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
1635
+ const { unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
1543
1636
  uiActions,
1544
1637
  });
1545
1638
  await waitFor(() => {
@@ -1576,7 +1669,7 @@ describe('InputPrompt', () => {
1576
1669
  },
1577
1670
  ])('$name', async ({ vimHandled, expectBufferHandleInput }) => {
1578
1671
  props.vimHandleInput = vi.fn().mockReturnValue(vimHandled);
1579
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
1672
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
1580
1673
  await act(async () => stdin.write('i'));
1581
1674
  await waitFor(() => {
1582
1675
  expect(props.vimHandleInput).toHaveBeenCalled();
@@ -1593,7 +1686,7 @@ describe('InputPrompt', () => {
1593
1686
  describe('unfocused paste', () => {
1594
1687
  it('should handle bracketed paste when not focused', async () => {
1595
1688
  props.focus = false;
1596
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
1689
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
1597
1690
  await act(async () => {
1598
1691
  stdin.write('\x1B[200~pasted text\x1B[201~');
1599
1692
  });
@@ -1607,7 +1700,7 @@ describe('InputPrompt', () => {
1607
1700
  });
1608
1701
  it('should ignore regular keypresses when not focused', async () => {
1609
1702
  props.focus = false;
1610
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
1703
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
1611
1704
  await act(async () => {
1612
1705
  stdin.write('a');
1613
1706
  });
@@ -1672,10 +1765,11 @@ describe('InputPrompt', () => {
1672
1765
  ])('should display cursor correctly $name', async ({ text, visualCursor }) => {
1673
1766
  mockBuffer.text = text;
1674
1767
  mockBuffer.lines = [text];
1768
+ mockBuffer.allVisualLines = [text];
1675
1769
  mockBuffer.viewportVisualLines = [text];
1676
1770
  mockBuffer.visualCursor = visualCursor;
1677
1771
  props.config.getUseBackgroundColor = () => false;
1678
- const renderResult = await renderWithProviders(_jsx(InputPrompt, { ...props }));
1772
+ const renderResult = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
1679
1773
  await renderResult.waitUntilReady();
1680
1774
  await expect(renderResult).toMatchSvgSnapshot();
1681
1775
  renderResult.unmount();
@@ -1714,11 +1808,12 @@ describe('InputPrompt', () => {
1714
1808
  ])('should display cursor correctly $name in a multiline block', async ({ text, visualCursor, visualToLogicalMap }) => {
1715
1809
  mockBuffer.text = text;
1716
1810
  mockBuffer.lines = text.split('\n');
1811
+ mockBuffer.allVisualLines = text.split('\n');
1717
1812
  mockBuffer.viewportVisualLines = text.split('\n');
1718
1813
  mockBuffer.visualCursor = visualCursor;
1719
1814
  mockBuffer.visualToLogicalMap = visualToLogicalMap;
1720
1815
  props.config.getUseBackgroundColor = () => false;
1721
- const renderResult = await renderWithProviders(_jsx(InputPrompt, { ...props }));
1816
+ const renderResult = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
1722
1817
  await renderResult.waitUntilReady();
1723
1818
  await expect(renderResult).toMatchSvgSnapshot();
1724
1819
  renderResult.unmount();
@@ -1727,6 +1822,7 @@ describe('InputPrompt', () => {
1727
1822
  const text = 'first line\n\nthird line';
1728
1823
  mockBuffer.text = text;
1729
1824
  mockBuffer.lines = text.split('\n');
1825
+ mockBuffer.allVisualLines = text.split('\n');
1730
1826
  mockBuffer.viewportVisualLines = text.split('\n');
1731
1827
  mockBuffer.visualCursor = [1, 0]; // cursor on the blank line
1732
1828
  mockBuffer.visualToLogicalMap = [
@@ -1735,18 +1831,102 @@ describe('InputPrompt', () => {
1735
1831
  [2, 0],
1736
1832
  ];
1737
1833
  props.config.getUseBackgroundColor = () => false;
1738
- const renderResult = await renderWithProviders(_jsx(InputPrompt, { ...props }));
1834
+ const renderResult = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
1739
1835
  await renderResult.waitUntilReady();
1740
1836
  await expect(renderResult).toMatchSvgSnapshot();
1741
1837
  renderResult.unmount();
1742
1838
  });
1743
1839
  });
1744
1840
  });
1841
+ describe('scrolling large inputs', () => {
1842
+ it('should correctly render scrolling down and up for large inputs', async () => {
1843
+ const lines = Array.from({ length: 50 }).map((_, i) => `testline ${i}`);
1844
+ // Since we need to test how the React component tree responds to TextBuffer state changes,
1845
+ // we must provide a fake TextBuffer implementation that triggers re-renders like the real one.
1846
+ const TestWrapper = () => {
1847
+ const [bufferState, setBufferState] = useState({
1848
+ text: lines.join('\n'),
1849
+ lines,
1850
+ allVisualLines: lines,
1851
+ viewportVisualLines: lines.slice(0, 10),
1852
+ visualToLogicalMap: lines.map((_, i) => [i, 0]),
1853
+ visualCursor: [0, 0],
1854
+ visualScrollRow: 0,
1855
+ viewportHeight: 10,
1856
+ });
1857
+ const fakeBuffer = {
1858
+ ...mockBuffer,
1859
+ ...bufferState,
1860
+ handleInput: vi.fn().mockImplementation((key) => {
1861
+ let newRow = bufferState.visualCursor[0];
1862
+ let newScroll = bufferState.visualScrollRow;
1863
+ if (key.name === 'down') {
1864
+ newRow = Math.min(49, newRow + 1);
1865
+ if (newRow >= newScroll + 10)
1866
+ newScroll++;
1867
+ }
1868
+ else if (key.name === 'up') {
1869
+ newRow = Math.max(0, newRow - 1);
1870
+ if (newRow < newScroll)
1871
+ newScroll--;
1872
+ }
1873
+ setBufferState({
1874
+ ...bufferState,
1875
+ visualCursor: [newRow, 0],
1876
+ visualScrollRow: newScroll,
1877
+ viewportVisualLines: lines.slice(newScroll, newScroll + 10),
1878
+ });
1879
+ return true;
1880
+ }),
1881
+ };
1882
+ const inputState = {
1883
+ buffer: fakeBuffer,
1884
+ userMessages: [],
1885
+ shellModeActive: false,
1886
+ showEscapePrompt: false,
1887
+ copyModeEnabled: false,
1888
+ inputWidth: 80,
1889
+ suggestionsWidth: 80,
1890
+ };
1891
+ return (_jsx(InputContext.Provider, { value: inputState, children: _jsx(InputPrompt, { ...props }) }));
1892
+ };
1893
+ const { stdout, unmount, stdin } = await renderWithProviders(_jsx(TestWrapper, {}), {
1894
+ uiActions,
1895
+ });
1896
+ // Verify initial render
1897
+ await waitFor(() => {
1898
+ expect(stdout.lastFrame()).toContain('testline 0');
1899
+ expect(stdout.lastFrame()).not.toContain('testline 49');
1900
+ });
1901
+ // Move cursor to bottom
1902
+ for (let i = 0; i < 49; i++) {
1903
+ act(() => {
1904
+ stdin.write('\x1b[B'); // Arrow Down
1905
+ });
1906
+ }
1907
+ await waitFor(() => {
1908
+ expect(stdout.lastFrame()).toContain('testline 49');
1909
+ expect(stdout.lastFrame()).not.toContain('testline 0');
1910
+ });
1911
+ // Move cursor back to top
1912
+ for (let i = 0; i < 49; i++) {
1913
+ act(() => {
1914
+ stdin.write('\x1b[A'); // Arrow Up
1915
+ });
1916
+ }
1917
+ await waitFor(() => {
1918
+ expect(stdout.lastFrame()).toContain('testline 0');
1919
+ expect(stdout.lastFrame()).not.toContain('testline 49');
1920
+ });
1921
+ unmount();
1922
+ });
1923
+ });
1745
1924
  describe('multiline rendering', () => {
1746
1925
  it('should correctly render multiline input including blank lines', async () => {
1747
1926
  const text = 'hello\n\nworld';
1748
1927
  mockBuffer.text = text;
1749
1928
  mockBuffer.lines = text.split('\n');
1929
+ mockBuffer.allVisualLines = text.split('\n');
1750
1930
  mockBuffer.viewportVisualLines = text.split('\n');
1751
1931
  mockBuffer.allVisualLines = text.split('\n');
1752
1932
  mockBuffer.visualCursor = [2, 5]; // cursor at the end of "world"
@@ -1757,7 +1937,7 @@ describe('InputPrompt', () => {
1757
1937
  [2, 0],
1758
1938
  ];
1759
1939
  props.config.getUseBackgroundColor = () => false;
1760
- const renderResult = await renderWithProviders(_jsx(InputPrompt, { ...props }));
1940
+ const renderResult = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
1761
1941
  await renderResult.waitUntilReady();
1762
1942
  await expect(renderResult).toMatchSvgSnapshot();
1763
1943
  renderResult.unmount();
@@ -1778,7 +1958,7 @@ describe('InputPrompt', () => {
1778
1958
  pastedText: 'This\r\nis\r\na\r\nmultiline\r\npaste.',
1779
1959
  },
1780
1960
  ])('should handle multiline paste $description', async ({ pastedText }) => {
1781
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
1961
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
1782
1962
  // Simulate a bracketed paste event from the terminal
1783
1963
  await act(async () => {
1784
1964
  stdin.write(`\x1b[200~${pastedText}\x1b[201~`);
@@ -1799,7 +1979,7 @@ describe('InputPrompt', () => {
1799
1979
  vi.mocked(clipboardUtils.clipboardHasImage).mockResolvedValue(false);
1800
1980
  const largeText = '1\n2\n3\n4\n5\n6';
1801
1981
  vi.mocked(clipboardy.read).mockResolvedValue(largeText);
1802
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
1982
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
1803
1983
  await act(async () => {
1804
1984
  stdin.write('\x16'); // Ctrl+V
1805
1985
  });
@@ -1812,7 +1992,7 @@ describe('InputPrompt', () => {
1812
1992
  vi.mocked(clipboardUtils.clipboardHasImage).mockResolvedValue(false);
1813
1993
  const largeText = 'a'.repeat(501);
1814
1994
  vi.mocked(clipboardy.read).mockResolvedValue(largeText);
1815
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
1995
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
1816
1996
  await act(async () => {
1817
1997
  stdin.write('\x16'); // Ctrl+V
1818
1998
  });
@@ -1825,7 +2005,7 @@ describe('InputPrompt', () => {
1825
2005
  vi.mocked(clipboardUtils.clipboardHasImage).mockResolvedValue(false);
1826
2006
  const smallText = 'hello world';
1827
2007
  vi.mocked(clipboardy.read).mockResolvedValue(smallText);
1828
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2008
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
1829
2009
  await act(async () => {
1830
2010
  stdin.write('\x16'); // Ctrl+V
1831
2011
  });
@@ -1840,7 +2020,7 @@ describe('InputPrompt', () => {
1840
2020
  const id = '[Pasted Text: 6 lines]';
1841
2021
  mockBuffer.text = `Check this: ${id}`;
1842
2022
  mockBuffer.pastedContent = { [id]: largeText };
1843
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2023
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
1844
2024
  await act(async () => {
1845
2025
  stdin.write('\r'); // Enter
1846
2026
  });
@@ -1865,7 +2045,7 @@ describe('InputPrompt', () => {
1865
2045
  it('should prevent auto-submission immediately after an unsafe paste', async () => {
1866
2046
  // isTerminalPasteTrusted will be false due to beforeEach setup.
1867
2047
  props.buffer.text = 'some command';
1868
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2048
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
1869
2049
  await act(async () => {
1870
2050
  await vi.runAllTimersAsync();
1871
2051
  });
@@ -1894,7 +2074,7 @@ describe('InputPrompt', () => {
1894
2074
  completionMode: CompletionMode.AT,
1895
2075
  });
1896
2076
  props.buffer.text = '@file.txt';
1897
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2077
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
1898
2078
  // Simulate an unsafe paste of a perfect match
1899
2079
  await act(async () => {
1900
2080
  stdin.write(`\x1b[200~@file.txt\x1b[201~`);
@@ -1912,7 +2092,7 @@ describe('InputPrompt', () => {
1912
2092
  it('should allow submission after unsafe paste protection timeout', async () => {
1913
2093
  // isTerminalPasteTrusted will be false due to beforeEach setup.
1914
2094
  props.buffer.text = 'pasted text';
1915
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2095
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
1916
2096
  await act(async () => {
1917
2097
  await vi.runAllTimersAsync();
1918
2098
  });
@@ -1949,7 +2129,7 @@ describe('InputPrompt', () => {
1949
2129
  ])('should allow immediate submission for a trusted paste ($name)', async ({ setup }) => {
1950
2130
  setup();
1951
2131
  props.buffer.text = 'pasted command';
1952
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2132
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
1953
2133
  await act(async () => {
1954
2134
  await vi.runAllTimersAsync();
1955
2135
  });
@@ -1974,7 +2154,7 @@ describe('InputPrompt', () => {
1974
2154
  it('should not interfere with normal Enter key submission when no recent paste', async () => {
1975
2155
  // Set up buffer with text before rendering to ensure submission works
1976
2156
  props.buffer.text = 'normal command';
1977
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2157
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
1978
2158
  await act(async () => {
1979
2159
  await vi.runAllTimersAsync();
1980
2160
  });
@@ -1997,7 +2177,7 @@ describe('InputPrompt', () => {
1997
2177
  const onEscapePromptChange = vi.fn();
1998
2178
  props.onEscapePromptChange = onEscapePromptChange;
1999
2179
  props.buffer.setText('text to clear');
2000
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2180
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2001
2181
  await act(async () => {
2002
2182
  stdin.write('\x03');
2003
2183
  vi.advanceTimersByTime(100);
@@ -2011,7 +2191,7 @@ describe('InputPrompt', () => {
2011
2191
  props.onEscapePromptChange = onEscapePromptChange;
2012
2192
  props.buffer.setText('');
2013
2193
  vi.mocked(props.buffer.setText).mockClear();
2014
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
2194
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
2015
2195
  uiState: {
2016
2196
  history: [{ id: 1, type: 'user', text: 'test' }],
2017
2197
  },
@@ -2030,7 +2210,7 @@ describe('InputPrompt', () => {
2030
2210
  props.onEscapePromptChange = onEscapePromptChange;
2031
2211
  props.buffer.setText('some text');
2032
2212
  vi.mocked(props.buffer.setText).mockClear();
2033
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2213
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2034
2214
  await act(async () => {
2035
2215
  stdin.write('\x1B\x1B');
2036
2216
  vi.advanceTimersByTime(100);
@@ -2043,7 +2223,7 @@ describe('InputPrompt', () => {
2043
2223
  const onEscapePromptChange = vi.fn();
2044
2224
  props.onEscapePromptChange = onEscapePromptChange;
2045
2225
  props.buffer.setText('some text');
2046
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2226
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2047
2227
  await act(async () => {
2048
2228
  stdin.write('\x1B');
2049
2229
  await waitFor(() => {
@@ -2060,7 +2240,7 @@ describe('InputPrompt', () => {
2060
2240
  });
2061
2241
  it('should handle ESC in shell mode by disabling shell mode', async () => {
2062
2242
  props.shellModeActive = true;
2063
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2243
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2064
2244
  await act(async () => {
2065
2245
  stdin.write('\x1B');
2066
2246
  vi.advanceTimersByTime(100);
@@ -2068,13 +2248,43 @@ describe('InputPrompt', () => {
2068
2248
  });
2069
2249
  unmount();
2070
2250
  });
2251
+ it('should not propagate ESC to global cancellation handler when shell mode is active (responding)', async () => {
2252
+ props.shellModeActive = true;
2253
+ props.streamingState = StreamingState.Responding;
2254
+ const onGlobalEscape = vi.fn();
2255
+ const { stdin, unmount } = await renderWithProviders(_jsxs(_Fragment, { children: [_jsx(GlobalEscapeHandler, { onEscape: onGlobalEscape }), _jsx(TestInputPrompt, { ...props })] }));
2256
+ await act(async () => {
2257
+ stdin.write('\x1B');
2258
+ vi.advanceTimersByTime(100);
2259
+ });
2260
+ await waitFor(() => {
2261
+ expect(props.setShellModeActive).toHaveBeenCalledWith(false);
2262
+ });
2263
+ expect(onGlobalEscape).not.toHaveBeenCalled();
2264
+ unmount();
2265
+ });
2266
+ it('should allow ESC to reach global cancellation handler when responding and no overlay is active', async () => {
2267
+ props.shellModeActive = false;
2268
+ props.streamingState = StreamingState.Responding;
2269
+ const onGlobalEscape = vi.fn();
2270
+ const { stdin, unmount } = await renderWithProviders(_jsxs(_Fragment, { children: [_jsx(GlobalEscapeHandler, { onEscape: onGlobalEscape }), _jsx(TestInputPrompt, { ...props })] }));
2271
+ await act(async () => {
2272
+ stdin.write('\x1B');
2273
+ vi.advanceTimersByTime(100);
2274
+ });
2275
+ await waitFor(() => {
2276
+ expect(onGlobalEscape).toHaveBeenCalledTimes(1);
2277
+ });
2278
+ expect(props.setShellModeActive).not.toHaveBeenCalled();
2279
+ unmount();
2280
+ });
2071
2281
  it('should handle ESC when completion suggestions are showing', async () => {
2072
2282
  mockedUseCommandCompletion.mockReturnValue({
2073
2283
  ...mockCommandCompletion,
2074
2284
  showSuggestions: true,
2075
2285
  suggestions: [{ label: 'suggestion', value: 'suggestion' }],
2076
2286
  });
2077
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2287
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2078
2288
  await act(async () => {
2079
2289
  stdin.write('\x1B');
2080
2290
  vi.advanceTimersByTime(100);
@@ -2085,7 +2295,7 @@ describe('InputPrompt', () => {
2085
2295
  it('should not call onEscapePromptChange when not provided', async () => {
2086
2296
  props.onEscapePromptChange = undefined;
2087
2297
  props.buffer.setText('some text');
2088
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2298
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2089
2299
  await act(async () => {
2090
2300
  await vi.runAllTimersAsync();
2091
2301
  });
@@ -2098,7 +2308,7 @@ describe('InputPrompt', () => {
2098
2308
  unmount();
2099
2309
  });
2100
2310
  it('should not interfere with existing keyboard shortcuts', async () => {
2101
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2311
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2102
2312
  await act(async () => {
2103
2313
  stdin.write('\x0C');
2104
2314
  });
@@ -2133,7 +2343,7 @@ describe('InputPrompt', () => {
2133
2343
  showSuggestions: true,
2134
2344
  activeSuggestionIndex: 0,
2135
2345
  });
2136
- const { stdin, stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2346
+ const { stdin, stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2137
2347
  // Trigger reverse search with Ctrl+R
2138
2348
  await act(async () => {
2139
2349
  stdin.write('\x12');
@@ -2151,7 +2361,7 @@ describe('InputPrompt', () => {
2151
2361
  { name: 'standard', escapeSequence: '\x1B' },
2152
2362
  { name: 'kitty', escapeSequence: '\u001b[27u' },
2153
2363
  ])('resets reverse search state on Escape ($name)', async ({ escapeSequence }) => {
2154
- const { stdin, stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2364
+ const { stdin, stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2155
2365
  await act(async () => {
2156
2366
  stdin.write('\x12');
2157
2367
  });
@@ -2186,7 +2396,7 @@ describe('InputPrompt', () => {
2186
2396
  activeSuggestionIndex: reverseSearchActive ? 0 : -1,
2187
2397
  handleAutocomplete: mockHandleAutocomplete,
2188
2398
  }));
2189
- const { stdin, stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2399
+ const { stdin, stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2190
2400
  // Enter reverse search mode with Ctrl+R
2191
2401
  await act(async () => {
2192
2402
  stdin.write('\x12');
@@ -2214,7 +2424,7 @@ describe('InputPrompt', () => {
2214
2424
  activeSuggestionIndex: 0,
2215
2425
  handleAutocomplete: mockHandleAutocomplete,
2216
2426
  });
2217
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
2427
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
2218
2428
  uiActions,
2219
2429
  });
2220
2430
  await act(async () => {
@@ -2239,7 +2449,7 @@ describe('InputPrompt', () => {
2239
2449
  showSuggestions: true,
2240
2450
  activeSuggestionIndex: 0,
2241
2451
  });
2242
- const { stdin, stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2452
+ const { stdin, stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2243
2453
  await act(async () => {
2244
2454
  stdin.write('\x12');
2245
2455
  });
@@ -2268,7 +2478,7 @@ describe('InputPrompt', () => {
2268
2478
  : [],
2269
2479
  showSuggestions: reverseSearchActiveFromInputPrompt,
2270
2480
  }));
2271
- const { stdin, stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2481
+ const { stdin, stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2272
2482
  // reverse search with Ctrl+R
2273
2483
  await act(async () => {
2274
2484
  stdin.write('\x12');
@@ -2293,7 +2503,7 @@ describe('InputPrompt', () => {
2293
2503
  props.buffer.text = 'line 1\nline 2\nline 3';
2294
2504
  props.buffer.cursor = [1, 2];
2295
2505
  props.buffer.lines = ['line 1', 'line 2', 'line 3'];
2296
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2506
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2297
2507
  await act(async () => {
2298
2508
  stdin.write('\x05'); // Ctrl+E
2299
2509
  });
@@ -2307,7 +2517,7 @@ describe('InputPrompt', () => {
2307
2517
  props.buffer.text = 'single line text';
2308
2518
  props.buffer.cursor = [0, 5];
2309
2519
  props.buffer.lines = ['single line text'];
2310
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2520
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2311
2521
  await act(async () => {
2312
2522
  stdin.write('\x05'); // Ctrl+E
2313
2523
  });
@@ -2332,7 +2542,7 @@ describe('InputPrompt', () => {
2332
2542
  showSuggestions: !!isActive,
2333
2543
  activeSuggestionIndex: isActive ? 0 : -1,
2334
2544
  }));
2335
- const { stdin, stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2545
+ const { stdin, stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2336
2546
  await act(async () => {
2337
2547
  stdin.write('\x12'); // Ctrl+R
2338
2548
  });
@@ -2355,7 +2565,7 @@ describe('InputPrompt', () => {
2355
2565
  visibleStartIndex: 0,
2356
2566
  isLoadingSuggestions: false,
2357
2567
  });
2358
- const { stdin, stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2568
+ const { stdin, stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2359
2569
  await act(async () => {
2360
2570
  stdin.write('\x12');
2361
2571
  });
@@ -2391,7 +2601,7 @@ describe('InputPrompt', () => {
2391
2601
  visibleStartIndex: 0,
2392
2602
  isLoadingSuggestions: false,
2393
2603
  });
2394
- const { stdin, stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2604
+ const { stdin, stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2395
2605
  await act(async () => {
2396
2606
  stdin.write('\x12');
2397
2607
  });
@@ -2421,7 +2631,7 @@ describe('InputPrompt', () => {
2421
2631
  visibleStartIndex: 0,
2422
2632
  isLoadingSuggestions: false,
2423
2633
  });
2424
- const { stdin, stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
2634
+ const { stdin, stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2425
2635
  await act(async () => {
2426
2636
  stdin.write('\x12');
2427
2637
  });
@@ -2437,7 +2647,7 @@ describe('InputPrompt', () => {
2437
2647
  it('ensures Ctrl+R search results are prioritized newest-to-oldest by reversing userMessages', async () => {
2438
2648
  props.shellModeActive = false;
2439
2649
  props.userMessages = ['oldest', 'middle', 'newest'];
2440
- await renderWithProviders(_jsx(InputPrompt, { ...props }));
2650
+ await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2441
2651
  const calls = vi.mocked(useReverseSearchCompletion).mock.calls;
2442
2652
  const commandSearchCall = calls.find((call) => call[1] === props.userMessages ||
2443
2653
  (Array.isArray(call[1]) && call[1][0] === 'newest'));
@@ -2484,7 +2694,7 @@ describe('InputPrompt', () => {
2484
2694
  markSelected: vi.fn(),
2485
2695
  },
2486
2696
  });
2487
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
2697
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
2488
2698
  uiActions,
2489
2699
  uiState: {},
2490
2700
  });
@@ -2522,7 +2732,7 @@ describe('InputPrompt', () => {
2522
2732
  markSelected: vi.fn(),
2523
2733
  },
2524
2734
  });
2525
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
2735
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
2526
2736
  uiActions,
2527
2737
  });
2528
2738
  await act(async () => {
@@ -2546,7 +2756,7 @@ describe('InputPrompt', () => {
2546
2756
  markSelected: vi.fn(),
2547
2757
  },
2548
2758
  });
2549
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
2759
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
2550
2760
  uiActions,
2551
2761
  uiState: { activePtyId: 1, cleanUiDetailsVisible: false },
2552
2762
  });
@@ -2572,7 +2782,7 @@ describe('InputPrompt', () => {
2572
2782
  markSelected: vi.fn(),
2573
2783
  },
2574
2784
  });
2575
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
2785
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
2576
2786
  uiActions,
2577
2787
  uiState: {},
2578
2788
  });
@@ -2619,14 +2829,16 @@ describe('InputPrompt', () => {
2619
2829
  ])('should move cursor on mouse click - $name', async ({ relX, relY, mouseCol, mouseRow }) => {
2620
2830
  props.buffer.text = 'hello world\nsecond line';
2621
2831
  props.buffer.lines = ['hello world', 'second line'];
2832
+ props.buffer.allVisualLines = ['hello world', 'second line'];
2622
2833
  props.buffer.viewportVisualLines = ['hello world', 'second line'];
2834
+ props.buffer.viewportHeight = 10;
2623
2835
  props.buffer.visualToLogicalMap = [
2624
2836
  [0, 0],
2625
2837
  [1, 0],
2626
2838
  ];
2627
2839
  props.buffer.visualCursor = [0, 11];
2628
2840
  props.buffer.visualScrollRow = 0;
2629
- const { stdin, stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), { mouseEventsEnabled: true, uiActions });
2841
+ const { stdin, stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), { mouseEventsEnabled: true, uiActions });
2630
2842
  // Wait for initial render
2631
2843
  await waitFor(() => {
2632
2844
  expect(stdout.lastFrame()).toContain('hello world');
@@ -2642,12 +2854,9 @@ describe('InputPrompt', () => {
2642
2854
  unmount();
2643
2855
  });
2644
2856
  it('should unfocus embedded shell on click', async () => {
2645
- props.buffer.text = 'hello';
2646
- props.buffer.lines = ['hello'];
2647
- props.buffer.viewportVisualLines = ['hello'];
2648
- props.buffer.visualToLogicalMap = [[0, 0]];
2857
+ props.buffer.setText('hello');
2649
2858
  props.isEmbeddedShellFocused = true;
2650
- const { stdin, stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), { mouseEventsEnabled: true, uiActions });
2859
+ const { stdin, stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), { mouseEventsEnabled: true, uiActions });
2651
2860
  await waitFor(() => {
2652
2861
  expect(stdout.lastFrame()).toContain('hello');
2653
2862
  });
@@ -2674,6 +2883,7 @@ describe('InputPrompt', () => {
2674
2883
  lines: currentLines,
2675
2884
  viewportVisualLines: currentLines,
2676
2885
  allVisualLines: currentLines,
2886
+ viewportHeight: 10,
2677
2887
  pastedContent: { [id]: largeText },
2678
2888
  transformationsByLine: isExpanded
2679
2889
  ? currentLines.map(() => [])
@@ -2703,7 +2913,7 @@ describe('InputPrompt', () => {
2703
2913
  .fn()
2704
2914
  .mockReturnValue(isExpanded ? id : null),
2705
2915
  };
2706
- return _jsx(InputPrompt, { ...baseProps, buffer: buffer });
2916
+ return _jsx(TestInputPrompt, { ...baseProps, buffer: buffer });
2707
2917
  };
2708
2918
  const { stdout, unmount, simulateClick } = await renderWithProviders(_jsx(TestWrapper, {}), {
2709
2919
  mouseEventsEnabled: true,
@@ -2745,6 +2955,7 @@ describe('InputPrompt', () => {
2745
2955
  lines: currentLines,
2746
2956
  viewportVisualLines: currentLines,
2747
2957
  allVisualLines: currentLines,
2958
+ viewportHeight: 10,
2748
2959
  pastedContent: { [id]: largeText },
2749
2960
  transformationsByLine: isExpanded
2750
2961
  ? currentLines.map(() => [])
@@ -2774,7 +2985,7 @@ describe('InputPrompt', () => {
2774
2985
  .fn()
2775
2986
  .mockImplementation((row) => isExpanded && row >= 0 && row < 10 ? id : null),
2776
2987
  };
2777
- return _jsx(InputPrompt, { ...baseProps, buffer: buffer });
2988
+ return _jsx(TestInputPrompt, { ...baseProps, buffer: buffer });
2778
2989
  };
2779
2990
  const { stdout, unmount, simulateClick } = await renderWithProviders(_jsx(TestWrapper, {}), {
2780
2991
  mouseEventsEnabled: true,
@@ -2800,11 +3011,13 @@ describe('InputPrompt', () => {
2800
3011
  props.config.getUseBackgroundColor = () => false;
2801
3012
  props.buffer.text = 'hello world';
2802
3013
  props.buffer.lines = ['hello world'];
3014
+ props.buffer.allVisualLines = ['hello world'];
2803
3015
  props.buffer.viewportVisualLines = ['hello world'];
3016
+ props.buffer.viewportHeight = 10;
2804
3017
  props.buffer.visualToLogicalMap = [[0, 0]];
2805
3018
  props.buffer.visualCursor = [0, 11];
2806
3019
  props.buffer.visualScrollRow = 0;
2807
- const { stdin, stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), { mouseEventsEnabled: true, uiActions });
3020
+ const { stdin, stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), { mouseEventsEnabled: true, uiActions });
2808
3021
  // Wait for initial render
2809
3022
  await waitFor(() => {
2810
3023
  expect(stdout.lastFrame()).toContain('hello world');
@@ -2825,7 +3038,7 @@ describe('InputPrompt', () => {
2825
3038
  mockPopAllMessages.mockReturnValue('Message 1\n\nMessage 2\n\nMessage 3');
2826
3039
  props.popAllMessages = mockPopAllMessages;
2827
3040
  props.buffer.text = '';
2828
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
3041
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2829
3042
  await act(async () => {
2830
3043
  stdin.write('\u001B[A');
2831
3044
  });
@@ -2837,7 +3050,7 @@ describe('InputPrompt', () => {
2837
3050
  const mockPopAllMessages = vi.fn();
2838
3051
  props.popAllMessages = mockPopAllMessages;
2839
3052
  props.buffer.text = 'some text';
2840
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
3053
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2841
3054
  await act(async () => {
2842
3055
  stdin.write('\u001B[A');
2843
3056
  });
@@ -2850,7 +3063,7 @@ describe('InputPrompt', () => {
2850
3063
  mockPopAllMessages.mockReturnValue(undefined);
2851
3064
  props.popAllMessages = mockPopAllMessages;
2852
3065
  props.buffer.text = '';
2853
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
3066
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2854
3067
  await act(async () => {
2855
3068
  stdin.write('\u001B[A');
2856
3069
  });
@@ -2866,7 +3079,7 @@ describe('InputPrompt', () => {
2866
3079
  props.buffer.allVisualLines = [''];
2867
3080
  props.buffer.visualCursor = [0, 0];
2868
3081
  props.buffer.visualScrollRow = 0;
2869
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
3082
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2870
3083
  await act(async () => {
2871
3084
  stdin.write('\u001B[A');
2872
3085
  });
@@ -2878,7 +3091,7 @@ describe('InputPrompt', () => {
2878
3091
  mockPopAllMessages.mockReturnValue('Single message');
2879
3092
  props.popAllMessages = mockPopAllMessages;
2880
3093
  props.buffer.text = '';
2881
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
3094
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2882
3095
  await act(async () => {
2883
3096
  stdin.write('\u001B[A');
2884
3097
  });
@@ -2890,7 +3103,7 @@ describe('InputPrompt', () => {
2890
3103
  const mockPopAllMessages = vi.fn();
2891
3104
  props.popAllMessages = mockPopAllMessages;
2892
3105
  props.buffer.text = ' '; // Whitespace only
2893
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
3106
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2894
3107
  await act(async () => {
2895
3108
  stdin.write('\u001B[A');
2896
3109
  });
@@ -2900,7 +3113,7 @@ describe('InputPrompt', () => {
2900
3113
  it('should not call popAllMessages if it is not provided', async () => {
2901
3114
  props.popAllMessages = undefined;
2902
3115
  props.buffer.text = '';
2903
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
3116
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2904
3117
  await act(async () => {
2905
3118
  stdin.write('\u001B[A');
2906
3119
  });
@@ -2912,7 +3125,7 @@ describe('InputPrompt', () => {
2912
3125
  mockPopAllMessages.mockReturnValue(undefined);
2913
3126
  props.popAllMessages = mockPopAllMessages;
2914
3127
  props.buffer.text = '';
2915
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
3128
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2916
3129
  await act(async () => {
2917
3130
  stdin.write('\u001B[A');
2918
3131
  });
@@ -2925,21 +3138,21 @@ describe('InputPrompt', () => {
2925
3138
  describe('snapshots', () => {
2926
3139
  it('should render correctly in shell mode', async () => {
2927
3140
  props.shellModeActive = true;
2928
- const { stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
3141
+ const { stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2929
3142
  await waitFor(() => expect(stdout.lastFrame()).toContain('!'));
2930
3143
  expect(stdout.lastFrame()).toMatchSnapshot();
2931
3144
  unmount();
2932
3145
  });
2933
3146
  it('should render correctly when accepting edits', async () => {
2934
3147
  props.approvalMode = ApprovalMode.AUTO_EDIT;
2935
- const { stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
3148
+ const { stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2936
3149
  await waitFor(() => expect(stdout.lastFrame()).toContain('>'));
2937
3150
  expect(stdout.lastFrame()).toMatchSnapshot();
2938
3151
  unmount();
2939
3152
  });
2940
3153
  it('should render correctly in yolo mode', async () => {
2941
3154
  props.approvalMode = ApprovalMode.YOLO;
2942
- const { stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
3155
+ const { stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2943
3156
  await waitFor(() => expect(stdout.lastFrame()).toContain('*'));
2944
3157
  expect(stdout.lastFrame()).toMatchSnapshot();
2945
3158
  unmount();
@@ -2947,14 +3160,14 @@ describe('InputPrompt', () => {
2947
3160
  it('should not show inverted cursor when shell is focused', async () => {
2948
3161
  props.isEmbeddedShellFocused = true;
2949
3162
  props.focus = false;
2950
- const renderResult = await renderWithProviders(_jsx(InputPrompt, { ...props }));
3163
+ const renderResult = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
2951
3164
  await renderResult.waitUntilReady();
2952
3165
  await expect(renderResult).toMatchSvgSnapshot();
2953
3166
  renderResult.unmount();
2954
3167
  });
2955
3168
  });
2956
3169
  it('should still allow input when shell is not focused', async () => {
2957
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
3170
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
2958
3171
  shellFocus: false,
2959
3172
  });
2960
3173
  await act(async () => {
@@ -3001,7 +3214,7 @@ describe('InputPrompt', () => {
3001
3214
  ])('$name', async ({ bufferText, shellMode, shouldSubmit, errorMessage }) => {
3002
3215
  props.buffer.text = bufferText;
3003
3216
  props.shellModeActive = shellMode;
3004
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
3217
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
3005
3218
  await act(async () => {
3006
3219
  stdin.write('\r');
3007
3220
  });
@@ -3021,13 +3234,10 @@ describe('InputPrompt', () => {
3021
3234
  describe('IME Cursor Support', () => {
3022
3235
  it('should report correct cursor position for simple ASCII text', async () => {
3023
3236
  const text = 'hello';
3024
- mockBuffer.text = text;
3025
- mockBuffer.lines = [text];
3026
- mockBuffer.viewportVisualLines = [text];
3027
- mockBuffer.visualToLogicalMap = [[0, 0]];
3237
+ mockBuffer.setText(text);
3028
3238
  mockBuffer.visualCursor = [0, 3]; // Cursor after 'hel'
3029
3239
  mockBuffer.visualScrollRow = 0;
3030
- const { stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), { uiActions });
3240
+ const { stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), { uiActions });
3031
3241
  await waitFor(() => {
3032
3242
  expect(stdout.lastFrame()).toContain('hello');
3033
3243
  });
@@ -3043,13 +3253,10 @@ describe('InputPrompt', () => {
3043
3253
  });
3044
3254
  it('should report correct cursor position for text with double-width characters', async () => {
3045
3255
  const text = '👍hello';
3046
- mockBuffer.text = text;
3047
- mockBuffer.lines = [text];
3048
- mockBuffer.viewportVisualLines = [text];
3049
- mockBuffer.visualToLogicalMap = [[0, 0]];
3256
+ mockBuffer.setText(text);
3050
3257
  mockBuffer.visualCursor = [0, 2]; // Cursor after '👍h' (Note: '👍' is one code point but width 2)
3051
3258
  mockBuffer.visualScrollRow = 0;
3052
- const { stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), { uiActions });
3259
+ const { stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), { uiActions });
3053
3260
  await waitFor(() => {
3054
3261
  expect(stdout.lastFrame()).toContain('👍hello');
3055
3262
  });
@@ -3064,13 +3271,10 @@ describe('InputPrompt', () => {
3064
3271
  });
3065
3272
  it('should report correct cursor position for a line full of "😀" emojis', async () => {
3066
3273
  const text = '😀😀😀';
3067
- mockBuffer.text = text;
3068
- mockBuffer.lines = [text];
3069
- mockBuffer.viewportVisualLines = [text];
3070
- mockBuffer.visualToLogicalMap = [[0, 0]];
3274
+ mockBuffer.setText(text);
3071
3275
  mockBuffer.visualCursor = [0, 2]; // Cursor after 2 emojis (each 1 code point, width 2)
3072
3276
  mockBuffer.visualScrollRow = 0;
3073
- const { stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), { uiActions });
3277
+ const { stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), { uiActions });
3074
3278
  await waitFor(() => {
3075
3279
  expect(stdout.lastFrame()).toContain('😀😀😀');
3076
3280
  });
@@ -3087,7 +3291,9 @@ describe('InputPrompt', () => {
3087
3291
  const lines = ['😀😀', 'hello 😀', 'world'];
3088
3292
  mockBuffer.text = lines.join('\n');
3089
3293
  mockBuffer.lines = lines;
3294
+ mockBuffer.allVisualLines = lines;
3090
3295
  mockBuffer.viewportVisualLines = lines;
3296
+ mockBuffer.viewportHeight = 10;
3091
3297
  mockBuffer.visualToLogicalMap = [
3092
3298
  [0, 0],
3093
3299
  [1, 0],
@@ -3095,7 +3301,7 @@ describe('InputPrompt', () => {
3095
3301
  ];
3096
3302
  mockBuffer.visualCursor = [1, 7]; // Second line, after 'hello 😀' (6 chars + 1 emoji = 7 code points)
3097
3303
  mockBuffer.visualScrollRow = 0;
3098
- const { stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), { uiActions });
3304
+ const { stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), { uiActions });
3099
3305
  await waitFor(() => {
3100
3306
  expect(stdout.lastFrame()).toContain('hello 😀');
3101
3307
  });
@@ -3112,7 +3318,9 @@ describe('InputPrompt', () => {
3112
3318
  const lines = ['first line', 'second line', 'third line'];
3113
3319
  mockBuffer.text = lines.join('\n');
3114
3320
  mockBuffer.lines = lines;
3321
+ mockBuffer.allVisualLines = lines;
3115
3322
  mockBuffer.viewportVisualLines = lines;
3323
+ mockBuffer.viewportHeight = 10;
3116
3324
  mockBuffer.visualToLogicalMap = [
3117
3325
  [0, 0],
3118
3326
  [1, 0],
@@ -3120,7 +3328,7 @@ describe('InputPrompt', () => {
3120
3328
  ];
3121
3329
  mockBuffer.visualCursor = [1, 7]; // Cursor on second line, after 'second '
3122
3330
  mockBuffer.visualScrollRow = 0;
3123
- const { stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), { uiActions });
3331
+ const { stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), { uiActions });
3124
3332
  await waitFor(() => {
3125
3333
  expect(stdout.lastFrame()).toContain('second line');
3126
3334
  });
@@ -3139,11 +3347,12 @@ describe('InputPrompt', () => {
3139
3347
  it('should report cursor position 0 when input is empty and placeholder is shown', async () => {
3140
3348
  mockBuffer.text = '';
3141
3349
  mockBuffer.lines = [''];
3350
+ mockBuffer.allVisualLines = [''];
3142
3351
  mockBuffer.viewportVisualLines = [''];
3143
3352
  mockBuffer.visualToLogicalMap = [[0, 0]];
3144
3353
  mockBuffer.visualCursor = [0, 0];
3145
3354
  mockBuffer.visualScrollRow = 0;
3146
- const { stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props, placeholder: "Type here" }), { uiActions });
3355
+ const { stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props, placeholder: "Type here" }), { uiActions });
3147
3356
  await waitFor(() => {
3148
3357
  expect(stdout.lastFrame()).toContain('Type here');
3149
3358
  });
@@ -3162,18 +3371,19 @@ describe('InputPrompt', () => {
3162
3371
  const applyVisualState = (visualLine, cursorCol) => {
3163
3372
  mockBuffer.text = logicalLine;
3164
3373
  mockBuffer.lines = [logicalLine];
3165
- mockBuffer.viewportVisualLines = [visualLine];
3166
3374
  mockBuffer.allVisualLines = [visualLine];
3375
+ mockBuffer.viewportVisualLines = [visualLine];
3167
3376
  mockBuffer.visualToLogicalMap = [[0, 0]];
3168
3377
  mockBuffer.visualToTransformedMap = [0];
3169
3378
  mockBuffer.transformationsByLine = [transformations];
3170
3379
  mockBuffer.cursor = [0, cursorCol];
3171
- mockBuffer.visualCursor = [0, 0];
3380
+ mockBuffer.visualCursor = [0, cursorCol];
3381
+ mockBuffer.visualScrollRow = 0;
3172
3382
  };
3173
3383
  it('should snapshot collapsed image path', async () => {
3174
3384
  const { transformedLine } = calculateTransformedLine(logicalLine, 0, [0, transformations[0].logEnd + 5], transformations);
3175
3385
  applyVisualState(transformedLine, transformations[0].logEnd + 5);
3176
- const { stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
3386
+ const { stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
3177
3387
  await waitFor(() => {
3178
3388
  expect(stdout.lastFrame()).toContain('[Image');
3179
3389
  });
@@ -3183,7 +3393,7 @@ describe('InputPrompt', () => {
3183
3393
  it('should snapshot expanded image path when cursor is on it', async () => {
3184
3394
  const { transformedLine } = calculateTransformedLine(logicalLine, 0, [0, transformations[0].logStart + 1], transformations);
3185
3395
  applyVisualState(transformedLine, transformations[0].logStart + 1);
3186
- const { stdout, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }));
3396
+ const { stdout, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }));
3187
3397
  await waitFor(() => {
3188
3398
  expect(stdout.lastFrame()).toContain('@/path/to/screenshots');
3189
3399
  });
@@ -3219,7 +3429,7 @@ describe('InputPrompt', () => {
3219
3429
  getExpandedPasteAtLine: vi.fn().mockReturnValue(null),
3220
3430
  togglePasteExpansion: toggleFn,
3221
3431
  };
3222
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props, buffer: buffer }), { uiActions });
3432
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props, buffer: buffer }), { uiActions });
3223
3433
  await act(async () => {
3224
3434
  stdin.write(CTRL_O);
3225
3435
  });
@@ -3262,7 +3472,7 @@ describe('InputPrompt', () => {
3262
3472
  checking: false,
3263
3473
  });
3264
3474
  }
3265
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props, buffer: method === 'terminal-paste' ? buffer : props.buffer }));
3475
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props, buffer: method === 'terminal-paste' ? buffer : props.buffer }));
3266
3476
  await act(async () => {
3267
3477
  if (method === 'ctrl-v') {
3268
3478
  stdin.write('\x16'); // Ctrl+V
@@ -3424,7 +3634,7 @@ describe('InputPrompt', () => {
3424
3634
  { name: 'Up arrow', key: '\u001B[A', position: 'start' },
3425
3635
  { name: 'Ctrl+P', key: '\u0010', position: 'start' },
3426
3636
  ])('should move cursor to $position on $name (older history)', async ({ key, position }) => {
3427
- const { stdin } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
3637
+ const { stdin } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
3428
3638
  uiActions,
3429
3639
  });
3430
3640
  await act(async () => {
@@ -3438,7 +3648,7 @@ describe('InputPrompt', () => {
3438
3648
  { name: 'Down arrow', key: '\u001B[B', position: 'end' },
3439
3649
  { name: 'Ctrl+N', key: '\u000E', position: 'end' },
3440
3650
  ])('should move cursor to $position on $name (newer history)', async ({ key, position }) => {
3441
- const { stdin } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
3651
+ const { stdin } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
3442
3652
  uiActions,
3443
3653
  });
3444
3654
  // First go up
@@ -3458,7 +3668,7 @@ describe('InputPrompt', () => {
3458
3668
  });
3459
3669
  });
3460
3670
  it('should suppress completion after history navigation', async () => {
3461
- const { stdin } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
3671
+ const { stdin } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
3462
3672
  uiActions,
3463
3673
  });
3464
3674
  await act(async () => {
@@ -3486,7 +3696,7 @@ describe('InputPrompt', () => {
3486
3696
  ? [{ value: 'suggestion', label: 'suggestion' }]
3487
3697
  : [],
3488
3698
  }));
3489
- const { stdout, stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), { uiActions });
3699
+ const { stdout, stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), { uiActions });
3490
3700
  // 2. Verify suggestions ARE showing initially because active is true by default
3491
3701
  await waitFor(() => {
3492
3702
  expect(stdout.lastFrame()).toContain('suggestion');
@@ -3503,7 +3713,7 @@ describe('InputPrompt', () => {
3503
3713
  unmount();
3504
3714
  });
3505
3715
  it('should continue to suppress completion after manual cursor movement', async () => {
3506
- const { stdin } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
3716
+ const { stdin } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
3507
3717
  uiActions,
3508
3718
  });
3509
3719
  // Navigate history (suppresses)
@@ -3541,7 +3751,7 @@ describe('InputPrompt', () => {
3541
3751
  });
3542
3752
  });
3543
3753
  it('should re-enable completion after typing', async () => {
3544
- const { stdin } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
3754
+ const { stdin } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
3545
3755
  uiActions,
3546
3756
  });
3547
3757
  // Navigate history (suppresses)
@@ -3567,7 +3777,7 @@ describe('InputPrompt', () => {
3567
3777
  const settings = createMockSettings({
3568
3778
  ui: { showShortcutsHint: false },
3569
3779
  });
3570
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
3780
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
3571
3781
  settings,
3572
3782
  uiActions: { setShortcutsHelpVisible },
3573
3783
  });
@@ -3606,8 +3816,8 @@ describe('InputPrompt', () => {
3606
3816
  input: '\x12',
3607
3817
  },
3608
3818
  {
3609
- name: 'Ctrl+X hotkey is pressed',
3610
- input: '\x18',
3819
+ name: 'Ctrl+G hotkey is pressed',
3820
+ input: '\x07',
3611
3821
  },
3612
3822
  {
3613
3823
  name: 'F12 hotkey is pressed',
@@ -3616,7 +3826,7 @@ describe('InputPrompt', () => {
3616
3826
  ])('should close shortcuts help when a $name', async ({ input, setupMocks, mouseEventsEnabled }) => {
3617
3827
  setupMocks?.();
3618
3828
  const setShortcutsHelpVisible = vi.fn();
3619
- const { stdin, unmount } = await renderWithProviders(_jsx(InputPrompt, { ...props }), {
3829
+ const { stdin, unmount } = await renderWithProviders(_jsx(TestInputPrompt, { ...props }), {
3620
3830
  uiState: { shortcutsHelpVisible: true },
3621
3831
  uiActions: { setShortcutsHelpVisible },
3622
3832
  mouseEventsEnabled,