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,6 @@
1
+ export function logForDebugging(
2
+ _message: string,
3
+ _options: {
4
+ level?: string
5
+ } = {}
6
+ ): void {}
@@ -0,0 +1,131 @@
1
+ import { lastGrapheme } from './intl.js'
2
+ let earlyInputBuffer = ''
3
+ let isCapturing = false
4
+ let readableHandler: (() => void) | null = null
5
+
6
+ export function startCapturingEarlyInput(): void {
7
+ if (!process.stdin.isTTY || isCapturing || process.argv.includes('-p') || process.argv.includes('--print')) {
8
+ return
9
+ }
10
+
11
+ isCapturing = true
12
+ earlyInputBuffer = ''
13
+
14
+ try {
15
+ process.stdin.setEncoding('utf8')
16
+ process.stdin.setRawMode(true)
17
+ process.stdin.ref()
18
+
19
+ readableHandler = () => {
20
+ let chunk = process.stdin.read()
21
+
22
+ while (chunk !== null) {
23
+ if (typeof chunk === 'string') {
24
+ processChunk(chunk)
25
+ }
26
+
27
+ chunk = process.stdin.read()
28
+ }
29
+ }
30
+
31
+ process.stdin.on('readable', readableHandler)
32
+ } catch {
33
+ isCapturing = false
34
+ }
35
+ }
36
+
37
+ function processChunk(str: string): void {
38
+ let i = 0
39
+
40
+ while (i < str.length) {
41
+ const char = str[i]!
42
+ const code = char.charCodeAt(0)
43
+
44
+ if (code === 3) {
45
+ stopCapturingEarlyInput()
46
+ process.exit(130)
47
+
48
+ return
49
+ }
50
+
51
+ if (code === 4) {
52
+ stopCapturingEarlyInput()
53
+
54
+ return
55
+ }
56
+
57
+ if (code === 127 || code === 8) {
58
+ if (earlyInputBuffer.length > 0) {
59
+ const last = lastGrapheme(earlyInputBuffer)
60
+ earlyInputBuffer = earlyInputBuffer.slice(0, -(last.length || 1))
61
+ }
62
+
63
+ i++
64
+
65
+ continue
66
+ }
67
+
68
+ if (code === 27) {
69
+ i++
70
+
71
+ while (i < str.length && !(str.charCodeAt(i) >= 64 && str.charCodeAt(i) <= 126)) {
72
+ i++
73
+ }
74
+
75
+ if (i < str.length) {
76
+ i++
77
+ }
78
+
79
+ continue
80
+ }
81
+
82
+ if (code < 32 && code !== 9 && code !== 10 && code !== 13) {
83
+ i++
84
+
85
+ continue
86
+ }
87
+
88
+ if (code === 13) {
89
+ earlyInputBuffer += '\n'
90
+ i++
91
+
92
+ continue
93
+ }
94
+
95
+ earlyInputBuffer += char
96
+ i++
97
+ }
98
+ }
99
+
100
+ export function stopCapturingEarlyInput(): void {
101
+ if (!isCapturing) {
102
+ return
103
+ }
104
+
105
+ isCapturing = false
106
+
107
+ if (readableHandler) {
108
+ process.stdin.removeListener('readable', readableHandler)
109
+ readableHandler = null
110
+ }
111
+ }
112
+
113
+ export function consumeEarlyInput(): string {
114
+ stopCapturingEarlyInput()
115
+ const input = earlyInputBuffer.trim()
116
+ earlyInputBuffer = ''
117
+
118
+ return input
119
+ }
120
+
121
+ export function hasEarlyInput(): boolean {
122
+ return earlyInputBuffer.trim().length > 0
123
+ }
124
+
125
+ export function seedEarlyInput(text: string): void {
126
+ earlyInputBuffer = text
127
+ }
128
+
129
+ export function isCapturingEarlyInput(): boolean {
130
+ return isCapturing
131
+ }
@@ -0,0 +1,66 @@
1
+ type TerminalName = string | null
2
+
3
+ function detectTerminal(): TerminalName {
4
+ if (process.env.CURSOR_TRACE_ID) {
5
+ return 'cursor'
6
+ }
7
+
8
+ if (process.env.TERM === 'xterm-ghostty') {
9
+ return 'ghostty'
10
+ }
11
+
12
+ if (process.env.TERM?.includes('kitty')) {
13
+ return 'kitty'
14
+ }
15
+
16
+ if (process.env.TERM_PROGRAM) {
17
+ return process.env.TERM_PROGRAM
18
+ }
19
+
20
+ if (process.env.TMUX) {
21
+ return 'tmux'
22
+ }
23
+
24
+ if (process.env.STY) {
25
+ return 'screen'
26
+ }
27
+
28
+ if (process.env.KITTY_WINDOW_ID) {
29
+ return 'kitty'
30
+ }
31
+
32
+ if (process.env.WT_SESSION) {
33
+ return 'windows-terminal'
34
+ }
35
+
36
+ return process.env.TERM ?? null
37
+ }
38
+
39
+ export const env = {
40
+ terminal: detectTerminal()
41
+ }
42
+
43
+ // Terminals known to correctly implement OSC 52 clipboard writes
44
+ // (ESC ] 52 ; c ; <b64> BEL/ST — osc() in ink/termio/osc.ts emits BEL
45
+ // for most terminals and ST for kitty). When detected, setClipboard() skips the
46
+ // native-tool safety net entirely — running wl-copy/xclip/pbcopy in
47
+ // parallel with OSC 52 races the terminal's own clipboard write and can
48
+ // corrupt it (e.g. wl-copy on Wayland holds the selection in a background
49
+ // daemon; stacking two writes within ~30ms triggers a SIGTERM race).
50
+ // Intentionally conservative: terminals with known flaky or disabled-by-
51
+ // default OSC 52 (iTerm2 disables OSC 52 by default; Alacritty detection
52
+ // is unreliable) are not on this list. Users on those terminals keep the
53
+ // existing behaviour (native safety net fires alongside OSC 52).
54
+ //
55
+ // Lives here in utils/env.ts (rather than ink/terminal.ts) so that
56
+ // ink/termio/osc.ts can import it without creating a circular dependency:
57
+ // ink/terminal.ts already imports `link` from ink/termio/osc.ts.
58
+ const OSC52_CAPABLE_TERMINALS = ['ghostty', 'kitty', 'WezTerm', 'windows-terminal', 'vscode']
59
+
60
+ /** True if this terminal is known to correctly handle OSC 52 clipboard
61
+ * writes, so setClipboard() can skip the native-tool safety net.
62
+ * Accepts an optional terminal name for testability; defaults to the
63
+ * module-level `env.terminal` detected at startup. */
64
+ export function supportsOsc52Clipboard(terminal: string | null = env.terminal): boolean {
65
+ return OSC52_CAPABLE_TERMINALS.includes(terminal ?? '')
66
+ }
@@ -0,0 +1,13 @@
1
+ export function isEnvTruthy(envVar: string | boolean | undefined): boolean {
2
+ if (!envVar) {
3
+ return false
4
+ }
5
+
6
+ if (typeof envVar === 'boolean') {
7
+ return envVar
8
+ }
9
+
10
+ const v = envVar.toLowerCase().trim()
11
+
12
+ return ['1', 'true', 'yes', 'on'].includes(v)
13
+ }
@@ -0,0 +1,146 @@
1
+ import { chmodSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
2
+ import { tmpdir } from 'node:os'
3
+ import { join } from 'node:path'
4
+
5
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest'
6
+
7
+ import { execFileNoThrow } from './execFileNoThrow.js'
8
+
9
+ // These tests shell out to /bin/sh, use chmodSync(0o755), and rely on
10
+ // POSIX sleep/job control. They will not work on Windows.
11
+ const onWindows = process.platform === 'win32'
12
+
13
+ // We simulate `wl-copy`'s daemonization behavior with a tiny shell script:
14
+ // 1. Fork a short-lived background sleeper that inherits stdio (so the
15
+ // parent process's pipes can never close).
16
+ // 2. Record the sleeper PID to a file so afterEach can clean it up.
17
+ // 3. Exit immediately with status 0.
18
+ //
19
+ // Without resolveOnExit, the await on `'close'` hangs until SIGTERM at
20
+ // timeout — exactly the production wl-copy bug. With resolveOnExit, the
21
+ // promise settles on `'exit'` regardless of the inherited pipes.
22
+
23
+ let scriptDir: string
24
+ let daemonScript: string
25
+ let sleeperPids: number[]
26
+
27
+ /** Read the PID file the daemon script writes, and track it for afterEach cleanup. */
28
+ function trackSleeperPid(pidFile: string): void {
29
+ try {
30
+ const pid = parseInt(readFileSync(pidFile, 'utf8').trim(), 10)
31
+ if (pid > 0) {
32
+ sleeperPids.push(pid)
33
+ }
34
+ } catch {
35
+ // PID file not written or unreadable — sleeper may have already exited.
36
+ }
37
+ }
38
+
39
+ beforeEach(() => {
40
+ sleeperPids = []
41
+ scriptDir = join(tmpdir(), `nastech-execfile-test-${process.pid}-${Date.now()}`)
42
+ mkdirSync(scriptDir, { recursive: true })
43
+ daemonScript = join(scriptDir, 'fake-daemonizer.sh')
44
+ // Posix sh: the `sleep 3 &` child inherits stdin/stdout/stderr from the
45
+ // shell, which inherited them from `spawn(stdio: 'pipe')`. The shell
46
+ // exits but its child (the sleeper) keeps the pipes open. Mirrors how
47
+ // wl-copy double-forks then exits while the daemon holds the selection.
48
+ // The sleeper writes its PID to $1 so we can clean it up reliably.
49
+ writeFileSync(daemonScript, '#!/bin/sh\nsleep 3 &\necho $! > "$1"\nexit 0\n')
50
+ chmodSync(daemonScript, 0o755)
51
+ })
52
+
53
+ afterEach(() => {
54
+ // Kill orphaned sleepers so they don't accumulate across watch runs.
55
+ for (const pid of sleeperPids) {
56
+ try {
57
+ process.kill(pid, 'SIGKILL')
58
+ } catch {
59
+ // Already exited — fine.
60
+ }
61
+ }
62
+ rmSync(scriptDir, { recursive: true, force: true })
63
+ })
64
+
65
+ describe.skipIf(onWindows)('execFileNoThrow with daemon-style children', () => {
66
+ // Skipped because the bug it documents is a forever-hang. Without
67
+ // resolveOnExit, the 'close' event doesn't fire when the immediate
68
+ // child has exited but a forked daemon still holds stdio open. Even
69
+ // SIGTERM at the timeout doesn't help — the daemon survives it. To
70
+ // verify by hand: remove `it.skip` and watch the test timeout. This
71
+ // test is here so a reviewer reading the resolveOnExit option knows
72
+ // *why* every clipboard-tool spawn in osc.ts wires it on.
73
+ it.skip("(documented hang) without resolveOnExit, await never resolves when daemon inherits stdio", async () => {
74
+ const pidFile = join(scriptDir, 'sleeper-skip.pid')
75
+ const result = await execFileNoThrow(daemonScript, [pidFile], { timeout: 300 })
76
+ trackSleeperPid(pidFile)
77
+
78
+ expect(result.code).toBe(124)
79
+ })
80
+
81
+ it("settles immediately on 'exit' when resolveOnExit is true, regardless of daemon stdio", async () => {
82
+ const pidFile = join(scriptDir, 'sleeper-exit.pid')
83
+ const start = Date.now()
84
+
85
+ const result = await execFileNoThrow(daemonScript, [pidFile], {
86
+ timeout: 2000,
87
+ resolveOnExit: true
88
+ })
89
+ trackSleeperPid(pidFile)
90
+
91
+ const elapsed = Date.now() - start
92
+
93
+ // The shell exits in a few ms. resolveOnExit lets us return on exit
94
+ // (code 0) instead of waiting for the orphaned sleeper to release
95
+ // stdio. Should be well under 200ms even on slow CI.
96
+ expect(result.code).toBe(0)
97
+ expect(elapsed).toBeLessThan(500)
98
+ })
99
+
100
+ it("still surfaces the right code when resolveOnExit'd child exits non-zero", async () => {
101
+ const pidFile = join(scriptDir, 'sleeper-fail.pid')
102
+ const failScript = join(scriptDir, 'fail.sh')
103
+ writeFileSync(failScript, `#!/bin/sh\nsleep 3 &\necho $! > "${pidFile}"\nexit 7\n`)
104
+ chmodSync(failScript, 0o755)
105
+
106
+ const result = await execFileNoThrow(failScript, [], {
107
+ timeout: 2000,
108
+ resolveOnExit: true
109
+ })
110
+ trackSleeperPid(pidFile)
111
+
112
+ expect(result.code).toBe(7)
113
+ })
114
+
115
+ it('settles on timeout=124 when the child itself never exits, even with resolveOnExit', async () => {
116
+ const slowScript = join(scriptDir, 'slow.sh')
117
+ writeFileSync(slowScript, '#!/bin/sh\nsleep 30\n')
118
+ chmodSync(slowScript, 0o755)
119
+
120
+ const result = await execFileNoThrow(slowScript, [], {
121
+ timeout: 200,
122
+ resolveOnExit: true
123
+ })
124
+
125
+ // Child process never exits on its own → timer fires → SIGTERM →
126
+ // child exits → 'exit' fires with non-null signal. The settle()
127
+ // call from the timer registers code=124 first. Either way: 124.
128
+ expect(result.code).toBe(124)
129
+ })
130
+
131
+ it('does not double-resolve when both timer and exit fire', async () => {
132
+ const pidFile = join(scriptDir, 'sleeper-race.pid')
133
+ // Race: child happens to exit right around the timeout. The settled
134
+ // guard ensures only the first resolution wins.
135
+ const result = await execFileNoThrow(daemonScript, [pidFile], {
136
+ timeout: 50, // very tight
137
+ resolveOnExit: true
138
+ })
139
+ trackSleeperPid(pidFile)
140
+
141
+ // Either code=0 (exit beat timer) or code=124 (timer beat exit).
142
+ // Both are valid outcomes; the contract is that the promise settles
143
+ // exactly once and doesn't throw.
144
+ expect([0, 124]).toContain(result.code)
145
+ })
146
+ })
@@ -0,0 +1,115 @@
1
+ import { spawn, type ChildProcess, type StdioOptions } from 'child_process'
2
+ type ExecFileOptions = {
3
+ input?: string
4
+ timeout?: number
5
+ useCwd?: boolean
6
+ env?: NodeJS.ProcessEnv
7
+ /** Resolve as soon as the child *exits*, instead of waiting for its
8
+ * stdio streams to close. Use this for tools that fork a daemon and
9
+ * let the daemon inherit the parent's stdio (e.g. `wl-copy`): the
10
+ * child exits immediately, but `'close'` never fires because the
11
+ * daemon holds the pipes open.
12
+ *
13
+ * When true, stdout and stderr are set to 'ignore' to prevent the
14
+ * daemon from inheriting those pipe FDs — the caller must not
15
+ * depend on collecting stdout/stderr content. Both will always be
16
+ * empty strings in this mode. */
17
+ resolveOnExit?: boolean
18
+ }
19
+
20
+ export function execFileNoThrow(
21
+ file: string,
22
+ args: string[],
23
+ options: ExecFileOptions = {}
24
+ ): Promise<{
25
+ stdout: string
26
+ stderr: string
27
+ code: number
28
+ error?: string
29
+ }> {
30
+ return new Promise(resolve => {
31
+ // When resolveOnExit is true, ignore stdout/stderr so the daemon
32
+ // doesn't inherit those pipe FDs — prevents handle leaks that can
33
+ // keep the parent process alive. No output data is collected in
34
+ // this mode; both stdout and stderr will be empty strings.
35
+ const stdioConfig: StdioOptions = options.resolveOnExit
36
+ ? ['pipe', 'ignore', 'ignore']
37
+ : 'pipe'
38
+
39
+ const child: ChildProcess = spawn(file, args, {
40
+ cwd: options.useCwd ? process.cwd() : undefined,
41
+ env: options.env,
42
+ stdio: stdioConfig
43
+ })
44
+
45
+ let stdout = ''
46
+ let stderr = ''
47
+ let timedOut = false
48
+ let settled = false
49
+
50
+ const settle = (code: number, error?: string) => {
51
+ if (settled) {
52
+ return
53
+ }
54
+
55
+ settled = true
56
+
57
+ if (timer) {
58
+ clearTimeout(timer)
59
+ }
60
+
61
+ // Destroy any remaining streams to release FDs promptly.
62
+ // After settle(), nobody reads from these anymore.
63
+ child.stdout?.destroy()
64
+ child.stderr?.destroy()
65
+
66
+ resolve({ stdout, stderr, code, ...(error ? { error } : {}) })
67
+ }
68
+
69
+ const timer = options.timeout
70
+ ? setTimeout(() => {
71
+ timedOut = true
72
+ child.kill('SIGTERM')
73
+
74
+ // When resolving on exit, SIGTERM-ing a child that has already
75
+ // exited is a no-op and `'exit'` won't fire again — settle here
76
+ // so the promise doesn't leak. Safe under settled-guard.
77
+ if (options.resolveOnExit) {
78
+ settle(124)
79
+ }
80
+ }, options.timeout)
81
+ : null
82
+
83
+ child.stdout?.on('data', chunk => {
84
+ stdout += String(chunk)
85
+ })
86
+ child.stderr?.on('data', chunk => {
87
+ stderr += String(chunk)
88
+ })
89
+ child.on('error', error => {
90
+ settle(1, String(error))
91
+ })
92
+
93
+ if (options.resolveOnExit) {
94
+ // 'exit' fires when the child process itself exits — even if the
95
+ // daemon it forked still holds the inherited stdio pipes open.
96
+ // When a signal kills the child, code is null — map that to 1
97
+ // so callers don't mistake a signal-terminated run for success.
98
+ child.on('exit', (code, signal) => {
99
+ const exitCode = timedOut ? 124 : (code ?? (signal ? 1 : 0))
100
+ settle(exitCode)
101
+ })
102
+ } else {
103
+ child.on('close', (code, signal) => {
104
+ const exitCode = timedOut ? 124 : (code ?? (signal ? 1 : 0))
105
+ settle(exitCode)
106
+ })
107
+ }
108
+
109
+ if (options.input) {
110
+ child.stdin?.write(options.input)
111
+ }
112
+
113
+ child.stdin?.end()
114
+ })
115
+ }
@@ -0,0 +1,3 @@
1
+ export function isMouseClicksDisabled(): boolean {
2
+ return /^(1|true|yes|on)$/.test((process.env.NASTECH_TUI_DISABLE_MOUSE_CLICKS ?? '').trim().toLowerCase())
3
+ }
@@ -0,0 +1,87 @@
1
+ let graphemeSegmenter: Intl.Segmenter | null = null
2
+ let wordSegmenter: Intl.Segmenter | null = null
3
+
4
+ export function getGraphemeSegmenter(): Intl.Segmenter {
5
+ if (!graphemeSegmenter) {
6
+ graphemeSegmenter = new Intl.Segmenter(undefined, {
7
+ granularity: 'grapheme'
8
+ })
9
+ }
10
+
11
+ return graphemeSegmenter
12
+ }
13
+
14
+ export function firstGrapheme(text: string): string {
15
+ if (!text) {
16
+ return ''
17
+ }
18
+
19
+ const segments = getGraphemeSegmenter().segment(text)
20
+ const first = segments[Symbol.iterator]().next().value
21
+
22
+ return first?.segment ?? ''
23
+ }
24
+
25
+ export function lastGrapheme(text: string): string {
26
+ if (!text) {
27
+ return ''
28
+ }
29
+
30
+ let last = ''
31
+
32
+ for (const { segment } of getGraphemeSegmenter().segment(text)) {
33
+ last = segment
34
+ }
35
+
36
+ return last
37
+ }
38
+
39
+ export function getWordSegmenter(): Intl.Segmenter {
40
+ if (!wordSegmenter) {
41
+ wordSegmenter = new Intl.Segmenter(undefined, { granularity: 'word' })
42
+ }
43
+
44
+ return wordSegmenter
45
+ }
46
+
47
+ const rtfCache = new Map<string, Intl.RelativeTimeFormat>()
48
+
49
+ export function getRelativeTimeFormat(
50
+ style: 'long' | 'short' | 'narrow',
51
+ numeric: 'always' | 'auto'
52
+ ): Intl.RelativeTimeFormat {
53
+ const key = `${style}:${numeric}`
54
+ let rtf = rtfCache.get(key)
55
+
56
+ if (!rtf) {
57
+ rtf = new Intl.RelativeTimeFormat('en', { style, numeric })
58
+ rtfCache.set(key, rtf)
59
+ }
60
+
61
+ return rtf
62
+ }
63
+
64
+ let cachedTimeZone: string | null = null
65
+
66
+ export function getTimeZone(): string {
67
+ if (!cachedTimeZone) {
68
+ cachedTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
69
+ }
70
+
71
+ return cachedTimeZone
72
+ }
73
+
74
+ let cachedSystemLocaleLanguage: string | undefined | null = null
75
+
76
+ export function getSystemLocaleLanguage(): string | undefined {
77
+ if (cachedSystemLocaleLanguage === null) {
78
+ try {
79
+ const locale = Intl.DateTimeFormat().resolvedOptions().locale
80
+ cachedSystemLocaleLanguage = new Intl.Locale(locale).language
81
+ } catch {
82
+ cachedSystemLocaleLanguage = undefined
83
+ }
84
+ }
85
+
86
+ return cachedSystemLocaleLanguage
87
+ }
@@ -0,0 +1,7 @@
1
+ export function logError(error: unknown): void {
2
+ if (!process.env.NASTECH_INK_DEBUG_ERRORS) {
3
+ return
4
+ }
5
+
6
+ console.error(error)
7
+ }
@@ -0,0 +1,57 @@
1
+ let _npmSemver: typeof import('semver') | undefined
2
+
3
+ function getNpmSemver(): typeof import('semver') {
4
+ if (!_npmSemver) {
5
+ _npmSemver = require('semver') as typeof import('semver')
6
+ }
7
+
8
+ return _npmSemver
9
+ }
10
+
11
+ export function gt(a: string, b: string): boolean {
12
+ if (typeof Bun !== 'undefined') {
13
+ return Bun.semver.order(a, b) === 1
14
+ }
15
+
16
+ return getNpmSemver().gt(a, b, { loose: true })
17
+ }
18
+
19
+ export function gte(a: string, b: string): boolean {
20
+ if (typeof Bun !== 'undefined') {
21
+ return Bun.semver.order(a, b) >= 0
22
+ }
23
+
24
+ return getNpmSemver().gte(a, b, { loose: true })
25
+ }
26
+
27
+ export function lt(a: string, b: string): boolean {
28
+ if (typeof Bun !== 'undefined') {
29
+ return Bun.semver.order(a, b) === -1
30
+ }
31
+
32
+ return getNpmSemver().lt(a, b, { loose: true })
33
+ }
34
+
35
+ export function lte(a: string, b: string): boolean {
36
+ if (typeof Bun !== 'undefined') {
37
+ return Bun.semver.order(a, b) <= 0
38
+ }
39
+
40
+ return getNpmSemver().lte(a, b, { loose: true })
41
+ }
42
+
43
+ export function satisfies(version: string, range: string): boolean {
44
+ if (typeof Bun !== 'undefined') {
45
+ return Bun.semver.satisfies(version, range)
46
+ }
47
+
48
+ return getNpmSemver().satisfies(version, range, { loose: true })
49
+ }
50
+
51
+ export function order(a: string, b: string): -1 | 0 | 1 {
52
+ if (typeof Bun !== 'undefined') {
53
+ return Bun.semver.order(a, b)
54
+ }
55
+
56
+ return getNpmSemver().compare(a, b, { loose: true }) as -1 | 0 | 1
57
+ }