nastech-tui 0.0.1

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 (424) hide show
  1. package/.prettierrc +11 -0
  2. package/README.md +346 -0
  3. package/eslint.config.mjs +111 -0
  4. package/package.json +51 -0
  5. package/packages/nastech-ink/ambient.d.ts +83 -0
  6. package/packages/nastech-ink/index.d.ts +40 -0
  7. package/packages/nastech-ink/index.js +1 -0
  8. package/packages/nastech-ink/nastech-ink/ambient.d.ts +83 -0
  9. package/packages/nastech-ink/nastech-ink/index.d.ts +40 -0
  10. package/packages/nastech-ink/nastech-ink/index.js +1 -0
  11. package/packages/nastech-ink/nastech-ink/package.json +54 -0
  12. package/packages/nastech-ink/nastech-ink/src/bootstrap/state.ts +9 -0
  13. package/packages/nastech-ink/nastech-ink/src/entry-exports.ts +32 -0
  14. package/packages/nastech-ink/nastech-ink/src/hooks/use-stderr.ts +15 -0
  15. package/packages/nastech-ink/nastech-ink/src/hooks/use-stdout.ts +15 -0
  16. package/packages/nastech-ink/nastech-ink/src/ink/Ansi.tsx +435 -0
  17. package/packages/nastech-ink/nastech-ink/src/ink/app-mouse.test.ts +123 -0
  18. package/packages/nastech-ink/nastech-ink/src/ink/bidi.ts +145 -0
  19. package/packages/nastech-ink/nastech-ink/src/ink/cache-eviction.ts +45 -0
  20. package/packages/nastech-ink/nastech-ink/src/ink/clearTerminal.ts +68 -0
  21. package/packages/nastech-ink/nastech-ink/src/ink/colorize.test.ts +60 -0
  22. package/packages/nastech-ink/nastech-ink/src/ink/colorize.ts +277 -0
  23. package/packages/nastech-ink/nastech-ink/src/ink/components/AlternateScreen.tsx +133 -0
  24. package/packages/nastech-ink/nastech-ink/src/ink/components/App.tsx +830 -0
  25. package/packages/nastech-ink/nastech-ink/src/ink/components/AppContext.ts +20 -0
  26. package/packages/nastech-ink/nastech-ink/src/ink/components/Box.tsx +294 -0
  27. package/packages/nastech-ink/nastech-ink/src/ink/components/Button.tsx +236 -0
  28. package/packages/nastech-ink/nastech-ink/src/ink/components/ClockContext.tsx +133 -0
  29. package/packages/nastech-ink/nastech-ink/src/ink/components/CursorAdvanceContext.ts +35 -0
  30. package/packages/nastech-ink/nastech-ink/src/ink/components/CursorDeclarationContext.ts +28 -0
  31. package/packages/nastech-ink/nastech-ink/src/ink/components/ErrorOverview.tsx +130 -0
  32. package/packages/nastech-ink/nastech-ink/src/ink/components/Link.tsx +38 -0
  33. package/packages/nastech-ink/nastech-ink/src/ink/components/Newline.tsx +43 -0
  34. package/packages/nastech-ink/nastech-ink/src/ink/components/NoSelect.tsx +73 -0
  35. package/packages/nastech-ink/nastech-ink/src/ink/components/RawAnsi.tsx +61 -0
  36. package/packages/nastech-ink/nastech-ink/src/ink/components/ScrollBox.tsx +290 -0
  37. package/packages/nastech-ink/nastech-ink/src/ink/components/Spacer.tsx +23 -0
  38. package/packages/nastech-ink/nastech-ink/src/ink/components/StdinContext.ts +25 -0
  39. package/packages/nastech-ink/nastech-ink/src/ink/components/TerminalFocusContext.tsx +63 -0
  40. package/packages/nastech-ink/nastech-ink/src/ink/components/TerminalSizeContext.tsx +7 -0
  41. package/packages/nastech-ink/nastech-ink/src/ink/components/Text.test.ts +38 -0
  42. package/packages/nastech-ink/nastech-ink/src/ink/components/Text.tsx +336 -0
  43. package/packages/nastech-ink/nastech-ink/src/ink/constants.ts +6 -0
  44. package/packages/nastech-ink/nastech-ink/src/ink/cursor.ts +5 -0
  45. package/packages/nastech-ink/nastech-ink/src/ink/devtools.ts +2 -0
  46. package/packages/nastech-ink/nastech-ink/src/ink/dom.ts +495 -0
  47. package/packages/nastech-ink/nastech-ink/src/ink/events/click-event.ts +38 -0
  48. package/packages/nastech-ink/nastech-ink/src/ink/events/cmd-shortcuts.test.ts +65 -0
  49. package/packages/nastech-ink/nastech-ink/src/ink/events/dispatcher.ts +242 -0
  50. package/packages/nastech-ink/nastech-ink/src/ink/events/emitter.ts +40 -0
  51. package/packages/nastech-ink/nastech-ink/src/ink/events/event-handlers.ts +84 -0
  52. package/packages/nastech-ink/nastech-ink/src/ink/events/event.ts +11 -0
  53. package/packages/nastech-ink/nastech-ink/src/ink/events/focus-event.ts +18 -0
  54. package/packages/nastech-ink/nastech-ink/src/ink/events/input-event.ts +176 -0
  55. package/packages/nastech-ink/nastech-ink/src/ink/events/keyboard-event.ts +57 -0
  56. package/packages/nastech-ink/nastech-ink/src/ink/events/mouse-event.ts +18 -0
  57. package/packages/nastech-ink/nastech-ink/src/ink/events/paste-event.ts +10 -0
  58. package/packages/nastech-ink/nastech-ink/src/ink/events/resize-event.ts +12 -0
  59. package/packages/nastech-ink/nastech-ink/src/ink/events/terminal-event.ts +107 -0
  60. package/packages/nastech-ink/nastech-ink/src/ink/events/terminal-focus-event.ts +19 -0
  61. package/packages/nastech-ink/nastech-ink/src/ink/focus.ts +219 -0
  62. package/packages/nastech-ink/nastech-ink/src/ink/frame.ts +124 -0
  63. package/packages/nastech-ink/nastech-ink/src/ink/get-max-width.ts +27 -0
  64. package/packages/nastech-ink/nastech-ink/src/ink/global.d.ts +1 -0
  65. package/packages/nastech-ink/nastech-ink/src/ink/hit-test.test.ts +38 -0
  66. package/packages/nastech-ink/nastech-ink/src/ink/hit-test.ts +224 -0
  67. package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-animation-frame.ts +62 -0
  68. package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-app.ts +9 -0
  69. package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-cursor-advance.ts +33 -0
  70. package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-declared-cursor.ts +75 -0
  71. package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-external-process.ts +27 -0
  72. package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-input.ts +95 -0
  73. package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-interval.ts +71 -0
  74. package/packages/nastech-ink/package.json +57 -0
  75. package/packages/nastech-ink/src/bootstrap/state.ts +9 -0
  76. package/packages/nastech-ink/src/entry-exports.ts +32 -0
  77. package/packages/nastech-ink/src/hooks/use-stderr.ts +15 -0
  78. package/packages/nastech-ink/src/hooks/use-stdout.ts +15 -0
  79. package/packages/nastech-ink/src/ink/Ansi.tsx +435 -0
  80. package/packages/nastech-ink/src/ink/app-mouse.test.ts +123 -0
  81. package/packages/nastech-ink/src/ink/app-rawmode-mouse.test.ts +91 -0
  82. package/packages/nastech-ink/src/ink/bidi.ts +145 -0
  83. package/packages/nastech-ink/src/ink/cache-eviction.ts +45 -0
  84. package/packages/nastech-ink/src/ink/clearTerminal.ts +68 -0
  85. package/packages/nastech-ink/src/ink/colorize.test.ts +60 -0
  86. package/packages/nastech-ink/src/ink/colorize.ts +277 -0
  87. package/packages/nastech-ink/src/ink/components/AlternateScreen.tsx +133 -0
  88. package/packages/nastech-ink/src/ink/components/App.tsx +855 -0
  89. package/packages/nastech-ink/src/ink/components/AppContext.ts +20 -0
  90. package/packages/nastech-ink/src/ink/components/Box.tsx +294 -0
  91. package/packages/nastech-ink/src/ink/components/Button.tsx +236 -0
  92. package/packages/nastech-ink/src/ink/components/ClockContext.tsx +133 -0
  93. package/packages/nastech-ink/src/ink/components/CursorAdvanceContext.ts +35 -0
  94. package/packages/nastech-ink/src/ink/components/CursorDeclarationContext.ts +28 -0
  95. package/packages/nastech-ink/src/ink/components/ErrorOverview.tsx +130 -0
  96. package/packages/nastech-ink/src/ink/components/Link.tsx +38 -0
  97. package/packages/nastech-ink/src/ink/components/Newline.tsx +43 -0
  98. package/packages/nastech-ink/src/ink/components/NoSelect.tsx +73 -0
  99. package/packages/nastech-ink/src/ink/components/RawAnsi.tsx +61 -0
  100. package/packages/nastech-ink/src/ink/components/ScrollBox.tsx +290 -0
  101. package/packages/nastech-ink/src/ink/components/Spacer.tsx +23 -0
  102. package/packages/nastech-ink/src/ink/components/StdinContext.ts +25 -0
  103. package/packages/nastech-ink/src/ink/components/TerminalFocusContext.tsx +63 -0
  104. package/packages/nastech-ink/src/ink/components/TerminalSizeContext.tsx +7 -0
  105. package/packages/nastech-ink/src/ink/components/Text.test.ts +38 -0
  106. package/packages/nastech-ink/src/ink/components/Text.tsx +336 -0
  107. package/packages/nastech-ink/src/ink/constants.ts +6 -0
  108. package/packages/nastech-ink/src/ink/cursor.ts +5 -0
  109. package/packages/nastech-ink/src/ink/devtools.ts +2 -0
  110. package/packages/nastech-ink/src/ink/dom.ts +495 -0
  111. package/packages/nastech-ink/src/ink/events/click-event.ts +38 -0
  112. package/packages/nastech-ink/src/ink/events/cmd-shortcuts.test.ts +65 -0
  113. package/packages/nastech-ink/src/ink/events/dispatcher.ts +242 -0
  114. package/packages/nastech-ink/src/ink/events/emitter.ts +40 -0
  115. package/packages/nastech-ink/src/ink/events/event-handlers.ts +84 -0
  116. package/packages/nastech-ink/src/ink/events/event.ts +11 -0
  117. package/packages/nastech-ink/src/ink/events/focus-event.ts +18 -0
  118. package/packages/nastech-ink/src/ink/events/input-event.ts +176 -0
  119. package/packages/nastech-ink/src/ink/events/keyboard-event.ts +57 -0
  120. package/packages/nastech-ink/src/ink/events/mouse-event.ts +18 -0
  121. package/packages/nastech-ink/src/ink/events/paste-event.ts +10 -0
  122. package/packages/nastech-ink/src/ink/events/resize-event.ts +12 -0
  123. package/packages/nastech-ink/src/ink/events/terminal-event.ts +107 -0
  124. package/packages/nastech-ink/src/ink/events/terminal-focus-event.ts +19 -0
  125. package/packages/nastech-ink/src/ink/focus.ts +219 -0
  126. package/packages/nastech-ink/src/ink/frame.ts +124 -0
  127. package/packages/nastech-ink/src/ink/get-max-width.ts +27 -0
  128. package/packages/nastech-ink/src/ink/global.d.ts +1 -0
  129. package/packages/nastech-ink/src/ink/hit-test.test.ts +38 -0
  130. package/packages/nastech-ink/src/ink/hit-test.ts +224 -0
  131. package/packages/nastech-ink/src/ink/hooks/use-animation-frame.ts +62 -0
  132. package/packages/nastech-ink/src/ink/hooks/use-app.ts +9 -0
  133. package/packages/nastech-ink/src/ink/hooks/use-cursor-advance.ts +33 -0
  134. package/packages/nastech-ink/src/ink/hooks/use-declared-cursor.ts +75 -0
  135. package/packages/nastech-ink/src/ink/hooks/use-external-process.ts +27 -0
  136. package/packages/nastech-ink/src/ink/hooks/use-input.ts +95 -0
  137. package/packages/nastech-ink/src/ink/hooks/use-interval.ts +71 -0
  138. package/packages/nastech-ink/src/ink/hooks/use-search-highlight.ts +56 -0
  139. package/packages/nastech-ink/src/ink/hooks/use-selection.ts +101 -0
  140. package/packages/nastech-ink/src/ink/hooks/use-stdin.ts +9 -0
  141. package/packages/nastech-ink/src/ink/hooks/use-tab-status.ts +71 -0
  142. package/packages/nastech-ink/src/ink/hooks/use-terminal-focus.ts +18 -0
  143. package/packages/nastech-ink/src/ink/hooks/use-terminal-title.ts +34 -0
  144. package/packages/nastech-ink/src/ink/hooks/use-terminal-viewport.ts +100 -0
  145. package/packages/nastech-ink/src/ink/hyperlinkHover.ts +52 -0
  146. package/packages/nastech-ink/src/ink/ink-cursor-advance.test.ts +234 -0
  147. package/packages/nastech-ink/src/ink/ink-resize.test.ts +50 -0
  148. package/packages/nastech-ink/src/ink/ink.tsx +2705 -0
  149. package/packages/nastech-ink/src/ink/instances.ts +10 -0
  150. package/packages/nastech-ink/src/ink/layout/engine.ts +6 -0
  151. package/packages/nastech-ink/src/ink/layout/geometry.ts +98 -0
  152. package/packages/nastech-ink/src/ink/layout/node.ts +145 -0
  153. package/packages/nastech-ink/src/ink/layout/yoga.ts +313 -0
  154. package/packages/nastech-ink/src/ink/line-width-cache.ts +38 -0
  155. package/packages/nastech-ink/src/ink/log-update.test.ts +223 -0
  156. package/packages/nastech-ink/src/ink/log-update.ts +752 -0
  157. package/packages/nastech-ink/src/ink/lru.ts +14 -0
  158. package/packages/nastech-ink/src/ink/measure-element.ts +23 -0
  159. package/packages/nastech-ink/src/ink/measure-text.ts +50 -0
  160. package/packages/nastech-ink/src/ink/node-cache.ts +53 -0
  161. package/packages/nastech-ink/src/ink/optimizer.ts +99 -0
  162. package/packages/nastech-ink/src/ink/output.ts +845 -0
  163. package/packages/nastech-ink/src/ink/parse-keypress.test.ts +133 -0
  164. package/packages/nastech-ink/src/ink/parse-keypress.ts +848 -0
  165. package/packages/nastech-ink/src/ink/reconciler.ts +382 -0
  166. package/packages/nastech-ink/src/ink/render-border.ts +206 -0
  167. package/packages/nastech-ink/src/ink/render-node-to-output.ts +1582 -0
  168. package/packages/nastech-ink/src/ink/render-to-screen.ts +236 -0
  169. package/packages/nastech-ink/src/ink/renderer.ts +169 -0
  170. package/packages/nastech-ink/src/ink/root.ts +204 -0
  171. package/packages/nastech-ink/src/ink/screen.ts +1590 -0
  172. package/packages/nastech-ink/src/ink/searchHighlight.ts +91 -0
  173. package/packages/nastech-ink/src/ink/selection.test.ts +82 -0
  174. package/packages/nastech-ink/src/ink/selection.ts +1143 -0
  175. package/packages/nastech-ink/src/ink/squash-text-nodes.ts +74 -0
  176. package/packages/nastech-ink/src/ink/stringWidth.ts +341 -0
  177. package/packages/nastech-ink/src/ink/styles.ts +750 -0
  178. package/packages/nastech-ink/src/ink/supports-hyperlinks.ts +51 -0
  179. package/packages/nastech-ink/src/ink/tabstops.ts +44 -0
  180. package/packages/nastech-ink/src/ink/terminal-focus-state.ts +52 -0
  181. package/packages/nastech-ink/src/ink/terminal-querier.ts +222 -0
  182. package/packages/nastech-ink/src/ink/terminal.test.ts +15 -0
  183. package/packages/nastech-ink/src/ink/terminal.ts +299 -0
  184. package/packages/nastech-ink/src/ink/termio/ansi.ts +75 -0
  185. package/packages/nastech-ink/src/ink/termio/csi.ts +334 -0
  186. package/packages/nastech-ink/src/ink/termio/dec.ts +99 -0
  187. package/packages/nastech-ink/src/ink/termio/esc.ts +69 -0
  188. package/packages/nastech-ink/src/ink/termio/osc.test.ts +191 -0
  189. package/packages/nastech-ink/src/ink/termio/osc.ts +724 -0
  190. package/packages/nastech-ink/src/ink/termio/parser.ts +467 -0
  191. package/packages/nastech-ink/src/ink/termio/sgr.ts +362 -0
  192. package/packages/nastech-ink/src/ink/termio/tokenize.test.ts +185 -0
  193. package/packages/nastech-ink/src/ink/termio/tokenize.ts +350 -0
  194. package/packages/nastech-ink/src/ink/termio/types.ts +230 -0
  195. package/packages/nastech-ink/src/ink/termio.ts +42 -0
  196. package/packages/nastech-ink/src/ink/useTerminalNotification.ts +110 -0
  197. package/packages/nastech-ink/src/ink/warn.ts +15 -0
  198. package/packages/nastech-ink/src/ink/widest-line.ts +22 -0
  199. package/packages/nastech-ink/src/ink/wrap-text.test.ts +17 -0
  200. package/packages/nastech-ink/src/ink/wrap-text.ts +144 -0
  201. package/packages/nastech-ink/src/ink/wrapAnsi.ts +13 -0
  202. package/packages/nastech-ink/src/native-ts/yoga-layout/enums.ts +112 -0
  203. package/packages/nastech-ink/src/native-ts/yoga-layout/index.ts +2326 -0
  204. package/packages/nastech-ink/src/utils/debug.ts +6 -0
  205. package/packages/nastech-ink/src/utils/earlyInput.ts +131 -0
  206. package/packages/nastech-ink/src/utils/env.ts +66 -0
  207. package/packages/nastech-ink/src/utils/envUtils.ts +13 -0
  208. package/packages/nastech-ink/src/utils/execFileNoThrow.test.ts +146 -0
  209. package/packages/nastech-ink/src/utils/execFileNoThrow.ts +115 -0
  210. package/packages/nastech-ink/src/utils/fullscreen.ts +3 -0
  211. package/packages/nastech-ink/src/utils/intl.ts +87 -0
  212. package/packages/nastech-ink/src/utils/log.ts +7 -0
  213. package/packages/nastech-ink/src/utils/semver.ts +57 -0
  214. package/packages/nastech-ink/src/utils/sliceAnsi.ts +106 -0
  215. package/packages/nastech-ink/text-input.d.ts +2 -0
  216. package/packages/nastech-ink/text-input.js +1 -0
  217. package/scripts/build.mjs +61 -0
  218. package/scripts/profile-tui.mjs +121 -0
  219. package/src/__tests__/activeSessionSwitcher.test.ts +157 -0
  220. package/src/__tests__/appChromeStatusRule.test.tsx +84 -0
  221. package/src/__tests__/appChromeStatusRuleDevCredits.test.tsx +73 -0
  222. package/src/__tests__/approvalAction.test.ts +50 -0
  223. package/src/__tests__/asCommandDispatch.test.ts +27 -0
  224. package/src/__tests__/blockLayout.test.ts +122 -0
  225. package/src/__tests__/clipboard.test.ts +369 -0
  226. package/src/__tests__/constants.test.ts +53 -0
  227. package/src/__tests__/createGatewayEventHandler.test.ts +1091 -0
  228. package/src/__tests__/createSlashHandler.test.ts +822 -0
  229. package/src/__tests__/creditsCommand.test.ts +144 -0
  230. package/src/__tests__/cursorDriftRegression.test.ts +114 -0
  231. package/src/__tests__/details.test.ts +115 -0
  232. package/src/__tests__/emoji.test.ts +64 -0
  233. package/src/__tests__/externalLink.test.ts +144 -0
  234. package/src/__tests__/forceTruecolor.test.ts +191 -0
  235. package/src/__tests__/gatewayClient.test.ts +394 -0
  236. package/src/__tests__/gatewayRecovery.test.ts +47 -0
  237. package/src/__tests__/markdown.test.ts +331 -0
  238. package/src/__tests__/mathUnicode.test.ts +293 -0
  239. package/src/__tests__/memoryMonitor.test.ts +102 -0
  240. package/src/__tests__/messageLine.test.ts +19 -0
  241. package/src/__tests__/messages.test.ts +92 -0
  242. package/src/__tests__/orchestratorPromptSession.test.ts +64 -0
  243. package/src/__tests__/osc52.test.ts +67 -0
  244. package/src/__tests__/parentLog.test.ts +75 -0
  245. package/src/__tests__/paths.test.ts +70 -0
  246. package/src/__tests__/platform.test.ts +556 -0
  247. package/src/__tests__/precisionWheel.test.ts +44 -0
  248. package/src/__tests__/prompt.test.ts +31 -0
  249. package/src/__tests__/providers.test.ts +65 -0
  250. package/src/__tests__/reasoning.test.ts +76 -0
  251. package/src/__tests__/rpc.test.ts +27 -0
  252. package/src/__tests__/scroll.test.ts +99 -0
  253. package/src/__tests__/slashParity.test.ts +123 -0
  254. package/src/__tests__/spawnHistoryStore.test.ts +46 -0
  255. package/src/__tests__/stateIsolation.test.ts +46 -0
  256. package/src/__tests__/statusBarTicker.test.ts +18 -0
  257. package/src/__tests__/statusRule.test.ts +32 -0
  258. package/src/__tests__/streamingMarkdown.test.ts +121 -0
  259. package/src/__tests__/subagentTree.test.ts +407 -0
  260. package/src/__tests__/syntax.test.ts +45 -0
  261. package/src/__tests__/terminalModes.test.ts +39 -0
  262. package/src/__tests__/terminalParity.test.ts +77 -0
  263. package/src/__tests__/terminalSetup.test.ts +386 -0
  264. package/src/__tests__/termux.test.ts +35 -0
  265. package/src/__tests__/termuxComposerLayout.test.ts +40 -0
  266. package/src/__tests__/text.test.ts +233 -0
  267. package/src/__tests__/textInputBurstInput.test.ts +40 -0
  268. package/src/__tests__/textInputCursorSourceOfTruth.test.ts +50 -0
  269. package/src/__tests__/textInputFastEcho.test.ts +200 -0
  270. package/src/__tests__/textInputLineNav.test.ts +55 -0
  271. package/src/__tests__/textInputPassThrough.test.ts +59 -0
  272. package/src/__tests__/textInputRightClick.test.ts +48 -0
  273. package/src/__tests__/textInputWrap.test.ts +151 -0
  274. package/src/__tests__/theme.test.ts +311 -0
  275. package/src/__tests__/turnControllerNotice.test.ts +43 -0
  276. package/src/__tests__/turnStore.test.ts +66 -0
  277. package/src/__tests__/useCompletion.test.ts +35 -0
  278. package/src/__tests__/useComposerState.test.ts +59 -0
  279. package/src/__tests__/useConfigSync.test.ts +460 -0
  280. package/src/__tests__/useInputHandlers.test.ts +77 -0
  281. package/src/__tests__/useQueue.test.ts +28 -0
  282. package/src/__tests__/useSessionLifecycle.test.ts +60 -0
  283. package/src/__tests__/useVirtualHistoryHeights.test.ts +39 -0
  284. package/src/__tests__/viewport.test.ts +58 -0
  285. package/src/__tests__/viewportStore.test.ts +85 -0
  286. package/src/__tests__/virtualHeights.test.ts +96 -0
  287. package/src/__tests__/virtualHistoryClamp.test.ts +19 -0
  288. package/src/__tests__/virtualHistoryOffsetCache.test.ts +282 -0
  289. package/src/__tests__/wheelAccel.test.ts +138 -0
  290. package/src/app/createGatewayEventHandler.ts +833 -0
  291. package/src/app/createSlashHandler.ts +130 -0
  292. package/src/app/delegationStore.ts +77 -0
  293. package/src/app/gatewayContext.tsx +19 -0
  294. package/src/app/gatewayRecovery.ts +35 -0
  295. package/src/app/inputSelectionStore.ts +15 -0
  296. package/src/app/interfaces.ts +394 -0
  297. package/src/app/overlayStore.ts +53 -0
  298. package/src/app/scroll.ts +71 -0
  299. package/src/app/setupHandoff.ts +54 -0
  300. package/src/app/slash/commands/core.ts +648 -0
  301. package/src/app/slash/commands/credits.ts +57 -0
  302. package/src/app/slash/commands/debug.ts +48 -0
  303. package/src/app/slash/commands/ops.ts +717 -0
  304. package/src/app/slash/commands/session.ts +554 -0
  305. package/src/app/slash/commands/setup.ts +20 -0
  306. package/src/app/slash/registry.ts +20 -0
  307. package/src/app/slash/types.ts +21 -0
  308. package/src/app/spawnHistoryStore.ts +159 -0
  309. package/src/app/turnController.ts +866 -0
  310. package/src/app/turnStore.ts +85 -0
  311. package/src/app/uiStore.ts +44 -0
  312. package/src/app/useComposerState.ts +367 -0
  313. package/src/app/useConfigSync.ts +288 -0
  314. package/src/app/useInputHandlers.ts +576 -0
  315. package/src/app/useLongRunToolCharms.ts +69 -0
  316. package/src/app/useMainApp.ts +1039 -0
  317. package/src/app/useSessionLifecycle.ts +366 -0
  318. package/src/app/useSubmission.ts +429 -0
  319. package/src/app.tsx +25 -0
  320. package/src/banner.ts +93 -0
  321. package/src/components/activeSessionSwitcher.tsx +635 -0
  322. package/src/components/agentsOverlay.tsx +1073 -0
  323. package/src/components/appChrome.tsx +554 -0
  324. package/src/components/appLayout.tsx +444 -0
  325. package/src/components/appOverlays.tsx +254 -0
  326. package/src/components/branding.tsx +466 -0
  327. package/src/components/fpsOverlay.tsx +30 -0
  328. package/src/components/helpHint.tsx +73 -0
  329. package/src/components/markdown.tsx +1119 -0
  330. package/src/components/maskedPrompt.tsx +34 -0
  331. package/src/components/messageLine.tsx +237 -0
  332. package/src/components/modelPicker.tsx +527 -0
  333. package/src/components/overlayControls.tsx +50 -0
  334. package/src/components/pluginsHub.tsx +238 -0
  335. package/src/components/prompts.tsx +276 -0
  336. package/src/components/queuedMessages.tsx +64 -0
  337. package/src/components/sessionPicker.tsx +227 -0
  338. package/src/components/skillsHub.tsx +308 -0
  339. package/src/components/streamingAssistant.tsx +110 -0
  340. package/src/components/streamingMarkdown.tsx +174 -0
  341. package/src/components/textInput.tsx +1340 -0
  342. package/src/components/themed.tsx +30 -0
  343. package/src/components/thinking.tsx +1224 -0
  344. package/src/components/todoPanel.tsx +93 -0
  345. package/src/config/env.ts +64 -0
  346. package/src/config/limits.ts +13 -0
  347. package/src/config/timing.ts +6 -0
  348. package/src/content/charms.ts +1 -0
  349. package/src/content/faces.ts +17 -0
  350. package/src/content/fortunes.ts +30 -0
  351. package/src/content/hotkeys.ts +37 -0
  352. package/src/content/placeholders.ts +13 -0
  353. package/src/content/setup.ts +17 -0
  354. package/src/content/verbs.ts +38 -0
  355. package/src/domain/blockLayout.ts +146 -0
  356. package/src/domain/details.ts +76 -0
  357. package/src/domain/messages.ts +91 -0
  358. package/src/domain/paths.ts +16 -0
  359. package/src/domain/providers.ts +11 -0
  360. package/src/domain/roles.ts +9 -0
  361. package/src/domain/slash.ts +10 -0
  362. package/src/domain/usage.ts +3 -0
  363. package/src/domain/viewport.ts +51 -0
  364. package/src/entry.tsx +104 -0
  365. package/src/gatewayClient.ts +730 -0
  366. package/src/gatewayTypes.ts +568 -0
  367. package/src/hooks/useCompletion.ts +112 -0
  368. package/src/hooks/useGitBranch.ts +72 -0
  369. package/src/hooks/useInputHistory.ts +11 -0
  370. package/src/hooks/useQueue.ts +76 -0
  371. package/src/hooks/useVirtualHistory.ts +554 -0
  372. package/src/lib/circularBuffer.ts +48 -0
  373. package/src/lib/clipboard.ts +182 -0
  374. package/src/lib/editor.test.ts +74 -0
  375. package/src/lib/editor.ts +47 -0
  376. package/src/lib/emoji.ts +55 -0
  377. package/src/lib/externalCli.ts +16 -0
  378. package/src/lib/externalLink.ts +435 -0
  379. package/src/lib/forceTruecolor.ts +60 -0
  380. package/src/lib/fpsStore.ts +51 -0
  381. package/src/lib/fuzzy.test.ts +109 -0
  382. package/src/lib/fuzzy.ts +177 -0
  383. package/src/lib/gracefulExit.ts +47 -0
  384. package/src/lib/history.ts +82 -0
  385. package/src/lib/inputMetrics.ts +203 -0
  386. package/src/lib/liveProgress.test.ts +116 -0
  387. package/src/lib/liveProgress.ts +79 -0
  388. package/src/lib/mathUnicode.ts +770 -0
  389. package/src/lib/memory.test.ts +155 -0
  390. package/src/lib/memory.ts +188 -0
  391. package/src/lib/memoryMonitor.ts +109 -0
  392. package/src/lib/messages.test.ts +29 -0
  393. package/src/lib/messages.ts +8 -0
  394. package/src/lib/openExternalUrl.test.ts +217 -0
  395. package/src/lib/openExternalUrl.ts +158 -0
  396. package/src/lib/osc52.ts +73 -0
  397. package/src/lib/parentLog.ts +57 -0
  398. package/src/lib/perfPane.tsx +107 -0
  399. package/src/lib/platform.ts +409 -0
  400. package/src/lib/precisionWheel.ts +48 -0
  401. package/src/lib/prompt.ts +35 -0
  402. package/src/lib/reasoning.ts +55 -0
  403. package/src/lib/rpc.ts +41 -0
  404. package/src/lib/subagentTree.ts +355 -0
  405. package/src/lib/syntax.ts +117 -0
  406. package/src/lib/terminalModes.ts +51 -0
  407. package/src/lib/terminalParity.ts +78 -0
  408. package/src/lib/terminalSetup.ts +444 -0
  409. package/src/lib/termux.ts +29 -0
  410. package/src/lib/text.test.ts +18 -0
  411. package/src/lib/text.ts +339 -0
  412. package/src/lib/todo.test.ts +21 -0
  413. package/src/lib/todo.ts +9 -0
  414. package/src/lib/viewportStore.ts +124 -0
  415. package/src/lib/virtualHeights.ts +145 -0
  416. package/src/lib/wheelAccel.ts +190 -0
  417. package/src/protocol/interpolation.ts +3 -0
  418. package/src/protocol/paste.ts +1 -0
  419. package/src/theme.ts +589 -0
  420. package/src/types/nastech-ink.d.ts +176 -0
  421. package/src/types.ts +212 -0
  422. package/tsconfig.build.json +9 -0
  423. package/tsconfig.json +19 -0
  424. package/vitest.config.ts +7 -0
@@ -0,0 +1,242 @@
1
+ import {
2
+ ContinuousEventPriority,
3
+ DefaultEventPriority,
4
+ DiscreteEventPriority,
5
+ NoEventPriority
6
+ } from 'react-reconciler/constants.js'
7
+
8
+ import { logError } from '../../utils/log.js'
9
+
10
+ import { HANDLER_FOR_EVENT } from './event-handlers.js'
11
+ import type { EventTarget, TerminalEvent } from './terminal-event.js'
12
+
13
+ // --
14
+
15
+ type DispatchListener = {
16
+ node: EventTarget
17
+ handler: (event: TerminalEvent) => void
18
+ phase: 'capturing' | 'at_target' | 'bubbling'
19
+ }
20
+
21
+ function getHandler(
22
+ node: EventTarget,
23
+ eventType: string,
24
+ capture: boolean
25
+ ): ((event: TerminalEvent) => void) | undefined {
26
+ const handlers = node._eventHandlers
27
+
28
+ if (!handlers) {
29
+ return undefined
30
+ }
31
+
32
+ const mapping = HANDLER_FOR_EVENT[eventType]
33
+
34
+ if (!mapping) {
35
+ return undefined
36
+ }
37
+
38
+ const propName = capture ? mapping.capture : mapping.bubble
39
+
40
+ if (!propName) {
41
+ return undefined
42
+ }
43
+
44
+ return handlers[propName] as ((event: TerminalEvent) => void) | undefined
45
+ }
46
+
47
+ /**
48
+ * Collect all listeners for an event in dispatch order.
49
+ *
50
+ * Uses react-dom's two-phase accumulation pattern:
51
+ * - Walk from target to root
52
+ * - Capture handlers are prepended (unshift) → root-first
53
+ * - Bubble handlers are appended (push) → target-first
54
+ *
55
+ * Result: [root-cap, ..., parent-cap, target-cap, target-bub, parent-bub, ..., root-bub]
56
+ */
57
+ function collectListeners(target: EventTarget, event: TerminalEvent): DispatchListener[] {
58
+ const listeners: DispatchListener[] = []
59
+
60
+ let node: EventTarget | undefined = target
61
+
62
+ while (node) {
63
+ const isTarget = node === target
64
+
65
+ const captureHandler = getHandler(node, event.type, true)
66
+ const bubbleHandler = getHandler(node, event.type, false)
67
+
68
+ if (captureHandler) {
69
+ listeners.unshift({
70
+ node,
71
+ handler: captureHandler,
72
+ phase: isTarget ? 'at_target' : 'capturing'
73
+ })
74
+ }
75
+
76
+ if (bubbleHandler && (event.bubbles || isTarget)) {
77
+ listeners.push({
78
+ node,
79
+ handler: bubbleHandler,
80
+ phase: isTarget ? 'at_target' : 'bubbling'
81
+ })
82
+ }
83
+
84
+ node = node.parentNode
85
+ }
86
+
87
+ return listeners
88
+ }
89
+
90
+ /**
91
+ * Execute collected listeners with propagation control.
92
+ *
93
+ * Before each handler, calls event._prepareForTarget(node) so event
94
+ * subclasses can do per-node setup.
95
+ */
96
+ function processDispatchQueue(listeners: DispatchListener[], event: TerminalEvent): void {
97
+ let previousNode: EventTarget | undefined
98
+
99
+ for (const { node, handler, phase } of listeners) {
100
+ if (event._isImmediatePropagationStopped()) {
101
+ break
102
+ }
103
+
104
+ if (event._isPropagationStopped() && node !== previousNode) {
105
+ break
106
+ }
107
+
108
+ event._setEventPhase(phase)
109
+ event._setCurrentTarget(node)
110
+ event._prepareForTarget(node)
111
+
112
+ try {
113
+ handler(event)
114
+ } catch (error) {
115
+ logError(error)
116
+ }
117
+
118
+ previousNode = node
119
+ }
120
+ }
121
+
122
+ // --
123
+
124
+ /**
125
+ * Map terminal event types to React scheduling priorities.
126
+ * Mirrors react-dom's getEventPriority() switch.
127
+ */
128
+ function getEventPriority(eventType: string): number {
129
+ switch (eventType) {
130
+ case 'keydown':
131
+
132
+ case 'keyup':
133
+
134
+ case 'click':
135
+
136
+ case 'focus':
137
+
138
+ case 'blur':
139
+
140
+ case 'paste':
141
+ return DiscreteEventPriority as number
142
+
143
+ case 'resize':
144
+
145
+ case 'scroll':
146
+
147
+ case 'mousemove':
148
+ return ContinuousEventPriority as number
149
+
150
+ default:
151
+ return DefaultEventPriority as number
152
+ }
153
+ }
154
+
155
+ // --
156
+
157
+ type DiscreteUpdates = <A, B>(fn: (a: A, b: B) => boolean, a: A, b: B, c: undefined, d: undefined) => boolean
158
+
159
+ /**
160
+ * Owns event dispatch state and the capture/bubble dispatch loop.
161
+ *
162
+ * The reconciler host config reads currentEvent and currentUpdatePriority
163
+ * to implement resolveUpdatePriority, resolveEventType, and
164
+ * resolveEventTimeStamp — mirroring how react-dom's host config reads
165
+ * ReactDOMSharedInternals and window.event.
166
+ *
167
+ * discreteUpdates is injected after construction (by InkReconciler)
168
+ * to break the import cycle.
169
+ */
170
+ export class Dispatcher {
171
+ currentEvent: TerminalEvent | null = null
172
+ currentUpdatePriority: number = DefaultEventPriority as number
173
+ discreteUpdates: DiscreteUpdates | null = null
174
+
175
+ /**
176
+ * Infer event priority from the currently-dispatching event.
177
+ * Called by the reconciler host config's resolveUpdatePriority
178
+ * when no explicit priority has been set.
179
+ */
180
+ resolveEventPriority(): number {
181
+ if (this.currentUpdatePriority !== (NoEventPriority as number)) {
182
+ return this.currentUpdatePriority
183
+ }
184
+
185
+ if (this.currentEvent) {
186
+ return getEventPriority(this.currentEvent.type)
187
+ }
188
+
189
+ return DefaultEventPriority as number
190
+ }
191
+
192
+ /**
193
+ * Dispatch an event through capture and bubble phases.
194
+ * Returns true if preventDefault() was NOT called.
195
+ */
196
+ dispatch(target: EventTarget, event: TerminalEvent): boolean {
197
+ const previousEvent = this.currentEvent
198
+ this.currentEvent = event
199
+
200
+ try {
201
+ event._setTarget(target)
202
+
203
+ const listeners = collectListeners(target, event)
204
+ processDispatchQueue(listeners, event)
205
+
206
+ event._setEventPhase('none')
207
+ event._setCurrentTarget(null)
208
+
209
+ return !event.defaultPrevented
210
+ } finally {
211
+ this.currentEvent = previousEvent
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Dispatch with discrete (sync) priority.
217
+ * For user-initiated events: keyboard, click, focus, paste.
218
+ */
219
+ dispatchDiscrete(target: EventTarget, event: TerminalEvent): boolean {
220
+ if (!this.discreteUpdates) {
221
+ return this.dispatch(target, event)
222
+ }
223
+
224
+ return this.discreteUpdates((t, e) => this.dispatch(t, e), target, event, undefined, undefined)
225
+ }
226
+
227
+ /**
228
+ * Dispatch with continuous priority.
229
+ * For high-frequency events: resize, scroll, mouse move.
230
+ */
231
+ dispatchContinuous(target: EventTarget, event: TerminalEvent): boolean {
232
+ const previousPriority = this.currentUpdatePriority
233
+
234
+ try {
235
+ this.currentUpdatePriority = ContinuousEventPriority as number
236
+
237
+ return this.dispatch(target, event)
238
+ } finally {
239
+ this.currentUpdatePriority = previousPriority
240
+ }
241
+ }
242
+ }
@@ -0,0 +1,40 @@
1
+ import { EventEmitter as NodeEventEmitter } from 'events'
2
+
3
+ import { Event } from './event.js'
4
+
5
+ // Similar to node's builtin EventEmitter, but is also aware of our `Event`
6
+ // class, and so `emit` respects `stopImmediatePropagation()`.
7
+ export class EventEmitter extends NodeEventEmitter {
8
+ constructor() {
9
+ super()
10
+ // Disable the default maxListeners warning. In React, many components
11
+ // can legitimately listen to the same event (e.g., useInput hooks).
12
+ // The default limit of 10 causes spurious warnings.
13
+ this.setMaxListeners(0)
14
+ }
15
+
16
+ override emit(type: string | symbol, ...args: unknown[]): boolean {
17
+ // Delegate to node for `error`, since it's not treated like a normal event
18
+ if (type === 'error') {
19
+ return super.emit(type, ...args)
20
+ }
21
+
22
+ const listeners = this.rawListeners(type)
23
+
24
+ if (listeners.length === 0) {
25
+ return false
26
+ }
27
+
28
+ const ccEvent = args[0] instanceof Event ? args[0] : null
29
+
30
+ for (const listener of listeners) {
31
+ listener.apply(this, args)
32
+
33
+ if (ccEvent?.didStopImmediatePropagation()) {
34
+ break
35
+ }
36
+ }
37
+
38
+ return true
39
+ }
40
+ }
@@ -0,0 +1,84 @@
1
+ import type { ClickEvent } from './click-event.js'
2
+ import type { FocusEvent } from './focus-event.js'
3
+ import type { KeyboardEvent } from './keyboard-event.js'
4
+ import type { MouseEvent } from './mouse-event.js'
5
+ import type { PasteEvent } from './paste-event.js'
6
+ import type { ResizeEvent } from './resize-event.js'
7
+
8
+ type KeyboardEventHandler = (event: KeyboardEvent) => void
9
+ type FocusEventHandler = (event: FocusEvent) => void
10
+ type PasteEventHandler = (event: PasteEvent) => void
11
+ type ResizeEventHandler = (event: ResizeEvent) => void
12
+ type ClickEventHandler = (event: ClickEvent) => void
13
+ type MouseEventHandler = (event: MouseEvent) => void
14
+ type HoverEventHandler = () => void
15
+
16
+ /**
17
+ * Props for event handlers on Box and other host components.
18
+ *
19
+ * Follows the React/DOM naming convention:
20
+ * - onEventName: handler for bubble phase
21
+ * - onEventNameCapture: handler for capture phase
22
+ */
23
+ export type EventHandlerProps = {
24
+ onKeyDown?: KeyboardEventHandler
25
+ onKeyDownCapture?: KeyboardEventHandler
26
+
27
+ onFocus?: FocusEventHandler
28
+ onFocusCapture?: FocusEventHandler
29
+ onBlur?: FocusEventHandler
30
+ onBlurCapture?: FocusEventHandler
31
+
32
+ onPaste?: PasteEventHandler
33
+ onPasteCapture?: PasteEventHandler
34
+
35
+ onResize?: ResizeEventHandler
36
+
37
+ onClick?: ClickEventHandler
38
+ onMouseDown?: MouseEventHandler
39
+ onMouseUp?: MouseEventHandler
40
+ onMouseDrag?: MouseEventHandler
41
+ onMouseEnter?: HoverEventHandler
42
+ onMouseLeave?: HoverEventHandler
43
+ }
44
+
45
+ /**
46
+ * Reverse lookup: event type string → handler prop names.
47
+ * Used by the dispatcher for O(1) handler lookup per node.
48
+ */
49
+ export const HANDLER_FOR_EVENT: Record<
50
+ string,
51
+ { bubble?: keyof EventHandlerProps; capture?: keyof EventHandlerProps }
52
+ > = {
53
+ keydown: { bubble: 'onKeyDown', capture: 'onKeyDownCapture' },
54
+ focus: { bubble: 'onFocus', capture: 'onFocusCapture' },
55
+ blur: { bubble: 'onBlur', capture: 'onBlurCapture' },
56
+ paste: { bubble: 'onPaste', capture: 'onPasteCapture' },
57
+ resize: { bubble: 'onResize' },
58
+ click: { bubble: 'onClick' },
59
+ mousedown: { bubble: 'onMouseDown' },
60
+ mouseup: { bubble: 'onMouseUp' },
61
+ mousedrag: { bubble: 'onMouseDrag' }
62
+ }
63
+
64
+ /**
65
+ * Set of all event handler prop names, for the reconciler to detect
66
+ * event props and store them in _eventHandlers instead of attributes.
67
+ */
68
+ export const EVENT_HANDLER_PROPS = new Set<string>([
69
+ 'onKeyDown',
70
+ 'onKeyDownCapture',
71
+ 'onFocus',
72
+ 'onFocusCapture',
73
+ 'onBlur',
74
+ 'onBlurCapture',
75
+ 'onPaste',
76
+ 'onPasteCapture',
77
+ 'onResize',
78
+ 'onClick',
79
+ 'onMouseDown',
80
+ 'onMouseUp',
81
+ 'onMouseDrag',
82
+ 'onMouseEnter',
83
+ 'onMouseLeave'
84
+ ])
@@ -0,0 +1,11 @@
1
+ export class Event {
2
+ private _didStopImmediatePropagation = false
3
+
4
+ didStopImmediatePropagation(): boolean {
5
+ return this._didStopImmediatePropagation
6
+ }
7
+
8
+ stopImmediatePropagation(): void {
9
+ this._didStopImmediatePropagation = true
10
+ }
11
+ }
@@ -0,0 +1,18 @@
1
+ import { type EventTarget, TerminalEvent } from './terminal-event.js'
2
+
3
+ /**
4
+ * Focus event for component focus changes.
5
+ *
6
+ * Dispatched when focus moves between elements. 'focus' fires on the
7
+ * newly focused element, 'blur' fires on the previously focused one.
8
+ * Both bubble, matching react-dom's use of focusin/focusout semantics
9
+ * so parent components can observe descendant focus changes.
10
+ */
11
+ export class FocusEvent extends TerminalEvent {
12
+ readonly relatedTarget: EventTarget | null
13
+
14
+ constructor(type: 'focus' | 'blur', relatedTarget: EventTarget | null = null) {
15
+ super(type, { bubbles: true, cancelable: false })
16
+ this.relatedTarget = relatedTarget
17
+ }
18
+ }
@@ -0,0 +1,176 @@
1
+ import { nonAlphanumericKeys, type ParsedKey } from '../parse-keypress.js'
2
+
3
+ import { Event } from './event.js'
4
+
5
+ const inputForSpecialSequence = (name: string): string =>
6
+ name === 'space' ? ' ' : name === 'return' || name === 'escape' ? '' : name
7
+
8
+ export type Key = {
9
+ upArrow: boolean
10
+ downArrow: boolean
11
+ leftArrow: boolean
12
+ rightArrow: boolean
13
+ pageDown: boolean
14
+ pageUp: boolean
15
+ wheelUp: boolean
16
+ wheelDown: boolean
17
+ home: boolean
18
+ end: boolean
19
+ return: boolean
20
+ escape: boolean
21
+ ctrl: boolean
22
+ shift: boolean
23
+ fn: boolean
24
+ tab: boolean
25
+ backspace: boolean
26
+ delete: boolean
27
+ meta: boolean
28
+ super: boolean
29
+ }
30
+
31
+ function parseKey(keypress: ParsedKey): [Key, string] {
32
+ const key: Key = {
33
+ upArrow: keypress.name === 'up',
34
+ downArrow: keypress.name === 'down',
35
+ leftArrow: keypress.name === 'left',
36
+ rightArrow: keypress.name === 'right',
37
+ pageDown: keypress.name === 'pagedown',
38
+ pageUp: keypress.name === 'pageup',
39
+ wheelUp: keypress.name === 'wheelup',
40
+ wheelDown: keypress.name === 'wheeldown',
41
+ home: keypress.name === 'home',
42
+ end: keypress.name === 'end',
43
+ return: keypress.name === 'return',
44
+ escape: keypress.name === 'escape',
45
+ fn: keypress.fn,
46
+ ctrl: keypress.ctrl,
47
+ shift: keypress.shift,
48
+ tab: keypress.name === 'tab',
49
+ backspace: keypress.name === 'backspace',
50
+ delete: keypress.name === 'delete',
51
+ // `parseKeypress` parses \u001B\u001B[A (meta + up arrow) as meta = false
52
+ // but with option = true, so we need to take this into account here
53
+ // to avoid breaking changes in Ink.
54
+ // TODO(vadimdemedes): consider removing this in the next major version.
55
+ meta: keypress.meta || keypress.name === 'escape' || keypress.option,
56
+ // Super (Cmd on macOS / Win key) — only arrives via kitty keyboard
57
+ // protocol CSI u sequences. Distinct from meta (Alt/Option) so
58
+ // bindings like cmd+c can be expressed separately from opt+c.
59
+ super: keypress.super
60
+ }
61
+
62
+ let input = keypress.ctrl ? keypress.name : keypress.sequence
63
+
64
+ // Handle undefined input case
65
+ if (input === undefined) {
66
+ input = ''
67
+ }
68
+
69
+ // When ctrl is set, keypress.name for space is the literal word "space".
70
+ // Convert to actual space character for consistency with the CSI u branch
71
+ // (which maps 'space' → ' '). Without this, ctrl+space leaks the literal
72
+ // word "space" into text input.
73
+ if (keypress.ctrl && input === 'space') {
74
+ input = ' '
75
+ }
76
+
77
+ // Suppress unrecognized escape sequences that were parsed as function keys
78
+ // (matched by FN_KEY_RE) but have no name in the keyName map.
79
+ // Examples: ESC[25~ (F13/Right Alt on Windows), ESC[26~ (F14), etc.
80
+ // Without this, the ESC prefix is stripped below and the remainder (e.g.,
81
+ // "[25~") leaks into the input as literal text.
82
+ if (keypress.code && !keypress.name) {
83
+ input = ''
84
+ }
85
+
86
+ // (SGR mouse-report fragments used to be scrubbed here. They no longer reach
87
+ // this layer: the tokenizer keeps an incomplete CSI buffered across a
88
+ // watchdog flush and reassembles it on the next feed instead of force-
89
+ // emitting the partial as input. See termio/tokenize.ts.)
90
+
91
+ // Strip meta if it's still remaining after `parseKeypress`
92
+ // TODO(vadimdemedes): remove this in the next major version.
93
+ if (input.startsWith('\u001B')) {
94
+ input = input.slice(1)
95
+ }
96
+
97
+ // Track whether we've already processed this as a special sequence
98
+ // that converted input to the key name (CSI u or application keypad mode).
99
+ // For these, we don't want to clear input with nonAlphanumericKeys check.
100
+ let processedAsSpecialSequence = false
101
+
102
+ // Handle CSI u sequences (Kitty keyboard protocol): after stripping ESC,
103
+ // we're left with "[codepoint;modifieru" (e.g., "[98;3u" for Alt+b).
104
+ // Use the parsed key name instead for input handling. Require a digit
105
+ // after [ — real CSI u is always [<digits>…u, and a bare startsWith('[')
106
+ // false-matches X10 mouse at row 85 (Cy = 85+32 = 'u'), leaking the
107
+ // literal text "mouse" into the prompt via processedAsSpecialSequence.
108
+ if (/^\[\d/.test(input) && input.endsWith('u')) {
109
+ if (!keypress.name) {
110
+ // Unmapped Kitty functional key (Caps Lock 57358, F13–F35, KP nav,
111
+ // bare modifiers, etc.) — keycodeToName() returned undefined. Swallow
112
+ // so the raw "[57358u" doesn't leak into the prompt. See #38781.
113
+ input = ''
114
+ } else {
115
+ input = inputForSpecialSequence(keypress.name)
116
+ }
117
+
118
+ processedAsSpecialSequence = true
119
+ }
120
+
121
+ // Handle xterm modifyOtherKeys sequences: after stripping ESC, we're left
122
+ // with "[27;modifier;keycode~" (e.g., "[27;3;98~" for Alt+b). Same
123
+ // extraction as CSI u — without this, printable-char keycodes (single-letter
124
+ // names) skip the nonAlphanumericKeys clear and leak "[27;..." as input.
125
+ if (input.startsWith('[27;') && input.endsWith('~')) {
126
+ if (!keypress.name) {
127
+ // Unmapped modifyOtherKeys keycode — swallow for consistency with
128
+ // the CSI u handler above. Practically untriggerable today (xterm
129
+ // modifyOtherKeys only sends ASCII keycodes, all mapped), but
130
+ // guards against future terminal behavior.
131
+ input = ''
132
+ } else {
133
+ input = inputForSpecialSequence(keypress.name)
134
+ }
135
+
136
+ processedAsSpecialSequence = true
137
+ }
138
+
139
+ // Handle application keypad mode sequences: after stripping ESC,
140
+ // we're left with "O<letter>" (e.g., "Op" for numpad 0, "Oy" for numpad 9).
141
+ // Use the parsed key name (the digit character) for input handling.
142
+ if (input.startsWith('O') && input.length === 2 && keypress.name && keypress.name.length === 1) {
143
+ input = keypress.name
144
+ processedAsSpecialSequence = true
145
+ }
146
+
147
+ // Clear input for non-alphanumeric keys (arrows, function keys, etc.)
148
+ // Skip this for CSI u and application keypad mode sequences since
149
+ // those were already converted to their proper input characters.
150
+ if (!processedAsSpecialSequence && keypress.name && nonAlphanumericKeys.includes(keypress.name)) {
151
+ input = ''
152
+ }
153
+
154
+ // Set shift=true for uppercase letters (A-Z)
155
+ // Must check it's actually a letter, not just any char unchanged by toUpperCase
156
+ if (input.length === 1 && typeof input[0] === 'string' && input[0] >= 'A' && input[0] <= 'Z') {
157
+ key.shift = true
158
+ }
159
+
160
+ return [key, input]
161
+ }
162
+
163
+ export class InputEvent extends Event {
164
+ readonly keypress: ParsedKey
165
+ readonly key: Key
166
+ readonly input: string
167
+
168
+ constructor(keypress: ParsedKey) {
169
+ super()
170
+ const [key, input] = parseKey(keypress)
171
+
172
+ this.keypress = keypress
173
+ this.key = key
174
+ this.input = input
175
+ }
176
+ }
@@ -0,0 +1,57 @@
1
+ import type { ParsedKey } from '../parse-keypress.js'
2
+
3
+ import { TerminalEvent } from './terminal-event.js'
4
+
5
+ /**
6
+ * Keyboard event dispatched through the DOM tree via capture/bubble.
7
+ *
8
+ * Follows browser KeyboardEvent semantics: `key` is the literal character
9
+ * for printable keys ('a', '3', ' ', '/') and a multi-char name for
10
+ * special keys ('down', 'return', 'escape', 'f1'). The idiomatic
11
+ * printable-char check is `e.key.length === 1`.
12
+ */
13
+ export class KeyboardEvent extends TerminalEvent {
14
+ readonly key: string
15
+ readonly ctrl: boolean
16
+ readonly shift: boolean
17
+ readonly meta: boolean
18
+ readonly superKey: boolean
19
+ readonly fn: boolean
20
+
21
+ constructor(parsedKey: ParsedKey) {
22
+ super('keydown', { bubbles: true, cancelable: true })
23
+
24
+ this.key = keyFromParsed(parsedKey)
25
+ this.ctrl = parsedKey.ctrl
26
+ this.shift = parsedKey.shift
27
+ this.meta = parsedKey.meta || parsedKey.option
28
+ this.superKey = parsedKey.super
29
+ this.fn = parsedKey.fn
30
+ }
31
+ }
32
+
33
+ function keyFromParsed(parsed: ParsedKey): string {
34
+ const seq = parsed.sequence ?? ''
35
+ const name = parsed.name ?? ''
36
+
37
+ // Ctrl combos: sequence is a control byte (\x03 for ctrl+c), name is the
38
+ // letter. Browsers report e.key === 'c' with e.ctrlKey === true.
39
+ if (parsed.ctrl) {
40
+ return name
41
+ }
42
+
43
+ // Single printable char (space through ~, plus anything above ASCII):
44
+ // use the literal char. Browsers report e.key === '3', not 'Digit3'.
45
+ if (seq.length === 1) {
46
+ const code = seq.charCodeAt(0)
47
+
48
+ if (code >= 0x20 && code !== 0x7f) {
49
+ return seq
50
+ }
51
+ }
52
+
53
+ // Special keys (arrows, F-keys, return, tab, escape, etc.): sequence is
54
+ // either an escape sequence (\x1b[B) or a control byte (\r, \t), so use
55
+ // the parsed name. Browsers report e.key === 'ArrowDown'.
56
+ return name || seq
57
+ }
@@ -0,0 +1,18 @@
1
+ import { Event } from './event.js'
2
+
3
+ export class MouseEvent extends Event {
4
+ readonly col: number
5
+ readonly row: number
6
+ localCol = 0
7
+ localRow = 0
8
+ readonly cellIsBlank: boolean
9
+ readonly button: number
10
+
11
+ constructor(col: number, row: number, cellIsBlank: boolean, button: number) {
12
+ super()
13
+ this.col = col
14
+ this.row = row
15
+ this.cellIsBlank = cellIsBlank
16
+ this.button = button
17
+ }
18
+ }
@@ -0,0 +1,10 @@
1
+ import { TerminalEvent } from './terminal-event.js'
2
+
3
+ export class PasteEvent extends TerminalEvent {
4
+ readonly text: string
5
+
6
+ constructor(text: string) {
7
+ super('paste', { bubbles: true, cancelable: true })
8
+ this.text = text
9
+ }
10
+ }
@@ -0,0 +1,12 @@
1
+ import { TerminalEvent } from './terminal-event.js'
2
+
3
+ export class ResizeEvent extends TerminalEvent {
4
+ readonly columns: number
5
+ readonly rows: number
6
+
7
+ constructor(columns: number, rows: number) {
8
+ super('resize', { bubbles: true, cancelable: true })
9
+ this.columns = columns
10
+ this.rows = rows
11
+ }
12
+ }