@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
@@ -2,8 +2,10 @@
2
2
  * Content-addressed binary blobs (images) for `image` nodes.
3
3
  *
4
4
  * `describe()` registers the bytes and puts the returned id in `image.p.blob`;
5
- * the native backend uploads each referenced blob once per surface with verb
6
- * `b` before the frame that first references it.
5
+ * the native backend delivers each referenced blob once per terminal
6
+ * connection (asking the terminal first which it holds, or through its blob
7
+ * cache), else uploads it with verb `b` before the frame that first
8
+ * references it.
7
9
  */
8
10
  import type { TspProps } from "@linxiraos/pi-wire";
9
11
  import { getImageDimensions } from "../terminal-capabilities";
@@ -16,7 +18,13 @@ export interface NativeBlob {
16
18
  readonly bytes: Uint8Array;
17
19
  }
18
20
 
19
- const blobs = new Map<string, NativeBlob>();
21
+ const blobs = new Map<string, WeakRef<NativeBlob>>();
22
+ const registeredBlobs = new Map<string, NativeBlob>();
23
+ const releasedBlobs = new FinalizationRegistry<{ id: string; reference: WeakRef<NativeBlob> }>(({ id, reference }) => {
24
+ if (blobs.get(id) === reference) blobs.delete(id);
25
+ });
26
+ // Props spreads preserve ownership; wire serialization omits symbol keys.
27
+ const kBlob = Symbol("native.blob");
20
28
  // Registration usually repeats with the same bytes object on every describe;
21
29
  // the tag skips rehashing it.
22
30
  const kBlobId = Symbol("native.blobId");
@@ -25,19 +33,42 @@ interface BlobTagged {
25
33
  [kBlobId]?: string;
26
34
  }
27
35
 
28
- /** Register `bytes` and return their content address (sha256 hex) for `image.p.blob`. */
29
- export function registerNativeBlob(bytes: Uint8Array, mime: string): string {
36
+ function getOrCreateBlob(bytes: Uint8Array, mime: string): NativeBlob {
30
37
  const known = (bytes as BlobTagged)[kBlobId];
31
- if (known !== undefined) return known;
32
- const id = new Bun.CryptoHasher("sha256").update(bytes).digest("hex");
38
+ const id = known ?? new Bun.CryptoHasher("sha256").update(bytes).digest("hex");
33
39
  (bytes as BlobTagged)[kBlobId] = id;
34
- if (!blobs.has(id)) blobs.set(id, { id, mime, bytes });
35
- return id;
40
+ let blob = blobs.get(id)?.deref();
41
+ if (!blob) {
42
+ blob = { id, mime, bytes };
43
+ const reference = new WeakRef(blob);
44
+ blobs.set(id, reference);
45
+ releasedBlobs.register(blob, { id, reference });
46
+ }
47
+ return blob;
48
+ }
49
+
50
+ /** Register bytes for process-lifetime, id-only use. Prefer {@link nativeImageNode} for owned images. */
51
+ export function registerNativeBlob(bytes: Uint8Array, mime: string): string {
52
+ const blob = getOrCreateBlob(bytes, mime);
53
+ registeredBlobs.set(blob.id, blob);
54
+ return blob.id;
36
55
  }
37
56
 
38
57
  /** A registered blob by id. */
39
58
  export function getNativeBlob(id: string): NativeBlob | undefined {
40
- return blobs.get(id);
59
+ return blobs.get(id)?.deref();
60
+ }
61
+
62
+ /** An image whose props own its bytes, including while hidden, unmounted, or awaiting upload. */
63
+ export function nativeImageNode(
64
+ bytes: Uint8Array,
65
+ mime: string,
66
+ p?: Omit<TspProps<"image">, "blob" | "builtin">,
67
+ key?: string,
68
+ ): NativeNode {
69
+ const blob = getOrCreateBlob(bytes, mime);
70
+ const props = { ...p, blob: blob.id, [kBlob]: blob };
71
+ return node("image", props, undefined, key);
41
72
  }
42
73
 
43
74
  /**
@@ -51,9 +82,13 @@ export function base64ImageNode(
51
82
  p?: Omit<TspProps<"image">, "blob" | "builtin" | "w" | "h">,
52
83
  key?: string,
53
84
  ): NativeNode {
54
- const blob = registerNativeBlob(Buffer.from(data, "base64"), mimeType);
55
85
  const size = getImageDimensions(data, mimeType);
56
- return node("image", size ? { ...p, blob, w: size.widthPx, h: size.heightPx } : { ...p, blob }, undefined, key);
86
+ return nativeImageNode(
87
+ Buffer.from(data, "base64"),
88
+ mimeType,
89
+ size ? { ...p, w: size.widthPx, h: size.heightPx } : p,
90
+ key,
91
+ );
57
92
  }
58
93
 
59
94
  /** `image` nodes for base64 payloads, one per slot key, rebuilt only when the slot's payload changes. */
@@ -15,19 +15,21 @@ export type TspIncoming = {
15
15
  };
16
16
  /** Message parameters (`k=v`, ASCII, never containing `;`). */
17
17
  export type TspParams = Readonly<Record<string, string | number>>;
18
- /** Split `body` into pieces of at most `limit` UTF-8 bytes, never inside a code point. */
19
- export declare function splitUtf8(body: string, limit: number): string[];
20
18
  /**
21
- * Encode one logical message, chunked when `body` exceeds `limit` UTF-8 bytes.
22
- * Returns the complete byte string to write (all chunks, in order).
19
+ * Encode one logical message, chunked when `body` exceeds `limit` UTF-8 bytes:
20
+ * the first chunk carries `params`, every chunk `c=<id>` and all but the last
21
+ * `m=1`. Returns the complete byte string to write (all chunks, in order).
23
22
  */
24
23
  export declare function encodeTspMessage(verb: TspVerb, body: string, params?: TspParams, limit?: number): string;
25
24
  /** Encode a JSON message body. */
26
25
  export declare function encodeTspJson(verb: TspVerb, value: unknown, params?: TspParams, limit?: number): string;
27
26
  /**
28
27
  * The `hello` query; callers follow it with a DA1 sentinel. `features: ["edit"]`
29
- * tells the terminal that zeta applies its `edit` events (TSP §8.5), so it may keep a
30
- * native selection in zeta's editors; without it, every key stays zeta's.
28
+ #1: * tells the terminal that zeta applies its `edit` events (Tern SDK,
29
+ * `protocol/input.md`), so it may keep a native selection in zeta's editors;
30
+ * without it, every key stays zeta's. `"undo"` says zeta applies `undo` events,
31
+ * so the terminal may turn ⌃Z in a field into one.
32
+ * `"send"` accepts an explicit prompt for a live composer without simulating keys.
31
33
  */
32
34
  export declare function encodeTspHelloQuery(version?: string): string;
33
35
  /** One decoded APC message: verb, parameters and raw body. */
@@ -6,7 +6,9 @@
6
6
  * negotiated `apc` limit is split across messages with the same verb, tagged
7
7
  * `c=<chunk-id>`, with `m=1` on every chunk but the last; the receiver joins
8
8
  * the bodies byte-wise. Chunks split on code-point boundaries, so every chunk
9
- * is valid UTF-8 on its own and the joined bytes equal the original body.
9
+ * is valid UTF-8 on its own and the joined bytes equal the original body, and
10
+ * never where the next chunk would lead with a `key=value;` segment the
11
+ * receiver would read as a parameter (Tern's `tsp_chunks`).
10
12
  */
11
13
  import { isRecord } from "@linxiraos/pi-utils/type-guards";
12
14
  import {
@@ -34,36 +36,58 @@ export type TspParams = Readonly<Record<string, string | number>>;
34
36
 
35
37
  let nextChunkId = 1;
36
38
 
37
- /** UTF-8 byte length of one UTF-16 code unit sequence starting at `i`, and its unit count. */
38
- function codePointBytes(text: string, i: number): { bytes: number; units: number } {
39
- const c = text.charCodeAt(i);
40
- if (c < 0x80) return { bytes: 1, units: 1 };
41
- if (c < 0x800) return { bytes: 2, units: 1 };
42
- if (c >= 0xd800 && c <= 0xdbff && i + 1 < text.length) {
43
- const next = text.charCodeAt(i + 1);
44
- if (next >= 0xdc00 && next <= 0xdfff) return { bytes: 4, units: 2 };
39
+ /** Whether `bytes` from `at` leads with a `key=value;` segment, which a receiver reads as one more parameter. */
40
+ function leadsWithParameter(bytes: Uint8Array, at: number): boolean {
41
+ let i = at;
42
+ // Key bytes: `[A-Za-z0-9_-]`.
43
+ for (; i < bytes.length; i++) {
44
+ const b = bytes[i]!;
45
+ if (
46
+ !((b >= 0x30 && b <= 0x39) || (b >= 0x41 && b <= 0x5a) || (b >= 0x61 && b <= 0x7a) || b === 0x5f || b === 0x2d)
47
+ )
48
+ break;
45
49
  }
46
- return { bytes: 3, units: 1 };
50
+ if (i === at || bytes[i] !== 0x3d) return false;
51
+ i++;
52
+ // Value bytes: printable ASCII other than `;`.
53
+ while (i < bytes.length && bytes[i]! >= 0x21 && bytes[i]! <= 0x7e && bytes[i] !== 0x3b) i++;
54
+ return bytes[i] === 0x3b;
47
55
  }
48
56
 
49
- /** Split `body` into pieces of at most `limit` UTF-8 bytes, never inside a code point. */
50
- export function splitUtf8(body: string, limit: number): string[] {
51
- const max = Math.max(4, Math.trunc(limit));
57
+ /**
58
+ * Where the chunk of `bytes` starting at `start` ends: the safe cut nearest
59
+ * below `start + limit` (above `start`), else the nearest above it, else the
60
+ * end. A cut is safe on a UTF-8 character boundary where the rest doesn't
61
+ * lead with a parameter-shaped segment.
62
+ */
63
+ function chunkEnd(bytes: Uint8Array, start: number, limit: number): number {
64
+ const target = start + limit;
65
+ if (target >= bytes.length) return bytes.length;
66
+ const safe = (at: number): boolean => (bytes[at]! & 0xc0) !== 0x80 && !leadsWithParameter(bytes, at);
67
+ for (let at = target; at > start; at--) if (safe(at)) return at;
68
+ for (let at = target + 1; at < bytes.length; at++) if (safe(at)) return at;
69
+ return bytes.length;
70
+ }
71
+
72
+ /**
73
+ * Chunk bodies for `body` of `byteLength` UTF-8 bytes, cut as Tern's
74
+ * `tsp_chunks` cuts. Pure ASCII without `;` (every base64 blob) has no
75
+ * parameter-shaped segment and no multibyte character, so it is cut every
76
+ * `limit` characters.
77
+ */
78
+ function chunkBodies(body: string, byteLength: number, limit: number): string[] {
79
+ const max = Math.max(1, Math.trunc(limit));
52
80
  const pieces: string[] = [];
53
- let start = 0;
54
- let bytes = 0;
55
- let i = 0;
56
- while (i < body.length) {
57
- const step = codePointBytes(body, i);
58
- if (bytes + step.bytes > max) {
59
- pieces.push(body.slice(start, i));
60
- start = i;
61
- bytes = 0;
62
- }
63
- bytes += step.bytes;
64
- i += step.units;
81
+ if (byteLength === body.length && !body.includes(";")) {
82
+ for (let at = 0; at < body.length; at += max) pieces.push(body.slice(at, at + max));
83
+ return pieces;
84
+ }
85
+ const bytes = Buffer.from(body, "utf8");
86
+ for (let start = 0; start < bytes.length;) {
87
+ const end = chunkEnd(bytes, start, max);
88
+ pieces.push(bytes.toString("utf8", start, end));
89
+ start = end;
65
90
  }
66
- pieces.push(body.slice(start));
67
91
  return pieces;
68
92
  }
69
93
 
@@ -79,8 +103,9 @@ function encodeParams(params: TspParams | undefined): string {
79
103
  }
80
104
 
81
105
  /**
82
- * Encode one logical message, chunked when `body` exceeds `limit` UTF-8 bytes.
83
- * Returns the complete byte string to write (all chunks, in order).
106
+ * Encode one logical message, chunked when `body` exceeds `limit` UTF-8 bytes:
107
+ * the first chunk carries `params`, every chunk `c=<id>` and all but the last
108
+ * `m=1`. Returns the complete byte string to write (all chunks, in order).
84
109
  */
85
110
  export function encodeTspMessage(
86
111
  verb: TspVerb,
@@ -90,13 +115,15 @@ export function encodeTspMessage(
90
115
  ): string {
91
116
  const base = encodeParams(params);
92
117
  // Fast path: ASCII-length bound first, exact byte count only near the limit.
93
- if (body.length * 3 <= limit || Buffer.byteLength(body, "utf8") <= limit) return frame(verb, base, body);
118
+ if (body.length * 3 <= limit) return frame(verb, base, body);
119
+ const byteLength = Buffer.byteLength(body, "utf8");
120
+ if (byteLength <= limit) return frame(verb, base, body);
94
121
  const chunkId = (nextChunkId++).toString(36);
95
- const pieces = splitUtf8(body, limit);
122
+ const pieces = chunkBodies(body, byteLength, limit);
96
123
  let out = "";
97
124
  for (let i = 0; i < pieces.length; i++) {
98
125
  const more = i < pieces.length - 1 ? ";m=1" : "";
99
- out += frame(verb, `${base};c=${chunkId}${more}`, pieces[i]!);
126
+ out += frame(verb, `${i === 0 ? base : ""};c=${chunkId}${more}`, pieces[i]!);
100
127
  }
101
128
  return out;
102
129
  }
@@ -108,11 +135,20 @@ export function encodeTspJson(verb: TspVerb, value: unknown, params?: TspParams,
108
135
 
109
136
  /**
110
137
  * The `hello` query; callers follow it with a DA1 sentinel. `features: ["edit"]`
111
- * tells the terminal that zeta applies its `edit` events (TSP §8.5), so it may keep a
112
- * native selection in zeta's editors; without it, every key stays zeta's.
138
+ #1: * tells the terminal that zeta applies its `edit` events (Tern SDK,
139
+ * `protocol/input.md`), so it may keep a native selection in zeta's editors;
140
+ * without it, every key stays zeta's. `"undo"` says zeta applies `undo` events,
141
+ * so the terminal may turn ⌃Z in a field into one.
142
+ * `"send"` accepts an explicit prompt for a live composer without simulating keys.
113
143
  */
114
144
  export function encodeTspHelloQuery(version?: string): string {
115
- return encodeTspJson("q", { q: "hello", v: [TSP_VERSION], app: "zeta", features: ["edit"], ver: version });
145
+ return encodeTspJson("q", {
146
+ q: "hello",
147
+ v: [TSP_VERSION],
148
+ app: "zeta",
149
+ features: ["edit", "undo", "send"],
150
+ ver: version,
151
+ });
116
152
  }
117
153
 
118
154
  /** One decoded APC message: verb, parameters and raw body. */
@@ -172,6 +208,7 @@ const EVENT_REQUIRED: Readonly<Record<string, Readonly<Record<string, "string" |
172
208
  // `value` varies by control (boolean, number, string, string[], null): the handler checks it.
173
209
  change: { id: "string", item: "string" },
174
210
  edit: { id: "string", from: "number", to: "number", text: "string", cursor: "number", len: "number" },
211
+ undo: { id: "string" },
175
212
  focus: { id: "string" },
176
213
  error: { msg: "string" },
177
214
  gone: { ids: "array" },
@@ -179,6 +216,11 @@ const EVENT_REQUIRED: Readonly<Record<string, Readonly<Record<string, "string" |
179
216
 
180
217
  function decodeEvent(value: Record<string, unknown>): TspEvent | null {
181
218
  if (typeof value.ev !== "string") return null;
219
+ if (value.ev === "send") {
220
+ const { sf, id, text } = value;
221
+ if (typeof sf !== "string" || !sf || typeof id !== "string" || !id || typeof text !== "string") return null;
222
+ return { ev: "send", sf, id, text };
223
+ }
182
224
  const required = EVENT_REQUIRED[value.ev];
183
225
  if (!required) return null;
184
226
  for (const key in required) {
@@ -11,7 +11,8 @@
11
11
  * `rows` fallback node rendered through `render(cx.cols)`.
12
12
  *
13
13
  * See `packages/wire/src/tsp.ts` for the wire vocabulary and
14
- * `crates/tern/SURFACE_PROTOCOL.md` (Stencil repository) for the spec.
14
+ * the Tern SDK's Surface Protocol reference (`docs/sdk/src/protocol` in the
15
+ * Stencil repository, https://docs.stencil.so/tern/protocol/) for the spec.
15
16
  */
16
17
  import type { TspEvent, TspKind, TspProps, TspScrollBy, TspSpan } from "@linxiraos/pi-wire";
17
18
  import type { Component } from "../tui";
@@ -28,10 +29,12 @@ export type NativeNode = {
28
29
  */
29
30
  readonly key?: string;
30
31
  /**
31
- * Scroll the node into view, placed like the `reveal` op, when it is
32
- * added. Key a node by what it points at to reveal it again on a move.
32
+ * Scroll the node into view, placed like the `reveal` op. A placement
33
+ * reveals it when it is added: key a node by what it points at to
34
+ * reveal it again on a move. A {@link NativeReveal} reveals it whenever
35
+ * its `n` differs from the previous description of the same node.
33
36
  */
34
- readonly reveal?: "start" | "end" | "nearest";
37
+ readonly reveal?: NativeRevealAt | NativeReveal;
35
38
  /**
36
39
  * Keyboard scrolling forwarded to the terminal (PgUp/PgDn/End reach the
37
40
  * program): moves the scroller at or above the node by `by` whenever
@@ -42,6 +45,17 @@ export type NativeNode = {
42
45
  readonly scroll?: NativeScroll;
43
46
  };
44
47
  }[TspKind];
48
+ /** Where a revealed node lands in its scroller. */
49
+ export type NativeRevealAt = "start" | "end" | "nearest";
50
+ /**
51
+ * A repeatable {@link NativeNode.reveal}: bump `n` to bring an existing node
52
+ * into view again (a Contents entry jumping to its section). A freshly added
53
+ * node is not revealed.
54
+ */
55
+ export interface NativeReveal {
56
+ readonly at: NativeRevealAt;
57
+ readonly n: number;
58
+ }
45
59
  /** A {@link NativeNode.scroll} request. */
46
60
  export interface NativeScroll {
47
61
  readonly by: TspScrollBy;
@@ -57,6 +71,12 @@ export interface DescribeContext {
57
71
  readonly reduceMotion: boolean;
58
72
  /** The terminal's appearance is dark. */
59
73
  readonly dark: boolean;
74
+ /**
75
+ * The user's system reads a 12-hour clock (`false`: 24-hour); `undefined`
76
+ * when the terminal doesn't say. Pass it as `hour12` when formatting times:
77
+ * the process's own default locale may not know.
78
+ */
79
+ readonly hour12?: boolean;
60
80
  /** Whether the terminal renders `kind` natively (else describe something simpler or let it fall back). */
61
81
  supports(kind: TspKind): boolean;
62
82
  /**
@@ -117,7 +137,18 @@ export type NativeUiEvent = {
117
137
  | ({
118
138
  readonly type: "edit";
119
139
  readonly key: string;
120
- } & NativeTextEdit);
140
+ } & NativeTextEdit)
141
+ /** Undo the last change to an `editor`/`input` node's text (the terminal's ⌃Z); a no-op with no history. */
142
+ | {
143
+ readonly type: "undo";
144
+ readonly key: string;
145
+ }
146
+ /** Submit an explicit prompt through the composer's normal path, preserving the previous draft for recall. */
147
+ | {
148
+ readonly type: "send";
149
+ readonly key: string;
150
+ readonly text: string;
151
+ };
121
152
  /**
122
153
  * A primitive edit the terminal made over its own text selection (cut,
123
154
  * typing, Backspace/Delete or paste over it, or collapsing it). Offsets are
@@ -11,7 +11,8 @@
11
11
  * `rows` fallback node rendered through `render(cx.cols)`.
12
12
  *
13
13
  * See `packages/wire/src/tsp.ts` for the wire vocabulary and
14
- * `crates/tern/SURFACE_PROTOCOL.md` (Stencil repository) for the spec.
14
+ * the Tern SDK's Surface Protocol reference (`docs/sdk/src/protocol` in the
15
+ * Stencil repository, https://docs.stencil.so/tern/protocol/) for the spec.
15
16
  */
16
17
  import type { TspEvent, TspKind, TspProps, TspScrollBy, TspSpan } from "@linxiraos/pi-wire";
17
18
  import type { Component } from "../tui";
@@ -29,10 +30,12 @@ export type NativeNode = {
29
30
  */
30
31
  readonly key?: string;
31
32
  /**
32
- * Scroll the node into view, placed like the `reveal` op, when it is
33
- * added. Key a node by what it points at to reveal it again on a move.
33
+ * Scroll the node into view, placed like the `reveal` op. A placement
34
+ * reveals it when it is added: key a node by what it points at to
35
+ * reveal it again on a move. A {@link NativeReveal} reveals it whenever
36
+ * its `n` differs from the previous description of the same node.
34
37
  */
35
- readonly reveal?: "start" | "end" | "nearest";
38
+ readonly reveal?: NativeRevealAt | NativeReveal;
36
39
  /**
37
40
  * Keyboard scrolling forwarded to the terminal (PgUp/PgDn/End reach the
38
41
  * program): moves the scroller at or above the node by `by` whenever
@@ -44,6 +47,19 @@ export type NativeNode = {
44
47
  };
45
48
  }[TspKind];
46
49
 
50
+ /** Where a revealed node lands in its scroller. */
51
+ export type NativeRevealAt = "start" | "end" | "nearest";
52
+
53
+ /**
54
+ * A repeatable {@link NativeNode.reveal}: bump `n` to bring an existing node
55
+ * into view again (a Contents entry jumping to its section). A freshly added
56
+ * node is not revealed.
57
+ */
58
+ export interface NativeReveal {
59
+ readonly at: NativeRevealAt;
60
+ readonly n: number;
61
+ }
62
+
47
63
  /** A {@link NativeNode.scroll} request. */
48
64
  export interface NativeScroll {
49
65
  readonly by: TspScrollBy;
@@ -61,6 +77,12 @@ export interface DescribeContext {
61
77
  readonly reduceMotion: boolean;
62
78
  /** The terminal's appearance is dark. */
63
79
  readonly dark: boolean;
80
+ /**
81
+ * The user's system reads a 12-hour clock (`false`: 24-hour); `undefined`
82
+ * when the terminal doesn't say. Pass it as `hour12` when formatting times:
83
+ * the process's own default locale may not know.
84
+ */
85
+ readonly hour12?: boolean;
64
86
  /** Whether the terminal renders `kind` natively (else describe something simpler or let it fall back). */
65
87
  supports(kind: TspKind): boolean;
66
88
  /**
@@ -113,7 +135,11 @@ export type NativeUiEvent =
113
135
  readonly value: boolean | number | string | readonly string[] | null;
114
136
  }
115
137
  /** An edit over the terminal's own selection in an `editor`/`input` node (see {@link NativeTextEdit}). */
116
- | ({ readonly type: "edit"; readonly key: string } & NativeTextEdit);
138
+ | ({ readonly type: "edit"; readonly key: string } & NativeTextEdit)
139
+ /** Undo the last change to an `editor`/`input` node's text (the terminal's ⌃Z); a no-op with no history. */
140
+ | { readonly type: "undo"; readonly key: string }
141
+ /** Submit an explicit prompt through the composer's normal path, preserving the previous draft for recall. */
142
+ | { readonly type: "send"; readonly key: string; readonly text: string };
117
143
 
118
144
  /**
119
145
  * A primitive edit the terminal made over its own text selection (cut,
@@ -7,7 +7,7 @@
7
7
  * component's root is a `card` whose `head` carries the title.
8
8
  */
9
9
  import type { TspProps, TspSpan, TspText } from "@linxiraos/pi-wire";
10
- import type { KeyName } from "../key-hint-format";
10
+ import { type KeyName } from "../key-hint-format";
11
11
  import { type Keybinding } from "../keybindings";
12
12
  import type { NativeChild, NativeNode } from "./node";
13
13
  /** One footer hint: the keys that trigger it and what it does. */
@@ -44,10 +44,10 @@ export interface ActionButtonOptions {
44
44
  /** Sibling identity key (defaults to the action id); `leafKey(event.key)` reports it back. */
45
45
  readonly key?: string;
46
46
  /** Key id of the keyboard path the button mirrors, drawn as a keycap inside it (`"r"`, `"ctrl+g"`). */
47
- readonly keys?: string;
47
+ readonly keys?: KeyName;
48
48
  /** `accent` = the view's hero action, `error` = destructive. */
49
49
  readonly tone?: "accent" | "error";
50
- /** Tooltip; defaults to the label plus the keycap (`"Refresh r"`). */
50
+ /** Tooltip; defaults to the label plus the keycap (`"Refresh r"`, see {@link formatTooltipKey}). */
51
51
  readonly title?: string;
52
52
  /** Target of an `open` action (URL or `file://` path). */
53
53
  readonly href?: string;
@@ -58,6 +58,11 @@ export interface ActionButtonOptions {
58
58
  * which the component routes to the same code path as the key.
59
59
  */
60
60
  export declare function actionButton(label: string, act: string, options?: ActionButtonOptions): NativeNode;
61
+ /**
62
+ * A bare `esc` keycap button for a view's top-right corner: a click sends
63
+ * `act` (default `close`), which the component routes to its Esc path.
64
+ */
65
+ export declare function escCloseButton(act?: string, key?: string): NativeNode;
61
66
  /** A row of {@link actionButton}s (role `zeta.actions`); `null` entries become the spacer that end-aligns what follows. */
62
67
  export declare function actionBar(buttons: readonly (NativeNode | null)[], key?: string): NativeNode;
63
68
  /** Spans of an annotation callout: a dim `label:` then the note. */
@@ -7,7 +7,7 @@
7
7
  * component's root is a `card` whose `head` carries the title.
8
8
  */
9
9
  import type { TspProps, TspSpan, TspText } from "@linxiraos/pi-wire";
10
- import type { KeyName } from "../key-hint-format";
10
+ import { formatTooltipKey, type KeyName } from "../key-hint-format";
11
11
  import { getKeybindings, type Keybinding } from "../keybindings";
12
12
  import { card, kbd, list, node, row, span, text } from "./describe";
13
13
  import type { NativeChild, NativeNode } from "./node";
@@ -86,10 +86,10 @@ export interface ActionButtonOptions {
86
86
  /** Sibling identity key (defaults to the action id); `leafKey(event.key)` reports it back. */
87
87
  readonly key?: string;
88
88
  /** Key id of the keyboard path the button mirrors, drawn as a keycap inside it (`"r"`, `"ctrl+g"`). */
89
- readonly keys?: string;
89
+ readonly keys?: KeyName;
90
90
  /** `accent` = the view's hero action, `error` = destructive. */
91
91
  readonly tone?: "accent" | "error";
92
- /** Tooltip; defaults to the label plus the keycap (`"Refresh r"`). */
92
+ /** Tooltip; defaults to the label plus the keycap (`"Refresh r"`, see {@link formatTooltipKey}). */
93
93
  readonly title?: string;
94
94
  /** Target of an `open` action (URL or `file://` path). */
95
95
  readonly href?: string;
@@ -110,7 +110,7 @@ export function actionButton(label: string, act: string, options: ActionButtonOp
110
110
  gap: "xs",
111
111
  align: "center",
112
112
  actions: { click: act },
113
- title: options.title ?? (options.keys ? `${label} ${options.keys}` : label),
113
+ title: options.title ?? (options.keys ? `${label} ${formatTooltipKey(options.keys)}` : label),
114
114
  ...(options.tone ? { tone: options.tone } : {}),
115
115
  ...(options.href ? { href: options.href } : {}),
116
116
  },
@@ -119,6 +119,19 @@ export function actionButton(label: string, act: string, options: ActionButtonOp
119
119
  );
120
120
  }
121
121
 
122
+ /**
123
+ * A bare `esc` keycap button for a view's top-right corner: a click sends
124
+ * `act` (default `close`), which the component routes to its Esc path.
125
+ */
126
+ export function escCloseButton(act = "close", key = "esc-close"): NativeNode {
127
+ return node(
128
+ "row",
129
+ { role: "zeta.btn", align: "center", actions: { click: act }, title: `Close ${formatTooltipKey("escape")}` },
130
+ [kbd("escape")],
131
+ key,
132
+ );
133
+ }
134
+
122
135
  /** A row of {@link actionButton}s (role `zeta.actions`); `null` entries become the spacer that end-aligns what follows. */
123
136
  export function actionBar(buttons: readonly (NativeNode | null)[], key = "actions"): NativeNode {
124
137
  const children = buttons.map(button => button ?? node("spacer", { grow: 1 }));
@@ -30,8 +30,9 @@
30
30
  import * as logger from "@linxiraos/pi-utils/logger";
31
31
  import { TSP_TEXT_KINDS, type TspKind, type TspNode, type TspOp, type TspScrollBy } from "@linxiraos/pi-wire";
32
32
  import { type Component, Container, CURSOR_MARKER } from "../tui";
33
+ import { getNativeBlob } from "./blobs";
33
34
  import { normalizeIconProps } from "./icons";
34
- import type { DescribeContext, NativeChild, NativeNode } from "./node";
35
+ import type { DescribeContext, NativeChild, NativeNode, NativeRevealAt } from "./node";
35
36
  import { isNativeSettled } from "./settle";
36
37
 
37
38
  /** The regions a frame fills. */
@@ -213,8 +214,11 @@ export class Reconciler {
213
214
  #ops: TspOp[] = [];
214
215
  #dels: Entry[] = [];
215
216
  #settles: string[] = [];
216
- /** Selected list items and added `reveal` nodes sent this frame, revealed once the frame's adds have landed. */
217
- #reveals: [id: string, at: "start" | "end" | "nearest"][] = [];
217
+ /**
218
+ * Selected list items, added `reveal` nodes and nodes whose reveal `n` moved this frame,
219
+ * revealed once the frame's adds have landed.
220
+ */
221
+ #reveals: [id: string, at: NativeRevealAt][] = [];
218
222
  /** `scroll` requests whose `n` moved this frame, sent after the reveals. */
219
223
  #scrolls: [id: string, by: TspScrollBy][] = [];
220
224
  /** Wire ids `list.selected` keys resolved to (an unresolved key names no node to reveal). */
@@ -288,6 +292,7 @@ export class Reconciler {
288
292
  this.#prevPortals = portals;
289
293
  this.#regions = next;
290
294
  for (const entry of this.#dels) this.#deleteEntry(entry);
295
+ this.#dels = [];
291
296
  // Parked to survive a parent/child swap but absent from the new description.
292
297
  for (const state of this.#parked) {
293
298
  if (!state.parked) continue;
@@ -595,6 +600,11 @@ export class Reconciler {
595
600
  this.#revisitNode(next, inner);
596
601
  return;
597
602
  }
603
+ const reveal = next.node.reveal;
604
+ if (typeof reveal === "object") {
605
+ const was = old.node.reveal;
606
+ if (reveal.n !== (typeof was === "object" ? was.n : undefined)) this.#reveals.push([next.id, reveal.at]);
607
+ }
598
608
  if (old.node.k !== next.node.k) {
599
609
  this.#dropSubtree(old);
600
610
  this.#ops.push(["del", next.id]);
@@ -703,6 +713,8 @@ export class Reconciler {
703
713
  owner: Owner,
704
714
  entries: readonly Entry[],
705
715
  ): Readonly<Record<string, unknown>> | undefined {
716
+ // Dereferencing pins the blob through this synchronous reconcile/upload job, even after settling drops its node.
717
+ if (node.k === "image" && node.p?.blob) getNativeBlob(node.p.blob);
706
718
  return normalizeIconProps(node.k, this.#resolveRefs(node, owner, entries));
707
719
  }
708
720
 
@@ -743,7 +755,7 @@ export class Reconciler {
743
755
 
744
756
  /** A full wire subtree for an entry; nested components get states (or pending moves when mounted elsewhere). */
745
757
  #materialize(entry: NodeEntry, walk: Walk): TspNode {
746
- if (entry.node.reveal) this.#reveals.push([entry.id, entry.node.reveal]);
758
+ if (typeof entry.node.reveal === "string") this.#reveals.push([entry.id, entry.node.reveal]);
747
759
  const entries = this.#entries(entry.node.c, entry.keypath, entry.owner, entry.hoist, walk);
748
760
  const children: TspNode[] = [];
749
761
  for (let i = 0; i < entries.length; i++) {
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * Settling: the frame provider marks finalized transcript blocks so the
3
- * native reconciler stops keeping their description (spec §12 "Settling and
4
- * program memory"). A settled block stays editable: a later change is sent as
5
- * targeted ops by id, followed by a fresh `settle` hint.
3
+ * native reconciler stops keeping their description (Tern SDK,
4
+ * `protocol/operations.md`, "Settling"). A settled block stays editable: a
5
+ * later change is sent as targeted ops by id, followed by a fresh `settle`
6
+ * hint.
6
7
  */
7
8
  import type { Component } from "../tui";
8
9
  /** Mark `component` (and everything it describes) as finalized. Idempotent; a no-op outside a TSP terminal. */
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * Settling: the frame provider marks finalized transcript blocks so the
3
- * native reconciler stops keeping their description (spec §12 "Settling and
4
- * program memory"). A settled block stays editable: a later change is sent as
5
- * targeted ops by id, followed by a fresh `settle` hint.
3
+ * native reconciler stops keeping their description (Tern SDK,
4
+ * `protocol/operations.md`, "Settling"). A settled block stays editable: a
5
+ * later change is sent as targeted ops by id, followed by a fresh `settle`
6
+ * hint.
6
7
  */
7
8
  import type { Component } from "../tui";
8
9
 
@@ -15,11 +15,12 @@ interface AgentTreeProjection<TRecord extends AgentRecordLike> {
15
15
  export declare const STATUS_ORDER: Record<AgentStatus, number>;
16
16
  /** Exact observer usage for one roster entry. */
17
17
  export declare function progressMetrics(observed: ObservableSession | undefined): AgentMetrics | undefined;
18
- /** Live session whose own messages back a row's metrics when no observer progress exists. */
18
+ /** Live session used to cache a row's direct assistant usage, including with observer progress. */
19
19
  export declare function hubFallbackStatsSession<TRecord extends AgentRecordLike>(ref: TRecord, observed: ObservableSession | undefined): NonNullable<TRecord["session"]> | undefined;
20
20
  /**
21
- * One roster row's usage: live observer progress, then persisted history, then
22
- * the cached fallback read of a live session (populated by {@link aggregateMetrics}).
21
+ * Preserve progress/history for non-cost metrics, overlaying cumulative direct-session cost.
22
+ * Persisted `history.metrics.cost` is a leaf-scoped snapshot, so it never overrides live
23
+ * progress; only the cumulative direct-cost sources do.
23
24
  */
24
25
  export declare function hubRowMetrics<TRecord extends AgentRecordLike>(ref: TRecord, observed: ObservableSession | undefined, sessionMetrics: WeakMap<object, {
25
26
  metrics: AgentMetrics | undefined;
@@ -37,6 +38,6 @@ export declare function aggregateMetrics<TRecord extends AgentRecordLike>(args:
37
38
  metrics: AggregateMetrics;
38
39
  hasFallbackLiveSessions: boolean;
39
40
  };
40
- /** Parent-before-child projection preserving the roster's stable sibling order. */
41
- export declare function projectAgentTree<TRecord extends AgentRecordLike>(refs: readonly TRecord[]): AgentTreeProjection<TRecord>;
41
+ /** Parent-before-child projection preserving initial subtree rank and prepending new siblings. */
42
+ export declare function projectAgentTree<TRecord extends AgentRecordLike>(refs: readonly TRecord[], rosterRank: ReadonlyMap<TRecord, number> | undefined): AgentTreeProjection<TRecord>;
42
43
  export {};