@oh-my-pi/pi-tui 18.2.4 → 18.2.6

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 (748) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +43 -0
  3. package/dist/types/app-keybindings.d.ts +395 -0
  4. package/dist/types/apps/autoresearch-dashboard.d.ts +43 -0
  5. package/dist/types/apps/autoresearch-data.d.ts +15 -0
  6. package/dist/types/apps/cleanse-board.d.ts +66 -0
  7. package/dist/types/apps/cleanse-picker.d.ts +23 -0
  8. package/dist/types/apps/debug/log-formatting.d.ts +6 -0
  9. package/dist/types/apps/debug/log-viewer.d.ts +81 -0
  10. package/dist/types/apps/debug/protocol-probe.d.ts +42 -0
  11. package/dist/types/apps/debug/raw-sse-buffer.d.ts +58 -0
  12. package/dist/types/apps/debug/raw-sse.d.ts +26 -0
  13. package/dist/types/apps/debug/terminal-info.d.ts +34 -0
  14. package/dist/types/apps/debug/viewer-frame.d.ts +52 -0
  15. package/dist/types/apps/git/avatar.d.ts +9 -0
  16. package/dist/types/apps/git/colors.d.ts +49 -0
  17. package/dist/types/apps/git/diff-pane.d.ts +188 -0
  18. package/dist/types/apps/git/git-tui.d.ts +66 -0
  19. package/dist/types/apps/git/sidebar.d.ts +149 -0
  20. package/dist/types/apps/git/state.d.ts +117 -0
  21. package/dist/types/apps/if-bench-board.d.ts +75 -0
  22. package/dist/types/apps/live-visualizer.d.ts +33 -0
  23. package/dist/types/apps/ps-data.d.ts +51 -0
  24. package/dist/types/apps/ps-top.d.ts +33 -0
  25. package/dist/types/apps/session-picker.d.ts +26 -0
  26. package/dist/types/apps/setup-model-picker.d.ts +13 -0
  27. package/dist/types/apps/standalone-picker.d.ts +42 -0
  28. package/dist/types/autocomplete.d.ts +4 -0
  29. package/dist/types/chat/advisor-message.d.ts +11 -0
  30. package/dist/types/chat/assistant-message.d.ts +106 -0
  31. package/dist/types/chat/background-tan-message.d.ts +9 -0
  32. package/dist/types/chat/bash-execution.d.ts +47 -0
  33. package/dist/types/chat/cache-invalidation-marker.d.ts +50 -0
  34. package/dist/types/chat/chat-transcript-builder.d.ts +50 -0
  35. package/dist/types/chat/collab-prompt-message.d.ts +10 -0
  36. package/dist/types/chat/compaction-summary-message.d.ts +54 -0
  37. package/dist/types/chat/custom-message.d.ts +10 -0
  38. package/dist/types/chat/display-preferences.d.ts +13 -0
  39. package/dist/types/chat/eval-execution.d.ts +29 -0
  40. package/dist/types/chat/execution-shared.d.ts +51 -0
  41. package/dist/types/chat/extension-types.d.ts +28 -0
  42. package/dist/types/chat/hook-message.d.ts +10 -0
  43. package/dist/types/chat/image-loading.d.ts +46 -0
  44. package/dist/types/chat/late-diagnostics-message.d.ts +21 -0
  45. package/dist/types/chat/messages.d.ts +189 -0
  46. package/dist/types/chat/reaction.d.ts +30 -0
  47. package/dist/types/chat/read-target.d.ts +4 -0
  48. package/dist/types/chat/read-tool-group.d.ts +67 -0
  49. package/dist/types/chat/served-model-marker.d.ts +47 -0
  50. package/dist/types/chat/skill-message.d.ts +33 -0
  51. package/dist/types/chat/skill-title-input.d.ts +14 -0
  52. package/dist/types/chat/stripped-tool-calls-placeholder.d.ts +12 -0
  53. package/dist/types/chat/thinking-display.d.ts +12 -0
  54. package/dist/types/chat/todo-reminder.d.ts +13 -0
  55. package/dist/types/chat/tool-execution.d.ts +138 -0
  56. package/dist/types/chat/transcript-browser.d.ts +93 -0
  57. package/dist/types/chat/transcript-entry.d.ts +45 -0
  58. package/dist/types/chat/transcript-outline.d.ts +86 -0
  59. package/dist/types/chat/transcript-render-helpers.d.ts +92 -0
  60. package/dist/types/chat/ttsr-notification.d.ts +23 -0
  61. package/dist/types/chat/user-message.d.ts +52 -0
  62. package/dist/types/chrome/chat-block.d.ts +64 -0
  63. package/dist/types/chrome/collab-qrcode.d.ts +28 -0
  64. package/dist/types/chrome/context-thresholds.d.ts +10 -0
  65. package/dist/types/chrome/countdown-timer.d.ts +14 -0
  66. package/dist/types/chrome/diff.d.ts +14 -0
  67. package/dist/types/chrome/dynamic-border.d.ts +16 -0
  68. package/dist/types/chrome/error-block.d.ts +17 -0
  69. package/dist/types/chrome/form-theme.d.ts +3 -0
  70. package/dist/types/chrome/format.d.ts +12 -0
  71. package/dist/types/chrome/index.d.ts +20 -0
  72. package/dist/types/chrome/keybinding-hints.d.ts +40 -0
  73. package/dist/types/chrome/live-board.d.ts +23 -0
  74. package/dist/types/chrome/local-date.d.ts +4 -0
  75. package/dist/types/chrome/message-divider.d.ts +22 -0
  76. package/dist/types/chrome/message-frame.d.ts +52 -0
  77. package/dist/types/chrome/message-notice.d.ts +35 -0
  78. package/dist/types/chrome/overlay-box.d.ts +74 -0
  79. package/dist/types/chrome/qrcode.d.ts +48 -0
  80. package/dist/types/chrome/segment-track.d.ts +27 -0
  81. package/dist/types/chrome/select-list-mouse-routing.d.ts +4 -0
  82. package/dist/types/chrome/selector-helpers.d.ts +52 -0
  83. package/dist/types/chrome/shared.d.ts +5 -0
  84. package/dist/types/chrome/streaming-panel.d.ts +19 -0
  85. package/dist/types/chrome/tool-activity.d.ts +17 -0
  86. package/dist/types/chrome/transcript-container.d.ts +129 -0
  87. package/dist/types/chrome/transcript-status.d.ts +12 -0
  88. package/dist/types/chrome/visual-truncate.d.ts +19 -0
  89. package/dist/types/components/disclosure.d.ts +42 -0
  90. package/dist/types/components/form.d.ts +130 -0
  91. package/dist/types/components/key-value-list.d.ts +24 -0
  92. package/dist/types/components/layout/geometry.d.ts +73 -0
  93. package/dist/types/components/layout/row.d.ts +55 -0
  94. package/dist/types/components/layout/split-pane.d.ts +80 -0
  95. package/dist/types/components/layout/stack.d.ts +50 -0
  96. package/dist/types/components/menu-selection.d.ts +71 -0
  97. package/dist/types/components/metric.d.ts +44 -0
  98. package/dist/types/components/progress-bar.d.ts +36 -0
  99. package/dist/types/components/scroll-view.d.ts +53 -19
  100. package/dist/types/components/scroll-viewport.d.ts +46 -0
  101. package/dist/types/components/section.d.ts +19 -0
  102. package/dist/types/components/select-list.d.ts +46 -2
  103. package/dist/types/components/settings-list.d.ts +20 -0
  104. package/dist/types/components/table.d.ts +32 -0
  105. package/dist/types/components/tree-view.d.ts +130 -0
  106. package/dist/types/components/wizard-step.d.ts +60 -0
  107. package/dist/types/hotkeys-markdown.d.ts +7 -0
  108. package/dist/types/index.d.ts +17 -0
  109. package/dist/types/keybinding-matchers.d.ts +35 -0
  110. package/dist/types/keys.d.ts +2 -2
  111. package/dist/types/lang-from-path.d.ts +9 -0
  112. package/dist/types/overlays/advisor-config.d.ts +114 -0
  113. package/dist/types/overlays/agent-activity.d.ts +41 -0
  114. package/dist/types/overlays/agent-hub-projection.d.ts +33 -0
  115. package/dist/types/overlays/agent-hub-renderer.d.ts +53 -0
  116. package/dist/types/overlays/agent-hub-types.d.ts +99 -0
  117. package/dist/types/overlays/agent-hub.d.ts +126 -0
  118. package/dist/types/overlays/agent-transcript-viewer.d.ts +71 -0
  119. package/dist/types/overlays/agents-hub.d.ts +72 -0
  120. package/dist/types/overlays/ask-dialog.d.ts +88 -0
  121. package/dist/types/overlays/bordered-loader.d.ts +11 -0
  122. package/dist/types/overlays/btw-history-panel.d.ts +29 -0
  123. package/dist/types/overlays/btw-history.d.ts +17 -0
  124. package/dist/types/overlays/btw-panel.d.ts +26 -0
  125. package/dist/types/overlays/cleanse-panel.d.ts +36 -0
  126. package/dist/types/overlays/codex-reset-fireworks.d.ts +52 -0
  127. package/dist/types/overlays/composer-shape-preview.d.ts +47 -0
  128. package/dist/types/overlays/composer-shape-registry.d.ts +50 -0
  129. package/dist/types/overlays/copy-selector.d.ts +48 -0
  130. package/dist/types/overlays/copy-targets.d.ts +63 -0
  131. package/dist/types/overlays/error-banner.d.ts +13 -0
  132. package/dist/types/overlays/extensions/display-text.d.ts +10 -0
  133. package/dist/types/overlays/extensions/extension-dashboard.d.ts +63 -0
  134. package/dist/types/overlays/extensions/extension-list.d.ts +54 -0
  135. package/dist/types/overlays/extensions/inspector-model.d.ts +109 -0
  136. package/dist/types/overlays/extensions/inspector-panel.d.ts +17 -0
  137. package/dist/types/overlays/extensions/live-tool-session.d.ts +28 -0
  138. package/dist/types/overlays/extensions/mcp-runtime.d.ts +107 -0
  139. package/dist/types/overlays/extensions/state-manager.d.ts +42 -0
  140. package/dist/types/overlays/extensions/types.d.ts +165 -0
  141. package/dist/types/overlays/history-search.d.ts +16 -0
  142. package/dist/types/overlays/hook-editor.d.ts +44 -0
  143. package/dist/types/overlays/hook-input.d.ts +20 -0
  144. package/dist/types/overlays/hook-selector.d.ts +71 -0
  145. package/dist/types/overlays/hub-frame.d.ts +77 -0
  146. package/dist/types/overlays/login-dialog.d.ts +43 -0
  147. package/dist/types/overlays/logout-account-selector.d.ts +15 -0
  148. package/dist/types/overlays/mcp-add-wizard.d.ts +87 -0
  149. package/dist/types/overlays/model-browser.d.ts +213 -0
  150. package/dist/types/overlays/model-hub.d.ts +72 -0
  151. package/dist/types/overlays/model-picker.d.ts +74 -0
  152. package/dist/types/overlays/model-selector.d.ts +52 -0
  153. package/dist/types/overlays/move-overlay.d.ts +39 -0
  154. package/dist/types/overlays/oauth-selector.d.ts +41 -0
  155. package/dist/types/overlays/omfg-panel.d.ts +20 -0
  156. package/dist/types/overlays/pause-screen.d.ts +43 -0
  157. package/dist/types/overlays/plan-review-overlay.d.ts +89 -0
  158. package/dist/types/overlays/plan-save-overlay.d.ts +19 -0
  159. package/dist/types/overlays/plan-toc.d.ts +41 -0
  160. package/dist/types/overlays/plugin-selector.d.ts +28 -0
  161. package/dist/types/overlays/plugin-settings.d.ts +180 -0
  162. package/dist/types/overlays/queue-mode-selector.d.ts +11 -0
  163. package/dist/types/overlays/reset-usage-selector.d.ts +23 -0
  164. package/dist/types/overlays/rewind-selector.d.ts +61 -0
  165. package/dist/types/overlays/running-subagent-badge.d.ts +6 -0
  166. package/dist/types/overlays/session-account-selector.d.ts +24 -0
  167. package/dist/types/overlays/session-info-overlay.d.ts +17 -0
  168. package/dist/types/overlays/session-observer-registry.d.ts +77 -0
  169. package/dist/types/overlays/session-selector.d.ts +131 -0
  170. package/dist/types/overlays/settings-defs.d.ts +119 -0
  171. package/dist/types/overlays/settings-selector.d.ts +73 -0
  172. package/dist/types/overlays/show-images-selector.d.ts +11 -0
  173. package/dist/types/overlays/snapcompact-shape-preview.d.ts +31 -0
  174. package/dist/types/overlays/theme-selector.d.ts +12 -0
  175. package/dist/types/overlays/thinking-selector.d.ts +12 -0
  176. package/dist/types/overlays/tiny-title-download-progress.d.ts +21 -0
  177. package/dist/types/overlays/tree-selector.d.ts +92 -0
  178. package/dist/types/overlays/usage-dashboard.d.ts +94 -0
  179. package/dist/types/overlays/usage-display.d.ts +5 -0
  180. package/dist/types/overlays/usage-row.d.ts +17 -0
  181. package/dist/types/prompt/attachment-chips.d.ts +19 -0
  182. package/dist/types/prompt/composer-attachments.d.ts +71 -0
  183. package/dist/types/prompt/composer-cache.d.ts +37 -0
  184. package/dist/types/prompt/composer.d.ts +159 -0
  185. package/dist/types/prompt/custom-editor.d.ts +261 -0
  186. package/dist/types/prompt/editor-top-gap.d.ts +18 -0
  187. package/dist/types/prompt/emoji-autocomplete.d.ts +16 -0
  188. package/dist/types/prompt/github-ref-autocomplete.d.ts +35 -0
  189. package/dist/types/prompt/gradient-highlight.d.ts +32 -0
  190. package/dist/types/prompt/image-format.d.ts +4 -0
  191. package/dist/types/prompt/image-references.d.ts +26 -0
  192. package/dist/types/prompt/interactive-context-helpers.d.ts +43 -0
  193. package/dist/types/prompt/internal-url-autocomplete.d.ts +56 -0
  194. package/dist/types/prompt/macos-spelling.d.ts +44 -0
  195. package/dist/types/prompt/magic-keyword-boundary.d.ts +9 -0
  196. package/dist/types/prompt/magic-keywords.d.ts +26 -0
  197. package/dist/types/prompt/markdown-prose.d.ts +15 -0
  198. package/dist/types/prompt/model-mention-autocomplete.d.ts +25 -0
  199. package/dist/types/prompt/model-mention-syntax.d.ts +24 -0
  200. package/dist/types/prompt/orchestrate.d.ts +13 -0
  201. package/dist/types/prompt/prompt-action-autocomplete.d.ts +56 -0
  202. package/dist/types/prompt/queue-input.d.ts +8 -0
  203. package/dist/types/prompt/skill-tokens.d.ts +13 -0
  204. package/dist/types/prompt/tools-markdown.d.ts +12 -0
  205. package/dist/types/prompt/ultrathink.d.ts +13 -0
  206. package/dist/types/prompt/usage-amounts.d.ts +26 -0
  207. package/dist/types/prompt/video.d.ts +18 -0
  208. package/dist/types/prompt/welcome.d.ts +83 -0
  209. package/dist/types/prompt/workflow.d.ts +13 -0
  210. package/dist/types/render/code-cell.d.ts +51 -0
  211. package/dist/types/render/file-list.d.ts +22 -0
  212. package/dist/types/render/hyperlink.d.ts +80 -0
  213. package/dist/types/render/index.d.ts +16 -0
  214. package/dist/types/render/output-block.d.ts +54 -0
  215. package/dist/types/render/output-pane.d.ts +80 -0
  216. package/dist/types/render/render-utils.d.ts +312 -0
  217. package/dist/types/render/sixel.d.ts +21 -0
  218. package/dist/types/render/status-line.d.ts +23 -0
  219. package/dist/types/render/tool-card.d.ts +71 -0
  220. package/dist/types/render/tree-list.d.ts +29 -0
  221. package/dist/types/render/types.d.ts +17 -0
  222. package/dist/types/render/utils.d.ts +43 -0
  223. package/dist/types/render/width-aware-text.d.ts +23 -0
  224. package/dist/types/setup/lazy.d.ts +3 -0
  225. package/dist/types/setup/scenes/composer.d.ts +3 -0
  226. package/dist/types/setup/scenes/glyph.d.ts +3 -0
  227. package/dist/types/setup/scenes/model.d.ts +3 -0
  228. package/dist/types/setup/scenes/outro.d.ts +2 -0
  229. package/dist/types/setup/scenes/providers.d.ts +3 -0
  230. package/dist/types/setup/scenes/sign-in.d.ts +21 -0
  231. package/dist/types/setup/scenes/splash.d.ts +11 -0
  232. package/dist/types/setup/scenes/theme.d.ts +3 -0
  233. package/dist/types/setup/scenes/types.d.ts +110 -0
  234. package/dist/types/setup/scenes/web-search.d.ts +22 -0
  235. package/dist/types/setup/setup-version.d.ts +11 -0
  236. package/dist/types/setup/startup-splash.d.ts +9 -0
  237. package/dist/types/setup/wizard-overlay.d.ts +16 -0
  238. package/dist/types/setup/wizard.d.ts +25 -0
  239. package/dist/types/status-line/component.d.ts +182 -0
  240. package/dist/types/status-line/context-usage.d.ts +156 -0
  241. package/dist/types/status-line/footer.d.ts +30 -0
  242. package/dist/types/status-line/git-utils.d.ts +22 -0
  243. package/dist/types/status-line/host.d.ts +129 -0
  244. package/dist/types/status-line/index.d.ts +6 -0
  245. package/dist/types/status-line/loop.d.ts +18 -0
  246. package/dist/types/status-line/metrics.d.ts +21 -0
  247. package/dist/types/status-line/presets.d.ts +3 -0
  248. package/dist/types/status-line/schema.d.ts +15 -0
  249. package/dist/types/status-line/segments.d.ts +5 -0
  250. package/dist/types/status-line/separators.d.ts +3 -0
  251. package/dist/types/status-line/types.d.ts +236 -0
  252. package/dist/types/stdin-buffer.d.ts +4 -0
  253. package/dist/types/theme/color.d.ts +24 -0
  254. package/dist/types/theme/defaults/index.d.ts +9489 -0
  255. package/dist/types/theme/index.d.ts +4 -0
  256. package/dist/types/theme/loader.d.ts +23 -0
  257. package/dist/types/theme/mermaid-cache.d.ts +26 -0
  258. package/dist/types/theme/schema-validation.d.ts +3 -0
  259. package/dist/types/theme/schema.d.ts +25 -0
  260. package/dist/types/theme/session-color.d.ts +43 -0
  261. package/dist/types/theme/shimmer.d.ts +44 -0
  262. package/dist/types/theme/symbols.d.ts +34 -0
  263. package/dist/types/theme/theme-class.d.ts +299 -0
  264. package/dist/types/theme/theme.d.ts +111 -0
  265. package/dist/types/theme/tui-adapters.d.ts +30 -0
  266. package/dist/types/thinking.d.ts +165 -0
  267. package/dist/types/tools/agent-tree.d.ts +36 -0
  268. package/dist/types/tools/ask.d.ts +67 -0
  269. package/dist/types/tools/ast-edit.d.ts +53 -0
  270. package/dist/types/tools/ast-grep.d.ts +52 -0
  271. package/dist/types/tools/autoresearch.d.ts +156 -0
  272. package/dist/types/tools/bash-interactive.d.ts +28 -0
  273. package/dist/types/tools/bash.d.ts +103 -0
  274. package/dist/types/tools/conflict-detect.d.ts +43 -0
  275. package/dist/types/tools/debug.d.ts +60 -0
  276. package/dist/types/tools/default-renderer.d.ts +24 -0
  277. package/dist/types/tools/edit.d.ts +158 -0
  278. package/dist/types/tools/eval-format/code-mode-declarations.d.ts +5 -0
  279. package/dist/types/tools/eval-format/index.d.ts +5 -0
  280. package/dist/types/tools/eval-format/javascript.d.ts +2 -0
  281. package/dist/types/tools/eval-format/python.d.ts +2 -0
  282. package/dist/types/tools/eval.d.ts +94 -0
  283. package/dist/types/tools/fetch.d.ts +42 -0
  284. package/dist/types/tools/gh-format.d.ts +8 -0
  285. package/dist/types/tools/github.d.ts +144 -0
  286. package/dist/types/tools/glob.d.ts +44 -0
  287. package/dist/types/tools/goal.d.ts +42 -0
  288. package/dist/types/tools/grep.d.ts +64 -0
  289. package/dist/types/tools/grouped-file-output.d.ts +71 -0
  290. package/dist/types/tools/hashline-format.d.ts +28 -0
  291. package/dist/types/tools/hub.d.ts +340 -0
  292. package/dist/types/tools/index.d.ts +4 -0
  293. package/dist/types/tools/json-tree.d.ts +59 -0
  294. package/dist/types/tools/line-ranges.d.ts +29 -0
  295. package/dist/types/tools/list-limit.d.ts +15 -0
  296. package/dist/types/tools/lsp.d.ts +72 -0
  297. package/dist/types/tools/match-line-format.d.ts +11 -0
  298. package/dist/types/tools/mcp.d.ts +81 -0
  299. package/dist/types/tools/memory.d.ts +67 -0
  300. package/dist/types/tools/output-meta.d.ts +151 -0
  301. package/dist/types/tools/read.d.ts +139 -0
  302. package/dist/types/tools/renderer.d.ts +98 -0
  303. package/dist/types/tools/report-tool-issue.d.ts +8 -0
  304. package/dist/types/tools/resolve.d.ts +47 -0
  305. package/dist/types/tools/streaming-output.d.ts +282 -0
  306. package/dist/types/tools/subprocess.d.ts +24 -0
  307. package/dist/types/tools/task-repair-args.d.ts +53 -0
  308. package/dist/types/tools/task-yield-assembly.d.ts +20 -0
  309. package/dist/types/tools/task.d.ts +425 -0
  310. package/dist/types/tools/terminal-output.d.ts +8 -0
  311. package/dist/types/tools/think.d.ts +13 -0
  312. package/dist/types/tools/todo.d.ts +118 -0
  313. package/dist/types/tools/tool-errors.d.ts +7 -0
  314. package/dist/types/tools/vibe.d.ts +120 -0
  315. package/dist/types/tools/web-search.d.ts +195 -0
  316. package/dist/types/tools/write.d.ts +76 -0
  317. package/dist/types/tools/xd-url.d.ts +13 -0
  318. package/dist/types/tools/xdev.d.ts +52 -0
  319. package/dist/types/tui.d.ts +18 -0
  320. package/dist/types/utils.d.ts +2 -0
  321. package/package.json +37 -3
  322. package/src/app-keybindings.ts +760 -0
  323. package/src/apps/autoresearch-dashboard.ts +500 -0
  324. package/src/apps/autoresearch-data.ts +64 -0
  325. package/src/apps/cleanse-board.ts +341 -0
  326. package/src/apps/cleanse-picker.ts +57 -0
  327. package/src/apps/debug/log-formatting.ts +53 -0
  328. package/src/apps/debug/log-viewer.ts +868 -0
  329. package/src/apps/debug/protocol-probe.ts +267 -0
  330. package/src/apps/debug/raw-sse-buffer.ts +449 -0
  331. package/src/apps/debug/raw-sse.ts +282 -0
  332. package/src/apps/debug/terminal-info.ts +115 -0
  333. package/src/apps/debug/viewer-frame.ts +174 -0
  334. package/src/apps/git/avatar.ts +52 -0
  335. package/src/apps/git/colors.ts +109 -0
  336. package/src/apps/git/diff-pane.ts +1512 -0
  337. package/src/apps/git/git-tui.ts +889 -0
  338. package/src/apps/git/sidebar.ts +1204 -0
  339. package/src/apps/git/state.ts +113 -0
  340. package/src/apps/if-bench-board.ts +324 -0
  341. package/src/apps/live-visualizer.ts +238 -0
  342. package/src/apps/ps-data.ts +116 -0
  343. package/src/apps/ps-top.ts +422 -0
  344. package/src/apps/session-picker.ts +95 -0
  345. package/src/apps/setup-model-picker.ts +21 -0
  346. package/src/apps/standalone-picker.ts +111 -0
  347. package/src/autocomplete.ts +9 -13
  348. package/src/chat/advisor-message.ts +175 -0
  349. package/src/chat/assistant-message.ts +1214 -0
  350. package/src/chat/background-tan-message.ts +35 -0
  351. package/src/chat/bash-execution.ts +394 -0
  352. package/src/chat/cache-invalidation-marker.ts +94 -0
  353. package/src/chat/chat-transcript-builder.ts +593 -0
  354. package/src/chat/collab-prompt-message.ts +34 -0
  355. package/src/chat/compaction-summary-message.ts +261 -0
  356. package/src/chat/custom-message.ts +23 -0
  357. package/src/chat/display-preferences.ts +24 -0
  358. package/src/chat/eval-execution.ts +172 -0
  359. package/src/chat/execution-shared.ts +113 -0
  360. package/src/chat/extension-types.ts +46 -0
  361. package/src/chat/hook-message.ts +20 -0
  362. package/src/chat/image-loading.ts +122 -0
  363. package/src/chat/late-diagnostics-message.ts +92 -0
  364. package/src/chat/messages.ts +305 -0
  365. package/src/chat/reaction.ts +65 -0
  366. package/src/chat/read-target.ts +7 -0
  367. package/src/chat/read-tool-group.ts +873 -0
  368. package/src/chat/served-model-marker.ts +91 -0
  369. package/src/chat/skill-message.ts +220 -0
  370. package/src/chat/skill-title-input.ts +41 -0
  371. package/src/chat/stripped-tool-calls-placeholder.ts +35 -0
  372. package/src/chat/thinking-display.ts +312 -0
  373. package/src/chat/todo-reminder.ts +33 -0
  374. package/src/chat/tool-execution.ts +1395 -0
  375. package/src/chat/transcript-browser.ts +268 -0
  376. package/src/chat/transcript-entry.ts +96 -0
  377. package/src/chat/transcript-outline.ts +260 -0
  378. package/src/chat/transcript-render-helpers.ts +315 -0
  379. package/src/chat/ttsr-notification.ts +123 -0
  380. package/src/chat/user-message.ts +287 -0
  381. package/src/chrome/chat-block.ts +110 -0
  382. package/src/chrome/collab-qrcode.ts +74 -0
  383. package/src/chrome/context-thresholds.ts +85 -0
  384. package/src/chrome/countdown-timer.ts +74 -0
  385. package/src/chrome/diff.ts +266 -0
  386. package/src/chrome/dynamic-border.ts +36 -0
  387. package/src/chrome/error-block.ts +63 -0
  388. package/src/chrome/form-theme.ts +10 -0
  389. package/src/chrome/format.ts +66 -0
  390. package/src/chrome/index.ts +21 -0
  391. package/src/chrome/keybinding-hints.ts +55 -0
  392. package/src/chrome/live-board.ts +123 -0
  393. package/src/chrome/local-date.ts +20 -0
  394. package/src/chrome/message-divider.ts +51 -0
  395. package/src/chrome/message-frame.ts +164 -0
  396. package/src/chrome/message-notice.ts +103 -0
  397. package/src/chrome/overlay-box.ts +301 -0
  398. package/src/chrome/qrcode.ts +539 -0
  399. package/src/chrome/segment-track.ts +86 -0
  400. package/src/chrome/select-list-mouse-routing.ts +11 -0
  401. package/src/chrome/selector-helpers.ts +119 -0
  402. package/src/chrome/shared.ts +27 -0
  403. package/src/chrome/streaming-panel.ts +72 -0
  404. package/src/chrome/tool-activity.ts +44 -0
  405. package/src/chrome/transcript-container.ts +902 -0
  406. package/src/chrome/transcript-status.ts +27 -0
  407. package/src/chrome/visual-truncate.ts +70 -0
  408. package/src/components/disclosure.ts +235 -0
  409. package/src/components/editor.ts +10 -12
  410. package/src/components/form.ts +566 -0
  411. package/src/components/input.ts +6 -27
  412. package/src/components/key-value-list.ts +88 -0
  413. package/src/components/layout/geometry.ts +202 -0
  414. package/src/components/layout/row.ts +283 -0
  415. package/src/components/layout/split-pane.ts +349 -0
  416. package/src/components/layout/stack.ts +261 -0
  417. package/src/components/markdown.ts +16 -12
  418. package/src/components/menu-selection.ts +248 -0
  419. package/src/components/metric.ts +132 -0
  420. package/src/components/progress-bar.ts +140 -0
  421. package/src/components/scroll-view.ts +372 -70
  422. package/src/components/scroll-viewport.ts +154 -0
  423. package/src/components/section.ts +77 -0
  424. package/src/components/select-list.ts +238 -159
  425. package/src/components/settings-list.ts +103 -80
  426. package/src/components/table.ts +127 -0
  427. package/src/components/tree-view.ts +481 -0
  428. package/src/components/wizard-step.ts +229 -0
  429. package/src/deccara.ts +1 -3
  430. package/src/hotkeys-markdown.ts +100 -0
  431. package/src/index.ts +18 -0
  432. package/src/keybinding-matchers.ts +99 -0
  433. package/src/keys.ts +2 -2
  434. package/src/lang-from-path.ts +252 -0
  435. package/src/overlays/advisor-config.ts +761 -0
  436. package/src/overlays/agent-activity.ts +113 -0
  437. package/src/overlays/agent-hub-projection.ts +250 -0
  438. package/src/overlays/agent-hub-renderer.ts +281 -0
  439. package/src/overlays/agent-hub-types.ts +74 -0
  440. package/src/overlays/agent-hub.ts +1562 -0
  441. package/src/overlays/agent-transcript-viewer.ts +669 -0
  442. package/src/overlays/agents-hub.ts +1203 -0
  443. package/src/overlays/ask-dialog.ts +1202 -0
  444. package/src/overlays/bordered-loader.ts +41 -0
  445. package/src/overlays/btw-history-panel.ts +591 -0
  446. package/src/overlays/btw-history.ts +33 -0
  447. package/src/overlays/btw-panel.ts +167 -0
  448. package/src/overlays/cleanse-panel.ts +167 -0
  449. package/src/overlays/codex-reset-fireworks.ts +375 -0
  450. package/src/overlays/composer-shape-preview.ts +137 -0
  451. package/src/overlays/composer-shape-registry.ts +82 -0
  452. package/src/overlays/copy-selector.ts +618 -0
  453. package/src/overlays/copy-targets.ts +210 -0
  454. package/src/overlays/error-banner.ts +39 -0
  455. package/src/overlays/extensions/display-text.ts +39 -0
  456. package/src/overlays/extensions/extension-dashboard.ts +645 -0
  457. package/src/overlays/extensions/extension-list.ts +667 -0
  458. package/src/overlays/extensions/inspector-model.ts +484 -0
  459. package/src/overlays/extensions/inspector-panel.ts +669 -0
  460. package/src/overlays/extensions/live-tool-session.ts +67 -0
  461. package/src/overlays/extensions/mcp-runtime.ts +289 -0
  462. package/src/overlays/extensions/state-manager.ts +337 -0
  463. package/src/overlays/extensions/types.ts +208 -0
  464. package/src/overlays/history-search.ts +268 -0
  465. package/src/overlays/hook-editor.ts +272 -0
  466. package/src/overlays/hook-input.ts +84 -0
  467. package/src/overlays/hook-selector.ts +635 -0
  468. package/src/overlays/hub-frame.ts +262 -0
  469. package/src/overlays/login-dialog.ts +231 -0
  470. package/src/overlays/logout-account-selector.ts +115 -0
  471. package/src/overlays/mcp-add-wizard.ts +1436 -0
  472. package/src/overlays/model-browser.ts +1176 -0
  473. package/src/overlays/model-hub.ts +2279 -0
  474. package/src/overlays/model-picker.ts +285 -0
  475. package/src/overlays/model-selector.ts +107 -0
  476. package/src/overlays/move-overlay.ts +197 -0
  477. package/src/overlays/oauth-selector.ts +446 -0
  478. package/src/overlays/omfg-panel.ts +136 -0
  479. package/src/overlays/pause-screen.ts +198 -0
  480. package/src/overlays/plan-review-overlay.ts +1227 -0
  481. package/src/overlays/plan-save-overlay.ts +74 -0
  482. package/src/overlays/plan-toc.ts +139 -0
  483. package/src/overlays/plugin-selector.ts +97 -0
  484. package/src/overlays/plugin-settings.ts +839 -0
  485. package/src/overlays/queue-mode-selector.ts +55 -0
  486. package/src/overlays/reset-usage-selector.ts +170 -0
  487. package/src/overlays/rewind-selector.ts +499 -0
  488. package/src/overlays/running-subagent-badge.ts +19 -0
  489. package/src/overlays/session-account-selector.ts +68 -0
  490. package/src/overlays/session-info-overlay.ts +96 -0
  491. package/src/overlays/session-observer-registry.ts +289 -0
  492. package/src/overlays/session-selector.ts +1137 -0
  493. package/src/overlays/settings-defs.ts +315 -0
  494. package/src/overlays/settings-selector.ts +1415 -0
  495. package/src/overlays/show-images-selector.ts +44 -0
  496. package/src/overlays/snapcompact-shape-preview-doc.md +14 -0
  497. package/src/overlays/snapcompact-shape-preview.ts +192 -0
  498. package/src/overlays/theme-selector.ts +62 -0
  499. package/src/overlays/thinking-selector.ts +51 -0
  500. package/src/overlays/tiny-title-download-progress.ts +102 -0
  501. package/src/overlays/tree-selector.ts +1121 -0
  502. package/src/overlays/usage-dashboard.ts +629 -0
  503. package/src/overlays/usage-display.ts +45 -0
  504. package/src/overlays/usage-row.ts +118 -0
  505. package/src/prompt/attachment-chips.ts +201 -0
  506. package/src/prompt/composer-attachments.ts +280 -0
  507. package/src/prompt/composer-cache.ts +304 -0
  508. package/src/prompt/composer.ts +934 -0
  509. package/src/prompt/custom-editor.ts +1392 -0
  510. package/src/prompt/data/emojis.json +1 -0
  511. package/src/prompt/editor-top-gap.ts +28 -0
  512. package/src/prompt/emoji-autocomplete.ts +285 -0
  513. package/src/prompt/github-ref-autocomplete.ts +75 -0
  514. package/src/prompt/gradient-highlight.ts +101 -0
  515. package/src/prompt/image-format.ts +28 -0
  516. package/src/prompt/image-references.ts +102 -0
  517. package/src/prompt/interactive-context-helpers.ts +126 -0
  518. package/src/prompt/internal-url-autocomplete.ts +155 -0
  519. package/src/prompt/macos-spelling.ts +456 -0
  520. package/src/prompt/magic-keyword-boundary.ts +23 -0
  521. package/src/prompt/magic-keywords.ts +42 -0
  522. package/src/prompt/markdown-prose.ts +245 -0
  523. package/src/prompt/model-mention-autocomplete.ts +94 -0
  524. package/src/prompt/model-mention-syntax.ts +41 -0
  525. package/src/prompt/orchestrate.ts +26 -0
  526. package/src/prompt/prompt-action-autocomplete.ts +337 -0
  527. package/src/prompt/queue-input.ts +132 -0
  528. package/src/prompt/skill-tokens.ts +36 -0
  529. package/src/prompt/tips.txt +27 -0
  530. package/src/prompt/tools-markdown.ts +29 -0
  531. package/src/prompt/ultrathink.ts +26 -0
  532. package/src/prompt/usage-amounts.ts +99 -0
  533. package/src/prompt/video.ts +47 -0
  534. package/src/prompt/welcome.ts +605 -0
  535. package/src/prompt/workflow.ts +26 -0
  536. package/src/render/code-cell.ts +244 -0
  537. package/src/render/file-list.ts +58 -0
  538. package/src/render/hyperlink.ts +192 -0
  539. package/src/render/index.ts +17 -0
  540. package/src/render/output-block.ts +267 -0
  541. package/src/render/output-pane.ts +299 -0
  542. package/src/render/render-utils.ts +1182 -0
  543. package/src/render/sixel.ts +69 -0
  544. package/src/render/status-line.ts +55 -0
  545. package/src/render/tool-card.ts +272 -0
  546. package/src/render/tree-list.ts +188 -0
  547. package/src/render/types.ts +19 -0
  548. package/src/render/utils.ts +109 -0
  549. package/src/render/width-aware-text.ts +60 -0
  550. package/src/setup/lazy.ts +17 -0
  551. package/src/setup/scenes/composer.ts +127 -0
  552. package/src/setup/scenes/glyph.ts +120 -0
  553. package/src/setup/scenes/model.ts +138 -0
  554. package/src/setup/scenes/outro.ts +24 -0
  555. package/src/setup/scenes/providers.ts +107 -0
  556. package/src/setup/scenes/sign-in.ts +373 -0
  557. package/src/setup/scenes/splash.ts +192 -0
  558. package/src/setup/scenes/theme.ts +343 -0
  559. package/src/setup/scenes/types.ts +111 -0
  560. package/src/setup/scenes/web-search.ts +165 -0
  561. package/src/setup/setup-version.ts +11 -0
  562. package/src/setup/startup-splash.ts +107 -0
  563. package/src/setup/wizard-overlay.ts +319 -0
  564. package/src/setup/wizard.ts +101 -0
  565. package/src/status-line/component.ts +3003 -0
  566. package/src/status-line/context-usage.ts +688 -0
  567. package/src/status-line/footer.ts +323 -0
  568. package/src/status-line/git-utils.ts +42 -0
  569. package/src/status-line/host.ts +97 -0
  570. package/src/status-line/index.ts +6 -0
  571. package/src/status-line/loop.ts +28 -0
  572. package/src/status-line/metrics.ts +94 -0
  573. package/src/status-line/presets.ts +107 -0
  574. package/src/status-line/schema.ts +57 -0
  575. package/src/status-line/segments.ts +934 -0
  576. package/src/status-line/separators.ts +55 -0
  577. package/src/status-line/types.ts +227 -0
  578. package/src/stdin-buffer.ts +4 -2
  579. package/src/theme/color.ts +95 -0
  580. package/src/theme/dark.json +95 -0
  581. package/src/theme/defaults/alabaster.json +93 -0
  582. package/src/theme/defaults/amethyst.json +96 -0
  583. package/src/theme/defaults/anthracite.json +93 -0
  584. package/src/theme/defaults/basalt.json +91 -0
  585. package/src/theme/defaults/birch.json +95 -0
  586. package/src/theme/defaults/dark-abyss.json +91 -0
  587. package/src/theme/defaults/dark-arctic.json +104 -0
  588. package/src/theme/defaults/dark-aurora.json +95 -0
  589. package/src/theme/defaults/dark-catppuccin.json +107 -0
  590. package/src/theme/defaults/dark-cavern.json +91 -0
  591. package/src/theme/defaults/dark-celestial.json +106 -0
  592. package/src/theme/defaults/dark-copper.json +95 -0
  593. package/src/theme/defaults/dark-cosmos.json +90 -0
  594. package/src/theme/defaults/dark-cyberpunk.json +102 -0
  595. package/src/theme/defaults/dark-dracula.json +98 -0
  596. package/src/theme/defaults/dark-eclipse.json +91 -0
  597. package/src/theme/defaults/dark-ember.json +95 -0
  598. package/src/theme/defaults/dark-equinox.json +90 -0
  599. package/src/theme/defaults/dark-forest.json +96 -0
  600. package/src/theme/defaults/dark-github.json +105 -0
  601. package/src/theme/defaults/dark-gruvbox.json +112 -0
  602. package/src/theme/defaults/dark-lavender.json +95 -0
  603. package/src/theme/defaults/dark-lunar.json +89 -0
  604. package/src/theme/defaults/dark-midnight.json +95 -0
  605. package/src/theme/defaults/dark-monochrome.json +94 -0
  606. package/src/theme/defaults/dark-monokai.json +98 -0
  607. package/src/theme/defaults/dark-nebula.json +90 -0
  608. package/src/theme/defaults/dark-nord.json +98 -0
  609. package/src/theme/defaults/dark-ocean.json +101 -0
  610. package/src/theme/defaults/dark-one.json +100 -0
  611. package/src/theme/defaults/dark-poimandres.json +115 -0
  612. package/src/theme/defaults/dark-rainforest.json +91 -0
  613. package/src/theme/defaults/dark-reef.json +91 -0
  614. package/src/theme/defaults/dark-retro.json +92 -0
  615. package/src/theme/defaults/dark-rose-pine.json +96 -0
  616. package/src/theme/defaults/dark-sakura.json +95 -0
  617. package/src/theme/defaults/dark-slate.json +95 -0
  618. package/src/theme/defaults/dark-solarized.json +97 -0
  619. package/src/theme/defaults/dark-solstice.json +90 -0
  620. package/src/theme/defaults/dark-starfall.json +91 -0
  621. package/src/theme/defaults/dark-sunset.json +99 -0
  622. package/src/theme/defaults/dark-swamp.json +90 -0
  623. package/src/theme/defaults/dark-synthwave.json +103 -0
  624. package/src/theme/defaults/dark-taiga.json +91 -0
  625. package/src/theme/defaults/dark-terminal.json +95 -0
  626. package/src/theme/defaults/dark-tokyo-night.json +101 -0
  627. package/src/theme/defaults/dark-tundra.json +91 -0
  628. package/src/theme/defaults/dark-twilight.json +91 -0
  629. package/src/theme/defaults/dark-volcanic.json +91 -0
  630. package/src/theme/defaults/graphite.json +92 -0
  631. package/src/theme/defaults/index.ts +201 -0
  632. package/src/theme/defaults/light-arctic.json +107 -0
  633. package/src/theme/defaults/light-aurora-day.json +91 -0
  634. package/src/theme/defaults/light-canyon.json +91 -0
  635. package/src/theme/defaults/light-catppuccin.json +106 -0
  636. package/src/theme/defaults/light-cirrus.json +90 -0
  637. package/src/theme/defaults/light-coral.json +95 -0
  638. package/src/theme/defaults/light-cyberpunk.json +96 -0
  639. package/src/theme/defaults/light-dawn.json +90 -0
  640. package/src/theme/defaults/light-dunes.json +91 -0
  641. package/src/theme/defaults/light-eucalyptus.json +95 -0
  642. package/src/theme/defaults/light-forest.json +100 -0
  643. package/src/theme/defaults/light-frost.json +95 -0
  644. package/src/theme/defaults/light-github.json +115 -0
  645. package/src/theme/defaults/light-glacier.json +91 -0
  646. package/src/theme/defaults/light-gruvbox.json +108 -0
  647. package/src/theme/defaults/light-haze.json +90 -0
  648. package/src/theme/defaults/light-honeycomb.json +95 -0
  649. package/src/theme/defaults/light-lagoon.json +91 -0
  650. package/src/theme/defaults/light-lavender.json +95 -0
  651. package/src/theme/defaults/light-meadow.json +91 -0
  652. package/src/theme/defaults/light-mint.json +95 -0
  653. package/src/theme/defaults/light-monochrome.json +101 -0
  654. package/src/theme/defaults/light-ocean.json +99 -0
  655. package/src/theme/defaults/light-one.json +99 -0
  656. package/src/theme/defaults/light-opal.json +91 -0
  657. package/src/theme/defaults/light-orchard.json +91 -0
  658. package/src/theme/defaults/light-paper.json +95 -0
  659. package/src/theme/defaults/light-poimandres.json +115 -0
  660. package/src/theme/defaults/light-prism.json +90 -0
  661. package/src/theme/defaults/light-retro.json +98 -0
  662. package/src/theme/defaults/light-sand.json +95 -0
  663. package/src/theme/defaults/light-savanna.json +91 -0
  664. package/src/theme/defaults/light-solarized.json +102 -0
  665. package/src/theme/defaults/light-soleil.json +90 -0
  666. package/src/theme/defaults/light-sunset.json +99 -0
  667. package/src/theme/defaults/light-synthwave.json +98 -0
  668. package/src/theme/defaults/light-tokyo-night.json +111 -0
  669. package/src/theme/defaults/light-wetland.json +91 -0
  670. package/src/theme/defaults/light-zenith.json +89 -0
  671. package/src/theme/defaults/limestone.json +94 -0
  672. package/src/theme/defaults/mahogany.json +97 -0
  673. package/src/theme/defaults/marble.json +93 -0
  674. package/src/theme/defaults/obsidian.json +91 -0
  675. package/src/theme/defaults/onyx.json +91 -0
  676. package/src/theme/defaults/pearl.json +93 -0
  677. package/src/theme/defaults/porcelain.json +91 -0
  678. package/src/theme/defaults/quartz.json +96 -0
  679. package/src/theme/defaults/sandstone.json +95 -0
  680. package/src/theme/defaults/titanium.json +90 -0
  681. package/src/theme/index.ts +5 -0
  682. package/src/theme/light.json +93 -0
  683. package/src/theme/loader.ts +200 -0
  684. package/src/theme/mermaid-cache.ts +92 -0
  685. package/src/theme/schema-validation.ts +119 -0
  686. package/src/theme/schema.ts +168 -0
  687. package/src/theme/session-color.ts +253 -0
  688. package/src/theme/shimmer.ts +307 -0
  689. package/src/theme/symbols.ts +1433 -0
  690. package/src/theme/theme-class.ts +787 -0
  691. package/src/theme/theme-schema.json +463 -0
  692. package/src/theme/theme.ts +810 -0
  693. package/src/theme/tui-adapters.ts +339 -0
  694. package/src/thinking.ts +380 -0
  695. package/src/tools/agent-tree.ts +128 -0
  696. package/src/tools/ask.ts +482 -0
  697. package/src/tools/ast-edit.ts +210 -0
  698. package/src/tools/ast-grep.ts +171 -0
  699. package/src/tools/autoresearch.ts +287 -0
  700. package/src/tools/bash-interactive.ts +295 -0
  701. package/src/tools/bash.ts +468 -0
  702. package/src/tools/conflict-detect.ts +77 -0
  703. package/src/tools/debug.ts +167 -0
  704. package/src/tools/default-renderer.ts +172 -0
  705. package/src/tools/edit.ts +1258 -0
  706. package/src/tools/eval-format/code-mode-declarations.ts +61 -0
  707. package/src/tools/eval-format/index.ts +16 -0
  708. package/src/tools/eval-format/javascript.ts +952 -0
  709. package/src/tools/eval-format/python.ts +544 -0
  710. package/src/tools/eval.ts +835 -0
  711. package/src/tools/fetch.ts +226 -0
  712. package/src/tools/gh-format.ts +18 -0
  713. package/src/tools/github.ts +686 -0
  714. package/src/tools/glob.ts +213 -0
  715. package/src/tools/goal.ts +153 -0
  716. package/src/tools/grep.ts +385 -0
  717. package/src/tools/grouped-file-output.ts +211 -0
  718. package/src/tools/hashline-format.ts +59 -0
  719. package/src/tools/hub.ts +1488 -0
  720. package/src/tools/index.ts +71 -0
  721. package/src/tools/json-tree.ts +388 -0
  722. package/src/tools/line-ranges.ts +98 -0
  723. package/src/tools/list-limit.ts +43 -0
  724. package/src/tools/lsp.ts +702 -0
  725. package/src/tools/match-line-format.ts +20 -0
  726. package/src/tools/mcp.ts +309 -0
  727. package/src/tools/memory.ts +220 -0
  728. package/src/tools/output-meta.ts +367 -0
  729. package/src/tools/read.ts +628 -0
  730. package/src/tools/renderer.ts +107 -0
  731. package/src/tools/report-tool-issue.ts +13 -0
  732. package/src/tools/resolve.ts +139 -0
  733. package/src/tools/streaming-output.ts +1576 -0
  734. package/src/tools/subprocess.ts +39 -0
  735. package/src/tools/task-repair-args.ts +118 -0
  736. package/src/tools/task-yield-assembly.ts +147 -0
  737. package/src/tools/task.ts +2110 -0
  738. package/src/tools/terminal-output.ts +153 -0
  739. package/src/tools/think.ts +28 -0
  740. package/src/tools/todo.ts +580 -0
  741. package/src/tools/tool-errors.ts +15 -0
  742. package/src/tools/vibe.ts +420 -0
  743. package/src/tools/web-search.ts +409 -0
  744. package/src/tools/write.ts +511 -0
  745. package/src/tools/xd-url.ts +28 -0
  746. package/src/tools/xdev.ts +201 -0
  747. package/src/tui.ts +57 -4
  748. package/src/utils.ts +8 -0
@@ -0,0 +1,268 @@
1
+ import type { Component } from "../tui";
2
+ import { type ScrollRangeAnchor, ScrollView } from "../components/scroll-view";
3
+ import { DynamicBorder } from "../chrome/dynamic-border";
4
+ import { truncateToWidth } from "../utils";
5
+ import { theme } from "../theme/theme";
6
+ import {
7
+ composeOutlineColumn,
8
+ type ComposedColumn,
9
+ OutlineRowCache,
10
+ type OutlineStyle,
11
+ type OutlineTarget,
12
+ outlineVisibility,
13
+ } from "./transcript-outline";
14
+
15
+ /** Logical body rows and optional selection supplied by a transcript browser controller. */
16
+ export interface TranscriptBrowserBody {
17
+ lines: readonly string[];
18
+ anchor?: ScrollRangeAnchor;
19
+ }
20
+
21
+ /** One complete browser frame. Header and footer rows are inset by one column. */
22
+ export interface TranscriptBrowserFrame {
23
+ header: readonly string[];
24
+ body: TranscriptBrowserBody;
25
+ footer: readonly string[];
26
+ }
27
+
28
+ /** Widths available while composing a transcript browser frame. */
29
+ export interface TranscriptBrowserRenderContext {
30
+ /** Width passed to {@link TranscriptBrowser.render}. */
31
+ frameWidth: number;
32
+ /** Stable transcript width, reserving the final column for an automatic scrollbar. */
33
+ contentWidth: number;
34
+ /** Width for inset header/footer children such as an editor. */
35
+ chromeWidth: number;
36
+ }
37
+
38
+ /** Construction options for the shared transcript browser viewport and frame. */
39
+ export interface TranscriptBrowserOptions {
40
+ /** Explicit height budget supplied by the fullscreen host. */
41
+ getHeight: () => number;
42
+ /** Domain controller which supplies header, body, footer, and optional selection. */
43
+ frame: (context: TranscriptBrowserRenderContext) => TranscriptBrowserFrame;
44
+ /** Preserve the historical three-row minimum used by transcript overlays. */
45
+ minimumBodyRows?: number;
46
+ /** Start in append-follow mode; manual scrolling updates the mode automatically. */
47
+ followBottom?: boolean;
48
+ }
49
+
50
+ /** Prepared transcript rows, visibility, and nearest valid selection. */
51
+ export interface PreparedTranscriptOutline {
52
+ childRows: Array<readonly string[]>;
53
+ visible: boolean[];
54
+ selected: number;
55
+ }
56
+
57
+ /** Options for composing the standard single-column dotted transcript outline. */
58
+ export interface TranscriptOutlineComposition {
59
+ children: readonly Component[];
60
+ targets: readonly OutlineTarget[];
61
+ selected: number;
62
+ columnWidth: number;
63
+ /** Reuse rows already prepared for custom branch/block composition in the same frame. */
64
+ prepared?: PreparedTranscriptOutline;
65
+ from?: number;
66
+ to?: number;
67
+ header?: string[];
68
+ style?: OutlineStyle;
69
+ }
70
+
71
+ interface BrowserLayout {
72
+ bodyTop: number;
73
+ bodyHeight: number;
74
+ }
75
+
76
+ function sameLines(left: readonly string[], right: readonly string[]): boolean {
77
+ if (left.length !== right.length) return false;
78
+ for (let index = 0; index < left.length; index++) {
79
+ if (left[index] !== right[index]) return false;
80
+ }
81
+ return true;
82
+ }
83
+
84
+ /** Nearest visible target, preferring the preceding item just like the legacy selectors. */
85
+ export function nearestVisibleOutlineTarget(visible: readonly boolean[], selected: number): number {
86
+ if (selected < 0 || selected >= visible.length) return visible.findIndex(Boolean);
87
+ if (visible[selected] !== false) return selected;
88
+ for (let above = selected - 1; above >= 0; above--) {
89
+ if (visible[above] !== false) return above;
90
+ }
91
+ for (let below = selected + 1; below < visible.length; below++) {
92
+ if (visible[below] !== false) return below;
93
+ }
94
+ return selected;
95
+ }
96
+
97
+ /**
98
+ * Shared framed viewport for transcript browsers.
99
+ *
100
+ * Domain controllers retain loading, actions, and branch/block presentation;
101
+ * this component owns outline row caching, frame sizing, scroll state,
102
+ * selection anchoring, append-follow behavior, and frame-to-body coordinates.
103
+ */
104
+ export class TranscriptBrowser implements Component {
105
+ readonly debugChildren: readonly Component[];
106
+
107
+ readonly #options: TranscriptBrowserOptions;
108
+ readonly #scrollView: ScrollView;
109
+ readonly #border = new DynamicBorder();
110
+ readonly #rowCache = new OutlineRowCache();
111
+ #followBottom: boolean;
112
+ #layout: BrowserLayout | undefined;
113
+ #cachedLines: readonly string[] | undefined;
114
+
115
+ constructor(options: TranscriptBrowserOptions) {
116
+ this.#options = options;
117
+ this.#followBottom = options.followBottom ?? false;
118
+ this.#scrollView = new ScrollView([], {
119
+ height: 0,
120
+ scrollbar: "auto",
121
+ followTail: this.#followBottom,
122
+ theme: { track: text => theme.fg("dim", text), thumb: text => theme.fg("accent", text) },
123
+ });
124
+ this.debugChildren = [this.#scrollView, this.#border];
125
+ }
126
+
127
+ invalidate(): void {
128
+ this.#cachedLines = undefined;
129
+ this.#border.invalidate();
130
+ this.#scrollView.invalidate();
131
+ }
132
+
133
+ /** Prompt-zone-safe rendered rows for outline composition at `columnWidth`. */
134
+ renderOutlineRows(children: readonly Component[], columnWidth: number): Array<readonly string[]> {
135
+ return this.#rowCache.rows(children, Math.max(10, columnWidth - 4));
136
+ }
137
+
138
+ /** Compute target visibility and snap a collapsed selection to the nearest rendered item. */
139
+ prepareOutline(
140
+ children: readonly Component[],
141
+ targets: readonly OutlineTarget[],
142
+ selected: number,
143
+ columnWidth: number,
144
+ ): PreparedTranscriptOutline {
145
+ const childRows = this.renderOutlineRows(children, columnWidth);
146
+ const visible = outlineVisibility(childRows, targets);
147
+ return {
148
+ childRows,
149
+ visible,
150
+ selected: nearestVisibleOutlineTarget(visible, selected),
151
+ };
152
+ }
153
+
154
+ /** Compose the standard single-column outline using the browser-owned row cache. */
155
+ composeOutline(options: TranscriptOutlineComposition): PreparedTranscriptOutline & { column: ComposedColumn } {
156
+ const prepared =
157
+ options.prepared ??
158
+ this.prepareOutline(options.children, options.targets, options.selected, options.columnWidth);
159
+ return {
160
+ ...prepared,
161
+ column: composeOutlineColumn(
162
+ prepared.childRows,
163
+ options.from ?? 0,
164
+ options.to ?? options.children.length,
165
+ options.targets,
166
+ prepared.selected,
167
+ options.columnWidth,
168
+ options.header,
169
+ options.style,
170
+ ),
171
+ };
172
+ }
173
+
174
+ /** Scroll logical body rows. Returns whether the offset changed. */
175
+ scroll(delta: number): boolean {
176
+ const before = this.#scrollView.getScrollOffset();
177
+ this.#scrollView.scroll(delta);
178
+ this.#syncFollowBottom();
179
+ return this.#scrollView.getScrollOffset() !== before;
180
+ }
181
+
182
+ /** Apply the ScrollView navigation key set. */
183
+ handleScrollKey(data: string): boolean {
184
+ if (!this.#scrollView.handleScrollKey(data)) return false;
185
+ this.#syncFollowBottom();
186
+ return true;
187
+ }
188
+
189
+ scrollToTop(): void {
190
+ this.#scrollView.scrollToTop();
191
+ this.#syncFollowBottom();
192
+ }
193
+
194
+ scrollToBottom(): void {
195
+ this.#scrollView.scrollToBottom();
196
+ this.#syncFollowBottom();
197
+ }
198
+
199
+ /** Whether an anchor identity has successfully been applied to the viewport. */
200
+ hasAnchored(id: string): boolean {
201
+ return this.#scrollView.hasRevealedRange(id);
202
+ }
203
+
204
+ /**
205
+ * Translate a 0-based frame mouse point into the logical, scrolled body.
206
+ * Returns undefined for borders, header/footer rows, and unpainted body rows.
207
+ */
208
+ toContentPoint(frameRow: number, frameCol: number): { row: number; col: number } | undefined {
209
+ const layout = this.#layout;
210
+ if (!layout) return undefined;
211
+ const localRow = Math.trunc(frameRow) - layout.bodyTop;
212
+ if (localRow < 0 || localRow >= layout.bodyHeight) return undefined;
213
+ const row = this.#scrollView.logicalRowAt(localRow);
214
+ if (row === undefined) return undefined;
215
+ return {
216
+ row,
217
+ col: Math.max(0, Math.trunc(frameCol)),
218
+ };
219
+ }
220
+
221
+ render(width: number): readonly string[] {
222
+ const frameWidth = Number.isFinite(width) ? Math.max(0, Math.trunc(width)) : 0;
223
+ const context: TranscriptBrowserRenderContext = {
224
+ frameWidth,
225
+ contentWidth: Math.max(1, frameWidth - 1),
226
+ chromeWidth: Math.max(1, frameWidth - 2),
227
+ };
228
+ const frame = this.#options.frame(context);
229
+ const heightValue = this.#options.getHeight();
230
+ const height = Number.isFinite(heightValue) ? Math.max(0, Math.trunc(heightValue)) : 0;
231
+ const borderRows = frameWidth > 0 ? 3 : 0;
232
+ const chromeRows = frame.header.length + frame.footer.length + borderRows;
233
+ const minimumBodyRows = Math.max(0, Math.trunc(this.#options.minimumBodyRows ?? 3));
234
+ const bodyHeight = Math.max(minimumBodyRows, height - chromeRows);
235
+ this.#layout = { bodyTop: frame.header.length + (frameWidth > 0 ? 2 : 0), bodyHeight };
236
+
237
+ this.#scrollView.setLines(frame.body.lines);
238
+ this.#scrollView.setHeight(bodyHeight);
239
+ if (frame.body.anchor && this.#scrollView.revealRange(frame.body.anchor, context.contentWidth)) {
240
+ this.#followBottom = false;
241
+ this.#scrollView.setFollowTail(false);
242
+ }
243
+
244
+ const border = frameWidth > 0 ? this.#border.render(frameWidth) : [];
245
+ const output: string[] = [];
246
+ output.push(...border);
247
+ for (const line of frame.header) output.push(this.#chromeLine(line, frameWidth));
248
+ output.push(...border);
249
+ output.push(...this.#scrollView.render(frameWidth));
250
+ for (const line of frame.footer) output.push(this.#chromeLine(line, frameWidth));
251
+ output.push(...border);
252
+ const cached = this.#cachedLines;
253
+ if (cached && sameLines(cached, output)) return cached;
254
+ this.#cachedLines = output;
255
+ return output;
256
+ }
257
+
258
+ #syncFollowBottom(): void {
259
+ if (!this.#options.followBottom) return;
260
+ this.#followBottom = this.#scrollView.getScrollOffset() >= this.#scrollView.getMaxScrollOffset();
261
+ this.#scrollView.setFollowTail(this.#followBottom);
262
+ }
263
+
264
+ #chromeLine(line: string, width: number): string {
265
+ if (width <= 0) return "";
266
+ return ` ${truncateToWidth(line, Math.max(0, width - 1))}`;
267
+ }
268
+ }
@@ -0,0 +1,96 @@
1
+ import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
2
+ import { createCustomMessage } from "@oh-my-pi/pi-agent-core/compaction/messages";
3
+ import type { MessageAttribution } from "@oh-my-pi/pi-ai";
4
+ import {
5
+ type CustomMessage,
6
+ type CustomMessageContent,
7
+ isCustomMessageContent,
8
+ isUserTurnInitiator,
9
+ normalizeCustomMessagePayload,
10
+ } from "./messages";
11
+ import { titleTextFromSkillPrompt } from "./skill-title-input";
12
+
13
+ /** Persisted message fields consumed by transcript rendering. */
14
+ export interface SessionMessageEntryLike {
15
+ type: "message";
16
+ id: string;
17
+ parentId: string | null;
18
+ timestamp: string;
19
+ message: AgentMessage;
20
+ }
21
+
22
+ /** Persisted custom-message fields consumed by transcript rendering. */
23
+ export interface CustomMessageEntryLike {
24
+ type: "custom_message";
25
+ id: string;
26
+ parentId: string | null;
27
+ timestamp: string;
28
+ customType: string;
29
+ content: CustomMessageContent;
30
+ details?: unknown;
31
+ display: boolean;
32
+ attribution?: MessageAttribution;
33
+ }
34
+
35
+ /** Entries that replay as visible or hidden transcript messages. */
36
+ export type TranscriptEntryLike = SessionMessageEntryLike | CustomMessageEntryLike;
37
+
38
+ /** Restore a persisted custom message, rejecting unsendable content. */
39
+ export function customMessageEntryMessage(entry: CustomMessageEntryLike): CustomMessage | undefined {
40
+ if (!isCustomMessageContent(entry.content)) return undefined;
41
+ const normalized = normalizeCustomMessagePayload(entry);
42
+ const attribution = entry.attribution === undefined ? undefined : normalized.attribution;
43
+ return createCustomMessage(
44
+ normalized.customType,
45
+ normalized.content,
46
+ normalized.display,
47
+ normalized.details,
48
+ entry.timestamp,
49
+ attribution,
50
+ );
51
+ }
52
+
53
+ /** Restore the message represented by a transcript entry. */
54
+ export function transcriptEntryMessage(entry: TranscriptEntryLike): AgentMessage | undefined {
55
+ return entry.type === "message" ? entry.message : customMessageEntryMessage(entry);
56
+ }
57
+
58
+ /** Identify user-authored requests among transcript and metadata entries. */
59
+ export function isUserRequestEntry(entry: TranscriptEntryLike | { type: string }): boolean {
60
+ if (entry.type === "message" && "message" in entry) {
61
+ if (entry.message.role === "user") return true;
62
+ return entry.message.role === "custom" && isUserTurnInitiator(entry.message);
63
+ }
64
+ if (entry.type === "custom_message" && "content" in entry) {
65
+ const message = customMessageEntryMessage(entry);
66
+ return message !== undefined && isUserTurnInitiator(message);
67
+ }
68
+ return false;
69
+ }
70
+
71
+ /** Editable user request text, preserving skill invocation syntax. */
72
+ export function userTurnDraft(entry: TranscriptEntryLike): string | undefined {
73
+ const message = transcriptEntryMessage(entry);
74
+ if (!message) return undefined;
75
+ if (message.role === "user") return textContent(message.content);
76
+ if (message.role !== "custom" || !isUserTurnInitiator(message)) return undefined;
77
+ return titleTextFromSkillPrompt(message) ?? textContent(message.content);
78
+ }
79
+
80
+ /** Extract text blocks verbatim, optionally separating block boundaries. */
81
+ export function textContent(content: string | ReadonlyArray<{ type: string; text?: string }>, separator = ""): string {
82
+ if (typeof content === "string") return content;
83
+ let text = "";
84
+ let boundary = "";
85
+ for (const block of content) {
86
+ if (block.type !== "text") continue;
87
+ text += boundary + (block.text ?? "");
88
+ boundary = separator;
89
+ }
90
+ return text;
91
+ }
92
+
93
+ /** Join text blocks with spaces and collapse whitespace into a single-line label. */
94
+ export function userMessageLabel(content: string | ReadonlyArray<{ type: string; text?: string }>): string {
95
+ return textContent(content, " ").replace(/\s+/g, " ").trim();
96
+ }
@@ -0,0 +1,260 @@
1
+ /**
2
+ * Shared engine for the ephemeral fullscreen transcript selectors (esc-esc
3
+ * rewind, `/copy`): replay session entries through {@link ChatTranscriptBuilder},
4
+ * map each rendered turn to a selectable target, and compose gutter-prefixed
5
+ * columns with a dotted outline around the selected target.
6
+ */
7
+ import { type Component } from "../tui";
8
+ import { visibleWidth } from "../utils";
9
+ import {
10
+ isUserRequestEntry,
11
+ type TranscriptEntryLike as TranscriptEntry,
12
+ userMessageLabel,
13
+ userTurnDraft,
14
+ } from "./transcript-entry";
15
+ import type { SessionMessageEntryLike as SessionMessageEntry } from "./transcript-entry";
16
+ import { type ThemeColor, theme } from "../theme";
17
+ import type { ChatTranscriptBuilder } from "./chat-transcript-builder";
18
+ import { padToWidth } from "../render/utils";
19
+ import { isUsageRowBlock } from "../overlays/usage-row";
20
+
21
+ /** One selectable transcript item: a message entry plus its rendered block range. */
22
+ export interface OutlineTarget {
23
+ /** Entry the selection resolves to; extended over trailing componentless tool results. */
24
+ entryId: string;
25
+ /** Entry that opened this turn (pre-fold) — anchor for tree lookups. */
26
+ turnId: string;
27
+ /** Real user prompt — drives user-turn jumps and role-specific actions. */
28
+ isUserTurn: boolean;
29
+ /** First transcript-container child rendered by this entry. */
30
+ start: number;
31
+ /** One past the last child rendered by this entry. */
32
+ end: number;
33
+ /** Entries this target spans: the turn plus any folded tool results. */
34
+ entries: TranscriptEntry[];
35
+ }
36
+
37
+ /** Composed rows of one column plus the outline's line range within them. */
38
+ export interface ComposedColumn {
39
+ lines: string[];
40
+ selStart: number;
41
+ selEnd: number;
42
+ }
43
+ /** Presentation of the dotted outline: stroke color and an optional caption inset into the top rule. */
44
+ export interface OutlineStyle {
45
+ color?: ThemeColor;
46
+ /** Short affordance label (e.g. "3 blocks →") drawn into the top rule's right end. */
47
+ caption?: string;
48
+ }
49
+
50
+ // User bubbles wrap their rows in OSC 133 prompt-zone marks (see
51
+ // user-message.ts). Re-emitting those inside the alternate-screen overlay
52
+ // latches the terminal's prompt semantics onto overlay rows and garbles the
53
+ // frame, so embedded rows shed them; the transcript proper keeps its zones.
54
+ const OSC133_SPAN_REGEX = /\x1b\]133;[^\x07\x1b]*(?:\x07|\x1b\\)/g;
55
+
56
+ /** Copy-on-write removal of OSC 133 spans from a rendered row array. */
57
+ export function stripPromptZones(rows: readonly string[]): readonly string[] {
58
+ let sanitized: string[] | undefined;
59
+ for (let index = 0; index < rows.length; index++) {
60
+ if (!rows[index]!.includes("\x1b]133;")) continue;
61
+ sanitized ??= rows.slice();
62
+ sanitized[index] = rows[index]!.replace(OSC133_SPAN_REGEX, "");
63
+ }
64
+ return sanitized ?? rows;
65
+ }
66
+
67
+ /**
68
+ * Prompt-zone-stripped rows for one selector column.
69
+ *
70
+ * The selectors recompose their whole column on every keystroke, and stripping
71
+ * every child's rows again per frame is pure waste on a long session. Per the
72
+ * {@link Component} render contract a child returns the same array while its
73
+ * rows are unchanged, so the stripped copy is keyed on that array: a child that
74
+ * repaints itself asynchronously (Kitty image conversion, todo strike frames)
75
+ * hands back a new array and is stripped again.
76
+ */
77
+ export class OutlineRowCache {
78
+ #stripped = new WeakMap<Component, { rows: readonly string[]; stripped: readonly string[] }>();
79
+
80
+ rows(children: readonly Component[], width: number): Array<readonly string[]> {
81
+ const columns: Array<readonly string[]> = [];
82
+ for (const child of children) {
83
+ const rows = child.render(width);
84
+ const cached = this.#stripped.get(child);
85
+ if (cached && cached.rows === rows) {
86
+ columns.push(cached.stripped);
87
+ continue;
88
+ }
89
+ const stripped = stripPromptZones(rows);
90
+ this.#stripped.set(child, { rows, stripped });
91
+ columns.push(stripped);
92
+ }
93
+ return columns;
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Append `entries` to `builder`, returning the selectable targets they
99
+ * produce. Tool results fold into the previous target (so a turn's rewind
100
+ * and `/copy` keep its output, including lazily created children such as
101
+ * the grouped-read card); notices and hidden messages that render nothing
102
+ * are skipped. Usage rows flushed at the head of an append are attributed
103
+ * to the turn above.
104
+ */
105
+ export function appendOutlineEntries(builder: ChatTranscriptBuilder, entries: TranscriptEntry[]): OutlineTarget[] {
106
+ const targets: OutlineTarget[] = [];
107
+ for (const entry of entries) {
108
+ const children = builder.container.children;
109
+ const before = children.length;
110
+ builder.append([entry]);
111
+ const after = children.length;
112
+ let start = before;
113
+ while (start < after && isUsageRowBlock(children[start]!)) {
114
+ const previous = targets.at(-1);
115
+ if (previous && previous.end === start) previous.end = start + 1;
116
+ start++;
117
+ }
118
+ const previous = targets.at(-1);
119
+ if (entry.type === "message" && entry.message.role === "toolResult" && previous) {
120
+ previous.entryId = entry.id;
121
+ previous.entries.push(entry);
122
+ if (after > previous.end) previous.end = after;
123
+ continue;
124
+ }
125
+ if (start >= after) continue;
126
+ targets.push({
127
+ entryId: entry.id,
128
+ turnId: entry.id,
129
+ isUserTurn: isUserTurnEntry(entry),
130
+ start,
131
+ end: after,
132
+ entries: [entry],
133
+ });
134
+ }
135
+ return targets;
136
+ }
137
+
138
+ /** Per-target "renders at least one non-blank row" flags at the given rows. */
139
+ export function outlineVisibility(
140
+ childRows: readonly (readonly string[])[],
141
+ targets: readonly OutlineTarget[],
142
+ ): boolean[] {
143
+ return targets.map(target => {
144
+ for (let index = target.start; index < target.end; index++) {
145
+ if (childRows[index]!.some(row => /\S/.test(row))) return true;
146
+ }
147
+ return false;
148
+ });
149
+ }
150
+
151
+ /** Dotted horizontal rule with rounded corners, spanning the outline width. */
152
+ export function outlineRule(
153
+ left: string,
154
+ right: string,
155
+ innerWidth: number,
156
+ color: ThemeColor = "accent",
157
+ caption?: string,
158
+ ): string {
159
+ const label = caption ? ` ${caption} ` : "";
160
+ const fill = Math.max(0, innerWidth + 2 - visibleWidth(label));
161
+ return (
162
+ theme.fg(color, left + theme.boxDotted.horizontal.repeat(fill)) +
163
+ theme.bold(theme.fg(color, label)) +
164
+ theme.fg(color, right)
165
+ );
166
+ }
167
+
168
+ /** Wrap pre-rendered rows in the dotted outline (rules above/below, `┆` sides). */
169
+ export function outlineRows(rows: readonly string[], innerWidth: number, style: OutlineStyle = {}): string[] {
170
+ const color = style.color ?? "accent";
171
+ const vertical = theme.fg(color, theme.boxDotted.vertical);
172
+ const lines: string[] = [
173
+ outlineRule(theme.boxRound.topLeft, theme.boxRound.topRight, innerWidth, color, style.caption),
174
+ ];
175
+ for (const row of rows) lines.push(`${vertical} ${innerWidth > 0 ? padToWidth(row, innerWidth) : ""} ${vertical}`);
176
+ lines.push(outlineRule(theme.boxRound.bottomLeft, theme.boxRound.bottomRight, innerWidth, color));
177
+ return lines;
178
+ }
179
+
180
+ /**
181
+ * Compose one column: gutter-prefixed rows for `childRows[from, to)` with a
182
+ * dotted outline around `targets[selected]`. `header` rows, when given, lead
183
+ * the column.
184
+ */
185
+ export function composeOutlineColumn(
186
+ childRows: readonly (readonly string[])[],
187
+ from: number,
188
+ to: number,
189
+ targets: readonly OutlineTarget[],
190
+ selected: number,
191
+ columnWidth: number,
192
+ header: string[] | undefined,
193
+ style: OutlineStyle = {},
194
+ ): ComposedColumn {
195
+ const inner = Math.max(10, columnWidth - 4);
196
+ const lines: string[] = header ? [...header] : [];
197
+ let selStart = -1;
198
+ let selEnd = -1;
199
+ const target = selected >= 0 ? targets[selected] : undefined;
200
+ for (let index = from; index < to; index++) {
201
+ if (target && index === target.start && target.end <= to) {
202
+ const segment: string[] = [];
203
+ for (let child = target.start; child < target.end; child++) segment.push(...childRows[child]!);
204
+ // Outline only the non-blank core; edge spacers stay outside.
205
+ let head = 0;
206
+ let tail = segment.length;
207
+ while (head < tail && !/\S/.test(segment[head]!)) head++;
208
+ while (tail > head && !/\S/.test(segment[tail - 1]!)) tail--;
209
+ for (let row = 0; row < head; row++) lines.push("");
210
+ selStart = lines.length;
211
+ lines.push(...outlineRows(segment.slice(head, tail), inner, style));
212
+ selEnd = lines.length;
213
+ for (let row = tail; row < segment.length; row++) lines.push("");
214
+ index = target.end - 1;
215
+ continue;
216
+ }
217
+ for (const row of childRows[index]!) lines.push(row ? ` ${row}` : row);
218
+ }
219
+ return { lines, selStart, selEnd };
220
+ }
221
+
222
+ /** Centered position rail for horizontally windowed content: `… ○ ◉ ○ …`. */
223
+ export function positionRail(
224
+ count: number,
225
+ active: number,
226
+ moreLeft: boolean,
227
+ moreRight: boolean,
228
+ width: number,
229
+ ): string {
230
+ const dots: string[] = [];
231
+ for (let index = 0; index < count; index++) {
232
+ dots.push(index === active ? theme.fg("accent", theme.radio.selected) : theme.fg("dim", theme.radio.unselected));
233
+ }
234
+ const rail = `${moreLeft ? theme.fg("dim", "… ") : " "}${dots.join(" ")}${moreRight ? theme.fg("dim", " …") : ""}`;
235
+ const pad = Math.max(0, Math.floor((width - visibleWidth(rail)) / 2));
236
+ return " ".repeat(pad) + rail;
237
+ }
238
+
239
+ /**
240
+ * A turn the user can rewind past and re-edit: a user message with prompt
241
+ * text, or a user-initiated custom message (skill / collab prompt).
242
+ */
243
+ export function isUserTurnEntry(entry: TranscriptEntry): boolean {
244
+ if (entry.type === "message" && entry.message.role === "user") return userMessageHasText(entry.message);
245
+ return isUserRequestEntry(entry);
246
+ }
247
+
248
+ /** Single-line label for a user turn: its prompt text, or the custom message's draft. */
249
+ export function userTurnLabel(entry: TranscriptEntry): string | undefined {
250
+ if (entry.type === "message" && entry.message.role === "user") return userMessageLabel(entry.message.content);
251
+ const draft = userTurnDraft(entry);
252
+ return draft === undefined ? undefined : userMessageLabel(draft);
253
+ }
254
+
255
+ /** Whether a user message carries prompt text (string or text blocks). */
256
+ export function userMessageHasText(message: SessionMessageEntry["message"]): boolean {
257
+ if (message.role !== "user") return false;
258
+ if (typeof message.content === "string") return message.content.trim().length > 0;
259
+ return message.content.some(block => block.type === "text" && block.text.trim().length > 0);
260
+ }