@bubblebrain-ai/bubble 0.0.52 → 0.0.54

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 (483) hide show
  1. package/README.md +4 -12
  2. package/dist/agent/routing-catalog.js +3 -2
  3. package/dist/agent/subagent/router.js +5 -0
  4. package/dist/agent/subagent/runtime.d.ts +1 -0
  5. package/dist/agent/subagent/runtime.js +13 -1
  6. package/dist/agent/subagent-control.d.ts +4 -0
  7. package/dist/agent/subagent-control.js +1 -0
  8. package/dist/agent/subagent-store.js +2 -0
  9. package/dist/agent/workflow/control.d.ts +2 -0
  10. package/dist/agent/workflow/runs.d.ts +1 -0
  11. package/dist/agent/workflow/runs.js +3 -0
  12. package/dist/agent.d.ts +11 -1
  13. package/dist/agent.js +158 -57
  14. package/dist/bin.js +2 -44
  15. package/dist/config.d.ts +14 -1
  16. package/dist/config.js +45 -4
  17. package/dist/context/budget.d.ts +7 -1
  18. package/dist/context/budget.js +25 -2
  19. package/dist/context/compact-llm.d.ts +1 -1
  20. package/dist/context/compact-llm.js +5 -2
  21. package/dist/context/overflow.js +2 -0
  22. package/dist/context/projector.d.ts +8 -0
  23. package/dist/context/projector.js +55 -6
  24. package/dist/context/tool-output-truncate.d.ts +17 -1
  25. package/dist/context/tool-output-truncate.js +171 -49
  26. package/dist/feishu/agent-host/run-driver.js +3 -0
  27. package/dist/feishu/serve.js +2 -0
  28. package/dist/goal/command.d.ts +1 -1
  29. package/dist/goal/command.js +7 -2
  30. package/dist/main.d.ts +1 -1
  31. package/dist/main.js +38 -8
  32. package/dist/memory/db.js +0 -7
  33. package/dist/model-catalog.js +25 -6
  34. package/dist/model-config.js +3 -2
  35. package/dist/model-pricing.d.ts +24 -5
  36. package/dist/model-pricing.js +0 -0
  37. package/dist/model-selection.js +13 -4
  38. package/dist/network/chatgpt-transport.js +0 -34
  39. package/dist/network/errors.d.ts +19 -0
  40. package/dist/network/errors.js +24 -0
  41. package/dist/network/provider-transport.d.ts +0 -4
  42. package/dist/network/provider-transport.js +3 -35
  43. package/dist/network/retry.d.ts +6 -1
  44. package/dist/network/retry.js +9 -0
  45. package/dist/provider-model-policy.d.ts +16 -0
  46. package/dist/provider-model-policy.js +33 -0
  47. package/dist/provider-registry.d.ts +1 -1
  48. package/dist/provider-registry.js +73 -10
  49. package/dist/provider-transform.js +32 -4
  50. package/dist/provider.d.ts +6 -2
  51. package/dist/provider.js +95 -6
  52. package/dist/question/controller.js +5 -4
  53. package/dist/question/normalize.d.ts +6 -0
  54. package/dist/question/normalize.js +11 -0
  55. package/dist/rewind.d.ts +20 -0
  56. package/dist/rewind.js +29 -0
  57. package/dist/sdk/index.d.ts +1 -1
  58. package/dist/sdk/index.js +11 -3
  59. package/dist/session.d.ts +7 -0
  60. package/dist/session.js +20 -0
  61. package/dist/skills/discovery.js +18 -0
  62. package/dist/skills/registry.d.ts +12 -2
  63. package/dist/skills/registry.js +40 -5
  64. package/dist/skills/types.d.ts +2 -0
  65. package/dist/slash-commands/commands.js +120 -81
  66. package/dist/slash-commands/registry.d.ts +2 -1
  67. package/dist/slash-commands/registry.js +3 -0
  68. package/dist/slash-commands/types.d.ts +22 -4
  69. package/dist/stats/usage.d.ts +3 -1
  70. package/dist/stats/usage.js +22 -13
  71. package/dist/tasks/manager.d.ts +4 -2
  72. package/dist/tasks/manager.js +34 -9
  73. package/dist/tasks/promotion.d.ts +2 -2
  74. package/dist/tasks/promotion.js +2 -2
  75. package/dist/tools/agent-lifecycle.js +4 -0
  76. package/dist/tools/bash.d.ts +3 -1
  77. package/dist/tools/bash.js +13 -2
  78. package/dist/tools/grep.d.ts +5 -1
  79. package/dist/tools/grep.js +318 -69
  80. package/dist/tools/index.d.ts +3 -1
  81. package/dist/tools/index.js +1 -0
  82. package/dist/tools/question.js +5 -4
  83. package/dist/tools/read.js +40 -21
  84. package/dist/tui/animation-clock.d.ts +14 -0
  85. package/dist/tui/animation-clock.js +34 -0
  86. package/dist/tui/app.d.ts +176 -0
  87. package/dist/tui/app.js +1647 -0
  88. package/dist/tui/components/approval-dialog.d.ts +43 -0
  89. package/dist/tui/components/approval-dialog.js +247 -0
  90. package/dist/tui/components/bottom-sheet.d.ts +9 -0
  91. package/dist/tui/components/bottom-sheet.js +32 -0
  92. package/dist/tui/components/context-info.d.ts +54 -0
  93. package/dist/tui/components/context-info.js +388 -0
  94. package/dist/tui/components/feedback-dialog.d.ts +56 -0
  95. package/dist/tui/components/feedback-dialog.js +262 -0
  96. package/dist/tui/components/feishu-setup-dialog.d.ts +65 -0
  97. package/dist/tui/components/feishu-setup-dialog.js +332 -0
  98. package/dist/tui/components/image-preview.d.ts +32 -0
  99. package/dist/tui/components/image-preview.js +130 -0
  100. package/dist/tui/components/plan-dialog.d.ts +34 -0
  101. package/dist/tui/components/plan-dialog.js +196 -0
  102. package/dist/tui/components/provider-key-input.d.ts +18 -0
  103. package/dist/tui/components/provider-key-input.js +49 -0
  104. package/dist/tui/components/question-dialog.d.ts +25 -0
  105. package/dist/tui/components/question-dialog.js +263 -0
  106. package/dist/tui/components/responsive-transcript.d.ts +31 -0
  107. package/dist/tui/components/responsive-transcript.js +77 -0
  108. package/dist/tui/components/rewind-picker.d.ts +62 -0
  109. package/dist/tui/components/rewind-picker.js +317 -0
  110. package/dist/tui/components/session-picker.d.ts +49 -0
  111. package/dist/tui/components/session-picker.js +303 -0
  112. package/dist/tui/components/skills-panel.d.ts +59 -0
  113. package/dist/tui/components/skills-panel.js +568 -0
  114. package/dist/tui/components/stats-panel.d.ts +40 -0
  115. package/dist/tui/components/stats-panel.js +301 -0
  116. package/dist/tui/components/streaming-message.d.ts +69 -0
  117. package/dist/tui/components/streaming-message.js +393 -0
  118. package/dist/tui/components/subagent-inspector.d.ts +28 -0
  119. package/dist/tui/components/subagent-inspector.js +127 -0
  120. package/dist/tui/components/task-inspector.d.ts +26 -0
  121. package/dist/tui/components/task-inspector.js +70 -0
  122. package/dist/tui/components/tasks-pane.d.ts +88 -0
  123. package/dist/tui/components/tasks-pane.js +416 -0
  124. package/dist/tui/components/transcript.d.ts +96 -0
  125. package/dist/tui/components/transcript.js +771 -0
  126. package/dist/tui/components/welcome.d.ts +20 -0
  127. package/dist/tui/components/welcome.js +133 -0
  128. package/dist/tui/components/workflow-inspector.d.ts +30 -0
  129. package/dist/tui/components/workflow-inspector.js +136 -0
  130. package/dist/tui/composer-autocomplete.d.ts +61 -0
  131. package/dist/tui/composer-autocomplete.js +383 -0
  132. package/dist/tui/composer-style.d.ts +7 -0
  133. package/dist/tui/composer-style.js +29 -0
  134. package/dist/tui/controller/agent-event-reducer.d.ts +75 -0
  135. package/dist/tui/controller/agent-event-reducer.js +238 -0
  136. package/dist/tui/controller/composer-controller.d.ts +95 -0
  137. package/dist/tui/controller/composer-controller.js +502 -0
  138. package/dist/tui/controller/controller.d.ts +194 -0
  139. package/dist/tui/controller/controller.js +1035 -0
  140. package/dist/tui/controller/effects.d.ts +71 -0
  141. package/dist/tui/controller/effects.js +1 -0
  142. package/dist/tui/controller/goal-runtime-controller.d.ts +47 -0
  143. package/dist/tui/controller/goal-runtime-controller.js +202 -0
  144. package/dist/tui/controller/input-queue-machine.d.ts +71 -0
  145. package/dist/tui/controller/input-queue-machine.js +121 -0
  146. package/dist/tui/controller/intents.d.ts +56 -0
  147. package/dist/tui/controller/intents.js +6 -0
  148. package/dist/tui/controller/overlay-controller.d.ts +64 -0
  149. package/dist/tui/controller/overlay-controller.js +129 -0
  150. package/dist/tui/controller/ports.d.ts +57 -0
  151. package/dist/tui/controller/ports.js +9 -0
  152. package/dist/tui/controller/session-transition.d.ts +54 -0
  153. package/dist/tui/controller/session-transition.js +68 -0
  154. package/dist/tui/controller/state.d.ts +14 -0
  155. package/dist/tui/controller/state.js +36 -0
  156. package/dist/tui/controller/task-runtime-controller.d.ts +66 -0
  157. package/dist/tui/controller/task-runtime-controller.js +158 -0
  158. package/dist/tui/footer.d.ts +37 -0
  159. package/dist/tui/footer.js +80 -0
  160. package/dist/{tui-ink → tui/formatting}/edit-diff.d.ts +1 -1
  161. package/dist/{tui-ink → tui/formatting}/edit-diff.js +1 -1
  162. package/dist/{tui-ink/app-helpers.d.ts → tui/formatting/summary.d.ts} +4 -4
  163. package/dist/{tui-ink/app-helpers.js → tui/formatting/summary.js} +2 -2
  164. package/dist/tui/fullscreen.d.ts +48 -0
  165. package/dist/tui/fullscreen.js +255 -0
  166. package/dist/tui/image-display.d.ts +4 -0
  167. package/dist/tui/image-display.js +30 -12
  168. package/dist/tui/markdown-style.d.ts +5 -0
  169. package/dist/tui/markdown-style.js +23 -0
  170. package/dist/{tui-ink → tui/model}/composer-buffer.js +1 -1
  171. package/dist/tui/model/composer-types.d.ts +17 -0
  172. package/dist/tui/model/composer-types.js +1 -0
  173. package/dist/{tui-ink → tui/model}/display-history.d.ts +7 -1
  174. package/dist/{tui-ink → tui/model}/display-reconstruct.d.ts +1 -1
  175. package/dist/{tui-ink → tui/model}/display-reconstruct.js +54 -6
  176. package/dist/{tui-ink → tui/model}/file-mentions.d.ts +2 -0
  177. package/dist/{tui-ink → tui/model}/file-mentions.js +4 -0
  178. package/dist/tui/model/image-attachment.d.ts +15 -0
  179. package/dist/tui/model/image-attachment.js +1 -0
  180. package/dist/{tui-ink → tui/model}/image-paste.d.ts +7 -1
  181. package/dist/{tui-ink → tui/model}/image-paste.js +46 -0
  182. package/dist/tui/model/input-history.d.ts +1 -0
  183. package/dist/tui/model/input-history.js +1 -0
  184. package/dist/{tui-ink → tui/model}/input-queue.d.ts +1 -1
  185. package/dist/{tui-ink → tui/model}/recent-activity.js +1 -1
  186. package/dist/{tui-ink → tui/model}/subagent-view.d.ts +17 -2
  187. package/dist/{tui-ink → tui/model}/subagent-view.js +125 -4
  188. package/dist/{tui-ink → tui/model}/submit-dedupe.d.ts +1 -1
  189. package/dist/tui/model/theme-style.d.ts +10 -0
  190. package/dist/tui/model/theme-style.js +79 -0
  191. package/dist/{tui-ink → tui/model}/theme.d.ts +11 -23
  192. package/dist/{tui-ink → tui/model}/theme.js +23 -38
  193. package/dist/{tui-ink → tui/model}/trace-groups.d.ts +2 -0
  194. package/dist/{tui-ink → tui/model}/trace-groups.js +91 -30
  195. package/dist/tui/model/trace-interaction.d.ts +63 -0
  196. package/dist/tui/model/trace-interaction.js +87 -0
  197. package/dist/tui/model-picker-data.d.ts +1 -2
  198. package/dist/tui/model-picker-data.js +8 -1
  199. package/dist/tui/model-switch.js +2 -0
  200. package/dist/{tui-ink → tui}/run-session-picker.d.ts +2 -3
  201. package/dist/tui/run-session-picker.js +64 -0
  202. package/dist/tui/run.d.ts +72 -0
  203. package/dist/tui/run.js +139 -0
  204. package/dist/tui/terminal/multiplexer.d.ts +5 -0
  205. package/dist/tui/terminal/multiplexer.js +14 -0
  206. package/dist/tui/testing/fake-agent.d.ts +24 -0
  207. package/dist/tui/testing/fake-agent.js +22 -0
  208. package/dist/tui/testing/spy-host.d.ts +21 -0
  209. package/dist/tui/testing/spy-host.js +55 -0
  210. package/dist/tui/trace-groups.js +27 -6
  211. package/dist/types.d.ts +7 -0
  212. package/dist/update/index.d.ts +1 -0
  213. package/dist/update/index.js +22 -17
  214. package/node_modules/@bubblebrain-ai/pi-tui/LICENSE +21 -0
  215. package/node_modules/@bubblebrain-ai/pi-tui/README.md +854 -0
  216. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/alt-screen-search.d.ts +26 -0
  217. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/alt-screen-search.d.ts.map +1 -0
  218. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/alt-screen-search.js +121 -0
  219. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/alt-screen-search.js.map +1 -0
  220. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/autocomplete.d.ts +86 -0
  221. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/autocomplete.d.ts.map +1 -0
  222. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/autocomplete.js +649 -0
  223. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/autocomplete.js.map +1 -0
  224. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/alt-screen-flash.d.ts +13 -0
  225. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/alt-screen-flash.d.ts.map +1 -0
  226. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/alt-screen-flash.js +36 -0
  227. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/alt-screen-flash.js.map +1 -0
  228. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/box.d.ts +22 -0
  229. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/box.d.ts.map +1 -0
  230. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/box.js +99 -0
  231. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/box.js.map +1 -0
  232. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/cancellable-loader.d.ts +22 -0
  233. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/cancellable-loader.d.ts.map +1 -0
  234. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/cancellable-loader.js +36 -0
  235. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/cancellable-loader.js.map +1 -0
  236. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/editor.d.ts +330 -0
  237. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/editor.d.ts.map +1 -0
  238. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/editor.js +2344 -0
  239. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/editor.js.map +1 -0
  240. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/h-stack.d.ts +7 -0
  241. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/h-stack.d.ts.map +1 -0
  242. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/h-stack.js +43 -0
  243. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/h-stack.js.map +1 -0
  244. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/image.d.ts +28 -0
  245. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/image.d.ts.map +1 -0
  246. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/image.js +82 -0
  247. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/image.js.map +1 -0
  248. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/input.d.ts +48 -0
  249. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/input.d.ts.map +1 -0
  250. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/input.js +390 -0
  251. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/input.js.map +1 -0
  252. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/loader.d.ts +31 -0
  253. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/loader.d.ts.map +1 -0
  254. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/loader.js +67 -0
  255. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/loader.js.map +1 -0
  256. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/markdown.d.ts +103 -0
  257. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/markdown.d.ts.map +1 -0
  258. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/markdown.js +797 -0
  259. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/markdown.js.map +1 -0
  260. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/scroll-view.d.ts +56 -0
  261. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/scroll-view.d.ts.map +1 -0
  262. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/scroll-view.js +179 -0
  263. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/scroll-view.js.map +1 -0
  264. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/select-list.d.ts +53 -0
  265. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/select-list.d.ts.map +1 -0
  266. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/select-list.js +175 -0
  267. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/select-list.js.map +1 -0
  268. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/settings-list.d.ts +50 -0
  269. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/settings-list.d.ts.map +1 -0
  270. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/settings-list.js +174 -0
  271. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/settings-list.js.map +1 -0
  272. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/spacer.d.ts +12 -0
  273. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/spacer.d.ts.map +1 -0
  274. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/spacer.js +22 -0
  275. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/spacer.js.map +1 -0
  276. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/stack.d.ts +32 -0
  277. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/stack.d.ts.map +1 -0
  278. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/stack.js +109 -0
  279. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/stack.js.map +1 -0
  280. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/text.d.ts +19 -0
  281. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/text.d.ts.map +1 -0
  282. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/text.js +81 -0
  283. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/text.js.map +1 -0
  284. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/truncated-text.d.ts +13 -0
  285. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/truncated-text.d.ts.map +1 -0
  286. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/truncated-text.js +48 -0
  287. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/truncated-text.js.map +1 -0
  288. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/v-stack.d.ts +8 -0
  289. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/v-stack.d.ts.map +1 -0
  290. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/v-stack.js +26 -0
  291. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/v-stack.js.map +1 -0
  292. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/editor-component.d.ts +39 -0
  293. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/editor-component.d.ts.map +1 -0
  294. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/editor-component.js +2 -0
  295. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/editor-component.js.map +1 -0
  296. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/fuzzy.d.ts +16 -0
  297. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/fuzzy.d.ts.map +1 -0
  298. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/fuzzy.js +110 -0
  299. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/fuzzy.js.map +1 -0
  300. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/index.d.ts +31 -0
  301. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/index.d.ts.map +1 -0
  302. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/index.js +42 -0
  303. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/index.js.map +1 -0
  304. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keybindings.d.ts +273 -0
  305. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keybindings.d.ts.map +1 -0
  306. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keybindings.js +231 -0
  307. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keybindings.js.map +1 -0
  308. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keys.d.ts +184 -0
  309. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keys.d.ts.map +1 -0
  310. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keys.js +1174 -0
  311. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keys.js.map +1 -0
  312. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/kill-ring.d.ts +28 -0
  313. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/kill-ring.d.ts.map +1 -0
  314. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/kill-ring.js +46 -0
  315. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/kill-ring.js.map +1 -0
  316. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/latex.d.ts +10 -0
  317. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/latex.d.ts.map +1 -0
  318. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/latex.js +1268 -0
  319. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/latex.js.map +1 -0
  320. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout-node.d.ts +40 -0
  321. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout-node.d.ts.map +1 -0
  322. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout-node.js +6 -0
  323. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout-node.js.map +1 -0
  324. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout.d.ts +42 -0
  325. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout.d.ts.map +1 -0
  326. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout.js +335 -0
  327. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout.js.map +1 -0
  328. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/native-modifiers.d.ts +3 -0
  329. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/native-modifiers.d.ts.map +1 -0
  330. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/native-modifiers.js +60 -0
  331. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/native-modifiers.js.map +1 -0
  332. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/stdin-buffer.d.ts +56 -0
  333. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/stdin-buffer.d.ts.map +1 -0
  334. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/stdin-buffer.js +363 -0
  335. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/stdin-buffer.js.map +1 -0
  336. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-colors.d.ts +10 -0
  337. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-colors.d.ts.map +1 -0
  338. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-colors.js +59 -0
  339. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-colors.js.map +1 -0
  340. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-image.d.ts +116 -0
  341. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-image.d.ts.map +1 -0
  342. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-image.js +518 -0
  343. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-image.js.map +1 -0
  344. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal.d.ts +142 -0
  345. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal.d.ts.map +1 -0
  346. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal.js +544 -0
  347. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal.js.map +1 -0
  348. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/testing.d.ts +11 -0
  349. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/testing.d.ts.map +1 -0
  350. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/testing.js +11 -0
  351. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/testing.js.map +1 -0
  352. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-alt-screen.d.ts +140 -0
  353. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-alt-screen.d.ts.map +1 -0
  354. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-alt-screen.js +1334 -0
  355. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-alt-screen.js.map +1 -0
  356. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-main-screen.d.ts +39 -0
  357. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-main-screen.d.ts.map +1 -0
  358. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-main-screen.js +536 -0
  359. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-main-screen.js.map +1 -0
  360. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui.d.ts +338 -0
  361. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui.d.ts.map +1 -0
  362. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui.js +1016 -0
  363. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui.js.map +1 -0
  364. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/undo-stack.d.ts +17 -0
  365. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/undo-stack.d.ts.map +1 -0
  366. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/undo-stack.js +27 -0
  367. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/undo-stack.js.map +1 -0
  368. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/utils.d.ts +96 -0
  369. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/utils.d.ts.map +1 -0
  370. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/utils.js +1193 -0
  371. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/utils.js.map +1 -0
  372. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/word-navigation.d.ts +25 -0
  373. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/word-navigation.d.ts.map +1 -0
  374. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/word-navigation.js +96 -0
  375. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/word-navigation.js.map +1 -0
  376. package/node_modules/@bubblebrain-ai/pi-tui/dist/test/virtual-terminal.d.ts +73 -0
  377. package/node_modules/@bubblebrain-ai/pi-tui/dist/test/virtual-terminal.d.ts.map +1 -0
  378. package/node_modules/@bubblebrain-ai/pi-tui/dist/test/virtual-terminal.js +188 -0
  379. package/node_modules/@bubblebrain-ai/pi-tui/dist/test/virtual-terminal.js.map +1 -0
  380. package/node_modules/@bubblebrain-ai/pi-tui/native/darwin/README.md +20 -0
  381. package/node_modules/@bubblebrain-ai/pi-tui/native/darwin/build.sh +62 -0
  382. package/node_modules/@bubblebrain-ai/pi-tui/native/darwin/prebuilds/darwin-arm64/darwin-modifiers.node +0 -0
  383. package/node_modules/@bubblebrain-ai/pi-tui/native/darwin/prebuilds/darwin-x64/darwin-modifiers.node +0 -0
  384. package/node_modules/@bubblebrain-ai/pi-tui/native/darwin/src/darwin-modifiers.c +70 -0
  385. package/node_modules/@bubblebrain-ai/pi-tui/native/win32/README.md +22 -0
  386. package/node_modules/@bubblebrain-ai/pi-tui/native/win32/build.mjs +229 -0
  387. package/node_modules/@bubblebrain-ai/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
  388. package/node_modules/@bubblebrain-ai/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
  389. package/node_modules/@bubblebrain-ai/pi-tui/native/win32/src/win32-console-mode.c +119 -0
  390. package/node_modules/@bubblebrain-ai/pi-tui/package.json +66 -0
  391. package/node_modules/get-east-asian-width/index.d.ts +60 -0
  392. package/node_modules/get-east-asian-width/index.js +30 -0
  393. package/node_modules/get-east-asian-width/license +9 -0
  394. package/node_modules/get-east-asian-width/lookup-data.js +21 -0
  395. package/node_modules/get-east-asian-width/lookup.js +138 -0
  396. package/node_modules/get-east-asian-width/package.json +71 -0
  397. package/node_modules/get-east-asian-width/readme.md +65 -0
  398. package/node_modules/get-east-asian-width/utilities.js +24 -0
  399. package/node_modules/marked/LICENSE +44 -0
  400. package/node_modules/marked/README.md +115 -0
  401. package/node_modules/marked/bin/main.js +284 -0
  402. package/node_modules/marked/bin/marked.js +16 -0
  403. package/node_modules/marked/lib/marked.d.ts +760 -0
  404. package/node_modules/marked/lib/marked.esm.js +77 -0
  405. package/node_modules/marked/lib/marked.esm.js.map +7 -0
  406. package/node_modules/marked/lib/marked.umd.js +79 -0
  407. package/node_modules/marked/lib/marked.umd.js.map +7 -0
  408. package/node_modules/marked/man/marked.1 +113 -0
  409. package/node_modules/marked/man/marked.1.md +93 -0
  410. package/node_modules/marked/package.json +103 -0
  411. package/package.json +25 -10
  412. package/dist/tui-ink/app.d.ts +0 -76
  413. package/dist/tui-ink/app.js +0 -2377
  414. package/dist/tui-ink/approval/approval-dialog.d.ts +0 -13
  415. package/dist/tui-ink/approval/approval-dialog.js +0 -184
  416. package/dist/tui-ink/approval/diff-view.d.ts +0 -7
  417. package/dist/tui-ink/approval/diff-view.js +0 -44
  418. package/dist/tui-ink/approval/select.d.ts +0 -35
  419. package/dist/tui-ink/approval/select.js +0 -98
  420. package/dist/tui-ink/code-highlight.d.ts +0 -8
  421. package/dist/tui-ink/code-highlight.js +0 -121
  422. package/dist/tui-ink/command-palette.d.ts +0 -32
  423. package/dist/tui-ink/command-palette.js +0 -158
  424. package/dist/tui-ink/compaction-progress.d.ts +0 -19
  425. package/dist/tui-ink/compaction-progress.js +0 -74
  426. package/dist/tui-ink/detect-theme.d.ts +0 -1
  427. package/dist/tui-ink/detect-theme.js +0 -1
  428. package/dist/tui-ink/feedback-dialog.d.ts +0 -19
  429. package/dist/tui-ink/feedback-dialog.js +0 -133
  430. package/dist/tui-ink/feishu-setup-picker.d.ts +0 -5
  431. package/dist/tui-ink/feishu-setup-picker.js +0 -271
  432. package/dist/tui-ink/footer.d.ts +0 -26
  433. package/dist/tui-ink/footer.js +0 -51
  434. package/dist/tui-ink/input-box.d.ts +0 -189
  435. package/dist/tui-ink/input-box.js +0 -1279
  436. package/dist/tui-ink/input-history.d.ts +0 -1
  437. package/dist/tui-ink/input-history.js +0 -1
  438. package/dist/tui-ink/markdown.d.ts +0 -103
  439. package/dist/tui-ink/markdown.js +0 -747
  440. package/dist/tui-ink/message-list.d.ts +0 -49
  441. package/dist/tui-ink/message-list.js +0 -841
  442. package/dist/tui-ink/model-picker.d.ts +0 -143
  443. package/dist/tui-ink/model-picker.js +0 -966
  444. package/dist/tui-ink/plan-confirm.d.ts +0 -7
  445. package/dist/tui-ink/plan-confirm.js +0 -115
  446. package/dist/tui-ink/question-dialog.d.ts +0 -8
  447. package/dist/tui-ink/question-dialog.js +0 -135
  448. package/dist/tui-ink/rewind-picker.d.ts +0 -8
  449. package/dist/tui-ink/rewind-picker.js +0 -102
  450. package/dist/tui-ink/run-session-picker.js +0 -22
  451. package/dist/tui-ink/run.d.ts +0 -62
  452. package/dist/tui-ink/run.js +0 -103
  453. package/dist/tui-ink/session-picker.d.ts +0 -10
  454. package/dist/tui-ink/session-picker.js +0 -113
  455. package/dist/tui-ink/stats-panel.d.ts +0 -11
  456. package/dist/tui-ink/stats-panel.js +0 -65
  457. package/dist/tui-ink/subagent-inspector.d.ts +0 -21
  458. package/dist/tui-ink/subagent-inspector.js +0 -205
  459. package/dist/tui-ink/use-terminal-size.d.ts +0 -4
  460. package/dist/tui-ink/use-terminal-size.js +0 -48
  461. package/dist/tui-ink/waiting-indicator.d.ts +0 -12
  462. package/dist/tui-ink/waiting-indicator.js +0 -129
  463. package/dist/tui-ink/welcome.d.ts +0 -25
  464. package/dist/tui-ink/welcome.js +0 -88
  465. package/dist/tui-ink/wordmark.d.ts +0 -8
  466. package/dist/tui-ink/wordmark.js +0 -103
  467. /package/dist/{tui-ink → tui/model}/composer-buffer.d.ts +0 -0
  468. /package/dist/{tui-ink → tui/model}/display-history.js +0 -0
  469. /package/dist/{tui-ink → tui/model}/input-queue.js +0 -0
  470. /package/dist/{tui-ink → tui/model}/key-events.d.ts +0 -0
  471. /package/dist/{tui-ink → tui/model}/key-events.js +0 -0
  472. /package/dist/{tui-ink → tui/model}/paste-operation-tracker.d.ts +0 -0
  473. /package/dist/{tui-ink → tui/model}/paste-operation-tracker.js +0 -0
  474. /package/dist/{tui-ink → tui/model}/recent-activity.d.ts +0 -0
  475. /package/dist/{tui-ink → tui/model}/submit-dedupe.js +0 -0
  476. /package/dist/{tui-ink → tui/model}/sync-output.d.ts +0 -0
  477. /package/dist/{tui-ink → tui/model}/sync-output.js +0 -0
  478. /package/dist/{tui-ink → tui/model}/terminal-env.d.ts +0 -0
  479. /package/dist/{tui-ink → tui/model}/terminal-env.js +0 -0
  480. /package/dist/{tui-ink → tui/model}/terminal-mouse.d.ts +0 -0
  481. /package/dist/{tui-ink → tui/model}/terminal-mouse.js +0 -0
  482. /package/dist/{tui-ink → tui/model}/width.d.ts +0 -0
  483. /package/dist/{tui-ink → tui/model}/width.js +0 -0
@@ -0,0 +1,80 @@
1
+ /** Shared footer line renderer (main + fullscreen modes). */
2
+ import chalk from "chalk";
3
+ import { truncateToWidth } from "@bubblebrain-ai/pi-tui";
4
+ import { formatContextUsageLabel, friendlyCwd } from "./formatting/summary.js";
5
+ import { PERMISSION_MODE_INFO } from "../permission/mode.js";
6
+ import { classifyExternalRuntimeBinding } from "../external-runtime/session-policy.js";
7
+ import { darkTheme } from "./model/theme.js";
8
+ import { themeDim, themeForeground } from "./model/theme-style.js";
9
+ /** Width-responsive single-row footer shared by main and fullscreen TUIs. */
10
+ export class ResponsiveFooterComponent {
11
+ getSnapshot;
12
+ constructor(getSnapshot) {
13
+ this.getSnapshot = getSnapshot;
14
+ }
15
+ render(width) {
16
+ const snapshot = this.getSnapshot();
17
+ if (snapshot.hidden)
18
+ return [];
19
+ const rows = [];
20
+ const theme = snapshot.theme ?? darkTheme;
21
+ const muted = snapshot.theme ? (text) => themeDim(theme.dim, text) : chalk.dim;
22
+ if (snapshot.goalLine?.trim()) {
23
+ rows.push(truncateToWidth(muted(snapshot.goalLine.trim()), Math.max(1, Math.floor(width))));
24
+ }
25
+ if (snapshot.runtimeLabel?.trim()) {
26
+ rows.push(truncateToWidth(snapshot.theme ? themeForeground(theme.accent, snapshot.runtimeLabel.trim()) : chalk.cyan(snapshot.runtimeLabel.trim()), Math.max(1, Math.floor(width))));
27
+ }
28
+ rows.push(renderFooterLine(snapshot.agent, width, snapshot));
29
+ return rows;
30
+ }
31
+ invalidate() {
32
+ // No cache: terminal width, model, cwd, usage, and queue badges are live.
33
+ }
34
+ }
35
+ export function renderFooterLine(agent, columns, options = {}) {
36
+ const theme = options.theme ?? darkTheme;
37
+ const muted = options.theme ? (text) => themeDim(theme.dim, text) : chalk.dim;
38
+ const usage = formatContextUsageLabel(agent.getContextUsageSnapshot());
39
+ const cwd = options.cwd ?? friendlyCwd(process.cwd());
40
+ const mode = renderPermissionModeBadge(options.mode);
41
+ const nativeDetails = !options.runtimeLabel?.trim();
42
+ const parts = [
43
+ ...(mode ? [mode] : []),
44
+ ...(nativeDetails && agent.model ? [muted(agent.model)] : []),
45
+ muted(cwd),
46
+ ...(options.branch?.trim() ? [muted(options.branch.trim())] : []),
47
+ ...(nativeDetails && options.sessionTitle?.trim() ? [muted(options.sessionTitle.trim())] : []),
48
+ ...(nativeDetails && usage ? [muted(usage)] : []),
49
+ ...(options.extra ?? []),
50
+ ];
51
+ const line = parts.join(muted(" │ "));
52
+ return truncateToWidth(line, Math.max(1, Math.floor(columns)));
53
+ }
54
+ /** Match the legacy footer contract for persisted external-runtime sessions. */
55
+ export function formatExternalRuntimeFooterLabel(binding) {
56
+ const kind = classifyExternalRuntimeBinding(binding);
57
+ if (kind === "none")
58
+ return undefined;
59
+ if (kind === "unsupported")
60
+ return "Unsupported external runtime · recovery-only";
61
+ const record = binding && typeof binding === "object"
62
+ ? binding
63
+ : undefined;
64
+ const model = typeof record?.modelId === "string" && record.modelId.trim()
65
+ ? record.modelId.trim()
66
+ : undefined;
67
+ const effort = typeof record?.reasoningEffort === "string"
68
+ && record.reasoningEffort.trim()
69
+ && record.reasoningEffort !== "off"
70
+ ? record.reasoningEffort.trim()
71
+ : undefined;
72
+ return ["Grok Subscription", model, effort, "workspace"].filter(Boolean).join(" · ");
73
+ }
74
+ export function renderPermissionModeBadge(mode) {
75
+ if (!mode || mode === "default")
76
+ return "";
77
+ const info = PERMISSION_MODE_INFO[mode];
78
+ const label = `${info.symbol ? `${info.symbol} ` : ""}${info.shortTitle} on`;
79
+ return mode === "bypassPermissions" ? chalk.bold.red(label) : chalk.bold.cyan(label);
80
+ }
@@ -1,4 +1,4 @@
1
- import type { DisplayToolCall } from "./display-history.js";
1
+ import type { DisplayToolCall } from "../model/display-history.js";
2
2
  export declare const EDIT_COLLAPSED_DIFF_LINES = 20;
3
3
  export interface EditDiffDetails {
4
4
  diff: string;
@@ -1,4 +1,4 @@
1
- import { countUnifiedDiffChanges } from "../diff-stats.js";
1
+ import { countUnifiedDiffChanges } from "../../diff-stats.js";
2
2
  export const EDIT_COLLAPSED_DIFF_LINES = 20;
3
3
  export function getEditDiffDetails(tool) {
4
4
  if (tool.name !== "edit" || tool.isError)
@@ -1,7 +1,7 @@
1
- import type { Agent } from "../agent.js";
2
- import { type ProviderRegistry } from "../provider-registry.js";
3
- import type { BackgroundTaskInfo } from "../tasks/manager.js";
4
- import { type DisplayMessage } from "./display-history.js";
1
+ import type { Agent } from "../../agent.js";
2
+ import { type ProviderRegistry } from "../../provider-registry.js";
3
+ import type { BackgroundTaskInfo } from "../../tasks/manager.js";
4
+ import { type DisplayMessage } from "../model/display-history.js";
5
5
  export declare const TASK_WAKE_DEBOUNCE_MS = 2000;
6
6
  export declare function buildTips(agent: Agent, registry: ProviderRegistry, grokActive?: boolean): string[];
7
7
  /**
@@ -5,8 +5,8 @@
5
5
  * clamp shared by the picker overlays.
6
6
  */
7
7
  import os from "node:os";
8
- import { displayModel } from "../provider-registry.js";
9
- import { nextDisplayMessageKey } from "./display-history.js";
8
+ import { displayModel } from "../../provider-registry.js";
9
+ import { nextDisplayMessageKey } from "../model/display-history.js";
10
10
  export const TASK_WAKE_DEBOUNCE_MS = 2000;
11
11
  export function buildTips(agent, registry, grokActive = false) {
12
12
  const tips = [];
@@ -0,0 +1,48 @@
1
+ import { type Terminal } from "@bubblebrain-ai/pi-tui";
2
+ import type { BubbleTuiController } from "./controller/controller.js";
3
+ import type { Agent } from "../agent.js";
4
+ import { TraceInteractionState } from "./model/trace-interaction.js";
5
+ import type { ComposerController } from "./controller/composer-controller.js";
6
+ import { type Theme } from "./model/theme.js";
7
+ export interface FullscreenAppOptions {
8
+ controller: BubbleTuiController;
9
+ agent: Pick<Agent, "model" | "mode" | "setMode" | "getContextUsageSnapshot">;
10
+ onExit(): void;
11
+ /** Route non-mode slash commands through the main app's shared registry. */
12
+ onCommand(command: string): void;
13
+ /** Test/embedded host injection; production uses ProcessTerminal. */
14
+ terminal?: Terminal;
15
+ /** Preserve tool-group folds when switching from the regular renderer. */
16
+ traceInteraction?: TraceInteractionState;
17
+ /** Shared semantic composer state when transitioning from the main renderer. */
18
+ composer?: ComposerController;
19
+ /** Shared live palette when this view is entered from the regular renderer. */
20
+ getTheme?: () => Theme;
21
+ }
22
+ export declare class FullscreenApp {
23
+ private readonly options;
24
+ private readonly tui;
25
+ private readonly transcript;
26
+ private readonly streamingMessage;
27
+ private readonly animationClock;
28
+ private readonly editor;
29
+ private readonly composerPreview?;
30
+ private readonly footer;
31
+ private readonly traceInteraction;
32
+ private readonly markdown;
33
+ private readonly transcriptTheme;
34
+ private readonly markdownRenderer;
35
+ private readonly unsubscribe;
36
+ private showReasoning;
37
+ private verboseTrace;
38
+ private disposed;
39
+ private streamingMounted;
40
+ constructor(options: FullscreenAppOptions);
41
+ private buildLayout;
42
+ private openImageViewer;
43
+ render(): void;
44
+ private transcriptRenderOptions;
45
+ start(): void;
46
+ dispose(): void;
47
+ waitUntilExit(): Promise<void>;
48
+ }
@@ -0,0 +1,255 @@
1
+ /**
2
+ * Fullscreen (alternate-screen) mode on TuiAltScreen (rewrite/pi-tui).
3
+ *
4
+ * Complements the default main-screen chat flow: instead of appending to
5
+ * scrollback, the whole transcript lives in a viewport with follow-end,
6
+ * mouse-wheel scrolling, click-drag selection, and Ctrl+F transcript search
7
+ * (all provided by TuiAltScreen + ScrollView). The composer stays docked at
8
+ * the bottom via a layout root: [transcript scroll view, editor, footer].
9
+ *
10
+ * Toggle with /fullscreen; Escape exits back to the main screen.
11
+ */
12
+ import process from "node:process";
13
+ import { ProcessTerminal, TuiAltScreen, VStack, ScrollView, Editor, Markdown, matchesKey, isKeyRelease, } from "@bubblebrain-ai/pi-tui";
14
+ import { ResponsiveTranscriptComponent } from "./components/responsive-transcript.js";
15
+ import { StreamingMessageComponent } from "./components/streaming-message.js";
16
+ import { createTranscriptTheme } from "./components/transcript.js";
17
+ import { ResponsiveFooterComponent } from "./footer.js";
18
+ import { getNextPermissionMode } from "../permission/mode.js";
19
+ import { COMPOSER_EDITOR_OPTIONS, createComposerEditorTheme } from "./composer-style.js";
20
+ import { TraceInteractionState } from "./model/trace-interaction.js";
21
+ import { ComposerImagePreviewComponent, ImageViewerComponent } from "./components/image-preview.js";
22
+ import { createAssistantMarkdownTheme } from "./markdown-style.js";
23
+ import { darkTheme } from "./model/theme.js";
24
+ import { TuiAnimationClock } from "./animation-clock.js";
25
+ export class FullscreenApp {
26
+ options;
27
+ tui;
28
+ transcript;
29
+ streamingMessage;
30
+ animationClock;
31
+ editor;
32
+ composerPreview;
33
+ footer;
34
+ traceInteraction;
35
+ markdown;
36
+ transcriptTheme;
37
+ markdownRenderer = (text, width) => {
38
+ this.markdown.setText(text);
39
+ return this.markdown.render(width);
40
+ };
41
+ unsubscribe;
42
+ showReasoning = false;
43
+ verboseTrace = false;
44
+ disposed = false;
45
+ streamingMounted = false;
46
+ constructor(options) {
47
+ this.options = options;
48
+ const terminal = options.terminal ?? new ProcessTerminal();
49
+ const getTheme = options.getTheme ?? (() => darkTheme);
50
+ this.transcriptTheme = createTranscriptTheme(getTheme);
51
+ this.markdown = new Markdown("", 0, 0, createAssistantMarkdownTheme(getTheme));
52
+ this.traceInteraction = options.traceInteraction ?? new TraceInteractionState();
53
+ // Trace hover depends on no-button pointer motion, including inside tmux.
54
+ this.tui = new TuiAltScreen(terminal, undefined, undefined, { mouseMotion: "all" });
55
+ this.editor = new Editor(this.tui, createComposerEditorTheme(getTheme), COMPOSER_EDITOR_OPTIONS);
56
+ this.composerPreview = options.composer
57
+ ? new ComposerImagePreviewComponent(() => options.composer?.previewAttachment(), getTheme)
58
+ : undefined;
59
+ this.transcript = new ResponsiveTranscriptComponent(() => ({
60
+ messages: this.options.controller.getTranscript(),
61
+ options: this.transcriptRenderOptions(),
62
+ }), {
63
+ onTraceAction: (action) => {
64
+ if (action.kind !== "open-image")
65
+ return;
66
+ const message = this.options.controller.getTranscript().find((candidate) => candidate.key === action.messageKey);
67
+ const image = message?.images?.find((candidate) => candidate.label === action.imageLabel);
68
+ if (image)
69
+ this.openImageViewer(image);
70
+ },
71
+ });
72
+ this.streamingMessage = new StreamingMessageComponent(8, () => this.tui.requestRender(), undefined, getTheme);
73
+ this.animationClock = new TuiAnimationClock((elapsedMs) => {
74
+ if (this.streamingMessage.advanceAnimationFrame(elapsedMs))
75
+ this.tui.requestRender();
76
+ });
77
+ this.footer = new ResponsiveFooterComponent(() => ({
78
+ agent: this.options.agent,
79
+ mode: this.options.agent.mode,
80
+ goalLine: this.options.controller.getGoalIndicator?.(),
81
+ hidden: this.tui.terminal.rows <= 2,
82
+ theme: getTheme(),
83
+ }));
84
+ this.buildLayout();
85
+ this.unsubscribe = this.options.controller.subscribe(() => this.render());
86
+ }
87
+ buildLayout() {
88
+ // The live tail belongs inside the scrolling transcript. Its activity lane
89
+ // stays docked above the composer and keeps one row both running and idle,
90
+ // so clearing the spinner cannot pull settled content downward.
91
+ const transcriptBody = new VStack([this.transcript, this.streamingMessage]);
92
+ const scroll = new ScrollView(transcriptBody, { follow: "end", primary: true });
93
+ const layout = new VStack([
94
+ { component: scroll, basis: 0, grow: 1, minSize: 0 },
95
+ { component: this.streamingMessage.activityLane, basis: "auto", shrink: 0 },
96
+ ...(this.composerPreview ? [{ component: this.composerPreview, basis: "auto", shrink: 0 }] : []),
97
+ { component: this.editor, basis: "auto", shrink: 0 },
98
+ { component: this.footer, basis: "auto", shrink: 0 },
99
+ ]);
100
+ this.tui.setLayoutRoot(layout);
101
+ this.tui.setFocus(this.editor);
102
+ if (this.options.composer) {
103
+ this.options.composer.attachEditor(this.editor);
104
+ this.options.composer.setOpenImageHandler((image) => this.openImageViewer(image));
105
+ }
106
+ else
107
+ this.editor.onSubmit = (text) => {
108
+ const trimmed = text.trim();
109
+ if (!trimmed)
110
+ return;
111
+ this.editor.addToHistory(trimmed);
112
+ if (trimmed === "/fullscreen" || trimmed === "/main") {
113
+ this.options.onExit();
114
+ return;
115
+ }
116
+ if (trimmed.startsWith("/")) {
117
+ this.options.onCommand(trimmed);
118
+ return;
119
+ }
120
+ if (this.options.controller.isRunning()) {
121
+ this.options.controller.steer(trimmed);
122
+ }
123
+ else if (this.options.controller.queueAfterCommand?.(trimmed)) {
124
+ this.render();
125
+ }
126
+ else {
127
+ this.options.controller.appendDisplayMessage({ key: `user-${Date.now()}`, role: "user", content: trimmed });
128
+ void this.options.controller.runTurn(trimmed, process.cwd());
129
+ }
130
+ };
131
+ this.tui.addInputListener((data) => {
132
+ // Kitty reports key releases separately. Global shortcuts must only run
133
+ // on the press or Escape would cancel the run and exit on key-up.
134
+ if (isKeyRelease(data))
135
+ return { consume: true };
136
+ if (matchesKey(data, "shift+tab")) {
137
+ this.options.agent.setMode(getNextPermissionMode(this.options.agent.mode));
138
+ this.render();
139
+ return { consume: true };
140
+ }
141
+ if (matchesKey(data, "escape")) {
142
+ if (this.options.controller.cancelActiveRun()) {
143
+ return { consume: true };
144
+ }
145
+ if (this.options.controller.isBusy?.())
146
+ return { consume: true };
147
+ this.options.onExit();
148
+ return { consume: true };
149
+ }
150
+ if (matchesKey(data, "ctrl+c")) {
151
+ if (this.options.controller.cancelActiveRun()) {
152
+ return { consume: true };
153
+ }
154
+ if (this.options.controller.isBusy?.())
155
+ return { consume: true };
156
+ this.options.onExit();
157
+ return { consume: true };
158
+ }
159
+ if (data === "\x14") {
160
+ this.showReasoning = !this.showReasoning;
161
+ this.render();
162
+ return { consume: true };
163
+ }
164
+ if (data === "\x0f") {
165
+ this.verboseTrace = !this.verboseTrace;
166
+ this.render();
167
+ return { consume: true };
168
+ }
169
+ return undefined;
170
+ });
171
+ }
172
+ openImageViewer(image) {
173
+ let handle;
174
+ const close = () => {
175
+ handle?.hide();
176
+ this.tui.setFocus(this.editor);
177
+ this.render();
178
+ };
179
+ const component = new ImageViewerComponent(image, close, () => this.tui.terminal.rows, this.options.getTheme);
180
+ handle = this.tui.showOverlay(component, {
181
+ anchor: "center",
182
+ width: "70%",
183
+ minWidth: 36,
184
+ maxWidth: 110,
185
+ maxHeight: "85%",
186
+ margin: 1,
187
+ dismissOnOutsideClick: true,
188
+ });
189
+ this.tui.setFocus(component);
190
+ }
191
+ render() {
192
+ if (this.disposed)
193
+ return;
194
+ const columns = this.tui.terminal.columns || process.stdout.columns || 80;
195
+ const tail = this.options.controller.isRunning()
196
+ ? this.options.controller.getStreamingTail()
197
+ : null;
198
+ const commandActivity = this.options.controller.getCommandActivity?.() ?? null;
199
+ if (tail) {
200
+ if (!this.streamingMounted) {
201
+ this.streamingMounted = true;
202
+ this.streamingMessage.startSpinner();
203
+ }
204
+ this.streamingMessage.noteWidth(columns);
205
+ this.streamingMessage.update(tail, columns, this.transcriptRenderOptions());
206
+ }
207
+ else if (commandActivity) {
208
+ if (!this.streamingMounted) {
209
+ this.streamingMounted = true;
210
+ this.streamingMessage.startSpinner();
211
+ }
212
+ this.streamingMessage.noteWidth(columns);
213
+ this.streamingMessage.updateCommandActivity(commandActivity.kind === "compact" ? "Compacting" : commandActivity.kind, commandActivity.status === "cancelling", columns);
214
+ }
215
+ else if (this.streamingMounted) {
216
+ this.streamingMounted = false;
217
+ this.streamingMessage.clearToNothing();
218
+ }
219
+ this.animationClock.setActive(this.streamingMessage.isAnimationActive());
220
+ this.tui.requestRender();
221
+ }
222
+ transcriptRenderOptions() {
223
+ return {
224
+ theme: this.transcriptTheme,
225
+ showReasoning: this.showReasoning,
226
+ verboseTrace: this.verboseTrace,
227
+ traceInteraction: this.traceInteraction,
228
+ markdownRenderer: this.markdownRenderer,
229
+ // While running, this separates settled history from the live surface.
230
+ // Once settled, the permanent blank activity lane owns the dock gap.
231
+ trailingSpacer: this.options.controller.isRunning(),
232
+ };
233
+ }
234
+ start() {
235
+ this.tui.start();
236
+ this.render();
237
+ }
238
+ dispose() {
239
+ if (this.disposed)
240
+ return;
241
+ this.disposed = true;
242
+ this.unsubscribe();
243
+ this.animationClock.dispose();
244
+ this.streamingMessage.dispose();
245
+ // Returning to the host/main renderer must not copy the fullscreen dock
246
+ // (composer + footer) into terminal scrollback.
247
+ this.tui.stop({ preserveScreen: true });
248
+ }
249
+ async waitUntilExit() {
250
+ await new Promise(() => {
251
+ // Exit is driven by onExit (Escape/Ctrl+C//fullscreen); the promise
252
+ // resolves via dispose() from the host.
253
+ });
254
+ }
255
+ }
@@ -16,4 +16,8 @@ export declare function splitImageDisplayContent(content: string): {
16
16
  referenceLines: string[];
17
17
  };
18
18
  export declare function formatImageUserDisplayText(input: string, imageCount: number, labelStart?: number): string;
19
+ export declare function displayImagesFromPayload(payload: SubmitPayload): DisplayImageAttachment[];
20
+ export declare function imageAttachmentFromDataUrl(url: string): ImageAttachment | undefined;
19
21
  export declare function nextImageDisplayLabelStart(messages: Iterable<ImageDisplayMessage>): number;
22
+ import type { SubmitPayload } from "./model/composer-types.js";
23
+ import type { DisplayImageAttachment, ImageAttachment } from "./model/image-attachment.js";
@@ -46,18 +46,36 @@ export function formatImageUserDisplayText(input, imageCount, labelStart = 1) {
46
46
  if (imageCount <= 0)
47
47
  return input;
48
48
  const labels = imageDisplayLabels(imageCount, labelStart);
49
- const base = input.trim();
50
- // Labels already present inline (placed at their paste position in the
51
- // composer) stay where they are; only labels missing from the text are
52
- // prepended as a headline (back-compat for callers without inline labels).
53
- const missing = labels.filter((label) => !input.includes(label));
54
- const headline = missing.length > 0
55
- ? (base ? `${missing.join(" ")} ${base}` : missing.join(" "))
56
- : base;
57
- return [
58
- headline,
59
- ...labels.map(imageDisplayReferenceLine),
60
- ].join("\n");
49
+ // The composer text is the canonical presentation: if a chip was inserted
50
+ // inline, keep it at that exact position after submit. Reconstructed legacy
51
+ // messages do not contain labels, so only their missing chips fall back to
52
+ // standalone reference rows.
53
+ const missingLabels = labels.filter((label) => !input.includes(label));
54
+ return [input, ...missingLabels.map(imageDisplayReferenceLine)].filter(Boolean).join("\n");
55
+ }
56
+ export function displayImagesFromPayload(payload) {
57
+ const start = payload.imageDisplayStart ?? 1;
58
+ return payload.images.map((attachment, index) => ({
59
+ ...attachment,
60
+ label: imageDisplayLabel(start + index),
61
+ }));
62
+ }
63
+ export function imageAttachmentFromDataUrl(url) {
64
+ const match = /^data:([^;,]+);base64,([A-Za-z0-9+/=\r\n]+)$/.exec(url.trim());
65
+ if (!match)
66
+ return undefined;
67
+ const mediaType = match[1].toLowerCase();
68
+ const base64 = match[2].replace(/[\r\n]/g, "");
69
+ if (!mediaType.startsWith("image/"))
70
+ return undefined;
71
+ let bytes = 0;
72
+ try {
73
+ bytes = Buffer.from(base64, "base64").byteLength;
74
+ }
75
+ catch {
76
+ return undefined;
77
+ }
78
+ return { base64, mediaType, bytes, dataUrl: `data:${mediaType};base64,${base64}` };
61
79
  }
62
80
  export function nextImageDisplayLabelStart(messages) {
63
81
  let max = 0;
@@ -0,0 +1,5 @@
1
+ import type { MarkdownTheme } from "@bubblebrain-ai/pi-tui";
2
+ import { type Theme } from "./model/theme.js";
3
+ /** Shared assistant Markdown styling for every transcript host. */
4
+ export declare function createAssistantMarkdownTheme(getTheme: () => Theme): MarkdownTheme;
5
+ export declare const ASSISTANT_MARKDOWN_THEME: MarkdownTheme;
@@ -0,0 +1,23 @@
1
+ import chalk from "chalk";
2
+ import { darkTheme } from "./model/theme.js";
3
+ import { themeDim, themeForeground } from "./model/theme-style.js";
4
+ /** Shared assistant Markdown styling for every transcript host. */
5
+ export function createAssistantMarkdownTheme(getTheme) {
6
+ return {
7
+ heading: (text) => chalk.bold(themeForeground(getTheme().accent, text)),
8
+ link: (text) => chalk.underline(themeForeground(getTheme().accent, text)),
9
+ linkUrl: (text) => themeDim(getTheme().dim, text),
10
+ code: (text) => themeForeground(getTheme().inlineCode, text),
11
+ codeBlock: (text) => themeForeground(getTheme().agent, text),
12
+ codeBlockBorder: (text) => themeDim(getTheme().border, text),
13
+ quote: (text) => themeDim(getTheme().dim, text),
14
+ quoteBorder: (text) => themeDim(getTheme().border, text),
15
+ hr: (text) => themeDim(getTheme().border, text),
16
+ listBullet: (text) => themeForeground(getTheme().accent, text),
17
+ bold: (text) => chalk.bold(text),
18
+ italic: (text) => chalk.italic(text),
19
+ strikethrough: (text) => chalk.strikethrough(text),
20
+ underline: (text) => chalk.underline(text),
21
+ };
22
+ }
23
+ export const ASSISTANT_MARKDOWN_THEME = createAssistantMarkdownTheme(() => darkTheme);
@@ -1,4 +1,4 @@
1
- import { createPastedContentMarker } from "../tui/paste-placeholder.js";
1
+ import { createPastedContentMarker } from "../../tui/paste-placeholder.js";
2
2
  function clampOffset(text, value) {
3
3
  if (!Number.isFinite(value))
4
4
  return 0;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Composer submission payload — the bridge type between the composer UI and
3
+ * the agent input path. Lives in the renderer-neutral model layer so the
4
+ * queue state machine can reference it without importing a renderer.
5
+ */
6
+ import type { ImageAttachment } from "./image-attachment.js";
7
+ export interface SubmitPayload {
8
+ /** Fully-expanded text sent to the agent. */
9
+ text: string;
10
+ /** Text shown in the composer/transcript when it differs from the real text. */
11
+ displayText?: string;
12
+ images: ImageAttachment[];
13
+ /** First UI-only [Image #N] label reserved for this submitted payload. */
14
+ imageDisplayStart?: number;
15
+ /** Harness-initiated submission; runs hidden (task wake path). */
16
+ internal?: "task_wake";
17
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,10 +1,13 @@
1
- import type { Message, ToolResultMetadata } from "../types.js";
1
+ import type { Message, ToolResultMetadata } from "../../types.js";
2
+ import type { DisplayImageAttachment } from "./image-attachment.js";
2
3
  export type UserInputStatus = "queued" | "pending_steer";
3
4
  export interface DisplayMessage {
4
5
  /** Stable identity, used as the transcript list key. Generated by the UI layer. */
5
6
  key?: string;
6
7
  role: "user" | "assistant" | "error";
7
8
  content: string;
9
+ /** Rich image state retained for chips, preview and session restore. */
10
+ images?: DisplayImageAttachment[];
8
11
  /** Correlates queued/steer placeholder rows with their lifecycle events. */
9
12
  clientId?: string;
10
13
  /** Badge for user input waiting to enter the run (QUEUED / STEER). */
@@ -50,6 +53,9 @@ export interface DisplayToolCall {
50
53
  * a command preview.
51
54
  */
52
55
  rawArguments?: string;
56
+ /** Live execution state. Result text may be present during a running
57
+ * subagent/tool update, so pending cannot be inferred from `result` alone. */
58
+ status?: "queued" | "pending" | "running" | "completed" | "failed" | "blocked" | "cancelled";
53
59
  result?: string;
54
60
  isError?: boolean;
55
61
  metadata?: ToolResultMetadata;
@@ -1,3 +1,3 @@
1
1
  import { type DisplayMessage } from "./display-history.js";
2
- import type { Message } from "../types.js";
2
+ import type { Message } from "../../types.js";
3
3
  export declare function reconstructDisplayMessages(agentMessages: Message[]): DisplayMessage[];
@@ -2,14 +2,59 @@
2
2
  * Rebuilds UI DisplayMessages from the agent's raw transcript — used on
3
3
  * initial mount and after transcript rewrites (rewind, resume).
4
4
  */
5
- import { INTERRUPTED_ASSISTANT_CONTENT } from "../agent.js";
6
- import { isHiddenToolMetadata } from "../agent/tool-visibility.js";
7
- import { isInternalBlockOnlyContent } from "../agent/internal-reminder-sanitizer.js";
5
+ import { INTERRUPTED_ASSISTANT_CONTENT } from "../../agent.js";
6
+ import { isHiddenToolMetadata } from "../../agent/tool-visibility.js";
7
+ import { isInternalBlockOnlyContent } from "../../agent/internal-reminder-sanitizer.js";
8
+ import { COMPACTION_SUMMARY_PREFIX } from "../../context/compact.js";
8
9
  import { nextDisplayMessageKey, stripInterruptedAssistantMarker } from "./display-history.js";
10
+ import { synchronizeSubagentSnapshots } from "./subagent-view.js";
11
+ import { formatImageUserDisplayText, imageAttachmentFromDataUrl, imageDisplayLabel } from "../image-display.js";
12
+ function reconstructUserContent(message, imageDisplayStart) {
13
+ const { content } = message;
14
+ if (typeof content === "string") {
15
+ return { text: content, images: [], nextImageDisplayStart: imageDisplayStart };
16
+ }
17
+ const text = content
18
+ .filter((part) => part.type === "text")
19
+ .map((part) => part.text)
20
+ .join("\n")
21
+ .trim();
22
+ const imageCount = content.filter((part) => part.type === "image_url").length;
23
+ const labelStart = message.ui?.imageDisplayStart ?? imageDisplayStart;
24
+ const images = content
25
+ .filter((part) => part.type === "image_url")
26
+ .map((part, index) => {
27
+ const attachment = imageAttachmentFromDataUrl(part.image_url.url);
28
+ return attachment ? { ...attachment, label: imageDisplayLabel(labelStart + index) } : undefined;
29
+ })
30
+ .filter((item) => item !== undefined);
31
+ return {
32
+ text: formatImageUserDisplayText(message.ui?.displayText ?? text, imageCount, labelStart),
33
+ images,
34
+ nextImageDisplayStart: Math.max(imageDisplayStart, labelStart + imageCount),
35
+ };
36
+ }
9
37
  export function reconstructDisplayMessages(agentMessages) {
10
38
  const result = [];
39
+ let nextImageDisplayStart = 1;
11
40
  for (const m of agentMessages) {
12
- if (m.role === "system" || m.role === "tool")
41
+ if (m.role === "system") {
42
+ const content = typeof m.content === "string" ? m.content : "";
43
+ if (content.startsWith(COMPACTION_SUMMARY_PREFIX)) {
44
+ const summary = content.slice(COMPACTION_SUMMARY_PREFIX.length).trim();
45
+ if (summary) {
46
+ result.push({
47
+ key: nextDisplayMessageKey("compact"),
48
+ role: "assistant",
49
+ content: "Compaction completed.",
50
+ syntheticKind: "ui_compact_summary",
51
+ compactionSummary: summary,
52
+ });
53
+ }
54
+ }
55
+ continue;
56
+ }
57
+ if (m.role === "tool")
13
58
  continue;
14
59
  if (m.role === "user") {
15
60
  if (m.isMeta)
@@ -20,10 +65,13 @@ export function reconstructDisplayMessages(agentMessages) {
20
65
  // when the transcript is rebuilt.
21
66
  if (isInternalBlockOnlyContent(m.content))
22
67
  continue;
68
+ const reconstructed = reconstructUserContent(m, nextImageDisplayStart);
69
+ nextImageDisplayStart = reconstructed.nextImageDisplayStart;
23
70
  result.push({
24
71
  key: nextDisplayMessageKey("user"),
25
72
  role: "user",
26
- content: typeof m.content === "string" ? m.content : "(multimedia)",
73
+ content: reconstructed.text,
74
+ images: reconstructed.images.length > 0 ? reconstructed.images : undefined,
27
75
  });
28
76
  }
29
77
  else if (m.role === "assistant") {
@@ -78,5 +126,5 @@ export function reconstructDisplayMessages(agentMessages) {
78
126
  }
79
127
  }
80
128
  }
81
- return result;
129
+ return synchronizeSubagentSnapshots(result);
82
130
  }