@machina.ai/cell-cli 1.13.0-rc5 → 1.16.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 (443) hide show
  1. package/dist/package.json +4 -4
  2. package/dist/src/commands/extensions/disable.js +2 -2
  3. package/dist/src/commands/extensions/disable.js.map +1 -1
  4. package/dist/src/commands/extensions/enable.js +4 -4
  5. package/dist/src/commands/extensions/enable.js.map +1 -1
  6. package/dist/src/commands/extensions/examples/mcp-server/package.json +1 -1
  7. package/dist/src/commands/extensions.js +1 -1
  8. package/dist/src/commands/extensions.js.map +1 -1
  9. package/dist/src/config/config.d.ts +4 -8
  10. package/dist/src/config/config.js +37 -24
  11. package/dist/src/config/config.js.map +1 -1
  12. package/dist/src/config/config.test.js +31 -11
  13. package/dist/src/config/config.test.js.map +1 -1
  14. package/dist/src/config/extension-manager.js +39 -14
  15. package/dist/src/config/extension-manager.js.map +1 -1
  16. package/dist/src/config/extension.test.js +65 -0
  17. package/dist/src/config/extension.test.js.map +1 -1
  18. package/dist/src/config/extensions/extensionSettings.js +3 -2
  19. package/dist/src/config/extensions/extensionSettings.js.map +1 -1
  20. package/dist/src/config/extensions/github.d.ts +1 -1
  21. package/dist/src/config/extensions/github.js +8 -2
  22. package/dist/src/config/extensions/github.js.map +1 -1
  23. package/dist/src/config/extensions/github.test.js +8 -10
  24. package/dist/src/config/extensions/github.test.js.map +1 -1
  25. package/dist/src/config/keyBindings.d.ts +19 -0
  26. package/dist/src/config/keyBindings.js +151 -0
  27. package/dist/src/config/keyBindings.js.map +1 -1
  28. package/dist/src/config/keyBindings.test.js +26 -1
  29. package/dist/src/config/keyBindings.test.js.map +1 -1
  30. package/dist/src/config/policy-engine.integration.test.js +62 -44
  31. package/dist/src/config/policy-engine.integration.test.js.map +1 -1
  32. package/dist/src/config/settingPaths.d.ts +10 -0
  33. package/dist/src/config/settingPaths.js +11 -0
  34. package/dist/src/config/settingPaths.js.map +1 -0
  35. package/dist/src/config/settings.d.ts +15 -5
  36. package/dist/src/config/settings.js +28 -8
  37. package/dist/src/config/settings.js.map +1 -1
  38. package/dist/src/config/settingsSchema.d.ts +64 -7
  39. package/dist/src/config/settingsSchema.js +68 -11
  40. package/dist/src/config/settingsSchema.js.map +1 -1
  41. package/dist/src/config/settingsSchema.test.js +9 -0
  42. package/dist/src/config/settingsSchema.test.js.map +1 -1
  43. package/dist/src/gemini.d.ts +2 -2
  44. package/dist/src/gemini.js +56 -27
  45. package/dist/src/gemini.js.map +1 -1
  46. package/dist/src/gemini.test.js +18 -7
  47. package/dist/src/gemini.test.js.map +1 -1
  48. package/dist/src/generated/git-commit.d.ts +2 -2
  49. package/dist/src/generated/git-commit.js +2 -2
  50. package/dist/src/nonInteractiveCli.d.ts +3 -2
  51. package/dist/src/nonInteractiveCli.js +6 -1
  52. package/dist/src/nonInteractiveCli.js.map +1 -1
  53. package/dist/src/nonInteractiveCli.test.js +2 -1
  54. package/dist/src/nonInteractiveCli.test.js.map +1 -1
  55. package/dist/src/services/BuiltinCommandLoader.d.ts +1 -1
  56. package/dist/src/services/BuiltinCommandLoader.js +2 -2
  57. package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
  58. package/dist/src/services/BuiltinCommandLoader.test.js +3 -1
  59. package/dist/src/services/BuiltinCommandLoader.test.js.map +1 -1
  60. package/dist/src/services/FileCommandLoader.js +9 -6
  61. package/dist/src/services/FileCommandLoader.js.map +1 -1
  62. package/dist/src/services/FileCommandLoader.test.js +76 -1
  63. package/dist/src/services/FileCommandLoader.test.js.map +1 -1
  64. package/dist/src/test-utils/render.d.ts +2 -2
  65. package/dist/src/test-utils/render.js +18 -3
  66. package/dist/src/test-utils/render.js.map +1 -1
  67. package/dist/src/ui/App.js +9 -1
  68. package/dist/src/ui/App.js.map +1 -1
  69. package/dist/src/ui/App.test.js +37 -1
  70. package/dist/src/ui/App.test.js.map +1 -1
  71. package/dist/src/ui/AppContainer.d.ts +2 -3
  72. package/dist/src/ui/AppContainer.js +126 -29
  73. package/dist/src/ui/AppContainer.js.map +1 -1
  74. package/dist/src/ui/AppContainer.test.js +356 -48
  75. package/dist/src/ui/AppContainer.test.js.map +1 -1
  76. package/dist/src/ui/auth/AuthDialog.js +1 -1
  77. package/dist/src/ui/auth/AuthDialog.js.map +1 -1
  78. package/dist/src/ui/auth/AuthDialog.test.js +1 -1
  79. package/dist/src/ui/auth/AuthDialog.test.js.map +1 -1
  80. package/dist/src/ui/commands/chatCommand.js +15 -3
  81. package/dist/src/ui/commands/chatCommand.js.map +1 -1
  82. package/dist/src/ui/commands/chatCommand.test.js +44 -5
  83. package/dist/src/ui/commands/chatCommand.test.js.map +1 -1
  84. package/dist/src/ui/commands/directoryCommand.js +2 -10
  85. package/dist/src/ui/commands/directoryCommand.js.map +1 -1
  86. package/dist/src/ui/commands/docsCommand.js +1 -1
  87. package/dist/src/ui/commands/docsCommand.js.map +1 -1
  88. package/dist/src/ui/commands/extensionsCommand.d.ts +7 -2
  89. package/dist/src/ui/commands/extensionsCommand.js +238 -24
  90. package/dist/src/ui/commands/extensionsCommand.js.map +1 -1
  91. package/dist/src/ui/commands/extensionsCommand.test.js +323 -82
  92. package/dist/src/ui/commands/extensionsCommand.test.js.map +1 -1
  93. package/dist/src/ui/commands/ideCommand.js +6 -4
  94. package/dist/src/ui/commands/ideCommand.js.map +1 -1
  95. package/dist/src/ui/commands/memoryCommand.js +2 -10
  96. package/dist/src/ui/commands/memoryCommand.js.map +1 -1
  97. package/dist/src/ui/commands/memoryCommand.test.js +11 -28
  98. package/dist/src/ui/commands/memoryCommand.test.js.map +1 -1
  99. package/dist/src/ui/commands/settingsCommand.js +1 -1
  100. package/dist/src/ui/commands/settingsCommand.js.map +1 -1
  101. package/dist/src/ui/commands/settingsCommand.test.js +1 -1
  102. package/dist/src/ui/commands/settingsCommand.test.js.map +1 -1
  103. package/dist/src/ui/commands/setupGithubCommand.js +1 -1
  104. package/dist/src/ui/commands/setupGithubCommand.js.map +1 -1
  105. package/dist/src/ui/commands/toolsCommand.js +1 -1
  106. package/dist/src/ui/commands/toolsCommand.js.map +1 -1
  107. package/dist/src/ui/commands/types.d.ts +1 -2
  108. package/dist/src/ui/commands/types.js.map +1 -1
  109. package/dist/src/ui/components/AboutBox.js +1 -1
  110. package/dist/src/ui/components/AboutBox.js.map +1 -1
  111. package/dist/src/ui/components/AlternateBufferQuittingDisplay.d.ts +6 -0
  112. package/dist/src/ui/components/AlternateBufferQuittingDisplay.js +24 -0
  113. package/dist/src/ui/components/AlternateBufferQuittingDisplay.js.map +1 -0
  114. package/dist/src/ui/components/AlternateBufferQuittingDisplay.test.d.ts +6 -0
  115. package/dist/src/ui/components/AlternateBufferQuittingDisplay.test.js +110 -0
  116. package/dist/src/ui/components/AlternateBufferQuittingDisplay.test.js.map +1 -0
  117. package/dist/src/ui/components/AppHeader.js +25 -3
  118. package/dist/src/ui/components/AppHeader.js.map +1 -1
  119. package/dist/src/ui/components/AppHeader.test.d.ts +6 -0
  120. package/dist/src/ui/components/AppHeader.test.js +138 -0
  121. package/dist/src/ui/components/AppHeader.test.js.map +1 -0
  122. package/dist/src/ui/components/AsciiArt.d.ts +6 -3
  123. package/dist/src/ui/components/AsciiArt.js +39 -3
  124. package/dist/src/ui/components/AsciiArt.js.map +1 -1
  125. package/dist/src/ui/components/Banner.d.ts +12 -0
  126. package/dist/src/ui/components/Banner.js +14 -0
  127. package/dist/src/ui/components/Banner.js.map +1 -0
  128. package/dist/src/ui/components/CliSpinner.d.ts +0 -1
  129. package/dist/src/ui/components/CliSpinner.js +3 -4
  130. package/dist/src/ui/components/CliSpinner.js.map +1 -1
  131. package/dist/src/ui/components/CliSpinner.test.d.ts +6 -0
  132. package/dist/src/ui/components/CliSpinner.test.js +23 -0
  133. package/dist/src/ui/components/CliSpinner.test.js.map +1 -0
  134. package/dist/src/ui/components/Composer.js +11 -4
  135. package/dist/src/ui/components/Composer.js.map +1 -1
  136. package/dist/src/ui/components/CopyModeWarning.d.ts +7 -0
  137. package/dist/src/ui/components/CopyModeWarning.js +12 -0
  138. package/dist/src/ui/components/CopyModeWarning.js.map +1 -0
  139. package/dist/src/ui/components/DebugProfiler.js +2 -2
  140. package/dist/src/ui/components/DebugProfiler.js.map +1 -1
  141. package/dist/src/ui/components/DebugProfiler.test.js +15 -0
  142. package/dist/src/ui/components/DebugProfiler.test.js.map +1 -1
  143. package/dist/src/ui/components/DetailedMessagesDisplay.d.ts +1 -0
  144. package/dist/src/ui/components/DetailedMessagesDisplay.js +47 -27
  145. package/dist/src/ui/components/DetailedMessagesDisplay.js.map +1 -1
  146. package/dist/src/ui/components/DialogManager.js +1 -1
  147. package/dist/src/ui/components/DialogManager.js.map +1 -1
  148. package/dist/src/ui/components/EditorSettingsDialog.d.ts +3 -4
  149. package/dist/src/ui/components/EditorSettingsDialog.js +2 -2
  150. package/dist/src/ui/components/EditorSettingsDialog.js.map +1 -1
  151. package/dist/src/ui/components/FolderTrustDialog.js +1 -1
  152. package/dist/src/ui/components/FolderTrustDialog.js.map +1 -1
  153. package/dist/src/ui/components/FolderTrustDialog.test.js +1 -1
  154. package/dist/src/ui/components/FolderTrustDialog.test.js.map +1 -1
  155. package/dist/src/ui/components/Footer.js +2 -2
  156. package/dist/src/ui/components/Footer.js.map +1 -1
  157. package/dist/src/ui/components/GradientRegression.test.d.ts +6 -0
  158. package/dist/src/ui/components/GradientRegression.test.js +84 -0
  159. package/dist/src/ui/components/GradientRegression.test.js.map +1 -0
  160. package/dist/src/ui/components/Header.js +9 -8
  161. package/dist/src/ui/components/Header.js.map +1 -1
  162. package/dist/src/ui/components/Header.test.js +102 -34
  163. package/dist/src/ui/components/Header.test.js.map +1 -1
  164. package/dist/src/ui/components/Help.js +1 -1
  165. package/dist/src/ui/components/Help.js.map +1 -1
  166. package/dist/src/ui/components/Help.test.js +9 -0
  167. package/dist/src/ui/components/Help.test.js.map +1 -1
  168. package/dist/src/ui/components/HistoryItemDisplay.js +1 -1
  169. package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -1
  170. package/dist/src/ui/components/HistoryItemDisplay.test.js +51 -40
  171. package/dist/src/ui/components/HistoryItemDisplay.test.js.map +1 -1
  172. package/dist/src/ui/components/InputPrompt.d.ts +3 -0
  173. package/dist/src/ui/components/InputPrompt.js +18 -8
  174. package/dist/src/ui/components/InputPrompt.js.map +1 -1
  175. package/dist/src/ui/components/InputPrompt.test.js +99 -116
  176. package/dist/src/ui/components/InputPrompt.test.js.map +1 -1
  177. package/dist/src/ui/components/MainContent.js +52 -15
  178. package/dist/src/ui/components/MainContent.js.map +1 -1
  179. package/dist/src/ui/components/ModelDialog.js +38 -29
  180. package/dist/src/ui/components/ModelDialog.js.map +1 -1
  181. package/dist/src/ui/components/ModelDialog.test.js +22 -11
  182. package/dist/src/ui/components/ModelDialog.test.js.map +1 -1
  183. package/dist/src/ui/components/PermissionsModifyTrustDialog.js +1 -1
  184. package/dist/src/ui/components/PermissionsModifyTrustDialog.js.map +1 -1
  185. package/dist/src/ui/components/ProQuotaDialog.d.ts +7 -2
  186. package/dist/src/ui/components/ProQuotaDialog.js +80 -15
  187. package/dist/src/ui/components/ProQuotaDialog.js.map +1 -1
  188. package/dist/src/ui/components/ProQuotaDialog.test.js +146 -40
  189. package/dist/src/ui/components/ProQuotaDialog.test.js.map +1 -1
  190. package/dist/src/ui/components/SettingsDialog.js +1 -1
  191. package/dist/src/ui/components/SettingsDialog.js.map +1 -1
  192. package/dist/src/ui/components/SettingsDialog.test.js +12 -12
  193. package/dist/src/ui/components/SettingsDialog.test.js.map +1 -1
  194. package/dist/src/ui/components/StatsDisplay.js +2 -2
  195. package/dist/src/ui/components/StatsDisplay.js.map +1 -1
  196. package/dist/src/ui/components/StickyHeader.d.ts +14 -0
  197. package/dist/src/ui/components/StickyHeader.js +5 -0
  198. package/dist/src/ui/components/StickyHeader.js.map +1 -0
  199. package/dist/src/ui/components/StickyHeader.test.d.ts +6 -0
  200. package/dist/src/ui/components/StickyHeader.test.js +17 -0
  201. package/dist/src/ui/components/StickyHeader.test.js.map +1 -0
  202. package/dist/src/ui/components/ThemeDialog.d.ts +2 -3
  203. package/dist/src/ui/components/ThemeDialog.js +11 -3
  204. package/dist/src/ui/components/ThemeDialog.js.map +1 -1
  205. package/dist/src/ui/components/ThemeDialog.test.js +3 -3
  206. package/dist/src/ui/components/ThemeDialog.test.js.map +1 -1
  207. package/dist/src/ui/components/ThemedGradient.d.ts +8 -0
  208. package/dist/src/ui/components/ThemedGradient.js +15 -0
  209. package/dist/src/ui/components/ThemedGradient.js.map +1 -0
  210. package/dist/src/ui/components/messages/DiffRenderer.js +129 -89
  211. package/dist/src/ui/components/messages/DiffRenderer.js.map +1 -1
  212. package/dist/src/ui/components/messages/DiffRenderer.test.js +107 -115
  213. package/dist/src/ui/components/messages/DiffRenderer.test.js.map +1 -1
  214. package/dist/src/ui/components/messages/GeminiMessage.js +3 -1
  215. package/dist/src/ui/components/messages/GeminiMessage.js.map +1 -1
  216. package/dist/src/ui/components/messages/GeminiMessageContent.js +3 -1
  217. package/dist/src/ui/components/messages/GeminiMessageContent.js.map +1 -1
  218. package/dist/src/ui/components/messages/InfoMessage.d.ts +2 -0
  219. package/dist/src/ui/components/messages/InfoMessage.js +4 -3
  220. package/dist/src/ui/components/messages/InfoMessage.js.map +1 -1
  221. package/dist/src/ui/components/messages/Todo.test.js +1 -1
  222. package/dist/src/ui/components/messages/Todo.test.js.map +1 -1
  223. package/dist/src/ui/components/messages/ToolConfirmationMessage.js +151 -122
  224. package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
  225. package/dist/src/ui/components/messages/ToolGroupMessage.js +18 -14
  226. package/dist/src/ui/components/messages/ToolGroupMessage.js.map +1 -1
  227. package/dist/src/ui/components/messages/ToolGroupMessage.test.js +57 -32
  228. package/dist/src/ui/components/messages/ToolGroupMessage.test.js.map +1 -1
  229. package/dist/src/ui/components/messages/ToolMessage.d.ts +3 -0
  230. package/dist/src/ui/components/messages/ToolMessage.js +36 -17
  231. package/dist/src/ui/components/messages/ToolMessage.js.map +1 -1
  232. package/dist/src/ui/components/messages/ToolMessage.test.js +3 -0
  233. package/dist/src/ui/components/messages/ToolMessage.test.js.map +1 -1
  234. package/dist/src/ui/components/messages/ToolMessageRawMarkdown.test.js +36 -4
  235. package/dist/src/ui/components/messages/ToolMessageRawMarkdown.test.js.map +1 -1
  236. package/dist/src/ui/components/messages/UserMessage.d.ts +1 -0
  237. package/dist/src/ui/components/messages/UserMessage.js +2 -2
  238. package/dist/src/ui/components/messages/UserMessage.js.map +1 -1
  239. package/dist/src/ui/components/shared/ScopeSelector.d.ts +4 -4
  240. package/dist/src/ui/components/shared/Scrollable.d.ts +18 -0
  241. package/dist/src/ui/components/shared/Scrollable.js +84 -0
  242. package/dist/src/ui/components/shared/Scrollable.js.map +1 -0
  243. package/dist/src/ui/components/shared/Scrollable.test.d.ts +6 -0
  244. package/dist/src/ui/components/shared/Scrollable.test.js +74 -0
  245. package/dist/src/ui/components/shared/Scrollable.test.js.map +1 -0
  246. package/dist/src/ui/components/shared/ScrollableList.d.ts +26 -0
  247. package/dist/src/ui/components/shared/ScrollableList.js +152 -0
  248. package/dist/src/ui/components/shared/ScrollableList.js.map +1 -0
  249. package/dist/src/ui/components/shared/ScrollableList.test.d.ts +6 -0
  250. package/dist/src/ui/components/shared/ScrollableList.test.js +228 -0
  251. package/dist/src/ui/components/shared/ScrollableList.test.js.map +1 -0
  252. package/dist/src/ui/components/shared/VirtualizedList.d.ts +44 -0
  253. package/dist/src/ui/components/shared/VirtualizedList.js +312 -0
  254. package/dist/src/ui/components/shared/VirtualizedList.js.map +1 -0
  255. package/dist/src/ui/components/shared/VirtualizedList.test.d.ts +6 -0
  256. package/dist/src/ui/components/shared/VirtualizedList.test.js +171 -0
  257. package/dist/src/ui/components/shared/VirtualizedList.test.js.map +1 -0
  258. package/dist/src/ui/components/shared/text-buffer.d.ts +2 -8
  259. package/dist/src/ui/components/shared/text-buffer.js +1 -1
  260. package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
  261. package/dist/src/ui/components/shared/text-buffer.test.js +35 -0
  262. package/dist/src/ui/components/shared/text-buffer.test.js.map +1 -1
  263. package/dist/src/ui/components/views/ToolsList.js +1 -1
  264. package/dist/src/ui/components/views/ToolsList.js.map +1 -1
  265. package/dist/src/ui/constants.d.ts +1 -0
  266. package/dist/src/ui/constants.js +5 -0
  267. package/dist/src/ui/constants.js.map +1 -1
  268. package/dist/src/ui/contexts/KeypressContext.d.ts +6 -11
  269. package/dist/src/ui/contexts/KeypressContext.js +456 -756
  270. package/dist/src/ui/contexts/KeypressContext.js.map +1 -1
  271. package/dist/src/ui/contexts/KeypressContext.test.js +103 -334
  272. package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
  273. package/dist/src/ui/contexts/MouseContext.js +16 -1
  274. package/dist/src/ui/contexts/MouseContext.js.map +1 -1
  275. package/dist/src/ui/contexts/MouseContext.test.js +34 -0
  276. package/dist/src/ui/contexts/MouseContext.test.js.map +1 -1
  277. package/dist/src/ui/contexts/ScrollProvider.d.ts +25 -0
  278. package/dist/src/ui/contexts/ScrollProvider.drag.test.d.ts +6 -0
  279. package/dist/src/ui/contexts/ScrollProvider.drag.test.js +319 -0
  280. package/dist/src/ui/contexts/ScrollProvider.drag.test.js.map +1 -0
  281. package/dist/src/ui/contexts/ScrollProvider.js +242 -0
  282. package/dist/src/ui/contexts/ScrollProvider.js.map +1 -0
  283. package/dist/src/ui/contexts/ScrollProvider.test.d.ts +6 -0
  284. package/dist/src/ui/contexts/ScrollProvider.test.js +377 -0
  285. package/dist/src/ui/contexts/ScrollProvider.test.js.map +1 -0
  286. package/dist/src/ui/contexts/UIActionsContext.d.ts +6 -5
  287. package/dist/src/ui/contexts/UIActionsContext.js.map +1 -1
  288. package/dist/src/ui/contexts/UIStateContext.d.ts +10 -0
  289. package/dist/src/ui/contexts/UIStateContext.js.map +1 -1
  290. package/dist/src/ui/debug.d.ts +8 -0
  291. package/dist/src/ui/debug.js +11 -0
  292. package/dist/src/ui/debug.js.map +1 -0
  293. package/dist/src/ui/editors/editorSettingsManager.d.ts +0 -1
  294. package/dist/src/ui/editors/editorSettingsManager.js +1 -11
  295. package/dist/src/ui/editors/editorSettingsManager.js.map +1 -1
  296. package/dist/src/ui/hooks/atCommandProcessor.js +3 -3
  297. package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
  298. package/dist/src/ui/hooks/atCommandProcessor.test.js +2 -1
  299. package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -1
  300. package/dist/src/ui/hooks/slashCommandProcessor.d.ts +1 -1
  301. package/dist/src/ui/hooks/slashCommandProcessor.js +23 -5
  302. package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
  303. package/dist/src/ui/hooks/slashCommandProcessor.test.js +103 -68
  304. package/dist/src/ui/hooks/slashCommandProcessor.test.js.map +1 -1
  305. package/dist/src/ui/hooks/useAlternateBuffer.d.ts +8 -0
  306. package/dist/src/ui/hooks/useAlternateBuffer.js +12 -0
  307. package/dist/src/ui/hooks/useAlternateBuffer.js.map +1 -0
  308. package/dist/src/ui/hooks/useAnimatedScrollbar.d.ts +10 -0
  309. package/dist/src/ui/hooks/useAnimatedScrollbar.js +91 -0
  310. package/dist/src/ui/hooks/useAnimatedScrollbar.js.map +1 -0
  311. package/dist/src/ui/hooks/useAnimatedScrollbar.test.d.ts +6 -0
  312. package/dist/src/ui/hooks/useAnimatedScrollbar.test.js +85 -0
  313. package/dist/src/ui/hooks/useAnimatedScrollbar.test.js.map +1 -0
  314. package/dist/src/ui/hooks/useBatchedScroll.d.ts +14 -0
  315. package/dist/src/ui/hooks/useBatchedScroll.js +27 -0
  316. package/dist/src/ui/hooks/useBatchedScroll.js.map +1 -0
  317. package/dist/src/ui/hooks/useBatchedScroll.test.d.ts +6 -0
  318. package/dist/src/ui/hooks/useBatchedScroll.test.js +62 -0
  319. package/dist/src/ui/hooks/useBatchedScroll.test.js.map +1 -0
  320. package/dist/src/ui/hooks/useEditorSettings.d.ts +2 -2
  321. package/dist/src/ui/hooks/useEditorSettings.js +4 -3
  322. package/dist/src/ui/hooks/useEditorSettings.js.map +1 -1
  323. package/dist/src/ui/hooks/useEditorSettings.test.js +17 -8
  324. package/dist/src/ui/hooks/useEditorSettings.test.js.map +1 -1
  325. package/dist/src/ui/hooks/useFocus.test.js +10 -10
  326. package/dist/src/ui/hooks/useFocus.test.js.map +1 -1
  327. package/dist/src/ui/hooks/useGeminiStream.js +2 -2
  328. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  329. package/dist/src/ui/hooks/useGeminiStream.test.js +4 -0
  330. package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -1
  331. package/dist/src/ui/hooks/useKeypress.test.js +9 -32
  332. package/dist/src/ui/hooks/useKeypress.test.js.map +1 -1
  333. package/dist/src/ui/hooks/usePhraseCycler.js +2 -2
  334. package/dist/src/ui/hooks/usePhraseCycler.js.map +1 -1
  335. package/dist/src/ui/hooks/usePromptCompletion.js +2 -9
  336. package/dist/src/ui/hooks/usePromptCompletion.js.map +1 -1
  337. package/dist/src/ui/hooks/useQuotaAndFallback.d.ts +3 -5
  338. package/dist/src/ui/hooks/useQuotaAndFallback.js +62 -77
  339. package/dist/src/ui/hooks/useQuotaAndFallback.js.map +1 -1
  340. package/dist/src/ui/hooks/useQuotaAndFallback.test.js +142 -106
  341. package/dist/src/ui/hooks/useQuotaAndFallback.test.js.map +1 -1
  342. package/dist/src/ui/hooks/useSelectionList.test.js +3 -0
  343. package/dist/src/ui/hooks/useSelectionList.test.js.map +1 -1
  344. package/dist/src/ui/hooks/useSessionBrowser.d.ts +18 -0
  345. package/dist/src/ui/hooks/useSessionBrowser.js +152 -0
  346. package/dist/src/ui/hooks/useSessionBrowser.js.map +1 -0
  347. package/dist/src/ui/hooks/useSessionBrowser.test.d.ts +6 -0
  348. package/dist/src/ui/hooks/useSessionBrowser.test.js +544 -0
  349. package/dist/src/ui/hooks/useSessionBrowser.test.js.map +1 -0
  350. package/dist/src/ui/hooks/useSessionResume.d.ts +30 -0
  351. package/dist/src/ui/hooks/useSessionResume.js +56 -0
  352. package/dist/src/ui/hooks/useSessionResume.js.map +1 -0
  353. package/dist/src/ui/hooks/useSessionResume.test.d.ts +6 -0
  354. package/dist/src/ui/hooks/useSessionResume.test.js +325 -0
  355. package/dist/src/ui/hooks/useSessionResume.test.js.map +1 -0
  356. package/dist/src/ui/hooks/useThemeCommand.d.ts +2 -2
  357. package/dist/src/ui/hooks/useThemeCommand.js.map +1 -1
  358. package/dist/src/ui/hooks/useToolScheduler.test.js +1 -0
  359. package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
  360. package/dist/src/ui/hooks/vim.js +1 -0
  361. package/dist/src/ui/hooks/vim.js.map +1 -1
  362. package/dist/src/ui/hooks/vim.test.js +1 -0
  363. package/dist/src/ui/hooks/vim.test.js.map +1 -1
  364. package/dist/src/ui/keyMatchers.test.js +38 -0
  365. package/dist/src/ui/keyMatchers.test.js.map +1 -1
  366. package/dist/src/ui/layouts/DefaultAppLayout.js +9 -1
  367. package/dist/src/ui/layouts/DefaultAppLayout.js.map +1 -1
  368. package/dist/src/ui/noninteractive/nonInteractiveUi.js +0 -1
  369. package/dist/src/ui/noninteractive/nonInteractiveUi.js.map +1 -1
  370. package/dist/src/ui/privacy/CloudFreePrivacyNotice.js +1 -1
  371. package/dist/src/ui/privacy/CloudFreePrivacyNotice.js.map +1 -1
  372. package/dist/src/ui/state/extensions.d.ts +5 -0
  373. package/dist/src/ui/state/extensions.js +12 -0
  374. package/dist/src/ui/state/extensions.js.map +1 -1
  375. package/dist/src/ui/state/extensions.test.d.ts +6 -0
  376. package/dist/src/ui/state/extensions.test.js +62 -0
  377. package/dist/src/ui/state/extensions.test.js.map +1 -0
  378. package/dist/src/ui/themes/color-utils.js +9 -0
  379. package/dist/src/ui/themes/color-utils.js.map +1 -1
  380. package/dist/src/ui/themes/color-utils.test.js +17 -0
  381. package/dist/src/ui/themes/color-utils.test.js.map +1 -1
  382. package/dist/src/ui/types.d.ts +6 -0
  383. package/dist/src/ui/types.js +4 -0
  384. package/dist/src/ui/types.js.map +1 -1
  385. package/dist/src/ui/utils/CodeColorizer.d.ts +11 -3
  386. package/dist/src/ui/utils/CodeColorizer.js +18 -9
  387. package/dist/src/ui/utils/CodeColorizer.js.map +1 -1
  388. package/dist/src/ui/utils/CodeColorizer.test.d.ts +6 -0
  389. package/dist/src/ui/utils/CodeColorizer.test.js +38 -0
  390. package/dist/src/ui/utils/CodeColorizer.test.js.map +1 -0
  391. package/dist/src/ui/utils/MarkdownDisplay.js +32 -6
  392. package/dist/src/ui/utils/MarkdownDisplay.js.map +1 -1
  393. package/dist/src/ui/utils/mouse.d.ts +2 -1
  394. package/dist/src/ui/utils/mouse.js +27 -1
  395. package/dist/src/ui/utils/mouse.js.map +1 -1
  396. package/dist/src/ui/utils/mouse.test.js +5 -0
  397. package/dist/src/ui/utils/mouse.test.js.map +1 -1
  398. package/dist/src/ui/utils/terminalSetup.d.ts +4 -0
  399. package/dist/src/ui/utils/terminalSetup.js +10 -3
  400. package/dist/src/ui/utils/terminalSetup.js.map +1 -1
  401. package/dist/src/ui/utils/textUtils.d.ts +1 -0
  402. package/dist/src/ui/utils/textUtils.js +3 -2
  403. package/dist/src/ui/utils/textUtils.js.map +1 -1
  404. package/dist/src/ui/utils/textUtils.test.js +7 -1
  405. package/dist/src/ui/utils/textUtils.test.js.map +1 -1
  406. package/dist/src/ui/utils/ui-sizing.js +10 -3
  407. package/dist/src/ui/utils/ui-sizing.js.map +1 -1
  408. package/dist/src/utils/cleanup.test.js +1 -1
  409. package/dist/src/utils/cleanup.test.js.map +1 -1
  410. package/dist/src/utils/dialogScopeUtils.d.ts +6 -13
  411. package/dist/src/utils/dialogScopeUtils.js +4 -2
  412. package/dist/src/utils/dialogScopeUtils.js.map +1 -1
  413. package/dist/src/utils/events.d.ts +5 -1
  414. package/dist/src/utils/events.js +2 -0
  415. package/dist/src/utils/events.js.map +1 -1
  416. package/dist/src/utils/persistentState.d.ts +19 -0
  417. package/dist/src/utils/persistentState.js +65 -0
  418. package/dist/src/utils/persistentState.js.map +1 -0
  419. package/dist/src/utils/sessionCleanup.test.js +76 -0
  420. package/dist/src/utils/sessionCleanup.test.js.map +1 -1
  421. package/dist/src/utils/sessionUtils.d.ts +54 -0
  422. package/dist/src/utils/sessionUtils.js +141 -1
  423. package/dist/src/utils/sessionUtils.js.map +1 -1
  424. package/dist/src/utils/sessionUtils.test.d.ts +6 -0
  425. package/dist/src/utils/sessionUtils.test.js +260 -0
  426. package/dist/src/utils/sessionUtils.test.js.map +1 -0
  427. package/dist/src/utils/sessions.d.ts +8 -0
  428. package/dist/src/utils/sessions.js +64 -0
  429. package/dist/src/utils/sessions.js.map +1 -0
  430. package/dist/src/utils/settingsUtils.d.ts +2 -2
  431. package/dist/src/utils/settingsUtils.js.map +1 -1
  432. package/dist/src/utils/userStartupWarnings.js +2 -2
  433. package/dist/src/utils/userStartupWarnings.js.map +1 -1
  434. package/dist/src/utils/windowTitle.d.ts +1 -1
  435. package/dist/src/utils/windowTitle.js +1 -1
  436. package/dist/tsconfig.tsbuildinfo +1 -1
  437. package/package.json +4 -4
  438. package/dist/src/config/policies/read-only.toml +0 -56
  439. package/dist/src/config/policies/write.toml +0 -63
  440. package/dist/src/config/policies/yolo.toml +0 -31
  441. package/dist/src/ui/utils/platformConstants.d.ts +0 -75
  442. package/dist/src/ui/utils/platformConstants.js +0 -78
  443. package/dist/src/ui/utils/platformConstants.js.map +0 -1
@@ -1,382 +1,476 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { debugLogger, KittySequenceOverflowEvent, logKittySequenceOverflow, } from '@google/gemini-cli-core';
2
+ /**
3
+ * @license
4
+ * Copyright 2025 Google LLC
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+ import { debugLogger } from '@google/gemini-cli-core';
3
8
  import { useStdin } from 'ink';
4
9
  import { createContext, useCallback, useContext, useEffect, useRef, } from 'react';
5
- import readline from 'node:readline';
6
- import { PassThrough } from 'node:stream';
7
- import { BACKSLASH_ENTER_DETECTION_WINDOW_MS, CHAR_CODE_ESC, KITTY_CTRL_C, KITTY_KEYCODE_BACKSPACE, KITTY_KEYCODE_ENTER, KITTY_KEYCODE_NUMPAD_ENTER, KITTY_KEYCODE_TAB, MAX_KITTY_SEQUENCE_LENGTH, KITTY_MODIFIER_BASE, KITTY_MODIFIER_EVENT_TYPES_OFFSET, MODIFIER_SHIFT_BIT, MODIFIER_ALT_BIT, MODIFIER_CTRL_BIT, } from '../utils/platformConstants.js';
8
- import { ESC, couldBeMouseSequence } from '../utils/input.js';
10
+ import { ESC } from '../utils/input.js';
11
+ import { parseMouseEvent } from '../utils/mouse.js';
9
12
  import { FOCUS_IN, FOCUS_OUT } from '../hooks/useFocus.js';
10
- import { isIncompleteMouseSequence, parseMouseEvent } from '../utils/mouse.js';
11
- export const PASTE_MODE_START = `${ESC}[200~`;
12
- export const PASTE_MODE_END = `${ESC}[201~`;
13
- export const DRAG_COMPLETION_TIMEOUT_MS = 100; // Broadcast full path after 100ms if no more input
14
- export const KITTY_SEQUENCE_TIMEOUT_MS = 50; // Flush incomplete kitty sequences after 50ms
15
- export const PASTE_CODE_TIMEOUT_MS = 50; // Flush incomplete paste code after 50ms
16
- export const SINGLE_QUOTE = "'";
17
- export const DOUBLE_QUOTE = '"';
18
- // On Mac, hitting alt+char will yield funny characters.
19
- // Remap these three since we listen for them.
13
+ import { appEvents, AppEvent } from '../../utils/events.js';
14
+ export const BACKSLASH_ENTER_TIMEOUT = 5;
15
+ export const ESC_TIMEOUT = 50;
16
+ export const PASTE_TIMEOUT = 30_000;
17
+ // Parse the key itself
18
+ const KEY_INFO_MAP = {
19
+ '[200~': { name: 'paste-start' },
20
+ '[201~': { name: 'paste-end' },
21
+ '[[A': { name: 'f1' },
22
+ '[[B': { name: 'f2' },
23
+ '[[C': { name: 'f3' },
24
+ '[[D': { name: 'f4' },
25
+ '[[E': { name: 'f5' },
26
+ '[1~': { name: 'home' },
27
+ '[2~': { name: 'insert' },
28
+ '[3~': { name: 'delete' },
29
+ '[4~': { name: 'end' },
30
+ '[5~': { name: 'pageup' },
31
+ '[6~': { name: 'pagedown' },
32
+ '[7~': { name: 'home' },
33
+ '[8~': { name: 'end' },
34
+ '[11~': { name: 'f1' },
35
+ '[12~': { name: 'f2' },
36
+ '[13~': { name: 'f3' },
37
+ '[14~': { name: 'f4' },
38
+ '[15~': { name: 'f5' },
39
+ '[17~': { name: 'f6' },
40
+ '[18~': { name: 'f7' },
41
+ '[19~': { name: 'f8' },
42
+ '[20~': { name: 'f9' },
43
+ '[21~': { name: 'f10' },
44
+ '[23~': { name: 'f11' },
45
+ '[24~': { name: 'f12' },
46
+ '[A': { name: 'up' },
47
+ '[B': { name: 'down' },
48
+ '[C': { name: 'right' },
49
+ '[D': { name: 'left' },
50
+ '[E': { name: 'clear' },
51
+ '[F': { name: 'end' },
52
+ '[H': { name: 'home' },
53
+ '[P': { name: 'f1' },
54
+ '[Q': { name: 'f2' },
55
+ '[R': { name: 'f3' },
56
+ '[S': { name: 'f4' },
57
+ OA: { name: 'up' },
58
+ OB: { name: 'down' },
59
+ OC: { name: 'right' },
60
+ OD: { name: 'left' },
61
+ OE: { name: 'clear' },
62
+ OF: { name: 'end' },
63
+ OH: { name: 'home' },
64
+ OP: { name: 'f1' },
65
+ OQ: { name: 'f2' },
66
+ OR: { name: 'f3' },
67
+ OS: { name: 'f4' },
68
+ '[[5~': { name: 'pageup' },
69
+ '[[6~': { name: 'pagedown' },
70
+ '[9u': { name: 'tab' },
71
+ '[13u': { name: 'return' },
72
+ '[27u': { name: 'escape' },
73
+ '[127u': { name: 'backspace' },
74
+ '[57414u': { name: 'return' }, // Numpad Enter
75
+ '[a': { name: 'up', shift: true },
76
+ '[b': { name: 'down', shift: true },
77
+ '[c': { name: 'right', shift: true },
78
+ '[d': { name: 'left', shift: true },
79
+ '[e': { name: 'clear', shift: true },
80
+ '[2$': { name: 'insert', shift: true },
81
+ '[3$': { name: 'delete', shift: true },
82
+ '[5$': { name: 'pageup', shift: true },
83
+ '[6$': { name: 'pagedown', shift: true },
84
+ '[7$': { name: 'home', shift: true },
85
+ '[8$': { name: 'end', shift: true },
86
+ '[Z': { name: 'tab', shift: true },
87
+ Oa: { name: 'up', ctrl: true },
88
+ Ob: { name: 'down', ctrl: true },
89
+ Oc: { name: 'right', ctrl: true },
90
+ Od: { name: 'left', ctrl: true },
91
+ Oe: { name: 'clear', ctrl: true },
92
+ '[2^': { name: 'insert', ctrl: true },
93
+ '[3^': { name: 'delete', ctrl: true },
94
+ '[5^': { name: 'pageup', ctrl: true },
95
+ '[6^': { name: 'pagedown', ctrl: true },
96
+ '[7^': { name: 'home', ctrl: true },
97
+ '[8^': { name: 'end', ctrl: true },
98
+ };
99
+ const kUTF16SurrogateThreshold = 0x10000; // 2 ** 16
100
+ function charLengthAt(str, i) {
101
+ if (str.length <= i) {
102
+ // Pretend to move to the right. This is necessary to autocomplete while
103
+ // moving to the right.
104
+ return 1;
105
+ }
106
+ const code = str.codePointAt(i);
107
+ return code !== undefined && code >= kUTF16SurrogateThreshold ? 2 : 1;
108
+ }
20
109
  const MAC_ALT_KEY_CHARACTER_MAP = {
21
110
  '\u222B': 'b', // "∫" back one word
22
111
  '\u0192': 'f', // "ƒ" forward one word
23
112
  '\u00B5': 'm', // "µ" toggle markup view
24
113
  };
25
- /**
26
- * Maps symbols from parameterized functional keys `\x1b[1;1<letter>`
27
- * to their corresponding key names (e.g., 'up', 'f1').
28
- */
29
- const LEGACY_FUNC_TO_NAME = {
30
- A: 'up',
31
- B: 'down',
32
- C: 'right',
33
- D: 'left',
34
- H: 'home',
35
- F: 'end',
36
- P: 'f1',
37
- Q: 'f2',
38
- R: 'f3',
39
- S: 'f4',
40
- };
41
- /**
42
- * Maps key codes from tilde-coded functional keys `\x1b[<code>~`
43
- * to their corresponding key names.
44
- */
45
- const TILDE_KEYCODE_TO_NAME = {
46
- 1: 'home',
47
- 2: 'insert',
48
- 3: 'delete',
49
- 4: 'end',
50
- 5: 'pageup',
51
- 6: 'pagedown',
52
- 11: 'f1',
53
- 12: 'f2',
54
- 13: 'f3',
55
- 14: 'f4',
56
- 15: 'f5',
57
- 17: 'f6', // skipping 16 is intentional
58
- 18: 'f7',
59
- 19: 'f8',
60
- 20: 'f9',
61
- 21: 'f10',
62
- 23: 'f11', // skipping 22 is intentional
63
- 24: 'f12',
64
- };
65
- /**
66
- * Check if a buffer could potentially be a valid kitty sequence or its prefix.
67
- */
68
- function couldBeKittySequence(buffer) {
69
- // Kitty sequences always start with ESC[.
70
- if (buffer.length === 0)
71
- return true;
72
- if (buffer === ESC || buffer === `${ESC}[`)
73
- return true;
74
- if (!buffer.startsWith(`${ESC}[`))
75
- return false;
76
- if (couldBeMouseSequence(buffer))
77
- return true;
78
- // Check for known kitty sequence patterns:
79
- // 1. ESC[<digit> - could be CSI-u or tilde-coded
80
- // 2. ESC[1;<digit> - parameterized functional
81
- // 3. ESC[<letter> - legacy functional keys
82
- // 4. ESC[Z - reverse tab
83
- const afterCSI = buffer.slice(2);
84
- // Check if it starts with a digit (could be CSI-u or parameterized)
85
- if (/^\d/.test(afterCSI))
86
- return true;
87
- // Check for known single-letter sequences
88
- if (/^[ABCDHFPQRSZ]/.test(afterCSI))
89
- return true;
90
- // Check for 1; pattern (parameterized sequences)
91
- if (/^1;\d/.test(afterCSI))
92
- return true;
93
- // Anything else starting with ESC[ that doesn't match our patterns
94
- // is likely not a kitty sequence we handle
95
- return false;
96
- }
97
- /**
98
- * Parses a single complete kitty/parameterized/legacy sequence from the start
99
- * of the buffer.
100
- *
101
- * This enables peel-and-continue parsing for batched input, allowing us to
102
- * "peel off" one complete event when multiple sequences arrive in a single
103
- * chunk, preventing buffer overflow and fragmentation.
104
- *
105
- * @param buffer - The input buffer string to parse.
106
- * @returns The parsed Key and the number of characters consumed, or null if
107
- * no complete sequence is found at the start of the buffer.
108
- */
109
- function parseKittyPrefix(buffer) {
110
- // In older terminals ESC [ Z was used as Cursor Backward Tabulation (CBT)
111
- // In newer terminals the same functionality of key combination for moving
112
- // backward through focusable elements is Shift+Tab, hence we will
113
- // map ESC [ Z to Shift+Tab
114
- // 0) Reverse Tab (legacy): ESC [ Z
115
- // Treat as Shift+Tab for UI purposes.
116
- // Regex parts:
117
- // ^ - start of buffer
118
- // ESC [ - CSI introducer
119
- // Z - legacy reverse tab
120
- const revTabLegacy = new RegExp(`^${ESC}\\[Z`);
121
- let m = buffer.match(revTabLegacy);
122
- if (m) {
123
- return {
124
- key: {
125
- name: 'tab',
126
- ctrl: false,
127
- meta: false,
128
- shift: true,
129
- paste: false,
130
- sequence: buffer.slice(0, m[0].length),
131
- kittyProtocol: false,
132
- },
133
- length: m[0].length,
134
- };
135
- }
136
- // 1) Reverse Tab (parameterized): ESC [ 1 ; <mods> Z
137
- // Parameterized reverse Tab: ESC [ 1 ; <mods> Z
138
- const revTabParam = new RegExp(`^${ESC}\\[1;(\\d+)Z`);
139
- m = buffer.match(revTabParam);
140
- if (m) {
141
- let mods = parseInt(m[1], 10);
142
- if (mods >= KITTY_MODIFIER_EVENT_TYPES_OFFSET) {
143
- mods -= KITTY_MODIFIER_EVENT_TYPES_OFFSET;
144
- }
145
- const bits = mods - KITTY_MODIFIER_BASE;
146
- const alt = (bits & MODIFIER_ALT_BIT) === MODIFIER_ALT_BIT;
147
- const ctrl = (bits & MODIFIER_CTRL_BIT) === MODIFIER_CTRL_BIT;
148
- return {
149
- key: {
150
- name: 'tab',
151
- ctrl,
152
- meta: alt,
153
- // Reverse tab implies Shift behavior; force shift regardless of mods
154
- shift: true,
155
- paste: false,
156
- sequence: buffer.slice(0, m[0].length),
157
- kittyProtocol: true,
158
- },
159
- length: m[0].length,
160
- };
161
- }
162
- // 2) Parameterized functional: ESC [ 1 ; <mods> (A|B|C|D|H|F|P|Q|R|S)
163
- // 2) Parameterized functional: ESC [ 1 ; <mods> (A|B|C|D|H|F|P|Q|R|S)
164
- // Arrows, Home/End, F1–F4 with modifiers encoded in <mods>.
165
- const arrowPrefix = new RegExp(`^${ESC}\\[1;(\\d+)([ABCDHFPQSR])`);
166
- m = buffer.match(arrowPrefix);
167
- if (m) {
168
- let mods = parseInt(m[1], 10);
169
- if (mods >= KITTY_MODIFIER_EVENT_TYPES_OFFSET) {
170
- mods -= KITTY_MODIFIER_EVENT_TYPES_OFFSET;
171
- }
172
- const bits = mods - KITTY_MODIFIER_BASE;
173
- const shift = (bits & MODIFIER_SHIFT_BIT) === MODIFIER_SHIFT_BIT;
174
- const alt = (bits & MODIFIER_ALT_BIT) === MODIFIER_ALT_BIT;
175
- const ctrl = (bits & MODIFIER_CTRL_BIT) === MODIFIER_CTRL_BIT;
176
- const sym = m[2];
177
- const name = LEGACY_FUNC_TO_NAME[sym] || '';
178
- if (!name)
179
- return null;
180
- return {
181
- key: {
182
- name,
183
- ctrl,
184
- meta: alt,
185
- shift,
186
- paste: false,
187
- sequence: buffer.slice(0, m[0].length),
188
- kittyProtocol: true,
189
- },
190
- length: m[0].length,
191
- };
192
- }
193
- // 3) CSI-u form: ESC [ <code> ; <mods> (u|~)
194
- // 3) CSI-u and tilde-coded functional keys: ESC [ <code> ; <mods> (u|~)
195
- // 'u' terminator: Kitty CSI-u; '~' terminator: tilde-coded function keys.
196
- const csiUPrefix = new RegExp(`^${ESC}\\[(\\d+)(;(\\d+))?([u~])`);
197
- m = buffer.match(csiUPrefix);
198
- if (m) {
199
- const keyCode = parseInt(m[1], 10);
200
- let modifiers = m[3] ? parseInt(m[3], 10) : KITTY_MODIFIER_BASE;
201
- if (modifiers >= KITTY_MODIFIER_EVENT_TYPES_OFFSET) {
202
- modifiers -= KITTY_MODIFIER_EVENT_TYPES_OFFSET;
203
- }
204
- const modifierBits = modifiers - KITTY_MODIFIER_BASE;
205
- const shift = (modifierBits & MODIFIER_SHIFT_BIT) === MODIFIER_SHIFT_BIT;
206
- const alt = (modifierBits & MODIFIER_ALT_BIT) === MODIFIER_ALT_BIT;
207
- const ctrl = (modifierBits & MODIFIER_CTRL_BIT) === MODIFIER_CTRL_BIT;
208
- const terminator = m[4];
209
- // Tilde-coded functional keys (Delete, Insert, PageUp/Down, Home/End)
210
- if (terminator === '~') {
211
- const name = TILDE_KEYCODE_TO_NAME[keyCode];
212
- if (name) {
213
- return {
214
- key: {
215
- name,
216
- ctrl,
217
- meta: alt,
218
- shift,
219
- paste: false,
220
- sequence: buffer.slice(0, m[0].length),
221
- kittyProtocol: false,
222
- },
223
- length: m[0].length,
224
- };
225
- }
114
+ function nonKeyboardEventFilter(keypressHandler) {
115
+ return (key) => {
116
+ if (!parseMouseEvent(key.sequence) &&
117
+ key.sequence !== FOCUS_IN &&
118
+ key.sequence !== FOCUS_OUT) {
119
+ keypressHandler(key);
226
120
  }
227
- const kittyKeyCodeToName = {
228
- [CHAR_CODE_ESC]: 'escape',
229
- [KITTY_KEYCODE_TAB]: 'tab',
230
- [KITTY_KEYCODE_BACKSPACE]: 'backspace',
231
- [KITTY_KEYCODE_ENTER]: 'return',
232
- [KITTY_KEYCODE_NUMPAD_ENTER]: 'return',
233
- };
234
- const name = kittyKeyCodeToName[keyCode];
235
- if (name) {
236
- return {
237
- key: {
238
- name,
239
- ctrl,
240
- meta: alt,
241
- shift,
242
- paste: false,
243
- sequence: buffer.slice(0, m[0].length),
244
- kittyProtocol: true,
245
- },
246
- length: m[0].length,
247
- };
248
- }
249
- // Ctrl+letters and Alt+letters
250
- if ((ctrl || alt) &&
251
- keyCode >= 'a'.charCodeAt(0) &&
252
- keyCode <= 'z'.charCodeAt(0)) {
253
- const letter = String.fromCharCode(keyCode);
254
- return {
255
- key: {
256
- name: letter,
257
- ctrl,
258
- meta: alt,
259
- shift,
260
- paste: false,
261
- sequence: buffer.slice(0, m[0].length),
262
- kittyProtocol: true,
263
- },
264
- length: m[0].length,
265
- };
266
- }
267
- }
268
- // 4) Legacy function keys (no parameters): ESC [ (A|B|C|D|H|F)
269
- // Arrows + Home/End without modifiers.
270
- const legacyFuncKey = new RegExp(`^${ESC}\\[([ABCDHF])`);
271
- m = buffer.match(legacyFuncKey);
272
- if (m) {
273
- const sym = m[1];
274
- const name = LEGACY_FUNC_TO_NAME[sym];
275
- return {
276
- key: {
277
- name,
278
- ctrl: false,
279
- meta: false,
280
- shift: false,
281
- paste: false,
282
- sequence: buffer.slice(0, m[0].length),
283
- kittyProtocol: false,
284
- },
285
- length: m[0].length,
286
- };
287
- }
288
- return null;
121
+ };
289
122
  }
290
123
  /**
291
- * Returns the first index before which we are certain there is no paste marker.
124
+ * Buffers "/" keys to see if they are followed return.
125
+ * Will flush the buffer if no data is received for DRAG_COMPLETION_TIMEOUT_MS
126
+ * or when a null key is received.
292
127
  */
293
- function earliestPossiblePasteMarker(data) {
294
- // Check data for full start-paste or end-paste markers.
295
- const startIndex = data.indexOf(PASTE_MODE_START);
296
- const endIndex = data.indexOf(PASTE_MODE_END);
297
- if (startIndex !== -1 && endIndex !== -1) {
298
- return Math.min(startIndex, endIndex);
299
- }
300
- else if (startIndex !== -1) {
301
- return startIndex;
302
- }
303
- else if (endIndex !== -1) {
304
- return endIndex;
305
- }
306
- // data contains no full start-paste or end-paste.
307
- // Check if data ends with a prefix of start-paste or end-paste.
308
- const codeLength = PASTE_MODE_START.length;
309
- for (let i = Math.min(data.length, codeLength - 1); i > 0; i--) {
310
- const candidate = data.slice(data.length - i);
311
- if (PASTE_MODE_START.indexOf(candidate) === 0 ||
312
- PASTE_MODE_END.indexOf(candidate) === 0) {
313
- return data.length - i;
128
+ function bufferBackslashEnter(keypressHandler) {
129
+ const bufferer = (function* () {
130
+ while (true) {
131
+ const key = yield;
132
+ if (key == null) {
133
+ continue;
134
+ }
135
+ else if (key.sequence !== '\\') {
136
+ keypressHandler(key);
137
+ continue;
138
+ }
139
+ const timeoutId = setTimeout(() => bufferer.next(null), BACKSLASH_ENTER_TIMEOUT);
140
+ const nextKey = yield;
141
+ clearTimeout(timeoutId);
142
+ if (nextKey === null) {
143
+ keypressHandler(key);
144
+ }
145
+ else if (nextKey.name === 'return') {
146
+ keypressHandler({
147
+ ...nextKey,
148
+ shift: true,
149
+ sequence: '\r', // Corrected escaping for newline
150
+ });
151
+ }
152
+ else {
153
+ keypressHandler(key);
154
+ keypressHandler(nextKey);
155
+ }
314
156
  }
315
- }
316
- return data.length;
157
+ })();
158
+ bufferer.next(); // prime the generator so it starts listening.
159
+ return (key) => bufferer.next(key);
317
160
  }
318
161
  /**
319
- * A generator that takes in data chunks and spits out paste-start and
320
- * paste-end keypresses. All non-paste marker data is passed to passthrough.
162
+ * Buffers paste events between paste-start and paste-end sequences.
163
+ * Will flush the buffer if no data is received for PASTE_TIMEOUT ms or
164
+ * when a null key is received.
321
165
  */
322
- function* pasteMarkerParser(passthrough, keypressHandler) {
323
- while (true) {
324
- let data = yield;
325
- if (data.length === 0) {
326
- continue; // we timed out
327
- }
166
+ function bufferPaste(keypressHandler) {
167
+ const bufferer = (function* () {
328
168
  while (true) {
329
- const index = earliestPossiblePasteMarker(data);
330
- if (index === data.length) {
331
- // no possible paste markers were found
332
- passthrough.write(data);
333
- break;
169
+ let key = yield;
170
+ if (key === null) {
171
+ continue;
334
172
  }
335
- if (index > 0) {
336
- // snip off and send the part that doesn't have a paste marker
337
- passthrough.write(data.slice(0, index));
338
- data = data.slice(index);
173
+ else if (key.name !== 'paste-start') {
174
+ keypressHandler(key);
175
+ continue;
339
176
  }
340
- // data starts with a possible paste marker
341
- const codeLength = PASTE_MODE_START.length;
342
- if (data.length < codeLength) {
343
- // we have a prefix. Concat the next data and try again.
344
- const newData = yield;
345
- if (newData.length === 0) {
346
- // we timed out. Just dump what we have and start over.
347
- passthrough.write(data);
177
+ let buffer = '';
178
+ while (true) {
179
+ const timeoutId = setTimeout(() => bufferer.next(null), PASTE_TIMEOUT);
180
+ key = yield;
181
+ clearTimeout(timeoutId);
182
+ if (key === null) {
183
+ appEvents.emit(AppEvent.PasteTimeout);
184
+ break;
185
+ }
186
+ if (key.name === 'paste-end') {
348
187
  break;
349
188
  }
350
- data += newData;
189
+ buffer += key.sequence;
351
190
  }
352
- else if (data.startsWith(PASTE_MODE_START)) {
353
- keypressHandler(undefined, {
354
- name: 'paste-start',
191
+ if (buffer.length > 0) {
192
+ keypressHandler({
193
+ name: '',
355
194
  ctrl: false,
356
195
  meta: false,
357
196
  shift: false,
358
- paste: false,
359
- sequence: '',
197
+ paste: true,
198
+ insertable: true,
199
+ sequence: buffer,
360
200
  });
361
- data = data.slice(PASTE_MODE_START.length);
362
201
  }
363
- else if (data.startsWith(PASTE_MODE_END)) {
364
- keypressHandler(undefined, {
365
- name: 'paste-end',
366
- ctrl: false,
367
- meta: false,
368
- shift: false,
369
- paste: false,
370
- sequence: '',
371
- });
372
- data = data.slice(PASTE_MODE_END.length);
202
+ }
203
+ })();
204
+ bufferer.next(); // prime the generator so it starts listening.
205
+ return (key) => bufferer.next(key);
206
+ }
207
+ /**
208
+ * Turns raw data strings into keypress events sent to the provided handler.
209
+ * Buffers escape sequences until a full sequence is received or
210
+ * until a timeout occurs.
211
+ */
212
+ function createDataListener(keypressHandler) {
213
+ const parser = emitKeys(keypressHandler);
214
+ parser.next(); // prime the generator so it starts listening.
215
+ let timeoutId;
216
+ return (data) => {
217
+ clearTimeout(timeoutId);
218
+ for (const char of data) {
219
+ parser.next(char);
220
+ }
221
+ if (data.length !== 0) {
222
+ timeoutId = setTimeout(() => parser.next(''), ESC_TIMEOUT);
223
+ }
224
+ };
225
+ }
226
+ /**
227
+ * Translates raw keypress characters into key events.
228
+ * Buffers escape sequences until a full sequence is received or
229
+ * until an empty string is sent to indicate a timeout.
230
+ */
231
+ function* emitKeys(keypressHandler) {
232
+ while (true) {
233
+ let ch = yield;
234
+ let sequence = ch;
235
+ let escaped = false;
236
+ let name = undefined;
237
+ let ctrl = false;
238
+ let meta = false;
239
+ let shift = false;
240
+ let code = undefined;
241
+ let insertable = false;
242
+ if (ch === ESC) {
243
+ escaped = true;
244
+ ch = yield;
245
+ sequence += ch;
246
+ if (ch === ESC) {
247
+ ch = yield;
248
+ sequence += ch;
249
+ }
250
+ }
251
+ if (escaped && (ch === 'O' || ch === '[')) {
252
+ // ANSI escape sequence
253
+ code = ch;
254
+ let modifier = 0;
255
+ if (ch === 'O') {
256
+ // ESC O letter
257
+ // ESC O modifier letter
258
+ ch = yield;
259
+ sequence += ch;
260
+ if (ch >= '0' && ch <= '9') {
261
+ modifier = parseInt(ch, 10) - 1;
262
+ ch = yield;
263
+ sequence += ch;
264
+ }
265
+ code += ch;
266
+ }
267
+ else if (ch === '[') {
268
+ // ESC [ letter
269
+ // ESC [ modifier letter
270
+ // ESC [ [ modifier letter
271
+ // ESC [ [ num char
272
+ ch = yield;
273
+ sequence += ch;
274
+ if (ch === '[') {
275
+ // \x1b[[A
276
+ // ^--- escape codes might have a second bracket
277
+ code += ch;
278
+ ch = yield;
279
+ sequence += ch;
280
+ }
281
+ /*
282
+ * Here and later we try to buffer just enough data to get
283
+ * a complete ascii sequence.
284
+ *
285
+ * We have basically two classes of ascii characters to process:
286
+ *
287
+ *
288
+ * 1. `\x1b[24;5~` should be parsed as { code: '[24~', modifier: 5 }
289
+ *
290
+ * This particular example is featuring Ctrl+F12 in xterm.
291
+ *
292
+ * - `;5` part is optional, e.g. it could be `\x1b[24~`
293
+ * - first part can contain one or two digits
294
+ * - there is also special case when there can be 3 digits
295
+ * but without modifier. They are the case of paste bracket mode
296
+ *
297
+ * So the generic regexp is like /^(?:\d\d?(;\d)?[~^$]|\d{3}~)$/
298
+ *
299
+ *
300
+ * 2. `\x1b[1;5H` should be parsed as { code: '[H', modifier: 5 }
301
+ *
302
+ * This particular example is featuring Ctrl+Home in xterm.
303
+ *
304
+ * - `1;5` part is optional, e.g. it could be `\x1b[H`
305
+ * - `1;` part is optional, e.g. it could be `\x1b[5H`
306
+ *
307
+ * So the generic regexp is like /^((\d;)?\d)?[A-Za-z]$/
308
+ *
309
+ */
310
+ const cmdStart = sequence.length - 1;
311
+ // collect as many digits as possible
312
+ while (ch >= '0' && ch <= '9') {
313
+ ch = yield;
314
+ sequence += ch;
315
+ }
316
+ // skip modifier
317
+ if (ch === ';') {
318
+ ch = yield;
319
+ sequence += ch;
320
+ // collect as many digits as possible
321
+ while (ch >= '0' && ch <= '9') {
322
+ ch = yield;
323
+ sequence += ch;
324
+ }
325
+ }
326
+ else if (ch === '<') {
327
+ // SGR mouse mode
328
+ ch = yield;
329
+ sequence += ch;
330
+ // Don't skip on empty string here to avoid timeouts on slow events.
331
+ while (ch === '' || ch === ';' || (ch >= '0' && ch <= '9')) {
332
+ ch = yield;
333
+ sequence += ch;
334
+ }
335
+ }
336
+ else if (ch === 'M') {
337
+ // X11 mouse mode
338
+ // three characters after 'M'
339
+ ch = yield;
340
+ sequence += ch;
341
+ ch = yield;
342
+ sequence += ch;
343
+ ch = yield;
344
+ sequence += ch;
345
+ }
346
+ /*
347
+ * We buffered enough data, now trying to extract code
348
+ * and modifier from it
349
+ */
350
+ const cmd = sequence.slice(cmdStart);
351
+ let match;
352
+ if ((match = /^(\d+)(?:;(\d+))?([~^$u])$/.exec(cmd))) {
353
+ code += match[1] + match[3];
354
+ // Defaults to '1' if no modifier exists, resulting in a 0 modifier value
355
+ modifier = parseInt(match[2] ?? '1', 10) - 1;
356
+ }
357
+ else if ((match = /^((\d;)?(\d))?([A-Za-z])$/.exec(cmd))) {
358
+ code += match[4];
359
+ modifier = parseInt(match[3] ?? '1', 10) - 1;
360
+ }
361
+ else {
362
+ code += cmd;
363
+ }
364
+ }
365
+ // Parse the key modifier
366
+ ctrl = !!(modifier & 4);
367
+ meta = !!(modifier & 10); // use 10 to catch both alt (2) and meta (8).
368
+ shift = !!(modifier & 1);
369
+ const keyInfo = KEY_INFO_MAP[code];
370
+ if (keyInfo) {
371
+ name = keyInfo.name;
372
+ if (keyInfo.shift) {
373
+ shift = true;
374
+ }
375
+ if (keyInfo.ctrl) {
376
+ ctrl = true;
377
+ }
373
378
  }
374
379
  else {
375
- // This should never happen.
376
- passthrough.write(data);
377
- break;
380
+ name = 'undefined';
381
+ if ((ctrl || meta) && (code.endsWith('u') || code.endsWith('~'))) {
382
+ // CSI-u or tilde-coded functional keys: ESC [ <code> ; <mods> (u|~)
383
+ const codeNumber = parseInt(code.slice(1, -1), 10);
384
+ if (codeNumber >= 'a'.charCodeAt(0) &&
385
+ codeNumber <= 'z'.charCodeAt(0)) {
386
+ name = String.fromCharCode(codeNumber);
387
+ }
388
+ }
378
389
  }
379
390
  }
391
+ else if (ch === '\r') {
392
+ // carriage return
393
+ name = 'return';
394
+ meta = escaped;
395
+ }
396
+ else if (ch === '\n') {
397
+ // Enter, should have been called linefeed
398
+ name = 'enter';
399
+ meta = escaped;
400
+ }
401
+ else if (ch === '\t') {
402
+ // tab
403
+ name = 'tab';
404
+ meta = escaped;
405
+ }
406
+ else if (ch === '\b' || ch === '\x7f') {
407
+ // backspace or ctrl+h
408
+ name = 'backspace';
409
+ meta = escaped;
410
+ }
411
+ else if (ch === ESC) {
412
+ // escape key
413
+ name = 'escape';
414
+ meta = escaped;
415
+ }
416
+ else if (ch === ' ') {
417
+ name = 'space';
418
+ meta = escaped;
419
+ insertable = true;
420
+ }
421
+ else if (!escaped && ch <= '\x1a') {
422
+ // ctrl+letter
423
+ name = String.fromCharCode(ch.charCodeAt(0) + 'a'.charCodeAt(0) - 1);
424
+ ctrl = true;
425
+ }
426
+ else if (/^[0-9A-Za-z]$/.exec(ch) !== null) {
427
+ // Letter, number, shift+letter
428
+ name = ch.toLowerCase();
429
+ shift = /^[A-Z]$/.exec(ch) !== null;
430
+ meta = escaped;
431
+ insertable = true;
432
+ }
433
+ else if (MAC_ALT_KEY_CHARACTER_MAP[ch] && process.platform === 'darwin') {
434
+ name = MAC_ALT_KEY_CHARACTER_MAP[ch];
435
+ meta = true;
436
+ }
437
+ else if (sequence === `${ESC}${ESC}`) {
438
+ // Double escape
439
+ name = 'escape';
440
+ meta = true;
441
+ // Emit first escape key here, then continue processing
442
+ keypressHandler({
443
+ name: 'escape',
444
+ ctrl,
445
+ meta,
446
+ shift,
447
+ paste: false,
448
+ insertable: false,
449
+ sequence: ESC,
450
+ });
451
+ }
452
+ else if (escaped) {
453
+ // Escape sequence timeout
454
+ name = ch.length ? undefined : 'escape';
455
+ meta = true;
456
+ }
457
+ else {
458
+ // Any other character is considered printable.
459
+ insertable = true;
460
+ }
461
+ if ((sequence.length !== 0 && (name !== undefined || escaped)) ||
462
+ charLengthAt(sequence, 0) === sequence.length) {
463
+ keypressHandler({
464
+ name: name || '',
465
+ ctrl,
466
+ meta,
467
+ shift,
468
+ paste: false,
469
+ insertable,
470
+ sequence,
471
+ });
472
+ }
473
+ // Unrecognized or broken escape sequence, don't emit anything
380
474
  }
381
475
  }
382
476
  const KeypressContext = createContext(undefined);
@@ -387,10 +481,7 @@ export function useKeypressContext() {
387
481
  }
388
482
  return context;
389
483
  }
390
- function shouldUsePassthrough() {
391
- return process.env['PASTE_WORKAROUND'] !== 'false';
392
- }
393
- export function KeypressProvider({ children, kittyProtocolEnabled, config, debugKeystrokeLogging, }) {
484
+ export function KeypressProvider({ children, config, debugKeystrokeLogging, }) {
394
485
  const { stdin, setRawMode } = useStdin();
395
486
  const subscribers = useRef(new Set()).current;
396
487
  const subscribe = useCallback((handler) => subscribers.add(handler), [subscribers]);
@@ -401,419 +492,28 @@ export function KeypressProvider({ children, kittyProtocolEnabled, config, debug
401
492
  if (wasRaw === false) {
402
493
  setRawMode(true);
403
494
  }
404
- const keypressStream = shouldUsePassthrough() ? new PassThrough() : null;
405
- // If non-null that means we are in paste mode
406
- let pasteBuffer = null;
407
- // Used to turn "\" quickly followed by a "enter" into a shift enter
408
- let backslashTimeout = null;
409
- // Buffers incomplete sequences (Kitty or Mouse) and timer to flush it
410
- let inputBuffer = '';
411
- let inputTimeout = null;
412
- // Used to detect filename drag-and-drops.
413
- let dragBuffer = '';
414
- let draggingTimer = null;
415
- const clearDraggingTimer = () => {
416
- if (draggingTimer) {
417
- clearTimeout(draggingTimer);
418
- draggingTimer = null;
419
- }
420
- };
421
- const flushInputBufferOnInterrupt = (reason) => {
422
- if (inputBuffer) {
423
- if (debugKeystrokeLogging) {
424
- debugLogger.log(`[DEBUG] Input sequence flushed due to ${reason}:`, JSON.stringify(inputBuffer));
425
- }
426
- broadcast({
427
- name: '',
428
- ctrl: false,
429
- meta: false,
430
- shift: false,
431
- paste: false,
432
- sequence: inputBuffer,
433
- });
434
- inputBuffer = '';
435
- }
436
- if (inputTimeout) {
437
- clearTimeout(inputTimeout);
438
- inputTimeout = null;
439
- }
440
- };
441
- const handleKeypress = (_, key) => {
442
- if (key.sequence === FOCUS_IN || key.sequence === FOCUS_OUT) {
443
- flushInputBufferOnInterrupt('focus event');
444
- return;
445
- }
446
- if (key.name === 'paste-start') {
447
- flushInputBufferOnInterrupt('paste start');
448
- pasteBuffer = Buffer.alloc(0);
449
- return;
450
- }
451
- if (key.name === 'paste-end') {
452
- if (pasteBuffer !== null) {
453
- broadcast({
454
- name: '',
455
- ctrl: false,
456
- meta: false,
457
- shift: false,
458
- paste: true,
459
- sequence: pasteBuffer.toString(),
460
- });
461
- }
462
- pasteBuffer = null;
463
- return;
464
- }
465
- if (pasteBuffer !== null) {
466
- pasteBuffer = Buffer.concat([pasteBuffer, Buffer.from(key.sequence)]);
467
- return;
468
- }
469
- if (key.sequence === SINGLE_QUOTE ||
470
- key.sequence === DOUBLE_QUOTE ||
471
- draggingTimer !== null) {
472
- dragBuffer += key.sequence;
473
- clearDraggingTimer();
474
- draggingTimer = setTimeout(() => {
475
- draggingTimer = null;
476
- const seq = dragBuffer;
477
- dragBuffer = '';
478
- if (seq) {
479
- broadcast({ ...key, name: '', paste: true, sequence: seq });
480
- }
481
- }, DRAG_COMPLETION_TIMEOUT_MS);
482
- return;
483
- }
484
- const mappedLetter = MAC_ALT_KEY_CHARACTER_MAP[key.sequence];
485
- if (process.platform === 'darwin' && mappedLetter && !key.meta) {
486
- broadcast({
487
- name: mappedLetter,
488
- ctrl: false,
489
- meta: true,
490
- shift: false,
491
- paste: pasteBuffer !== null,
492
- sequence: key.sequence,
493
- });
494
- return;
495
- }
496
- if (key.name === 'return' && backslashTimeout !== null) {
497
- clearTimeout(backslashTimeout);
498
- backslashTimeout = null;
499
- broadcast({
500
- ...key,
501
- shift: true,
502
- sequence: '\r', // Corrected escaping for newline
503
- });
504
- return;
505
- }
506
- if (key.sequence === '\\' && !key.name) {
507
- // Corrected escaping for backslash
508
- backslashTimeout = setTimeout(() => {
509
- backslashTimeout = null;
510
- broadcast(key);
511
- }, BACKSLASH_ENTER_DETECTION_WINDOW_MS);
512
- return;
513
- }
514
- if (backslashTimeout !== null && key.name !== 'return') {
515
- clearTimeout(backslashTimeout);
516
- backslashTimeout = null;
517
- broadcast({
518
- name: '',
519
- sequence: '\\',
520
- ctrl: false,
521
- meta: false,
522
- shift: false,
523
- paste: false,
524
- });
525
- }
526
- if (['up', 'down', 'left', 'right'].includes(key.name)) {
527
- broadcast(key);
528
- return;
529
- }
530
- if ((key.ctrl && key.name === 'c') ||
531
- key.sequence === `${ESC}${KITTY_CTRL_C}`) {
532
- if (inputBuffer && debugKeystrokeLogging) {
533
- debugLogger.log('[DEBUG] Input buffer cleared on Ctrl+C:', inputBuffer);
534
- }
535
- inputBuffer = '';
536
- if (inputTimeout) {
537
- clearTimeout(inputTimeout);
538
- inputTimeout = null;
539
- }
540
- if (key.sequence === `${ESC}${KITTY_CTRL_C}`) {
541
- broadcast({
542
- name: 'c',
543
- ctrl: true,
544
- meta: false,
545
- shift: false,
546
- paste: false,
547
- sequence: key.sequence,
548
- kittyProtocol: true,
549
- });
495
+ process.stdin.setEncoding('utf8'); // Make data events emit strings
496
+ const mouseFilterer = nonKeyboardEventFilter(broadcast);
497
+ const backslashBufferer = bufferBackslashEnter(mouseFilterer);
498
+ const pasteBufferer = bufferPaste(backslashBufferer);
499
+ let dataListener = createDataListener(pasteBufferer);
500
+ if (debugKeystrokeLogging) {
501
+ const old = dataListener;
502
+ dataListener = (data) => {
503
+ if (data.length > 0) {
504
+ debugLogger.log(`[DEBUG] Raw StdIn: ${JSON.stringify(data)}`);
550
505
  }
551
- else {
552
- broadcast(key);
553
- }
554
- return;
555
- }
556
- // Clear any pending timeout when new input arrives
557
- if (inputTimeout) {
558
- clearTimeout(inputTimeout);
559
- inputTimeout = null;
560
- }
561
- // Always check if this could start a sequence we need to buffer (Kitty or Mouse)
562
- // Other ESC sequences (like Alt+Key which is ESC+Key) should be let through if readline parsed them.
563
- const shouldBuffer = couldBeKittySequence(key.sequence);
564
- const isExcluded = [
565
- PASTE_MODE_START,
566
- PASTE_MODE_END,
567
- FOCUS_IN,
568
- FOCUS_OUT,
569
- ].some((prefix) => key.sequence.startsWith(prefix));
570
- if (inputBuffer || (shouldBuffer && !isExcluded)) {
571
- inputBuffer += key.sequence;
572
- if (debugKeystrokeLogging && !couldBeMouseSequence(inputBuffer)) {
573
- debugLogger.log('[DEBUG] Input buffer accumulating:', JSON.stringify(inputBuffer));
574
- }
575
- // Try immediate parsing
576
- let remainingBuffer = inputBuffer;
577
- let parsedAny = false;
578
- while (remainingBuffer) {
579
- const parsed = parseKittyPrefix(remainingBuffer);
580
- if (parsed) {
581
- // If kitty protocol is disabled, only allow legacy/standard sequences.
582
- // parseKittyPrefix returns true for kittyProtocol if it's a modern kitty sequence.
583
- if (kittyProtocolEnabled || !parsed.key.kittyProtocol) {
584
- if (debugKeystrokeLogging) {
585
- const parsedSequence = remainingBuffer.slice(0, parsed.length);
586
- debugLogger.log('[DEBUG] Sequence parsed successfully:', JSON.stringify(parsedSequence));
587
- }
588
- broadcast(parsed.key);
589
- remainingBuffer = remainingBuffer.slice(parsed.length);
590
- parsedAny = true;
591
- continue;
592
- }
593
- }
594
- const mouseParsed = parseMouseEvent(remainingBuffer);
595
- if (mouseParsed) {
596
- // These are handled by the separate mouse sequence parser.
597
- // All we need to do is make sure we don't get confused by these
598
- // sequences.
599
- remainingBuffer = remainingBuffer.slice(mouseParsed.length);
600
- parsedAny = true;
601
- continue;
602
- }
603
- // If we can't parse a sequence at the start, check if there's
604
- // another ESC later in the buffer. If so, the data before it
605
- // is garbage/incomplete and should be dropped so we can
606
- // process the next sequence.
607
- const nextEscIndex = remainingBuffer.indexOf(ESC, 1);
608
- if (nextEscIndex !== -1) {
609
- const garbage = remainingBuffer.slice(0, nextEscIndex);
610
- // Special case: if garbage is exactly ESC, it's likely a rapid ESC press.
611
- if (garbage === ESC) {
612
- if (debugKeystrokeLogging) {
613
- debugLogger.log('[DEBUG] Flushing rapid ESC before next ESC:', JSON.stringify(garbage));
614
- }
615
- broadcast({
616
- name: 'escape',
617
- ctrl: false,
618
- meta: true,
619
- shift: false,
620
- paste: false,
621
- sequence: garbage,
622
- });
623
- }
624
- else {
625
- if (debugKeystrokeLogging) {
626
- debugLogger.log('[DEBUG] Dropping incomplete sequence before next ESC:', JSON.stringify(garbage));
627
- }
628
- }
629
- // Continue parsing from next ESC
630
- remainingBuffer = remainingBuffer.slice(nextEscIndex);
631
- // We made progress, so we can continue the loop to parse the next sequence
632
- continue;
633
- }
634
- // Check if buffer could become a valid sequence
635
- const couldBeValidKitty = kittyProtocolEnabled && couldBeKittySequence(remainingBuffer);
636
- const isMouse = isIncompleteMouseSequence(remainingBuffer);
637
- const couldBeValid = couldBeValidKitty || isMouse;
638
- if (!couldBeValid) {
639
- // Not a valid sequence - flush as regular input immediately
640
- if (debugKeystrokeLogging) {
641
- debugLogger.log('[DEBUG] Not a valid sequence, flushing:', JSON.stringify(remainingBuffer));
642
- }
643
- broadcast({
644
- name: '',
645
- ctrl: false,
646
- meta: false,
647
- shift: false,
648
- paste: false,
649
- sequence: remainingBuffer,
650
- });
651
- remainingBuffer = '';
652
- parsedAny = true;
653
- }
654
- else if (remainingBuffer.length > MAX_KITTY_SEQUENCE_LENGTH) {
655
- // Buffer overflow - log and clear
656
- if (debugKeystrokeLogging) {
657
- debugLogger.log('[DEBUG] Input buffer overflow, clearing:', JSON.stringify(remainingBuffer));
658
- }
659
- if (config && kittyProtocolEnabled) {
660
- const event = new KittySequenceOverflowEvent(remainingBuffer.length, remainingBuffer);
661
- logKittySequenceOverflow(config, event);
662
- }
663
- // Flush as regular input
664
- broadcast({
665
- name: '',
666
- ctrl: false,
667
- meta: false,
668
- shift: false,
669
- paste: false,
670
- sequence: remainingBuffer,
671
- });
672
- remainingBuffer = '';
673
- parsedAny = true;
674
- }
675
- else {
676
- if ((config?.getDebugMode() || debugKeystrokeLogging) &&
677
- !couldBeMouseSequence(inputBuffer)) {
678
- debugLogger.warn('Input sequence buffer has content:', JSON.stringify(inputBuffer));
679
- }
680
- // Could be valid but incomplete - set timeout
681
- // Only set timeout if it's NOT a mouse sequence.
682
- // Mouse sequences might be slow (e.g. over network) and we don't want to
683
- // flush them as garbage keypresses.
684
- // However, if it's just ESC or ESC[, it might be a user typing slowly,
685
- // so we should still timeout in that case.
686
- const isAmbiguousPrefix = remainingBuffer === ESC || remainingBuffer === `${ESC}[`;
687
- if (!isMouse || isAmbiguousPrefix) {
688
- inputTimeout = setTimeout(() => {
689
- if (inputBuffer) {
690
- if (debugKeystrokeLogging) {
691
- debugLogger.log('[DEBUG] Input sequence timeout, flushing:', JSON.stringify(inputBuffer));
692
- }
693
- const isEscape = inputBuffer === ESC;
694
- broadcast({
695
- name: isEscape ? 'escape' : '',
696
- ctrl: false,
697
- meta: isEscape,
698
- shift: false,
699
- paste: false,
700
- sequence: inputBuffer,
701
- });
702
- inputBuffer = '';
703
- }
704
- inputTimeout = null;
705
- }, KITTY_SEQUENCE_TIMEOUT_MS);
706
- }
707
- else {
708
- // It IS a mouse sequence and it's long enough to be unambiguously NOT just a user hitting ESC slowly.
709
- // We just wait for more data.
710
- if (inputTimeout) {
711
- clearTimeout(inputTimeout);
712
- inputTimeout = null;
713
- }
714
- }
715
- break;
716
- }
717
- }
718
- inputBuffer = remainingBuffer;
719
- if (parsedAny || inputBuffer)
720
- return;
721
- }
722
- if (key.name === 'return' && key.sequence === `${ESC}\r`) {
723
- key.meta = true;
724
- }
725
- broadcast({ ...key, paste: pasteBuffer !== null });
726
- };
727
- let cleanup = () => { };
728
- let rl;
729
- if (keypressStream !== null) {
730
- rl = readline.createInterface({
731
- input: keypressStream,
732
- escapeCodeTimeout: 0,
733
- });
734
- readline.emitKeypressEvents(keypressStream, rl);
735
- const parser = pasteMarkerParser(keypressStream, handleKeypress);
736
- parser.next(); // prime the generator so it starts listening.
737
- let timeoutId;
738
- const handleRawKeypress = (data) => {
739
- clearTimeout(timeoutId);
740
- parser.next(data);
741
- timeoutId = setTimeout(() => parser.next(''), PASTE_CODE_TIMEOUT_MS);
742
- };
743
- keypressStream.on('keypress', handleKeypress);
744
- process.stdin.setEncoding('utf8'); // so handleRawKeypress gets strings
745
- stdin.on('data', handleRawKeypress);
746
- cleanup = () => {
747
- keypressStream.removeListener('keypress', handleKeypress);
748
- stdin.removeListener('data', handleRawKeypress);
506
+ old(data);
749
507
  };
750
508
  }
751
- else {
752
- rl = readline.createInterface({ input: stdin, escapeCodeTimeout: 0 });
753
- readline.emitKeypressEvents(stdin, rl);
754
- stdin.on('keypress', handleKeypress);
755
- cleanup = () => stdin.removeListener('keypress', handleKeypress);
756
- }
509
+ stdin.on('data', dataListener);
757
510
  return () => {
758
- cleanup();
759
- rl.close();
760
- // Restore the terminal to its original state.
511
+ stdin.removeListener('data', dataListener);
761
512
  if (wasRaw === false) {
762
513
  setRawMode(false);
763
514
  }
764
- if (backslashTimeout) {
765
- clearTimeout(backslashTimeout);
766
- backslashTimeout = null;
767
- }
768
- if (inputTimeout) {
769
- clearTimeout(inputTimeout);
770
- inputTimeout = null;
771
- }
772
- // Flush any pending kitty sequence data to avoid data loss on exit.
773
- if (inputBuffer) {
774
- broadcast({
775
- name: '',
776
- ctrl: false,
777
- meta: false,
778
- shift: false,
779
- paste: false,
780
- sequence: inputBuffer,
781
- });
782
- inputBuffer = '';
783
- }
784
- // Flush any pending paste data to avoid data loss on exit.
785
- if (pasteBuffer !== null) {
786
- broadcast({
787
- name: '',
788
- ctrl: false,
789
- meta: false,
790
- shift: false,
791
- paste: true,
792
- sequence: pasteBuffer.toString(),
793
- });
794
- pasteBuffer = null;
795
- }
796
- clearDraggingTimer();
797
- if (dragBuffer) {
798
- broadcast({
799
- name: '',
800
- ctrl: false,
801
- meta: false,
802
- shift: false,
803
- paste: true,
804
- sequence: dragBuffer,
805
- });
806
- dragBuffer = '';
807
- }
808
515
  };
809
- }, [
810
- stdin,
811
- setRawMode,
812
- kittyProtocolEnabled,
813
- config,
814
- debugKeystrokeLogging,
815
- broadcast,
816
- ]);
516
+ }, [stdin, setRawMode, config, debugKeystrokeLogging, broadcast]);
817
517
  return (_jsx(KeypressContext.Provider, { value: { subscribe, unsubscribe }, children: children }));
818
518
  }
819
519
  //# sourceMappingURL=KeypressContext.js.map