@linxiraos/pi-tui 1.1.26 → 1.2.0

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 (423) hide show
  1. package/CHANGELOG.md +51 -491
  2. package/README.md +13 -7
  3. package/dist/types/active-terminal.d.ts +30 -0
  4. package/dist/types/app-keybindings.d.ts +7 -2
  5. package/dist/types/apps/cleanse-board.d.ts +1 -1
  6. package/dist/types/apps/debug/log-viewer.d.ts +4 -0
  7. package/dist/types/apps/debug/raw-sse-buffer.d.ts +2 -0
  8. package/dist/types/apps/git/git-tui.d.ts +5 -4
  9. package/dist/types/apps/git/help.d.ts +3 -1
  10. package/dist/types/apps/if-bench-board.d.ts +2 -2
  11. package/dist/types/apps/setup-model-picker.d.ts +1 -1
  12. package/dist/types/autocomplete.d.ts +5 -2
  13. package/dist/types/charts/chart-plan.d.ts +674 -0
  14. package/dist/types/charts/chart-svg.d.ts +59 -0
  15. package/dist/types/charts/table-data.d.ts +175 -0
  16. package/dist/types/chat/assistant-message.d.ts +11 -1
  17. package/dist/types/chat/chat-transcript-builder.d.ts +3 -0
  18. package/dist/types/chat/compaction-summary-message.d.ts +1 -0
  19. package/dist/types/chat/execution-shared.d.ts +6 -5
  20. package/dist/types/chat/fence-figure.d.ts +42 -0
  21. package/dist/types/chat/figure-markdown.d.ts +42 -0
  22. package/dist/types/chat/messages.d.ts +1 -1
  23. package/dist/types/chat/svg-figure.d.ts +33 -0
  24. package/dist/types/chat/svg-source.d.ts +49 -0
  25. package/dist/types/chat/table-chart.d.ts +89 -0
  26. package/dist/types/chat/tool-execution.d.ts +2 -0
  27. package/dist/types/chat/user-message.d.ts +17 -4
  28. package/dist/types/chrome/shared.d.ts +9 -0
  29. package/dist/types/chrome/status-notice.d.ts +15 -3
  30. package/dist/types/chrome/transcript-container.d.ts +6 -0
  31. package/dist/types/components/box.d.ts +1 -0
  32. package/dist/types/components/disclosure.d.ts +1 -0
  33. package/dist/types/components/editor.d.ts +23 -5
  34. package/dist/types/components/form.d.ts +1 -0
  35. package/dist/types/components/image.d.ts +26 -44
  36. package/dist/types/components/input.d.ts +2 -1
  37. package/dist/types/components/key-value-list.d.ts +1 -0
  38. package/dist/types/components/layout/row.d.ts +1 -0
  39. package/dist/types/components/layout/stack.d.ts +1 -0
  40. package/dist/types/components/loader.d.ts +5 -6
  41. package/dist/types/components/markdown.d.ts +47 -5
  42. package/dist/types/components/scroll-view.d.ts +1 -0
  43. package/dist/types/components/section.d.ts +1 -0
  44. package/dist/types/components/table.d.ts +1 -0
  45. package/dist/types/components/text.d.ts +1 -0
  46. package/dist/types/components/tree-view.d.ts +7 -0
  47. package/dist/types/components/truncated-text.d.ts +1 -0
  48. package/dist/types/fuzzy.d.ts +29 -1
  49. package/dist/types/key-hint-format.d.ts +9 -1
  50. package/dist/types/keybinding-matchers.d.ts +3 -0
  51. package/dist/types/keybindings.d.ts +1 -1
  52. package/dist/types/kitty-graphics.d.ts +2 -2
  53. package/dist/types/loop-watchdog.d.ts +8 -7
  54. package/dist/types/multiplexers/cmux.d.ts +16 -0
  55. package/dist/types/multiplexers/herdr.d.ts +26 -0
  56. package/dist/types/multiplexers/notify.d.ts +13 -0
  57. package/dist/types/multiplexers/orca.d.ts +12 -0
  58. package/dist/types/multiplexers/screen.d.ts +9 -0
  59. package/dist/types/multiplexers/tmux.d.ts +29 -0
  60. package/dist/types/multiplexers/types.d.ts +100 -0
  61. package/dist/types/multiplexers/wmux.d.ts +12 -0
  62. package/dist/types/multiplexers/zellij.d.ts +12 -0
  63. package/dist/types/native/apply.d.ts +4 -3
  64. package/dist/types/native/backend.d.ts +5 -4
  65. package/dist/types/native/blobs.d.ts +7 -3
  66. package/dist/types/native/encode.d.ts +8 -6
  67. package/dist/types/native/node.d.ts +36 -5
  68. package/dist/types/native/overlay.d.ts +8 -3
  69. package/dist/types/native/settle.d.ts +4 -3
  70. package/dist/types/overlays/agent-hub-projection.d.ts +6 -5
  71. package/dist/types/overlays/agent-hub-types.d.ts +9 -0
  72. package/dist/types/overlays/agent-hub.d.ts +3 -0
  73. package/dist/types/overlays/agent-transcript-viewer.d.ts +12 -2
  74. package/dist/types/overlays/agents-hub.d.ts +9 -0
  75. package/dist/types/overlays/annotation-overlay.d.ts +19 -2
  76. package/dist/types/overlays/annotation-types.d.ts +2 -0
  77. package/dist/types/overlays/ask-dialog.d.ts +5 -2
  78. package/dist/types/overlays/btw-history-panel.d.ts +13 -1
  79. package/dist/types/overlays/copy-selector.d.ts +1 -0
  80. package/dist/types/overlays/history-search.d.ts +10 -0
  81. package/dist/types/overlays/hook-selector.d.ts +9 -4
  82. package/dist/types/overlays/hub-frame.d.ts +4 -1
  83. package/dist/types/overlays/jobs-panel.d.ts +1 -7
  84. package/dist/types/overlays/model-browser.d.ts +54 -7
  85. package/dist/types/overlays/model-hub.d.ts +37 -0
  86. package/dist/types/overlays/oauth-selector.d.ts +0 -1
  87. package/dist/types/overlays/plan-review-overlay.d.ts +3 -2
  88. package/dist/types/overlays/report-panel.d.ts +68 -0
  89. package/dist/types/overlays/rewind-selector.d.ts +1 -0
  90. package/dist/types/overlays/session-observer-registry.d.ts +2 -0
  91. package/dist/types/overlays/session-selector.d.ts +6 -2
  92. package/dist/types/overlays/settings-defs.d.ts +1 -0
  93. package/dist/types/overlays/thinking-selector.d.ts +2 -2
  94. package/dist/types/overlays/usage-dashboard.d.ts +12 -8
  95. package/dist/types/overlays/usage-display.d.ts +3 -1
  96. package/dist/types/prompt/composer-cache.d.ts +0 -16
  97. package/dist/types/prompt/composer.d.ts +18 -3
  98. package/dist/types/prompt/custom-editor.d.ts +25 -13
  99. package/dist/types/prompt/image-source.d.ts +2 -1
  100. package/dist/types/prompt/interactive-context-helpers.d.ts +5 -1
  101. package/dist/types/prompt/model-mention-autocomplete.d.ts +1 -1
  102. package/dist/types/prompt/welcome.d.ts +7 -2
  103. package/dist/types/render/composite.d.ts +2 -0
  104. package/dist/types/render/output-pane.d.ts +1 -0
  105. package/dist/types/render/render-utils.d.ts +1 -0
  106. package/dist/types/render/tool-card.d.ts +6 -0
  107. package/dist/types/render/width-aware-text.d.ts +2 -0
  108. package/dist/types/setup/scenes/types.d.ts +1 -0
  109. package/dist/types/space-hold.d.ts +40 -25
  110. package/dist/types/status-line/component.d.ts +3 -0
  111. package/dist/types/status-line/context-usage.d.ts +7 -5
  112. package/dist/types/status-line/host.d.ts +4 -1
  113. package/dist/types/status-line/segments.d.ts +2 -0
  114. package/dist/types/status-line/types.d.ts +14 -3
  115. package/dist/types/terminal-capabilities.d.ts +41 -36
  116. package/dist/types/terminal-multiplexer.d.ts +127 -14
  117. package/dist/types/terminal.d.ts +23 -16
  118. package/dist/types/theme/active-symbols.d.ts +1 -1
  119. package/dist/types/theme/schema.d.ts +11 -2
  120. package/dist/types/theme/symbols.d.ts +1 -1
  121. package/dist/types/theme/theme-class.d.ts +7 -0
  122. package/dist/types/theme/theme.d.ts +1 -1
  123. package/dist/types/theme/tui-adapters.d.ts +3 -0
  124. package/dist/types/thinking.d.ts +1 -1
  125. package/dist/types/tmux.d.ts +11 -4
  126. package/dist/types/tools/bash.d.ts +7 -2
  127. package/dist/types/tools/daemon.d.ts +1 -1
  128. package/dist/types/tools/eval.d.ts +22 -3
  129. package/dist/types/tools/glob.d.ts +4 -0
  130. package/dist/types/tools/native-view.d.ts +47 -0
  131. package/dist/types/tools/output-meta.d.ts +11 -1
  132. package/dist/types/tools/renderer.d.ts +37 -2
  133. package/dist/types/tools/streaming-output.d.ts +20 -1
  134. package/dist/types/tools/task.d.ts +2 -3
  135. package/dist/types/tools/write.d.ts +9 -2
  136. package/dist/types/tools/yield.d.ts +22 -0
  137. package/dist/types/tui.d.ts +36 -0
  138. package/dist/types/utils.d.ts +6 -0
  139. package/dist/types/vim.d.ts +19 -5
  140. package/dist/types/windows-input-mode.d.ts +33 -1
  141. package/package.json +13 -9
  142. package/src/active-terminal.d.ts +30 -0
  143. package/src/active-terminal.ts +80 -0
  144. package/src/app-keybindings.d.ts +7 -2
  145. package/src/app-keybindings.ts +7 -2
  146. package/src/apps/autoresearch-dashboard.ts +7 -3
  147. package/src/apps/cleanse-board.ts +2 -2
  148. package/src/apps/cleanse-picker.ts +1 -1
  149. package/src/apps/debug/log-viewer.ts +188 -72
  150. package/src/apps/debug/raw-sse-buffer.ts +8 -0
  151. package/src/apps/debug/raw-sse.ts +39 -5
  152. package/src/apps/git/diff-pane.ts +96 -23
  153. package/src/apps/git/git-tui.ts +23 -16
  154. package/src/apps/git/help.ts +29 -20
  155. package/src/apps/git/sidebar.ts +8 -3
  156. package/src/apps/if-bench-board.ts +2 -2
  157. package/src/apps/ps-top.ts +2 -2
  158. package/src/apps/setup-model-picker.ts +1 -1
  159. package/src/autocomplete.d.ts +5 -2
  160. package/src/autocomplete.ts +67 -43
  161. package/src/bracketed-paste.ts +10 -3
  162. package/src/charts/chart-plan.d.ts +674 -0
  163. package/src/charts/chart-plan.ts +5081 -0
  164. package/src/charts/chart-svg.d.ts +59 -0
  165. package/src/charts/chart-svg.ts +4657 -0
  166. package/src/charts/table-data.d.ts +175 -0
  167. package/src/charts/table-data.ts +1478 -0
  168. package/src/chat/advisor-message.ts +11 -0
  169. package/src/chat/assistant-message.d.ts +11 -1
  170. package/src/chat/assistant-message.ts +245 -54
  171. package/src/chat/chat-transcript-builder.d.ts +3 -0
  172. package/src/chat/chat-transcript-builder.ts +9 -3
  173. package/src/chat/compaction-summary-message.d.ts +1 -0
  174. package/src/chat/compaction-summary-message.ts +8 -0
  175. package/src/chat/execution-shared.d.ts +6 -5
  176. package/src/chat/execution-shared.ts +42 -25
  177. package/src/chat/fence-figure.d.ts +42 -0
  178. package/src/chat/fence-figure.ts +80 -0
  179. package/src/chat/figure-markdown.d.ts +42 -0
  180. package/src/chat/figure-markdown.ts +174 -0
  181. package/src/chat/messages.d.ts +1 -1
  182. package/src/chat/messages.ts +1 -1
  183. package/src/chat/read-tool-group.ts +6 -4
  184. package/src/chat/skill-message.ts +6 -0
  185. package/src/chat/svg-figure.d.ts +33 -0
  186. package/src/chat/svg-figure.ts +399 -0
  187. package/src/chat/svg-source.d.ts +49 -0
  188. package/src/chat/svg-source.ts +188 -0
  189. package/src/chat/table-chart.d.ts +89 -0
  190. package/src/chat/table-chart.ts +294 -0
  191. package/src/chat/tool-execution.d.ts +2 -0
  192. package/src/chat/tool-execution.ts +86 -7
  193. package/src/chat/user-message.d.ts +17 -4
  194. package/src/chat/user-message.ts +71 -8
  195. package/src/chrome/shared.ts +53 -0
  196. package/src/chrome/status-notice.ts +25 -7
  197. package/src/chrome/transcript-container.d.ts +6 -0
  198. package/src/chrome/transcript-container.ts +162 -19
  199. package/src/components/box.d.ts +1 -0
  200. package/src/components/box.ts +5 -0
  201. package/src/components/disclosure.d.ts +1 -0
  202. package/src/components/disclosure.ts +8 -0
  203. package/src/components/editor.d.ts +23 -5
  204. package/src/components/editor.ts +316 -47
  205. package/src/components/form.d.ts +1 -0
  206. package/src/components/form.ts +8 -0
  207. package/src/components/image.d.ts +26 -44
  208. package/src/components/image.ts +115 -152
  209. package/src/components/input.d.ts +2 -1
  210. package/src/components/input.ts +17 -7
  211. package/src/components/key-value-list.d.ts +1 -0
  212. package/src/components/key-value-list.ts +4 -0
  213. package/src/components/layout/row.d.ts +1 -0
  214. package/src/components/layout/row.ts +7 -0
  215. package/src/components/layout/stack.d.ts +1 -0
  216. package/src/components/layout/stack.ts +7 -0
  217. package/src/components/loader.d.ts +5 -6
  218. package/src/components/loader.ts +10 -17
  219. package/src/components/markdown.d.ts +47 -5
  220. package/src/components/markdown.ts +786 -303
  221. package/src/components/scroll-view.d.ts +1 -0
  222. package/src/components/scroll-view.ts +5 -0
  223. package/src/components/section.d.ts +1 -0
  224. package/src/components/section.ts +5 -0
  225. package/src/components/settings-list.ts +2 -0
  226. package/src/components/table.d.ts +1 -0
  227. package/src/components/table.ts +4 -0
  228. package/src/components/text.d.ts +1 -0
  229. package/src/components/text.ts +7 -0
  230. package/src/components/tree-view.d.ts +7 -0
  231. package/src/components/tree-view.ts +38 -8
  232. package/src/components/truncated-text.d.ts +1 -0
  233. package/src/components/truncated-text.ts +5 -0
  234. package/src/desktop-notify.ts +3 -2
  235. package/src/fuzzy.d.ts +29 -1
  236. package/src/fuzzy.ts +115 -30
  237. package/src/hotkeys-markdown.ts +9 -2
  238. package/src/key-hint-format.d.ts +9 -1
  239. package/src/key-hint-format.ts +26 -11
  240. package/src/keybinding-matchers.d.ts +3 -0
  241. package/src/keybinding-matchers.ts +6 -2
  242. package/src/keybindings.d.ts +1 -1
  243. package/src/keybindings.ts +1 -1
  244. package/src/kitty-graphics.d.ts +2 -2
  245. package/src/kitty-graphics.ts +11 -5
  246. package/src/loop-watchdog.d.ts +8 -7
  247. package/src/loop-watchdog.ts +18 -13
  248. package/src/multiplexers/cmux.d.ts +16 -0
  249. package/src/multiplexers/cmux.ts +29 -0
  250. package/src/multiplexers/herdr.d.ts +26 -0
  251. package/src/multiplexers/herdr.ts +64 -0
  252. package/src/multiplexers/notify.d.ts +13 -0
  253. package/src/multiplexers/notify.ts +24 -0
  254. package/src/multiplexers/orca.d.ts +12 -0
  255. package/src/multiplexers/orca.ts +16 -0
  256. package/src/multiplexers/screen.d.ts +9 -0
  257. package/src/multiplexers/screen.ts +15 -0
  258. package/src/multiplexers/tmux.d.ts +29 -0
  259. package/src/multiplexers/tmux.ts +40 -0
  260. package/src/multiplexers/types.d.ts +100 -0
  261. package/src/multiplexers/types.ts +110 -0
  262. package/src/multiplexers/wmux.d.ts +12 -0
  263. package/src/multiplexers/wmux.ts +16 -0
  264. package/src/multiplexers/zellij.d.ts +12 -0
  265. package/src/multiplexers/zellij.ts +24 -0
  266. package/src/native/apply.d.ts +4 -3
  267. package/src/native/apply.ts +4 -3
  268. package/src/native/backend.d.ts +5 -4
  269. package/src/native/backend.ts +199 -22
  270. package/src/native/blobs.d.ts +7 -3
  271. package/src/native/blobs.ts +47 -12
  272. package/src/native/encode.d.ts +8 -6
  273. package/src/native/encode.ts +76 -34
  274. package/src/native/node.d.ts +36 -5
  275. package/src/native/node.ts +31 -5
  276. package/src/native/overlay.d.ts +8 -3
  277. package/src/native/overlay.ts +17 -4
  278. package/src/native/reconcile.ts +16 -4
  279. package/src/native/settle.d.ts +4 -3
  280. package/src/native/settle.ts +4 -3
  281. package/src/overlays/agent-hub-projection.d.ts +6 -5
  282. package/src/overlays/agent-hub-projection.ts +124 -13
  283. package/src/overlays/agent-hub-types.d.ts +9 -0
  284. package/src/overlays/agent-hub-types.ts +6 -0
  285. package/src/overlays/agent-hub.ts +48 -29
  286. package/src/overlays/agent-transcript-viewer.ts +93 -23
  287. package/src/overlays/agents-hub.ts +28 -8
  288. package/src/overlays/annotation-overlay.ts +293 -90
  289. package/src/overlays/annotation-types.ts +2 -0
  290. package/src/overlays/ask-dialog.ts +10 -17
  291. package/src/overlays/btw-history-panel.ts +136 -39
  292. package/src/overlays/copy-selector.d.ts +1 -0
  293. package/src/overlays/copy-selector.ts +32 -8
  294. package/src/overlays/extensions/extension-dashboard.ts +4 -4
  295. package/src/overlays/extensions/state-manager.ts +52 -12
  296. package/src/overlays/history-search.ts +100 -7
  297. package/src/overlays/hook-selector.ts +12 -5
  298. package/src/overlays/hub-frame.ts +19 -1
  299. package/src/overlays/jobs-panel.ts +33 -52
  300. package/src/overlays/model-browser.ts +367 -122
  301. package/src/overlays/model-hub.ts +435 -59
  302. package/src/overlays/move-overlay.ts +28 -14
  303. package/src/overlays/oauth-selector.ts +54 -70
  304. package/src/overlays/pause-screen.ts +2 -2
  305. package/src/overlays/plan-review-overlay.ts +208 -70
  306. package/src/overlays/plugin-settings.ts +3 -3
  307. package/src/overlays/report-panel.ts +191 -0
  308. package/src/overlays/rewind-selector.ts +88 -17
  309. package/src/overlays/session-observer-registry.d.ts +2 -0
  310. package/src/overlays/session-observer-registry.ts +10 -2
  311. package/src/overlays/session-selector.ts +64 -26
  312. package/src/overlays/settings-defs.ts +5 -4
  313. package/src/overlays/settings-selector.ts +33 -8
  314. package/src/overlays/snapcompact-shape-preview.ts +2 -3
  315. package/src/overlays/stats-notice.ts +1 -1
  316. package/src/overlays/thinking-selector.ts +11 -10
  317. package/src/overlays/tree-selector.ts +41 -20
  318. package/src/overlays/usage-dashboard.ts +117 -58
  319. package/src/overlays/usage-display.ts +10 -4
  320. package/src/overlays/usage-row.ts +22 -8
  321. package/src/prompt/attachment-chips.ts +15 -11
  322. package/src/prompt/composer-attachments.ts +6 -4
  323. package/src/prompt/composer-cache.ts +7 -86
  324. package/src/prompt/composer.ts +37 -26
  325. package/src/prompt/custom-editor.ts +282 -105
  326. package/src/prompt/image-source.ts +2 -1
  327. package/src/prompt/interactive-context-helpers.ts +32 -18
  328. package/src/prompt/macos-spelling.ts +7 -0
  329. package/src/prompt/magic-keywords.ts +11 -2
  330. package/src/prompt/model-mention-autocomplete.ts +14 -14
  331. package/src/prompt/queued-messages.ts +6 -4
  332. package/src/prompt/tips.txt +13 -9
  333. package/src/prompt/welcome.ts +64 -46
  334. package/src/prompt/word-completion.ts +38 -5
  335. package/src/render/composite.d.ts +2 -0
  336. package/src/render/composite.ts +64 -0
  337. package/src/render/output-pane.d.ts +1 -0
  338. package/src/render/output-pane.ts +6 -0
  339. package/src/render/render-utils.d.ts +1 -0
  340. package/src/render/render-utils.ts +16 -1
  341. package/src/render/tool-card.d.ts +6 -0
  342. package/src/render/tool-card.ts +15 -0
  343. package/src/render/width-aware-text.d.ts +2 -0
  344. package/src/render/width-aware-text.ts +5 -0
  345. package/src/setup/scenes/model.ts +2 -1
  346. package/src/setup/scenes/types.ts +1 -0
  347. package/src/space-hold.d.ts +40 -25
  348. package/src/space-hold.ts +156 -52
  349. package/src/status-line/component.ts +292 -78
  350. package/src/status-line/context-usage.ts +21 -46
  351. package/src/status-line/host.ts +4 -1
  352. package/src/status-line/segments.ts +40 -22
  353. package/src/status-line/types.ts +15 -3
  354. package/src/terminal-capabilities.d.ts +41 -36
  355. package/src/terminal-capabilities.ts +137 -213
  356. package/src/terminal-multiplexer.d.ts +127 -14
  357. package/src/terminal-multiplexer.ts +112 -33
  358. package/src/terminal.d.ts +23 -16
  359. package/src/terminal.ts +203 -99
  360. package/src/theme/active-symbols.d.ts +1 -1
  361. package/src/theme/active-symbols.ts +1 -1
  362. package/src/theme/schema-validation.ts +1 -0
  363. package/src/theme/schema.d.ts +11 -2
  364. package/src/theme/schema.ts +14 -1
  365. package/src/theme/session-color.ts +1 -7
  366. package/src/theme/symbols.d.ts +1 -1
  367. package/src/theme/symbols.ts +11 -4
  368. package/src/theme/theme-class.d.ts +7 -0
  369. package/src/theme/theme-class.ts +26 -1
  370. package/src/theme/theme-schema.json +5 -1
  371. package/src/theme/theme.d.ts +1 -1
  372. package/src/theme/theme.ts +8 -4
  373. package/src/theme/tui-adapters.d.ts +3 -0
  374. package/src/theme/tui-adapters.ts +68 -0
  375. package/src/thinking.d.ts +1 -1
  376. package/src/thinking.ts +1 -1
  377. package/src/tmux.d.ts +11 -4
  378. package/src/tmux.ts +47 -11
  379. package/src/tools/ast-edit.ts +59 -35
  380. package/src/tools/ast-grep.ts +35 -16
  381. package/src/tools/bash.d.ts +7 -2
  382. package/src/tools/bash.ts +116 -47
  383. package/src/tools/daemon.d.ts +1 -1
  384. package/src/tools/daemon.ts +1 -1
  385. package/src/tools/default-renderer.ts +35 -19
  386. package/src/tools/edit.ts +142 -120
  387. package/src/tools/eval-format/index.ts +28 -2
  388. package/src/tools/eval-format/javascript.ts +7 -5
  389. package/src/tools/eval.d.ts +22 -3
  390. package/src/tools/eval.ts +364 -208
  391. package/src/tools/fetch.ts +5 -6
  392. package/src/tools/glob.d.ts +4 -0
  393. package/src/tools/glob.ts +33 -65
  394. package/src/tools/grep.ts +81 -48
  395. package/src/tools/index.ts +2 -0
  396. package/src/tools/lsp.ts +81 -59
  397. package/src/tools/mcp.ts +111 -68
  398. package/src/tools/native-view.d.ts +47 -0
  399. package/src/tools/native-view.ts +102 -1
  400. package/src/tools/output-meta.d.ts +11 -1
  401. package/src/tools/output-meta.ts +23 -3
  402. package/src/tools/read.ts +7 -5
  403. package/src/tools/renderer.d.ts +37 -2
  404. package/src/tools/renderer.ts +42 -2
  405. package/src/tools/streaming-output.d.ts +20 -1
  406. package/src/tools/streaming-output.ts +154 -50
  407. package/src/tools/task.d.ts +2 -3
  408. package/src/tools/task.ts +115 -62
  409. package/src/tools/todo.ts +119 -30
  410. package/src/tools/wait.ts +34 -24
  411. package/src/tools/web-search.ts +1 -1
  412. package/src/tools/write.d.ts +9 -2
  413. package/src/tools/write.ts +147 -95
  414. package/src/tools/yield.d.ts +22 -0
  415. package/src/tools/yield.ts +225 -0
  416. package/src/tui.d.ts +36 -0
  417. package/src/tui.ts +666 -217
  418. package/src/utils.d.ts +6 -0
  419. package/src/utils.ts +19 -0
  420. package/src/vim.d.ts +19 -5
  421. package/src/vim.ts +333 -18
  422. package/src/windows-input-mode.d.ts +33 -1
  423. package/src/windows-input-mode.ts +212 -6
@@ -65,6 +65,13 @@ const PICKER_KEY = "picker";
65
65
  /** Visible result rows; also the jump distance for PageUp/PageDown. */
66
66
  const MAX_VISIBLE = 10;
67
67
 
68
+ /**
69
+ * Quiet period after the last query edit before the synchronous storage
70
+ * search runs. Only applied when the host wires {@link HistorySearchComponent.setOnRequestRender},
71
+ * since the deferred results need a repaint to show up.
72
+ */
73
+ const SEARCH_DEBOUNCE_MS = 100;
74
+
68
75
  /** Split a query the same way `HistorySource` tokenizes it, so highlights align with matches. */
69
76
  function queryTokens(query: string): string[] {
70
77
  return query
@@ -106,6 +113,8 @@ class HistoryResultsList implements Component {
106
113
  #menu: MenuSelection<HistorySearchEntry>;
107
114
  #tokens: string[] = [];
108
115
  #maxVisible = MAX_VISIBLE;
116
+ /** Highlighted prompt text per entry, valid for one `(tokens, budget)` pair; reset on invalidate (theme). */
117
+ #highlightCache = new WeakMap<HistorySearchEntry, { tokens: string[]; budget: number; text: string }>();
109
118
 
110
119
  constructor(menu: MenuSelection<HistorySearchEntry>) {
111
120
  this.#menu = menu;
@@ -116,7 +125,17 @@ class HistoryResultsList implements Component {
116
125
  }
117
126
 
118
127
  invalidate(): void {
119
- // No cached state to invalidate currently
128
+ this.#highlightCache = new WeakMap();
129
+ }
130
+
131
+ /** Truncated, token-highlighted prompt of `entry` for `budget` cells. */
132
+ #highlightedPrompt(entry: HistorySearchEntry, budget: number): string {
133
+ const cached = this.#highlightCache.get(entry);
134
+ if (cached !== undefined && cached.tokens === this.#tokens && cached.budget === budget) return cached.text;
135
+ const normalized = entry.prompt.replace(/\s+/g, " ").trim();
136
+ const text = highlightTokens(truncateToWidth(normalized, budget), this.#tokens);
137
+ this.#highlightCache.set(entry, { tokens: this.#tokens, budget, text });
138
+ return text;
120
139
  }
121
140
 
122
141
  render(width: number): readonly string[] {
@@ -151,9 +170,7 @@ class HistoryResultsList implements Component {
151
170
  const showTime = rowWidth >= gutterWidth + 12 + timeWidth;
152
171
 
153
172
  const promptBudget = Math.max(4, rowWidth - gutterWidth - (showTime ? timeWidth + 1 : 0));
154
- const normalized = entry.prompt.replace(/\s+/g, " ").trim();
155
- const plain = truncateToWidth(normalized, promptBudget);
156
- const highlighted = highlightTokens(plain, this.#tokens);
173
+ const highlighted = this.#highlightedPrompt(entry, promptBudget);
157
174
 
158
175
  const cursor = isSelected ? theme.fg("accent", cursorSymbol) : padding(gutterWidth);
159
176
  let line = cursor + (isSelected ? theme.bold(highlighted) : highlighted);
@@ -186,12 +203,22 @@ export class HistorySearchComponent extends OverlayPanel {
186
203
  #nativeHints: NativeNode | undefined;
187
204
  #nativeMemo: HistoryNativeMemo | undefined;
188
205
  #pickerItems: { items: readonly HistorySearchEntry[]; rows: readonly TspPickerItem[] } | undefined;
206
+ /** Trimmed query the current results were fetched for; `undefined` before the first fetch. */
207
+ #resultsQuery: string | undefined;
208
+ #searchTimer: NodeJS.Timeout | undefined;
209
+ #onRequestRender?: () => void;
189
210
 
190
211
  constructor(historyStorage: HistorySource, onSelect: (prompt: string) => void, onCancel: () => void) {
191
212
  super("History", "zeta.overlay.history");
192
213
  this.#historyStorage = historyStorage;
193
- this.#onSelect = onSelect;
194
- this.#onCancel = onCancel;
214
+ this.#onSelect = prompt => {
215
+ this.#cancelPendingSearch();
216
+ onSelect(prompt);
217
+ };
218
+ this.#onCancel = () => {
219
+ this.#cancelPendingSearch();
220
+ onCancel();
221
+ };
195
222
 
196
223
  this.#menu = new MenuSelection<HistorySearchEntry>([], {
197
224
  getKey: entry => `${entry.created_at}:${entry.prompt}`,
@@ -199,6 +226,7 @@ export class HistorySearchComponent extends OverlayPanel {
199
226
  });
200
227
  this.#searchInput = new Input();
201
228
  this.#searchInput.onSubmit = () => {
229
+ this.#flushPendingSearch();
202
230
  const selected = this.#menu.selectedItem;
203
231
  if (selected) {
204
232
  this.#onSelect(selected.prompt);
@@ -225,38 +253,59 @@ export class HistorySearchComponent extends OverlayPanel {
225
253
  this.#updateResults();
226
254
  }
227
255
 
256
+ /**
257
+ * Repaint hook for debounced result updates. Once set, query edits search
258
+ * storage after a {@link SEARCH_DEBOUNCE_MS} quiet period instead of on
259
+ * every key; without it every edit searches synchronously.
260
+ */
261
+ setOnRequestRender(callback: () => void): void {
262
+ this.#onRequestRender = callback;
263
+ }
264
+
265
+ override dispose(): void {
266
+ this.#cancelPendingSearch();
267
+ super.dispose();
268
+ }
269
+
228
270
  handleInput(keyData: string): void {
229
271
  if (matchesSelectUp(keyData)) {
272
+ this.#flushPendingSearch();
230
273
  this.#menu.move(-1, false);
231
274
  return;
232
275
  }
233
276
 
234
277
  if (matchesSelectDown(keyData)) {
278
+ this.#flushPendingSearch();
235
279
  this.#menu.move(1, false);
236
280
  return;
237
281
  }
238
282
 
239
283
  if (matchesSelectPageUp(keyData)) {
284
+ this.#flushPendingSearch();
240
285
  this.#menu.move(-MAX_VISIBLE, false);
241
286
  return;
242
287
  }
243
288
 
244
289
  if (matchesSelectPageDown(keyData)) {
290
+ this.#flushPendingSearch();
245
291
  this.#menu.move(MAX_VISIBLE, false);
246
292
  return;
247
293
  }
248
294
 
249
295
  if (matchesKey(keyData, "home")) {
296
+ this.#flushPendingSearch();
250
297
  this.#menu.moveToBoundary("first");
251
298
  return;
252
299
  }
253
300
 
254
301
  if (matchesKey(keyData, "end")) {
302
+ this.#flushPendingSearch();
255
303
  this.#menu.moveToBoundary("last");
256
304
  return;
257
305
  }
258
306
 
259
307
  if (matchesKey(keyData, "enter") || matchesKey(keyData, "return") || keyData === "\n") {
308
+ this.#flushPendingSearch();
260
309
  const selected = this.#menu.selectedItem;
261
310
  if (selected) {
262
311
  this.#onSelect(selected.prompt);
@@ -270,7 +319,7 @@ export class HistorySearchComponent extends OverlayPanel {
270
319
  }
271
320
 
272
321
  this.#searchInput.handleInput(keyData);
273
- this.#updateResults();
322
+ this.#scheduleResults();
274
323
  }
275
324
 
276
325
  /**
@@ -372,6 +421,9 @@ export class HistorySearchComponent extends OverlayPanel {
372
421
  * Picker: a row click highlights, a second click or `Insert` inserts it
373
422
  * (Enter), `Close` cancels (Esc), `Clear search` empties the query.
374
423
  * List: picking a result does what highlighting it and pressing Enter does.
424
+ * A row picked while a debounced search is pending belongs to the previous
425
+ * query: results are refreshed first and the pick only lands if that entry
426
+ * is still among them.
375
427
  */
376
428
  handleNativeEvent(event: NativeUiEvent): void {
377
429
  const ev = pickerEvent(event, PICKER_KEY);
@@ -385,6 +437,7 @@ export class HistorySearchComponent extends OverlayPanel {
385
437
  }
386
438
  return;
387
439
  }
440
+ this.#flushPendingSearch();
388
441
  const index = this.#menu.visibleItems.findIndex(entry => nativeEntryKey(entry) === ev.item);
389
442
  if (index < 0) return;
390
443
  this.#menu.setSelectedIndex(index);
@@ -392,6 +445,7 @@ export class HistorySearchComponent extends OverlayPanel {
392
445
  return;
393
446
  }
394
447
  if ((event.type !== "select" && event.type !== "activate") || event.key !== "list") return;
448
+ this.#flushPendingSearch();
395
449
  const index = this.#menu.visibleItems.findIndex(entry => nativeEntryKey(entry) === event.item);
396
450
  const target = this.#menu.visibleItems[index];
397
451
  if (!target) return;
@@ -399,8 +453,47 @@ export class HistorySearchComponent extends OverlayPanel {
399
453
  this.#onSelect(target.prompt);
400
454
  }
401
455
 
456
+ /**
457
+ * Refresh results after a query edit: no-op when the trimmed query is
458
+ * unchanged (cursor moves, trailing spaces), immediate for the empty query
459
+ * or when no repaint hook is wired, debounced otherwise.
460
+ */
461
+ #scheduleResults(): void {
462
+ const query = this.#searchInput.getValue().trim();
463
+ if (query === this.#resultsQuery) {
464
+ this.#cancelPendingSearch();
465
+ return;
466
+ }
467
+ const requestRender = this.#onRequestRender;
468
+ if (!query || !requestRender) {
469
+ this.#updateResults();
470
+ return;
471
+ }
472
+ this.#cancelPendingSearch();
473
+ this.#searchTimer = setTimeout(() => {
474
+ this.#searchTimer = undefined;
475
+ this.#updateResults();
476
+ requestRender();
477
+ }, SEARCH_DEBOUNCE_MS);
478
+ }
479
+
480
+ /** Run a pending debounced search now, so selection acts on the current query's results. */
481
+ #flushPendingSearch(): void {
482
+ if (this.#searchTimer === undefined) return;
483
+ this.#cancelPendingSearch();
484
+ this.#updateResults();
485
+ }
486
+
487
+ #cancelPendingSearch(): void {
488
+ if (this.#searchTimer === undefined) return;
489
+ clearTimeout(this.#searchTimer);
490
+ this.#searchTimer = undefined;
491
+ }
492
+
402
493
  #updateResults(): void {
494
+ this.#cancelPendingSearch();
403
495
  const query = this.#searchInput.getValue().trim();
496
+ this.#resultsQuery = query;
404
497
  const results = query
405
498
  ? this.#historyStorage.search(query, this.#resultLimit)
406
499
  : this.#historyStorage.getRecent(this.#resultLimit);
@@ -94,6 +94,10 @@ export interface HookSelectorOptions {
94
94
  /** Number of leading options (original order) that receive a selection
95
95
  * marker. Defaults to every option when {@link selectionMarker} is set. */
96
96
  markableCount?: number;
97
+ /** Describe as a card in the dock (the composer slot) instead of a picker
98
+ * sheet, so dock content above it (e.g. a `/omfg` candidate rule) stays
99
+ * visible and the transcript stays scrollable on native surfaces. */
100
+ inline?: boolean;
97
101
  }
98
102
 
99
103
  export interface HookSelectorOption {
@@ -210,6 +214,7 @@ export class HookSelectorComponent extends OverlayPanel {
210
214
  #sliderComponent: Text | undefined;
211
215
  #lastRenderWidth: number | undefined;
212
216
  readonly #detailLines: readonly string[];
217
+ readonly #inline: boolean;
213
218
  readonly #helpText: string | undefined;
214
219
  /** Described option rows by original index; `marker` is the radio state baked into the label. */
215
220
  readonly #nativeItems = new Map<number, { marker: boolean; node: NativeNode }>();
@@ -264,6 +269,7 @@ export class HookSelectorComponent extends OverlayPanel {
264
269
  this.#baseTitle = this.title;
265
270
  this.#detailLines = title.split(/\r?\n/).slice(1);
266
271
  this.#helpText = opts?.helpText;
272
+ this.#inline = opts?.inline ?? false;
267
273
  this.#onLeftCallback = opts?.onLeft;
268
274
  this.#onRightCallback = opts?.onRight;
269
275
  this.#onExternalEditorCallback = opts?.onExternalEditor;
@@ -726,13 +732,14 @@ export class HookSelectorComponent extends OverlayPanel {
726
732
  }
727
733
 
728
734
  /**
729
- * A plain option list is a picker sheet. Otherwise a card headed by the
730
- * title (plus the countdown `elapsed` when a timeout runs), the extra title
731
- * lines, the slider as `tabs`, the options as a `list` keyed by original
732
- * option index, the search query while typing, and the key hints.
735
+ * A plain option list is a picker sheet. Otherwise (inline, slider, or
736
+ * countdown) a card headed by the title (plus the countdown `elapsed` when a
737
+ * timeout runs), the extra title lines, the slider as `tabs`, the options as
738
+ * a `list` keyed by original option index, the search query while typing,
739
+ * and the key hints.
733
740
  */
734
741
  override describe(cx: DescribeContext): NativeNode {
735
- if (cx.supports("picker") && !this.#slider && !this.#countdown) return this.#describePicker();
742
+ if (cx.supports("picker") && !this.#inline && !this.#slider && !this.#countdown) return this.#describePicker();
736
743
  const items = this.#menu.visibleItems;
737
744
  const selected = this.#menu.selectedKey;
738
745
  const query = this.#menu.query;
@@ -149,6 +149,10 @@ export class HubFrame {
149
149
  readonly #stack: Stack;
150
150
  readonly #title: string;
151
151
  readonly #sidebarBounds: { min: number; max: number };
152
+ /** Whether narrow layouts may reduce the body floor to keep the sidebar usable. */
153
+ readonly #preserveSidebar: boolean;
154
+ /** Preferred body floor, reduced only as needed to retain sidebar navigation. */
155
+ readonly #bodyMinWidth: number;
152
156
 
153
157
  /** Compose hub-specific sidebar and body renderers into a persistent frame. */
154
158
  constructor(
@@ -156,9 +160,12 @@ export class HubFrame {
156
160
  sidebarBounds: { min: number; max: number },
157
161
  renderSidebar: (width: number, rows: number) => string[],
158
162
  renderBody: (width: number, height: number | undefined) => readonly string[],
163
+ options: { bodyMinWidth?: number; preserveSidebar?: boolean } = {},
159
164
  ) {
160
165
  this.#title = title;
161
166
  this.#sidebarBounds = sidebarBounds;
167
+ this.#preserveSidebar = options.preserveSidebar ?? false;
168
+ this.#bodyMinWidth = options.bodyMinWidth ?? 0;
162
169
  this.#split = new SplitPane({
163
170
  left: (width, height) => {
164
171
  const rows = Math.max(0, Math.floor(height ?? 10));
@@ -167,6 +174,7 @@ export class HubFrame {
167
174
  return lines.slice(0, rows);
168
175
  },
169
176
  right: renderBody,
177
+ rightMinWidth: this.#bodyMinWidth,
170
178
  prefix: () => `${theme.fg("border", theme.boxRound.vertical)} `,
171
179
  divider: () => ` ${theme.fg("border", theme.boxRound.vertical)} `,
172
180
  suffix: () => ` ${theme.fg("border", theme.boxRound.vertical)}`,
@@ -330,7 +338,17 @@ export class HubFrame {
330
338
  /** Paint a complete fullscreen hub with its title, width bounds, and contextual footer. */
331
339
  render(width: number, height: number, entries: readonly SidebarEntry<string>[], footer: string): readonly string[] {
332
340
  const contentRows = Math.max(10, height - 4);
333
- this.#split.setLeftSize({ fixed: this.sidebarWidth(entries) });
341
+ const sidebarWidth = this.sidebarWidth(entries);
342
+ this.#split.setLeftSize({
343
+ fixed: sidebarWidth,
344
+ min: this.#preserveSidebar ? this.#sidebarBounds.min : undefined,
345
+ });
346
+ if (this.#preserveSidebar && this.#bodyMinWidth > 0) {
347
+ const geometry = this.#split.measure(width);
348
+ const splitWidth = (geometry.left?.width ?? 0) + (geometry.right?.width ?? 0);
349
+ const rightMinWidth = Math.max(0, Math.min(this.#bodyMinWidth, splitWidth - this.#sidebarBounds.min));
350
+ this.#split.setRightMinWidth(rightMinWidth);
351
+ }
334
352
  const leftWidth = this.#split.measure(width).left?.width ?? 0;
335
353
  this.#top.setLines([topBorderSplit(width, this.#title, leftWidth)]);
336
354
  this.#divider.setLines([dividerSplit(width, leftWidth)]);
@@ -1,14 +1,13 @@
1
1
  /**
2
- * The async background jobs of a session, twice: {@link JobsPanel} is the
3
- * `/jobs` transcript block (ANSI keeps the caller's text report; natively one
4
- * frame), {@link JobsSheet} the dismissable sheet the native jobs pill opens.
5
- * The panel draws task jobs as `agent` nodes and the others as a status dot,
6
- * the one-line label and a live `elapsed`; the sheet lists every job and
7
- * inspects the selected one (command, cwd, live pids, exit code, output tail).
2
+ * The async background jobs of a session as {@link JobsSheet}: the dismissable
3
+ * sheet the native jobs pill and `/jobs` open. It draws task jobs as `agent`
4
+ * nodes and the others as a status dot, the one-line label and a live
5
+ * `elapsed`, lists every job and inspects the selected one (command, cwd, live
6
+ * pids, exit code, output tail).
8
7
  */
9
8
  import type { TspAgentProps, TspSpan } from "@linxiraos/pi-wire";
10
9
  import { formatDuration } from "@linxiraos/pi-utils";
11
- import { type Component, Container } from "../tui";
10
+ import type { Component } from "../tui";
12
11
  import { matchesSelectCancel, matchesSelectDown, matchesSelectUp } from "../keybinding-matchers";
13
12
  import { matchesKey } from "../keys";
14
13
  import { truncateToWidth } from "../utils";
@@ -92,31 +91,6 @@ const DOT: Record<JobsPanelJob["status"], TspSpan> = {
92
91
  /** Output tail rows the terminal fallback shows under the selected job. */
93
92
  const FALLBACK_TAIL_LINES = 8;
94
93
 
95
- /** The `/jobs` block: `ansi` renders in the terminal, the snapshot describes the native frame. */
96
- export class JobsPanel extends Container {
97
- readonly #snapshot: JobsPanelSnapshot;
98
- readonly #nowMs: number;
99
- #native: { agent: boolean; node: NativeNode } | undefined;
100
-
101
- constructor(snapshot: JobsPanelSnapshot, nowMs: number, ansi: readonly Component[]) {
102
- super();
103
- this.#snapshot = snapshot;
104
- this.#nowMs = nowMs;
105
- for (const child of ansi) this.addChild(child);
106
- }
107
-
108
- override describe(cx: DescribeContext): NativeNode {
109
- const agent = cx.supports("agent");
110
- if (this.#native?.agent === agent) return this.#native.node;
111
- const head: TspSpan[] = [span("Background jobs", "strong")];
112
- const running = this.#snapshot.running.length;
113
- if (running > 0) head.push(span(` · ${running} running`, "muted"));
114
- const described = card({ role: "zeta.jobs", head }, describeJobs(this.#snapshot, this.#nowMs, agent));
115
- this.#native = { agent, node: described };
116
- return described;
117
- }
118
- }
119
-
120
94
  /**
121
95
  * The jobs pill's sheet: a centred `lg` glass sheet titled Background jobs.
122
96
  * A selectable list of every job (running first) sits over the selected
@@ -136,6 +110,8 @@ export class JobsSheet implements Component {
136
110
  readonly #source: JobsSheetSource;
137
111
  #selectedId: string | undefined;
138
112
  #native: { key: string; output: string | undefined; node: NativeNode } | undefined;
113
+ /** Fallback output tail, reused while the selected job's output is unchanged. */
114
+ #tail: { id: string; output: string; lines: readonly string[] } | undefined;
139
115
 
140
116
  constructor(source: JobsSheetSource) {
141
117
  this.#source = source;
@@ -203,8 +179,9 @@ export class JobsSheet implements Component {
203
179
  detail.artifactId && `artifact://${detail.artifactId}`,
204
180
  ]);
205
181
  if (facts.length > 0) lines.push(truncateToWidth(` ${facts.join(" · ")}`, width));
206
- const tail = (detail.output ?? "").trimEnd().split("\n").slice(-FALLBACK_TAIL_LINES);
207
- for (const line of tail) if (line) lines.push(truncateToWidth(` ${line}`, width));
182
+ for (const line of this.#tailLines(selected.id, detail.output ?? "")) {
183
+ if (line) lines.push(truncateToWidth(` ${line}`, width));
184
+ }
208
185
  }
209
186
  return lines;
210
187
  }
@@ -236,6 +213,14 @@ export class JobsSheet implements Component {
236
213
  return { jobs, selected };
237
214
  }
238
215
 
216
+ #tailLines(id: string, output: string): readonly string[] {
217
+ const cached = this.#tail;
218
+ if (cached?.id === id && cached.output === output) return cached.lines;
219
+ const lines = tailLines(output, FALLBACK_TAIL_LINES);
220
+ this.#tail = { id, output, lines };
221
+ return lines;
222
+ }
223
+
239
224
  #move(delta: number): void {
240
225
  const { jobs, selected } = this.#current();
241
226
  if (!selected) return;
@@ -254,25 +239,21 @@ function jobAge(job: JobsPanelJob, nowMs: number): number {
254
239
  return Math.max(0, (job.endTime ?? nowMs) - job.startTime);
255
240
  }
256
241
 
257
- /** The body the `/jobs` panel draws: running rows, then a Recent section; an empty note when there are none. */
258
- function describeJobs(snapshot: JobsPanelSnapshot, nowMs: number, agent: boolean): NativeChild[] {
259
- const { running, recent } = snapshot;
260
- const children: NativeChild[] = [];
261
- if (running.length === 0 && recent.length === 0) {
262
- children.push(node("text", { text: "No background jobs", role: "zeta.jobs.empty" }, undefined, "empty"));
263
- }
264
- for (const job of running) children.push(describeJob(job, nowMs, agent));
265
- if (recent.length > 0) {
266
- children.push(
267
- node(
268
- "section",
269
- { head: [span("Recent", "muted")] },
270
- recent.map(job => describeJob(job, nowMs, agent)),
271
- "recent",
272
- ),
273
- );
242
+ /**
243
+ * The last `count` pieces of `text.trimEnd().split("\n")`, found by scanning
244
+ * back from the end so a long running output is never split as a whole.
245
+ */
246
+ function tailLines(text: string, count: number): string[] {
247
+ const trimmed = text.trimEnd();
248
+ const lines: string[] = [];
249
+ let end = trimmed.length;
250
+ while (lines.length < count) {
251
+ const newline = end > 0 ? trimmed.lastIndexOf("\n", end - 1) : -1;
252
+ lines.push(trimmed.slice(newline + 1, end));
253
+ if (newline < 0) break;
254
+ end = newline;
274
255
  }
275
- return children;
256
+ return lines.reverse();
276
257
  }
277
258
 
278
259
  /** A task job as an `agent` node when the terminal draws them, else a one-line dot row. */