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,350 @@
1
+ /**
2
+ * Input Tokenizer - Escape sequence boundary detection
3
+ *
4
+ * Splits terminal input into tokens: text chunks and raw escape sequences.
5
+ * Unlike the Parser which interprets sequences semantically, this just
6
+ * identifies boundaries for use by keyboard input parsing.
7
+ */
8
+
9
+ import { C0, ESC_TYPE, isEscFinal } from './ansi.js'
10
+ import { isCSIFinal, isCSIIntermediate, isCSIParam } from './csi.js'
11
+
12
+ export type Token = { type: 'text'; value: string } | { type: 'sequence'; value: string }
13
+
14
+ type State = 'ground' | 'escape' | 'escapeIntermediate' | 'csi' | 'ss3' | 'osc' | 'dcs' | 'apc'
15
+
16
+ export type Tokenizer = {
17
+ /** Feed input and get resulting tokens */
18
+ feed(input: string): Token[]
19
+ /** Flush any buffered incomplete sequences */
20
+ flush(): Token[]
21
+ /** Reset tokenizer state */
22
+ reset(): void
23
+ /** Get any buffered incomplete sequence */
24
+ buffer(): string
25
+ }
26
+
27
+ type TokenizerOptions = {
28
+ /**
29
+ * Treat `CSI M` as an X10 mouse event prefix and consume 3 payload bytes.
30
+ * Only enable for stdin input — `\x1b[M` is also CSI DL (Delete Lines) in
31
+ * output streams, and enabling this there swallows display text. Default false.
32
+ */
33
+ x10Mouse?: boolean
34
+ }
35
+
36
+ /**
37
+ * Create a streaming tokenizer for terminal input.
38
+ *
39
+ * Usage:
40
+ * ```typescript
41
+ * const tokenizer = createTokenizer()
42
+ * const tokens1 = tokenizer.feed('hello\x1b[')
43
+ * const tokens2 = tokenizer.feed('A') // completes the escape sequence
44
+ * const remaining = tokenizer.flush() // force output incomplete sequences
45
+ * ```
46
+ */
47
+ export function createTokenizer(options?: TokenizerOptions): Tokenizer {
48
+ let currentState: State = 'ground'
49
+ let currentBuffer = ''
50
+ // The control-sequence buffer kept across the previous flush, if any. Used
51
+ // as a one-tick truncation valve: a partial CSI mouse report normally
52
+ // reassembles on the very next feed, so if a flush sees the exact same
53
+ // buffer it kept last time (the continuation never arrived), we drop it.
54
+ let lastFlushedBuffer = ''
55
+ const x10Mouse = options?.x10Mouse ?? false
56
+
57
+ return {
58
+ feed(input: string): Token[] {
59
+ // Real bytes arrived — any kept partial is no longer stale.
60
+ lastFlushedBuffer = ''
61
+
62
+ const result = tokenize(input, currentState, currentBuffer, false, x10Mouse)
63
+
64
+ currentState = result.state.state
65
+ currentBuffer = result.state.buffer
66
+
67
+ return result.tokens
68
+ },
69
+
70
+ flush(): Token[] {
71
+ const result = tokenize('', currentState, currentBuffer, true, x10Mouse)
72
+ currentState = result.state.state
73
+ currentBuffer = result.state.buffer
74
+
75
+ // tokenize() keeps (doesn't emit) an incomplete control sequence on
76
+ // flush. If two consecutive flushes see the same buffer with no feed in
77
+ // between, the continuation is never coming (truncated write / killed
78
+ // process) — drop it so it can't fuse with the next keypress's bytes.
79
+ if (currentBuffer && currentBuffer === lastFlushedBuffer) {
80
+ currentState = 'ground'
81
+ currentBuffer = ''
82
+ lastFlushedBuffer = ''
83
+ } else {
84
+ lastFlushedBuffer = currentBuffer
85
+ }
86
+
87
+ return result.tokens
88
+ },
89
+
90
+ reset(): void {
91
+ currentState = 'ground'
92
+ currentBuffer = ''
93
+ lastFlushedBuffer = ''
94
+ },
95
+
96
+ buffer(): string {
97
+ return currentBuffer
98
+ }
99
+ }
100
+ }
101
+
102
+ type InternalState = {
103
+ state: State
104
+ buffer: string
105
+ }
106
+
107
+ function tokenize(
108
+ input: string,
109
+ initialState: State,
110
+ initialBuffer: string,
111
+ flush: boolean,
112
+ x10Mouse: boolean
113
+ ): { tokens: Token[]; state: InternalState } {
114
+ const tokens: Token[] = []
115
+
116
+ const result: InternalState = {
117
+ state: initialState,
118
+ buffer: ''
119
+ }
120
+
121
+ const data = initialBuffer + input
122
+ let i = 0
123
+ let textStart = 0
124
+ let seqStart = 0
125
+
126
+ const flushText = (): void => {
127
+ if (i > textStart) {
128
+ const text = data.slice(textStart, i)
129
+
130
+ if (text) {
131
+ tokens.push({ type: 'text', value: text })
132
+ }
133
+ }
134
+
135
+ textStart = i
136
+ }
137
+
138
+ const emitSequence = (seq: string): void => {
139
+ if (seq) {
140
+ tokens.push({ type: 'sequence', value: seq })
141
+ }
142
+
143
+ result.state = 'ground'
144
+ textStart = i
145
+ }
146
+
147
+ while (i < data.length) {
148
+ const code = data.charCodeAt(i)
149
+
150
+ switch (result.state) {
151
+ case 'ground':
152
+ if (code === C0.ESC) {
153
+ flushText()
154
+ seqStart = i
155
+ result.state = 'escape'
156
+ i++
157
+ } else {
158
+ i++
159
+ }
160
+
161
+ break
162
+
163
+ case 'escape':
164
+ if (code === ESC_TYPE.CSI) {
165
+ result.state = 'csi'
166
+ i++
167
+ } else if (code === ESC_TYPE.OSC) {
168
+ result.state = 'osc'
169
+ i++
170
+ } else if (code === ESC_TYPE.DCS) {
171
+ result.state = 'dcs'
172
+ i++
173
+ } else if (code === ESC_TYPE.APC) {
174
+ result.state = 'apc'
175
+ i++
176
+ } else if (code === 0x4f) {
177
+ // 'O' - SS3
178
+ result.state = 'ss3'
179
+ i++
180
+ } else if (isCSIIntermediate(code)) {
181
+ // Intermediate byte (e.g., ESC ( for charset) - continue buffering
182
+ result.state = 'escapeIntermediate'
183
+ i++
184
+ } else if (isEscFinal(code)) {
185
+ // Two-character escape sequence
186
+ i++
187
+ emitSequence(data.slice(seqStart, i))
188
+ } else if (code === C0.ESC) {
189
+ // Double escape - emit first, start new
190
+ emitSequence(data.slice(seqStart, i))
191
+ seqStart = i
192
+ result.state = 'escape'
193
+ i++
194
+ } else {
195
+ // Invalid - treat ESC as text
196
+ result.state = 'ground'
197
+ textStart = seqStart
198
+ }
199
+
200
+ break
201
+
202
+ case 'escapeIntermediate':
203
+ // After intermediate byte(s), wait for final byte
204
+ if (isCSIIntermediate(code)) {
205
+ // More intermediate bytes
206
+ i++
207
+ } else if (isEscFinal(code)) {
208
+ // Final byte - complete the sequence
209
+ i++
210
+ emitSequence(data.slice(seqStart, i))
211
+ } else {
212
+ // Invalid - treat as text
213
+ result.state = 'ground'
214
+ textStart = seqStart
215
+ }
216
+
217
+ break
218
+
219
+ case 'csi':
220
+ // X10 mouse: CSI M + 3 raw payload bytes (Cb+32, Cx+32, Cy+32).
221
+ // M immediately after [ (offset 2) means no params — SGR mouse
222
+ // (CSI < … M) has a `<` param byte first and reaches M at offset > 2.
223
+ // Terminals that ignore DECSET 1006 but honor 1000/1002 emit this
224
+ // legacy encoding; without this branch the 3 payload bytes leak
225
+ // through as text (`` `rK `` / `arK` garbage in the prompt).
226
+ //
227
+ // Gated on x10Mouse — `\x1b[M` is also CSI DL (Delete Lines) and
228
+ // blindly consuming 3 chars corrupts output rendering (Parser/Ansi)
229
+ // and fragments bracketed-paste PASTE_END. Only stdin enables this.
230
+ // The ≥0x20 check on each payload slot is belt-and-suspenders: X10
231
+ // guarantees Cb≥32, Cx≥33, Cy≥33, so a control byte (ESC=0x1B) in
232
+ // any slot means this is CSI DL adjacent to another sequence, not a
233
+ // mouse event. Checking all three slots prevents PASTE_END's ESC
234
+ // from being consumed when paste content ends in `\x1b[M`+0-2 chars.
235
+ //
236
+ // Known limitation: this counts JS string chars, but X10 is byte-
237
+ // oriented and stdin uses utf8 encoding (App.tsx). At col 162-191 ×
238
+ // row 96-159 the two coord bytes (0xC2-0xDF, 0x80-0xBF) form a valid
239
+ // UTF-8 2-byte sequence and collapse to one char — the length check
240
+ // fails and the event buffers until the next keypress absorbs it.
241
+ // Fixing this requires latin1 stdin; X10's 223-coord cap is exactly
242
+ // why SGR was invented, and no-SGR terminals at 162+ cols are rare.
243
+ if (
244
+ x10Mouse &&
245
+ code === 0x4d /* M */ &&
246
+ i - seqStart === 2 &&
247
+ (i + 1 >= data.length || data.charCodeAt(i + 1) >= 0x20) &&
248
+ (i + 2 >= data.length || data.charCodeAt(i + 2) >= 0x20) &&
249
+ (i + 3 >= data.length || data.charCodeAt(i + 3) >= 0x20)
250
+ ) {
251
+ if (i + 4 <= data.length) {
252
+ i += 4
253
+ emitSequence(data.slice(seqStart, i))
254
+ } else {
255
+ // Incomplete — exit loop; end-of-input buffers from seqStart.
256
+ // Re-entry re-tokenizes from ground via the invalid-CSI fallthrough.
257
+ i = data.length
258
+ }
259
+
260
+ break
261
+ }
262
+
263
+ if (isCSIFinal(code)) {
264
+ i++
265
+ emitSequence(data.slice(seqStart, i))
266
+ } else if (isCSIParam(code) || isCSIIntermediate(code)) {
267
+ i++
268
+ } else {
269
+ // Invalid CSI - abort, treat as text
270
+ result.state = 'ground'
271
+ textStart = seqStart
272
+ }
273
+
274
+ break
275
+
276
+ case 'ss3':
277
+ // SS3 sequences: ESC O followed by a single final byte
278
+ if (code >= 0x40 && code <= 0x7e) {
279
+ i++
280
+ emitSequence(data.slice(seqStart, i))
281
+ } else {
282
+ // Invalid - treat as text
283
+ result.state = 'ground'
284
+ textStart = seqStart
285
+ }
286
+
287
+ break
288
+
289
+ case 'osc':
290
+ if (code === C0.BEL) {
291
+ i++
292
+ emitSequence(data.slice(seqStart, i))
293
+ } else if (code === C0.ESC && i + 1 < data.length && data.charCodeAt(i + 1) === ESC_TYPE.ST) {
294
+ i += 2
295
+ emitSequence(data.slice(seqStart, i))
296
+ } else {
297
+ i++
298
+ }
299
+
300
+ break
301
+
302
+ case 'dcs':
303
+
304
+ case 'apc':
305
+ if (code === C0.BEL) {
306
+ i++
307
+ emitSequence(data.slice(seqStart, i))
308
+ } else if (code === C0.ESC && i + 1 < data.length && data.charCodeAt(i + 1) === ESC_TYPE.ST) {
309
+ i += 2
310
+ emitSequence(data.slice(seqStart, i))
311
+ } else {
312
+ i++
313
+ }
314
+
315
+ break
316
+ }
317
+ }
318
+
319
+ // Handle end of input
320
+ if (result.state === 'ground') {
321
+ flushText()
322
+ } else if (flush && result.state === 'escape') {
323
+ // A bare ESC with nothing after it is the Escape key — the one incomplete
324
+ // state a flush should turn into input (the classic ESCDELAY lone-ESC
325
+ // disambiguation: ESC alone vs. ESC as a sequence/meta prefix).
326
+ const remaining = data.slice(seqStart)
327
+
328
+ if (remaining) {
329
+ tokens.push({ type: 'sequence', value: remaining })
330
+ }
331
+
332
+ result.state = 'ground'
333
+ } else {
334
+ // Buffer the incomplete sequence. Two paths land here:
335
+ // - streaming (flush=false): normal carry-over to the next feed.
336
+ // - flush=true while still inside a multi-byte control sequence
337
+ // (csi/osc/dcs/apc/ss3/escapeIntermediate): we deliberately do NOT
338
+ // emit it. A half-arrived CSI mouse report (ESC[<btn;col;row M) is an
339
+ // unfinished sequence, not user input — force-emitting it is what
340
+ // injects `46M`/`35;46M` shards into the prompt during a render stall.
341
+ // Keeping it buffered lets the continuation reassemble on the next
342
+ // feed (the xterm.js state-machine discipline — partial sequences
343
+ // never become text). createTokenizer.flush() drops the buffer if it
344
+ // survives a second flush with no progress (a genuine truncation), so
345
+ // a stuck partial can never merge into the next keypress's bytes.
346
+ result.buffer = data.slice(seqStart)
347
+ }
348
+
349
+ return { tokens, state: result }
350
+ }
@@ -0,0 +1,230 @@
1
+ /**
2
+ * ANSI Parser - Semantic Types
3
+ *
4
+ * These types represent the semantic meaning of ANSI escape sequences,
5
+ * not their string representation. Inspired by ghostty's action-based design.
6
+ */
7
+
8
+ // =============================================================================
9
+ // Colors
10
+ // =============================================================================
11
+
12
+ /** Named colors from the 16-color palette */
13
+ export type NamedColor =
14
+ | 'black'
15
+ | 'red'
16
+ | 'green'
17
+ | 'yellow'
18
+ | 'blue'
19
+ | 'magenta'
20
+ | 'cyan'
21
+ | 'white'
22
+ | 'brightBlack'
23
+ | 'brightRed'
24
+ | 'brightGreen'
25
+ | 'brightYellow'
26
+ | 'brightBlue'
27
+ | 'brightMagenta'
28
+ | 'brightCyan'
29
+ | 'brightWhite'
30
+
31
+ /** Color specification - can be named, indexed (256), or RGB */
32
+ export type Color =
33
+ | { type: 'named'; name: NamedColor }
34
+ | { type: 'indexed'; index: number } // 0-255
35
+ | { type: 'rgb'; r: number; g: number; b: number }
36
+ | { type: 'default' }
37
+
38
+ // =============================================================================
39
+ // Text Styles
40
+ // =============================================================================
41
+
42
+ /** Underline style variants */
43
+ export type UnderlineStyle = 'none' | 'single' | 'double' | 'curly' | 'dotted' | 'dashed'
44
+
45
+ /** Text style attributes - represents current styling state */
46
+ export type TextStyle = {
47
+ bold: boolean
48
+ dim: boolean
49
+ italic: boolean
50
+ underline: UnderlineStyle
51
+ blink: boolean
52
+ inverse: boolean
53
+ hidden: boolean
54
+ strikethrough: boolean
55
+ overline: boolean
56
+ fg: Color
57
+ bg: Color
58
+ underlineColor: Color
59
+ }
60
+
61
+ /** Create a default (reset) text style */
62
+ export function defaultStyle(): TextStyle {
63
+ return {
64
+ bold: false,
65
+ dim: false,
66
+ italic: false,
67
+ underline: 'none',
68
+ blink: false,
69
+ inverse: false,
70
+ hidden: false,
71
+ strikethrough: false,
72
+ overline: false,
73
+ fg: { type: 'default' },
74
+ bg: { type: 'default' },
75
+ underlineColor: { type: 'default' }
76
+ }
77
+ }
78
+
79
+ /** Check if two styles are equal */
80
+ export function stylesEqual(a: TextStyle, b: TextStyle): boolean {
81
+ return (
82
+ a.bold === b.bold &&
83
+ a.dim === b.dim &&
84
+ a.italic === b.italic &&
85
+ a.underline === b.underline &&
86
+ a.blink === b.blink &&
87
+ a.inverse === b.inverse &&
88
+ a.hidden === b.hidden &&
89
+ a.strikethrough === b.strikethrough &&
90
+ a.overline === b.overline &&
91
+ colorsEqual(a.fg, b.fg) &&
92
+ colorsEqual(a.bg, b.bg) &&
93
+ colorsEqual(a.underlineColor, b.underlineColor)
94
+ )
95
+ }
96
+
97
+ /** Check if two colors are equal */
98
+ export function colorsEqual(a: Color, b: Color): boolean {
99
+ if (a.type !== b.type) {
100
+ return false
101
+ }
102
+
103
+ switch (a.type) {
104
+ case 'named':
105
+ return a.name === (b as typeof a).name
106
+
107
+ case 'indexed':
108
+ return a.index === (b as typeof a).index
109
+
110
+ case 'rgb':
111
+ return a.r === (b as typeof a).r && a.g === (b as typeof a).g && a.b === (b as typeof a).b
112
+
113
+ case 'default':
114
+ return true
115
+ }
116
+ }
117
+
118
+ // =============================================================================
119
+ // Cursor Actions
120
+ // =============================================================================
121
+
122
+ export type CursorDirection = 'up' | 'down' | 'forward' | 'back'
123
+
124
+ export type CursorAction =
125
+ | { type: 'move'; direction: CursorDirection; count: number }
126
+ | { type: 'position'; row: number; col: number }
127
+ | { type: 'column'; col: number }
128
+ | { type: 'row'; row: number }
129
+ | { type: 'save' }
130
+ | { type: 'restore' }
131
+ | { type: 'show' }
132
+ | { type: 'hide' }
133
+ | {
134
+ type: 'style'
135
+ style: 'block' | 'underline' | 'bar'
136
+ blinking: boolean
137
+ }
138
+ | { type: 'nextLine'; count: number }
139
+ | { type: 'prevLine'; count: number }
140
+
141
+ // =============================================================================
142
+ // Erase Actions
143
+ // =============================================================================
144
+
145
+ export type EraseAction =
146
+ | { type: 'display'; region: 'toEnd' | 'toStart' | 'all' | 'scrollback' }
147
+ | { type: 'line'; region: 'toEnd' | 'toStart' | 'all' }
148
+ | { type: 'chars'; count: number }
149
+
150
+ // =============================================================================
151
+ // Scroll Actions
152
+ // =============================================================================
153
+
154
+ export type ScrollAction =
155
+ | { type: 'up'; count: number }
156
+ | { type: 'down'; count: number }
157
+ | { type: 'setRegion'; top: number; bottom: number }
158
+
159
+ // =============================================================================
160
+ // Mode Actions
161
+ // =============================================================================
162
+
163
+ export type ModeAction =
164
+ | { type: 'alternateScreen'; enabled: boolean }
165
+ | { type: 'bracketedPaste'; enabled: boolean }
166
+ | { type: 'mouseTracking'; mode: 'off' | 'normal' | 'button' | 'any' }
167
+ | { type: 'focusEvents'; enabled: boolean }
168
+
169
+ // =============================================================================
170
+ // Link Actions (OSC 8)
171
+ // =============================================================================
172
+
173
+ export type LinkAction = { type: 'start'; url: string; params?: Record<string, string> } | { type: 'end' }
174
+
175
+ // =============================================================================
176
+ // Title Actions (OSC 0/1/2)
177
+ // =============================================================================
178
+
179
+ export type TitleAction =
180
+ | { type: 'windowTitle'; title: string }
181
+ | { type: 'iconName'; name: string }
182
+ | { type: 'both'; title: string }
183
+
184
+ // =============================================================================
185
+ // Tab Status Action (OSC 21337)
186
+ // =============================================================================
187
+
188
+ /**
189
+ * Per-tab chrome metadata. Tristate for each field:
190
+ * - property absent → not mentioned in sequence, no change
191
+ * - null → explicitly cleared (bare key or key= with empty value)
192
+ * - value → set to this
193
+ */
194
+ export type TabStatusAction = {
195
+ indicator?: Color | null
196
+ status?: string | null
197
+ statusColor?: Color | null
198
+ }
199
+
200
+ // =============================================================================
201
+ // Parsed Segments - The output of the parser
202
+ // =============================================================================
203
+
204
+ /** A segment of styled text */
205
+ export type TextSegment = {
206
+ type: 'text'
207
+ text: string
208
+ style: TextStyle
209
+ }
210
+
211
+ /** A grapheme (visual character unit) with width info */
212
+ export type Grapheme = {
213
+ value: string
214
+ width: 1 | 2 // Display width in columns
215
+ }
216
+
217
+ /** All possible parsed actions */
218
+ export type Action =
219
+ | { type: 'text'; graphemes: Grapheme[]; style: TextStyle }
220
+ | { type: 'cursor'; action: CursorAction }
221
+ | { type: 'erase'; action: EraseAction }
222
+ | { type: 'scroll'; action: ScrollAction }
223
+ | { type: 'mode'; action: ModeAction }
224
+ | { type: 'link'; action: LinkAction }
225
+ | { type: 'title'; action: TitleAction }
226
+ | { type: 'tabStatus'; action: TabStatusAction }
227
+ | { type: 'sgr'; params: string } // Select Graphic Rendition (style change)
228
+ | { type: 'bell' }
229
+ | { type: 'reset' } // Full terminal reset (ESC c)
230
+ | { type: 'unknown'; sequence: string } // Unrecognized sequence
@@ -0,0 +1,42 @@
1
+ /**
2
+ * ANSI Parser Module
3
+ *
4
+ * A semantic ANSI escape sequence parser inspired by ghostty, tmux, and iTerm2.
5
+ *
6
+ * Key features:
7
+ * - Semantic output: produces structured actions, not string tokens
8
+ * - Streaming: can parse input incrementally via Parser class
9
+ * - Style tracking: maintains text style state across parse calls
10
+ * - Comprehensive: supports SGR, CSI, OSC, ESC sequences
11
+ *
12
+ * Usage:
13
+ *
14
+ * ```typescript
15
+ * import { Parser } from './termio.js'
16
+ *
17
+ * const parser = new Parser()
18
+ * const actions = parser.feed('\x1b[31mred\x1b[0m')
19
+ * // => [{ type: 'text', graphemes: [...], style: { fg: { type: 'named', name: 'red' }, ... } }]
20
+ * ```
21
+ */
22
+
23
+ // Parser
24
+ export { Parser } from './termio/parser.js'
25
+ // Types
26
+ export type {
27
+ Action,
28
+ Color,
29
+ CursorAction,
30
+ CursorDirection,
31
+ EraseAction,
32
+ Grapheme,
33
+ LinkAction,
34
+ ModeAction,
35
+ NamedColor,
36
+ ScrollAction,
37
+ TextSegment,
38
+ TextStyle,
39
+ TitleAction,
40
+ UnderlineStyle
41
+ } from './termio/types.js'
42
+ export { colorsEqual, defaultStyle, stylesEqual } from './termio/types.js'