@oh-my-pi/pi-tui 18.4.2 → 18.4.4

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 (463) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/dist/types/apps/cleanse-board.d.ts +17 -0
  3. package/dist/types/apps/git/help.d.ts +16 -0
  4. package/dist/types/apps/git/sidebar.d.ts +18 -0
  5. package/dist/types/apps/live-visualizer.d.ts +10 -0
  6. package/dist/types/apps/ps-top.d.ts +15 -0
  7. package/dist/types/apps/standalone-picker.d.ts +3 -0
  8. package/dist/types/autocomplete.d.ts +8 -0
  9. package/dist/types/chat/advisor-message.d.ts +12 -2
  10. package/dist/types/chat/assistant-message.d.ts +20 -0
  11. package/dist/types/chat/bash-execution.d.ts +9 -0
  12. package/dist/types/chat/chat-transcript-builder.d.ts +6 -1
  13. package/dist/types/chat/collab-prompt-message.d.ts +4 -0
  14. package/dist/types/chat/compaction-summary-message.d.ts +15 -0
  15. package/dist/types/chat/eval-execution.d.ts +8 -0
  16. package/dist/types/chat/execution-shared.d.ts +58 -0
  17. package/dist/types/chat/late-diagnostics-message.d.ts +15 -1
  18. package/dist/types/chat/read-tool-group.d.ts +15 -0
  19. package/dist/types/chat/skill-message.d.ts +9 -0
  20. package/dist/types/chat/stripped-tool-calls-placeholder.d.ts +3 -0
  21. package/dist/types/chat/thinking-display.d.ts +2 -0
  22. package/dist/types/chat/todo-reminder.d.ts +4 -1
  23. package/dist/types/chat/tool-execution.d.ts +25 -1
  24. package/dist/types/chat/transcript-actions.d.ts +37 -0
  25. package/dist/types/chat/transcript-entry.d.ts +3 -1
  26. package/dist/types/chat/user-message.d.ts +25 -0
  27. package/dist/types/chrome/collab-qrcode.d.ts +7 -0
  28. package/dist/types/chrome/context-thresholds.d.ts +11 -0
  29. package/dist/types/chrome/countdown-timer.d.ts +9 -3
  30. package/dist/types/chrome/diff.d.ts +12 -0
  31. package/dist/types/chrome/dynamic-border.d.ts +3 -0
  32. package/dist/types/chrome/format.d.ts +6 -0
  33. package/dist/types/chrome/message-divider.d.ts +13 -0
  34. package/dist/types/chrome/message-frame.d.ts +10 -0
  35. package/dist/types/chrome/message-notice.d.ts +23 -0
  36. package/dist/types/chrome/overlay-box.d.ts +11 -2
  37. package/dist/types/chrome/qrcode.d.ts +7 -0
  38. package/dist/types/chrome/segment-track.d.ts +7 -0
  39. package/dist/types/chrome/selector-helpers.d.ts +0 -6
  40. package/dist/types/chrome/status-notice.d.ts +14 -0
  41. package/dist/types/chrome/streaming-panel.d.ts +3 -0
  42. package/dist/types/chrome/tool-activity.d.ts +3 -0
  43. package/dist/types/chrome/transcript-container.d.ts +13 -0
  44. package/dist/types/chrome/transcript-status.d.ts +15 -3
  45. package/dist/types/components/box.d.ts +7 -0
  46. package/dist/types/components/disclosure.d.ts +9 -0
  47. package/dist/types/components/editor.d.ts +42 -0
  48. package/dist/types/components/form.d.ts +14 -0
  49. package/dist/types/components/image.d.ts +7 -0
  50. package/dist/types/components/input.d.ts +20 -1
  51. package/dist/types/components/key-value-list.d.ts +3 -0
  52. package/dist/types/components/layout/geometry.d.ts +16 -0
  53. package/dist/types/components/layout/row.d.ts +7 -0
  54. package/dist/types/components/layout/split-pane.d.ts +8 -0
  55. package/dist/types/components/layout/stack.d.ts +6 -0
  56. package/dist/types/components/loader.d.ts +48 -0
  57. package/dist/types/components/markdown.d.ts +8 -0
  58. package/dist/types/components/metric.d.ts +7 -0
  59. package/dist/types/components/progress-bar.d.ts +3 -0
  60. package/dist/types/components/scroll-view.d.ts +6 -0
  61. package/dist/types/components/section.d.ts +3 -0
  62. package/dist/types/components/select-list.d.ts +33 -0
  63. package/dist/types/components/settings-list.d.ts +68 -0
  64. package/dist/types/components/spacer.d.ts +4 -0
  65. package/dist/types/components/tab-bar.d.ts +9 -0
  66. package/dist/types/components/table.d.ts +7 -0
  67. package/dist/types/components/text.d.ts +6 -0
  68. package/dist/types/components/tree-view.d.ts +9 -0
  69. package/dist/types/components/truncated-text.d.ts +3 -0
  70. package/dist/types/components/wizard-step.d.ts +6 -0
  71. package/dist/types/hotkeys-markdown.d.ts +24 -0
  72. package/dist/types/index.d.ts +5 -0
  73. package/dist/types/latex-block.d.ts +7 -0
  74. package/dist/types/loop-watchdog.d.ts +9 -0
  75. package/dist/types/native/apply.d.ts +39 -0
  76. package/dist/types/native/backend.d.ts +94 -0
  77. package/dist/types/native/blobs.d.ts +29 -0
  78. package/dist/types/native/describe.d.ts +56 -0
  79. package/dist/types/native/encode.d.ts +50 -0
  80. package/dist/types/native/icons.d.ts +18 -0
  81. package/dist/types/native/memo.d.ts +27 -0
  82. package/dist/types/native/node.d.ts +107 -0
  83. package/dist/types/native/overlay.d.ts +64 -0
  84. package/dist/types/native/picker.d.ts +124 -0
  85. package/dist/types/native/reconcile.d.ts +41 -0
  86. package/dist/types/native/settle.d.ts +11 -0
  87. package/dist/types/native/spans.d.ts +21 -0
  88. package/dist/types/native/state.d.ts +6 -0
  89. package/dist/types/native/tone.d.ts +24 -0
  90. package/dist/types/overlays/advisor-config.d.ts +20 -0
  91. package/dist/types/overlays/agent-hub-renderer.d.ts +27 -11
  92. package/dist/types/overlays/agent-hub.d.ts +10 -0
  93. package/dist/types/overlays/agent-transcript-viewer.d.ts +7 -0
  94. package/dist/types/overlays/agents-hub.d.ts +8 -0
  95. package/dist/types/overlays/annotation-overlay.d.ts +3 -0
  96. package/dist/types/overlays/ask-dialog.d.ts +23 -0
  97. package/dist/types/overlays/bordered-loader.d.ts +3 -0
  98. package/dist/types/overlays/btw-history-panel.d.ts +9 -0
  99. package/dist/types/overlays/btw-panel.d.ts +3 -0
  100. package/dist/types/overlays/cleanse-panel.d.ts +5 -2
  101. package/dist/types/overlays/composer-shape-preview.d.ts +7 -1
  102. package/dist/types/overlays/copy-selector.d.ts +38 -0
  103. package/dist/types/overlays/error-banner.d.ts +9 -0
  104. package/dist/types/overlays/extensions/extension-list.d.ts +1 -0
  105. package/dist/types/overlays/history-search.d.ts +18 -0
  106. package/dist/types/overlays/hook-editor.d.ts +28 -1
  107. package/dist/types/overlays/hook-input.d.ts +3 -0
  108. package/dist/types/overlays/hook-selector.d.ts +10 -0
  109. package/dist/types/overlays/hub-frame.d.ts +18 -0
  110. package/dist/types/overlays/jobs-panel.d.ts +24 -0
  111. package/dist/types/overlays/login-dialog.d.ts +10 -0
  112. package/dist/types/overlays/logout-account-selector.d.ts +4 -0
  113. package/dist/types/overlays/mcp-add-wizard.d.ts +4 -0
  114. package/dist/types/overlays/model-browser.d.ts +69 -0
  115. package/dist/types/overlays/model-hub.d.ts +7 -0
  116. package/dist/types/overlays/model-picker.d.ts +9 -1
  117. package/dist/types/overlays/move-overlay.d.ts +3 -0
  118. package/dist/types/overlays/oauth-selector.d.ts +4 -0
  119. package/dist/types/overlays/omfg-panel.d.ts +3 -0
  120. package/dist/types/overlays/pause-screen.d.ts +12 -0
  121. package/dist/types/overlays/plan-review-overlay.d.ts +5 -0
  122. package/dist/types/overlays/plan-save-overlay.d.ts +10 -0
  123. package/dist/types/overlays/plugin-selector.d.ts +4 -0
  124. package/dist/types/overlays/plugin-settings.d.ts +30 -0
  125. package/dist/types/overlays/queue-mode-selector.d.ts +4 -0
  126. package/dist/types/overlays/reset-usage-selector.d.ts +8 -0
  127. package/dist/types/overlays/rewind-selector.d.ts +5 -0
  128. package/dist/types/overlays/session-info-overlay.d.ts +19 -1
  129. package/dist/types/overlays/session-selector.d.ts +64 -1
  130. package/dist/types/overlays/settings-defs.d.ts +14 -0
  131. package/dist/types/overlays/settings-selector.d.ts +21 -0
  132. package/dist/types/overlays/show-images-selector.d.ts +4 -0
  133. package/dist/types/overlays/snapcompact-shape-preview.d.ts +2 -0
  134. package/dist/types/overlays/stats-notice.d.ts +8 -0
  135. package/dist/types/overlays/theme-selector.d.ts +11 -0
  136. package/dist/types/overlays/thinking-selector.d.ts +4 -0
  137. package/dist/types/overlays/tree-selector.d.ts +60 -2
  138. package/dist/types/overlays/usage-dashboard.d.ts +26 -3
  139. package/dist/types/overlays/usage-row.d.ts +36 -2
  140. package/dist/types/prompt/attachment-chips.d.ts +8 -0
  141. package/dist/types/prompt/composer-attachments.d.ts +15 -3
  142. package/dist/types/prompt/composer.d.ts +18 -1
  143. package/dist/types/prompt/custom-editor.d.ts +48 -2
  144. package/dist/types/prompt/editor-top-gap.d.ts +2 -0
  145. package/dist/types/prompt/macos-spelling.d.ts +6 -0
  146. package/dist/types/prompt/magic-keywords.d.ts +9 -0
  147. package/dist/types/prompt/queued-messages.d.ts +23 -0
  148. package/dist/types/prompt/skill-tokens.d.ts +4 -2
  149. package/dist/types/prompt/welcome.d.ts +16 -0
  150. package/dist/types/render/code-cell.d.ts +10 -0
  151. package/dist/types/render/file-list.d.ts +8 -0
  152. package/dist/types/render/hyperlink.d.ts +14 -0
  153. package/dist/types/render/output-block.d.ts +43 -0
  154. package/dist/types/render/output-pane.d.ts +17 -0
  155. package/dist/types/render/tool-card.d.ts +8 -0
  156. package/dist/types/render/tree-list.d.ts +8 -0
  157. package/dist/types/render/width-aware-text.d.ts +7 -0
  158. package/dist/types/setup/scenes/outro.d.ts +7 -0
  159. package/dist/types/setup/scenes/sign-in.d.ts +16 -9
  160. package/dist/types/setup/scenes/splash.d.ts +8 -0
  161. package/dist/types/setup/scenes/types.d.ts +6 -27
  162. package/dist/types/setup/wizard-overlay.d.ts +9 -0
  163. package/dist/types/status-line/component.d.ts +49 -5
  164. package/dist/types/status-line/context-usage.d.ts +20 -0
  165. package/dist/types/status-line/footer.d.ts +8 -0
  166. package/dist/types/status-line/metrics.d.ts +1 -2
  167. package/dist/types/status-line/segments.d.ts +10 -1
  168. package/dist/types/status-line/types.d.ts +40 -1
  169. package/dist/types/stdin-buffer.d.ts +10 -7
  170. package/dist/types/terminal-capabilities.d.ts +1 -1
  171. package/dist/types/terminal.d.ts +36 -0
  172. package/dist/types/theme/defaults/index.d.ts +100 -0
  173. package/dist/types/theme/schema.d.ts +2 -0
  174. package/dist/types/theme/shimmer.d.ts +8 -0
  175. package/dist/types/theme/theme-class.d.ts +2 -0
  176. package/dist/types/theme/theme.d.ts +33 -1
  177. package/dist/types/tools/ask.d.ts +3 -0
  178. package/dist/types/tools/ast-edit.d.ts +10 -1
  179. package/dist/types/tools/ast-grep.d.ts +10 -1
  180. package/dist/types/tools/autoresearch.d.ts +21 -4
  181. package/dist/types/tools/bash.d.ts +30 -1
  182. package/dist/types/tools/cfg-render.d.ts +5 -1
  183. package/dist/types/tools/debug.d.ts +3 -1
  184. package/dist/types/tools/default-renderer.d.ts +6 -1
  185. package/dist/types/tools/edit.d.ts +14 -1
  186. package/dist/types/tools/eval.d.ts +12 -1
  187. package/dist/types/tools/fetch.d.ts +16 -1
  188. package/dist/types/tools/find.d.ts +15 -1
  189. package/dist/types/tools/github.d.ts +3 -0
  190. package/dist/types/tools/glob.d.ts +14 -1
  191. package/dist/types/tools/goal.d.ts +3 -1
  192. package/dist/types/tools/grep.d.ts +14 -1
  193. package/dist/types/tools/grouped-file-output.d.ts +58 -0
  194. package/dist/types/tools/json-tree.d.ts +20 -0
  195. package/dist/types/tools/lsp.d.ts +3 -10
  196. package/dist/types/tools/mcp.d.ts +16 -1
  197. package/dist/types/tools/memory.d.ts +26 -0
  198. package/dist/types/tools/native-view.d.ts +90 -0
  199. package/dist/types/tools/proc-render.d.ts +7 -1
  200. package/dist/types/tools/read.d.ts +23 -1
  201. package/dist/types/tools/renderer.d.ts +57 -0
  202. package/dist/types/tools/report-tool-issue.d.ts +3 -0
  203. package/dist/types/tools/resolve.d.ts +14 -1
  204. package/dist/types/tools/task.d.ts +3 -0
  205. package/dist/types/tools/think.d.ts +3 -0
  206. package/dist/types/tools/todo.d.ts +12 -0
  207. package/dist/types/tools/vibe.d.ts +3 -1
  208. package/dist/types/tools/wait.d.ts +3 -0
  209. package/dist/types/tools/web-search-types.d.ts +90 -0
  210. package/dist/types/tools/web-search.d.ts +9 -168
  211. package/dist/types/tools/write.d.ts +14 -1
  212. package/dist/types/tools/xdev.d.ts +13 -0
  213. package/dist/types/tui.d.ts +49 -0
  214. package/package.json +9 -9
  215. package/src/apps/autoresearch-dashboard.ts +362 -4
  216. package/src/apps/cleanse-board.ts +219 -1
  217. package/src/apps/cleanse-picker.ts +9 -1
  218. package/src/apps/debug/log-viewer.ts +15 -15
  219. package/src/apps/debug/protocol-probe.ts +2 -20
  220. package/src/apps/git/avatar.ts +2 -22
  221. package/src/apps/git/git-tui.ts +406 -59
  222. package/src/apps/git/help.ts +130 -0
  223. package/src/apps/git/sidebar.ts +491 -0
  224. package/src/apps/live-visualizer.ts +65 -0
  225. package/src/apps/ps-top.ts +448 -17
  226. package/src/apps/session-picker.ts +1 -0
  227. package/src/apps/setup-model-picker.ts +5 -1
  228. package/src/apps/standalone-picker.ts +55 -1
  229. package/src/autocomplete.ts +44 -1
  230. package/src/chat/advisor-message.ts +72 -3
  231. package/src/chat/assistant-message.ts +538 -51
  232. package/src/chat/background-tan-message.ts +4 -4
  233. package/src/chat/bash-execution.ts +81 -0
  234. package/src/chat/cache-invalidation-marker.ts +8 -0
  235. package/src/chat/chat-transcript-builder.ts +37 -6
  236. package/src/chat/collab-prompt-message.ts +15 -3
  237. package/src/chat/compaction-summary-message.ts +74 -1
  238. package/src/chat/custom-message.ts +3 -1
  239. package/src/chat/eval-execution.ts +57 -0
  240. package/src/chat/execution-shared.ts +153 -1
  241. package/src/chat/hook-message.ts +1 -0
  242. package/src/chat/late-diagnostics-message.ts +85 -2
  243. package/src/chat/read-tool-group.ts +341 -1
  244. package/src/chat/served-model-marker.ts +8 -0
  245. package/src/chat/skill-message.ts +63 -0
  246. package/src/chat/stripped-tool-calls-placeholder.ts +18 -10
  247. package/src/chat/thinking-display.ts +73 -11
  248. package/src/chat/todo-reminder.ts +34 -4
  249. package/src/chat/tool-execution.ts +385 -10
  250. package/src/chat/transcript-actions.ts +38 -0
  251. package/src/chat/transcript-browser.ts +2 -9
  252. package/src/chat/transcript-entry.ts +10 -1
  253. package/src/chat/transcript-render-helpers.ts +16 -15
  254. package/src/chat/ttsr-notification.ts +38 -1
  255. package/src/chat/user-message.ts +167 -4
  256. package/src/chrome/collab-qrcode.ts +27 -2
  257. package/src/chrome/context-thresholds.ts +34 -0
  258. package/src/chrome/countdown-timer.ts +24 -1
  259. package/src/chrome/diff.ts +60 -1
  260. package/src/chrome/dynamic-border.ts +7 -0
  261. package/src/chrome/format.ts +12 -0
  262. package/src/chrome/message-divider.ts +33 -1
  263. package/src/chrome/message-frame.ts +53 -10
  264. package/src/chrome/message-notice.ts +71 -0
  265. package/src/chrome/overlay-box.ts +45 -2
  266. package/src/chrome/qrcode.ts +28 -0
  267. package/src/chrome/segment-track.ts +26 -0
  268. package/src/chrome/selector-helpers.ts +1 -17
  269. package/src/chrome/status-notice.ts +46 -0
  270. package/src/chrome/streaming-panel.ts +25 -1
  271. package/src/chrome/tool-activity.ts +20 -0
  272. package/src/chrome/transcript-container.ts +139 -17
  273. package/src/chrome/transcript-status.ts +40 -11
  274. package/src/components/box.ts +51 -0
  275. package/src/components/disclosure.ts +33 -0
  276. package/src/components/editor.ts +239 -36
  277. package/src/components/form.ts +93 -9
  278. package/src/components/image.ts +30 -0
  279. package/src/components/input.ts +77 -26
  280. package/src/components/key-value-list.ts +18 -0
  281. package/src/components/layout/geometry.ts +44 -0
  282. package/src/components/layout/row.ts +30 -0
  283. package/src/components/layout/split-pane.ts +65 -0
  284. package/src/components/layout/stack.ts +27 -0
  285. package/src/components/loader.ts +183 -1
  286. package/src/components/markdown.ts +131 -56
  287. package/src/components/metric.ts +39 -0
  288. package/src/components/progress-bar.ts +28 -0
  289. package/src/components/scroll-view.ts +23 -0
  290. package/src/components/section.ts +16 -0
  291. package/src/components/select-list.ts +174 -25
  292. package/src/components/settings-list.ts +264 -7
  293. package/src/components/spacer.ts +17 -0
  294. package/src/components/tab-bar.ts +42 -0
  295. package/src/components/table.ts +34 -0
  296. package/src/components/text.ts +23 -0
  297. package/src/components/tree-view.ts +65 -0
  298. package/src/components/truncated-text.ts +14 -0
  299. package/src/components/wizard-step.ts +18 -9
  300. package/src/debug-server.ts +14 -7
  301. package/src/hotkeys-markdown.ts +251 -69
  302. package/src/index.ts +6 -0
  303. package/src/latex-block.ts +11 -0
  304. package/src/loop-watchdog.ts +38 -10
  305. package/src/native/apply.ts +275 -0
  306. package/src/native/backend.ts +682 -0
  307. package/src/native/blobs.ts +70 -0
  308. package/src/native/describe.ts +124 -0
  309. package/src/native/encode.ts +233 -0
  310. package/src/native/icons.ts +184 -0
  311. package/src/native/memo.ts +64 -0
  312. package/src/native/node.ts +112 -0
  313. package/src/native/overlay.ts +131 -0
  314. package/src/native/picker.ts +333 -0
  315. package/src/native/reconcile.ts +1063 -0
  316. package/src/native/settle.ts +23 -0
  317. package/src/native/spans.ts +308 -0
  318. package/src/native/state.ts +28 -0
  319. package/src/native/tone.ts +79 -0
  320. package/src/overlays/advisor-config.ts +420 -0
  321. package/src/overlays/agent-hub-renderer.ts +155 -18
  322. package/src/overlays/agent-hub.ts +1037 -44
  323. package/src/overlays/agent-transcript-viewer.ts +129 -0
  324. package/src/overlays/agents-hub.ts +688 -53
  325. package/src/overlays/annotation-overlay.ts +391 -52
  326. package/src/overlays/ask-dialog.ts +435 -24
  327. package/src/overlays/bordered-loader.ts +17 -0
  328. package/src/overlays/btw-history-panel.ts +182 -0
  329. package/src/overlays/btw-panel.ts +68 -2
  330. package/src/overlays/cleanse-panel.ts +105 -15
  331. package/src/overlays/codex-reset-fireworks.ts +65 -5
  332. package/src/overlays/composer-shape-preview.ts +26 -1
  333. package/src/overlays/copy-selector.ts +545 -23
  334. package/src/overlays/error-banner.ts +44 -0
  335. package/src/overlays/extensions/extension-list.ts +23 -17
  336. package/src/overlays/history-search.ts +175 -33
  337. package/src/overlays/hook-editor.ts +113 -6
  338. package/src/overlays/hook-input.ts +22 -1
  339. package/src/overlays/hook-selector.ts +311 -22
  340. package/src/overlays/hub-frame.ts +80 -0
  341. package/src/overlays/jobs-panel.ts +112 -0
  342. package/src/overlays/login-dialog.ts +183 -1
  343. package/src/overlays/logout-account-selector.ts +102 -4
  344. package/src/overlays/mcp-add-wizard.ts +232 -53
  345. package/src/overlays/model-browser.ts +681 -22
  346. package/src/overlays/model-hub.ts +1402 -78
  347. package/src/overlays/model-picker.ts +184 -7
  348. package/src/overlays/move-overlay.ts +45 -0
  349. package/src/overlays/oauth-selector.ts +227 -23
  350. package/src/overlays/omfg-panel.ts +86 -2
  351. package/src/overlays/pause-screen.ts +55 -4
  352. package/src/overlays/plan-review-overlay.ts +352 -0
  353. package/src/overlays/plan-save-overlay.ts +45 -0
  354. package/src/overlays/plugin-selector.ts +21 -1
  355. package/src/overlays/plugin-settings.ts +195 -5
  356. package/src/overlays/queue-mode-selector.ts +19 -1
  357. package/src/overlays/reset-usage-selector.ts +110 -40
  358. package/src/overlays/rewind-selector.ts +458 -44
  359. package/src/overlays/session-account-selector.ts +1 -1
  360. package/src/overlays/session-info-overlay.ts +137 -1
  361. package/src/overlays/session-selector.ts +807 -46
  362. package/src/overlays/settings-defs.ts +41 -0
  363. package/src/overlays/settings-selector.ts +585 -33
  364. package/src/overlays/show-images-selector.ts +18 -1
  365. package/src/overlays/snapcompact-shape-preview.ts +48 -3
  366. package/src/overlays/stats-notice.ts +31 -0
  367. package/src/overlays/theme-selector.ts +31 -1
  368. package/src/overlays/thinking-selector.ts +22 -1
  369. package/src/overlays/tree-selector.ts +570 -110
  370. package/src/overlays/usage-dashboard.ts +587 -12
  371. package/src/overlays/usage-row.ts +161 -25
  372. package/src/prompt/attachment-chips.ts +60 -0
  373. package/src/prompt/composer-attachments.ts +31 -9
  374. package/src/prompt/composer.ts +55 -2
  375. package/src/prompt/custom-editor.ts +302 -4
  376. package/src/prompt/editor-top-gap.ts +8 -0
  377. package/src/prompt/macos-spelling.ts +24 -9
  378. package/src/prompt/magic-keywords.ts +22 -1
  379. package/src/prompt/model-mention-autocomplete.ts +1 -0
  380. package/src/prompt/queued-messages.ts +101 -0
  381. package/src/prompt/skill-tokens.ts +5 -3
  382. package/src/prompt/welcome.ts +213 -6
  383. package/src/render/code-cell.ts +103 -2
  384. package/src/render/file-list.ts +29 -0
  385. package/src/render/hyperlink.ts +32 -0
  386. package/src/render/output-block.ts +110 -0
  387. package/src/render/output-pane.ts +37 -0
  388. package/src/render/tool-card.ts +137 -0
  389. package/src/render/tree-list.ts +39 -0
  390. package/src/render/width-aware-text.ts +20 -0
  391. package/src/setup/scenes/composer.ts +29 -0
  392. package/src/setup/scenes/glyph.ts +15 -0
  393. package/src/setup/scenes/model.ts +36 -8
  394. package/src/setup/scenes/outro.ts +28 -1
  395. package/src/setup/scenes/sign-in.ts +138 -24
  396. package/src/setup/scenes/splash.ts +28 -1
  397. package/src/setup/scenes/theme.ts +88 -3
  398. package/src/setup/scenes/types.ts +7 -28
  399. package/src/setup/startup-splash.ts +46 -9
  400. package/src/setup/wizard-overlay.ts +140 -23
  401. package/src/setup/wizard.ts +1 -1
  402. package/src/status-line/component.ts +414 -18
  403. package/src/status-line/context-usage.ts +279 -50
  404. package/src/status-line/footer.ts +94 -1
  405. package/src/status-line/metrics.ts +3 -6
  406. package/src/status-line/segments.ts +463 -97
  407. package/src/status-line/separators.ts +3 -16
  408. package/src/status-line/types.ts +43 -1
  409. package/src/stdin-buffer.ts +27 -21
  410. package/src/terminal-capabilities.ts +7 -0
  411. package/src/terminal.ts +153 -11
  412. package/src/theme/defaults/dark-neon-noir.json +100 -0
  413. package/src/theme/defaults/index.ts +2 -0
  414. package/src/theme/defaults/light-prism.json +5 -5
  415. package/src/theme/defaults/onyx.json +62 -62
  416. package/src/theme/mermaid-cache.ts +10 -1
  417. package/src/theme/schema.ts +15 -0
  418. package/src/theme/shimmer.ts +33 -0
  419. package/src/theme/theme-class.ts +24 -19
  420. package/src/theme/theme.ts +111 -9
  421. package/src/theme/tui-adapters.ts +14 -1
  422. package/src/tools/ask.ts +157 -1
  423. package/src/tools/ast-edit.ts +174 -1
  424. package/src/tools/ast-grep.ts +82 -2
  425. package/src/tools/autoresearch.ts +149 -1
  426. package/src/tools/bash.ts +233 -62
  427. package/src/tools/cfg-render.ts +66 -1
  428. package/src/tools/debug.ts +78 -1
  429. package/src/tools/default-renderer.ts +35 -1
  430. package/src/tools/edit.ts +357 -31
  431. package/src/tools/eval.ts +257 -1
  432. package/src/tools/fetch.ts +102 -3
  433. package/src/tools/find.ts +127 -1
  434. package/src/tools/github.ts +119 -10
  435. package/src/tools/glob.ts +116 -1
  436. package/src/tools/goal.ts +56 -1
  437. package/src/tools/grep.ts +83 -2
  438. package/src/tools/grouped-file-output.ts +205 -0
  439. package/src/tools/json-tree.ts +116 -1
  440. package/src/tools/lsp.ts +318 -1
  441. package/src/tools/mcp.ts +80 -1
  442. package/src/tools/memory.ts +93 -11
  443. package/src/tools/native-view.ts +292 -0
  444. package/src/tools/proc-render.ts +221 -1
  445. package/src/tools/read.ts +199 -4
  446. package/src/tools/renderer.ts +61 -0
  447. package/src/tools/report-tool-issue.ts +7 -1
  448. package/src/tools/resolve.ts +63 -1
  449. package/src/tools/streaming-output.ts +79 -16
  450. package/src/tools/task.ts +406 -4
  451. package/src/tools/think.ts +19 -1
  452. package/src/tools/todo.ts +89 -0
  453. package/src/tools/vibe.ts +230 -2
  454. package/src/tools/wait.ts +181 -1
  455. package/src/tools/web-search-types.ts +99 -0
  456. package/src/tools/web-search.ts +111 -170
  457. package/src/tools/write.ts +144 -5
  458. package/src/tools/xdev.ts +64 -1
  459. package/src/tui.ts +295 -4
  460. package/dist/types/setup/scenes/providers.d.ts +0 -3
  461. package/dist/types/setup/scenes/web-search.d.ts +0 -22
  462. package/src/setup/scenes/providers.ts +0 -110
  463. package/src/setup/scenes/web-search.ts +0 -165
@@ -1,5 +1,9 @@
1
1
  import type { MouseRoutable, SgrMouseEvent } from "../mouse";
2
+ import { col } from "../native/describe";
3
+ import { sameItems } from "../native/memo";
4
+ import type { DescribeContext, NativeNode } from "../native/node";
2
5
  import type { Component } from "../tui";
6
+ import { spaceForRows } from "./spacer";
3
7
 
4
8
  /** Semantic role of a wizard step's primary interactive content. */
5
9
  export type WizardStepKind = "input" | "choice" | "confirm" | "async" | "custom";
@@ -37,14 +41,6 @@ function isMouseRoutable(component: Component): component is Component & MouseRo
37
41
  return "routeMouse" in component && typeof component.routeMouse === "function";
38
42
  }
39
43
 
40
- function sameLines(left: readonly string[], right: readonly string[]): boolean {
41
- if (left.length !== right.length) return false;
42
- for (let i = 0; i < left.length; i++) {
43
- if (left[i] !== right[i]) return false;
44
- }
45
- return true;
46
- }
47
-
48
44
  /**
49
45
  * Reusable presentation for input, choice, confirmation, and asynchronous
50
46
  * wizard steps. Controllers retain state transitions; this component owns the
@@ -68,6 +64,7 @@ export class WizardStep implements Component, MouseRoutable {
68
64
  #contentRowStart = -1;
69
65
  #contentRowCount = 0;
70
66
  #cachedLines: readonly string[] | undefined;
67
+ #native: { slots: readonly Component[]; node: NativeNode } | undefined;
71
68
 
72
69
  constructor(options: WizardStepOptions) {
73
70
  this.#kind = options.kind;
@@ -163,6 +160,18 @@ export class WizardStep implements Component, MouseRoutable {
163
160
  content.routeMouse(event, line - this.#contentRowStart, col);
164
161
  }
165
162
 
163
+ /**
164
+ * The slots in order as a spaced `col`; the height budget and optional
165
+ * preview collapse are the terminal's (it scrolls instead of clipping).
166
+ */
167
+ describe(_cx: DescribeContext): NativeNode {
168
+ const slots = this.debugChildren;
169
+ if (sameItems(this.#native?.slots, slots)) return this.#native!.node;
170
+ const described = col(slots, { gap: spaceForRows(this.#gap) });
171
+ this.#native = { slots, node: described };
172
+ return described;
173
+ }
174
+
166
175
  render(width: number): readonly string[] {
167
176
  const safeWidth = Math.max(1, width);
168
177
  const gap = this.#gap;
@@ -217,7 +226,7 @@ export class WizardStep implements Component, MouseRoutable {
217
226
  lines.push(...slot.lines);
218
227
  }
219
228
  const bounded = maxHeight === undefined || lines.length <= maxHeight ? lines : lines.slice(0, maxHeight);
220
- if (this.#cachedLines && sameLines(this.#cachedLines, bounded)) return this.#cachedLines;
229
+ if (this.#cachedLines && sameItems(this.#cachedLines, bounded)) return this.#cachedLines;
221
230
  this.#cachedLines = bounded;
222
231
  return bounded;
223
232
  }
@@ -1,7 +1,7 @@
1
1
  import { existsSync, unlinkSync } from "node:fs";
2
2
  import { createServer, type Server, type Socket } from "node:net";
3
3
  import { type Component, isFocusable, type OverlayOptions, type TUI } from "./tui";
4
- import { replaceTabs } from "./utils";
4
+ import { plainText } from "./native/spans";
5
5
 
6
6
  export interface TuiDebugTreeNode {
7
7
  kind: string;
@@ -63,10 +63,6 @@ const SPECIAL_KEYS: Readonly<Record<string, string>> = {
63
63
  f12: "\x1b[24~",
64
64
  };
65
65
 
66
- function plainLine(line: string): string {
67
- return replaceTabs(Bun.stripANSI(line)).replace(/[\x00-\x1f\x7f-\x9f]/g, "");
68
- }
69
-
70
66
  function errorMessage(error: unknown): string {
71
67
  try {
72
68
  return error instanceof Error ? error.message : String(error);
@@ -326,14 +322,25 @@ export class TuiDebugServer {
326
322
  if (paint === undefined) return { ok: false, error: "no frame painted yet" };
327
323
  return {
328
324
  ok: true,
329
- lines: paint.lines.map(plainLine),
325
+ lines: paint.lines.map(plainText),
330
326
  window_top: paint.windowTop,
331
327
  alt_screen: paint.altScreen,
332
328
  ...(paint.cursor === undefined ? {} : { cursor: paint.cursor }),
333
329
  };
334
330
  }
335
331
  case "frame":
336
- return { ok: true, lines: this.#tui.getDebugDocument().map(plainLine) };
332
+ return { ok: true, lines: this.#tui.getDebugDocument().map(plainText) };
333
+ case "doc": {
334
+ // The document a Tern Surface Protocol terminal should hold: every sent
335
+ // frame applied by the reference applier.
336
+ const doc = this.#tui.getNativeDocument();
337
+ if (doc === undefined) return { ok: false, error: "no native surface" };
338
+ return { ok: true, doc, rows: this.#tui.nativeFallbackCount };
339
+ }
340
+ case "tsp": {
341
+ const count = typeof request.n === "number" && request.n > 0 ? Math.trunc(request.n) : undefined;
342
+ return { ok: true, native: this.#tui.nativeRendering, frames: this.#tui.getNativeFrames(count) };
343
+ }
337
344
  case "tree":
338
345
  return { ok: true, tree: this.#tree() };
339
346
  case "values":
@@ -1,24 +1,67 @@
1
- import {
2
- type AppKeybinding,
3
- formatKeyHint,
4
- formatKeyHints,
5
- type KeybindingsManager,
6
- keyHintPlatform,
7
- } from "./app-keybindings";
1
+ import type { TspSpan } from "@oh-my-pi/pi-wire";
2
+ import { type AppKeybinding, formatKeyHint, type KeybindingsManager, keyHintPlatform } from "./app-keybindings";
3
+ import { Markdown } from "./components/markdown";
4
+ import { matchesSelectCancel } from "./keybinding-matchers";
5
+ import type { KeyName } from "./key-hint-format";
8
6
  import { canonicalKeyId } from "./keybindings";
7
+ import { col, node, span } from "./native/describe";
8
+ import type { NativeNode, NativeUiEvent } from "./native/node";
9
+ import { actionBar, actionButton } from "./native/overlay";
10
+ import { getMarkdownTheme } from "./theme/theme";
11
+ import type { Component } from "./tui";
9
12
 
10
13
  /** Effective keybinding operations used to render the hotkey reference. */
11
14
  export interface HotkeysMarkdownBindings {
12
15
  keybindings: Pick<KeybindingsManager, "getDisplayString" | "getKeys" | "matchesCanonical">;
13
16
  }
14
17
 
15
- function hotkeyLabel(bindings: HotkeysMarkdownBindings, action: AppKeybinding): string {
16
- return bindings.keybindings.getDisplayString(action) || "Disabled";
18
+ /**
19
+ * One piece of a shortcut cell: formatted key hints (alternatives, one keycap
20
+ * each), a literal typed token (`#<number>`, `!!`), or connecting prose.
21
+ */
22
+ type HotkeyPart =
23
+ | {
24
+ /** Formatted for the markdown table (`⌃R`); `Disabled` when unbound. */
25
+ keys: readonly string[];
26
+ /** Key ids (`ctrl+r`) for native keycaps, which the terminal draws with platform glyphs. */
27
+ ids: readonly KeyName[];
28
+ action?: AppKeybinding;
29
+ }
30
+ | { token: string }
31
+ | { text: string };
32
+
33
+ interface HotkeyRow {
34
+ readonly keys: readonly HotkeyPart[];
35
+ readonly action: string;
17
36
  }
18
37
 
19
- /** Build the platform-aware Markdown reference for effective application hotkeys. */
20
- export function buildHotkeysMarkdown(bindings: HotkeysMarkdownBindings): string {
38
+ interface HotkeyGroup {
39
+ readonly title: string;
40
+ readonly rows: readonly HotkeyRow[];
41
+ }
42
+
43
+ /** Formatted hints for key ids. */
44
+ function hints(keys: readonly KeyName[]): HotkeyPart {
45
+ return { keys: keys.map(formatKeyHint), ids: keys };
46
+ }
47
+
48
+ /** The markdown cell text of a part; key alternatives join with `/` as `formatKeyHints` does. */
49
+ function markdownPart(bindings: HotkeysMarkdownBindings, part: HotkeyPart): string {
50
+ if ("text" in part) return part.text;
51
+ if ("token" in part) return `\`${part.token}\``;
52
+ const label = part.action ? bindings.keybindings.getDisplayString(part.action) || "Disabled" : part.keys.join("/");
53
+ return `\`${label}\``;
54
+ }
55
+
56
+ /** The shortcut groups, built from the effective bindings. */
57
+ function hotkeyGroups(bindings: HotkeysMarkdownBindings): HotkeyGroup[] {
21
58
  const isMac = keyHintPlatform() === "darwin";
59
+ // An action's effective keys, one keycap each; `Disabled` when unbound.
60
+ const act = (action: AppKeybinding): HotkeyPart => {
61
+ const keys = bindings.keybindings.getKeys(action);
62
+ if (keys.length > 0) return { keys: keys.map(formatKeyHint), ids: keys, action };
63
+ return { keys: [bindings.keybindings.getDisplayString(action) || "Disabled"], ids: [], action };
64
+ };
22
65
  // CustomEditor tests the chord that was actually pressed, so exit keys split by role: a key
23
66
  // that also carries tui.editor.deleteCharForward (the readline `^D` overlap) forward-deletes
24
67
  // while the prompt holds a draft, any other exit key quits immediately. Mixed bindings such as
@@ -31,67 +74,206 @@ export function buildHotkeysMarkdown(bindings: HotkeysMarkdownBindings): string
31
74
  const quittingExitKeys = exitKeys.filter(
32
75
  key => !bindings.keybindings.matchesCanonical(canonicalKeyId(key), "tui.editor.deleteCharForward"),
33
76
  );
34
- const exitRows: string[] = [];
77
+ const exitRows: HotkeyRow[] = [];
35
78
  if (deletingExitKeys.length > 0) {
36
- exitRows.push(
37
- `| \`${formatKeyHints(deletingExitKeys)}\` | Delete char forward (with draft) / exit (empty prompt) |`,
38
- );
79
+ exitRows.push({
80
+ keys: [hints(deletingExitKeys)],
81
+ action: "Delete char forward (with draft) / exit (empty prompt)",
82
+ });
39
83
  }
40
84
  // An unbound exit action still gets its row, mirroring the `Disabled` hint every other row uses.
41
85
  if (quittingExitKeys.length > 0 || deletingExitKeys.length === 0) {
42
- exitRows.push(`| \`${formatKeyHints(quittingExitKeys) || "Disabled"}\` | Exit |`);
86
+ exitRows.push({
87
+ keys: [quittingExitKeys.length > 0 ? hints(quittingExitKeys) : { keys: ["Disabled"], ids: [] }],
88
+ action: "Exit",
89
+ });
90
+ }
91
+ const groups: HotkeyGroup[] = [
92
+ {
93
+ title: "Navigation",
94
+ rows: [
95
+ {
96
+ keys: [hints(["up", "down", "left", "right"])],
97
+ action: `Move cursor / browse history (${formatKeyHint("up")} when empty)`,
98
+ },
99
+ { keys: [hints(["alt+left", "alt+right"])], action: "Move by word" },
100
+ {
101
+ keys: [hints(isMac ? ["ctrl+a", "home", "super+left"] : ["ctrl+a", "home"])],
102
+ action: "Start of line",
103
+ },
104
+ { keys: [hints(isMac ? ["ctrl+e", "end", "super+right"] : ["ctrl+e", "end"])], action: "End of line" },
105
+ ],
106
+ },
107
+ {
108
+ title: "Editing",
109
+ rows: [
110
+ { keys: [hints(["enter"])], action: "Send message" },
111
+ { keys: [hints(["shift+enter", "alt+enter"])], action: "New line" },
112
+ { keys: [hints(["ctrl+w", "alt+backspace"])], action: "Delete word backwards" },
113
+ { keys: [hints(["ctrl+u"])], action: "Delete to start of line" },
114
+ { keys: [hints(["ctrl+k"])], action: "Delete to end of line" },
115
+ { keys: [act("app.clipboard.copyLine")], action: "Copy current line" },
116
+ { keys: [act("app.clipboard.copyPrompt")], action: "Copy whole prompt" },
117
+ ],
118
+ },
119
+ {
120
+ title: "Other",
121
+ rows: [
122
+ { keys: [hints(["tab"])], action: "Path completion / accept autocomplete" },
123
+ { keys: [act("app.interrupt")], action: "Cancel autocomplete / interrupt active work" },
124
+ { keys: [act("app.clear")], action: "Clear editor (first) / exit (second)" },
125
+ ...exitRows,
126
+ { keys: [act("app.suspend")], action: "Suspend to background" },
127
+ { keys: [act("app.display.reset")], action: "Reset terminal display" },
128
+ { keys: [act("app.thinking.cycle")], action: "Cycle thinking level" },
129
+ { keys: [act("app.model.cycleForward")], action: "Cycle role models (slow/default/smol)" },
130
+ { keys: [act("app.model.cycleBackward")], action: "Cycle role models (backward)" },
131
+ { keys: [act("app.model.selectTemporary")], action: "Select model (temporary)" },
132
+ { keys: [act("app.model.select")], action: "Select model (set roles)" },
133
+ { keys: [act("app.plan.toggle")], action: "Toggle plan mode" },
134
+ { keys: [act("app.history.search")], action: "Search prompt history" },
135
+ { keys: [act("app.tools.expand")], action: "Toggle tool output expansion" },
136
+ { keys: [act("app.tools.toggleVisibility")], action: "Toggle tool activity visibility" },
137
+ { keys: [act("app.thinking.toggle")], action: "Toggle thinking block visibility" },
138
+ { keys: [act("app.editor.external")], action: "Edit message in external editor" },
139
+ { keys: [act("app.retry")], action: "Retry last failed assistant turn" },
140
+ { keys: [act("app.clipboard.pasteImage")], action: "Paste image or text from clipboard" },
141
+ {
142
+ keys: [{ text: "Hold " }, hints(["space"])],
143
+ action: "Speech-to-text (push-to-talk): hold to record, release to transcribe",
144
+ },
145
+ { keys: [act("app.live.toggle")], action: "Start/stop live voice mode (/live)" },
146
+ {
147
+ keys: [
148
+ act("app.agents.hub"),
149
+ { text: " / " },
150
+ act("app.session.observe"),
151
+ { text: " / double-tap " },
152
+ hints(["left"]),
153
+ { text: " (empty editor)" },
154
+ ],
155
+ action: "Open the agent hub",
156
+ },
157
+ { keys: [{ token: "#<number>" }], action: "GitHub issue/PR reference (e.g. `#3164` → `pr://`/`issue://`)" },
158
+ {
159
+ keys: [{ token: "#" }, { text: " / " }, { token: "#<text>" }],
160
+ action: "Prompt actions (copy / undo / move cursor)",
161
+ },
162
+ { keys: [{ token: "/" }], action: "Slash commands" },
163
+ { keys: [{ token: "!" }], action: "Run bash command" },
164
+ { keys: [{ token: "!!" }], action: "Run bash command (excluded from context)" },
165
+ { keys: [{ token: "$" }], action: "Run Python in shared kernel" },
166
+ { keys: [{ token: "$$" }], action: "Run Python (excluded from context)" },
167
+ ],
168
+ },
169
+ ];
170
+ return groups;
171
+ }
172
+
173
+ /** Build the platform-aware Markdown reference for effective application hotkeys. */
174
+ export function buildHotkeysMarkdown(bindings: HotkeysMarkdownBindings): string {
175
+ const lines: string[] = [];
176
+ for (const [index, group] of hotkeyGroups(bindings).entries()) {
177
+ if (index > 0) lines.push("");
178
+ lines.push(`**${group.title}**`, "| Key | Action |", "|-----|--------|");
179
+ for (const row of group.rows) {
180
+ const keys = row.keys.map(part => markdownPart(bindings, part)).join("");
181
+ lines.push(`| ${keys} | ${row.action} |`);
182
+ }
183
+ }
184
+ return lines.join("\n");
185
+ }
186
+
187
+ /**
188
+ * A shortcut cell as spans: each key alternative a `key` span holding its key
189
+ * id (`ctrl+r`, drawn as a keycap like `kbd`), literal tokens as code, prose dim.
190
+ */
191
+ function keySpans(parts: readonly HotkeyPart[]): TspSpan[] {
192
+ const spans: TspSpan[] = [];
193
+ for (const part of parts) {
194
+ if ("text" in part) spans.push(span(part.text, "dim"));
195
+ else if ("token" in part) spans.push(span(part.token, "code"));
196
+ else if (part.ids.length === 0) spans.push(span(part.keys.join("/"), "dim"));
197
+ else {
198
+ for (const [index, id] of part.ids.entries()) {
199
+ if (index > 0) spans.push(span(" ", "dim"));
200
+ spans.push(span(id, "key"));
201
+ }
202
+ }
203
+ }
204
+ return spans;
205
+ }
206
+
207
+ /** Inline markdown (backticks) of an action description as spans: code runs mono, the rest plain. */
208
+ function actionSpans(action: string): TspSpan[] {
209
+ return action.split(/(`[^`]+`)/).flatMap(piece => {
210
+ if (piece === "") return [];
211
+ return piece.startsWith("`") && piece.endsWith("`") ? [span(piece.slice(1, -1), "code")] : [span(piece)];
212
+ });
213
+ }
214
+
215
+ /**
216
+ * `/hotkeys` under a native terminal: a large sheet "Keyboard shortcuts" with
217
+ * one section per group, each a two-column table whose key cells carry `key`
218
+ * spans (Tern draws them as keycaps). Esc (or Close) dismisses it. Terminals
219
+ * without the native surface get the transcript markdown panel instead.
220
+ */
221
+ export class HotkeysSheetComponent implements Component {
222
+ readonly nativeOverlay = { role: "omp.overlay.hotkeys", size: "lg", head: "Keyboard shortcuts" } as const;
223
+ readonly #bindings: HotkeysMarkdownBindings;
224
+ readonly #onClose: () => void;
225
+ #native: NativeNode | undefined;
226
+ #markdown: Markdown | undefined;
227
+
228
+ constructor(bindings: HotkeysMarkdownBindings, onClose: () => void) {
229
+ this.#bindings = bindings;
230
+ this.#onClose = onClose;
231
+ }
232
+
233
+ describe(): NativeNode {
234
+ if (this.#native) return this.#native;
235
+ const sections = hotkeyGroups(this.#bindings).map((group, index) =>
236
+ node(
237
+ "section",
238
+ { head: group.title, role: "omp.hotkeys.group" },
239
+ [
240
+ node("table", {
241
+ role: "omp.hotkeys.table",
242
+ cols: [
243
+ { id: "keys", head: "Key" },
244
+ { id: "action", head: "Action", grow: 1 },
245
+ ],
246
+ rows: group.rows.map((row, rowIndex) => ({
247
+ id: String(rowIndex),
248
+ cells: { keys: keySpans(row.keys), action: actionSpans(row.action) },
249
+ })),
250
+ }),
251
+ ],
252
+ `g${index}`,
253
+ ),
254
+ );
255
+ const close = actionButton("Close", "close", { keys: "escape" });
256
+ this.#native = col([...sections, actionBar([null, close])], { gap: "lg" });
257
+ return this.#native;
258
+ }
259
+
260
+ /** The markdown reference, for a terminal that falls back to rows. */
261
+ render(width: number): readonly string[] {
262
+ this.#markdown ??= new Markdown(buildHotkeysMarkdown(this.#bindings), 1, 1, getMarkdownTheme());
263
+ return this.#markdown.render(width);
264
+ }
265
+
266
+ invalidate(): void {
267
+ this.#native = undefined;
268
+ this.#markdown = undefined;
269
+ }
270
+
271
+ handleInput(data: string): void {
272
+ if (matchesSelectCancel(data)) this.#onClose();
273
+ }
274
+
275
+ /** Close runs what Esc runs. */
276
+ handleNativeEvent(event: NativeUiEvent): void {
277
+ if (event.type === "action" && event.act === "close") this.#onClose();
43
278
  }
44
- return [
45
- "**Navigation**",
46
- "| Key | Action |",
47
- "|-----|--------|",
48
- `| \`${formatKeyHints(["up", "down", "left", "right"])}\` | Move cursor / browse history (${formatKeyHint("up")} when empty) |`,
49
- `| \`${formatKeyHints(["alt+left", "alt+right"])}\` | Move by word |`,
50
- `| \`${formatKeyHints(isMac ? ["ctrl+a", "home", "super+left"] : ["ctrl+a", "home"])}\` | Start of line |`,
51
- `| \`${formatKeyHints(isMac ? ["ctrl+e", "end", "super+right"] : ["ctrl+e", "end"])}\` | End of line |`,
52
- "",
53
- "**Editing**",
54
- "| Key | Action |",
55
- "|-----|--------|",
56
- `| \`${formatKeyHint("enter")}\` | Send message |`,
57
- `| \`${formatKeyHints(["shift+enter", "alt+enter"])}\` | New line |`,
58
- `| \`${formatKeyHints(["ctrl+w", "alt+backspace"])}\` | Delete word backwards |`,
59
- `| \`${formatKeyHint("ctrl+u")}\` | Delete to start of line |`,
60
- `| \`${formatKeyHint("ctrl+k")}\` | Delete to end of line |`,
61
- `| \`${hotkeyLabel(bindings, "app.clipboard.copyLine")}\` | Copy current line |`,
62
- `| \`${hotkeyLabel(bindings, "app.clipboard.copyPrompt")}\` | Copy whole prompt |`,
63
- "",
64
- "**Other**",
65
- "| Key | Action |",
66
- "|-----|--------|",
67
- `| \`${formatKeyHint("tab")}\` | Path completion / accept autocomplete |`,
68
- `| \`${hotkeyLabel(bindings, "app.interrupt")}\` | Cancel autocomplete / interrupt active work |`,
69
- `| \`${hotkeyLabel(bindings, "app.clear")}\` | Clear editor (first) / exit (second) |`,
70
- ...exitRows,
71
- `| \`${hotkeyLabel(bindings, "app.suspend")}\` | Suspend to background |`,
72
- `| \`${hotkeyLabel(bindings, "app.display.reset")}\` | Reset terminal display |`,
73
- `| \`${hotkeyLabel(bindings, "app.thinking.cycle")}\` | Cycle thinking level |`,
74
- `| \`${hotkeyLabel(bindings, "app.model.cycleForward")}\` | Cycle role models (slow/default/smol) |`,
75
- `| \`${hotkeyLabel(bindings, "app.model.cycleBackward")}\` | Cycle role models (backward) |`,
76
- `| \`${hotkeyLabel(bindings, "app.model.selectTemporary")}\` | Select model (temporary) |`,
77
- `| \`${hotkeyLabel(bindings, "app.model.select")}\` | Select model (set roles) |`,
78
- `| \`${hotkeyLabel(bindings, "app.plan.toggle")}\` | Toggle plan mode |`,
79
- `| \`${hotkeyLabel(bindings, "app.history.search")}\` | Search prompt history |`,
80
- `| \`${hotkeyLabel(bindings, "app.tools.expand")}\` | Toggle tool output expansion |`,
81
- `| \`${hotkeyLabel(bindings, "app.tools.toggleVisibility")}\` | Toggle tool activity visibility |`,
82
- `| \`${hotkeyLabel(bindings, "app.thinking.toggle")}\` | Toggle thinking block visibility |`,
83
- `| \`${hotkeyLabel(bindings, "app.editor.external")}\` | Edit message in external editor |`,
84
- `| \`${hotkeyLabel(bindings, "app.retry")}\` | Retry last failed assistant turn |`,
85
- `| \`${hotkeyLabel(bindings, "app.clipboard.pasteImage")}\` | Paste image or text from clipboard |`,
86
- `| Hold \`${formatKeyHint("space")}\` | Speech-to-text (push-to-talk): hold to record, release to transcribe |`,
87
- `| \`${hotkeyLabel(bindings, "app.live.toggle")}\` | Start/stop live voice mode (/live) |`,
88
- `| \`${hotkeyLabel(bindings, "app.agents.hub")}\` / \`${hotkeyLabel(bindings, "app.session.observe")}\` / double-tap \`${formatKeyHint("left")}\` (empty editor) | Open the agent hub |`,
89
- "| `#<number>` | GitHub issue/PR reference (e.g. `#3164` → `pr://`/`issue://`) |",
90
- "| `#` / `#<text>` | Prompt actions (copy / undo / move cursor) |",
91
- "| `/` | Slash commands |",
92
- "| `!` | Run bash command |",
93
- "| `!!` | Run bash command (excluded from context) |",
94
- "| `$` | Run Python in shared kernel |",
95
- "| `$$` | Run Python (excluded from context) |",
96
- ].join("\n");
97
279
  }
package/src/index.ts CHANGED
@@ -57,6 +57,12 @@ export * from "./latex-block";
57
57
  export * from "./latex-to-unicode";
58
58
  // SGR mouse report parsing
59
59
  export * from "./mouse";
60
+ // Tern Surface Protocol: describe contract, builders, blobs, settling, render state
61
+ export * from "./native/blobs";
62
+ export * from "./native/describe";
63
+ export type * from "./native/node";
64
+ export * from "./native/settle";
65
+ export * from "./native/state";
60
66
  // Mermaid diagram support
61
67
  // Input buffering for batch splitting
62
68
  export * from "./stdin-buffer";
@@ -23,6 +23,8 @@
23
23
  // scratch here on this module's ANSI-aware Box model.
24
24
 
25
25
  import { latexColorScope, latexToUnicode, MATH_FONT_COMMANDS } from "./latex-to-unicode";
26
+ import { node } from "./native/describe";
27
+ import type { NativeNode } from "./native/node";
26
28
  import { visibleWidth } from "./utils";
27
29
 
28
30
  /**
@@ -1428,6 +1430,15 @@ function splitLines(src: string): string[] {
1428
1430
  return lines;
1429
1431
  }
1430
1432
 
1433
+ /**
1434
+ * The native form of {@link latexToBlock}: the TeX source as a `math` node
1435
+ * the terminal typesets (display style by default, `display: false` for
1436
+ * inline `$…$` math).
1437
+ */
1438
+ export function describeLatex(src: string, display = true): NativeNode {
1439
+ return node("math", { text: src, display });
1440
+ }
1441
+
1431
1442
  /**
1432
1443
  * Render a display LaTeX math fragment to lines with full 2-D layout: stacked
1433
1444
  * fractions, stretchy delimiters, matrix grids, operator limits, drawn
@@ -64,6 +64,8 @@ export class LoopWatchdog {
64
64
  #expected = 0;
65
65
  #expectedCpu = 0;
66
66
  #wasBlocked = false;
67
+ // When the most recent late tick ran — the moment a detected block ended.
68
+ #stallEndedAt = Number.NEGATIVE_INFINITY;
67
69
  #running = false;
68
70
  // Bumped by stop(); each scheduled tick captures the generation it was armed
69
71
  // under and no-ops if it no longer matches, so a start()→stop()→start() cycle
@@ -94,17 +96,40 @@ export class LoopWatchdog {
94
96
  if (this.#running) return;
95
97
  this.#running = true;
96
98
  this.#wasBlocked = false;
99
+ this.#stallEndedAt = Number.NEGATIVE_INFINITY;
97
100
  this.#armTick();
98
101
  }
99
102
 
100
103
  stop(): void {
101
104
  this.#running = false;
102
105
  this.#wasBlocked = false;
106
+ this.#stallEndedAt = Number.NEGATIVE_INFINITY;
103
107
  this.#generation++;
104
108
  this.#handle?.cancel?.();
105
109
  this.#handle = undefined;
106
110
  }
107
111
 
112
+ /**
113
+ * Whether the loop is blocked right now — the armed tick is already more
114
+ * than `thresholdMs` overdue — or a detected block ended within the last
115
+ * `thresholdMs`. Input read at such a moment may be keystrokes the block
116
+ * batched into one read. Resolves both orders in which a resumed loop can
117
+ * run the late tick and the queued stdin read. A suspended-process gap is
118
+ * not a stall, and a stopped watchdog never reports one.
119
+ */
120
+ isStalled(): boolean {
121
+ if (!this.#running) return false;
122
+ const now = this.#now();
123
+ if (now - this.#stallEndedAt <= this.#thresholdMs) return true;
124
+ const overdueMs = now - this.#expected;
125
+ return overdueMs > this.#thresholdMs && !this.#isSuspension(overdueMs, this.#cpuNow() - this.#expectedCpu);
126
+ }
127
+
128
+ /** A long gap the process spent negligible CPU on: it was suspended, not blocked. */
129
+ #isSuspension(blockedMs: number, cpuMs: number): boolean {
130
+ return blockedMs > this.#sleepMs && cpuMs < blockedMs * CPU_BUSY_RATIO;
131
+ }
132
+
108
133
  #armTick(): void {
109
134
  const generation = this.#generation;
110
135
  this.#expected = this.#now() + this.#intervalMs;
@@ -115,23 +140,26 @@ export class LoopWatchdog {
115
140
 
116
141
  #tick(generation: number): void {
117
142
  if (!this.#running || generation !== this.#generation) return;
118
- const blockedMs = this.#now() - this.#expected;
143
+ const now = this.#now();
144
+ const blockedMs = now - this.#expected;
119
145
  const cpuMs = this.#cpuNow() - this.#expectedCpu;
120
146
  // Consume the recent phase every tick (block or not) so attribution is
121
147
  // scoped to the just-elapsed interval and never carries a stale phase
122
148
  // forward to a later, phase-less block.
123
149
  const phase = takeRecentLoopPhase();
124
150
  if (blockedMs > this.#thresholdMs) {
125
- if (blockedMs > this.#sleepMs && cpuMs < blockedMs * CPU_BUSY_RATIO) {
126
- // A long gap the process did not spend CPU on: it was suspended.
151
+ if (this.#isSuspension(blockedMs, cpuMs)) {
127
152
  this.#wasBlocked = false;
128
- } else if (!this.#wasBlocked) {
129
- this.#wasBlocked = true;
130
- logger.warn("ui.loop-blocked", {
131
- blockedMs: Math.round(blockedMs),
132
- cpuMs: Math.round(cpuMs),
133
- phase: phase ?? "unknown",
134
- });
153
+ } else {
154
+ this.#stallEndedAt = now;
155
+ if (!this.#wasBlocked) {
156
+ this.#wasBlocked = true;
157
+ logger.warn("ui.loop-blocked", {
158
+ blockedMs: Math.round(blockedMs),
159
+ cpuMs: Math.round(cpuMs),
160
+ phase: phase ?? "unknown",
161
+ });
162
+ }
135
163
  }
136
164
  } else {
137
165
  this.#wasBlocked = false;