@machina.ai/cell-cli 1.10.0-rc1 → 1.13.0-rc1

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 (813) hide show
  1. package/dist/index.js +5 -5
  2. package/dist/index.js.map +1 -1
  3. package/dist/package.json +14 -12
  4. package/dist/src/commands/extensions/disable.d.ts +1 -1
  5. package/dist/src/commands/extensions/disable.js +19 -8
  6. package/dist/src/commands/extensions/disable.js.map +1 -1
  7. package/dist/src/commands/extensions/enable.d.ts +1 -1
  8. package/dist/src/commands/extensions/enable.js +19 -9
  9. package/dist/src/commands/extensions/enable.js.map +1 -1
  10. package/dist/src/commands/extensions/examples/mcp-server/example.js +46 -0
  11. package/dist/src/commands/extensions/examples/mcp-server/example.js.map +1 -0
  12. package/dist/src/commands/extensions/install.d.ts +1 -0
  13. package/dist/src/commands/extensions/install.js +29 -4
  14. package/dist/src/commands/extensions/install.js.map +1 -1
  15. package/dist/src/commands/extensions/install.test.js +39 -19
  16. package/dist/src/commands/extensions/install.test.js.map +1 -1
  17. package/dist/src/commands/extensions/link.js +16 -4
  18. package/dist/src/commands/extensions/link.js.map +1 -1
  19. package/dist/src/commands/extensions/list.js +17 -6
  20. package/dist/src/commands/extensions/list.js.map +1 -1
  21. package/dist/src/commands/extensions/new.js +14 -20
  22. package/dist/src/commands/extensions/new.js.map +1 -1
  23. package/dist/src/commands/extensions/uninstall.js +16 -4
  24. package/dist/src/commands/extensions/uninstall.js.map +1 -1
  25. package/dist/src/commands/extensions/update.js +28 -23
  26. package/dist/src/commands/extensions/update.js.map +1 -1
  27. package/dist/src/commands/extensions/validate.d.ts +12 -0
  28. package/dist/src/commands/extensions/validate.js +83 -0
  29. package/dist/src/commands/extensions/validate.js.map +1 -0
  30. package/dist/src/commands/extensions/validate.test.d.ts +6 -0
  31. package/dist/src/commands/extensions/validate.test.js +93 -0
  32. package/dist/src/commands/extensions/validate.test.js.map +1 -0
  33. package/dist/src/commands/extensions.js +3 -0
  34. package/dist/src/commands/extensions.js.map +1 -1
  35. package/dist/src/commands/mcp/add.js +7 -4
  36. package/dist/src/commands/mcp/add.js.map +1 -1
  37. package/dist/src/commands/mcp/add.test.d.ts +6 -0
  38. package/dist/src/commands/mcp/add.test.js +247 -0
  39. package/dist/src/commands/mcp/add.test.js.map +1 -0
  40. package/dist/src/commands/mcp/list.js +18 -9
  41. package/dist/src/commands/mcp/list.js.map +1 -1
  42. package/dist/src/commands/mcp/list.test.d.ts +6 -0
  43. package/dist/src/commands/mcp/list.test.js +128 -0
  44. package/dist/src/commands/mcp/list.test.js.map +1 -0
  45. package/dist/src/commands/mcp/remove.js +3 -2
  46. package/dist/src/commands/mcp/remove.js.map +1 -1
  47. package/dist/src/commands/mcp/remove.test.d.ts +6 -0
  48. package/dist/src/commands/mcp/remove.test.js +175 -0
  49. package/dist/src/commands/mcp/remove.test.js.map +1 -0
  50. package/dist/src/commands/mcp.test.d.ts +6 -0
  51. package/dist/src/commands/mcp.test.js +62 -0
  52. package/dist/src/commands/mcp.test.js.map +1 -0
  53. package/dist/src/config/auth.js +0 -3
  54. package/dist/src/config/auth.js.map +1 -1
  55. package/dist/src/config/config.d.ts +6 -15
  56. package/dist/src/config/config.integration.test.d.ts +6 -0
  57. package/dist/src/config/config.integration.test.js +321 -0
  58. package/dist/src/config/config.integration.test.js.map +1 -0
  59. package/dist/src/config/config.js +85 -164
  60. package/dist/src/config/config.js.map +1 -1
  61. package/dist/src/config/config.test.d.ts +6 -0
  62. package/dist/src/config/config.test.js +1972 -0
  63. package/dist/src/config/config.test.js.map +1 -0
  64. package/dist/src/config/extension-manager.d.ts +63 -0
  65. package/dist/src/config/extension-manager.js +450 -0
  66. package/dist/src/config/extension-manager.js.map +1 -0
  67. package/dist/src/config/extension.d.ts +4 -61
  68. package/dist/src/config/extension.js +1 -538
  69. package/dist/src/config/extension.js.map +1 -1
  70. package/dist/src/config/extension.test.d.ts +6 -0
  71. package/dist/src/config/extension.test.js +1412 -0
  72. package/dist/src/config/extension.test.js.map +1 -0
  73. package/dist/src/config/extensions/consent.d.ts +38 -0
  74. package/dist/src/config/extensions/consent.js +123 -0
  75. package/dist/src/config/extensions/consent.js.map +1 -0
  76. package/dist/src/config/extensions/extensionEnablement.d.ts +2 -2
  77. package/dist/src/config/extensions/extensionEnablement.js +7 -5
  78. package/dist/src/config/extensions/extensionEnablement.js.map +1 -1
  79. package/dist/src/config/extensions/extensionEnablement.test.js +31 -28
  80. package/dist/src/config/extensions/extensionEnablement.test.js.map +1 -1
  81. package/dist/src/config/extensions/extensionSettings.d.ts +15 -0
  82. package/dist/src/config/extensions/extensionSettings.js +113 -0
  83. package/dist/src/config/extensions/extensionSettings.js.map +1 -0
  84. package/dist/src/config/extensions/extensionSettings.test.d.ts +6 -0
  85. package/dist/src/config/extensions/extensionSettings.test.js +254 -0
  86. package/dist/src/config/extensions/extensionSettings.test.js.map +1 -0
  87. package/dist/src/config/extensions/github.d.ts +18 -9
  88. package/dist/src/config/extensions/github.js +108 -36
  89. package/dist/src/config/extensions/github.js.map +1 -1
  90. package/dist/src/config/extensions/github.test.js +158 -164
  91. package/dist/src/config/extensions/github.test.js.map +1 -1
  92. package/dist/src/config/extensions/github_fetch.d.ts +1 -1
  93. package/dist/src/config/extensions/github_fetch.js +13 -1
  94. package/dist/src/config/extensions/github_fetch.js.map +1 -1
  95. package/dist/src/config/extensions/github_fetch.test.d.ts +6 -0
  96. package/dist/src/config/extensions/github_fetch.test.js +169 -0
  97. package/dist/src/config/extensions/github_fetch.test.js.map +1 -0
  98. package/dist/src/config/extensions/storage.d.ts +14 -0
  99. package/dist/src/config/extensions/storage.js +32 -0
  100. package/dist/src/config/extensions/storage.js.map +1 -0
  101. package/dist/src/config/extensions/update.d.ts +5 -4
  102. package/dist/src/config/extensions/update.js +41 -37
  103. package/dist/src/config/extensions/update.js.map +1 -1
  104. package/dist/src/config/extensions/update.test.js +72 -74
  105. package/dist/src/config/extensions/update.test.js.map +1 -1
  106. package/dist/src/config/extensions/variableSchema.d.ts +0 -4
  107. package/dist/src/config/extensions/variableSchema.js.map +1 -1
  108. package/dist/src/config/extensions/variables.d.ts +4 -0
  109. package/dist/src/config/extensions/variables.js +6 -0
  110. package/dist/src/config/extensions/variables.js.map +1 -1
  111. package/dist/src/config/keyBindings.d.ts +5 -1
  112. package/dist/src/config/keyBindings.js +34 -10
  113. package/dist/src/config/keyBindings.js.map +1 -1
  114. package/dist/src/config/keyBindings.test.js +17 -0
  115. package/dist/src/config/keyBindings.test.js.map +1 -1
  116. package/dist/src/config/policies/read-only.toml +56 -0
  117. package/dist/src/config/policies/write.toml +63 -0
  118. package/dist/src/config/policies/yolo.toml +31 -0
  119. package/dist/src/config/policy-engine.integration.test.js +41 -38
  120. package/dist/src/config/policy-engine.integration.test.js.map +1 -1
  121. package/dist/src/config/policy.d.ts +4 -3
  122. package/dist/src/config/policy.js +13 -142
  123. package/dist/src/config/policy.js.map +1 -1
  124. package/dist/src/config/sandboxConfig.d.ts +1 -2
  125. package/dist/src/config/sandboxConfig.js +7 -6
  126. package/dist/src/config/sandboxConfig.js.map +1 -1
  127. package/dist/src/config/settings.d.ts +2 -1
  128. package/dist/src/config/settings.js +59 -15
  129. package/dist/src/config/settings.js.map +1 -1
  130. package/dist/src/config/settings.test.d.ts +6 -0
  131. package/dist/src/config/settings.test.js +2000 -0
  132. package/dist/src/config/settings.test.js.map +1 -0
  133. package/dist/src/config/settingsSchema.d.ts +170 -28
  134. package/dist/src/config/settingsSchema.js +418 -27
  135. package/dist/src/config/settingsSchema.js.map +1 -1
  136. package/dist/src/config/settingsSchema.test.js +42 -1
  137. package/dist/src/config/settingsSchema.test.js.map +1 -1
  138. package/dist/src/config/trustedFolders.d.ts +1 -1
  139. package/dist/src/config/trustedFolders.js +4 -2
  140. package/dist/src/config/trustedFolders.js.map +1 -1
  141. package/dist/src/core/initializer.js +2 -1
  142. package/dist/src/core/initializer.js.map +1 -1
  143. package/dist/src/gemini.d.ts +1 -1
  144. package/dist/src/gemini.js +63 -27
  145. package/dist/src/gemini.js.map +1 -1
  146. package/dist/src/gemini.test.js +123 -34
  147. package/dist/src/gemini.test.js.map +1 -1
  148. package/dist/src/generated/git-commit.d.ts +2 -2
  149. package/dist/src/generated/git-commit.js +2 -2
  150. package/dist/src/nonInteractiveCli.d.ts +9 -1
  151. package/dist/src/nonInteractiveCli.js +205 -10
  152. package/dist/src/nonInteractiveCli.js.map +1 -1
  153. package/dist/src/nonInteractiveCli.test.d.ts +6 -0
  154. package/dist/src/nonInteractiveCli.test.js +984 -0
  155. package/dist/src/nonInteractiveCli.test.js.map +1 -0
  156. package/dist/src/nonInteractiveCliCommands.js +2 -2
  157. package/dist/src/nonInteractiveCliCommands.js.map +1 -1
  158. package/dist/src/services/BuiltinCommandLoader.js +4 -0
  159. package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
  160. package/dist/src/services/BuiltinCommandLoader.test.js +22 -0
  161. package/dist/src/services/BuiltinCommandLoader.test.js.map +1 -1
  162. package/dist/src/services/CommandService.js +2 -1
  163. package/dist/src/services/CommandService.js.map +1 -1
  164. package/dist/src/services/FeedbackService.js +2 -2
  165. package/dist/src/services/FeedbackService.js.map +1 -1
  166. package/dist/src/services/FileCommandLoader.test.d.ts +6 -0
  167. package/dist/src/services/FileCommandLoader.test.js +971 -0
  168. package/dist/src/services/FileCommandLoader.test.js.map +1 -0
  169. package/dist/src/services/McpPromptLoader.js +2 -2
  170. package/dist/src/services/McpPromptLoader.js.map +1 -1
  171. package/dist/src/services/McpPromptLoader.test.js +4 -2
  172. package/dist/src/services/McpPromptLoader.test.js.map +1 -1
  173. package/dist/src/services/prompt-processors/argumentProcessor.test.d.ts +6 -0
  174. package/dist/src/services/prompt-processors/argumentProcessor.test.js +40 -0
  175. package/dist/src/services/prompt-processors/argumentProcessor.test.js.map +1 -0
  176. package/dist/src/services/prompt-processors/atFileProcessor.js +3 -2
  177. package/dist/src/services/prompt-processors/atFileProcessor.js.map +1 -1
  178. package/dist/src/services/prompt-processors/shellProcessor.test.d.ts +6 -0
  179. package/dist/src/services/prompt-processors/shellProcessor.test.js +482 -0
  180. package/dist/src/services/prompt-processors/shellProcessor.test.js.map +1 -0
  181. package/dist/src/test-utils/async.d.ts +9 -0
  182. package/dist/src/test-utils/async.js +29 -0
  183. package/dist/src/test-utils/async.js.map +1 -0
  184. package/dist/src/test-utils/createExtension.d.ts +3 -1
  185. package/dist/src/test-utils/createExtension.js +3 -3
  186. package/dist/src/test-utils/createExtension.js.map +1 -1
  187. package/dist/src/test-utils/render.d.ts +17 -2
  188. package/dist/src/test-utils/render.js +69 -4
  189. package/dist/src/test-utils/render.js.map +1 -1
  190. package/dist/src/test-utils/render.test.d.ts +6 -0
  191. package/dist/src/test-utils/render.test.js +79 -0
  192. package/dist/src/test-utils/render.test.js.map +1 -0
  193. package/dist/src/ui/App.test.d.ts +6 -0
  194. package/dist/src/ui/App.test.js +110 -0
  195. package/dist/src/ui/App.test.js.map +1 -0
  196. package/dist/src/ui/AppContainer.js +223 -92
  197. package/dist/src/ui/AppContainer.js.map +1 -1
  198. package/dist/src/ui/AppContainer.test.js +531 -147
  199. package/dist/src/ui/AppContainer.test.js.map +1 -1
  200. package/dist/src/ui/IdeIntegrationNudge.js +1 -1
  201. package/dist/src/ui/IdeIntegrationNudge.js.map +1 -1
  202. package/dist/src/ui/auth/ApiAuthDialog.d.ts +14 -0
  203. package/dist/src/ui/auth/ApiAuthDialog.js +26 -0
  204. package/dist/src/ui/auth/ApiAuthDialog.js.map +1 -0
  205. package/dist/src/ui/auth/ApiAuthDialog.test.d.ts +6 -0
  206. package/dist/src/ui/auth/ApiAuthDialog.test.js +91 -0
  207. package/dist/src/ui/auth/ApiAuthDialog.test.js.map +1 -0
  208. package/dist/src/ui/auth/AuthDialog.d.ts +1 -1
  209. package/dist/src/ui/auth/AuthDialog.js +9 -3
  210. package/dist/src/ui/auth/AuthDialog.js.map +1 -1
  211. package/dist/src/ui/auth/useAuth.d.ts +3 -1
  212. package/dist/src/ui/auth/useAuth.js +35 -4
  213. package/dist/src/ui/auth/useAuth.js.map +1 -1
  214. package/dist/src/ui/colors.js +3 -0
  215. package/dist/src/ui/colors.js.map +1 -1
  216. package/dist/src/ui/commands/aboutCommand.js +1 -1
  217. package/dist/src/ui/commands/aboutCommand.test.d.ts +6 -0
  218. package/dist/src/ui/commands/aboutCommand.test.js +130 -0
  219. package/dist/src/ui/commands/aboutCommand.test.js.map +1 -0
  220. package/dist/src/ui/commands/authCommand.js +1 -1
  221. package/dist/src/ui/commands/authCommand.test.d.ts +6 -0
  222. package/dist/src/ui/commands/authCommand.test.js +30 -0
  223. package/dist/src/ui/commands/authCommand.test.js.map +1 -0
  224. package/dist/src/ui/commands/bugCommand.js +1 -1
  225. package/dist/src/ui/commands/bugCommand.test.d.ts +6 -0
  226. package/dist/src/ui/commands/bugCommand.test.js +105 -0
  227. package/dist/src/ui/commands/bugCommand.test.js.map +1 -0
  228. package/dist/src/ui/commands/chatCommand.js +1 -1
  229. package/dist/src/ui/commands/chatCommand.js.map +1 -1
  230. package/dist/src/ui/commands/chatCommand.test.d.ts +6 -0
  231. package/dist/src/ui/commands/chatCommand.test.js +555 -0
  232. package/dist/src/ui/commands/chatCommand.test.js.map +1 -0
  233. package/dist/src/ui/commands/clearCommand.js +1 -1
  234. package/dist/src/ui/commands/clearCommand.test.d.ts +6 -0
  235. package/dist/src/ui/commands/clearCommand.test.js +76 -0
  236. package/dist/src/ui/commands/clearCommand.test.js.map +1 -0
  237. package/dist/src/ui/commands/compressCommand.js +1 -1
  238. package/dist/src/ui/commands/compressCommand.js.map +1 -1
  239. package/dist/src/ui/commands/compressCommand.test.d.ts +6 -0
  240. package/dist/src/ui/commands/compressCommand.test.js +98 -0
  241. package/dist/src/ui/commands/compressCommand.test.js.map +1 -0
  242. package/dist/src/ui/commands/copyCommand.js +2 -1
  243. package/dist/src/ui/commands/copyCommand.js.map +1 -1
  244. package/dist/src/ui/commands/copyCommand.test.d.ts +6 -0
  245. package/dist/src/ui/commands/copyCommand.test.js +242 -0
  246. package/dist/src/ui/commands/copyCommand.test.js.map +1 -0
  247. package/dist/src/ui/commands/corgiCommand.js +1 -1
  248. package/dist/src/ui/commands/corgiCommand.js.map +1 -1
  249. package/dist/src/ui/commands/corgiCommand.test.d.ts +6 -0
  250. package/dist/src/ui/commands/corgiCommand.test.js +28 -0
  251. package/dist/src/ui/commands/corgiCommand.test.js.map +1 -0
  252. package/dist/src/ui/commands/directoryCommand.js +1 -1
  253. package/dist/src/ui/commands/directoryCommand.js.map +1 -1
  254. package/dist/src/ui/commands/directoryCommand.test.d.ts +6 -0
  255. package/dist/src/ui/commands/directoryCommand.test.js +144 -0
  256. package/dist/src/ui/commands/directoryCommand.test.js.map +1 -0
  257. package/dist/src/ui/commands/docsCommand.js +1 -1
  258. package/dist/src/ui/commands/docsCommand.test.d.ts +6 -0
  259. package/dist/src/ui/commands/docsCommand.test.js +72 -0
  260. package/dist/src/ui/commands/docsCommand.test.js.map +1 -0
  261. package/dist/src/ui/commands/editorCommand.js +1 -1
  262. package/dist/src/ui/commands/editorCommand.test.d.ts +6 -0
  263. package/dist/src/ui/commands/editorCommand.test.js +27 -0
  264. package/dist/src/ui/commands/editorCommand.test.js.map +1 -0
  265. package/dist/src/ui/commands/extensionsCommand.js +64 -11
  266. package/dist/src/ui/commands/extensionsCommand.js.map +1 -1
  267. package/dist/src/ui/commands/extensionsCommand.test.d.ts +6 -0
  268. package/dist/src/ui/commands/extensionsCommand.test.js +315 -0
  269. package/dist/src/ui/commands/extensionsCommand.test.js.map +1 -0
  270. package/dist/src/ui/commands/helpCommand.js +1 -1
  271. package/dist/src/ui/commands/helpCommand.test.d.ts +6 -0
  272. package/dist/src/ui/commands/helpCommand.test.js +42 -0
  273. package/dist/src/ui/commands/helpCommand.test.js.map +1 -0
  274. package/dist/src/ui/commands/ideCommand.js +6 -6
  275. package/dist/src/ui/commands/ideCommand.test.d.ts +6 -0
  276. package/dist/src/ui/commands/ideCommand.test.js +205 -0
  277. package/dist/src/ui/commands/ideCommand.test.js.map +1 -0
  278. package/dist/src/ui/commands/initCommand.js +1 -1
  279. package/dist/src/ui/commands/initCommand.js.map +1 -1
  280. package/dist/src/ui/commands/initCommand.test.d.ts +6 -0
  281. package/dist/src/ui/commands/initCommand.test.js +80 -0
  282. package/dist/src/ui/commands/initCommand.test.js.map +1 -0
  283. package/dist/src/ui/commands/mcpCommand.js +110 -100
  284. package/dist/src/ui/commands/mcpCommand.js.map +1 -1
  285. package/dist/src/ui/commands/mcpCommand.test.d.ts +6 -0
  286. package/dist/src/ui/commands/mcpCommand.test.js +152 -0
  287. package/dist/src/ui/commands/mcpCommand.test.js.map +1 -0
  288. package/dist/src/ui/commands/memoryCommand.js +6 -6
  289. package/dist/src/ui/commands/memoryCommand.js.map +1 -1
  290. package/dist/src/ui/commands/memoryCommand.test.d.ts +6 -0
  291. package/dist/src/ui/commands/memoryCommand.test.js +268 -0
  292. package/dist/src/ui/commands/memoryCommand.test.js.map +1 -0
  293. package/dist/src/ui/commands/policiesCommand.d.ts +7 -0
  294. package/dist/src/ui/commands/policiesCommand.js +59 -0
  295. package/dist/src/ui/commands/policiesCommand.js.map +1 -0
  296. package/dist/src/ui/commands/policiesCommand.test.d.ts +6 -0
  297. package/dist/src/ui/commands/policiesCommand.test.js +83 -0
  298. package/dist/src/ui/commands/policiesCommand.test.js.map +1 -0
  299. package/dist/src/ui/commands/privacyCommand.js +1 -1
  300. package/dist/src/ui/commands/privacyCommand.test.d.ts +6 -0
  301. package/dist/src/ui/commands/privacyCommand.test.js +32 -0
  302. package/dist/src/ui/commands/privacyCommand.test.js.map +1 -0
  303. package/dist/src/ui/commands/quitCommand.js +1 -1
  304. package/dist/src/ui/commands/quitCommand.test.d.ts +6 -0
  305. package/dist/src/ui/commands/quitCommand.test.js +50 -0
  306. package/dist/src/ui/commands/quitCommand.test.js.map +1 -0
  307. package/dist/src/ui/commands/restoreCommand.test.d.ts +6 -0
  308. package/dist/src/ui/commands/restoreCommand.test.js +190 -0
  309. package/dist/src/ui/commands/restoreCommand.test.js.map +1 -0
  310. package/dist/src/ui/commands/settingsCommand.test.d.ts +6 -0
  311. package/dist/src/ui/commands/settingsCommand.test.js +30 -0
  312. package/dist/src/ui/commands/settingsCommand.test.js.map +1 -0
  313. package/dist/src/ui/commands/setupGithubCommand.js +4 -3
  314. package/dist/src/ui/commands/setupGithubCommand.js.map +1 -1
  315. package/dist/src/ui/commands/setupGithubCommand.test.js +1 -2
  316. package/dist/src/ui/commands/setupGithubCommand.test.js.map +1 -1
  317. package/dist/src/ui/commands/statsCommand.js +3 -3
  318. package/dist/src/ui/commands/statsCommand.js.map +1 -1
  319. package/dist/src/ui/commands/statsCommand.test.d.ts +6 -0
  320. package/dist/src/ui/commands/statsCommand.test.js +53 -0
  321. package/dist/src/ui/commands/statsCommand.test.js.map +1 -0
  322. package/dist/src/ui/commands/terminalSetupCommand.test.d.ts +6 -0
  323. package/dist/src/ui/commands/terminalSetupCommand.test.js +66 -0
  324. package/dist/src/ui/commands/terminalSetupCommand.test.js.map +1 -0
  325. package/dist/src/ui/commands/themeCommand.js +1 -1
  326. package/dist/src/ui/commands/themeCommand.test.d.ts +6 -0
  327. package/dist/src/ui/commands/themeCommand.test.js +32 -0
  328. package/dist/src/ui/commands/themeCommand.test.js.map +1 -0
  329. package/dist/src/ui/commands/toolsCommand.js +1 -1
  330. package/dist/src/ui/commands/toolsCommand.test.d.ts +6 -0
  331. package/dist/src/ui/commands/toolsCommand.test.js +100 -0
  332. package/dist/src/ui/commands/toolsCommand.test.js.map +1 -0
  333. package/dist/src/ui/commands/types.d.ts +1 -0
  334. package/dist/src/ui/commands/vimCommand.js +1 -1
  335. package/dist/src/ui/components/AnsiOutput.test.js +1 -1
  336. package/dist/src/ui/components/AnsiOutput.test.js.map +1 -1
  337. package/dist/src/ui/components/AsciiArt.d.ts +3 -3
  338. package/dist/src/ui/components/AsciiArt.js +3 -3
  339. package/dist/src/ui/components/Composer.js +6 -4
  340. package/dist/src/ui/components/Composer.js.map +1 -1
  341. package/dist/src/ui/components/Composer.test.js +21 -3
  342. package/dist/src/ui/components/Composer.test.js.map +1 -1
  343. package/dist/src/ui/components/ConfigInitDisplay.js +4 -6
  344. package/dist/src/ui/components/ConfigInitDisplay.js.map +1 -1
  345. package/dist/src/ui/components/ConsentPrompt.test.js +18 -8
  346. package/dist/src/ui/components/ConsentPrompt.test.js.map +1 -1
  347. package/dist/src/ui/components/ConsoleSummaryDisplay.js +1 -1
  348. package/dist/src/ui/components/ConsoleSummaryDisplay.js.map +1 -1
  349. package/dist/src/ui/components/ContextSummaryDisplay.d.ts +0 -1
  350. package/dist/src/ui/components/ContextSummaryDisplay.js +2 -12
  351. package/dist/src/ui/components/ContextSummaryDisplay.js.map +1 -1
  352. package/dist/src/ui/components/ContextSummaryDisplay.test.d.ts +6 -0
  353. package/dist/src/ui/components/ContextSummaryDisplay.test.js +71 -0
  354. package/dist/src/ui/components/ContextSummaryDisplay.test.js.map +1 -0
  355. package/dist/src/ui/components/DetailedMessagesDisplay.js +1 -1
  356. package/dist/src/ui/components/DetailedMessagesDisplay.js.map +1 -1
  357. package/dist/src/ui/components/DialogManager.js +5 -5
  358. package/dist/src/ui/components/DialogManager.js.map +1 -1
  359. package/dist/src/ui/components/EditorSettingsDialog.js +1 -1
  360. package/dist/src/ui/components/EditorSettingsDialog.js.map +1 -1
  361. package/dist/src/ui/components/FolderTrustDialog.test.js +8 -3
  362. package/dist/src/ui/components/FolderTrustDialog.test.js.map +1 -1
  363. package/dist/src/ui/components/Footer.js +4 -3
  364. package/dist/src/ui/components/Footer.js.map +1 -1
  365. package/dist/src/ui/components/Footer.test.d.ts +6 -0
  366. package/dist/src/ui/components/Footer.test.js +314 -0
  367. package/dist/src/ui/components/Footer.test.js.map +1 -0
  368. package/dist/src/ui/components/Header.test.js +13 -5
  369. package/dist/src/ui/components/Header.test.js.map +1 -1
  370. package/dist/src/ui/components/Help.test.js +5 -4
  371. package/dist/src/ui/components/Help.test.js.map +1 -1
  372. package/dist/src/ui/components/HistoryItemDisplay.js +1 -1
  373. package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -1
  374. package/dist/src/ui/components/InputPrompt.d.ts +4 -0
  375. package/dist/src/ui/components/InputPrompt.js +80 -12
  376. package/dist/src/ui/components/InputPrompt.js.map +1 -1
  377. package/dist/src/ui/components/InputPrompt.test.d.ts +6 -0
  378. package/dist/src/ui/components/InputPrompt.test.js +1786 -0
  379. package/dist/src/ui/components/InputPrompt.test.js.map +1 -0
  380. package/dist/src/ui/components/LoadingIndicator.js +2 -2
  381. package/dist/src/ui/components/LoadingIndicator.js.map +1 -1
  382. package/dist/src/ui/components/LoadingIndicator.test.js +28 -15
  383. package/dist/src/ui/components/LoadingIndicator.test.js.map +1 -1
  384. package/dist/src/ui/components/LoopDetectionConfirmation.js +1 -1
  385. package/dist/src/ui/components/LoopDetectionConfirmation.js.map +1 -1
  386. package/dist/src/ui/components/LoopDetectionConfirmation.test.js +2 -2
  387. package/dist/src/ui/components/LoopDetectionConfirmation.test.js.map +1 -1
  388. package/dist/src/ui/components/MainContent.js +15 -4
  389. package/dist/src/ui/components/MainContent.js.map +1 -1
  390. package/dist/src/ui/components/ModelDialog.js +1 -1
  391. package/dist/src/ui/components/ModelDialog.js.map +1 -1
  392. package/dist/src/ui/components/ModelDialog.test.js +23 -13
  393. package/dist/src/ui/components/ModelDialog.test.js.map +1 -1
  394. package/dist/src/ui/components/ModelStatsDisplay.test.d.ts +6 -0
  395. package/dist/src/ui/components/ModelStatsDisplay.test.js +285 -0
  396. package/dist/src/ui/components/ModelStatsDisplay.test.js.map +1 -0
  397. package/dist/src/ui/components/Notifications.js +38 -5
  398. package/dist/src/ui/components/Notifications.js.map +1 -1
  399. package/dist/src/ui/components/PermissionsModifyTrustDialog.js +22 -18
  400. package/dist/src/ui/components/PermissionsModifyTrustDialog.js.map +1 -1
  401. package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js +12 -4
  402. package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js.map +1 -1
  403. package/dist/src/ui/components/PrepareLabel.test.js +14 -8
  404. package/dist/src/ui/components/PrepareLabel.test.js.map +1 -1
  405. package/dist/src/ui/components/ProQuotaDialog.test.js +14 -6
  406. package/dist/src/ui/components/ProQuotaDialog.test.js.map +1 -1
  407. package/dist/src/ui/components/QueuedMessageDisplay.js +3 -3
  408. package/dist/src/ui/components/QueuedMessageDisplay.js.map +1 -1
  409. package/dist/src/ui/components/QueuedMessageDisplay.test.js +15 -6
  410. package/dist/src/ui/components/QueuedMessageDisplay.test.js.map +1 -1
  411. package/dist/src/ui/components/RawMarkdownIndicator.d.ts +7 -0
  412. package/dist/src/ui/components/RawMarkdownIndicator.js +8 -0
  413. package/dist/src/ui/components/RawMarkdownIndicator.js.map +1 -0
  414. package/dist/src/ui/components/SessionSummaryDisplay.test.d.ts +6 -0
  415. package/dist/src/ui/components/SessionSummaryDisplay.test.js +74 -0
  416. package/dist/src/ui/components/SessionSummaryDisplay.test.js.map +1 -0
  417. package/dist/src/ui/components/SettingsDialog.js +43 -35
  418. package/dist/src/ui/components/SettingsDialog.js.map +1 -1
  419. package/dist/src/ui/components/SettingsDialog.test.js +554 -545
  420. package/dist/src/ui/components/SettingsDialog.test.js.map +1 -1
  421. package/dist/src/ui/components/ShellConfirmationDialog.js +1 -1
  422. package/dist/src/ui/components/ShellConfirmationDialog.js.map +1 -1
  423. package/dist/src/ui/components/ShellConfirmationDialog.test.js +2 -2
  424. package/dist/src/ui/components/ShellConfirmationDialog.test.js.map +1 -1
  425. package/dist/src/ui/components/StatsDisplay.test.d.ts +6 -0
  426. package/dist/src/ui/components/StatsDisplay.test.js +351 -0
  427. package/dist/src/ui/components/StatsDisplay.test.js.map +1 -0
  428. package/dist/src/ui/components/SuggestionsDisplay.js +1 -1
  429. package/dist/src/ui/components/SuggestionsDisplay.js.map +1 -1
  430. package/dist/src/ui/components/ThemeDialog.d.ts +4 -2
  431. package/dist/src/ui/components/ThemeDialog.js +3 -3
  432. package/dist/src/ui/components/ThemeDialog.js.map +1 -1
  433. package/dist/src/ui/components/ThemeDialog.test.js +14 -1
  434. package/dist/src/ui/components/ThemeDialog.test.js.map +1 -1
  435. package/dist/src/ui/components/ToolStatsDisplay.test.d.ts +6 -0
  436. package/dist/src/ui/components/ToolStatsDisplay.test.js +227 -0
  437. package/dist/src/ui/components/ToolStatsDisplay.test.js.map +1 -0
  438. package/dist/src/ui/components/messages/CompressionMessage.test.js +25 -17
  439. package/dist/src/ui/components/messages/CompressionMessage.test.js.map +1 -1
  440. package/dist/src/ui/components/messages/DiffRenderer.test.js +1 -1
  441. package/dist/src/ui/components/messages/DiffRenderer.test.js.map +1 -1
  442. package/dist/src/ui/components/messages/GeminiMessage.js +3 -1
  443. package/dist/src/ui/components/messages/GeminiMessage.js.map +1 -1
  444. package/dist/src/ui/components/messages/GeminiMessage.test.d.ts +6 -0
  445. package/dist/src/ui/components/messages/GeminiMessage.test.js +35 -0
  446. package/dist/src/ui/components/messages/GeminiMessage.test.js.map +1 -0
  447. package/dist/src/ui/components/messages/GeminiMessageContent.js +3 -1
  448. package/dist/src/ui/components/messages/GeminiMessageContent.js.map +1 -1
  449. package/dist/src/ui/components/messages/InfoMessage.js +1 -1
  450. package/dist/src/ui/components/messages/InfoMessage.js.map +1 -1
  451. package/dist/src/ui/components/messages/Todo.d.ts +7 -0
  452. package/dist/src/ui/components/messages/Todo.js +91 -0
  453. package/dist/src/ui/components/messages/Todo.js.map +1 -0
  454. package/dist/src/ui/components/messages/Todo.test.d.ts +6 -0
  455. package/dist/src/ui/components/messages/Todo.test.js +114 -0
  456. package/dist/src/ui/components/messages/Todo.test.js.map +1 -0
  457. package/dist/src/ui/components/messages/ToolConfirmationMessage.js +1 -1
  458. package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
  459. package/dist/src/ui/components/messages/ToolGroupMessage.js +1 -1
  460. package/dist/src/ui/components/messages/ToolGroupMessage.js.map +1 -1
  461. package/dist/src/ui/components/messages/ToolGroupMessage.test.js +29 -15
  462. package/dist/src/ui/components/messages/ToolGroupMessage.test.js.map +1 -1
  463. package/dist/src/ui/components/messages/ToolMessage.js +8 -3
  464. package/dist/src/ui/components/messages/ToolMessage.js.map +1 -1
  465. package/dist/src/ui/components/messages/ToolMessage.test.js +2 -2
  466. package/dist/src/ui/components/messages/ToolMessage.test.js.map +1 -1
  467. package/dist/src/ui/components/messages/ToolMessageRawMarkdown.test.d.ts +6 -0
  468. package/dist/src/ui/components/messages/ToolMessageRawMarkdown.test.js +30 -0
  469. package/dist/src/ui/components/messages/ToolMessageRawMarkdown.test.js.map +1 -0
  470. package/dist/src/ui/components/messages/UserShellMessage.js +1 -1
  471. package/dist/src/ui/components/messages/UserShellMessage.js.map +1 -1
  472. package/dist/src/ui/components/messages/WarningMessage.js +2 -2
  473. package/dist/src/ui/components/messages/WarningMessage.js.map +1 -1
  474. package/dist/src/ui/components/shared/BaseSelectionList.test.js +34 -25
  475. package/dist/src/ui/components/shared/BaseSelectionList.test.js.map +1 -1
  476. package/dist/src/ui/components/shared/MaxSizedBox.test.js +43 -22
  477. package/dist/src/ui/components/shared/MaxSizedBox.test.js.map +1 -1
  478. package/dist/src/ui/components/shared/TextInput.d.ts +15 -0
  479. package/dist/src/ui/components/shared/TextInput.js +38 -0
  480. package/dist/src/ui/components/shared/TextInput.js.map +1 -0
  481. package/dist/src/ui/components/shared/TextInput.test.d.ts +6 -0
  482. package/dist/src/ui/components/shared/TextInput.test.js +242 -0
  483. package/dist/src/ui/components/shared/TextInput.test.js.map +1 -0
  484. package/dist/src/ui/components/shared/text-buffer.d.ts +9 -2
  485. package/dist/src/ui/components/shared/text-buffer.js +52 -14
  486. package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
  487. package/dist/src/ui/components/shared/text-buffer.test.d.ts +6 -0
  488. package/dist/src/ui/components/shared/text-buffer.test.js +1761 -0
  489. package/dist/src/ui/components/shared/text-buffer.test.js.map +1 -0
  490. package/dist/src/ui/components/shared/vim-buffer-actions.test.d.ts +6 -0
  491. package/dist/src/ui/components/shared/vim-buffer-actions.test.js +951 -0
  492. package/dist/src/ui/components/shared/vim-buffer-actions.test.js.map +1 -0
  493. package/dist/src/ui/components/views/ChatList.test.js +7 -4
  494. package/dist/src/ui/components/views/ChatList.test.js.map +1 -1
  495. package/dist/src/ui/components/views/ExtensionsList.d.ts +7 -1
  496. package/dist/src/ui/components/views/ExtensionsList.js +12 -15
  497. package/dist/src/ui/components/views/ExtensionsList.js.map +1 -1
  498. package/dist/src/ui/components/views/ExtensionsList.test.js +43 -29
  499. package/dist/src/ui/components/views/ExtensionsList.test.js.map +1 -1
  500. package/dist/src/ui/components/views/McpStatus.d.ts +0 -1
  501. package/dist/src/ui/components/views/McpStatus.js +4 -4
  502. package/dist/src/ui/components/views/McpStatus.js.map +1 -1
  503. package/dist/src/ui/components/views/McpStatus.test.js +23 -17
  504. package/dist/src/ui/components/views/McpStatus.test.js.map +1 -1
  505. package/dist/src/ui/components/views/ToolsList.test.js +4 -4
  506. package/dist/src/ui/components/views/ToolsList.test.js.map +1 -1
  507. package/dist/src/ui/contexts/KeypressContext.d.ts +4 -2
  508. package/dist/src/ui/contexts/KeypressContext.js +635 -439
  509. package/dist/src/ui/contexts/KeypressContext.js.map +1 -1
  510. package/dist/src/ui/contexts/KeypressContext.test.js +634 -515
  511. package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
  512. package/dist/src/ui/contexts/MouseContext.d.ts +21 -0
  513. package/dist/src/ui/contexts/MouseContext.js +89 -0
  514. package/dist/src/ui/contexts/MouseContext.js.map +1 -0
  515. package/dist/src/ui/contexts/MouseContext.test.d.ts +6 -0
  516. package/dist/src/ui/contexts/MouseContext.test.js +164 -0
  517. package/dist/src/ui/contexts/MouseContext.test.js.map +1 -0
  518. package/dist/src/ui/contexts/SessionContext.test.d.ts +6 -0
  519. package/dist/src/ui/contexts/SessionContext.test.js +195 -0
  520. package/dist/src/ui/contexts/SessionContext.test.js.map +1 -0
  521. package/dist/src/ui/contexts/UIActionsContext.d.ts +7 -4
  522. package/dist/src/ui/contexts/UIStateContext.d.ts +5 -3
  523. package/dist/src/ui/contexts/UIStateContext.js.map +1 -1
  524. package/dist/src/ui/hooks/atCommandProcessor.js +33 -11
  525. package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
  526. package/dist/src/ui/hooks/atCommandProcessor.test.js +163 -64
  527. package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -1
  528. package/dist/src/ui/hooks/shellCommandProcessor.js +0 -1
  529. package/dist/src/ui/hooks/shellCommandProcessor.js.map +1 -1
  530. package/dist/src/ui/hooks/shellCommandProcessor.test.js +64 -35
  531. package/dist/src/ui/hooks/shellCommandProcessor.test.js.map +1 -1
  532. package/dist/src/ui/hooks/slashCommandProcessor.js +2 -0
  533. package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
  534. package/dist/src/ui/hooks/slashCommandProcessor.test.d.ts +6 -0
  535. package/dist/src/ui/hooks/slashCommandProcessor.test.js +807 -0
  536. package/dist/src/ui/hooks/slashCommandProcessor.test.js.map +1 -0
  537. package/dist/src/ui/hooks/useAtCompletion.js +2 -2
  538. package/dist/src/ui/hooks/useAtCompletion.js.map +1 -1
  539. package/dist/src/ui/hooks/useAtCompletion.test.d.ts +6 -0
  540. package/dist/src/ui/hooks/useAtCompletion.test.js +396 -0
  541. package/dist/src/ui/hooks/useAtCompletion.test.js.map +1 -0
  542. package/dist/src/ui/hooks/useAutoAcceptIndicator.js +10 -0
  543. package/dist/src/ui/hooks/useAutoAcceptIndicator.js.map +1 -1
  544. package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js +32 -2
  545. package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js.map +1 -1
  546. package/dist/src/ui/hooks/useCommandCompletion.d.ts +1 -1
  547. package/dist/src/ui/hooks/useCommandCompletion.js +5 -3
  548. package/dist/src/ui/hooks/useCommandCompletion.js.map +1 -1
  549. package/dist/src/ui/hooks/useCommandCompletion.test.d.ts +6 -0
  550. package/dist/src/ui/hooks/useCommandCompletion.test.js +377 -0
  551. package/dist/src/ui/hooks/useCommandCompletion.test.js.map +1 -0
  552. package/dist/src/ui/hooks/useConsoleMessages.test.d.ts +6 -0
  553. package/dist/src/ui/hooks/useConsoleMessages.test.js +127 -0
  554. package/dist/src/ui/hooks/useConsoleMessages.test.js.map +1 -0
  555. package/dist/src/ui/hooks/useEditorSettings.test.js +40 -34
  556. package/dist/src/ui/hooks/useEditorSettings.test.js.map +1 -1
  557. package/dist/src/ui/hooks/useExtensionUpdates.d.ts +14 -4
  558. package/dist/src/ui/hooks/useExtensionUpdates.js +18 -11
  559. package/dist/src/ui/hooks/useExtensionUpdates.js.map +1 -1
  560. package/dist/src/ui/hooks/useExtensionUpdates.test.js +52 -35
  561. package/dist/src/ui/hooks/useExtensionUpdates.test.js.map +1 -1
  562. package/dist/src/ui/hooks/useFlickerDetector.test.js +9 -5
  563. package/dist/src/ui/hooks/useFlickerDetector.test.js.map +1 -1
  564. package/dist/src/ui/hooks/useFocus.test.d.ts +6 -0
  565. package/dist/src/ui/hooks/useFocus.test.js +131 -0
  566. package/dist/src/ui/hooks/useFocus.test.js.map +1 -0
  567. package/dist/src/ui/hooks/useFolderTrust.test.d.ts +6 -0
  568. package/dist/src/ui/hooks/useFolderTrust.test.js +188 -0
  569. package/dist/src/ui/hooks/useFolderTrust.test.js.map +1 -0
  570. package/dist/src/ui/hooks/useGeminiStream.js +119 -74
  571. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  572. package/dist/src/ui/hooks/useGeminiStream.test.d.ts +6 -0
  573. package/dist/src/ui/hooks/useGeminiStream.test.js +1820 -0
  574. package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -0
  575. package/dist/src/ui/hooks/useGitBranchName.js +4 -0
  576. package/dist/src/ui/hooks/useGitBranchName.js.map +1 -1
  577. package/dist/src/ui/hooks/useGitBranchName.test.js +46 -34
  578. package/dist/src/ui/hooks/useGitBranchName.test.js.map +1 -1
  579. package/dist/src/ui/hooks/useHistoryManager.test.js +2 -1
  580. package/dist/src/ui/hooks/useHistoryManager.test.js.map +1 -1
  581. package/dist/src/ui/hooks/useIdeTrustListener.test.js +40 -9
  582. package/dist/src/ui/hooks/useIdeTrustListener.test.js.map +1 -1
  583. package/dist/src/ui/hooks/useInputHistory.test.js +2 -1
  584. package/dist/src/ui/hooks/useInputHistory.test.js.map +1 -1
  585. package/dist/src/ui/hooks/useInputHistoryStore.js +2 -1
  586. package/dist/src/ui/hooks/useInputHistoryStore.js.map +1 -1
  587. package/dist/src/ui/hooks/useInputHistoryStore.test.js +2 -1
  588. package/dist/src/ui/hooks/useInputHistoryStore.test.js.map +1 -1
  589. package/dist/src/ui/hooks/useKeypress.test.d.ts +6 -0
  590. package/dist/src/ui/hooks/useKeypress.test.js +223 -0
  591. package/dist/src/ui/hooks/useKeypress.test.js.map +1 -0
  592. package/dist/src/ui/hooks/useLoadingIndicator.test.js +29 -6
  593. package/dist/src/ui/hooks/useLoadingIndicator.test.js.map +1 -1
  594. package/dist/src/ui/hooks/useMemoryMonitor.test.js +10 -5
  595. package/dist/src/ui/hooks/useMemoryMonitor.test.js.map +1 -1
  596. package/dist/src/ui/hooks/useMessageQueue.d.ts +1 -0
  597. package/dist/src/ui/hooks/useMessageQueue.js +14 -0
  598. package/dist/src/ui/hooks/useMessageQueue.js.map +1 -1
  599. package/dist/src/ui/hooks/useMessageQueue.test.js +173 -35
  600. package/dist/src/ui/hooks/useMessageQueue.test.js.map +1 -1
  601. package/dist/src/ui/hooks/useModelCommand.test.js +21 -11
  602. package/dist/src/ui/hooks/useModelCommand.test.js.map +1 -1
  603. package/dist/src/ui/hooks/useMouse.d.ts +17 -0
  604. package/dist/src/ui/hooks/useMouse.js +27 -0
  605. package/dist/src/ui/hooks/useMouse.js.map +1 -0
  606. package/dist/src/ui/hooks/useMouse.test.d.ts +6 -0
  607. package/dist/src/ui/hooks/useMouse.test.js +57 -0
  608. package/dist/src/ui/hooks/useMouse.test.js.map +1 -0
  609. package/dist/src/ui/hooks/usePermissionsModifyTrust.test.js +2 -2
  610. package/dist/src/ui/hooks/usePermissionsModifyTrust.test.js.map +1 -1
  611. package/dist/src/ui/hooks/usePhraseCycler.d.ts +1 -0
  612. package/dist/src/ui/hooks/usePhraseCycler.js +156 -5
  613. package/dist/src/ui/hooks/usePhraseCycler.js.map +1 -1
  614. package/dist/src/ui/hooks/usePhraseCycler.test.d.ts +6 -0
  615. package/dist/src/ui/hooks/usePhraseCycler.test.js +158 -0
  616. package/dist/src/ui/hooks/usePhraseCycler.test.js.map +1 -0
  617. package/dist/src/ui/hooks/usePrivacySettings.test.js +26 -6
  618. package/dist/src/ui/hooks/usePrivacySettings.test.js.map +1 -1
  619. package/dist/src/ui/hooks/usePromptCompletion.js +2 -2
  620. package/dist/src/ui/hooks/usePromptCompletion.js.map +1 -1
  621. package/dist/src/ui/hooks/useQuotaAndFallback.js +13 -14
  622. package/dist/src/ui/hooks/useQuotaAndFallback.js.map +1 -1
  623. package/dist/src/ui/hooks/useQuotaAndFallback.test.js +55 -48
  624. package/dist/src/ui/hooks/useQuotaAndFallback.test.js.map +1 -1
  625. package/dist/src/ui/hooks/useReactToolScheduler.d.ts +8 -1
  626. package/dist/src/ui/hooks/useReactToolScheduler.js +61 -36
  627. package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -1
  628. package/dist/src/ui/hooks/useReactToolScheduler.test.d.ts +6 -0
  629. package/dist/src/ui/hooks/useReactToolScheduler.test.js +65 -0
  630. package/dist/src/ui/hooks/useReactToolScheduler.test.js.map +1 -0
  631. package/dist/src/ui/hooks/useReverseSearchCompletion.test.js +2 -2
  632. package/dist/src/ui/hooks/useReverseSearchCompletion.test.js.map +1 -1
  633. package/dist/src/ui/hooks/useSelectionList.js +5 -4
  634. package/dist/src/ui/hooks/useSelectionList.js.map +1 -1
  635. package/dist/src/ui/hooks/useSelectionList.test.js +272 -183
  636. package/dist/src/ui/hooks/useSelectionList.test.js.map +1 -1
  637. package/dist/src/ui/hooks/useShellHistory.test.js +52 -20
  638. package/dist/src/ui/hooks/useShellHistory.test.js.map +1 -1
  639. package/dist/src/ui/hooks/useShowMemoryCommand.d.ts +1 -1
  640. package/dist/src/ui/hooks/useShowMemoryCommand.js +4 -3
  641. package/dist/src/ui/hooks/useShowMemoryCommand.js.map +1 -1
  642. package/dist/src/ui/hooks/useSlashCompletion.js +20 -8
  643. package/dist/src/ui/hooks/useSlashCompletion.js.map +1 -1
  644. package/dist/src/ui/hooks/useSlashCompletion.test.js +275 -137
  645. package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
  646. package/dist/src/ui/hooks/useThemeCommand.d.ts +2 -1
  647. package/dist/src/ui/hooks/useThemeCommand.js +6 -0
  648. package/dist/src/ui/hooks/useThemeCommand.js.map +1 -1
  649. package/dist/src/ui/hooks/useTimer.test.js +43 -14
  650. package/dist/src/ui/hooks/useTimer.test.js.map +1 -1
  651. package/dist/src/ui/hooks/useToolScheduler.test.js +229 -242
  652. package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
  653. package/dist/src/ui/hooks/vim.js +2 -1
  654. package/dist/src/ui/hooks/vim.js.map +1 -1
  655. package/dist/src/ui/hooks/vim.test.d.ts +6 -0
  656. package/dist/src/ui/hooks/vim.test.js +1269 -0
  657. package/dist/src/ui/hooks/vim.test.js.map +1 -0
  658. package/dist/src/ui/keyMatchers.test.js +39 -6
  659. package/dist/src/ui/keyMatchers.test.js.map +1 -1
  660. package/dist/src/ui/state/extensions.d.ts +1 -0
  661. package/dist/src/ui/state/extensions.js +1 -0
  662. package/dist/src/ui/state/extensions.js.map +1 -1
  663. package/dist/src/ui/themes/ansi-light.js +1 -0
  664. package/dist/src/ui/themes/ansi-light.js.map +1 -1
  665. package/dist/src/ui/themes/ansi.js +1 -0
  666. package/dist/src/ui/themes/ansi.js.map +1 -1
  667. package/dist/src/ui/themes/atom-one-dark.js +2 -0
  668. package/dist/src/ui/themes/atom-one-dark.js.map +1 -1
  669. package/dist/src/ui/themes/ayu-light.js +2 -0
  670. package/dist/src/ui/themes/ayu-light.js.map +1 -1
  671. package/dist/src/ui/themes/ayu.js +2 -0
  672. package/dist/src/ui/themes/ayu.js.map +1 -1
  673. package/dist/src/ui/themes/color-utils.d.ts +1 -0
  674. package/dist/src/ui/themes/color-utils.js +8 -1
  675. package/dist/src/ui/themes/color-utils.js.map +1 -1
  676. package/dist/src/ui/themes/color-utils.test.js +13 -1
  677. package/dist/src/ui/themes/color-utils.test.js.map +1 -1
  678. package/dist/src/ui/themes/dracula.js +2 -0
  679. package/dist/src/ui/themes/dracula.js.map +1 -1
  680. package/dist/src/ui/themes/github-dark.js +2 -0
  681. package/dist/src/ui/themes/github-dark.js.map +1 -1
  682. package/dist/src/ui/themes/github-light.js +2 -0
  683. package/dist/src/ui/themes/github-light.js.map +1 -1
  684. package/dist/src/ui/themes/googlecode.js +2 -0
  685. package/dist/src/ui/themes/googlecode.js.map +1 -1
  686. package/dist/src/ui/themes/no-color.js +3 -0
  687. package/dist/src/ui/themes/no-color.js.map +1 -1
  688. package/dist/src/ui/themes/semantic-tokens.d.ts +2 -0
  689. package/dist/src/ui/themes/semantic-tokens.js +6 -0
  690. package/dist/src/ui/themes/semantic-tokens.js.map +1 -1
  691. package/dist/src/ui/themes/shades-of-purple.js +2 -0
  692. package/dist/src/ui/themes/shades-of-purple.js.map +1 -1
  693. package/dist/src/ui/themes/theme-manager.js +8 -7
  694. package/dist/src/ui/themes/theme-manager.js.map +1 -1
  695. package/dist/src/ui/themes/theme.d.ts +3 -0
  696. package/dist/src/ui/themes/theme.js +14 -3
  697. package/dist/src/ui/themes/theme.js.map +1 -1
  698. package/dist/src/ui/themes/theme.test.d.ts +6 -0
  699. package/dist/src/ui/themes/theme.test.js +151 -0
  700. package/dist/src/ui/themes/theme.test.js.map +1 -0
  701. package/dist/src/ui/themes/xcode.js +2 -0
  702. package/dist/src/ui/themes/xcode.js.map +1 -1
  703. package/dist/src/ui/types.d.ts +3 -2
  704. package/dist/src/ui/types.js +2 -0
  705. package/dist/src/ui/types.js.map +1 -1
  706. package/dist/src/ui/utils/CodeColorizer.d.ts +1 -1
  707. package/dist/src/ui/utils/CodeColorizer.js +6 -3
  708. package/dist/src/ui/utils/CodeColorizer.js.map +1 -1
  709. package/dist/src/ui/utils/InlineMarkdownRenderer.d.ts +1 -0
  710. package/dist/src/ui/utils/InlineMarkdownRenderer.js +11 -10
  711. package/dist/src/ui/utils/InlineMarkdownRenderer.js.map +1 -1
  712. package/dist/src/ui/utils/MarkdownDisplay.d.ts +1 -0
  713. package/dist/src/ui/utils/MarkdownDisplay.js +19 -10
  714. package/dist/src/ui/utils/MarkdownDisplay.js.map +1 -1
  715. package/dist/src/ui/utils/clipboardUtils.js +2 -2
  716. package/dist/src/ui/utils/clipboardUtils.js.map +1 -1
  717. package/dist/src/ui/utils/commandUtils.js +20 -3
  718. package/dist/src/ui/utils/commandUtils.js.map +1 -1
  719. package/dist/src/ui/utils/commandUtils.test.js +61 -6
  720. package/dist/src/ui/utils/commandUtils.test.js.map +1 -1
  721. package/dist/src/ui/utils/computeStats.js +5 -2
  722. package/dist/src/ui/utils/computeStats.js.map +1 -1
  723. package/dist/src/ui/utils/computeStats.test.d.ts +6 -0
  724. package/dist/src/ui/utils/computeStats.test.js +262 -0
  725. package/dist/src/ui/utils/computeStats.test.js.map +1 -0
  726. package/dist/src/ui/utils/input.d.ts +17 -0
  727. package/dist/src/ui/utils/input.js +51 -0
  728. package/dist/src/ui/utils/input.js.map +1 -0
  729. package/dist/src/ui/utils/input.test.d.ts +6 -0
  730. package/dist/src/ui/utils/input.test.js +44 -0
  731. package/dist/src/ui/utils/input.test.js.map +1 -0
  732. package/dist/src/ui/utils/kittyProtocolDetector.js +13 -4
  733. package/dist/src/ui/utils/kittyProtocolDetector.js.map +1 -1
  734. package/dist/src/ui/utils/mouse.d.ts +31 -0
  735. package/dist/src/ui/utils/mouse.js +164 -0
  736. package/dist/src/ui/utils/mouse.js.map +1 -0
  737. package/dist/src/ui/utils/mouse.test.d.ts +6 -0
  738. package/dist/src/ui/utils/mouse.test.js +131 -0
  739. package/dist/src/ui/utils/mouse.test.js.map +1 -0
  740. package/dist/src/ui/utils/terminalSetup.js +3 -2
  741. package/dist/src/ui/utils/terminalSetup.js.map +1 -1
  742. package/dist/src/ui/utils/textOutput.d.ts +25 -0
  743. package/dist/src/ui/utils/textOutput.js +49 -0
  744. package/dist/src/ui/utils/textOutput.js.map +1 -0
  745. package/dist/src/ui/utils/textOutput.test.d.ts +6 -0
  746. package/dist/src/ui/utils/textOutput.test.js +79 -0
  747. package/dist/src/ui/utils/textOutput.test.js.map +1 -0
  748. package/dist/src/ui/utils/updateCheck.d.ts +9 -2
  749. package/dist/src/ui/utils/updateCheck.js +38 -30
  750. package/dist/src/ui/utils/updateCheck.js.map +1 -1
  751. package/dist/src/ui/utils/updateCheck.test.js +48 -59
  752. package/dist/src/ui/utils/updateCheck.test.js.map +1 -1
  753. package/dist/src/utils/cleanup.test.d.ts +6 -0
  754. package/dist/src/utils/cleanup.test.js +49 -0
  755. package/dist/src/utils/cleanup.test.js.map +1 -0
  756. package/dist/src/utils/commentJson.js +2 -2
  757. package/dist/src/utils/commentJson.js.map +1 -1
  758. package/dist/src/utils/commentJson.test.js +7 -6
  759. package/dist/src/utils/commentJson.test.js.map +1 -1
  760. package/dist/src/utils/envVarResolver.d.ts +2 -2
  761. package/dist/src/utils/envVarResolver.js +10 -7
  762. package/dist/src/utils/envVarResolver.js.map +1 -1
  763. package/dist/src/utils/errors.d.ts +1 -0
  764. package/dist/src/utils/errors.js +66 -5
  765. package/dist/src/utils/errors.js.map +1 -1
  766. package/dist/src/utils/events.d.ts +11 -2
  767. package/dist/src/utils/events.js +1 -0
  768. package/dist/src/utils/events.js.map +1 -1
  769. package/dist/src/utils/gitUtils.js +3 -2
  770. package/dist/src/utils/gitUtils.js.map +1 -1
  771. package/dist/src/utils/handleAutoUpdate.js +9 -3
  772. package/dist/src/utils/handleAutoUpdate.js.map +1 -1
  773. package/dist/src/utils/handleAutoUpdate.test.d.ts +6 -0
  774. package/dist/src/utils/handleAutoUpdate.test.js +225 -0
  775. package/dist/src/utils/handleAutoUpdate.test.js.map +1 -0
  776. package/dist/src/utils/installationInfo.js +2 -2
  777. package/dist/src/utils/installationInfo.js.map +1 -1
  778. package/dist/src/utils/installationInfo.test.js +8 -4
  779. package/dist/src/utils/installationInfo.test.js.map +1 -1
  780. package/dist/src/utils/readStdin.js +2 -1
  781. package/dist/src/utils/readStdin.js.map +1 -1
  782. package/dist/src/utils/sandbox-macos-permissive-open.sb +2 -0
  783. package/dist/src/utils/sandbox.js +28 -30
  784. package/dist/src/utils/sandbox.js.map +1 -1
  785. package/dist/src/utils/sessionCleanup.js +4 -4
  786. package/dist/src/utils/sessionCleanup.js.map +1 -1
  787. package/dist/src/utils/startupWarnings.test.d.ts +6 -0
  788. package/dist/src/utils/startupWarnings.test.js +61 -0
  789. package/dist/src/utils/startupWarnings.test.js.map +1 -0
  790. package/dist/src/utils/version.js +6 -2
  791. package/dist/src/utils/version.js.map +1 -1
  792. package/dist/src/validateNonInterActiveAuth.js +2 -2
  793. package/dist/src/validateNonInterActiveAuth.js.map +1 -1
  794. package/dist/src/zed-integration/acp.js +2 -1
  795. package/dist/src/zed-integration/acp.js.map +1 -1
  796. package/dist/src/zed-integration/schema.d.ts +4 -4
  797. package/dist/src/zed-integration/zedIntegration.d.ts +2 -2
  798. package/dist/src/zed-integration/zedIntegration.js +16 -25
  799. package/dist/src/zed-integration/zedIntegration.js.map +1 -1
  800. package/dist/tsconfig.tsbuildinfo +1 -1
  801. package/package.json +17 -17
  802. package/dist/src/config/policy.test.js +0 -336
  803. package/dist/src/config/policy.test.js.map +0 -1
  804. package/dist/src/ui/components/WorkspaceMigrationDialog.d.ts +0 -11
  805. package/dist/src/ui/components/WorkspaceMigrationDialog.js +0 -44
  806. package/dist/src/ui/components/WorkspaceMigrationDialog.js.map +0 -1
  807. package/dist/src/ui/hooks/useWorkspaceMigration.d.ts +0 -13
  808. package/dist/src/ui/hooks/useWorkspaceMigration.js +0 -59
  809. package/dist/src/ui/hooks/useWorkspaceMigration.js.map +0 -1
  810. package/dist/src/utils/package.d.ts +0 -12
  811. package/dist/src/utils/package.js +0 -24
  812. package/dist/src/utils/package.js.map +0 -1
  813. /package/dist/src/{config/policy.test.d.ts → commands/extensions/examples/mcp-server/example.d.ts} +0 -0
@@ -0,0 +1,1269 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
7
+ import { act } from 'react';
8
+ import { renderHook } from '../../test-utils/render.js';
9
+ import { waitFor } from '../../test-utils/async.js';
10
+ import { useVim } from './vim.js';
11
+ import { textBufferReducer } from '../components/shared/text-buffer.js';
12
+ // Mock the VimModeContext
13
+ const mockVimContext = {
14
+ vimEnabled: true,
15
+ vimMode: 'NORMAL',
16
+ toggleVimEnabled: vi.fn(),
17
+ setVimMode: vi.fn(),
18
+ };
19
+ vi.mock('../contexts/VimModeContext.js', () => ({
20
+ useVimMode: () => mockVimContext,
21
+ VimModeProvider: ({ children }) => children,
22
+ }));
23
+ // Helper to create a full Key object from partial data
24
+ const createKey = (partial) => ({
25
+ name: partial.name || '',
26
+ sequence: partial.sequence || '',
27
+ ctrl: partial.ctrl || false,
28
+ meta: partial.meta || false,
29
+ shift: partial.shift || false,
30
+ paste: partial.paste || false,
31
+ ...partial,
32
+ });
33
+ const createMockTextBufferState = (partial) => {
34
+ const lines = partial.lines || [''];
35
+ return {
36
+ lines,
37
+ cursorRow: 0,
38
+ cursorCol: 0,
39
+ preferredCol: null,
40
+ undoStack: [],
41
+ redoStack: [],
42
+ clipboard: null,
43
+ selectionAnchor: null,
44
+ viewportWidth: 80,
45
+ viewportHeight: 24,
46
+ visualLayout: {
47
+ visualLines: lines,
48
+ logicalToVisualMap: lines.map((_, i) => [[i, 0]]),
49
+ visualToLogicalMap: lines.map((_, i) => [i, 0]),
50
+ },
51
+ ...partial,
52
+ };
53
+ };
54
+ // Test constants
55
+ const TEST_SEQUENCES = {
56
+ ESCAPE: createKey({ sequence: '\u001b', name: 'escape' }),
57
+ LEFT: createKey({ sequence: 'h' }),
58
+ RIGHT: createKey({ sequence: 'l' }),
59
+ UP: createKey({ sequence: 'k' }),
60
+ DOWN: createKey({ sequence: 'j' }),
61
+ INSERT: createKey({ sequence: 'i' }),
62
+ APPEND: createKey({ sequence: 'a' }),
63
+ DELETE_CHAR: createKey({ sequence: 'x' }),
64
+ DELETE: createKey({ sequence: 'd' }),
65
+ CHANGE: createKey({ sequence: 'c' }),
66
+ WORD_FORWARD: createKey({ sequence: 'w' }),
67
+ WORD_BACKWARD: createKey({ sequence: 'b' }),
68
+ WORD_END: createKey({ sequence: 'e' }),
69
+ LINE_START: createKey({ sequence: '0' }),
70
+ LINE_END: createKey({ sequence: '$' }),
71
+ REPEAT: createKey({ sequence: '.' }),
72
+ };
73
+ describe('useVim hook', () => {
74
+ let mockBuffer;
75
+ let mockHandleFinalSubmit;
76
+ const createMockBuffer = (text = 'hello world', cursor = [0, 5]) => {
77
+ const cursorState = { pos: cursor };
78
+ const lines = text.split('\n');
79
+ return {
80
+ lines,
81
+ get cursor() {
82
+ return cursorState.pos;
83
+ },
84
+ set cursor(newPos) {
85
+ cursorState.pos = newPos;
86
+ },
87
+ text,
88
+ move: vi.fn().mockImplementation((direction) => {
89
+ let [row, col] = cursorState.pos;
90
+ const line = lines[row] || '';
91
+ if (direction === 'left') {
92
+ col = Math.max(0, col - 1);
93
+ }
94
+ else if (direction === 'right') {
95
+ col = Math.min(line.length, col + 1);
96
+ }
97
+ else if (direction === 'home') {
98
+ col = 0;
99
+ }
100
+ else if (direction === 'end') {
101
+ col = line.length;
102
+ }
103
+ cursorState.pos = [row, col];
104
+ }),
105
+ del: vi.fn(),
106
+ moveToOffset: vi.fn(),
107
+ insert: vi.fn(),
108
+ newline: vi.fn(),
109
+ replaceRangeByOffset: vi.fn(),
110
+ handleInput: vi.fn(),
111
+ setText: vi.fn(),
112
+ // Vim-specific methods
113
+ vimDeleteWordForward: vi.fn(),
114
+ vimDeleteWordBackward: vi.fn(),
115
+ vimDeleteWordEnd: vi.fn(),
116
+ vimChangeWordForward: vi.fn(),
117
+ vimChangeWordBackward: vi.fn(),
118
+ vimChangeWordEnd: vi.fn(),
119
+ vimDeleteLine: vi.fn(),
120
+ vimChangeLine: vi.fn(),
121
+ vimDeleteToEndOfLine: vi.fn(),
122
+ vimChangeToEndOfLine: vi.fn(),
123
+ vimChangeMovement: vi.fn(),
124
+ vimMoveLeft: vi.fn(),
125
+ vimMoveRight: vi.fn(),
126
+ vimMoveUp: vi.fn(),
127
+ vimMoveDown: vi.fn(),
128
+ vimMoveWordForward: vi.fn(),
129
+ vimMoveWordBackward: vi.fn(),
130
+ vimMoveWordEnd: vi.fn(),
131
+ vimDeleteChar: vi.fn(),
132
+ vimInsertAtCursor: vi.fn(),
133
+ vimAppendAtCursor: vi.fn().mockImplementation(() => {
134
+ // Append moves cursor right (vim 'a' behavior - position after current char)
135
+ const [row, col] = cursorState.pos;
136
+ // In vim, 'a' moves cursor to position after current character
137
+ // This allows inserting at the end of the line
138
+ cursorState.pos = [row, col + 1];
139
+ }),
140
+ vimOpenLineBelow: vi.fn(),
141
+ vimOpenLineAbove: vi.fn(),
142
+ vimAppendAtLineEnd: vi.fn(),
143
+ vimInsertAtLineStart: vi.fn(),
144
+ vimMoveToLineStart: vi.fn(),
145
+ vimMoveToLineEnd: vi.fn(),
146
+ vimMoveToFirstNonWhitespace: vi.fn(),
147
+ vimMoveToFirstLine: vi.fn(),
148
+ vimMoveToLastLine: vi.fn(),
149
+ vimMoveToLine: vi.fn(),
150
+ vimEscapeInsertMode: vi.fn().mockImplementation(() => {
151
+ // Escape moves cursor left unless at beginning of line
152
+ const [row, col] = cursorState.pos;
153
+ if (col > 0) {
154
+ cursorState.pos = [row, col - 1];
155
+ }
156
+ }),
157
+ };
158
+ };
159
+ const renderVimHook = (buffer) => renderHook(() => useVim((buffer || mockBuffer), mockHandleFinalSubmit));
160
+ const exitInsertMode = (result) => {
161
+ act(() => {
162
+ result.current.handleInput(TEST_SEQUENCES.ESCAPE);
163
+ });
164
+ };
165
+ beforeEach(() => {
166
+ vi.clearAllMocks();
167
+ mockHandleFinalSubmit = vi.fn();
168
+ mockBuffer = createMockBuffer();
169
+ // Reset mock context to default state
170
+ mockVimContext.vimEnabled = true;
171
+ mockVimContext.vimMode = 'NORMAL';
172
+ mockVimContext.toggleVimEnabled.mockClear();
173
+ mockVimContext.setVimMode.mockClear();
174
+ });
175
+ describe('Mode switching', () => {
176
+ it('should start in NORMAL mode', () => {
177
+ const { result } = renderVimHook();
178
+ expect(result.current.mode).toBe('NORMAL');
179
+ });
180
+ it('should switch to INSERT mode with i command', () => {
181
+ const { result } = renderVimHook();
182
+ act(() => {
183
+ result.current.handleInput(TEST_SEQUENCES.INSERT);
184
+ });
185
+ expect(result.current.mode).toBe('INSERT');
186
+ expect(mockVimContext.setVimMode).toHaveBeenCalledWith('INSERT');
187
+ });
188
+ it('should switch back to NORMAL mode with Escape', () => {
189
+ const { result } = renderVimHook();
190
+ act(() => {
191
+ result.current.handleInput(TEST_SEQUENCES.INSERT);
192
+ });
193
+ expect(result.current.mode).toBe('INSERT');
194
+ exitInsertMode(result);
195
+ expect(result.current.mode).toBe('NORMAL');
196
+ });
197
+ it('should properly handle escape followed immediately by a command', () => {
198
+ const testBuffer = createMockBuffer('hello world test', [0, 6]);
199
+ const { result } = renderVimHook(testBuffer);
200
+ act(() => {
201
+ result.current.handleInput(createKey({ sequence: 'i' }));
202
+ });
203
+ expect(result.current.mode).toBe('INSERT');
204
+ vi.clearAllMocks();
205
+ exitInsertMode(result);
206
+ expect(result.current.mode).toBe('NORMAL');
207
+ act(() => {
208
+ result.current.handleInput(createKey({ sequence: 'b' }));
209
+ });
210
+ expect(testBuffer.vimMoveWordBackward).toHaveBeenCalledWith(1);
211
+ });
212
+ });
213
+ describe('Navigation commands', () => {
214
+ it('should handle h (left movement)', () => {
215
+ const { result } = renderVimHook();
216
+ act(() => {
217
+ result.current.handleInput(createKey({ sequence: 'h' }));
218
+ });
219
+ expect(mockBuffer.vimMoveLeft).toHaveBeenCalledWith(1);
220
+ });
221
+ it('should handle l (right movement)', () => {
222
+ const { result } = renderVimHook();
223
+ act(() => {
224
+ result.current.handleInput(createKey({ sequence: 'l' }));
225
+ });
226
+ expect(mockBuffer.vimMoveRight).toHaveBeenCalledWith(1);
227
+ });
228
+ it('should handle j (down movement)', () => {
229
+ const testBuffer = createMockBuffer('first line\nsecond line');
230
+ const { result } = renderVimHook(testBuffer);
231
+ act(() => {
232
+ result.current.handleInput(createKey({ sequence: 'j' }));
233
+ });
234
+ expect(testBuffer.vimMoveDown).toHaveBeenCalledWith(1);
235
+ });
236
+ it('should handle k (up movement)', () => {
237
+ const testBuffer = createMockBuffer('first line\nsecond line');
238
+ const { result } = renderVimHook(testBuffer);
239
+ act(() => {
240
+ result.current.handleInput(createKey({ sequence: 'k' }));
241
+ });
242
+ expect(testBuffer.vimMoveUp).toHaveBeenCalledWith(1);
243
+ });
244
+ it('should handle 0 (move to start of line)', () => {
245
+ const { result } = renderVimHook();
246
+ act(() => {
247
+ result.current.handleInput(createKey({ sequence: '0' }));
248
+ });
249
+ expect(mockBuffer.vimMoveToLineStart).toHaveBeenCalled();
250
+ });
251
+ it('should handle $ (move to end of line)', () => {
252
+ const { result } = renderVimHook();
253
+ act(() => {
254
+ result.current.handleInput(createKey({ sequence: '$' }));
255
+ });
256
+ expect(mockBuffer.vimMoveToLineEnd).toHaveBeenCalled();
257
+ });
258
+ });
259
+ describe('Mode switching commands', () => {
260
+ it('should handle a (append after cursor)', () => {
261
+ const { result } = renderVimHook();
262
+ act(() => {
263
+ result.current.handleInput(createKey({ sequence: 'a' }));
264
+ });
265
+ expect(mockBuffer.vimAppendAtCursor).toHaveBeenCalled();
266
+ expect(result.current.mode).toBe('INSERT');
267
+ });
268
+ it('should handle A (append at end of line)', () => {
269
+ const { result } = renderVimHook();
270
+ act(() => {
271
+ result.current.handleInput(createKey({ sequence: 'A' }));
272
+ });
273
+ expect(mockBuffer.vimAppendAtLineEnd).toHaveBeenCalled();
274
+ expect(result.current.mode).toBe('INSERT');
275
+ });
276
+ it('should handle o (open line below)', () => {
277
+ const { result } = renderVimHook();
278
+ act(() => {
279
+ result.current.handleInput(createKey({ sequence: 'o' }));
280
+ });
281
+ expect(mockBuffer.vimOpenLineBelow).toHaveBeenCalled();
282
+ expect(result.current.mode).toBe('INSERT');
283
+ });
284
+ it('should handle O (open line above)', () => {
285
+ const { result } = renderVimHook();
286
+ act(() => {
287
+ result.current.handleInput(createKey({ sequence: 'O' }));
288
+ });
289
+ expect(mockBuffer.vimOpenLineAbove).toHaveBeenCalled();
290
+ expect(result.current.mode).toBe('INSERT');
291
+ });
292
+ });
293
+ describe('Edit commands', () => {
294
+ it('should handle x (delete character)', () => {
295
+ const { result } = renderVimHook();
296
+ vi.clearAllMocks();
297
+ act(() => {
298
+ result.current.handleInput(createKey({ sequence: 'x' }));
299
+ });
300
+ expect(mockBuffer.vimDeleteChar).toHaveBeenCalledWith(1);
301
+ });
302
+ it('should move cursor left when deleting last character on line (vim behavior)', () => {
303
+ const testBuffer = createMockBuffer('hello', [0, 4]);
304
+ const { result } = renderVimHook(testBuffer);
305
+ act(() => {
306
+ result.current.handleInput(createKey({ sequence: 'x' }));
307
+ });
308
+ expect(testBuffer.vimDeleteChar).toHaveBeenCalledWith(1);
309
+ });
310
+ it('should handle first d key (sets pending state)', () => {
311
+ const { result } = renderVimHook();
312
+ act(() => {
313
+ result.current.handleInput(createKey({ sequence: 'd' }));
314
+ });
315
+ expect(mockBuffer.replaceRangeByOffset).not.toHaveBeenCalled();
316
+ });
317
+ });
318
+ describe('Count handling', () => {
319
+ it('should handle count input and return to count 0 after command', () => {
320
+ const { result } = renderVimHook();
321
+ act(() => {
322
+ const handled = result.current.handleInput(createKey({ sequence: '3' }));
323
+ expect(handled).toBe(true);
324
+ });
325
+ act(() => {
326
+ const handled = result.current.handleInput(createKey({ sequence: 'h' }));
327
+ expect(handled).toBe(true);
328
+ });
329
+ expect(mockBuffer.vimMoveLeft).toHaveBeenCalledWith(3);
330
+ });
331
+ it('should only delete 1 character with x command when no count is specified', () => {
332
+ const testBuffer = createMockBuffer();
333
+ const { result } = renderVimHook(testBuffer);
334
+ act(() => {
335
+ result.current.handleInput(createKey({ sequence: 'x' }));
336
+ });
337
+ expect(testBuffer.vimDeleteChar).toHaveBeenCalledWith(1);
338
+ });
339
+ });
340
+ describe('Word movement', () => {
341
+ it('should properly initialize vim hook with word movement support', () => {
342
+ const testBuffer = createMockBuffer('cat elephant mouse', [0, 0]);
343
+ const { result } = renderVimHook(testBuffer);
344
+ expect(result.current.vimModeEnabled).toBe(true);
345
+ expect(result.current.mode).toBe('NORMAL');
346
+ expect(result.current.handleInput).toBeDefined();
347
+ });
348
+ it('should support vim mode and basic operations across multiple lines', () => {
349
+ const testBuffer = createMockBuffer('first line word\nsecond line word', [0, 11]);
350
+ const { result } = renderVimHook(testBuffer);
351
+ expect(result.current.vimModeEnabled).toBe(true);
352
+ expect(result.current.mode).toBe('NORMAL');
353
+ expect(result.current.handleInput).toBeDefined();
354
+ expect(testBuffer.replaceRangeByOffset).toBeDefined();
355
+ expect(testBuffer.moveToOffset).toBeDefined();
356
+ });
357
+ it('should handle w (next word)', () => {
358
+ const testBuffer = createMockBuffer('hello world test');
359
+ const { result } = renderVimHook(testBuffer);
360
+ act(() => {
361
+ result.current.handleInput(createKey({ sequence: 'w' }));
362
+ });
363
+ expect(testBuffer.vimMoveWordForward).toHaveBeenCalledWith(1);
364
+ });
365
+ it('should handle b (previous word)', () => {
366
+ const testBuffer = createMockBuffer('hello world test', [0, 6]);
367
+ const { result } = renderVimHook(testBuffer);
368
+ act(() => {
369
+ result.current.handleInput(createKey({ sequence: 'b' }));
370
+ });
371
+ expect(testBuffer.vimMoveWordBackward).toHaveBeenCalledWith(1);
372
+ });
373
+ it('should handle e (end of word)', () => {
374
+ const testBuffer = createMockBuffer('hello world test');
375
+ const { result } = renderVimHook(testBuffer);
376
+ act(() => {
377
+ result.current.handleInput(createKey({ sequence: 'e' }));
378
+ });
379
+ expect(testBuffer.vimMoveWordEnd).toHaveBeenCalledWith(1);
380
+ });
381
+ it('should handle w when cursor is on the last word', () => {
382
+ const testBuffer = createMockBuffer('hello world', [0, 8]);
383
+ const { result } = renderVimHook(testBuffer);
384
+ act(() => {
385
+ result.current.handleInput(createKey({ sequence: 'w' }));
386
+ });
387
+ expect(testBuffer.vimMoveWordForward).toHaveBeenCalledWith(1);
388
+ });
389
+ it('should handle first c key (sets pending change state)', () => {
390
+ const { result } = renderVimHook();
391
+ act(() => {
392
+ result.current.handleInput(createKey({ sequence: 'c' }));
393
+ });
394
+ expect(result.current.mode).toBe('NORMAL');
395
+ expect(mockBuffer.del).not.toHaveBeenCalled();
396
+ });
397
+ it('should clear pending state on invalid command sequence (df)', () => {
398
+ const { result } = renderVimHook();
399
+ act(() => {
400
+ result.current.handleInput(createKey({ sequence: 'd' }));
401
+ result.current.handleInput(createKey({ sequence: 'f' }));
402
+ });
403
+ expect(mockBuffer.replaceRangeByOffset).not.toHaveBeenCalled();
404
+ expect(mockBuffer.del).not.toHaveBeenCalled();
405
+ });
406
+ it('should clear pending state with Escape in NORMAL mode', () => {
407
+ const { result } = renderVimHook();
408
+ act(() => {
409
+ result.current.handleInput(createKey({ sequence: 'd' }));
410
+ });
411
+ exitInsertMode(result);
412
+ expect(mockBuffer.replaceRangeByOffset).not.toHaveBeenCalled();
413
+ });
414
+ });
415
+ describe('Disabled vim mode', () => {
416
+ it('should not respond to vim commands when disabled', () => {
417
+ mockVimContext.vimEnabled = false;
418
+ const { result } = renderVimHook(mockBuffer);
419
+ act(() => {
420
+ result.current.handleInput(createKey({ sequence: 'h' }));
421
+ });
422
+ expect(mockBuffer.move).not.toHaveBeenCalled();
423
+ });
424
+ });
425
+ // These tests are no longer applicable at the hook level
426
+ describe('Command repeat system', () => {
427
+ it('should repeat x command from current cursor position', () => {
428
+ const testBuffer = createMockBuffer('abcd\nefgh\nijkl', [0, 1]);
429
+ const { result } = renderVimHook(testBuffer);
430
+ act(() => {
431
+ result.current.handleInput(createKey({ sequence: 'x' }));
432
+ });
433
+ expect(testBuffer.vimDeleteChar).toHaveBeenCalledWith(1);
434
+ testBuffer.cursor = [1, 2];
435
+ act(() => {
436
+ result.current.handleInput(createKey({ sequence: '.' }));
437
+ });
438
+ expect(testBuffer.vimDeleteChar).toHaveBeenCalledWith(1);
439
+ });
440
+ it('should repeat dd command from current position', () => {
441
+ const testBuffer = createMockBuffer('line1\nline2\nline3', [1, 0]);
442
+ const { result } = renderVimHook(testBuffer);
443
+ act(() => {
444
+ result.current.handleInput(createKey({ sequence: 'd' }));
445
+ });
446
+ act(() => {
447
+ result.current.handleInput(createKey({ sequence: 'd' }));
448
+ });
449
+ expect(testBuffer.vimDeleteLine).toHaveBeenCalledTimes(1);
450
+ testBuffer.cursor = [0, 0];
451
+ act(() => {
452
+ result.current.handleInput(createKey({ sequence: '.' }));
453
+ });
454
+ expect(testBuffer.vimDeleteLine).toHaveBeenCalledTimes(2);
455
+ });
456
+ it('should repeat ce command from current position', () => {
457
+ const testBuffer = createMockBuffer('word', [0, 0]);
458
+ const { result } = renderVimHook(testBuffer);
459
+ act(() => {
460
+ result.current.handleInput(createKey({ sequence: 'c' }));
461
+ });
462
+ act(() => {
463
+ result.current.handleInput(createKey({ sequence: 'e' }));
464
+ });
465
+ expect(testBuffer.vimChangeWordEnd).toHaveBeenCalledTimes(1);
466
+ // Exit INSERT mode to complete the command
467
+ exitInsertMode(result);
468
+ testBuffer.cursor = [0, 2];
469
+ act(() => {
470
+ result.current.handleInput(createKey({ sequence: '.' }));
471
+ });
472
+ expect(testBuffer.vimChangeWordEnd).toHaveBeenCalledTimes(2);
473
+ });
474
+ it('should repeat cc command from current position', () => {
475
+ const testBuffer = createMockBuffer('line1\nline2\nline3', [1, 2]);
476
+ const { result } = renderVimHook(testBuffer);
477
+ act(() => {
478
+ result.current.handleInput(createKey({ sequence: 'c' }));
479
+ });
480
+ act(() => {
481
+ result.current.handleInput(createKey({ sequence: 'c' }));
482
+ });
483
+ expect(testBuffer.vimChangeLine).toHaveBeenCalledTimes(1);
484
+ // Exit INSERT mode to complete the command
485
+ exitInsertMode(result);
486
+ testBuffer.cursor = [0, 1];
487
+ act(() => {
488
+ result.current.handleInput(createKey({ sequence: '.' }));
489
+ });
490
+ expect(testBuffer.vimChangeLine).toHaveBeenCalledTimes(2);
491
+ });
492
+ it('should repeat cw command from current position', () => {
493
+ const testBuffer = createMockBuffer('hello world test', [0, 6]);
494
+ const { result } = renderVimHook(testBuffer);
495
+ act(() => {
496
+ result.current.handleInput(createKey({ sequence: 'c' }));
497
+ });
498
+ act(() => {
499
+ result.current.handleInput(createKey({ sequence: 'w' }));
500
+ });
501
+ expect(testBuffer.vimChangeWordForward).toHaveBeenCalledTimes(1);
502
+ // Exit INSERT mode to complete the command
503
+ exitInsertMode(result);
504
+ testBuffer.cursor = [0, 0];
505
+ act(() => {
506
+ result.current.handleInput(createKey({ sequence: '.' }));
507
+ });
508
+ expect(testBuffer.vimChangeWordForward).toHaveBeenCalledTimes(2);
509
+ });
510
+ it('should repeat D command from current position', () => {
511
+ const testBuffer = createMockBuffer('hello world test', [0, 6]);
512
+ const { result } = renderVimHook(testBuffer);
513
+ act(() => {
514
+ result.current.handleInput(createKey({ sequence: 'D' }));
515
+ });
516
+ expect(testBuffer.vimDeleteToEndOfLine).toHaveBeenCalledTimes(1);
517
+ testBuffer.cursor = [0, 2];
518
+ vi.clearAllMocks(); // Clear all mocks instead of just one method
519
+ act(() => {
520
+ result.current.handleInput(createKey({ sequence: '.' }));
521
+ });
522
+ expect(testBuffer.vimDeleteToEndOfLine).toHaveBeenCalledTimes(1);
523
+ });
524
+ it('should repeat C command from current position', () => {
525
+ const testBuffer = createMockBuffer('hello world test', [0, 6]);
526
+ const { result } = renderVimHook(testBuffer);
527
+ act(() => {
528
+ result.current.handleInput(createKey({ sequence: 'C' }));
529
+ });
530
+ expect(testBuffer.vimChangeToEndOfLine).toHaveBeenCalledTimes(1);
531
+ // Exit INSERT mode to complete the command
532
+ exitInsertMode(result);
533
+ testBuffer.cursor = [0, 2];
534
+ act(() => {
535
+ result.current.handleInput(createKey({ sequence: '.' }));
536
+ });
537
+ expect(testBuffer.vimChangeToEndOfLine).toHaveBeenCalledTimes(2);
538
+ });
539
+ it('should repeat command after cursor movement', () => {
540
+ const testBuffer = createMockBuffer('test text', [0, 0]);
541
+ const { result } = renderVimHook(testBuffer);
542
+ act(() => {
543
+ result.current.handleInput(createKey({ sequence: 'x' }));
544
+ });
545
+ expect(testBuffer.vimDeleteChar).toHaveBeenCalledWith(1);
546
+ testBuffer.cursor = [0, 2];
547
+ act(() => {
548
+ result.current.handleInput(createKey({ sequence: '.' }));
549
+ });
550
+ expect(testBuffer.vimDeleteChar).toHaveBeenCalledWith(1);
551
+ });
552
+ it('should move cursor to the correct position after exiting INSERT mode with "a"', () => {
553
+ const testBuffer = createMockBuffer('hello world', [0, 10]);
554
+ const { result } = renderVimHook(testBuffer);
555
+ act(() => {
556
+ result.current.handleInput(createKey({ sequence: 'a' }));
557
+ });
558
+ expect(result.current.mode).toBe('INSERT');
559
+ expect(testBuffer.cursor).toEqual([0, 11]);
560
+ exitInsertMode(result);
561
+ expect(result.current.mode).toBe('NORMAL');
562
+ expect(testBuffer.cursor).toEqual([0, 10]);
563
+ });
564
+ });
565
+ describe('Special characters and edge cases', () => {
566
+ it('should handle ^ (move to first non-whitespace character)', () => {
567
+ const testBuffer = createMockBuffer(' hello world', [0, 5]);
568
+ const { result } = renderVimHook(testBuffer);
569
+ act(() => {
570
+ result.current.handleInput(createKey({ sequence: '^' }));
571
+ });
572
+ expect(testBuffer.vimMoveToFirstNonWhitespace).toHaveBeenCalled();
573
+ });
574
+ it('should handle G without count (go to last line)', () => {
575
+ const testBuffer = createMockBuffer('line1\nline2\nline3', [0, 0]);
576
+ const { result } = renderVimHook(testBuffer);
577
+ act(() => {
578
+ result.current.handleInput(createKey({ sequence: 'G' }));
579
+ });
580
+ expect(testBuffer.vimMoveToLastLine).toHaveBeenCalled();
581
+ });
582
+ it('should handle gg (go to first line)', () => {
583
+ const testBuffer = createMockBuffer('line1\nline2\nline3', [2, 0]);
584
+ const { result } = renderVimHook(testBuffer);
585
+ // First 'g' sets pending state
586
+ act(() => {
587
+ result.current.handleInput(createKey({ sequence: 'g' }));
588
+ });
589
+ // Second 'g' executes the command
590
+ act(() => {
591
+ result.current.handleInput(createKey({ sequence: 'g' }));
592
+ });
593
+ expect(testBuffer.vimMoveToFirstLine).toHaveBeenCalled();
594
+ });
595
+ it('should handle count with movement commands', () => {
596
+ const testBuffer = createMockBuffer('hello world test', [0, 0]);
597
+ const { result } = renderVimHook(testBuffer);
598
+ act(() => {
599
+ result.current.handleInput(createKey({ sequence: '3' }));
600
+ });
601
+ act(() => {
602
+ result.current.handleInput(TEST_SEQUENCES.WORD_FORWARD);
603
+ });
604
+ expect(testBuffer.vimMoveWordForward).toHaveBeenCalledWith(3);
605
+ });
606
+ });
607
+ describe('Vim word operations', () => {
608
+ describe('dw (delete word forward)', () => {
609
+ it('should delete from cursor to start of next word', () => {
610
+ const testBuffer = createMockBuffer('hello world test', [0, 0]);
611
+ const { result } = renderVimHook(testBuffer);
612
+ act(() => {
613
+ result.current.handleInput(createKey({ sequence: 'd' }));
614
+ });
615
+ act(() => {
616
+ result.current.handleInput(createKey({ sequence: 'w' }));
617
+ });
618
+ expect(testBuffer.vimDeleteWordForward).toHaveBeenCalledWith(1);
619
+ });
620
+ it('should actually delete the complete word including trailing space', () => {
621
+ // This test uses the real text-buffer reducer instead of mocks
622
+ const initialState = createMockTextBufferState({
623
+ lines: ['hello world test'],
624
+ cursorRow: 0,
625
+ cursorCol: 0,
626
+ preferredCol: null,
627
+ undoStack: [],
628
+ redoStack: [],
629
+ clipboard: null,
630
+ selectionAnchor: null,
631
+ });
632
+ const result = textBufferReducer(initialState, {
633
+ type: 'vim_delete_word_forward',
634
+ payload: { count: 1 },
635
+ });
636
+ // Should delete "hello " (word + space), leaving "world test"
637
+ expect(result.lines).toEqual(['world test']);
638
+ expect(result.cursorRow).toBe(0);
639
+ expect(result.cursorCol).toBe(0);
640
+ });
641
+ it('should delete word from middle of word correctly', () => {
642
+ const initialState = createMockTextBufferState({
643
+ lines: ['hello world test'],
644
+ cursorRow: 0,
645
+ cursorCol: 2, // cursor on 'l' in "hello"
646
+ preferredCol: null,
647
+ undoStack: [],
648
+ redoStack: [],
649
+ clipboard: null,
650
+ selectionAnchor: null,
651
+ });
652
+ const result = textBufferReducer(initialState, {
653
+ type: 'vim_delete_word_forward',
654
+ payload: { count: 1 },
655
+ });
656
+ // Should delete "llo " (rest of word + space), leaving "he world test"
657
+ expect(result.lines).toEqual(['heworld test']);
658
+ expect(result.cursorRow).toBe(0);
659
+ expect(result.cursorCol).toBe(2);
660
+ });
661
+ it('should handle dw at end of line', () => {
662
+ const initialState = createMockTextBufferState({
663
+ lines: ['hello world'],
664
+ cursorRow: 0,
665
+ cursorCol: 6, // cursor on 'w' in "world"
666
+ preferredCol: null,
667
+ undoStack: [],
668
+ redoStack: [],
669
+ clipboard: null,
670
+ selectionAnchor: null,
671
+ });
672
+ const result = textBufferReducer(initialState, {
673
+ type: 'vim_delete_word_forward',
674
+ payload: { count: 1 },
675
+ });
676
+ // Should delete "world" (no trailing space at end), leaving "hello "
677
+ expect(result.lines).toEqual(['hello ']);
678
+ expect(result.cursorRow).toBe(0);
679
+ expect(result.cursorCol).toBe(6);
680
+ });
681
+ it('should delete multiple words with count', () => {
682
+ const testBuffer = createMockBuffer('one two three four', [0, 0]);
683
+ const { result } = renderVimHook(testBuffer);
684
+ act(() => {
685
+ result.current.handleInput(createKey({ sequence: '2' }));
686
+ });
687
+ act(() => {
688
+ result.current.handleInput(createKey({ sequence: 'd' }));
689
+ });
690
+ act(() => {
691
+ result.current.handleInput(createKey({ sequence: 'w' }));
692
+ });
693
+ expect(testBuffer.vimDeleteWordForward).toHaveBeenCalledWith(2);
694
+ });
695
+ it('should record command for repeat with dot', () => {
696
+ const testBuffer = createMockBuffer('hello world test', [0, 0]);
697
+ const { result } = renderVimHook(testBuffer);
698
+ // Execute dw
699
+ act(() => {
700
+ result.current.handleInput(createKey({ sequence: 'd' }));
701
+ });
702
+ act(() => {
703
+ result.current.handleInput(createKey({ sequence: 'w' }));
704
+ });
705
+ vi.clearAllMocks();
706
+ // Execute dot repeat
707
+ act(() => {
708
+ result.current.handleInput(createKey({ sequence: '.' }));
709
+ });
710
+ expect(testBuffer.vimDeleteWordForward).toHaveBeenCalledWith(1);
711
+ });
712
+ });
713
+ describe('de (delete word end)', () => {
714
+ it('should delete from cursor to end of current word', () => {
715
+ const testBuffer = createMockBuffer('hello world test', [0, 1]);
716
+ const { result } = renderVimHook(testBuffer);
717
+ act(() => {
718
+ result.current.handleInput(createKey({ sequence: 'd' }));
719
+ });
720
+ act(() => {
721
+ result.current.handleInput(createKey({ sequence: 'e' }));
722
+ });
723
+ expect(testBuffer.vimDeleteWordEnd).toHaveBeenCalledWith(1);
724
+ });
725
+ it('should handle count with de', () => {
726
+ const testBuffer = createMockBuffer('one two three four', [0, 0]);
727
+ const { result } = renderVimHook(testBuffer);
728
+ act(() => {
729
+ result.current.handleInput(createKey({ sequence: '3' }));
730
+ });
731
+ act(() => {
732
+ result.current.handleInput(createKey({ sequence: 'd' }));
733
+ });
734
+ act(() => {
735
+ result.current.handleInput(createKey({ sequence: 'e' }));
736
+ });
737
+ expect(testBuffer.vimDeleteWordEnd).toHaveBeenCalledWith(3);
738
+ });
739
+ });
740
+ describe('cw (change word forward)', () => {
741
+ it('should change from cursor to start of next word and enter INSERT mode', () => {
742
+ const testBuffer = createMockBuffer('hello world test', [0, 0]);
743
+ const { result } = renderVimHook(testBuffer);
744
+ act(() => {
745
+ result.current.handleInput(createKey({ sequence: 'c' }));
746
+ });
747
+ act(() => {
748
+ result.current.handleInput(createKey({ sequence: 'w' }));
749
+ });
750
+ expect(testBuffer.vimChangeWordForward).toHaveBeenCalledWith(1);
751
+ expect(result.current.mode).toBe('INSERT');
752
+ expect(mockVimContext.setVimMode).toHaveBeenCalledWith('INSERT');
753
+ });
754
+ it('should handle count with cw', () => {
755
+ const testBuffer = createMockBuffer('one two three four', [0, 0]);
756
+ const { result } = renderVimHook(testBuffer);
757
+ act(() => {
758
+ result.current.handleInput(createKey({ sequence: '2' }));
759
+ });
760
+ act(() => {
761
+ result.current.handleInput(createKey({ sequence: 'c' }));
762
+ });
763
+ act(() => {
764
+ result.current.handleInput(createKey({ sequence: 'w' }));
765
+ });
766
+ expect(testBuffer.vimChangeWordForward).toHaveBeenCalledWith(2);
767
+ expect(result.current.mode).toBe('INSERT');
768
+ });
769
+ it('should be repeatable with dot', () => {
770
+ const testBuffer = createMockBuffer('hello world test more', [0, 0]);
771
+ const { result } = renderVimHook(testBuffer);
772
+ // Execute cw
773
+ act(() => {
774
+ result.current.handleInput(createKey({ sequence: 'c' }));
775
+ });
776
+ act(() => {
777
+ result.current.handleInput(createKey({ sequence: 'w' }));
778
+ });
779
+ // Exit INSERT mode
780
+ exitInsertMode(result);
781
+ vi.clearAllMocks();
782
+ mockVimContext.setVimMode.mockClear();
783
+ // Execute dot repeat
784
+ act(() => {
785
+ result.current.handleInput(createKey({ sequence: '.' }));
786
+ });
787
+ expect(testBuffer.vimChangeWordForward).toHaveBeenCalledWith(1);
788
+ expect(result.current.mode).toBe('INSERT');
789
+ });
790
+ });
791
+ describe('ce (change word end)', () => {
792
+ it('should change from cursor to end of word and enter INSERT mode', () => {
793
+ const testBuffer = createMockBuffer('hello world test', [0, 1]);
794
+ const { result } = renderVimHook(testBuffer);
795
+ act(() => {
796
+ result.current.handleInput(createKey({ sequence: 'c' }));
797
+ });
798
+ act(() => {
799
+ result.current.handleInput(createKey({ sequence: 'e' }));
800
+ });
801
+ expect(testBuffer.vimChangeWordEnd).toHaveBeenCalledWith(1);
802
+ expect(result.current.mode).toBe('INSERT');
803
+ });
804
+ it('should handle count with ce', () => {
805
+ const testBuffer = createMockBuffer('one two three four', [0, 0]);
806
+ const { result } = renderVimHook(testBuffer);
807
+ act(() => {
808
+ result.current.handleInput(createKey({ sequence: '2' }));
809
+ });
810
+ act(() => {
811
+ result.current.handleInput(createKey({ sequence: 'c' }));
812
+ });
813
+ act(() => {
814
+ result.current.handleInput(createKey({ sequence: 'e' }));
815
+ });
816
+ expect(testBuffer.vimChangeWordEnd).toHaveBeenCalledWith(2);
817
+ expect(result.current.mode).toBe('INSERT');
818
+ });
819
+ });
820
+ describe('cc (change line)', () => {
821
+ it('should change entire line and enter INSERT mode', () => {
822
+ const testBuffer = createMockBuffer('hello world\nsecond line', [0, 5]);
823
+ const { result } = renderVimHook(testBuffer);
824
+ act(() => {
825
+ result.current.handleInput(createKey({ sequence: 'c' }));
826
+ });
827
+ act(() => {
828
+ result.current.handleInput(createKey({ sequence: 'c' }));
829
+ });
830
+ expect(testBuffer.vimChangeLine).toHaveBeenCalledWith(1);
831
+ expect(result.current.mode).toBe('INSERT');
832
+ });
833
+ it('should change multiple lines with count', () => {
834
+ const testBuffer = createMockBuffer('line1\nline2\nline3\nline4', [1, 0]);
835
+ const { result } = renderVimHook(testBuffer);
836
+ act(() => {
837
+ result.current.handleInput(createKey({ sequence: '3' }));
838
+ });
839
+ act(() => {
840
+ result.current.handleInput(createKey({ sequence: 'c' }));
841
+ });
842
+ act(() => {
843
+ result.current.handleInput(createKey({ sequence: 'c' }));
844
+ });
845
+ expect(testBuffer.vimChangeLine).toHaveBeenCalledWith(3);
846
+ expect(result.current.mode).toBe('INSERT');
847
+ });
848
+ it('should be repeatable with dot', () => {
849
+ const testBuffer = createMockBuffer('line1\nline2\nline3', [0, 0]);
850
+ const { result } = renderVimHook(testBuffer);
851
+ // Execute cc
852
+ act(() => {
853
+ result.current.handleInput(createKey({ sequence: 'c' }));
854
+ });
855
+ act(() => {
856
+ result.current.handleInput(createKey({ sequence: 'c' }));
857
+ });
858
+ // Exit INSERT mode
859
+ exitInsertMode(result);
860
+ vi.clearAllMocks();
861
+ mockVimContext.setVimMode.mockClear();
862
+ // Execute dot repeat
863
+ act(() => {
864
+ result.current.handleInput(createKey({ sequence: '.' }));
865
+ });
866
+ expect(testBuffer.vimChangeLine).toHaveBeenCalledWith(1);
867
+ expect(result.current.mode).toBe('INSERT');
868
+ });
869
+ });
870
+ describe('db (delete word backward)', () => {
871
+ it('should delete from cursor to start of previous word', () => {
872
+ const testBuffer = createMockBuffer('hello world test', [0, 11]);
873
+ const { result } = renderVimHook(testBuffer);
874
+ act(() => {
875
+ result.current.handleInput(createKey({ sequence: 'd' }));
876
+ });
877
+ act(() => {
878
+ result.current.handleInput(createKey({ sequence: 'b' }));
879
+ });
880
+ expect(testBuffer.vimDeleteWordBackward).toHaveBeenCalledWith(1);
881
+ });
882
+ it('should handle count with db', () => {
883
+ const testBuffer = createMockBuffer('one two three four', [0, 18]);
884
+ const { result } = renderVimHook(testBuffer);
885
+ act(() => {
886
+ result.current.handleInput(createKey({ sequence: '2' }));
887
+ });
888
+ act(() => {
889
+ result.current.handleInput(createKey({ sequence: 'd' }));
890
+ });
891
+ act(() => {
892
+ result.current.handleInput(createKey({ sequence: 'b' }));
893
+ });
894
+ expect(testBuffer.vimDeleteWordBackward).toHaveBeenCalledWith(2);
895
+ });
896
+ });
897
+ describe('cb (change word backward)', () => {
898
+ it('should change from cursor to start of previous word and enter INSERT mode', () => {
899
+ const testBuffer = createMockBuffer('hello world test', [0, 11]);
900
+ const { result } = renderVimHook(testBuffer);
901
+ act(() => {
902
+ result.current.handleInput(createKey({ sequence: 'c' }));
903
+ });
904
+ act(() => {
905
+ result.current.handleInput(createKey({ sequence: 'b' }));
906
+ });
907
+ expect(testBuffer.vimChangeWordBackward).toHaveBeenCalledWith(1);
908
+ expect(result.current.mode).toBe('INSERT');
909
+ });
910
+ it('should handle count with cb', () => {
911
+ const testBuffer = createMockBuffer('one two three four', [0, 18]);
912
+ const { result } = renderVimHook(testBuffer);
913
+ act(() => {
914
+ result.current.handleInput(createKey({ sequence: '3' }));
915
+ });
916
+ act(() => {
917
+ result.current.handleInput(createKey({ sequence: 'c' }));
918
+ });
919
+ act(() => {
920
+ result.current.handleInput(createKey({ sequence: 'b' }));
921
+ });
922
+ expect(testBuffer.vimChangeWordBackward).toHaveBeenCalledWith(3);
923
+ expect(result.current.mode).toBe('INSERT');
924
+ });
925
+ });
926
+ describe('Pending state handling', () => {
927
+ it('should clear pending delete state after dw', () => {
928
+ const testBuffer = createMockBuffer('hello world', [0, 0]);
929
+ const { result } = renderVimHook(testBuffer);
930
+ // Press 'd' to enter pending delete state
931
+ act(() => {
932
+ result.current.handleInput(createKey({ sequence: 'd' }));
933
+ });
934
+ // Complete with 'w'
935
+ act(() => {
936
+ result.current.handleInput(createKey({ sequence: 'w' }));
937
+ });
938
+ // Next 'd' should start a new pending state, not continue the previous one
939
+ act(() => {
940
+ result.current.handleInput(createKey({ sequence: 'd' }));
941
+ });
942
+ // This should trigger dd (delete line), not an error
943
+ act(() => {
944
+ result.current.handleInput(createKey({ sequence: 'd' }));
945
+ });
946
+ expect(testBuffer.vimDeleteLine).toHaveBeenCalledWith(1);
947
+ });
948
+ it('should clear pending change state after cw', () => {
949
+ const testBuffer = createMockBuffer('hello world', [0, 0]);
950
+ const { result } = renderVimHook(testBuffer);
951
+ // Execute cw
952
+ act(() => {
953
+ result.current.handleInput(createKey({ sequence: 'c' }));
954
+ });
955
+ act(() => {
956
+ result.current.handleInput(createKey({ sequence: 'w' }));
957
+ });
958
+ // Exit INSERT mode
959
+ exitInsertMode(result);
960
+ // Next 'c' should start a new pending state
961
+ act(() => {
962
+ result.current.handleInput(createKey({ sequence: 'c' }));
963
+ });
964
+ act(() => {
965
+ result.current.handleInput(createKey({ sequence: 'c' }));
966
+ });
967
+ expect(testBuffer.vimChangeLine).toHaveBeenCalledWith(1);
968
+ });
969
+ it('should clear pending state with escape', () => {
970
+ const testBuffer = createMockBuffer('hello world', [0, 0]);
971
+ const { result } = renderVimHook(testBuffer);
972
+ // Enter pending delete state
973
+ act(() => {
974
+ result.current.handleInput(createKey({ sequence: 'd' }));
975
+ });
976
+ // Press escape to clear pending state
977
+ act(() => {
978
+ result.current.handleInput(createKey({ name: 'escape' }));
979
+ });
980
+ // Now 'w' should just move cursor, not delete
981
+ act(() => {
982
+ result.current.handleInput(createKey({ sequence: 'w' }));
983
+ });
984
+ expect(testBuffer.vimDeleteWordForward).not.toHaveBeenCalled();
985
+ // w should move to next word after clearing pending state
986
+ expect(testBuffer.vimMoveWordForward).toHaveBeenCalledWith(1);
987
+ });
988
+ });
989
+ describe('NORMAL mode escape behavior', () => {
990
+ it('should pass escape through when no pending operator is active', () => {
991
+ mockVimContext.vimMode = 'NORMAL';
992
+ const { result } = renderVimHook();
993
+ const handled = result.current.handleInput(createKey({ name: 'escape' }));
994
+ expect(handled).toBe(false);
995
+ });
996
+ it('should handle escape and clear pending operator', () => {
997
+ mockVimContext.vimMode = 'NORMAL';
998
+ const { result } = renderVimHook();
999
+ act(() => {
1000
+ result.current.handleInput(createKey({ sequence: 'd' }));
1001
+ });
1002
+ let handled;
1003
+ act(() => {
1004
+ handled = result.current.handleInput(createKey({ name: 'escape' }));
1005
+ });
1006
+ expect(handled).toBe(true);
1007
+ });
1008
+ });
1009
+ });
1010
+ describe('Shell command pass-through', () => {
1011
+ it('should pass through ctrl+r in INSERT mode', async () => {
1012
+ mockVimContext.vimMode = 'INSERT';
1013
+ const { result } = renderVimHook();
1014
+ await waitFor(() => {
1015
+ expect(result.current.mode).toBe('INSERT');
1016
+ });
1017
+ const handled = result.current.handleInput(createKey({ name: 'r', ctrl: true }));
1018
+ expect(handled).toBe(false);
1019
+ });
1020
+ it('should pass through ! in INSERT mode when buffer is empty', async () => {
1021
+ mockVimContext.vimMode = 'INSERT';
1022
+ const emptyBuffer = createMockBuffer('');
1023
+ const { result } = renderVimHook(emptyBuffer);
1024
+ await waitFor(() => {
1025
+ expect(result.current.mode).toBe('INSERT');
1026
+ });
1027
+ const handled = result.current.handleInput(createKey({ sequence: '!' }));
1028
+ expect(handled).toBe(false);
1029
+ });
1030
+ it('should handle ! as input in INSERT mode when buffer is not empty', async () => {
1031
+ mockVimContext.vimMode = 'INSERT';
1032
+ const nonEmptyBuffer = createMockBuffer('not empty');
1033
+ const { result } = renderVimHook(nonEmptyBuffer);
1034
+ await waitFor(() => {
1035
+ expect(result.current.mode).toBe('INSERT');
1036
+ });
1037
+ const key = createKey({ sequence: '!', name: '!' });
1038
+ act(() => {
1039
+ result.current.handleInput(key);
1040
+ });
1041
+ expect(nonEmptyBuffer.handleInput).toHaveBeenCalledWith(expect.objectContaining(key));
1042
+ });
1043
+ });
1044
+ // Line operations (dd, cc) are tested in text-buffer.test.ts
1045
+ describe('Reducer-based integration tests', () => {
1046
+ const testCases = [
1047
+ {
1048
+ command: 'de',
1049
+ desc: 'delete from cursor to end of current word',
1050
+ lines: ['hello world test'],
1051
+ cursorRow: 0,
1052
+ cursorCol: 1,
1053
+ actionType: 'vim_delete_word_end',
1054
+ count: 1,
1055
+ expectedLines: ['h world test'],
1056
+ expectedCursorRow: 0,
1057
+ expectedCursorCol: 1,
1058
+ },
1059
+ {
1060
+ command: 'de',
1061
+ desc: 'delete multiple word ends with count',
1062
+ lines: ['hello world test more'],
1063
+ cursorRow: 0,
1064
+ cursorCol: 1,
1065
+ actionType: 'vim_delete_word_end',
1066
+ count: 2,
1067
+ expectedLines: ['h test more'],
1068
+ expectedCursorRow: 0,
1069
+ expectedCursorCol: 1,
1070
+ },
1071
+ {
1072
+ command: 'db',
1073
+ desc: 'delete from cursor to start of previous word',
1074
+ lines: ['hello world test'],
1075
+ cursorRow: 0,
1076
+ cursorCol: 11,
1077
+ actionType: 'vim_delete_word_backward',
1078
+ count: 1,
1079
+ expectedLines: ['hello test'],
1080
+ expectedCursorRow: 0,
1081
+ expectedCursorCol: 6,
1082
+ },
1083
+ {
1084
+ command: 'db',
1085
+ desc: 'delete multiple words backward with count',
1086
+ lines: ['hello world test more'],
1087
+ cursorRow: 0,
1088
+ cursorCol: 17,
1089
+ actionType: 'vim_delete_word_backward',
1090
+ count: 2,
1091
+ expectedLines: ['hello more'],
1092
+ expectedCursorRow: 0,
1093
+ expectedCursorCol: 6,
1094
+ },
1095
+ {
1096
+ command: 'cw',
1097
+ desc: 'delete from cursor to start of next word',
1098
+ lines: ['hello world test'],
1099
+ cursorRow: 0,
1100
+ cursorCol: 0,
1101
+ actionType: 'vim_change_word_forward',
1102
+ count: 1,
1103
+ expectedLines: ['world test'],
1104
+ expectedCursorRow: 0,
1105
+ expectedCursorCol: 0,
1106
+ },
1107
+ {
1108
+ command: 'cw',
1109
+ desc: 'change multiple words with count',
1110
+ lines: ['hello world test more'],
1111
+ cursorRow: 0,
1112
+ cursorCol: 0,
1113
+ actionType: 'vim_change_word_forward',
1114
+ count: 2,
1115
+ expectedLines: ['test more'],
1116
+ expectedCursorRow: 0,
1117
+ expectedCursorCol: 0,
1118
+ },
1119
+ {
1120
+ command: 'ce',
1121
+ desc: 'change from cursor to end of current word',
1122
+ lines: ['hello world test'],
1123
+ cursorRow: 0,
1124
+ cursorCol: 1,
1125
+ actionType: 'vim_change_word_end',
1126
+ count: 1,
1127
+ expectedLines: ['h world test'],
1128
+ expectedCursorRow: 0,
1129
+ expectedCursorCol: 1,
1130
+ },
1131
+ {
1132
+ command: 'ce',
1133
+ desc: 'change multiple word ends with count',
1134
+ lines: ['hello world test'],
1135
+ cursorRow: 0,
1136
+ cursorCol: 1,
1137
+ actionType: 'vim_change_word_end',
1138
+ count: 2,
1139
+ expectedLines: ['h test'],
1140
+ expectedCursorRow: 0,
1141
+ expectedCursorCol: 1,
1142
+ },
1143
+ {
1144
+ command: 'cb',
1145
+ desc: 'change from cursor to start of previous word',
1146
+ lines: ['hello world test'],
1147
+ cursorRow: 0,
1148
+ cursorCol: 11,
1149
+ actionType: 'vim_change_word_backward',
1150
+ count: 1,
1151
+ expectedLines: ['hello test'],
1152
+ expectedCursorRow: 0,
1153
+ expectedCursorCol: 6,
1154
+ },
1155
+ {
1156
+ command: 'cc',
1157
+ desc: 'clear the line and place cursor at the start',
1158
+ lines: [' hello world'],
1159
+ cursorRow: 0,
1160
+ cursorCol: 5,
1161
+ actionType: 'vim_change_line',
1162
+ count: 1,
1163
+ expectedLines: [''],
1164
+ expectedCursorRow: 0,
1165
+ expectedCursorCol: 0,
1166
+ },
1167
+ {
1168
+ command: 'dd',
1169
+ desc: 'delete the current line',
1170
+ lines: ['line1', 'line2', 'line3'],
1171
+ cursorRow: 1,
1172
+ cursorCol: 2,
1173
+ actionType: 'vim_delete_line',
1174
+ count: 1,
1175
+ expectedLines: ['line1', 'line3'],
1176
+ expectedCursorRow: 1,
1177
+ expectedCursorCol: 0,
1178
+ },
1179
+ {
1180
+ command: 'dd',
1181
+ desc: 'delete multiple lines with count',
1182
+ lines: ['line1', 'line2', 'line3', 'line4'],
1183
+ cursorRow: 1,
1184
+ cursorCol: 2,
1185
+ actionType: 'vim_delete_line',
1186
+ count: 2,
1187
+ expectedLines: ['line1', 'line4'],
1188
+ expectedCursorRow: 1,
1189
+ expectedCursorCol: 0,
1190
+ },
1191
+ {
1192
+ command: 'dd',
1193
+ desc: 'handle deleting last line',
1194
+ lines: ['only line'],
1195
+ cursorRow: 0,
1196
+ cursorCol: 3,
1197
+ actionType: 'vim_delete_line',
1198
+ count: 1,
1199
+ expectedLines: [''],
1200
+ expectedCursorRow: 0,
1201
+ expectedCursorCol: 0,
1202
+ },
1203
+ {
1204
+ command: 'D',
1205
+ desc: 'delete from cursor to end of line',
1206
+ lines: ['hello world test'],
1207
+ cursorRow: 0,
1208
+ cursorCol: 6,
1209
+ actionType: 'vim_delete_to_end_of_line',
1210
+ expectedLines: ['hello '],
1211
+ expectedCursorRow: 0,
1212
+ expectedCursorCol: 6,
1213
+ },
1214
+ {
1215
+ command: 'D',
1216
+ desc: 'handle D at end of line',
1217
+ lines: ['hello world'],
1218
+ cursorRow: 0,
1219
+ cursorCol: 11,
1220
+ actionType: 'vim_delete_to_end_of_line',
1221
+ expectedLines: ['hello world'],
1222
+ expectedCursorRow: 0,
1223
+ expectedCursorCol: 11,
1224
+ },
1225
+ {
1226
+ command: 'C',
1227
+ desc: 'change from cursor to end of line',
1228
+ lines: ['hello world test'],
1229
+ cursorRow: 0,
1230
+ cursorCol: 6,
1231
+ actionType: 'vim_change_to_end_of_line',
1232
+ expectedLines: ['hello '],
1233
+ expectedCursorRow: 0,
1234
+ expectedCursorCol: 6,
1235
+ },
1236
+ {
1237
+ command: 'C',
1238
+ desc: 'handle C at beginning of line',
1239
+ lines: ['hello world'],
1240
+ cursorRow: 0,
1241
+ cursorCol: 0,
1242
+ actionType: 'vim_change_to_end_of_line',
1243
+ expectedLines: [''],
1244
+ expectedCursorRow: 0,
1245
+ expectedCursorCol: 0,
1246
+ },
1247
+ ];
1248
+ it.each(testCases)('$command: should $desc', ({ lines, cursorRow, cursorCol, actionType, count, expectedLines, expectedCursorRow, expectedCursorCol, }) => {
1249
+ const initialState = createMockTextBufferState({
1250
+ lines,
1251
+ cursorRow,
1252
+ cursorCol,
1253
+ preferredCol: null,
1254
+ undoStack: [],
1255
+ redoStack: [],
1256
+ clipboard: null,
1257
+ selectionAnchor: null,
1258
+ });
1259
+ const action = (count
1260
+ ? { type: actionType, payload: { count } }
1261
+ : { type: actionType });
1262
+ const result = textBufferReducer(initialState, action);
1263
+ expect(result.lines).toEqual(expectedLines);
1264
+ expect(result.cursorRow).toBe(expectedCursorRow);
1265
+ expect(result.cursorCol).toBe(expectedCursorCol);
1266
+ });
1267
+ });
1268
+ });
1269
+ //# sourceMappingURL=vim.test.js.map