@machina.ai/cell-cli 1.11.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 (538) hide show
  1. package/dist/package.json +12 -10
  2. package/dist/src/commands/extensions/disable.d.ts +1 -1
  3. package/dist/src/commands/extensions/disable.js +15 -7
  4. package/dist/src/commands/extensions/disable.js.map +1 -1
  5. package/dist/src/commands/extensions/enable.d.ts +1 -1
  6. package/dist/src/commands/extensions/enable.js +15 -7
  7. package/dist/src/commands/extensions/enable.js.map +1 -1
  8. package/dist/src/commands/extensions/install.js +14 -3
  9. package/dist/src/commands/extensions/install.js.map +1 -1
  10. package/dist/src/commands/extensions/install.test.js +39 -19
  11. package/dist/src/commands/extensions/install.test.js.map +1 -1
  12. package/dist/src/commands/extensions/link.js +14 -3
  13. package/dist/src/commands/extensions/link.js.map +1 -1
  14. package/dist/src/commands/extensions/list.js +13 -4
  15. package/dist/src/commands/extensions/list.js.map +1 -1
  16. package/dist/src/commands/extensions/uninstall.js +13 -2
  17. package/dist/src/commands/extensions/uninstall.js.map +1 -1
  18. package/dist/src/commands/extensions/update.js +18 -13
  19. package/dist/src/commands/extensions/update.js.map +1 -1
  20. package/dist/src/commands/extensions/validate.d.ts +12 -0
  21. package/dist/src/commands/extensions/validate.js +83 -0
  22. package/dist/src/commands/extensions/validate.js.map +1 -0
  23. package/dist/src/commands/extensions/validate.test.js +93 -0
  24. package/dist/src/commands/extensions/validate.test.js.map +1 -0
  25. package/dist/src/commands/extensions.js +3 -0
  26. package/dist/src/commands/extensions.js.map +1 -1
  27. package/dist/src/commands/mcp/add.test.js +3 -0
  28. package/dist/src/commands/mcp/add.test.js.map +1 -1
  29. package/dist/src/commands/mcp/list.js +10 -3
  30. package/dist/src/commands/mcp/list.js.map +1 -1
  31. package/dist/src/commands/mcp/list.test.js +37 -27
  32. package/dist/src/commands/mcp/list.test.js.map +1 -1
  33. package/dist/src/config/auth.js +0 -5
  34. package/dist/src/config/auth.js.map +1 -1
  35. package/dist/src/config/config.d.ts +6 -3
  36. package/dist/src/config/config.js +65 -80
  37. package/dist/src/config/config.js.map +1 -1
  38. package/dist/src/config/config.test.js +235 -212
  39. package/dist/src/config/config.test.js.map +1 -1
  40. package/dist/src/config/extension-manager.d.ts +63 -0
  41. package/dist/src/config/extension-manager.js +450 -0
  42. package/dist/src/config/extension-manager.js.map +1 -0
  43. package/dist/src/config/extension.d.ts +4 -51
  44. package/dist/src/config/extension.js +1 -535
  45. package/dist/src/config/extension.js.map +1 -1
  46. package/dist/src/config/extension.test.js +525 -201
  47. package/dist/src/config/extension.test.js.map +1 -1
  48. package/dist/src/config/extensions/consent.d.ts +38 -0
  49. package/dist/src/config/extensions/consent.js +123 -0
  50. package/dist/src/config/extensions/consent.js.map +1 -0
  51. package/dist/src/config/extensions/extensionEnablement.d.ts +1 -1
  52. package/dist/src/config/extensions/extensionEnablement.js +4 -3
  53. package/dist/src/config/extensions/extensionEnablement.js.map +1 -1
  54. package/dist/src/config/extensions/extensionEnablement.test.js +10 -10
  55. package/dist/src/config/extensions/extensionEnablement.test.js.map +1 -1
  56. package/dist/src/config/extensions/extensionSettings.d.ts +15 -0
  57. package/dist/src/config/extensions/extensionSettings.js +113 -0
  58. package/dist/src/config/extensions/extensionSettings.js.map +1 -0
  59. package/dist/src/config/extensions/extensionSettings.test.d.ts +6 -0
  60. package/dist/src/config/extensions/extensionSettings.test.js +254 -0
  61. package/dist/src/config/extensions/extensionSettings.test.js.map +1 -0
  62. package/dist/src/config/extensions/github.d.ts +2 -2
  63. package/dist/src/config/extensions/github.js +5 -10
  64. package/dist/src/config/extensions/github.js.map +1 -1
  65. package/dist/src/config/extensions/github.test.js +153 -167
  66. package/dist/src/config/extensions/github.test.js.map +1 -1
  67. package/dist/src/config/extensions/github_fetch.d.ts +1 -1
  68. package/dist/src/config/extensions/github_fetch.js +13 -1
  69. package/dist/src/config/extensions/github_fetch.js.map +1 -1
  70. package/dist/src/config/extensions/github_fetch.test.d.ts +6 -0
  71. package/dist/src/config/extensions/github_fetch.test.js +169 -0
  72. package/dist/src/config/extensions/github_fetch.test.js.map +1 -0
  73. package/dist/src/config/extensions/storage.d.ts +14 -0
  74. package/dist/src/config/extensions/storage.js +32 -0
  75. package/dist/src/config/extensions/storage.js.map +1 -0
  76. package/dist/src/config/extensions/update.d.ts +4 -4
  77. package/dist/src/config/extensions/update.js +39 -39
  78. package/dist/src/config/extensions/update.js.map +1 -1
  79. package/dist/src/config/extensions/update.test.js +72 -74
  80. package/dist/src/config/extensions/update.test.js.map +1 -1
  81. package/dist/src/config/extensions/variableSchema.d.ts +0 -6
  82. package/dist/src/config/extensions/variableSchema.js.map +1 -1
  83. package/dist/src/config/extensions/variables.d.ts +4 -0
  84. package/dist/src/config/extensions/variables.js +6 -0
  85. package/dist/src/config/extensions/variables.js.map +1 -1
  86. package/dist/src/config/keyBindings.d.ts +3 -0
  87. package/dist/src/config/keyBindings.js +30 -8
  88. package/dist/src/config/keyBindings.js.map +1 -1
  89. package/dist/src/config/keyBindings.test.js +17 -0
  90. package/dist/src/config/keyBindings.test.js.map +1 -1
  91. package/dist/src/config/policies/read-only.toml +56 -0
  92. package/dist/src/config/policies/write.toml +63 -0
  93. package/dist/src/config/policies/yolo.toml +31 -0
  94. package/dist/src/config/policy-engine.integration.test.js +41 -38
  95. package/dist/src/config/policy-engine.integration.test.js.map +1 -1
  96. package/dist/src/config/policy.d.ts +2 -2
  97. package/dist/src/config/policy.js +10 -148
  98. package/dist/src/config/policy.js.map +1 -1
  99. package/dist/src/config/sandboxConfig.d.ts +1 -1
  100. package/dist/src/config/sandboxConfig.js +6 -3
  101. package/dist/src/config/sandboxConfig.js.map +1 -1
  102. package/dist/src/config/settings.d.ts +2 -1
  103. package/dist/src/config/settings.js +58 -18
  104. package/dist/src/config/settings.js.map +1 -1
  105. package/dist/src/config/settings.test.js +128 -69
  106. package/dist/src/config/settings.test.js.map +1 -1
  107. package/dist/src/config/settingsSchema.d.ts +170 -28
  108. package/dist/src/config/settingsSchema.js +418 -27
  109. package/dist/src/config/settingsSchema.js.map +1 -1
  110. package/dist/src/config/settingsSchema.test.js +42 -1
  111. package/dist/src/config/settingsSchema.test.js.map +1 -1
  112. package/dist/src/config/trustedFolders.d.ts +1 -1
  113. package/dist/src/config/trustedFolders.js +4 -2
  114. package/dist/src/config/trustedFolders.js.map +1 -1
  115. package/dist/src/core/initializer.js +2 -1
  116. package/dist/src/core/initializer.js.map +1 -1
  117. package/dist/src/gemini.d.ts +1 -1
  118. package/dist/src/gemini.js +46 -16
  119. package/dist/src/gemini.js.map +1 -1
  120. package/dist/src/gemini.test.js +88 -30
  121. package/dist/src/gemini.test.js.map +1 -1
  122. package/dist/src/generated/git-commit.d.ts +2 -2
  123. package/dist/src/generated/git-commit.js +2 -2
  124. package/dist/src/nonInteractiveCli.d.ts +9 -1
  125. package/dist/src/nonInteractiveCli.js +114 -7
  126. package/dist/src/nonInteractiveCli.js.map +1 -1
  127. package/dist/src/nonInteractiveCli.test.js +355 -112
  128. package/dist/src/nonInteractiveCli.test.js.map +1 -1
  129. package/dist/src/services/BuiltinCommandLoader.js +4 -0
  130. package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
  131. package/dist/src/services/BuiltinCommandLoader.test.js +22 -0
  132. package/dist/src/services/BuiltinCommandLoader.test.js.map +1 -1
  133. package/dist/src/services/FeedbackService.js +2 -2
  134. package/dist/src/services/FeedbackService.js.map +1 -1
  135. package/dist/src/services/McpPromptLoader.js +2 -2
  136. package/dist/src/services/McpPromptLoader.js.map +1 -1
  137. package/dist/src/services/McpPromptLoader.test.js +4 -2
  138. package/dist/src/services/McpPromptLoader.test.js.map +1 -1
  139. package/dist/src/test-utils/async.d.ts +9 -0
  140. package/dist/src/test-utils/async.js +29 -0
  141. package/dist/src/test-utils/async.js.map +1 -0
  142. package/dist/src/test-utils/createExtension.d.ts +3 -1
  143. package/dist/src/test-utils/createExtension.js +3 -3
  144. package/dist/src/test-utils/createExtension.js.map +1 -1
  145. package/dist/src/test-utils/render.d.ts +16 -2
  146. package/dist/src/test-utils/render.js +66 -4
  147. package/dist/src/test-utils/render.js.map +1 -1
  148. package/dist/src/test-utils/render.test.d.ts +6 -0
  149. package/dist/src/test-utils/render.test.js +79 -0
  150. package/dist/src/test-utils/render.test.js.map +1 -0
  151. package/dist/src/ui/App.test.js +1 -1
  152. package/dist/src/ui/App.test.js.map +1 -1
  153. package/dist/src/ui/AppContainer.js +181 -65
  154. package/dist/src/ui/AppContainer.js.map +1 -1
  155. package/dist/src/ui/AppContainer.test.js +505 -147
  156. package/dist/src/ui/AppContainer.test.js.map +1 -1
  157. package/dist/src/ui/IdeIntegrationNudge.js +1 -1
  158. package/dist/src/ui/IdeIntegrationNudge.js.map +1 -1
  159. package/dist/src/ui/auth/ApiAuthDialog.d.ts +14 -0
  160. package/dist/src/ui/auth/ApiAuthDialog.js +26 -0
  161. package/dist/src/ui/auth/ApiAuthDialog.js.map +1 -0
  162. package/dist/src/ui/auth/ApiAuthDialog.test.d.ts +6 -0
  163. package/dist/src/ui/auth/ApiAuthDialog.test.js +91 -0
  164. package/dist/src/ui/auth/ApiAuthDialog.test.js.map +1 -0
  165. package/dist/src/ui/auth/AuthDialog.js +7 -3
  166. package/dist/src/ui/auth/AuthDialog.js.map +1 -1
  167. package/dist/src/ui/auth/useAuth.d.ts +2 -0
  168. package/dist/src/ui/auth/useAuth.js +31 -2
  169. package/dist/src/ui/auth/useAuth.js.map +1 -1
  170. package/dist/src/ui/colors.js +3 -0
  171. package/dist/src/ui/colors.js.map +1 -1
  172. package/dist/src/ui/commands/directoryCommand.js +1 -1
  173. package/dist/src/ui/commands/directoryCommand.js.map +1 -1
  174. package/dist/src/ui/commands/extensionsCommand.js +64 -11
  175. package/dist/src/ui/commands/extensionsCommand.js.map +1 -1
  176. package/dist/src/ui/commands/extensionsCommand.test.js +72 -1
  177. package/dist/src/ui/commands/extensionsCommand.test.js.map +1 -1
  178. package/dist/src/ui/commands/mcpCommand.js +14 -14
  179. package/dist/src/ui/commands/mcpCommand.js.map +1 -1
  180. package/dist/src/ui/commands/mcpCommand.test.js +4 -0
  181. package/dist/src/ui/commands/mcpCommand.test.js.map +1 -1
  182. package/dist/src/ui/commands/memoryCommand.js +1 -1
  183. package/dist/src/ui/commands/memoryCommand.js.map +1 -1
  184. package/dist/src/ui/commands/memoryCommand.test.js +3 -1
  185. package/dist/src/ui/commands/memoryCommand.test.js.map +1 -1
  186. package/dist/src/ui/commands/policiesCommand.d.ts +7 -0
  187. package/dist/src/ui/commands/policiesCommand.js +59 -0
  188. package/dist/src/ui/commands/policiesCommand.js.map +1 -0
  189. package/dist/src/ui/commands/policiesCommand.test.d.ts +6 -0
  190. package/dist/src/ui/commands/policiesCommand.test.js +83 -0
  191. package/dist/src/ui/commands/policiesCommand.test.js.map +1 -0
  192. package/dist/src/ui/components/AnsiOutput.test.js +1 -1
  193. package/dist/src/ui/components/AnsiOutput.test.js.map +1 -1
  194. package/dist/src/ui/components/AsciiArt.d.ts +3 -3
  195. package/dist/src/ui/components/AsciiArt.js +3 -3
  196. package/dist/src/ui/components/Composer.js +1 -1
  197. package/dist/src/ui/components/Composer.js.map +1 -1
  198. package/dist/src/ui/components/Composer.test.js +5 -2
  199. package/dist/src/ui/components/Composer.test.js.map +1 -1
  200. package/dist/src/ui/components/ConfigInitDisplay.js +4 -6
  201. package/dist/src/ui/components/ConfigInitDisplay.js.map +1 -1
  202. package/dist/src/ui/components/ConsentPrompt.test.js +18 -8
  203. package/dist/src/ui/components/ConsentPrompt.test.js.map +1 -1
  204. package/dist/src/ui/components/ConsoleSummaryDisplay.js +1 -1
  205. package/dist/src/ui/components/ConsoleSummaryDisplay.js.map +1 -1
  206. package/dist/src/ui/components/ContextSummaryDisplay.test.js +11 -6
  207. package/dist/src/ui/components/ContextSummaryDisplay.test.js.map +1 -1
  208. package/dist/src/ui/components/DetailedMessagesDisplay.js +1 -1
  209. package/dist/src/ui/components/DetailedMessagesDisplay.js.map +1 -1
  210. package/dist/src/ui/components/DialogManager.js +4 -0
  211. package/dist/src/ui/components/DialogManager.js.map +1 -1
  212. package/dist/src/ui/components/FolderTrustDialog.test.js +2 -1
  213. package/dist/src/ui/components/FolderTrustDialog.test.js.map +1 -1
  214. package/dist/src/ui/components/Footer.js +4 -3
  215. package/dist/src/ui/components/Footer.js.map +1 -1
  216. package/dist/src/ui/components/Footer.test.js +83 -0
  217. package/dist/src/ui/components/Footer.test.js.map +1 -1
  218. package/dist/src/ui/components/Header.test.js +13 -5
  219. package/dist/src/ui/components/Header.test.js.map +1 -1
  220. package/dist/src/ui/components/Help.test.js +5 -4
  221. package/dist/src/ui/components/Help.test.js.map +1 -1
  222. package/dist/src/ui/components/HistoryItemDisplay.js +1 -1
  223. package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -1
  224. package/dist/src/ui/components/InputPrompt.js +27 -8
  225. package/dist/src/ui/components/InputPrompt.js.map +1 -1
  226. package/dist/src/ui/components/InputPrompt.test.js +776 -727
  227. package/dist/src/ui/components/InputPrompt.test.js.map +1 -1
  228. package/dist/src/ui/components/LoadingIndicator.js +2 -2
  229. package/dist/src/ui/components/LoadingIndicator.js.map +1 -1
  230. package/dist/src/ui/components/LoadingIndicator.test.js +28 -15
  231. package/dist/src/ui/components/LoadingIndicator.test.js.map +1 -1
  232. package/dist/src/ui/components/LoopDetectionConfirmation.js +1 -1
  233. package/dist/src/ui/components/LoopDetectionConfirmation.js.map +1 -1
  234. package/dist/src/ui/components/LoopDetectionConfirmation.test.js +2 -2
  235. package/dist/src/ui/components/LoopDetectionConfirmation.test.js.map +1 -1
  236. package/dist/src/ui/components/MainContent.js +15 -4
  237. package/dist/src/ui/components/MainContent.js.map +1 -1
  238. package/dist/src/ui/components/ModelDialog.js +1 -1
  239. package/dist/src/ui/components/ModelDialog.js.map +1 -1
  240. package/dist/src/ui/components/ModelDialog.test.js +23 -13
  241. package/dist/src/ui/components/ModelDialog.test.js.map +1 -1
  242. package/dist/src/ui/components/ModelStatsDisplay.test.js +1 -1
  243. package/dist/src/ui/components/ModelStatsDisplay.test.js.map +1 -1
  244. package/dist/src/ui/components/Notifications.js +38 -5
  245. package/dist/src/ui/components/Notifications.js.map +1 -1
  246. package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js +2 -2
  247. package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js.map +1 -1
  248. package/dist/src/ui/components/PrepareLabel.test.js +14 -8
  249. package/dist/src/ui/components/PrepareLabel.test.js.map +1 -1
  250. package/dist/src/ui/components/ProQuotaDialog.test.js +14 -6
  251. package/dist/src/ui/components/ProQuotaDialog.test.js.map +1 -1
  252. package/dist/src/ui/components/QueuedMessageDisplay.test.js +11 -6
  253. package/dist/src/ui/components/QueuedMessageDisplay.test.js.map +1 -1
  254. package/dist/src/ui/components/SessionSummaryDisplay.test.js +1 -1
  255. package/dist/src/ui/components/SessionSummaryDisplay.test.js.map +1 -1
  256. package/dist/src/ui/components/SettingsDialog.js +32 -25
  257. package/dist/src/ui/components/SettingsDialog.js.map +1 -1
  258. package/dist/src/ui/components/SettingsDialog.test.js +428 -532
  259. package/dist/src/ui/components/SettingsDialog.test.js.map +1 -1
  260. package/dist/src/ui/components/ShellConfirmationDialog.js +1 -1
  261. package/dist/src/ui/components/ShellConfirmationDialog.js.map +1 -1
  262. package/dist/src/ui/components/ShellConfirmationDialog.test.js +2 -2
  263. package/dist/src/ui/components/ShellConfirmationDialog.test.js.map +1 -1
  264. package/dist/src/ui/components/StatsDisplay.test.js +1 -1
  265. package/dist/src/ui/components/StatsDisplay.test.js.map +1 -1
  266. package/dist/src/ui/components/SuggestionsDisplay.js +1 -1
  267. package/dist/src/ui/components/SuggestionsDisplay.js.map +1 -1
  268. package/dist/src/ui/components/ThemeDialog.test.js +2 -2
  269. package/dist/src/ui/components/ThemeDialog.test.js.map +1 -1
  270. package/dist/src/ui/components/ToolStatsDisplay.test.js +1 -1
  271. package/dist/src/ui/components/ToolStatsDisplay.test.js.map +1 -1
  272. package/dist/src/ui/components/messages/CompressionMessage.test.js +25 -17
  273. package/dist/src/ui/components/messages/CompressionMessage.test.js.map +1 -1
  274. package/dist/src/ui/components/messages/DiffRenderer.test.js +1 -1
  275. package/dist/src/ui/components/messages/DiffRenderer.test.js.map +1 -1
  276. package/dist/src/ui/components/messages/InfoMessage.js +1 -1
  277. package/dist/src/ui/components/messages/InfoMessage.js.map +1 -1
  278. package/dist/src/ui/components/messages/Todo.js +27 -5
  279. package/dist/src/ui/components/messages/Todo.js.map +1 -1
  280. package/dist/src/ui/components/messages/Todo.test.js +20 -8
  281. package/dist/src/ui/components/messages/Todo.test.js.map +1 -1
  282. package/dist/src/ui/components/messages/ToolConfirmationMessage.js +1 -1
  283. package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
  284. package/dist/src/ui/components/messages/ToolGroupMessage.test.js +29 -15
  285. package/dist/src/ui/components/messages/ToolGroupMessage.test.js.map +1 -1
  286. package/dist/src/ui/components/messages/WarningMessage.js +2 -2
  287. package/dist/src/ui/components/messages/WarningMessage.js.map +1 -1
  288. package/dist/src/ui/components/shared/BaseSelectionList.test.js +1 -1
  289. package/dist/src/ui/components/shared/BaseSelectionList.test.js.map +1 -1
  290. package/dist/src/ui/components/shared/MaxSizedBox.test.js +43 -22
  291. package/dist/src/ui/components/shared/MaxSizedBox.test.js.map +1 -1
  292. package/dist/src/ui/components/shared/TextInput.d.ts +15 -0
  293. package/dist/src/ui/components/shared/TextInput.js +38 -0
  294. package/dist/src/ui/components/shared/TextInput.js.map +1 -0
  295. package/dist/src/ui/components/shared/TextInput.test.d.ts +6 -0
  296. package/dist/src/ui/components/shared/TextInput.test.js +242 -0
  297. package/dist/src/ui/components/shared/TextInput.test.js.map +1 -0
  298. package/dist/src/ui/components/shared/text-buffer.d.ts +9 -2
  299. package/dist/src/ui/components/shared/text-buffer.js +51 -13
  300. package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
  301. package/dist/src/ui/components/shared/text-buffer.test.js +385 -202
  302. package/dist/src/ui/components/shared/text-buffer.test.js.map +1 -1
  303. package/dist/src/ui/components/views/ChatList.test.js +7 -4
  304. package/dist/src/ui/components/views/ChatList.test.js.map +1 -1
  305. package/dist/src/ui/components/views/ExtensionsList.d.ts +7 -1
  306. package/dist/src/ui/components/views/ExtensionsList.js +9 -11
  307. package/dist/src/ui/components/views/ExtensionsList.js.map +1 -1
  308. package/dist/src/ui/components/views/ExtensionsList.test.js +43 -22
  309. package/dist/src/ui/components/views/ExtensionsList.test.js.map +1 -1
  310. package/dist/src/ui/components/views/McpStatus.test.js +23 -12
  311. package/dist/src/ui/components/views/McpStatus.test.js.map +1 -1
  312. package/dist/src/ui/contexts/KeypressContext.d.ts +3 -2
  313. package/dist/src/ui/contexts/KeypressContext.js +610 -540
  314. package/dist/src/ui/contexts/KeypressContext.js.map +1 -1
  315. package/dist/src/ui/contexts/KeypressContext.test.js +438 -718
  316. package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
  317. package/dist/src/ui/contexts/MouseContext.d.ts +21 -0
  318. package/dist/src/ui/contexts/MouseContext.js +89 -0
  319. package/dist/src/ui/contexts/MouseContext.js.map +1 -0
  320. package/dist/src/ui/contexts/MouseContext.test.d.ts +6 -0
  321. package/dist/src/ui/contexts/MouseContext.test.js +164 -0
  322. package/dist/src/ui/contexts/MouseContext.test.js.map +1 -0
  323. package/dist/src/ui/contexts/SessionContext.test.js +35 -17
  324. package/dist/src/ui/contexts/SessionContext.test.js.map +1 -1
  325. package/dist/src/ui/contexts/UIActionsContext.d.ts +2 -0
  326. package/dist/src/ui/contexts/UIActionsContext.js.map +1 -1
  327. package/dist/src/ui/contexts/UIStateContext.d.ts +2 -0
  328. package/dist/src/ui/contexts/UIStateContext.js.map +1 -1
  329. package/dist/src/ui/hooks/atCommandProcessor.js +31 -9
  330. package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
  331. package/dist/src/ui/hooks/atCommandProcessor.test.js +163 -64
  332. package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -1
  333. package/dist/src/ui/hooks/shellCommandProcessor.test.js +64 -35
  334. package/dist/src/ui/hooks/shellCommandProcessor.test.js.map +1 -1
  335. package/dist/src/ui/hooks/slashCommandProcessor.test.js +193 -165
  336. package/dist/src/ui/hooks/slashCommandProcessor.test.js.map +1 -1
  337. package/dist/src/ui/hooks/useAtCompletion.test.js +16 -5
  338. package/dist/src/ui/hooks/useAtCompletion.test.js.map +1 -1
  339. package/dist/src/ui/hooks/useAutoAcceptIndicator.js +10 -0
  340. package/dist/src/ui/hooks/useAutoAcceptIndicator.js.map +1 -1
  341. package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js +32 -1
  342. package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js.map +1 -1
  343. package/dist/src/ui/hooks/useCommandCompletion.test.js +66 -64
  344. package/dist/src/ui/hooks/useCommandCompletion.test.js.map +1 -1
  345. package/dist/src/ui/hooks/useConsoleMessages.test.js +26 -9
  346. package/dist/src/ui/hooks/useConsoleMessages.test.js.map +1 -1
  347. package/dist/src/ui/hooks/useEditorSettings.test.js +40 -34
  348. package/dist/src/ui/hooks/useEditorSettings.test.js.map +1 -1
  349. package/dist/src/ui/hooks/useExtensionUpdates.d.ts +14 -5
  350. package/dist/src/ui/hooks/useExtensionUpdates.js +18 -13
  351. package/dist/src/ui/hooks/useExtensionUpdates.js.map +1 -1
  352. package/dist/src/ui/hooks/useExtensionUpdates.test.js +49 -44
  353. package/dist/src/ui/hooks/useExtensionUpdates.test.js.map +1 -1
  354. package/dist/src/ui/hooks/useFlickerDetector.test.js +9 -5
  355. package/dist/src/ui/hooks/useFlickerDetector.test.js.map +1 -1
  356. package/dist/src/ui/hooks/useFocus.test.js +25 -9
  357. package/dist/src/ui/hooks/useFocus.test.js.map +1 -1
  358. package/dist/src/ui/hooks/useFolderTrust.test.js +46 -22
  359. package/dist/src/ui/hooks/useFolderTrust.test.js.map +1 -1
  360. package/dist/src/ui/hooks/useGeminiStream.js +56 -19
  361. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  362. package/dist/src/ui/hooks/useGeminiStream.test.js +260 -411
  363. package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -1
  364. package/dist/src/ui/hooks/useGitBranchName.js +4 -0
  365. package/dist/src/ui/hooks/useGitBranchName.js.map +1 -1
  366. package/dist/src/ui/hooks/useGitBranchName.test.js +46 -34
  367. package/dist/src/ui/hooks/useGitBranchName.test.js.map +1 -1
  368. package/dist/src/ui/hooks/useHistoryManager.test.js +2 -1
  369. package/dist/src/ui/hooks/useHistoryManager.test.js.map +1 -1
  370. package/dist/src/ui/hooks/useIdeTrustListener.test.js +40 -9
  371. package/dist/src/ui/hooks/useIdeTrustListener.test.js.map +1 -1
  372. package/dist/src/ui/hooks/useInputHistory.test.js +2 -1
  373. package/dist/src/ui/hooks/useInputHistory.test.js.map +1 -1
  374. package/dist/src/ui/hooks/useInputHistoryStore.test.js +2 -1
  375. package/dist/src/ui/hooks/useInputHistoryStore.test.js.map +1 -1
  376. package/dist/src/ui/hooks/useKeypress.test.js +103 -114
  377. package/dist/src/ui/hooks/useKeypress.test.js.map +1 -1
  378. package/dist/src/ui/hooks/useLoadingIndicator.test.js +24 -6
  379. package/dist/src/ui/hooks/useLoadingIndicator.test.js.map +1 -1
  380. package/dist/src/ui/hooks/useMemoryMonitor.test.js +10 -5
  381. package/dist/src/ui/hooks/useMemoryMonitor.test.js.map +1 -1
  382. package/dist/src/ui/hooks/useMessageQueue.test.js +62 -45
  383. package/dist/src/ui/hooks/useMessageQueue.test.js.map +1 -1
  384. package/dist/src/ui/hooks/useModelCommand.test.js +21 -11
  385. package/dist/src/ui/hooks/useModelCommand.test.js.map +1 -1
  386. package/dist/src/ui/hooks/useMouse.d.ts +17 -0
  387. package/dist/src/ui/hooks/useMouse.js +27 -0
  388. package/dist/src/ui/hooks/useMouse.js.map +1 -0
  389. package/dist/src/ui/hooks/useMouse.test.d.ts +6 -0
  390. package/dist/src/ui/hooks/useMouse.test.js +57 -0
  391. package/dist/src/ui/hooks/useMouse.test.js.map +1 -0
  392. package/dist/src/ui/hooks/usePermissionsModifyTrust.test.js +2 -2
  393. package/dist/src/ui/hooks/usePermissionsModifyTrust.test.js.map +1 -1
  394. package/dist/src/ui/hooks/usePhraseCycler.js +1 -1
  395. package/dist/src/ui/hooks/usePhraseCycler.js.map +1 -1
  396. package/dist/src/ui/hooks/usePhraseCycler.test.js +109 -106
  397. package/dist/src/ui/hooks/usePhraseCycler.test.js.map +1 -1
  398. package/dist/src/ui/hooks/usePrivacySettings.test.js +26 -6
  399. package/dist/src/ui/hooks/usePrivacySettings.test.js.map +1 -1
  400. package/dist/src/ui/hooks/usePromptCompletion.js +2 -2
  401. package/dist/src/ui/hooks/usePromptCompletion.js.map +1 -1
  402. package/dist/src/ui/hooks/useQuotaAndFallback.js +13 -14
  403. package/dist/src/ui/hooks/useQuotaAndFallback.js.map +1 -1
  404. package/dist/src/ui/hooks/useQuotaAndFallback.test.js +55 -48
  405. package/dist/src/ui/hooks/useQuotaAndFallback.test.js.map +1 -1
  406. package/dist/src/ui/hooks/useReactToolScheduler.d.ts +8 -1
  407. package/dist/src/ui/hooks/useReactToolScheduler.js +59 -34
  408. package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -1
  409. package/dist/src/ui/hooks/useReactToolScheduler.test.d.ts +6 -0
  410. package/dist/src/ui/hooks/useReactToolScheduler.test.js +65 -0
  411. package/dist/src/ui/hooks/useReactToolScheduler.test.js.map +1 -0
  412. package/dist/src/ui/hooks/useReverseSearchCompletion.test.js +2 -2
  413. package/dist/src/ui/hooks/useReverseSearchCompletion.test.js.map +1 -1
  414. package/dist/src/ui/hooks/useSelectionList.js +5 -4
  415. package/dist/src/ui/hooks/useSelectionList.js.map +1 -1
  416. package/dist/src/ui/hooks/useSelectionList.test.js +272 -183
  417. package/dist/src/ui/hooks/useSelectionList.test.js.map +1 -1
  418. package/dist/src/ui/hooks/useShellHistory.test.js +52 -20
  419. package/dist/src/ui/hooks/useShellHistory.test.js.map +1 -1
  420. package/dist/src/ui/hooks/useSlashCompletion.js +18 -7
  421. package/dist/src/ui/hooks/useSlashCompletion.js.map +1 -1
  422. package/dist/src/ui/hooks/useSlashCompletion.test.js +275 -137
  423. package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
  424. package/dist/src/ui/hooks/useTimer.test.js +43 -14
  425. package/dist/src/ui/hooks/useTimer.test.js.map +1 -1
  426. package/dist/src/ui/hooks/useToolScheduler.test.js +226 -242
  427. package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
  428. package/dist/src/ui/hooks/vim.test.js +235 -355
  429. package/dist/src/ui/hooks/vim.test.js.map +1 -1
  430. package/dist/src/ui/keyMatchers.test.js +30 -3
  431. package/dist/src/ui/keyMatchers.test.js.map +1 -1
  432. package/dist/src/ui/state/extensions.d.ts +1 -0
  433. package/dist/src/ui/state/extensions.js +1 -0
  434. package/dist/src/ui/state/extensions.js.map +1 -1
  435. package/dist/src/ui/themes/ansi-light.js +1 -0
  436. package/dist/src/ui/themes/ansi-light.js.map +1 -1
  437. package/dist/src/ui/themes/ansi.js +1 -0
  438. package/dist/src/ui/themes/ansi.js.map +1 -1
  439. package/dist/src/ui/themes/atom-one-dark.js +2 -0
  440. package/dist/src/ui/themes/atom-one-dark.js.map +1 -1
  441. package/dist/src/ui/themes/ayu-light.js +2 -0
  442. package/dist/src/ui/themes/ayu-light.js.map +1 -1
  443. package/dist/src/ui/themes/ayu.js +2 -0
  444. package/dist/src/ui/themes/ayu.js.map +1 -1
  445. package/dist/src/ui/themes/color-utils.d.ts +1 -0
  446. package/dist/src/ui/themes/color-utils.js +6 -0
  447. package/dist/src/ui/themes/color-utils.js.map +1 -1
  448. package/dist/src/ui/themes/color-utils.test.js +13 -1
  449. package/dist/src/ui/themes/color-utils.test.js.map +1 -1
  450. package/dist/src/ui/themes/dracula.js +2 -0
  451. package/dist/src/ui/themes/dracula.js.map +1 -1
  452. package/dist/src/ui/themes/github-dark.js +2 -0
  453. package/dist/src/ui/themes/github-dark.js.map +1 -1
  454. package/dist/src/ui/themes/github-light.js +2 -0
  455. package/dist/src/ui/themes/github-light.js.map +1 -1
  456. package/dist/src/ui/themes/googlecode.js +2 -0
  457. package/dist/src/ui/themes/googlecode.js.map +1 -1
  458. package/dist/src/ui/themes/no-color.js +3 -0
  459. package/dist/src/ui/themes/no-color.js.map +1 -1
  460. package/dist/src/ui/themes/semantic-tokens.d.ts +2 -0
  461. package/dist/src/ui/themes/semantic-tokens.js +6 -0
  462. package/dist/src/ui/themes/semantic-tokens.js.map +1 -1
  463. package/dist/src/ui/themes/shades-of-purple.js +2 -0
  464. package/dist/src/ui/themes/shades-of-purple.js.map +1 -1
  465. package/dist/src/ui/themes/theme.d.ts +3 -0
  466. package/dist/src/ui/themes/theme.js +14 -3
  467. package/dist/src/ui/themes/theme.js.map +1 -1
  468. package/dist/src/ui/themes/theme.test.js +67 -1
  469. package/dist/src/ui/themes/theme.test.js.map +1 -1
  470. package/dist/src/ui/themes/xcode.js +2 -0
  471. package/dist/src/ui/themes/xcode.js.map +1 -1
  472. package/dist/src/ui/types.d.ts +3 -1
  473. package/dist/src/ui/types.js +2 -0
  474. package/dist/src/ui/types.js.map +1 -1
  475. package/dist/src/ui/utils/CodeColorizer.js +2 -1
  476. package/dist/src/ui/utils/CodeColorizer.js.map +1 -1
  477. package/dist/src/ui/utils/InlineMarkdownRenderer.d.ts +1 -0
  478. package/dist/src/ui/utils/InlineMarkdownRenderer.js +11 -10
  479. package/dist/src/ui/utils/InlineMarkdownRenderer.js.map +1 -1
  480. package/dist/src/ui/utils/MarkdownDisplay.js +11 -9
  481. package/dist/src/ui/utils/MarkdownDisplay.js.map +1 -1
  482. package/dist/src/ui/utils/clipboardUtils.js +2 -2
  483. package/dist/src/ui/utils/clipboardUtils.js.map +1 -1
  484. package/dist/src/ui/utils/input.d.ts +17 -0
  485. package/dist/src/ui/utils/input.js +51 -0
  486. package/dist/src/ui/utils/input.js.map +1 -0
  487. package/dist/src/ui/utils/input.test.d.ts +6 -0
  488. package/dist/src/ui/utils/input.test.js +44 -0
  489. package/dist/src/ui/utils/input.test.js.map +1 -0
  490. package/dist/src/ui/utils/kittyProtocolDetector.js +13 -4
  491. package/dist/src/ui/utils/kittyProtocolDetector.js.map +1 -1
  492. package/dist/src/ui/utils/mouse.d.ts +31 -0
  493. package/dist/src/ui/utils/mouse.js +164 -0
  494. package/dist/src/ui/utils/mouse.js.map +1 -0
  495. package/dist/src/ui/utils/mouse.test.d.ts +6 -0
  496. package/dist/src/ui/utils/mouse.test.js +131 -0
  497. package/dist/src/ui/utils/mouse.test.js.map +1 -0
  498. package/dist/src/ui/utils/textOutput.d.ts +25 -0
  499. package/dist/src/ui/utils/textOutput.js +49 -0
  500. package/dist/src/ui/utils/textOutput.js.map +1 -0
  501. package/dist/src/ui/utils/textOutput.test.d.ts +6 -0
  502. package/dist/src/ui/utils/textOutput.test.js +79 -0
  503. package/dist/src/ui/utils/textOutput.test.js.map +1 -0
  504. package/dist/src/ui/utils/updateCheck.d.ts +7 -1
  505. package/dist/src/ui/utils/updateCheck.js +33 -29
  506. package/dist/src/ui/utils/updateCheck.js.map +1 -1
  507. package/dist/src/ui/utils/updateCheck.test.js +24 -50
  508. package/dist/src/ui/utils/updateCheck.test.js.map +1 -1
  509. package/dist/src/utils/commentJson.js +2 -2
  510. package/dist/src/utils/commentJson.js.map +1 -1
  511. package/dist/src/utils/commentJson.test.js +7 -6
  512. package/dist/src/utils/commentJson.test.js.map +1 -1
  513. package/dist/src/utils/envVarResolver.d.ts +2 -2
  514. package/dist/src/utils/envVarResolver.js +10 -7
  515. package/dist/src/utils/envVarResolver.js.map +1 -1
  516. package/dist/src/utils/events.d.ts +11 -2
  517. package/dist/src/utils/events.js +1 -0
  518. package/dist/src/utils/events.js.map +1 -1
  519. package/dist/src/utils/handleAutoUpdate.js +9 -3
  520. package/dist/src/utils/handleAutoUpdate.js.map +1 -1
  521. package/dist/src/utils/sandbox.js +16 -18
  522. package/dist/src/utils/sandbox.js.map +1 -1
  523. package/dist/src/utils/version.js +6 -2
  524. package/dist/src/utils/version.js.map +1 -1
  525. package/dist/src/zed-integration/acp.js +2 -1
  526. package/dist/src/zed-integration/acp.js.map +1 -1
  527. package/dist/src/zed-integration/schema.d.ts +4 -4
  528. package/dist/src/zed-integration/zedIntegration.d.ts +2 -2
  529. package/dist/src/zed-integration/zedIntegration.js +12 -19
  530. package/dist/src/zed-integration/zedIntegration.js.map +1 -1
  531. package/dist/tsconfig.tsbuildinfo +1 -1
  532. package/package.json +14 -14
  533. package/dist/src/config/policy.test.js +0 -360
  534. package/dist/src/config/policy.test.js.map +0 -1
  535. package/dist/src/utils/package.d.ts +0 -12
  536. package/dist/src/utils/package.js +0 -24
  537. package/dist/src/utils/package.js.map +0 -1
  538. /package/dist/src/{config/policy.test.d.ts → commands/extensions/validate.test.d.ts} +0 -0
@@ -5,7 +5,8 @@
5
5
  */
6
6
  import { describe, it, expect, beforeEach } from 'vitest';
7
7
  import stripAnsi from 'strip-ansi';
8
- import { renderHook, act } from '@testing-library/react';
8
+ import { act } from 'react';
9
+ import { renderHook } from '../../../test-utils/render.js';
9
10
  import { useTextBuffer, offsetToLogicalPos, logicalPosToOffset, textBufferReducer, findWordEndInLine, findNextWordStartInLine, isWordCharStrict, } from './text-buffer.js';
10
11
  import { cpLen } from '../../utils/textUtils.js';
11
12
  const defaultVisualLayout = {
@@ -76,6 +77,40 @@ describe('textBufferReducer', () => {
76
77
  expect(state.cursorCol).toBe(0);
77
78
  });
78
79
  });
80
+ describe('insert action with options', () => {
81
+ it('should filter input using inputFilter option', () => {
82
+ const action = { type: 'insert', payload: 'a1b2c3' };
83
+ const options = {
84
+ inputFilter: (text) => text.replace(/[0-9]/g, ''),
85
+ };
86
+ const state = textBufferReducer(initialState, action, options);
87
+ expect(state.lines).toEqual(['abc']);
88
+ expect(state.cursorCol).toBe(3);
89
+ });
90
+ it('should strip newlines when singleLine option is true', () => {
91
+ const action = {
92
+ type: 'insert',
93
+ payload: 'hello\nworld',
94
+ };
95
+ const options = { singleLine: true };
96
+ const state = textBufferReducer(initialState, action, options);
97
+ expect(state.lines).toEqual(['helloworld']);
98
+ expect(state.cursorCol).toBe(10);
99
+ });
100
+ it('should apply both inputFilter and singleLine options', () => {
101
+ const action = {
102
+ type: 'insert',
103
+ payload: 'h\ne\nl\nl\no\n1\n2\n3',
104
+ };
105
+ const options = {
106
+ singleLine: true,
107
+ inputFilter: (text) => text.replace(/[0-9]/g, ''),
108
+ };
109
+ const state = textBufferReducer(initialState, action, options);
110
+ expect(state.lines).toEqual(['hello']);
111
+ expect(state.cursorCol).toBe(5);
112
+ });
113
+ });
79
114
  describe('backspace action', () => {
80
115
  it('should remove a character', () => {
81
116
  const stateWithText = {
@@ -153,41 +188,38 @@ describe('textBufferReducer', () => {
153
188
  });
154
189
  });
155
190
  describe('delete_word_left action', () => {
156
- it('should delete a simple word', () => {
157
- const stateWithText = {
158
- ...initialState,
159
- lines: ['hello world'],
160
- cursorRow: 0,
191
+ const createSingleLineState = (text, col) => ({
192
+ ...initialState,
193
+ lines: [text],
194
+ cursorRow: 0,
195
+ cursorCol: col,
196
+ });
197
+ it.each([
198
+ {
199
+ input: 'hello world',
161
200
  cursorCol: 11,
162
- };
163
- const action = { type: 'delete_word_left' };
164
- const state = textBufferReducer(stateWithText, action);
165
- expect(state.lines).toEqual(['hello ']);
166
- expect(state.cursorCol).toBe(6);
167
- });
168
- it('should delete a path segment', () => {
169
- const stateWithText = {
170
- ...initialState,
171
- lines: ['path/to/file'],
172
- cursorRow: 0,
201
+ expectedLines: ['hello '],
202
+ expectedCol: 6,
203
+ desc: 'simple word',
204
+ },
205
+ {
206
+ input: 'path/to/file',
173
207
  cursorCol: 12,
174
- };
175
- const action = { type: 'delete_word_left' };
176
- const state = textBufferReducer(stateWithText, action);
177
- expect(state.lines).toEqual(['path/to/']);
178
- expect(state.cursorCol).toBe(8);
179
- });
180
- it('should delete variable_name parts', () => {
181
- const stateWithText = {
182
- ...initialState,
183
- lines: ['variable_name'],
184
- cursorRow: 0,
208
+ expectedLines: ['path/to/'],
209
+ expectedCol: 8,
210
+ desc: 'path segment',
211
+ },
212
+ {
213
+ input: 'variable_name',
185
214
  cursorCol: 13,
186
- };
187
- const action = { type: 'delete_word_left' };
188
- const state = textBufferReducer(stateWithText, action);
189
- expect(state.lines).toEqual(['variable_']);
190
- expect(state.cursorCol).toBe(9);
215
+ expectedLines: ['variable_'],
216
+ expectedCol: 9,
217
+ desc: 'variable_name parts',
218
+ },
219
+ ])('should delete $desc', ({ input, cursorCol, expectedLines, expectedCol }) => {
220
+ const state = textBufferReducer(createSingleLineState(input, cursorCol), { type: 'delete_word_left' });
221
+ expect(state.lines).toEqual(expectedLines);
222
+ expect(state.cursorCol).toBe(expectedCol);
191
223
  });
192
224
  it('should act like backspace at the beginning of a line', () => {
193
225
  const stateWithText = {
@@ -196,51 +228,55 @@ describe('textBufferReducer', () => {
196
228
  cursorRow: 1,
197
229
  cursorCol: 0,
198
230
  };
199
- const action = { type: 'delete_word_left' };
200
- const state = textBufferReducer(stateWithText, action);
231
+ const state = textBufferReducer(stateWithText, {
232
+ type: 'delete_word_left',
233
+ });
201
234
  expect(state.lines).toEqual(['helloworld']);
202
235
  expect(state.cursorRow).toBe(0);
203
236
  expect(state.cursorCol).toBe(5);
204
237
  });
205
238
  });
206
239
  describe('delete_word_right action', () => {
207
- it('should delete a simple word', () => {
208
- const stateWithText = {
209
- ...initialState,
210
- lines: ['hello world'],
211
- cursorRow: 0,
240
+ const createSingleLineState = (text, col) => ({
241
+ ...initialState,
242
+ lines: [text],
243
+ cursorRow: 0,
244
+ cursorCol: col,
245
+ });
246
+ it.each([
247
+ {
248
+ input: 'hello world',
212
249
  cursorCol: 0,
213
- };
214
- const action = { type: 'delete_word_right' };
215
- const state = textBufferReducer(stateWithText, action);
216
- expect(state.lines).toEqual(['world']);
217
- expect(state.cursorCol).toBe(0);
218
- });
219
- it('should delete a path segment', () => {
250
+ expectedLines: ['world'],
251
+ expectedCol: 0,
252
+ desc: 'simple word',
253
+ },
254
+ {
255
+ input: 'variable_name',
256
+ cursorCol: 0,
257
+ expectedLines: ['_name'],
258
+ expectedCol: 0,
259
+ desc: 'variable_name parts',
260
+ },
261
+ ])('should delete $desc', ({ input, cursorCol, expectedLines, expectedCol }) => {
262
+ const state = textBufferReducer(createSingleLineState(input, cursorCol), { type: 'delete_word_right' });
263
+ expect(state.lines).toEqual(expectedLines);
264
+ expect(state.cursorCol).toBe(expectedCol);
265
+ });
266
+ it('should delete path segments progressively', () => {
220
267
  const stateWithText = {
221
268
  ...initialState,
222
269
  lines: ['path/to/file'],
223
270
  cursorRow: 0,
224
271
  cursorCol: 0,
225
272
  };
226
- const action = { type: 'delete_word_right' };
227
- let state = textBufferReducer(stateWithText, action);
273
+ let state = textBufferReducer(stateWithText, {
274
+ type: 'delete_word_right',
275
+ });
228
276
  expect(state.lines).toEqual(['/to/file']);
229
- state = textBufferReducer(state, action);
277
+ state = textBufferReducer(state, { type: 'delete_word_right' });
230
278
  expect(state.lines).toEqual(['to/file']);
231
279
  });
232
- it('should delete variable_name parts', () => {
233
- const stateWithText = {
234
- ...initialState,
235
- lines: ['variable_name'],
236
- cursorRow: 0,
237
- cursorCol: 0,
238
- };
239
- const action = { type: 'delete_word_right' };
240
- const state = textBufferReducer(stateWithText, action);
241
- expect(state.lines).toEqual(['_name']);
242
- expect(state.cursorCol).toBe(0);
243
- });
244
280
  it('should act like delete at the end of a line', () => {
245
281
  const stateWithText = {
246
282
  ...initialState,
@@ -248,15 +284,15 @@ describe('textBufferReducer', () => {
248
284
  cursorRow: 0,
249
285
  cursorCol: 5,
250
286
  };
251
- const action = { type: 'delete_word_right' };
252
- const state = textBufferReducer(stateWithText, action);
287
+ const state = textBufferReducer(stateWithText, {
288
+ type: 'delete_word_right',
289
+ });
253
290
  expect(state.lines).toEqual(['helloworld']);
254
291
  expect(state.cursorRow).toBe(0);
255
292
  expect(state.cursorCol).toBe(5);
256
293
  });
257
294
  });
258
295
  });
259
- // Helper to get the state from the hook
260
296
  const getBufferState = (result) => {
261
297
  expect(result.current).toHaveOnlyValidCharacters();
262
298
  return {
@@ -1094,71 +1130,46 @@ Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots
1094
1130
  });
1095
1131
  });
1096
1132
  describe('Input Sanitization', () => {
1097
- it('should strip ANSI escape codes from input', () => {
1098
- const { result } = renderHook(() => useTextBuffer({ viewport, isValidPath: () => false }));
1099
- const textWithAnsi = '\x1B[31mHello\x1B[0m \x1B[32mWorld\x1B[0m';
1100
- act(() => result.current.handleInput({
1101
- name: '',
1102
- ctrl: false,
1103
- meta: false,
1104
- shift: false,
1105
- paste: false,
1106
- sequence: textWithAnsi,
1107
- }));
1108
- expect(getBufferState(result).text).toBe('Hello World');
1109
- });
1110
- it('should strip control characters from input', () => {
1133
+ const createInput = (sequence) => ({
1134
+ name: '',
1135
+ ctrl: false,
1136
+ meta: false,
1137
+ shift: false,
1138
+ paste: false,
1139
+ sequence,
1140
+ });
1141
+ it.each([
1142
+ {
1143
+ input: '\x1B[31mHello\x1B[0m \x1B[32mWorld\x1B[0m',
1144
+ expected: 'Hello World',
1145
+ desc: 'ANSI escape codes',
1146
+ },
1147
+ {
1148
+ input: 'H\x07e\x08l\x0Bl\x0Co',
1149
+ expected: 'Hello',
1150
+ desc: 'control characters',
1151
+ },
1152
+ {
1153
+ input: '\u001B[4mH\u001B[0mello',
1154
+ expected: 'Hello',
1155
+ desc: 'mixed ANSI and control characters',
1156
+ },
1157
+ {
1158
+ input: '\u001B[4mPasted\u001B[4m Text',
1159
+ expected: 'Pasted Text',
1160
+ desc: 'pasted text with ANSI',
1161
+ },
1162
+ ])('should strip $desc from input', ({ input, expected }) => {
1111
1163
  const { result } = renderHook(() => useTextBuffer({ viewport, isValidPath: () => false }));
1112
- const textWithControlChars = 'H\x07e\x08l\x0Bl\x0Co'; // BELL, BACKSPACE, VT, FF
1113
- act(() => result.current.handleInput({
1114
- name: '',
1115
- ctrl: false,
1116
- meta: false,
1117
- shift: false,
1118
- paste: false,
1119
- sequence: textWithControlChars,
1120
- }));
1121
- expect(getBufferState(result).text).toBe('Hello');
1122
- });
1123
- it('should strip mixed ANSI and control characters from input', () => {
1124
- const { result } = renderHook(() => useTextBuffer({ viewport, isValidPath: () => false }));
1125
- const textWithMixed = '\u001B[4mH\u001B[0mello';
1126
- act(() => result.current.handleInput({
1127
- name: '',
1128
- ctrl: false,
1129
- meta: false,
1130
- shift: false,
1131
- paste: false,
1132
- sequence: textWithMixed,
1133
- }));
1134
- expect(getBufferState(result).text).toBe('Hello');
1164
+ act(() => result.current.handleInput(createInput(input)));
1165
+ expect(getBufferState(result).text).toBe(expected);
1135
1166
  });
1136
1167
  it('should not strip standard characters or newlines', () => {
1137
1168
  const { result } = renderHook(() => useTextBuffer({ viewport, isValidPath: () => false }));
1138
1169
  const validText = 'Hello World\nThis is a test.';
1139
- act(() => result.current.handleInput({
1140
- name: '',
1141
- ctrl: false,
1142
- meta: false,
1143
- shift: false,
1144
- paste: false,
1145
- sequence: validText,
1146
- }));
1170
+ act(() => result.current.handleInput(createInput(validText)));
1147
1171
  expect(getBufferState(result).text).toBe(validText);
1148
1172
  });
1149
- it('should sanitize pasted text via handleInput', () => {
1150
- const { result } = renderHook(() => useTextBuffer({ viewport, isValidPath: () => false }));
1151
- const pastedText = '\u001B[4mPasted\u001B[4m Text';
1152
- act(() => result.current.handleInput({
1153
- name: '',
1154
- ctrl: false,
1155
- meta: false,
1156
- shift: false,
1157
- paste: false,
1158
- sequence: pastedText,
1159
- }));
1160
- expect(getBufferState(result).text).toBe('Pasted Text');
1161
- });
1162
1173
  it('should sanitize large text (>5000 chars) and strip unsafe characters', () => {
1163
1174
  const { result } = renderHook(() => useTextBuffer({ viewport, isValidPath: () => false }));
1164
1175
  const unsafeChars = '\x07\x08\x0B\x0C';
@@ -1218,6 +1229,55 @@ Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots
1218
1229
  expect(getBufferState(result).text).toBe(emojis);
1219
1230
  });
1220
1231
  });
1232
+ describe('inputFilter', () => {
1233
+ it('should filter input based on the provided filter function', () => {
1234
+ const { result } = renderHook(() => useTextBuffer({
1235
+ viewport,
1236
+ isValidPath: () => false,
1237
+ inputFilter: (text) => text.replace(/[^0-9]/g, ''),
1238
+ }));
1239
+ act(() => result.current.insert('a1b2c3'));
1240
+ expect(getBufferState(result).text).toBe('123');
1241
+ });
1242
+ it('should handle empty result from filter', () => {
1243
+ const { result } = renderHook(() => useTextBuffer({
1244
+ viewport,
1245
+ isValidPath: () => false,
1246
+ inputFilter: (text) => text.replace(/[^0-9]/g, ''),
1247
+ }));
1248
+ act(() => result.current.insert('abc'));
1249
+ expect(getBufferState(result).text).toBe('');
1250
+ });
1251
+ it('should filter pasted text', () => {
1252
+ const { result } = renderHook(() => useTextBuffer({
1253
+ viewport,
1254
+ isValidPath: () => false,
1255
+ inputFilter: (text) => text.toUpperCase(),
1256
+ }));
1257
+ act(() => result.current.insert('hello', { paste: true }));
1258
+ expect(getBufferState(result).text).toBe('HELLO');
1259
+ });
1260
+ it('should not filter newlines if they are allowed by the filter', () => {
1261
+ const { result } = renderHook(() => useTextBuffer({
1262
+ viewport,
1263
+ isValidPath: () => false,
1264
+ inputFilter: (text) => text, // Allow everything including newlines
1265
+ }));
1266
+ act(() => result.current.insert('a\nb'));
1267
+ // The insert function splits by newline and inserts separately if it detects them.
1268
+ // If the filter allows them, they should be handled correctly by the subsequent logic in insert.
1269
+ expect(getBufferState(result).text).toBe('a\nb');
1270
+ });
1271
+ it('should filter before newline check in insert', () => {
1272
+ const { result } = renderHook(() => useTextBuffer({
1273
+ viewport,
1274
+ isValidPath: () => false,
1275
+ inputFilter: (text) => text.replace(/\n/g, ''), // Filter out newlines
1276
+ }));
1277
+ act(() => result.current.insert('a\nb'));
1278
+ expect(getBufferState(result).text).toBe('ab');
1279
+ });
1280
+ });
1221
1281
  describe('stripAnsi', () => {
1222
1282
  it('should correctly strip ANSI escape codes', () => {
1223
1283
  const textWithAnsi = '\x1B[31mHello\x1B[0m World';
@@ -1269,88 +1329,212 @@ Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots
1269
1329
  expect(getBufferState(result).text).toBe('hello world');
1270
1330
  });
1271
1331
  });
1332
+ describe('singleLine mode', () => {
1333
+ it('should not insert a newline character when singleLine is true', () => {
1334
+ const { result } = renderHook(() => useTextBuffer({
1335
+ viewport,
1336
+ isValidPath: () => false,
1337
+ singleLine: true,
1338
+ }));
1339
+ act(() => result.current.insert('\n'));
1340
+ const state = getBufferState(result);
1341
+ expect(state.text).toBe('');
1342
+ expect(state.lines).toEqual(['']);
1343
+ });
1344
+ it('should not create a new line when newline() is called and singleLine is true', () => {
1345
+ const { result } = renderHook(() => useTextBuffer({
1346
+ initialText: 'ab',
1347
+ viewport,
1348
+ isValidPath: () => false,
1349
+ singleLine: true,
1350
+ }));
1351
+ act(() => result.current.move('end')); // cursor at [0,2]
1352
+ act(() => result.current.newline());
1353
+ const state = getBufferState(result);
1354
+ expect(state.text).toBe('ab');
1355
+ expect(state.lines).toEqual(['ab']);
1356
+ expect(state.cursor).toEqual([0, 2]);
1357
+ });
1358
+ it('should not handle "Enter" key as newline when singleLine is true', () => {
1359
+ const { result } = renderHook(() => useTextBuffer({
1360
+ viewport,
1361
+ isValidPath: () => false,
1362
+ singleLine: true,
1363
+ }));
1364
+ act(() => result.current.handleInput({
1365
+ name: 'return',
1366
+ ctrl: false,
1367
+ meta: false,
1368
+ shift: false,
1369
+ paste: false,
1370
+ sequence: '\r',
1371
+ }));
1372
+ expect(getBufferState(result).lines).toEqual(['']);
1373
+ });
1374
+ it('should strip newlines from pasted text when singleLine is true', () => {
1375
+ const { result } = renderHook(() => useTextBuffer({
1376
+ viewport,
1377
+ isValidPath: () => false,
1378
+ singleLine: true,
1379
+ }));
1380
+ act(() => result.current.insert('hello\nworld', { paste: true }));
1381
+ const state = getBufferState(result);
1382
+ expect(state.text).toBe('helloworld');
1383
+ expect(state.lines).toEqual(['helloworld']);
1384
+ });
1385
+ });
1272
1386
  });
1273
1387
  describe('offsetToLogicalPos', () => {
1274
- it('should return [0,0] for offset 0', () => {
1275
- expect(offsetToLogicalPos('any text', 0)).toEqual([0, 0]);
1276
- });
1277
- it('should handle single line text', () => {
1278
- const text = 'hello';
1279
- expect(offsetToLogicalPos(text, 0)).toEqual([0, 0]); // Start
1280
- expect(offsetToLogicalPos(text, 2)).toEqual([0, 2]); // Middle 'l'
1281
- expect(offsetToLogicalPos(text, 5)).toEqual([0, 5]); // End
1282
- expect(offsetToLogicalPos(text, 10)).toEqual([0, 5]); // Beyond end
1388
+ it.each([
1389
+ { text: 'any text', offset: 0, expected: [0, 0], desc: 'offset 0' },
1390
+ { text: 'hello', offset: 0, expected: [0, 0], desc: 'single line start' },
1391
+ { text: 'hello', offset: 2, expected: [0, 2], desc: 'single line middle' },
1392
+ { text: 'hello', offset: 5, expected: [0, 5], desc: 'single line end' },
1393
+ { text: 'hello', offset: 10, expected: [0, 5], desc: 'beyond end clamps' },
1394
+ {
1395
+ text: 'a\n\nc',
1396
+ offset: 0,
1397
+ expected: [0, 0],
1398
+ desc: 'empty lines - first char',
1399
+ },
1400
+ {
1401
+ text: 'a\n\nc',
1402
+ offset: 1,
1403
+ expected: [0, 1],
1404
+ desc: 'empty lines - end of first',
1405
+ },
1406
+ {
1407
+ text: 'a\n\nc',
1408
+ offset: 2,
1409
+ expected: [1, 0],
1410
+ desc: 'empty lines - empty line',
1411
+ },
1412
+ {
1413
+ text: 'a\n\nc',
1414
+ offset: 3,
1415
+ expected: [2, 0],
1416
+ desc: 'empty lines - last line start',
1417
+ },
1418
+ {
1419
+ text: 'a\n\nc',
1420
+ offset: 4,
1421
+ expected: [2, 1],
1422
+ desc: 'empty lines - last line end',
1423
+ },
1424
+ {
1425
+ text: 'hello\n',
1426
+ offset: 5,
1427
+ expected: [0, 5],
1428
+ desc: 'newline end - before newline',
1429
+ },
1430
+ {
1431
+ text: 'hello\n',
1432
+ offset: 6,
1433
+ expected: [1, 0],
1434
+ desc: 'newline end - after newline',
1435
+ },
1436
+ {
1437
+ text: 'hello\n',
1438
+ offset: 7,
1439
+ expected: [1, 0],
1440
+ desc: 'newline end - beyond',
1441
+ },
1442
+ {
1443
+ text: '\nhello',
1444
+ offset: 0,
1445
+ expected: [0, 0],
1446
+ desc: 'newline start - first line',
1447
+ },
1448
+ {
1449
+ text: '\nhello',
1450
+ offset: 1,
1451
+ expected: [1, 0],
1452
+ desc: 'newline start - second line',
1453
+ },
1454
+ {
1455
+ text: '\nhello',
1456
+ offset: 3,
1457
+ expected: [1, 2],
1458
+ desc: 'newline start - middle of second',
1459
+ },
1460
+ { text: '', offset: 0, expected: [0, 0], desc: 'empty string at 0' },
1461
+ { text: '', offset: 5, expected: [0, 0], desc: 'empty string beyond' },
1462
+ {
1463
+ text: '你好\n世界',
1464
+ offset: 0,
1465
+ expected: [0, 0],
1466
+ desc: 'unicode - start',
1467
+ },
1468
+ {
1469
+ text: '你好\n世界',
1470
+ offset: 1,
1471
+ expected: [0, 1],
1472
+ desc: 'unicode - after first char',
1473
+ },
1474
+ {
1475
+ text: '你好\n世界',
1476
+ offset: 2,
1477
+ expected: [0, 2],
1478
+ desc: 'unicode - end first line',
1479
+ },
1480
+ {
1481
+ text: '你好\n世界',
1482
+ offset: 3,
1483
+ expected: [1, 0],
1484
+ desc: 'unicode - second line start',
1485
+ },
1486
+ {
1487
+ text: '你好\n世界',
1488
+ offset: 4,
1489
+ expected: [1, 1],
1490
+ desc: 'unicode - second line middle',
1491
+ },
1492
+ {
1493
+ text: '你好\n世界',
1494
+ offset: 5,
1495
+ expected: [1, 2],
1496
+ desc: 'unicode - second line end',
1497
+ },
1498
+ {
1499
+ text: '你好\n世界',
1500
+ offset: 6,
1501
+ expected: [1, 2],
1502
+ desc: 'unicode - beyond',
1503
+ },
1504
+ {
1505
+ text: 'abc\ndef',
1506
+ offset: 3,
1507
+ expected: [0, 3],
1508
+ desc: 'at newline - end of line',
1509
+ },
1510
+ {
1511
+ text: 'abc\ndef',
1512
+ offset: 4,
1513
+ expected: [1, 0],
1514
+ desc: 'at newline - after newline',
1515
+ },
1516
+ { text: '🐶🐱', offset: 0, expected: [0, 0], desc: 'emoji - start' },
1517
+ { text: '🐶🐱', offset: 1, expected: [0, 1], desc: 'emoji - middle' },
1518
+ { text: '🐶🐱', offset: 2, expected: [0, 2], desc: 'emoji - end' },
1519
+ ])('should handle $desc', ({ text, offset, expected }) => {
1520
+ expect(offsetToLogicalPos(text, offset)).toEqual(expected);
1283
1521
  });
1284
- it('should handle multi-line text', () => {
1522
+ describe('multi-line text', () => {
1285
1523
  const text = 'hello\nworld\n123';
1286
- // "hello" (5) + \n (1) + "world" (5) + \n (1) + "123" (3)
1287
- // h e l l o \n w o r l d \n 1 2 3
1288
- // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4
1289
- // Line 0: "hello" (length 5)
1290
- expect(offsetToLogicalPos(text, 0)).toEqual([0, 0]); // Start of 'hello'
1291
- expect(offsetToLogicalPos(text, 3)).toEqual([0, 3]); // 'l' in 'hello'
1292
- expect(offsetToLogicalPos(text, 5)).toEqual([0, 5]); // End of 'hello' (before \n)
1293
- // Line 1: "world" (length 5)
1294
- expect(offsetToLogicalPos(text, 6)).toEqual([1, 0]); // Start of 'world' (after \n)
1295
- expect(offsetToLogicalPos(text, 8)).toEqual([1, 2]); // 'r' in 'world'
1296
- expect(offsetToLogicalPos(text, 11)).toEqual([1, 5]); // End of 'world' (before \n)
1297
- // Line 2: "123" (length 3)
1298
- expect(offsetToLogicalPos(text, 12)).toEqual([2, 0]); // Start of '123' (after \n)
1299
- expect(offsetToLogicalPos(text, 13)).toEqual([2, 1]); // '2' in '123'
1300
- expect(offsetToLogicalPos(text, 15)).toEqual([2, 3]); // End of '123'
1301
- expect(offsetToLogicalPos(text, 20)).toEqual([2, 3]); // Beyond end of text
1302
- });
1303
- it('should handle empty lines', () => {
1304
- const text = 'a\n\nc'; // "a" (1) + \n (1) + "" (0) + \n (1) + "c" (1)
1305
- expect(offsetToLogicalPos(text, 0)).toEqual([0, 0]); // 'a'
1306
- expect(offsetToLogicalPos(text, 1)).toEqual([0, 1]); // End of 'a'
1307
- expect(offsetToLogicalPos(text, 2)).toEqual([1, 0]); // Start of empty line
1308
- expect(offsetToLogicalPos(text, 3)).toEqual([2, 0]); // Start of 'c'
1309
- expect(offsetToLogicalPos(text, 4)).toEqual([2, 1]); // End of 'c'
1310
- });
1311
- it('should handle text ending with a newline', () => {
1312
- const text = 'hello\n'; // "hello" (5) + \n (1)
1313
- expect(offsetToLogicalPos(text, 5)).toEqual([0, 5]); // End of 'hello'
1314
- expect(offsetToLogicalPos(text, 6)).toEqual([1, 0]); // Position on the new empty line after
1315
- expect(offsetToLogicalPos(text, 7)).toEqual([1, 0]); // Still on the new empty line
1316
- });
1317
- it('should handle text starting with a newline', () => {
1318
- const text = '\nhello'; // "" (0) + \n (1) + "hello" (5)
1319
- expect(offsetToLogicalPos(text, 0)).toEqual([0, 0]); // Start of first empty line
1320
- expect(offsetToLogicalPos(text, 1)).toEqual([1, 0]); // Start of 'hello'
1321
- expect(offsetToLogicalPos(text, 3)).toEqual([1, 2]); // 'l' in 'hello'
1322
- });
1323
- it('should handle empty string input', () => {
1324
- expect(offsetToLogicalPos('', 0)).toEqual([0, 0]);
1325
- expect(offsetToLogicalPos('', 5)).toEqual([0, 0]);
1326
- });
1327
- it('should handle multi-byte unicode characters correctly', () => {
1328
- const text = '你好\n世界'; // "你好" (2 chars) + \n (1) + "世界" (2 chars)
1329
- // Total "code points" for offset calculation: 2 + 1 + 2 = 5
1330
- expect(offsetToLogicalPos(text, 0)).toEqual([0, 0]); // Start of '你好'
1331
- expect(offsetToLogicalPos(text, 1)).toEqual([0, 1]); // After '你', before '好'
1332
- expect(offsetToLogicalPos(text, 2)).toEqual([0, 2]); // End of '你好'
1333
- expect(offsetToLogicalPos(text, 3)).toEqual([1, 0]); // Start of '世界'
1334
- expect(offsetToLogicalPos(text, 4)).toEqual([1, 1]); // After '世', before '界'
1335
- expect(offsetToLogicalPos(text, 5)).toEqual([1, 2]); // End of '世界'
1336
- expect(offsetToLogicalPos(text, 6)).toEqual([1, 2]); // Beyond end
1337
- });
1338
- it('should handle offset exactly at newline character', () => {
1339
- const text = 'abc\ndef';
1340
- // a b c \n d e f
1341
- // 0 1 2 3 4 5 6
1342
- expect(offsetToLogicalPos(text, 3)).toEqual([0, 3]); // End of 'abc'
1343
- // The next character is the newline, so an offset of 4 means the start of the next line.
1344
- expect(offsetToLogicalPos(text, 4)).toEqual([1, 0]); // Start of 'def'
1345
- });
1346
- it('should handle offset in the middle of a multi-byte character (should place at start of that char)', () => {
1347
- // This scenario is tricky as "offset" is usually character-based.
1348
- // Assuming cpLen and related logic handles this by treating multi-byte as one unit.
1349
- // The current implementation of offsetToLogicalPos uses cpLen, so it should be code-point aware.
1350
- const text = '🐶🐱'; // 2 code points
1351
- expect(offsetToLogicalPos(text, 0)).toEqual([0, 0]);
1352
- expect(offsetToLogicalPos(text, 1)).toEqual([0, 1]); // After 🐶
1353
- expect(offsetToLogicalPos(text, 2)).toEqual([0, 2]); // After 🐱
1524
+ it.each([
1525
+ { offset: 0, expected: [0, 0], desc: 'start of first line' },
1526
+ { offset: 3, expected: [0, 3], desc: 'middle of first line' },
1527
+ { offset: 5, expected: [0, 5], desc: 'end of first line' },
1528
+ { offset: 6, expected: [1, 0], desc: 'start of second line' },
1529
+ { offset: 8, expected: [1, 2], desc: 'middle of second line' },
1530
+ { offset: 11, expected: [1, 5], desc: 'end of second line' },
1531
+ { offset: 12, expected: [2, 0], desc: 'start of third line' },
1532
+ { offset: 13, expected: [2, 1], desc: 'middle of third line' },
1533
+ { offset: 15, expected: [2, 3], desc: 'end of third line' },
1534
+ { offset: 20, expected: [2, 3], desc: 'beyond end' },
1535
+ ])('should return $expected for $desc (offset $offset)', ({ offset, expected }) => {
1536
+ expect(offsetToLogicalPos(text, offset)).toEqual(expected);
1537
+ });
1354
1538
  });
1355
1539
  });
1356
1540
  describe('logicalPosToOffset', () => {
@@ -1400,7 +1584,6 @@ describe('logicalPosToOffset', () => {
1400
1584
  expect(logicalPosToOffset(lines, 5, 10)).toBe(5); // Clamps to end of last line
1401
1585
  });
1402
1586
  });
1403
- // Helper to create state for reducer tests
1404
1587
  const createTestState = (lines, cursorRow, cursorCol, viewportWidth = 80) => {
1405
1588
  const text = lines.join('\n');
1406
1589
  let state = textBufferReducer(initialState, {