@machina.ai/cell-cli 1.11.0-rc1 → 1.13.0-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 (538) hide show
  1. package/dist/package.json +16 -10
  2. package/dist/src/commands/extensions/disable.d.ts +1 -1
  3. package/dist/src/commands/extensions/disable.js +15 -7
  4. package/dist/src/commands/extensions/disable.js.map +1 -1
  5. package/dist/src/commands/extensions/enable.d.ts +1 -1
  6. package/dist/src/commands/extensions/enable.js +15 -7
  7. package/dist/src/commands/extensions/enable.js.map +1 -1
  8. package/dist/src/commands/extensions/install.js +14 -3
  9. package/dist/src/commands/extensions/install.js.map +1 -1
  10. package/dist/src/commands/extensions/install.test.js +39 -19
  11. package/dist/src/commands/extensions/install.test.js.map +1 -1
  12. package/dist/src/commands/extensions/link.js +14 -3
  13. package/dist/src/commands/extensions/link.js.map +1 -1
  14. package/dist/src/commands/extensions/list.js +13 -4
  15. package/dist/src/commands/extensions/list.js.map +1 -1
  16. package/dist/src/commands/extensions/uninstall.js +13 -2
  17. package/dist/src/commands/extensions/uninstall.js.map +1 -1
  18. package/dist/src/commands/extensions/update.js +18 -13
  19. package/dist/src/commands/extensions/update.js.map +1 -1
  20. package/dist/src/commands/extensions/validate.d.ts +12 -0
  21. package/dist/src/commands/extensions/validate.js +83 -0
  22. package/dist/src/commands/extensions/validate.js.map +1 -0
  23. package/dist/src/commands/extensions/validate.test.js +93 -0
  24. package/dist/src/commands/extensions/validate.test.js.map +1 -0
  25. package/dist/src/commands/extensions.js +3 -0
  26. package/dist/src/commands/extensions.js.map +1 -1
  27. package/dist/src/commands/mcp/add.test.js +3 -0
  28. package/dist/src/commands/mcp/add.test.js.map +1 -1
  29. package/dist/src/commands/mcp/list.js +10 -3
  30. package/dist/src/commands/mcp/list.js.map +1 -1
  31. package/dist/src/commands/mcp/list.test.js +37 -27
  32. package/dist/src/commands/mcp/list.test.js.map +1 -1
  33. package/dist/src/config/auth.js +0 -5
  34. package/dist/src/config/auth.js.map +1 -1
  35. package/dist/src/config/config.d.ts +6 -3
  36. package/dist/src/config/config.js +65 -80
  37. package/dist/src/config/config.js.map +1 -1
  38. package/dist/src/config/config.test.js +235 -212
  39. package/dist/src/config/config.test.js.map +1 -1
  40. package/dist/src/config/extension-manager.d.ts +63 -0
  41. package/dist/src/config/extension-manager.js +450 -0
  42. package/dist/src/config/extension-manager.js.map +1 -0
  43. package/dist/src/config/extension.d.ts +4 -51
  44. package/dist/src/config/extension.js +1 -535
  45. package/dist/src/config/extension.js.map +1 -1
  46. package/dist/src/config/extension.test.js +525 -201
  47. package/dist/src/config/extension.test.js.map +1 -1
  48. package/dist/src/config/extensions/consent.d.ts +38 -0
  49. package/dist/src/config/extensions/consent.js +123 -0
  50. package/dist/src/config/extensions/consent.js.map +1 -0
  51. package/dist/src/config/extensions/extensionEnablement.d.ts +1 -1
  52. package/dist/src/config/extensions/extensionEnablement.js +4 -3
  53. package/dist/src/config/extensions/extensionEnablement.js.map +1 -1
  54. package/dist/src/config/extensions/extensionEnablement.test.js +10 -10
  55. package/dist/src/config/extensions/extensionEnablement.test.js.map +1 -1
  56. package/dist/src/config/extensions/extensionSettings.d.ts +15 -0
  57. package/dist/src/config/extensions/extensionSettings.js +113 -0
  58. package/dist/src/config/extensions/extensionSettings.js.map +1 -0
  59. package/dist/src/config/extensions/extensionSettings.test.d.ts +6 -0
  60. package/dist/src/config/extensions/extensionSettings.test.js +254 -0
  61. package/dist/src/config/extensions/extensionSettings.test.js.map +1 -0
  62. package/dist/src/config/extensions/github.d.ts +2 -2
  63. package/dist/src/config/extensions/github.js +5 -10
  64. package/dist/src/config/extensions/github.js.map +1 -1
  65. package/dist/src/config/extensions/github.test.js +153 -167
  66. package/dist/src/config/extensions/github.test.js.map +1 -1
  67. package/dist/src/config/extensions/github_fetch.d.ts +1 -1
  68. package/dist/src/config/extensions/github_fetch.js +13 -1
  69. package/dist/src/config/extensions/github_fetch.js.map +1 -1
  70. package/dist/src/config/extensions/github_fetch.test.d.ts +6 -0
  71. package/dist/src/config/extensions/github_fetch.test.js +169 -0
  72. package/dist/src/config/extensions/github_fetch.test.js.map +1 -0
  73. package/dist/src/config/extensions/storage.d.ts +14 -0
  74. package/dist/src/config/extensions/storage.js +32 -0
  75. package/dist/src/config/extensions/storage.js.map +1 -0
  76. package/dist/src/config/extensions/update.d.ts +4 -4
  77. package/dist/src/config/extensions/update.js +39 -39
  78. package/dist/src/config/extensions/update.js.map +1 -1
  79. package/dist/src/config/extensions/update.test.js +72 -74
  80. package/dist/src/config/extensions/update.test.js.map +1 -1
  81. package/dist/src/config/extensions/variableSchema.d.ts +0 -6
  82. package/dist/src/config/extensions/variableSchema.js.map +1 -1
  83. package/dist/src/config/extensions/variables.d.ts +4 -0
  84. package/dist/src/config/extensions/variables.js +6 -0
  85. package/dist/src/config/extensions/variables.js.map +1 -1
  86. package/dist/src/config/keyBindings.d.ts +3 -0
  87. package/dist/src/config/keyBindings.js +30 -8
  88. package/dist/src/config/keyBindings.js.map +1 -1
  89. package/dist/src/config/keyBindings.test.js +17 -0
  90. package/dist/src/config/keyBindings.test.js.map +1 -1
  91. package/dist/src/config/policies/read-only.toml +56 -0
  92. package/dist/src/config/policies/write.toml +63 -0
  93. package/dist/src/config/policies/yolo.toml +31 -0
  94. package/dist/src/config/policy-engine.integration.test.js +41 -38
  95. package/dist/src/config/policy-engine.integration.test.js.map +1 -1
  96. package/dist/src/config/policy.d.ts +2 -2
  97. package/dist/src/config/policy.js +10 -148
  98. package/dist/src/config/policy.js.map +1 -1
  99. package/dist/src/config/sandboxConfig.d.ts +1 -1
  100. package/dist/src/config/sandboxConfig.js +6 -3
  101. package/dist/src/config/sandboxConfig.js.map +1 -1
  102. package/dist/src/config/settings.d.ts +2 -1
  103. package/dist/src/config/settings.js +58 -18
  104. package/dist/src/config/settings.js.map +1 -1
  105. package/dist/src/config/settings.test.js +128 -69
  106. package/dist/src/config/settings.test.js.map +1 -1
  107. package/dist/src/config/settingsSchema.d.ts +170 -28
  108. package/dist/src/config/settingsSchema.js +418 -27
  109. package/dist/src/config/settingsSchema.js.map +1 -1
  110. package/dist/src/config/settingsSchema.test.js +42 -1
  111. package/dist/src/config/settingsSchema.test.js.map +1 -1
  112. package/dist/src/config/trustedFolders.d.ts +1 -1
  113. package/dist/src/config/trustedFolders.js +4 -2
  114. package/dist/src/config/trustedFolders.js.map +1 -1
  115. package/dist/src/core/initializer.js +2 -1
  116. package/dist/src/core/initializer.js.map +1 -1
  117. package/dist/src/gemini.d.ts +1 -1
  118. package/dist/src/gemini.js +46 -16
  119. package/dist/src/gemini.js.map +1 -1
  120. package/dist/src/gemini.test.js +88 -30
  121. package/dist/src/gemini.test.js.map +1 -1
  122. package/dist/src/generated/git-commit.d.ts +2 -2
  123. package/dist/src/generated/git-commit.js +2 -2
  124. package/dist/src/nonInteractiveCli.d.ts +9 -1
  125. package/dist/src/nonInteractiveCli.js +114 -7
  126. package/dist/src/nonInteractiveCli.js.map +1 -1
  127. package/dist/src/nonInteractiveCli.test.js +355 -112
  128. package/dist/src/nonInteractiveCli.test.js.map +1 -1
  129. package/dist/src/services/BuiltinCommandLoader.js +4 -0
  130. package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
  131. package/dist/src/services/BuiltinCommandLoader.test.js +22 -0
  132. package/dist/src/services/BuiltinCommandLoader.test.js.map +1 -1
  133. package/dist/src/services/FeedbackService.js +2 -2
  134. package/dist/src/services/FeedbackService.js.map +1 -1
  135. package/dist/src/services/McpPromptLoader.js +2 -2
  136. package/dist/src/services/McpPromptLoader.js.map +1 -1
  137. package/dist/src/services/McpPromptLoader.test.js +4 -2
  138. package/dist/src/services/McpPromptLoader.test.js.map +1 -1
  139. package/dist/src/test-utils/async.d.ts +9 -0
  140. package/dist/src/test-utils/async.js +29 -0
  141. package/dist/src/test-utils/async.js.map +1 -0
  142. package/dist/src/test-utils/createExtension.d.ts +3 -1
  143. package/dist/src/test-utils/createExtension.js +3 -3
  144. package/dist/src/test-utils/createExtension.js.map +1 -1
  145. package/dist/src/test-utils/render.d.ts +16 -2
  146. package/dist/src/test-utils/render.js +66 -4
  147. package/dist/src/test-utils/render.js.map +1 -1
  148. package/dist/src/test-utils/render.test.d.ts +6 -0
  149. package/dist/src/test-utils/render.test.js +79 -0
  150. package/dist/src/test-utils/render.test.js.map +1 -0
  151. package/dist/src/ui/App.test.js +1 -1
  152. package/dist/src/ui/App.test.js.map +1 -1
  153. package/dist/src/ui/AppContainer.js +181 -65
  154. package/dist/src/ui/AppContainer.js.map +1 -1
  155. package/dist/src/ui/AppContainer.test.js +505 -147
  156. package/dist/src/ui/AppContainer.test.js.map +1 -1
  157. package/dist/src/ui/IdeIntegrationNudge.js +1 -1
  158. package/dist/src/ui/IdeIntegrationNudge.js.map +1 -1
  159. package/dist/src/ui/auth/ApiAuthDialog.d.ts +14 -0
  160. package/dist/src/ui/auth/ApiAuthDialog.js +26 -0
  161. package/dist/src/ui/auth/ApiAuthDialog.js.map +1 -0
  162. package/dist/src/ui/auth/ApiAuthDialog.test.d.ts +6 -0
  163. package/dist/src/ui/auth/ApiAuthDialog.test.js +91 -0
  164. package/dist/src/ui/auth/ApiAuthDialog.test.js.map +1 -0
  165. package/dist/src/ui/auth/AuthDialog.js +7 -3
  166. package/dist/src/ui/auth/AuthDialog.js.map +1 -1
  167. package/dist/src/ui/auth/useAuth.d.ts +2 -0
  168. package/dist/src/ui/auth/useAuth.js +31 -2
  169. package/dist/src/ui/auth/useAuth.js.map +1 -1
  170. package/dist/src/ui/colors.js +3 -0
  171. package/dist/src/ui/colors.js.map +1 -1
  172. package/dist/src/ui/commands/directoryCommand.js +1 -1
  173. package/dist/src/ui/commands/directoryCommand.js.map +1 -1
  174. package/dist/src/ui/commands/extensionsCommand.js +64 -11
  175. package/dist/src/ui/commands/extensionsCommand.js.map +1 -1
  176. package/dist/src/ui/commands/extensionsCommand.test.js +72 -1
  177. package/dist/src/ui/commands/extensionsCommand.test.js.map +1 -1
  178. package/dist/src/ui/commands/mcpCommand.js +14 -14
  179. package/dist/src/ui/commands/mcpCommand.js.map +1 -1
  180. package/dist/src/ui/commands/mcpCommand.test.js +4 -0
  181. package/dist/src/ui/commands/mcpCommand.test.js.map +1 -1
  182. package/dist/src/ui/commands/memoryCommand.js +1 -1
  183. package/dist/src/ui/commands/memoryCommand.js.map +1 -1
  184. package/dist/src/ui/commands/memoryCommand.test.js +3 -1
  185. package/dist/src/ui/commands/memoryCommand.test.js.map +1 -1
  186. package/dist/src/ui/commands/policiesCommand.d.ts +7 -0
  187. package/dist/src/ui/commands/policiesCommand.js +59 -0
  188. package/dist/src/ui/commands/policiesCommand.js.map +1 -0
  189. package/dist/src/ui/commands/policiesCommand.test.d.ts +6 -0
  190. package/dist/src/ui/commands/policiesCommand.test.js +83 -0
  191. package/dist/src/ui/commands/policiesCommand.test.js.map +1 -0
  192. package/dist/src/ui/components/AnsiOutput.test.js +1 -1
  193. package/dist/src/ui/components/AnsiOutput.test.js.map +1 -1
  194. package/dist/src/ui/components/AsciiArt.d.ts +3 -3
  195. package/dist/src/ui/components/AsciiArt.js +3 -3
  196. package/dist/src/ui/components/Composer.js +1 -1
  197. package/dist/src/ui/components/Composer.js.map +1 -1
  198. package/dist/src/ui/components/Composer.test.js +5 -2
  199. package/dist/src/ui/components/Composer.test.js.map +1 -1
  200. package/dist/src/ui/components/ConfigInitDisplay.js +4 -6
  201. package/dist/src/ui/components/ConfigInitDisplay.js.map +1 -1
  202. package/dist/src/ui/components/ConsentPrompt.test.js +18 -8
  203. package/dist/src/ui/components/ConsentPrompt.test.js.map +1 -1
  204. package/dist/src/ui/components/ConsoleSummaryDisplay.js +1 -1
  205. package/dist/src/ui/components/ConsoleSummaryDisplay.js.map +1 -1
  206. package/dist/src/ui/components/ContextSummaryDisplay.test.js +11 -6
  207. package/dist/src/ui/components/ContextSummaryDisplay.test.js.map +1 -1
  208. package/dist/src/ui/components/DetailedMessagesDisplay.js +1 -1
  209. package/dist/src/ui/components/DetailedMessagesDisplay.js.map +1 -1
  210. package/dist/src/ui/components/DialogManager.js +4 -0
  211. package/dist/src/ui/components/DialogManager.js.map +1 -1
  212. package/dist/src/ui/components/FolderTrustDialog.test.js +2 -1
  213. package/dist/src/ui/components/FolderTrustDialog.test.js.map +1 -1
  214. package/dist/src/ui/components/Footer.js +4 -3
  215. package/dist/src/ui/components/Footer.js.map +1 -1
  216. package/dist/src/ui/components/Footer.test.js +83 -0
  217. package/dist/src/ui/components/Footer.test.js.map +1 -1
  218. package/dist/src/ui/components/Header.test.js +13 -5
  219. package/dist/src/ui/components/Header.test.js.map +1 -1
  220. package/dist/src/ui/components/Help.test.js +5 -4
  221. package/dist/src/ui/components/Help.test.js.map +1 -1
  222. package/dist/src/ui/components/HistoryItemDisplay.js +1 -1
  223. package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -1
  224. package/dist/src/ui/components/InputPrompt.js +27 -8
  225. package/dist/src/ui/components/InputPrompt.js.map +1 -1
  226. package/dist/src/ui/components/InputPrompt.test.js +776 -727
  227. package/dist/src/ui/components/InputPrompt.test.js.map +1 -1
  228. package/dist/src/ui/components/LoadingIndicator.js +2 -2
  229. package/dist/src/ui/components/LoadingIndicator.js.map +1 -1
  230. package/dist/src/ui/components/LoadingIndicator.test.js +28 -15
  231. package/dist/src/ui/components/LoadingIndicator.test.js.map +1 -1
  232. package/dist/src/ui/components/LoopDetectionConfirmation.js +1 -1
  233. package/dist/src/ui/components/LoopDetectionConfirmation.js.map +1 -1
  234. package/dist/src/ui/components/LoopDetectionConfirmation.test.js +2 -2
  235. package/dist/src/ui/components/LoopDetectionConfirmation.test.js.map +1 -1
  236. package/dist/src/ui/components/MainContent.js +15 -4
  237. package/dist/src/ui/components/MainContent.js.map +1 -1
  238. package/dist/src/ui/components/ModelDialog.js +1 -1
  239. package/dist/src/ui/components/ModelDialog.js.map +1 -1
  240. package/dist/src/ui/components/ModelDialog.test.js +23 -13
  241. package/dist/src/ui/components/ModelDialog.test.js.map +1 -1
  242. package/dist/src/ui/components/ModelStatsDisplay.test.js +1 -1
  243. package/dist/src/ui/components/ModelStatsDisplay.test.js.map +1 -1
  244. package/dist/src/ui/components/Notifications.js +38 -5
  245. package/dist/src/ui/components/Notifications.js.map +1 -1
  246. package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js +2 -2
  247. package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js.map +1 -1
  248. package/dist/src/ui/components/PrepareLabel.test.js +14 -8
  249. package/dist/src/ui/components/PrepareLabel.test.js.map +1 -1
  250. package/dist/src/ui/components/ProQuotaDialog.test.js +14 -6
  251. package/dist/src/ui/components/ProQuotaDialog.test.js.map +1 -1
  252. package/dist/src/ui/components/QueuedMessageDisplay.test.js +11 -6
  253. package/dist/src/ui/components/QueuedMessageDisplay.test.js.map +1 -1
  254. package/dist/src/ui/components/SessionSummaryDisplay.test.js +1 -1
  255. package/dist/src/ui/components/SessionSummaryDisplay.test.js.map +1 -1
  256. package/dist/src/ui/components/SettingsDialog.js +32 -25
  257. package/dist/src/ui/components/SettingsDialog.js.map +1 -1
  258. package/dist/src/ui/components/SettingsDialog.test.js +428 -532
  259. package/dist/src/ui/components/SettingsDialog.test.js.map +1 -1
  260. package/dist/src/ui/components/ShellConfirmationDialog.js +1 -1
  261. package/dist/src/ui/components/ShellConfirmationDialog.js.map +1 -1
  262. package/dist/src/ui/components/ShellConfirmationDialog.test.js +2 -2
  263. package/dist/src/ui/components/ShellConfirmationDialog.test.js.map +1 -1
  264. package/dist/src/ui/components/StatsDisplay.test.js +1 -1
  265. package/dist/src/ui/components/StatsDisplay.test.js.map +1 -1
  266. package/dist/src/ui/components/SuggestionsDisplay.js +1 -1
  267. package/dist/src/ui/components/SuggestionsDisplay.js.map +1 -1
  268. package/dist/src/ui/components/ThemeDialog.test.js +2 -2
  269. package/dist/src/ui/components/ThemeDialog.test.js.map +1 -1
  270. package/dist/src/ui/components/ToolStatsDisplay.test.js +1 -1
  271. package/dist/src/ui/components/ToolStatsDisplay.test.js.map +1 -1
  272. package/dist/src/ui/components/messages/CompressionMessage.test.js +25 -17
  273. package/dist/src/ui/components/messages/CompressionMessage.test.js.map +1 -1
  274. package/dist/src/ui/components/messages/DiffRenderer.test.js +1 -1
  275. package/dist/src/ui/components/messages/DiffRenderer.test.js.map +1 -1
  276. package/dist/src/ui/components/messages/InfoMessage.js +1 -1
  277. package/dist/src/ui/components/messages/InfoMessage.js.map +1 -1
  278. package/dist/src/ui/components/messages/Todo.js +27 -5
  279. package/dist/src/ui/components/messages/Todo.js.map +1 -1
  280. package/dist/src/ui/components/messages/Todo.test.js +20 -8
  281. package/dist/src/ui/components/messages/Todo.test.js.map +1 -1
  282. package/dist/src/ui/components/messages/ToolConfirmationMessage.js +1 -1
  283. package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
  284. package/dist/src/ui/components/messages/ToolGroupMessage.test.js +29 -15
  285. package/dist/src/ui/components/messages/ToolGroupMessage.test.js.map +1 -1
  286. package/dist/src/ui/components/messages/WarningMessage.js +2 -2
  287. package/dist/src/ui/components/messages/WarningMessage.js.map +1 -1
  288. package/dist/src/ui/components/shared/BaseSelectionList.test.js +1 -1
  289. package/dist/src/ui/components/shared/BaseSelectionList.test.js.map +1 -1
  290. package/dist/src/ui/components/shared/MaxSizedBox.test.js +43 -22
  291. package/dist/src/ui/components/shared/MaxSizedBox.test.js.map +1 -1
  292. package/dist/src/ui/components/shared/TextInput.d.ts +15 -0
  293. package/dist/src/ui/components/shared/TextInput.js +38 -0
  294. package/dist/src/ui/components/shared/TextInput.js.map +1 -0
  295. package/dist/src/ui/components/shared/TextInput.test.d.ts +6 -0
  296. package/dist/src/ui/components/shared/TextInput.test.js +242 -0
  297. package/dist/src/ui/components/shared/TextInput.test.js.map +1 -0
  298. package/dist/src/ui/components/shared/text-buffer.d.ts +9 -2
  299. package/dist/src/ui/components/shared/text-buffer.js +51 -13
  300. package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
  301. package/dist/src/ui/components/shared/text-buffer.test.js +385 -202
  302. package/dist/src/ui/components/shared/text-buffer.test.js.map +1 -1
  303. package/dist/src/ui/components/views/ChatList.test.js +7 -4
  304. package/dist/src/ui/components/views/ChatList.test.js.map +1 -1
  305. package/dist/src/ui/components/views/ExtensionsList.d.ts +7 -1
  306. package/dist/src/ui/components/views/ExtensionsList.js +9 -11
  307. package/dist/src/ui/components/views/ExtensionsList.js.map +1 -1
  308. package/dist/src/ui/components/views/ExtensionsList.test.js +43 -22
  309. package/dist/src/ui/components/views/ExtensionsList.test.js.map +1 -1
  310. package/dist/src/ui/components/views/McpStatus.test.js +23 -12
  311. package/dist/src/ui/components/views/McpStatus.test.js.map +1 -1
  312. package/dist/src/ui/contexts/KeypressContext.d.ts +3 -2
  313. package/dist/src/ui/contexts/KeypressContext.js +610 -540
  314. package/dist/src/ui/contexts/KeypressContext.js.map +1 -1
  315. package/dist/src/ui/contexts/KeypressContext.test.js +438 -718
  316. package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
  317. package/dist/src/ui/contexts/MouseContext.d.ts +21 -0
  318. package/dist/src/ui/contexts/MouseContext.js +89 -0
  319. package/dist/src/ui/contexts/MouseContext.js.map +1 -0
  320. package/dist/src/ui/contexts/MouseContext.test.d.ts +6 -0
  321. package/dist/src/ui/contexts/MouseContext.test.js +164 -0
  322. package/dist/src/ui/contexts/MouseContext.test.js.map +1 -0
  323. package/dist/src/ui/contexts/SessionContext.test.js +35 -17
  324. package/dist/src/ui/contexts/SessionContext.test.js.map +1 -1
  325. package/dist/src/ui/contexts/UIActionsContext.d.ts +2 -0
  326. package/dist/src/ui/contexts/UIActionsContext.js.map +1 -1
  327. package/dist/src/ui/contexts/UIStateContext.d.ts +2 -0
  328. package/dist/src/ui/contexts/UIStateContext.js.map +1 -1
  329. package/dist/src/ui/hooks/atCommandProcessor.js +31 -9
  330. package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
  331. package/dist/src/ui/hooks/atCommandProcessor.test.js +163 -64
  332. package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -1
  333. package/dist/src/ui/hooks/shellCommandProcessor.test.js +64 -35
  334. package/dist/src/ui/hooks/shellCommandProcessor.test.js.map +1 -1
  335. package/dist/src/ui/hooks/slashCommandProcessor.test.js +193 -165
  336. package/dist/src/ui/hooks/slashCommandProcessor.test.js.map +1 -1
  337. package/dist/src/ui/hooks/useAtCompletion.test.js +16 -5
  338. package/dist/src/ui/hooks/useAtCompletion.test.js.map +1 -1
  339. package/dist/src/ui/hooks/useAutoAcceptIndicator.js +10 -0
  340. package/dist/src/ui/hooks/useAutoAcceptIndicator.js.map +1 -1
  341. package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js +32 -1
  342. package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js.map +1 -1
  343. package/dist/src/ui/hooks/useCommandCompletion.test.js +66 -64
  344. package/dist/src/ui/hooks/useCommandCompletion.test.js.map +1 -1
  345. package/dist/src/ui/hooks/useConsoleMessages.test.js +26 -9
  346. package/dist/src/ui/hooks/useConsoleMessages.test.js.map +1 -1
  347. package/dist/src/ui/hooks/useEditorSettings.test.js +40 -34
  348. package/dist/src/ui/hooks/useEditorSettings.test.js.map +1 -1
  349. package/dist/src/ui/hooks/useExtensionUpdates.d.ts +14 -5
  350. package/dist/src/ui/hooks/useExtensionUpdates.js +18 -13
  351. package/dist/src/ui/hooks/useExtensionUpdates.js.map +1 -1
  352. package/dist/src/ui/hooks/useExtensionUpdates.test.js +49 -44
  353. package/dist/src/ui/hooks/useExtensionUpdates.test.js.map +1 -1
  354. package/dist/src/ui/hooks/useFlickerDetector.test.js +9 -5
  355. package/dist/src/ui/hooks/useFlickerDetector.test.js.map +1 -1
  356. package/dist/src/ui/hooks/useFocus.test.js +25 -9
  357. package/dist/src/ui/hooks/useFocus.test.js.map +1 -1
  358. package/dist/src/ui/hooks/useFolderTrust.test.js +46 -22
  359. package/dist/src/ui/hooks/useFolderTrust.test.js.map +1 -1
  360. package/dist/src/ui/hooks/useGeminiStream.js +56 -19
  361. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  362. package/dist/src/ui/hooks/useGeminiStream.test.js +260 -411
  363. package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -1
  364. package/dist/src/ui/hooks/useGitBranchName.js +4 -0
  365. package/dist/src/ui/hooks/useGitBranchName.js.map +1 -1
  366. package/dist/src/ui/hooks/useGitBranchName.test.js +46 -34
  367. package/dist/src/ui/hooks/useGitBranchName.test.js.map +1 -1
  368. package/dist/src/ui/hooks/useHistoryManager.test.js +2 -1
  369. package/dist/src/ui/hooks/useHistoryManager.test.js.map +1 -1
  370. package/dist/src/ui/hooks/useIdeTrustListener.test.js +40 -9
  371. package/dist/src/ui/hooks/useIdeTrustListener.test.js.map +1 -1
  372. package/dist/src/ui/hooks/useInputHistory.test.js +2 -1
  373. package/dist/src/ui/hooks/useInputHistory.test.js.map +1 -1
  374. package/dist/src/ui/hooks/useInputHistoryStore.test.js +2 -1
  375. package/dist/src/ui/hooks/useInputHistoryStore.test.js.map +1 -1
  376. package/dist/src/ui/hooks/useKeypress.test.js +103 -114
  377. package/dist/src/ui/hooks/useKeypress.test.js.map +1 -1
  378. package/dist/src/ui/hooks/useLoadingIndicator.test.js +24 -6
  379. package/dist/src/ui/hooks/useLoadingIndicator.test.js.map +1 -1
  380. package/dist/src/ui/hooks/useMemoryMonitor.test.js +10 -5
  381. package/dist/src/ui/hooks/useMemoryMonitor.test.js.map +1 -1
  382. package/dist/src/ui/hooks/useMessageQueue.test.js +62 -45
  383. package/dist/src/ui/hooks/useMessageQueue.test.js.map +1 -1
  384. package/dist/src/ui/hooks/useModelCommand.test.js +21 -11
  385. package/dist/src/ui/hooks/useModelCommand.test.js.map +1 -1
  386. package/dist/src/ui/hooks/useMouse.d.ts +17 -0
  387. package/dist/src/ui/hooks/useMouse.js +27 -0
  388. package/dist/src/ui/hooks/useMouse.js.map +1 -0
  389. package/dist/src/ui/hooks/useMouse.test.d.ts +6 -0
  390. package/dist/src/ui/hooks/useMouse.test.js +57 -0
  391. package/dist/src/ui/hooks/useMouse.test.js.map +1 -0
  392. package/dist/src/ui/hooks/usePermissionsModifyTrust.test.js +2 -2
  393. package/dist/src/ui/hooks/usePermissionsModifyTrust.test.js.map +1 -1
  394. package/dist/src/ui/hooks/usePhraseCycler.js +1 -1
  395. package/dist/src/ui/hooks/usePhraseCycler.js.map +1 -1
  396. package/dist/src/ui/hooks/usePhraseCycler.test.js +109 -106
  397. package/dist/src/ui/hooks/usePhraseCycler.test.js.map +1 -1
  398. package/dist/src/ui/hooks/usePrivacySettings.test.js +26 -6
  399. package/dist/src/ui/hooks/usePrivacySettings.test.js.map +1 -1
  400. package/dist/src/ui/hooks/usePromptCompletion.js +2 -2
  401. package/dist/src/ui/hooks/usePromptCompletion.js.map +1 -1
  402. package/dist/src/ui/hooks/useQuotaAndFallback.js +13 -14
  403. package/dist/src/ui/hooks/useQuotaAndFallback.js.map +1 -1
  404. package/dist/src/ui/hooks/useQuotaAndFallback.test.js +55 -48
  405. package/dist/src/ui/hooks/useQuotaAndFallback.test.js.map +1 -1
  406. package/dist/src/ui/hooks/useReactToolScheduler.d.ts +8 -1
  407. package/dist/src/ui/hooks/useReactToolScheduler.js +59 -34
  408. package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -1
  409. package/dist/src/ui/hooks/useReactToolScheduler.test.d.ts +6 -0
  410. package/dist/src/ui/hooks/useReactToolScheduler.test.js +65 -0
  411. package/dist/src/ui/hooks/useReactToolScheduler.test.js.map +1 -0
  412. package/dist/src/ui/hooks/useReverseSearchCompletion.test.js +2 -2
  413. package/dist/src/ui/hooks/useReverseSearchCompletion.test.js.map +1 -1
  414. package/dist/src/ui/hooks/useSelectionList.js +5 -4
  415. package/dist/src/ui/hooks/useSelectionList.js.map +1 -1
  416. package/dist/src/ui/hooks/useSelectionList.test.js +272 -183
  417. package/dist/src/ui/hooks/useSelectionList.test.js.map +1 -1
  418. package/dist/src/ui/hooks/useShellHistory.test.js +52 -20
  419. package/dist/src/ui/hooks/useShellHistory.test.js.map +1 -1
  420. package/dist/src/ui/hooks/useSlashCompletion.js +18 -7
  421. package/dist/src/ui/hooks/useSlashCompletion.js.map +1 -1
  422. package/dist/src/ui/hooks/useSlashCompletion.test.js +275 -137
  423. package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
  424. package/dist/src/ui/hooks/useTimer.test.js +43 -14
  425. package/dist/src/ui/hooks/useTimer.test.js.map +1 -1
  426. package/dist/src/ui/hooks/useToolScheduler.test.js +226 -242
  427. package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
  428. package/dist/src/ui/hooks/vim.test.js +235 -355
  429. package/dist/src/ui/hooks/vim.test.js.map +1 -1
  430. package/dist/src/ui/keyMatchers.test.js +30 -3
  431. package/dist/src/ui/keyMatchers.test.js.map +1 -1
  432. package/dist/src/ui/state/extensions.d.ts +1 -0
  433. package/dist/src/ui/state/extensions.js +1 -0
  434. package/dist/src/ui/state/extensions.js.map +1 -1
  435. package/dist/src/ui/themes/ansi-light.js +1 -0
  436. package/dist/src/ui/themes/ansi-light.js.map +1 -1
  437. package/dist/src/ui/themes/ansi.js +1 -0
  438. package/dist/src/ui/themes/ansi.js.map +1 -1
  439. package/dist/src/ui/themes/atom-one-dark.js +2 -0
  440. package/dist/src/ui/themes/atom-one-dark.js.map +1 -1
  441. package/dist/src/ui/themes/ayu-light.js +2 -0
  442. package/dist/src/ui/themes/ayu-light.js.map +1 -1
  443. package/dist/src/ui/themes/ayu.js +2 -0
  444. package/dist/src/ui/themes/ayu.js.map +1 -1
  445. package/dist/src/ui/themes/color-utils.d.ts +1 -0
  446. package/dist/src/ui/themes/color-utils.js +6 -0
  447. package/dist/src/ui/themes/color-utils.js.map +1 -1
  448. package/dist/src/ui/themes/color-utils.test.js +13 -1
  449. package/dist/src/ui/themes/color-utils.test.js.map +1 -1
  450. package/dist/src/ui/themes/dracula.js +2 -0
  451. package/dist/src/ui/themes/dracula.js.map +1 -1
  452. package/dist/src/ui/themes/github-dark.js +2 -0
  453. package/dist/src/ui/themes/github-dark.js.map +1 -1
  454. package/dist/src/ui/themes/github-light.js +2 -0
  455. package/dist/src/ui/themes/github-light.js.map +1 -1
  456. package/dist/src/ui/themes/googlecode.js +2 -0
  457. package/dist/src/ui/themes/googlecode.js.map +1 -1
  458. package/dist/src/ui/themes/no-color.js +3 -0
  459. package/dist/src/ui/themes/no-color.js.map +1 -1
  460. package/dist/src/ui/themes/semantic-tokens.d.ts +2 -0
  461. package/dist/src/ui/themes/semantic-tokens.js +6 -0
  462. package/dist/src/ui/themes/semantic-tokens.js.map +1 -1
  463. package/dist/src/ui/themes/shades-of-purple.js +2 -0
  464. package/dist/src/ui/themes/shades-of-purple.js.map +1 -1
  465. package/dist/src/ui/themes/theme.d.ts +3 -0
  466. package/dist/src/ui/themes/theme.js +14 -3
  467. package/dist/src/ui/themes/theme.js.map +1 -1
  468. package/dist/src/ui/themes/theme.test.js +67 -1
  469. package/dist/src/ui/themes/theme.test.js.map +1 -1
  470. package/dist/src/ui/themes/xcode.js +2 -0
  471. package/dist/src/ui/themes/xcode.js.map +1 -1
  472. package/dist/src/ui/types.d.ts +3 -1
  473. package/dist/src/ui/types.js +2 -0
  474. package/dist/src/ui/types.js.map +1 -1
  475. package/dist/src/ui/utils/CodeColorizer.js +2 -1
  476. package/dist/src/ui/utils/CodeColorizer.js.map +1 -1
  477. package/dist/src/ui/utils/InlineMarkdownRenderer.d.ts +1 -0
  478. package/dist/src/ui/utils/InlineMarkdownRenderer.js +11 -10
  479. package/dist/src/ui/utils/InlineMarkdownRenderer.js.map +1 -1
  480. package/dist/src/ui/utils/MarkdownDisplay.js +11 -9
  481. package/dist/src/ui/utils/MarkdownDisplay.js.map +1 -1
  482. package/dist/src/ui/utils/clipboardUtils.js +2 -2
  483. package/dist/src/ui/utils/clipboardUtils.js.map +1 -1
  484. package/dist/src/ui/utils/input.d.ts +17 -0
  485. package/dist/src/ui/utils/input.js +51 -0
  486. package/dist/src/ui/utils/input.js.map +1 -0
  487. package/dist/src/ui/utils/input.test.d.ts +6 -0
  488. package/dist/src/ui/utils/input.test.js +44 -0
  489. package/dist/src/ui/utils/input.test.js.map +1 -0
  490. package/dist/src/ui/utils/kittyProtocolDetector.js +13 -4
  491. package/dist/src/ui/utils/kittyProtocolDetector.js.map +1 -1
  492. package/dist/src/ui/utils/mouse.d.ts +31 -0
  493. package/dist/src/ui/utils/mouse.js +164 -0
  494. package/dist/src/ui/utils/mouse.js.map +1 -0
  495. package/dist/src/ui/utils/mouse.test.d.ts +6 -0
  496. package/dist/src/ui/utils/mouse.test.js +131 -0
  497. package/dist/src/ui/utils/mouse.test.js.map +1 -0
  498. package/dist/src/ui/utils/textOutput.d.ts +25 -0
  499. package/dist/src/ui/utils/textOutput.js +49 -0
  500. package/dist/src/ui/utils/textOutput.js.map +1 -0
  501. package/dist/src/ui/utils/textOutput.test.d.ts +6 -0
  502. package/dist/src/ui/utils/textOutput.test.js +79 -0
  503. package/dist/src/ui/utils/textOutput.test.js.map +1 -0
  504. package/dist/src/ui/utils/updateCheck.d.ts +7 -1
  505. package/dist/src/ui/utils/updateCheck.js +33 -29
  506. package/dist/src/ui/utils/updateCheck.js.map +1 -1
  507. package/dist/src/ui/utils/updateCheck.test.js +24 -50
  508. package/dist/src/ui/utils/updateCheck.test.js.map +1 -1
  509. package/dist/src/utils/commentJson.js +2 -2
  510. package/dist/src/utils/commentJson.js.map +1 -1
  511. package/dist/src/utils/commentJson.test.js +7 -6
  512. package/dist/src/utils/commentJson.test.js.map +1 -1
  513. package/dist/src/utils/envVarResolver.d.ts +2 -2
  514. package/dist/src/utils/envVarResolver.js +10 -7
  515. package/dist/src/utils/envVarResolver.js.map +1 -1
  516. package/dist/src/utils/events.d.ts +11 -2
  517. package/dist/src/utils/events.js +1 -0
  518. package/dist/src/utils/events.js.map +1 -1
  519. package/dist/src/utils/handleAutoUpdate.js +9 -3
  520. package/dist/src/utils/handleAutoUpdate.js.map +1 -1
  521. package/dist/src/utils/sandbox.js +16 -18
  522. package/dist/src/utils/sandbox.js.map +1 -1
  523. package/dist/src/utils/version.js +6 -2
  524. package/dist/src/utils/version.js.map +1 -1
  525. package/dist/src/zed-integration/acp.js +2 -1
  526. package/dist/src/zed-integration/acp.js.map +1 -1
  527. package/dist/src/zed-integration/schema.d.ts +4 -4
  528. package/dist/src/zed-integration/zedIntegration.d.ts +2 -2
  529. package/dist/src/zed-integration/zedIntegration.js +12 -19
  530. package/dist/src/zed-integration/zedIntegration.js.map +1 -1
  531. package/dist/tsconfig.tsbuildinfo +1 -1
  532. package/package.json +18 -14
  533. package/dist/src/config/policy.test.js +0 -360
  534. package/dist/src/config/policy.test.js.map +0 -1
  535. package/dist/src/utils/package.d.ts +0 -12
  536. package/dist/src/utils/package.js +0 -24
  537. package/dist/src/utils/package.js.map +0 -1
  538. /package/dist/src/{config/policy.test.d.ts → commands/extensions/validate.test.d.ts} +0 -0
@@ -5,13 +5,28 @@ import { jsx as _jsx } from "react/jsx-runtime";
5
5
  * SPDX-License-Identifier: Apache-2.0
6
6
  */
7
7
  import { describe, it, expect, vi, beforeEach, afterEach, } from 'vitest';
8
- import { render, cleanup } from 'ink-testing-library';
8
+ import { render } from '../test-utils/render.js';
9
+ import { cleanup } from 'ink-testing-library';
10
+ import { act, useContext } from 'react';
9
11
  import { AppContainer } from './AppContainer.js';
10
- import { makeFakeConfig } from '@google/gemini-cli-core';
12
+ import { makeFakeConfig, CoreEvent, } from '@google/gemini-cli-core';
13
+ // Mock coreEvents
14
+ const mockCoreEvents = vi.hoisted(() => ({
15
+ on: vi.fn(),
16
+ off: vi.fn(),
17
+ drainFeedbackBacklog: vi.fn(),
18
+ emit: vi.fn(),
19
+ }));
20
+ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
21
+ const actual = await importOriginal();
22
+ return {
23
+ ...actual,
24
+ coreEvents: mockCoreEvents,
25
+ };
26
+ });
11
27
  import { useQuotaAndFallback } from './hooks/useQuotaAndFallback.js';
12
28
  import { UIStateContext } from './contexts/UIStateContext.js';
13
29
  import { UIActionsContext, } from './contexts/UIActionsContext.js';
14
- import { useContext } from 'react';
15
30
  // Mock useStdout to capture terminal title writes
16
31
  let mockStdout;
17
32
  vi.mock('ink', async (importOriginal) => {
@@ -66,6 +81,10 @@ vi.mock('../utils/events.js');
66
81
  vi.mock('../utils/handleAutoUpdate.js');
67
82
  vi.mock('./utils/ConsolePatcher.js');
68
83
  vi.mock('../utils/cleanup.js');
84
+ vi.mock('./utils/mouse.js', () => ({
85
+ enableMouseEvents: vi.fn(),
86
+ disableMouseEvents: vi.fn(),
87
+ }));
69
88
  import { useHistory } from './hooks/useHistoryManager.js';
70
89
  import { useThemeCommand } from './hooks/useThemeCommand.js';
71
90
  import { useAuthCommand } from './auth/useAuth.js';
@@ -86,13 +105,17 @@ import { useSessionStats } from './contexts/SessionContext.js';
86
105
  import { useTextBuffer } from './components/shared/text-buffer.js';
87
106
  import { useLogger } from './hooks/useLogger.js';
88
107
  import { useLoadingIndicator } from './hooks/useLoadingIndicator.js';
108
+ import { useKeypress } from './hooks/useKeypress.js';
89
109
  import { measureElement } from 'ink';
90
110
  import { useTerminalSize } from './hooks/useTerminalSize.js';
91
111
  import { ShellExecutionService } from '@google/gemini-cli-core';
112
+ import {} from '../config/extension-manager.js';
113
+ import { enableMouseEvents, disableMouseEvents } from './utils/mouse.js';
92
114
  describe('AppContainer State Management', () => {
93
115
  let mockConfig;
94
116
  let mockSettings;
95
117
  let mockInitResult;
118
+ let mockExtensionManager;
96
119
  // Create typed mocks for all hooks
97
120
  const mockedUseQuotaAndFallback = useQuotaAndFallback;
98
121
  const mockedUseHistory = useHistory;
@@ -115,6 +138,7 @@ describe('AppContainer State Management', () => {
115
138
  const mockedUseTextBuffer = useTextBuffer;
116
139
  const mockedUseLogger = useLogger;
117
140
  const mockedUseLoadingIndicator = useLoadingIndicator;
141
+ const mockedUseKeypress = useKeypress;
118
142
  beforeEach(() => {
119
143
  vi.clearAllMocks();
120
144
  // Initialize mock stdout for terminal title tests
@@ -235,6 +259,13 @@ describe('AppContainer State Management', () => {
235
259
  mockConfig = makeFakeConfig();
236
260
  // Mock config's getTargetDir to return consistent workspace directory
237
261
  vi.spyOn(mockConfig, 'getTargetDir').mockReturnValue('/test/workspace');
262
+ mockExtensionManager = vi.mockObject({
263
+ getExtensions: vi.fn().mockReturnValue([]),
264
+ setRequestConsent: vi.fn(),
265
+ setRequestSetting: vi.fn(),
266
+ start: vi.fn(),
267
+ });
268
+ vi.spyOn(mockConfig, 'getExtensionLoader').mockReturnValue(mockExtensionManager);
238
269
  // Mock LoadedSettings
239
270
  mockSettings = {
240
271
  merged: {
@@ -261,27 +292,33 @@ describe('AppContainer State Management', () => {
261
292
  cleanup();
262
293
  });
263
294
  describe('Basic Rendering', () => {
264
- it('renders without crashing with minimal props', () => {
265
- expect(() => {
266
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
267
- }).not.toThrow();
295
+ it('renders without crashing with minimal props', async () => {
296
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
297
+ await act(async () => {
298
+ await new Promise((resolve) => setTimeout(resolve, 0));
299
+ });
300
+ unmount();
268
301
  });
269
- it('renders with startup warnings', () => {
302
+ it('renders with startup warnings', async () => {
270
303
  const startupWarnings = ['Warning 1', 'Warning 2'];
271
- expect(() => {
272
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, startupWarnings: startupWarnings, version: "1.0.0", initializationResult: mockInitResult }));
273
- }).not.toThrow();
304
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, startupWarnings: startupWarnings, version: "1.0.0", initializationResult: mockInitResult }));
305
+ await act(async () => {
306
+ await new Promise((resolve) => setTimeout(resolve, 0));
307
+ });
308
+ unmount();
274
309
  });
275
310
  });
276
311
  describe('State Initialization', () => {
277
- it('initializes with theme error from initialization result', () => {
312
+ it('initializes with theme error from initialization result', async () => {
278
313
  const initResultWithError = {
279
314
  ...mockInitResult,
280
315
  themeError: 'Failed to load theme',
281
316
  };
282
- expect(() => {
283
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: initResultWithError }));
284
- }).not.toThrow();
317
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: initResultWithError }));
318
+ await act(async () => {
319
+ await new Promise((resolve) => setTimeout(resolve, 0));
320
+ });
321
+ unmount();
285
322
  });
286
323
  it('handles debug mode state', () => {
287
324
  const debugConfig = makeFakeConfig();
@@ -292,29 +329,38 @@ describe('AppContainer State Management', () => {
292
329
  });
293
330
  });
294
331
  describe('Context Providers', () => {
295
- it('provides AppContext with correct values', () => {
332
+ it('provides AppContext with correct values', async () => {
296
333
  const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "2.0.0", initializationResult: mockInitResult }));
334
+ await act(async () => {
335
+ await new Promise((resolve) => setTimeout(resolve, 0));
336
+ });
297
337
  // Should render and unmount cleanly
298
338
  expect(() => unmount()).not.toThrow();
299
339
  });
300
- it('provides UIStateContext with state management', () => {
301
- expect(() => {
302
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
303
- }).not.toThrow();
340
+ it('provides UIStateContext with state management', async () => {
341
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
342
+ await act(async () => {
343
+ await new Promise((resolve) => setTimeout(resolve, 0));
344
+ });
345
+ unmount();
304
346
  });
305
- it('provides UIActionsContext with action handlers', () => {
306
- expect(() => {
307
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
308
- }).not.toThrow();
347
+ it('provides UIActionsContext with action handlers', async () => {
348
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
349
+ await act(async () => {
350
+ await new Promise((resolve) => setTimeout(resolve, 0));
351
+ });
352
+ unmount();
309
353
  });
310
- it('provides ConfigContext with config object', () => {
311
- expect(() => {
312
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
313
- }).not.toThrow();
354
+ it('provides ConfigContext with config object', async () => {
355
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
356
+ await act(async () => {
357
+ await new Promise((resolve) => setTimeout(resolve, 0));
358
+ });
359
+ unmount();
314
360
  });
315
361
  });
316
362
  describe('Settings Integration', () => {
317
- it('handles settings with all display options disabled', () => {
363
+ it('handles settings with all display options disabled', async () => {
318
364
  const settingsAllHidden = {
319
365
  merged: {
320
366
  hideBanner: true,
@@ -323,11 +369,13 @@ describe('AppContainer State Management', () => {
323
369
  showMemoryUsage: false,
324
370
  },
325
371
  };
326
- expect(() => {
327
- render(_jsx(AppContainer, { config: mockConfig, settings: settingsAllHidden, version: "1.0.0", initializationResult: mockInitResult }));
328
- }).not.toThrow();
372
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: settingsAllHidden, version: "1.0.0", initializationResult: mockInitResult }));
373
+ await act(async () => {
374
+ await new Promise((resolve) => setTimeout(resolve, 0));
375
+ });
376
+ unmount();
329
377
  });
330
- it('handles settings with memory usage enabled', () => {
378
+ it('handles settings with memory usage enabled', async () => {
331
379
  const settingsWithMemory = {
332
380
  merged: {
333
381
  hideBanner: false,
@@ -336,36 +384,44 @@ describe('AppContainer State Management', () => {
336
384
  showMemoryUsage: true,
337
385
  },
338
386
  };
339
- expect(() => {
340
- render(_jsx(AppContainer, { config: mockConfig, settings: settingsWithMemory, version: "1.0.0", initializationResult: mockInitResult }));
341
- }).not.toThrow();
387
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: settingsWithMemory, version: "1.0.0", initializationResult: mockInitResult }));
388
+ await act(async () => {
389
+ await new Promise((resolve) => setTimeout(resolve, 0));
390
+ });
391
+ unmount();
342
392
  });
343
393
  });
344
394
  describe('Version Handling', () => {
345
- it.each(['1.0.0', '2.1.3-beta', '3.0.0-nightly'])('handles version format: %s', (version) => {
346
- expect(() => {
347
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: version, initializationResult: mockInitResult }));
348
- }).not.toThrow();
395
+ it.each(['1.0.0', '2.1.3-beta', '3.0.0-nightly'])('handles version format: %s', async (version) => {
396
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: version, initializationResult: mockInitResult }));
397
+ await act(async () => {
398
+ await new Promise((resolve) => setTimeout(resolve, 0));
399
+ });
400
+ unmount();
349
401
  });
350
402
  });
351
403
  describe('Error Handling', () => {
352
- it('handles config methods that might throw', () => {
404
+ it('handles config methods that might throw', async () => {
353
405
  const errorConfig = makeFakeConfig();
354
406
  vi.spyOn(errorConfig, 'getModel').mockImplementation(() => {
355
407
  throw new Error('Config error');
356
408
  });
357
409
  // Should still render without crashing - errors should be handled internally
358
- expect(() => {
359
- render(_jsx(AppContainer, { config: errorConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
360
- }).not.toThrow();
410
+ const { unmount } = render(_jsx(AppContainer, { config: errorConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
411
+ await act(async () => {
412
+ await new Promise((resolve) => setTimeout(resolve, 0));
413
+ });
414
+ unmount();
361
415
  });
362
- it('handles undefined settings gracefully', () => {
416
+ it('handles undefined settings gracefully', async () => {
363
417
  const undefinedSettings = {
364
418
  merged: {},
365
419
  };
366
- expect(() => {
367
- render(_jsx(AppContainer, { config: mockConfig, settings: undefinedSettings, version: "1.0.0", initializationResult: mockInitResult }));
368
- }).not.toThrow();
420
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: undefinedSettings, version: "1.0.0", initializationResult: mockInitResult }));
421
+ await act(async () => {
422
+ await new Promise((resolve) => setTimeout(resolve, 0));
423
+ });
424
+ unmount();
369
425
  });
370
426
  });
371
427
  describe('Provider Hierarchy', () => {
@@ -377,13 +433,17 @@ describe('AppContainer State Management', () => {
377
433
  });
378
434
  });
379
435
  describe('Quota and Fallback Integration', () => {
380
- it('passes a null proQuotaRequest to UIStateContext by default', () => {
436
+ it('passes a null proQuotaRequest to UIStateContext by default', async () => {
381
437
  // The default mock from beforeEach already sets proQuotaRequest to null
382
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
438
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
439
+ await act(async () => {
440
+ await new Promise((resolve) => setTimeout(resolve, 0));
441
+ });
383
442
  // Assert that the context value is as expected
384
443
  expect(capturedUIState.proQuotaRequest).toBeNull();
444
+ unmount();
385
445
  });
386
- it('passes a valid proQuotaRequest to UIStateContext when provided by the hook', () => {
446
+ it('passes a valid proQuotaRequest to UIStateContext when provided by the hook', async () => {
387
447
  // Arrange: Create a mock request object that a UI dialog would receive
388
448
  const mockRequest = {
389
449
  failedModel: 'gemini-pro',
@@ -395,11 +455,15 @@ describe('AppContainer State Management', () => {
395
455
  handleProQuotaChoice: vi.fn(),
396
456
  });
397
457
  // Act: Render the container
398
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
458
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
459
+ await act(async () => {
460
+ await new Promise((resolve) => setTimeout(resolve, 0));
461
+ });
399
462
  // Assert: The mock request is correctly passed through the context
400
463
  expect(capturedUIState.proQuotaRequest).toEqual(mockRequest);
464
+ unmount();
401
465
  });
402
- it('passes the handleProQuotaChoice function to UIActionsContext', () => {
466
+ it('passes the handleProQuotaChoice function to UIActionsContext', async () => {
403
467
  // Arrange: Create a mock handler function
404
468
  const mockHandler = vi.fn();
405
469
  mockedUseQuotaAndFallback.mockReturnValue({
@@ -407,12 +471,18 @@ describe('AppContainer State Management', () => {
407
471
  handleProQuotaChoice: mockHandler,
408
472
  });
409
473
  // Act: Render the container
410
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
474
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
475
+ await act(async () => {
476
+ await new Promise((resolve) => setTimeout(resolve, 0));
477
+ });
411
478
  // Assert: The action in the context is the mock handler we provided
412
479
  expect(capturedUIActions.handleProQuotaChoice).toBe(mockHandler);
413
480
  // You can even verify that the plumbed function is callable
414
- capturedUIActions.handleProQuotaChoice('auth');
481
+ act(() => {
482
+ capturedUIActions.handleProQuotaChoice('auth');
483
+ });
415
484
  expect(mockHandler).toHaveBeenCalledWith('auth');
485
+ unmount();
416
486
  });
417
487
  });
418
488
  describe('Terminal Title Update Feature', () => {
@@ -661,37 +731,59 @@ describe('AppContainer State Management', () => {
661
731
  vi.useRealTimers();
662
732
  });
663
733
  it('should set and clear the queue error message after a timeout', async () => {
664
- const { rerender } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
734
+ const { rerender, unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
735
+ await act(async () => {
736
+ vi.advanceTimersByTime(0);
737
+ });
665
738
  expect(capturedUIState.queueErrorMessage).toBeNull();
666
- capturedUIActions.setQueueErrorMessage('Test error');
739
+ act(() => {
740
+ capturedUIActions.setQueueErrorMessage('Test error');
741
+ });
667
742
  rerender(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
668
743
  expect(capturedUIState.queueErrorMessage).toBe('Test error');
669
- vi.advanceTimersByTime(3000);
744
+ act(() => {
745
+ vi.advanceTimersByTime(3000);
746
+ });
670
747
  rerender(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
671
748
  expect(capturedUIState.queueErrorMessage).toBeNull();
749
+ unmount();
672
750
  });
673
751
  it('should reset the timer if a new error message is set', async () => {
674
- const { rerender } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
675
- capturedUIActions.setQueueErrorMessage('First error');
752
+ const { rerender, unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
753
+ await act(async () => {
754
+ vi.advanceTimersByTime(0);
755
+ });
756
+ act(() => {
757
+ capturedUIActions.setQueueErrorMessage('First error');
758
+ });
676
759
  rerender(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
677
760
  expect(capturedUIState.queueErrorMessage).toBe('First error');
678
- vi.advanceTimersByTime(1500);
679
- capturedUIActions.setQueueErrorMessage('Second error');
761
+ act(() => {
762
+ vi.advanceTimersByTime(1500);
763
+ });
764
+ act(() => {
765
+ capturedUIActions.setQueueErrorMessage('Second error');
766
+ });
680
767
  rerender(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
681
768
  expect(capturedUIState.queueErrorMessage).toBe('Second error');
682
- vi.advanceTimersByTime(2000);
769
+ act(() => {
770
+ vi.advanceTimersByTime(2000);
771
+ });
683
772
  rerender(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
684
773
  expect(capturedUIState.queueErrorMessage).toBe('Second error');
685
774
  // 5. Advance time past the 3 second timeout from the second message
686
- vi.advanceTimersByTime(1000);
775
+ act(() => {
776
+ vi.advanceTimersByTime(1000);
777
+ });
687
778
  rerender(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
688
779
  expect(capturedUIState.queueErrorMessage).toBeNull();
780
+ unmount();
689
781
  });
690
782
  });
691
783
  describe('Terminal Height Calculation', () => {
692
784
  const mockedMeasureElement = measureElement;
693
785
  const mockedUseTerminalSize = useTerminalSize;
694
- it('should prevent terminal height from being less than 1', () => {
786
+ it('should prevent terminal height from being less than 1', async () => {
695
787
  const resizePtySpy = vi.spyOn(ShellExecutionService, 'resizePty');
696
788
  // Arrange: Simulate a small terminal and a large footer
697
789
  mockedUseTerminalSize.mockReturnValue({ columns: 80, rows: 5 });
@@ -705,61 +797,55 @@ describe('AppContainer State Management', () => {
705
797
  cancelOngoingRequest: vi.fn(),
706
798
  activePtyId: 'some-id',
707
799
  });
708
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
800
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
801
+ await act(async () => {
802
+ await new Promise((resolve) => setTimeout(resolve, 0));
803
+ });
709
804
  // Assert: The shell should be resized to a minimum height of 1, not a negative number.
710
805
  // The old code would have tried to set a negative height.
711
806
  expect(resizePtySpy).toHaveBeenCalled();
712
807
  const lastCall = resizePtySpy.mock.calls[resizePtySpy.mock.calls.length - 1];
713
808
  // Check the height argument specifically
714
809
  expect(lastCall[2]).toBe(1);
810
+ unmount();
715
811
  });
716
812
  });
717
- describe('Keyboard Input Handling', () => {
718
- it('should block quit command during authentication', () => {
719
- mockedUseAuthCommand.mockReturnValue({
720
- authState: 'unauthenticated',
721
- setAuthState: vi.fn(),
722
- authError: null,
723
- onAuthError: vi.fn(),
724
- });
725
- const mockHandleSlashCommand = vi.fn();
726
- mockedUseSlashCommandProcessor.mockReturnValue({
727
- handleSlashCommand: mockHandleSlashCommand,
728
- slashCommands: [],
729
- pendingHistoryItems: [],
730
- commandContext: {},
731
- shellConfirmationRequest: null,
732
- confirmationRequest: null,
733
- });
734
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
735
- expect(mockHandleSlashCommand).not.toHaveBeenCalledWith('/quit');
736
- });
737
- it('should prevent exit command when text buffer has content', () => {
738
- mockedUseTextBuffer.mockReturnValue({
739
- text: 'some user input',
740
- setText: vi.fn(),
741
- });
742
- const mockHandleSlashCommand = vi.fn();
743
- mockedUseSlashCommandProcessor.mockReturnValue({
744
- handleSlashCommand: mockHandleSlashCommand,
745
- slashCommands: [],
746
- pendingHistoryItems: [],
747
- commandContext: {},
748
- shellConfirmationRequest: null,
749
- confirmationRequest: null,
813
+ describe('Keyboard Input Handling (CTRL+C / CTRL+D)', () => {
814
+ let handleGlobalKeypress;
815
+ let mockHandleSlashCommand;
816
+ let mockCancelOngoingRequest;
817
+ let rerender;
818
+ let unmount;
819
+ // Helper function to reduce boilerplate in tests
820
+ const setupKeypressTest = async () => {
821
+ const renderResult = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
822
+ await act(async () => {
823
+ vi.advanceTimersByTime(0);
750
824
  });
751
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
752
- expect(mockHandleSlashCommand).not.toHaveBeenCalledWith('/quit');
753
- });
754
- it('should require double Ctrl+C to exit when dialogs are open', () => {
755
- vi.useFakeTimers();
756
- mockedUseThemeCommand.mockReturnValue({
757
- isThemeDialogOpen: true,
758
- openThemeDialog: vi.fn(),
759
- handleThemeSelect: vi.fn(),
760
- handleThemeHighlight: vi.fn(),
825
+ rerender = () => renderResult.rerender(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
826
+ unmount = renderResult.unmount;
827
+ };
828
+ const pressKey = (key, times = 1) => {
829
+ for (let i = 0; i < times; i++) {
830
+ act(() => {
831
+ handleGlobalKeypress({
832
+ name: 'c',
833
+ ctrl: false,
834
+ meta: false,
835
+ shift: false,
836
+ ...key,
837
+ });
838
+ });
839
+ rerender();
840
+ }
841
+ };
842
+ beforeEach(() => {
843
+ // Capture the keypress handler from the AppContainer
844
+ mockedUseKeypress.mockImplementation((callback) => {
845
+ handleGlobalKeypress = callback;
761
846
  });
762
- const mockHandleSlashCommand = vi.fn();
847
+ // Mock slash command handler
848
+ mockHandleSlashCommand = vi.fn();
763
849
  mockedUseSlashCommandProcessor.mockReturnValue({
764
850
  handleSlashCommand: mockHandleSlashCommand,
765
851
  slashCommands: [],
@@ -768,72 +854,344 @@ describe('AppContainer State Management', () => {
768
854
  shellConfirmationRequest: null,
769
855
  confirmationRequest: null,
770
856
  });
771
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
772
- expect(mockHandleSlashCommand).not.toHaveBeenCalledWith('/quit');
773
- expect(mockHandleSlashCommand).not.toHaveBeenCalledWith('/quit');
774
- vi.useRealTimers();
775
- });
776
- it('should cancel ongoing request on first Ctrl+C', () => {
777
- const mockCancelOngoingRequest = vi.fn();
857
+ // Mock request cancellation
858
+ mockCancelOngoingRequest = vi.fn();
778
859
  mockedUseGeminiStream.mockReturnValue({
779
- streamingState: 'responding',
860
+ streamingState: 'idle',
780
861
  submitQuery: vi.fn(),
781
862
  initError: null,
782
863
  pendingHistoryItems: [],
783
864
  thought: null,
784
865
  cancelOngoingRequest: mockCancelOngoingRequest,
785
866
  });
786
- const mockHandleSlashCommand = vi.fn();
787
- mockedUseSlashCommandProcessor.mockReturnValue({
788
- handleSlashCommand: mockHandleSlashCommand,
789
- slashCommands: [],
790
- pendingHistoryItems: [],
791
- commandContext: {},
792
- shellConfirmationRequest: null,
793
- confirmationRequest: null,
867
+ // Default empty text buffer
868
+ mockedUseTextBuffer.mockReturnValue({
869
+ text: '',
870
+ setText: vi.fn(),
794
871
  });
795
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
796
- expect(mockHandleSlashCommand).not.toHaveBeenCalledWith('/quit');
797
- });
798
- it('should reset Ctrl+C state after timeout', () => {
799
872
  vi.useFakeTimers();
800
- const mockHandleSlashCommand = vi.fn();
801
- mockedUseSlashCommandProcessor.mockReturnValue({
802
- handleSlashCommand: mockHandleSlashCommand,
803
- slashCommands: [],
804
- pendingHistoryItems: [],
805
- commandContext: {},
806
- shellConfirmationRequest: null,
807
- confirmationRequest: null,
873
+ });
874
+ afterEach(() => {
875
+ vi.useRealTimers();
876
+ });
877
+ describe('CTRL+C', () => {
878
+ it('should cancel ongoing request on first press', async () => {
879
+ mockedUseGeminiStream.mockReturnValue({
880
+ streamingState: 'responding',
881
+ submitQuery: vi.fn(),
882
+ initError: null,
883
+ pendingHistoryItems: [],
884
+ thought: null,
885
+ cancelOngoingRequest: mockCancelOngoingRequest,
886
+ });
887
+ await setupKeypressTest();
888
+ pressKey({ name: 'c', ctrl: true });
889
+ expect(mockCancelOngoingRequest).toHaveBeenCalledTimes(1);
890
+ expect(mockHandleSlashCommand).not.toHaveBeenCalled();
891
+ unmount();
892
+ });
893
+ it('should quit on second press', async () => {
894
+ await setupKeypressTest();
895
+ pressKey({ name: 'c', ctrl: true }, 2);
896
+ expect(mockCancelOngoingRequest).toHaveBeenCalledTimes(2);
897
+ expect(mockHandleSlashCommand).toHaveBeenCalledWith('/quit');
898
+ unmount();
899
+ });
900
+ it('should reset press count after a timeout', async () => {
901
+ await setupKeypressTest();
902
+ pressKey({ name: 'c', ctrl: true });
903
+ expect(mockHandleSlashCommand).not.toHaveBeenCalled();
904
+ // Advance timer past the reset threshold
905
+ act(() => {
906
+ vi.advanceTimersByTime(1001);
907
+ });
908
+ pressKey({ name: 'c', ctrl: true });
909
+ expect(mockHandleSlashCommand).not.toHaveBeenCalled();
910
+ unmount();
911
+ });
912
+ });
913
+ describe('CTRL+D', () => {
914
+ it('should do nothing if text buffer is not empty', async () => {
915
+ mockedUseTextBuffer.mockReturnValue({
916
+ text: 'some text',
917
+ setText: vi.fn(),
918
+ });
919
+ await setupKeypressTest();
920
+ pressKey({ name: 'd', ctrl: true }, 2);
921
+ expect(mockHandleSlashCommand).not.toHaveBeenCalled();
922
+ unmount();
923
+ });
924
+ it('should quit on second press if buffer is empty', async () => {
925
+ await setupKeypressTest();
926
+ pressKey({ name: 'd', ctrl: true }, 2);
927
+ expect(mockHandleSlashCommand).toHaveBeenCalledWith('/quit');
928
+ unmount();
929
+ });
930
+ it('should reset press count after a timeout', async () => {
931
+ await setupKeypressTest();
932
+ pressKey({ name: 'd', ctrl: true });
933
+ expect(mockHandleSlashCommand).not.toHaveBeenCalled();
934
+ // Advance timer past the reset threshold
935
+ act(() => {
936
+ vi.advanceTimersByTime(1001);
937
+ });
938
+ pressKey({ name: 'd', ctrl: true });
939
+ expect(mockHandleSlashCommand).not.toHaveBeenCalled();
940
+ unmount();
941
+ });
942
+ });
943
+ });
944
+ describe('Copy Mode (CTRL+S)', () => {
945
+ let handleGlobalKeypress;
946
+ let rerender;
947
+ let unmount;
948
+ const setupCopyModeTest = async (isAlternateMode = false) => {
949
+ // Update settings for this test run
950
+ const testSettings = {
951
+ ...mockSettings,
952
+ merged: {
953
+ ...mockSettings.merged,
954
+ ui: {
955
+ ...mockSettings.merged.ui,
956
+ useAlternateBuffer: isAlternateMode,
957
+ },
958
+ },
959
+ };
960
+ const renderResult = render(_jsx(AppContainer, { config: mockConfig, settings: testSettings, version: "1.0.0", initializationResult: mockInitResult }));
961
+ await act(async () => {
962
+ vi.advanceTimersByTime(0);
963
+ });
964
+ rerender = () => renderResult.rerender(_jsx(AppContainer, { config: mockConfig, settings: testSettings, version: "1.0.0", initializationResult: mockInitResult }));
965
+ unmount = renderResult.unmount;
966
+ };
967
+ beforeEach(() => {
968
+ mockStdout.write.mockClear();
969
+ mockedUseKeypress.mockImplementation((callback) => {
970
+ handleGlobalKeypress = callback;
808
971
  });
809
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
810
- expect(mockHandleSlashCommand).not.toHaveBeenCalledWith('/quit');
811
- vi.advanceTimersByTime(1001);
812
- expect(mockHandleSlashCommand).not.toHaveBeenCalledWith('/quit');
972
+ vi.useFakeTimers();
973
+ });
974
+ afterEach(() => {
813
975
  vi.useRealTimers();
814
976
  });
977
+ describe.each([
978
+ {
979
+ isAlternateMode: false,
980
+ shouldEnable: false,
981
+ modeName: 'Normal Mode',
982
+ },
983
+ {
984
+ isAlternateMode: true,
985
+ shouldEnable: true,
986
+ modeName: 'Alternate Buffer Mode',
987
+ },
988
+ ])('$modeName', ({ isAlternateMode, shouldEnable }) => {
989
+ it(`should ${shouldEnable ? 'toggle' : 'NOT toggle'} mouse off when Ctrl+S is pressed`, async () => {
990
+ await setupCopyModeTest(isAlternateMode);
991
+ mockStdout.write.mockClear(); // Clear initial enable call
992
+ act(() => {
993
+ handleGlobalKeypress({
994
+ name: 's',
995
+ ctrl: true,
996
+ meta: false,
997
+ shift: false,
998
+ paste: false,
999
+ sequence: '\x13',
1000
+ });
1001
+ });
1002
+ rerender();
1003
+ if (shouldEnable) {
1004
+ expect(disableMouseEvents).toHaveBeenCalled();
1005
+ }
1006
+ else {
1007
+ expect(disableMouseEvents).not.toHaveBeenCalled();
1008
+ }
1009
+ unmount();
1010
+ });
1011
+ if (shouldEnable) {
1012
+ it('should toggle mouse back on when Ctrl+S is pressed again', async () => {
1013
+ await setupCopyModeTest(isAlternateMode);
1014
+ mockStdout.write.mockClear();
1015
+ // Turn it on (disable mouse)
1016
+ act(() => {
1017
+ handleGlobalKeypress({
1018
+ name: 's',
1019
+ ctrl: true,
1020
+ meta: false,
1021
+ shift: false,
1022
+ paste: false,
1023
+ sequence: '\x13',
1024
+ });
1025
+ });
1026
+ rerender();
1027
+ expect(disableMouseEvents).toHaveBeenCalled();
1028
+ // Turn it off (enable mouse)
1029
+ act(() => {
1030
+ handleGlobalKeypress({
1031
+ name: 'any', // Any key should exit copy mode
1032
+ ctrl: false,
1033
+ meta: false,
1034
+ shift: false,
1035
+ paste: false,
1036
+ sequence: 'a',
1037
+ });
1038
+ });
1039
+ rerender();
1040
+ expect(enableMouseEvents).toHaveBeenCalled();
1041
+ unmount();
1042
+ });
1043
+ it('should exit copy mode on any key press', async () => {
1044
+ await setupCopyModeTest(isAlternateMode);
1045
+ // Enter copy mode
1046
+ act(() => {
1047
+ handleGlobalKeypress({
1048
+ name: 's',
1049
+ ctrl: true,
1050
+ meta: false,
1051
+ shift: false,
1052
+ paste: false,
1053
+ sequence: '\x13',
1054
+ });
1055
+ });
1056
+ rerender();
1057
+ mockStdout.write.mockClear();
1058
+ // Press any other key
1059
+ act(() => {
1060
+ handleGlobalKeypress({
1061
+ name: 'a',
1062
+ ctrl: false,
1063
+ meta: false,
1064
+ shift: false,
1065
+ paste: false,
1066
+ sequence: 'a',
1067
+ });
1068
+ });
1069
+ rerender();
1070
+ // Should have re-enabled mouse
1071
+ expect(enableMouseEvents).toHaveBeenCalled();
1072
+ unmount();
1073
+ });
1074
+ }
1075
+ });
815
1076
  });
816
1077
  describe('Model Dialog Integration', () => {
817
- it('should provide isModelDialogOpen in the UIStateContext', () => {
1078
+ it('should provide isModelDialogOpen in the UIStateContext', async () => {
818
1079
  mockedUseModelCommand.mockReturnValue({
819
1080
  isModelDialogOpen: true,
820
1081
  openModelDialog: vi.fn(),
821
1082
  closeModelDialog: vi.fn(),
822
1083
  });
823
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
1084
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
1085
+ await act(async () => {
1086
+ await new Promise((resolve) => setTimeout(resolve, 0));
1087
+ });
824
1088
  expect(capturedUIState.isModelDialogOpen).toBe(true);
1089
+ unmount();
825
1090
  });
826
- it('should provide model dialog actions in the UIActionsContext', () => {
1091
+ it('should provide model dialog actions in the UIActionsContext', async () => {
827
1092
  const mockCloseModelDialog = vi.fn();
828
1093
  mockedUseModelCommand.mockReturnValue({
829
1094
  isModelDialogOpen: false,
830
1095
  openModelDialog: vi.fn(),
831
1096
  closeModelDialog: mockCloseModelDialog,
832
1097
  });
833
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
1098
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
1099
+ await act(async () => {
1100
+ await new Promise((resolve) => setTimeout(resolve, 0));
1101
+ });
834
1102
  // Verify that the actions are correctly passed through context
835
- capturedUIActions.closeModelDialog();
1103
+ act(() => {
1104
+ capturedUIActions.closeModelDialog();
1105
+ });
836
1106
  expect(mockCloseModelDialog).toHaveBeenCalled();
1107
+ unmount();
1108
+ });
1109
+ });
1110
+ describe('CoreEvents Integration', () => {
1111
+ it('subscribes to UserFeedback and drains backlog on mount', async () => {
1112
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
1113
+ await act(async () => {
1114
+ await new Promise((resolve) => setTimeout(resolve, 0));
1115
+ });
1116
+ expect(mockCoreEvents.on).toHaveBeenCalledWith(CoreEvent.UserFeedback, expect.any(Function));
1117
+ expect(mockCoreEvents.drainFeedbackBacklog).toHaveBeenCalledTimes(1);
1118
+ unmount();
1119
+ });
1120
+ it('unsubscribes from UserFeedback on unmount', async () => {
1121
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
1122
+ await act(async () => {
1123
+ await new Promise((resolve) => setTimeout(resolve, 0));
1124
+ });
1125
+ unmount();
1126
+ expect(mockCoreEvents.off).toHaveBeenCalledWith(CoreEvent.UserFeedback, expect.any(Function));
1127
+ });
1128
+ it('adds history item when UserFeedback event is received', async () => {
1129
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
1130
+ await act(async () => {
1131
+ await new Promise((resolve) => setTimeout(resolve, 0));
1132
+ });
1133
+ // Get the registered handler
1134
+ const handler = mockCoreEvents.on.mock.calls.find((call) => call[0] === CoreEvent.UserFeedback)?.[1];
1135
+ expect(handler).toBeDefined();
1136
+ // Simulate an event
1137
+ const payload = {
1138
+ severity: 'error',
1139
+ message: 'Test error message',
1140
+ };
1141
+ act(() => {
1142
+ handler(payload);
1143
+ });
1144
+ expect(mockedUseHistory().addItem).toHaveBeenCalledWith(expect.objectContaining({
1145
+ type: 'error',
1146
+ text: 'Test error message',
1147
+ }), expect.any(Number));
1148
+ unmount();
1149
+ });
1150
+ it('updates currentModel when ModelChanged event is received', async () => {
1151
+ // Arrange: Mock initial model
1152
+ vi.spyOn(mockConfig, 'getModel').mockReturnValue('initial-model');
1153
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
1154
+ // Verify initial model
1155
+ await act(async () => {
1156
+ await vi.waitFor(() => {
1157
+ expect(capturedUIState?.currentModel).toBe('initial-model');
1158
+ });
1159
+ });
1160
+ // Get the registered handler for ModelChanged
1161
+ const handler = mockCoreEvents.on.mock.calls.find((call) => call[0] === CoreEvent.ModelChanged)?.[1];
1162
+ expect(handler).toBeDefined();
1163
+ // Act: Simulate ModelChanged event
1164
+ act(() => {
1165
+ handler({ model: 'new-model' });
1166
+ });
1167
+ // Assert: Verify model is updated
1168
+ expect(capturedUIState.currentModel).toBe('new-model');
1169
+ unmount();
1170
+ });
1171
+ });
1172
+ describe('Shell Interaction', () => {
1173
+ it('should not crash if resizing the pty fails', async () => {
1174
+ const resizePtySpy = vi
1175
+ .spyOn(ShellExecutionService, 'resizePty')
1176
+ .mockImplementation(() => {
1177
+ throw new Error('Cannot resize a pty that has already exited');
1178
+ });
1179
+ mockedUseGeminiStream.mockReturnValue({
1180
+ streamingState: 'idle',
1181
+ submitQuery: vi.fn(),
1182
+ initError: null,
1183
+ pendingHistoryItems: [],
1184
+ thought: null,
1185
+ cancelOngoingRequest: vi.fn(),
1186
+ activePtyId: 'some-pty-id', // Make sure activePtyId is set
1187
+ });
1188
+ // The main assertion is that the render does not throw.
1189
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
1190
+ await act(async () => {
1191
+ await new Promise((resolve) => setTimeout(resolve, 0));
1192
+ });
1193
+ expect(resizePtySpy).toHaveBeenCalled();
1194
+ unmount();
837
1195
  });
838
1196
  });
839
1197
  });