@bubblebrain-ai/bubble 0.0.51 → 0.0.53

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 (481) 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 +80 -11
  49. package/dist/provider-transform.js +32 -4
  50. package/dist/provider.d.ts +6 -2
  51. package/dist/provider.js +100 -11
  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/node_modules/@bubblebrain-ai/pi-tui/LICENSE +21 -0
  213. package/node_modules/@bubblebrain-ai/pi-tui/README.md +854 -0
  214. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/alt-screen-search.d.ts +26 -0
  215. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/alt-screen-search.d.ts.map +1 -0
  216. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/alt-screen-search.js +121 -0
  217. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/alt-screen-search.js.map +1 -0
  218. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/autocomplete.d.ts +86 -0
  219. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/autocomplete.d.ts.map +1 -0
  220. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/autocomplete.js +649 -0
  221. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/autocomplete.js.map +1 -0
  222. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/alt-screen-flash.d.ts +13 -0
  223. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/alt-screen-flash.d.ts.map +1 -0
  224. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/alt-screen-flash.js +36 -0
  225. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/alt-screen-flash.js.map +1 -0
  226. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/box.d.ts +22 -0
  227. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/box.d.ts.map +1 -0
  228. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/box.js +99 -0
  229. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/box.js.map +1 -0
  230. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/cancellable-loader.d.ts +22 -0
  231. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/cancellable-loader.d.ts.map +1 -0
  232. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/cancellable-loader.js +36 -0
  233. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/cancellable-loader.js.map +1 -0
  234. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/editor.d.ts +330 -0
  235. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/editor.d.ts.map +1 -0
  236. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/editor.js +2344 -0
  237. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/editor.js.map +1 -0
  238. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/h-stack.d.ts +7 -0
  239. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/h-stack.d.ts.map +1 -0
  240. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/h-stack.js +43 -0
  241. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/h-stack.js.map +1 -0
  242. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/image.d.ts +28 -0
  243. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/image.d.ts.map +1 -0
  244. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/image.js +82 -0
  245. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/image.js.map +1 -0
  246. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/input.d.ts +48 -0
  247. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/input.d.ts.map +1 -0
  248. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/input.js +390 -0
  249. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/input.js.map +1 -0
  250. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/loader.d.ts +31 -0
  251. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/loader.d.ts.map +1 -0
  252. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/loader.js +67 -0
  253. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/loader.js.map +1 -0
  254. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/markdown.d.ts +103 -0
  255. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/markdown.d.ts.map +1 -0
  256. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/markdown.js +797 -0
  257. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/markdown.js.map +1 -0
  258. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/scroll-view.d.ts +56 -0
  259. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/scroll-view.d.ts.map +1 -0
  260. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/scroll-view.js +179 -0
  261. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/scroll-view.js.map +1 -0
  262. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/select-list.d.ts +53 -0
  263. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/select-list.d.ts.map +1 -0
  264. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/select-list.js +175 -0
  265. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/select-list.js.map +1 -0
  266. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/settings-list.d.ts +50 -0
  267. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/settings-list.d.ts.map +1 -0
  268. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/settings-list.js +174 -0
  269. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/settings-list.js.map +1 -0
  270. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/spacer.d.ts +12 -0
  271. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/spacer.d.ts.map +1 -0
  272. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/spacer.js +22 -0
  273. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/spacer.js.map +1 -0
  274. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/stack.d.ts +32 -0
  275. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/stack.d.ts.map +1 -0
  276. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/stack.js +109 -0
  277. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/stack.js.map +1 -0
  278. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/text.d.ts +19 -0
  279. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/text.d.ts.map +1 -0
  280. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/text.js +81 -0
  281. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/text.js.map +1 -0
  282. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/truncated-text.d.ts +13 -0
  283. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/truncated-text.d.ts.map +1 -0
  284. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/truncated-text.js +48 -0
  285. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/truncated-text.js.map +1 -0
  286. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/v-stack.d.ts +8 -0
  287. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/v-stack.d.ts.map +1 -0
  288. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/v-stack.js +26 -0
  289. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/v-stack.js.map +1 -0
  290. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/editor-component.d.ts +39 -0
  291. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/editor-component.d.ts.map +1 -0
  292. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/editor-component.js +2 -0
  293. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/editor-component.js.map +1 -0
  294. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/fuzzy.d.ts +16 -0
  295. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/fuzzy.d.ts.map +1 -0
  296. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/fuzzy.js +110 -0
  297. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/fuzzy.js.map +1 -0
  298. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/index.d.ts +31 -0
  299. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/index.d.ts.map +1 -0
  300. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/index.js +42 -0
  301. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/index.js.map +1 -0
  302. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keybindings.d.ts +273 -0
  303. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keybindings.d.ts.map +1 -0
  304. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keybindings.js +231 -0
  305. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keybindings.js.map +1 -0
  306. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keys.d.ts +184 -0
  307. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keys.d.ts.map +1 -0
  308. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keys.js +1174 -0
  309. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keys.js.map +1 -0
  310. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/kill-ring.d.ts +28 -0
  311. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/kill-ring.d.ts.map +1 -0
  312. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/kill-ring.js +46 -0
  313. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/kill-ring.js.map +1 -0
  314. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/latex.d.ts +10 -0
  315. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/latex.d.ts.map +1 -0
  316. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/latex.js +1268 -0
  317. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/latex.js.map +1 -0
  318. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout-node.d.ts +40 -0
  319. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout-node.d.ts.map +1 -0
  320. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout-node.js +6 -0
  321. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout-node.js.map +1 -0
  322. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout.d.ts +42 -0
  323. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout.d.ts.map +1 -0
  324. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout.js +335 -0
  325. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout.js.map +1 -0
  326. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/native-modifiers.d.ts +3 -0
  327. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/native-modifiers.d.ts.map +1 -0
  328. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/native-modifiers.js +60 -0
  329. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/native-modifiers.js.map +1 -0
  330. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/stdin-buffer.d.ts +56 -0
  331. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/stdin-buffer.d.ts.map +1 -0
  332. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/stdin-buffer.js +363 -0
  333. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/stdin-buffer.js.map +1 -0
  334. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-colors.d.ts +10 -0
  335. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-colors.d.ts.map +1 -0
  336. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-colors.js +59 -0
  337. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-colors.js.map +1 -0
  338. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-image.d.ts +116 -0
  339. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-image.d.ts.map +1 -0
  340. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-image.js +518 -0
  341. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-image.js.map +1 -0
  342. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal.d.ts +142 -0
  343. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal.d.ts.map +1 -0
  344. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal.js +544 -0
  345. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal.js.map +1 -0
  346. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/testing.d.ts +11 -0
  347. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/testing.d.ts.map +1 -0
  348. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/testing.js +11 -0
  349. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/testing.js.map +1 -0
  350. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-alt-screen.d.ts +140 -0
  351. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-alt-screen.d.ts.map +1 -0
  352. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-alt-screen.js +1334 -0
  353. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-alt-screen.js.map +1 -0
  354. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-main-screen.d.ts +39 -0
  355. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-main-screen.d.ts.map +1 -0
  356. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-main-screen.js +536 -0
  357. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-main-screen.js.map +1 -0
  358. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui.d.ts +338 -0
  359. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui.d.ts.map +1 -0
  360. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui.js +1016 -0
  361. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui.js.map +1 -0
  362. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/undo-stack.d.ts +17 -0
  363. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/undo-stack.d.ts.map +1 -0
  364. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/undo-stack.js +27 -0
  365. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/undo-stack.js.map +1 -0
  366. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/utils.d.ts +96 -0
  367. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/utils.d.ts.map +1 -0
  368. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/utils.js +1193 -0
  369. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/utils.js.map +1 -0
  370. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/word-navigation.d.ts +25 -0
  371. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/word-navigation.d.ts.map +1 -0
  372. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/word-navigation.js +96 -0
  373. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/word-navigation.js.map +1 -0
  374. package/node_modules/@bubblebrain-ai/pi-tui/dist/test/virtual-terminal.d.ts +73 -0
  375. package/node_modules/@bubblebrain-ai/pi-tui/dist/test/virtual-terminal.d.ts.map +1 -0
  376. package/node_modules/@bubblebrain-ai/pi-tui/dist/test/virtual-terminal.js +188 -0
  377. package/node_modules/@bubblebrain-ai/pi-tui/dist/test/virtual-terminal.js.map +1 -0
  378. package/node_modules/@bubblebrain-ai/pi-tui/native/darwin/README.md +20 -0
  379. package/node_modules/@bubblebrain-ai/pi-tui/native/darwin/build.sh +62 -0
  380. package/node_modules/@bubblebrain-ai/pi-tui/native/darwin/prebuilds/darwin-arm64/darwin-modifiers.node +0 -0
  381. package/node_modules/@bubblebrain-ai/pi-tui/native/darwin/prebuilds/darwin-x64/darwin-modifiers.node +0 -0
  382. package/node_modules/@bubblebrain-ai/pi-tui/native/darwin/src/darwin-modifiers.c +70 -0
  383. package/node_modules/@bubblebrain-ai/pi-tui/native/win32/README.md +22 -0
  384. package/node_modules/@bubblebrain-ai/pi-tui/native/win32/build.mjs +229 -0
  385. package/node_modules/@bubblebrain-ai/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
  386. package/node_modules/@bubblebrain-ai/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
  387. package/node_modules/@bubblebrain-ai/pi-tui/native/win32/src/win32-console-mode.c +119 -0
  388. package/node_modules/@bubblebrain-ai/pi-tui/package.json +66 -0
  389. package/node_modules/get-east-asian-width/index.d.ts +60 -0
  390. package/node_modules/get-east-asian-width/index.js +30 -0
  391. package/node_modules/get-east-asian-width/license +9 -0
  392. package/node_modules/get-east-asian-width/lookup-data.js +21 -0
  393. package/node_modules/get-east-asian-width/lookup.js +138 -0
  394. package/node_modules/get-east-asian-width/package.json +71 -0
  395. package/node_modules/get-east-asian-width/readme.md +65 -0
  396. package/node_modules/get-east-asian-width/utilities.js +24 -0
  397. package/package.json +23 -10
  398. package/packages/pi-tui/node_modules/marked/LICENSE +44 -0
  399. package/packages/pi-tui/node_modules/marked/README.md +115 -0
  400. package/packages/pi-tui/node_modules/marked/bin/main.js +284 -0
  401. package/packages/pi-tui/node_modules/marked/bin/marked.js +16 -0
  402. package/packages/pi-tui/node_modules/marked/lib/marked.d.ts +760 -0
  403. package/packages/pi-tui/node_modules/marked/lib/marked.esm.js +77 -0
  404. package/packages/pi-tui/node_modules/marked/lib/marked.esm.js.map +7 -0
  405. package/packages/pi-tui/node_modules/marked/lib/marked.umd.js +79 -0
  406. package/packages/pi-tui/node_modules/marked/lib/marked.umd.js.map +7 -0
  407. package/packages/pi-tui/node_modules/marked/man/marked.1 +113 -0
  408. package/packages/pi-tui/node_modules/marked/man/marked.1.md +93 -0
  409. package/packages/pi-tui/node_modules/marked/package.json +103 -0
  410. package/dist/tui-ink/app.d.ts +0 -76
  411. package/dist/tui-ink/app.js +0 -2377
  412. package/dist/tui-ink/approval/approval-dialog.d.ts +0 -13
  413. package/dist/tui-ink/approval/approval-dialog.js +0 -184
  414. package/dist/tui-ink/approval/diff-view.d.ts +0 -7
  415. package/dist/tui-ink/approval/diff-view.js +0 -44
  416. package/dist/tui-ink/approval/select.d.ts +0 -35
  417. package/dist/tui-ink/approval/select.js +0 -98
  418. package/dist/tui-ink/code-highlight.d.ts +0 -8
  419. package/dist/tui-ink/code-highlight.js +0 -121
  420. package/dist/tui-ink/command-palette.d.ts +0 -32
  421. package/dist/tui-ink/command-palette.js +0 -158
  422. package/dist/tui-ink/compaction-progress.d.ts +0 -19
  423. package/dist/tui-ink/compaction-progress.js +0 -74
  424. package/dist/tui-ink/detect-theme.d.ts +0 -1
  425. package/dist/tui-ink/detect-theme.js +0 -1
  426. package/dist/tui-ink/feedback-dialog.d.ts +0 -19
  427. package/dist/tui-ink/feedback-dialog.js +0 -133
  428. package/dist/tui-ink/feishu-setup-picker.d.ts +0 -5
  429. package/dist/tui-ink/feishu-setup-picker.js +0 -271
  430. package/dist/tui-ink/footer.d.ts +0 -26
  431. package/dist/tui-ink/footer.js +0 -51
  432. package/dist/tui-ink/input-box.d.ts +0 -189
  433. package/dist/tui-ink/input-box.js +0 -1279
  434. package/dist/tui-ink/input-history.d.ts +0 -1
  435. package/dist/tui-ink/input-history.js +0 -1
  436. package/dist/tui-ink/markdown.d.ts +0 -103
  437. package/dist/tui-ink/markdown.js +0 -747
  438. package/dist/tui-ink/message-list.d.ts +0 -49
  439. package/dist/tui-ink/message-list.js +0 -841
  440. package/dist/tui-ink/model-picker.d.ts +0 -143
  441. package/dist/tui-ink/model-picker.js +0 -966
  442. package/dist/tui-ink/plan-confirm.d.ts +0 -7
  443. package/dist/tui-ink/plan-confirm.js +0 -115
  444. package/dist/tui-ink/question-dialog.d.ts +0 -8
  445. package/dist/tui-ink/question-dialog.js +0 -135
  446. package/dist/tui-ink/rewind-picker.d.ts +0 -8
  447. package/dist/tui-ink/rewind-picker.js +0 -102
  448. package/dist/tui-ink/run-session-picker.js +0 -22
  449. package/dist/tui-ink/run.d.ts +0 -62
  450. package/dist/tui-ink/run.js +0 -103
  451. package/dist/tui-ink/session-picker.d.ts +0 -10
  452. package/dist/tui-ink/session-picker.js +0 -113
  453. package/dist/tui-ink/stats-panel.d.ts +0 -11
  454. package/dist/tui-ink/stats-panel.js +0 -65
  455. package/dist/tui-ink/subagent-inspector.d.ts +0 -21
  456. package/dist/tui-ink/subagent-inspector.js +0 -205
  457. package/dist/tui-ink/use-terminal-size.d.ts +0 -4
  458. package/dist/tui-ink/use-terminal-size.js +0 -48
  459. package/dist/tui-ink/waiting-indicator.d.ts +0 -12
  460. package/dist/tui-ink/waiting-indicator.js +0 -129
  461. package/dist/tui-ink/welcome.d.ts +0 -25
  462. package/dist/tui-ink/welcome.js +0 -88
  463. package/dist/tui-ink/wordmark.d.ts +0 -8
  464. package/dist/tui-ink/wordmark.js +0 -103
  465. /package/dist/{tui-ink → tui/model}/composer-buffer.d.ts +0 -0
  466. /package/dist/{tui-ink → tui/model}/display-history.js +0 -0
  467. /package/dist/{tui-ink → tui/model}/input-queue.js +0 -0
  468. /package/dist/{tui-ink → tui/model}/key-events.d.ts +0 -0
  469. /package/dist/{tui-ink → tui/model}/key-events.js +0 -0
  470. /package/dist/{tui-ink → tui/model}/paste-operation-tracker.d.ts +0 -0
  471. /package/dist/{tui-ink → tui/model}/paste-operation-tracker.js +0 -0
  472. /package/dist/{tui-ink → tui/model}/recent-activity.d.ts +0 -0
  473. /package/dist/{tui-ink → tui/model}/submit-dedupe.js +0 -0
  474. /package/dist/{tui-ink → tui/model}/sync-output.d.ts +0 -0
  475. /package/dist/{tui-ink → tui/model}/sync-output.js +0 -0
  476. /package/dist/{tui-ink → tui/model}/terminal-env.d.ts +0 -0
  477. /package/dist/{tui-ink → tui/model}/terminal-env.js +0 -0
  478. /package/dist/{tui-ink → tui/model}/terminal-mouse.d.ts +0 -0
  479. /package/dist/{tui-ink → tui/model}/terminal-mouse.js +0 -0
  480. /package/dist/{tui-ink → tui/model}/width.d.ts +0 -0
  481. /package/dist/{tui-ink → tui/model}/width.js +0 -0
@@ -0,0 +1,502 @@
1
+ import { appendHistoryEntry, loadHistoryEntriesSync, pushHistoryEntry, stepHistory, } from "../model/input-history.js";
2
+ import { bareImageFilenameFromPaste, extractImagePathTokens, ingestClipboardImage, ingestImagePath, } from "../model/image-paste.js";
3
+ import { PasteOperationTracker } from "../model/paste-operation-tracker.js";
4
+ import { imageDisplayLabel, stripInlineImageLabels } from "../image-display.js";
5
+ import { darkTheme } from "../model/theme.js";
6
+ import { themeBackground, themeForeground } from "../model/theme-style.js";
7
+ const READING_IMAGE_PREFIX = "Reading image";
8
+ function cloneHistoryEntry(entry) {
9
+ return {
10
+ text: entry.text,
11
+ images: entry.images.map((image) => ({ ...image })),
12
+ ...(entry.imageDisplayStart !== undefined ? { imageDisplayStart: entry.imageDisplayStart } : {}),
13
+ };
14
+ }
15
+ function normalizedScope(scope) {
16
+ return {
17
+ sessionFile: scope.sessionFile?.trim() || undefined,
18
+ cwd: scope.cwd?.trim() || undefined,
19
+ };
20
+ }
21
+ function scopesEqual(a, b) {
22
+ return a.sessionFile === b.sessionFile && a.cwd === b.cwd;
23
+ }
24
+ /**
25
+ * Owns semantic composer state that Pi Editor deliberately does not know about:
26
+ * image attachments, asynchronous paste operations and scoped persistent
27
+ * history. Text editing and cursor mechanics remain inside Editor.
28
+ */
29
+ export class ComposerController {
30
+ options;
31
+ editor;
32
+ scope;
33
+ history = [];
34
+ historyIndex = null;
35
+ historyDraft = { text: "", images: [] };
36
+ attachments = [];
37
+ imageDisplayStart;
38
+ nextImageLabelStart;
39
+ pasteOperations = new PasteOperationTracker();
40
+ draftGeneration = 0;
41
+ applyingEditorState = false;
42
+ historyNavigationChangePending = false;
43
+ editorSubmitting = false;
44
+ disposed = false;
45
+ recentPreviewLabel;
46
+ recentPreviewCursorOffset;
47
+ openImageHandler;
48
+ constructor(options) {
49
+ this.options = options;
50
+ this.editor = options.editor;
51
+ this.scope = normalizedScope(options.scope);
52
+ this.nextImageLabelStart = Math.max(1, options.nextImageLabelStart);
53
+ this.openImageHandler = options.onOpenImage;
54
+ this.attachEditor(options.editor);
55
+ this.reloadHistory();
56
+ }
57
+ attachEditor(editor) {
58
+ if (this.editor !== editor) {
59
+ const previousText = this.editor.getText();
60
+ this.detachEditor(this.editor);
61
+ this.editor = editor;
62
+ this.applyingEditorState = true;
63
+ editor.setText(previousText);
64
+ this.applyingEditorState = false;
65
+ }
66
+ editor.onPaste = (text) => this.handlePaste(text);
67
+ editor.onHistoryNavigate = (direction, currentText) => this.navigateHistory(direction, currentText);
68
+ editor.onChange = () => this.handleEditorChange();
69
+ editor.onCursorMove = () => {
70
+ if (this.applyingEditorState)
71
+ return;
72
+ this.recentPreviewLabel = undefined;
73
+ this.recentPreviewCursorOffset = undefined;
74
+ this.options.onStateChange();
75
+ };
76
+ editor.onBeforeSubmit = () => {
77
+ this.editorSubmitting = true;
78
+ };
79
+ editor.onSubmit = (text) => this.handleEditorSubmit(text);
80
+ this.syncOpenImageActivation();
81
+ editor.disableSubmit = this.pasteOperations.hasPending;
82
+ this.syncEditorDecorations();
83
+ }
84
+ detachEditor(editor) {
85
+ editor.onPaste = undefined;
86
+ editor.onHistoryNavigate = undefined;
87
+ editor.onChange = undefined;
88
+ editor.onCursorMove = undefined;
89
+ editor.onBeforeSubmit = undefined;
90
+ editor.onSubmit = undefined;
91
+ editor.onInlineDecorationActivate = undefined;
92
+ editor.setInlineDecorations([]);
93
+ editor.disableSubmit = false;
94
+ }
95
+ dispose() {
96
+ if (this.disposed)
97
+ return;
98
+ this.disposed = true;
99
+ this.invalidateDraftAsyncWork();
100
+ this.detachEditor(this.editor);
101
+ }
102
+ pendingImageCount() {
103
+ return this.pasteOperations.pendingCount;
104
+ }
105
+ setOpenImageHandler(handler) {
106
+ this.openImageHandler = handler;
107
+ this.syncOpenImageActivation();
108
+ }
109
+ syncOpenImageActivation() {
110
+ this.editor.onInlineDecorationActivate = this.openImageHandler
111
+ ? (id) => {
112
+ const item = this.attachments.find((candidate) => candidate.label === id);
113
+ if (item)
114
+ this.openImageHandler?.({ label: item.label, attachment: { ...item.attachment } });
115
+ }
116
+ : undefined;
117
+ }
118
+ /**
119
+ * Explicit keyboard-driven clipboard probe. Image-only clipboards do not
120
+ * produce text for many terminals, so Cmd+V may have no bracketed-paste body
121
+ * and Ctrl+V arrives as a key chord instead of a paste event.
122
+ */
123
+ requestClipboardImagePaste() {
124
+ if (this.disposed)
125
+ return;
126
+ if (this.pasteOperations.hasPending)
127
+ return;
128
+ if (!(this.options.allowImageAttachments?.() ?? true)) {
129
+ this.options.onNotice("Image attachments are disabled in this runtime session.");
130
+ return;
131
+ }
132
+ this.startClipboardPaste("", true);
133
+ }
134
+ historyTexts() {
135
+ return this.history.map((entry) => entry.text);
136
+ }
137
+ getText() {
138
+ return this.editor.getText();
139
+ }
140
+ snapshotDraft() {
141
+ return {
142
+ text: this.editor.getText(),
143
+ attachments: this.attachments.map((item) => ({
144
+ label: item.label,
145
+ attachment: { ...item.attachment },
146
+ })),
147
+ ...(this.imageDisplayStart !== undefined ? { imageDisplayStart: this.imageDisplayStart } : {}),
148
+ };
149
+ }
150
+ /** Image whose chip was just inserted, is under the cursor, or is hovered. */
151
+ previewAttachment() {
152
+ const recentStillAtInsertionPoint = this.recentPreviewCursorOffset === this.editor.getCursorOffset();
153
+ const activeLabel = this.editor.getActiveInlineDecorationId()
154
+ ?? (recentStillAtInsertionPoint ? this.recentPreviewLabel : undefined);
155
+ const item = this.attachments.find((candidate) => candidate.label === activeLabel);
156
+ return item ? { label: item.label, attachment: { ...item.attachment } } : undefined;
157
+ }
158
+ restoreDraft(snapshot) {
159
+ this.invalidateDraftAsyncWork();
160
+ this.attachments = snapshot.attachments.map((item) => ({
161
+ label: item.label,
162
+ attachment: { ...item.attachment },
163
+ }));
164
+ this.imageDisplayStart = snapshot.imageDisplayStart;
165
+ this.historyIndex = null;
166
+ this.historyDraft = { text: "", images: [] };
167
+ this.applyingEditorState = true;
168
+ this.editor.setText(snapshot.text);
169
+ this.applyingEditorState = false;
170
+ this.syncEditorDecorations();
171
+ this.options.onStateChange();
172
+ }
173
+ /** Replace the complete draft and invalidate attachments/pastes/history browse. */
174
+ replaceDraft(text) {
175
+ this.invalidateDraftAsyncWork();
176
+ this.attachments = [];
177
+ this.imageDisplayStart = undefined;
178
+ this.historyIndex = null;
179
+ this.historyDraft = { text: "", images: [] };
180
+ this.applyingEditorState = true;
181
+ this.editor.setText(text);
182
+ this.applyingEditorState = false;
183
+ this.recentPreviewLabel = undefined;
184
+ this.recentPreviewCursorOffset = undefined;
185
+ this.syncEditorDecorations();
186
+ this.options.onStateChange();
187
+ }
188
+ /** Rebind persistent history after a successful session transition. */
189
+ setScope(scope, nextImageLabelStart) {
190
+ const nextScope = normalizedScope(scope);
191
+ const changed = !scopesEqual(this.scope, nextScope);
192
+ this.scope = nextScope;
193
+ this.nextImageLabelStart = Math.max(1, nextImageLabelStart);
194
+ if (!changed)
195
+ return;
196
+ this.invalidateDraftAsyncWork();
197
+ this.attachments = [];
198
+ this.imageDisplayStart = undefined;
199
+ this.historyIndex = null;
200
+ this.historyDraft = { text: "", images: [] };
201
+ this.reloadHistory();
202
+ this.applyingEditorState = true;
203
+ this.editor.setText("");
204
+ this.applyingEditorState = false;
205
+ this.recentPreviewLabel = undefined;
206
+ this.recentPreviewCursorOffset = undefined;
207
+ this.syncEditorDecorations();
208
+ this.options.onStateChange();
209
+ }
210
+ reloadHistory() {
211
+ if (this.options.persistHistory === false) {
212
+ this.history = [];
213
+ return;
214
+ }
215
+ this.history = loadHistoryEntriesSync({
216
+ scope: this.scope,
217
+ ...(this.options.historyFilePath ? { filePath: this.options.historyFilePath } : {}),
218
+ }).map(cloneHistoryEntry);
219
+ }
220
+ handleEditorChange() {
221
+ if (this.applyingEditorState)
222
+ return;
223
+ if (this.editorSubmitting)
224
+ return;
225
+ if (this.historyNavigationChangePending) {
226
+ this.historyNavigationChangePending = false;
227
+ this.syncEditorDecorations();
228
+ return;
229
+ }
230
+ this.recentPreviewLabel = undefined;
231
+ this.recentPreviewCursorOffset = undefined;
232
+ // Editing a recalled entry starts a new draft, matching Editor's native
233
+ // history semantics. Attachments stay attached until their labels are gone.
234
+ if (this.historyIndex !== null) {
235
+ this.historyIndex = null;
236
+ this.historyDraft = { text: "", images: [] };
237
+ }
238
+ if (this.attachments.length > 0) {
239
+ const text = this.editor.getText();
240
+ const retained = this.attachments.filter((item) => text.includes(item.label));
241
+ if (retained.length !== this.attachments.length) {
242
+ if (retained.length === 0) {
243
+ this.attachments = [];
244
+ this.imageDisplayStart = undefined;
245
+ }
246
+ else {
247
+ const labelStart = this.imageDisplayStart ?? this.nextImageLabelStart;
248
+ this.applyingEditorState = true;
249
+ for (let index = 0; index < retained.length; index++) {
250
+ const item = retained[index];
251
+ const nextLabel = imageDisplayLabel(labelStart + index);
252
+ if (item.label !== nextLabel) {
253
+ const current = this.editor.getText();
254
+ const offset = current.indexOf(item.label);
255
+ if (offset >= 0)
256
+ this.editor.replaceRange(offset, offset + item.label.length, nextLabel);
257
+ item.label = nextLabel;
258
+ }
259
+ }
260
+ this.applyingEditorState = false;
261
+ this.attachments = retained;
262
+ this.imageDisplayStart = labelStart;
263
+ }
264
+ this.options.onStateChange();
265
+ }
266
+ }
267
+ this.syncEditorDecorations();
268
+ }
269
+ handleEditorSubmit(submittedText) {
270
+ this.editorSubmitting = false;
271
+ const labels = this.attachments.map((item) => item.label);
272
+ const modelText = stripInlineImageLabels(submittedText, labels).trim();
273
+ const isSlashCommand = modelText.startsWith("/");
274
+ const images = isSlashCommand ? [] : this.attachments.map((item) => ({ ...item.attachment }));
275
+ if (!modelText && images.length === 0) {
276
+ this.resetAfterSubmit();
277
+ return;
278
+ }
279
+ if (isSlashCommand && this.attachments.length > 0) {
280
+ this.options.onNotice("Image attachments were ignored for the slash command.");
281
+ }
282
+ const payload = {
283
+ text: modelText,
284
+ ...(images.length > 0 && submittedText !== modelText ? { displayText: submittedText } : {}),
285
+ images,
286
+ ...(images.length > 0 && this.imageDisplayStart !== undefined
287
+ ? { imageDisplayStart: this.imageDisplayStart }
288
+ : {}),
289
+ };
290
+ const historyEntry = {
291
+ // History restores the draft surface, not the provider prompt. Keep the
292
+ // chip exactly where it was submitted and derive modelText again on the
293
+ // next submit.
294
+ text: images.length > 0 ? submittedText : modelText,
295
+ images,
296
+ ...(images.length > 0 && this.imageDisplayStart !== undefined
297
+ ? { imageDisplayStart: this.imageDisplayStart }
298
+ : {}),
299
+ };
300
+ const nextHistory = pushHistoryEntry(this.history, historyEntry);
301
+ if (nextHistory !== this.history) {
302
+ this.history = nextHistory;
303
+ if (this.options.persistHistory !== false) {
304
+ appendHistoryEntry(historyEntry, {
305
+ scope: this.scope,
306
+ ...(this.options.historyFilePath ? { filePath: this.options.historyFilePath } : {}),
307
+ });
308
+ }
309
+ }
310
+ if (images.length > 0) {
311
+ this.nextImageLabelStart = Math.max(this.nextImageLabelStart, (this.imageDisplayStart ?? this.nextImageLabelStart) + images.length);
312
+ }
313
+ this.resetAfterSubmit();
314
+ this.options.onSubmit(payload);
315
+ }
316
+ resetAfterSubmit() {
317
+ this.invalidateDraftAsyncWork();
318
+ this.attachments = [];
319
+ this.imageDisplayStart = undefined;
320
+ this.recentPreviewLabel = undefined;
321
+ this.recentPreviewCursorOffset = undefined;
322
+ this.syncEditorDecorations();
323
+ this.historyIndex = null;
324
+ this.historyDraft = { text: "", images: [] };
325
+ this.options.onStateChange();
326
+ }
327
+ navigateHistory(direction, currentText) {
328
+ if (this.pasteOperations.hasPending)
329
+ return undefined;
330
+ const currentEntry = {
331
+ text: currentText,
332
+ images: this.attachments.map((item) => ({ ...item.attachment })),
333
+ ...(this.imageDisplayStart !== undefined ? { imageDisplayStart: this.imageDisplayStart } : {}),
334
+ };
335
+ const result = stepHistory({
336
+ history: this.history,
337
+ index: this.historyIndex,
338
+ draft: this.historyDraft,
339
+ }, direction, currentEntry);
340
+ if (!result.changed)
341
+ return undefined;
342
+ if (this.historyIndex === null && result.index !== null) {
343
+ this.historyDraft = cloneHistoryEntry(currentEntry);
344
+ }
345
+ const restoredImages = (result.images ?? []).map((image) => ({ ...image }));
346
+ const labelStart = restoredImages.length > 0
347
+ ? result.imageDisplayStart ?? this.nextImageLabelStart
348
+ : undefined;
349
+ this.attachments = restoredImages.map((attachment, index) => ({
350
+ attachment,
351
+ label: imageDisplayLabel((labelStart ?? 1) + index),
352
+ }));
353
+ this.imageDisplayStart = labelStart;
354
+ this.historyIndex = result.index;
355
+ if (result.index === null)
356
+ this.historyDraft = { text: "", images: [] };
357
+ const labels = this.attachments.map((item) => item.label);
358
+ const restoredText = labels.length > 0 && !labels.some((label) => result.text.includes(label))
359
+ ? `${labels.join(" ")} ${result.text}`.trimEnd()
360
+ : result.text;
361
+ this.historyNavigationChangePending = true;
362
+ this.options.onStateChange();
363
+ return { text: restoredText, active: result.index !== null };
364
+ }
365
+ handlePaste(raw) {
366
+ if (this.disposed)
367
+ return false;
368
+ const clean = raw
369
+ .replace(/\x1b\[I$/, "")
370
+ .replace(/\x1b\[O$/, "")
371
+ .replace(/\r\n?/g, "\n");
372
+ const allowImages = this.options.allowImageAttachments?.() ?? true;
373
+ const pathTokens = extractImagePathTokens(clean);
374
+ const bareName = bareImageFilenameFromPaste(clean);
375
+ const imageIntent = clean.length === 0 || pathTokens.length > 0 || bareName !== null;
376
+ if (!imageIntent)
377
+ return false;
378
+ if (!allowImages) {
379
+ this.options.onNotice("Image attachments are disabled in this runtime session.");
380
+ return true;
381
+ }
382
+ if (clean.length === 0 || bareName !== null) {
383
+ this.startClipboardPaste(clean);
384
+ return true;
385
+ }
386
+ this.startPathPaste(clean, pathTokens);
387
+ return true;
388
+ }
389
+ beginPastePlaceholder() {
390
+ const id = this.pasteOperations.begin();
391
+ const marker = `[${READING_IMAGE_PREFIX} #${id}…]`;
392
+ this.editor.disableSubmit = true;
393
+ this.editor.insertTextAtCursor(`${marker} `);
394
+ this.options.onStateChange();
395
+ return { id, marker, generation: this.draftGeneration };
396
+ }
397
+ finishPaste(id) {
398
+ this.pasteOperations.finish(id);
399
+ this.editor.disableSubmit = this.pasteOperations.hasPending;
400
+ this.options.onStateChange();
401
+ }
402
+ replacePasteMarker(marker, replacement, removeTrailingSeparator = false) {
403
+ const text = this.editor.getText();
404
+ const start = text.indexOf(marker);
405
+ if (start < 0)
406
+ return false;
407
+ const markerEnd = start + marker.length;
408
+ const end = removeTrailingSeparator && text[markerEnd] === " "
409
+ ? markerEnd + 1
410
+ : markerEnd;
411
+ this.applyingEditorState = true;
412
+ this.editor.replaceRange(start, end, replacement);
413
+ this.applyingEditorState = false;
414
+ if (this.recentPreviewLabel && replacement.includes(this.recentPreviewLabel)) {
415
+ this.recentPreviewCursorOffset = this.editor.getCursorOffset();
416
+ }
417
+ return true;
418
+ }
419
+ startClipboardPaste(fallbackText, notifyWhenEmpty = false) {
420
+ const pending = this.beginPastePlaceholder();
421
+ const readClipboardImage = this.options.readClipboardImage ?? ingestClipboardImage;
422
+ void readClipboardImage()
423
+ .then(({ attachment, error }) => {
424
+ if (this.disposed || pending.generation !== this.draftGeneration)
425
+ return;
426
+ if (!attachment) {
427
+ this.replacePasteMarker(pending.marker, fallbackText, fallbackText.length === 0);
428
+ if (notifyWhenEmpty && error === "clipboard has no image") {
429
+ this.options.onNotice("Clipboard does not contain a supported image.");
430
+ }
431
+ else if (error && error !== "clipboard has no image") {
432
+ this.options.onNotice(`Image paste failed: ${error}`);
433
+ }
434
+ return;
435
+ }
436
+ if (!this.editor.getText().includes(pending.marker))
437
+ return;
438
+ const item = this.registerAttachment(attachment);
439
+ this.replacePasteMarker(pending.marker, item.label);
440
+ })
441
+ .finally(() => this.finishPaste(pending.id));
442
+ }
443
+ startPathPaste(pastedText, tokens) {
444
+ const pending = this.beginPastePlaceholder();
445
+ void Promise.all(tokens.map(async (token) => ({ token, result: await ingestImagePath(token.rawPath) })))
446
+ .then((results) => {
447
+ if (this.disposed || pending.generation !== this.draftGeneration)
448
+ return;
449
+ if (!this.editor.getText().includes(pending.marker))
450
+ return;
451
+ let replacement = "";
452
+ let cursor = 0;
453
+ for (const { token, result } of results) {
454
+ replacement += pastedText.slice(cursor, token.start);
455
+ if (result.attachment) {
456
+ replacement += this.registerAttachment(result.attachment).label;
457
+ }
458
+ else {
459
+ replacement += pastedText.slice(token.start, token.end);
460
+ this.options.onNotice(`${token.rawPath}: ${result.error ?? "could not attach image"}`);
461
+ }
462
+ cursor = token.end;
463
+ }
464
+ replacement += pastedText.slice(cursor);
465
+ this.replacePasteMarker(pending.marker, replacement);
466
+ })
467
+ .finally(() => this.finishPaste(pending.id));
468
+ }
469
+ registerAttachment(attachment) {
470
+ if (this.imageDisplayStart === undefined)
471
+ this.imageDisplayStart = this.nextImageLabelStart;
472
+ const item = {
473
+ attachment: { ...attachment },
474
+ label: imageDisplayLabel(this.imageDisplayStart + this.attachments.length),
475
+ };
476
+ this.attachments.push(item);
477
+ this.recentPreviewLabel = item.label;
478
+ this.syncEditorDecorations();
479
+ return item;
480
+ }
481
+ syncEditorDecorations() {
482
+ const decorations = this.attachments.map((item) => ({
483
+ id: item.label,
484
+ text: item.label,
485
+ style: (text, state) => {
486
+ const theme = this.options.getTheme?.() ?? darkTheme;
487
+ const background = state.focused
488
+ ? theme.traceSelectedBg
489
+ : state.hovered
490
+ ? theme.traceHoverBg
491
+ : theme.backgroundElement;
492
+ return themeForeground(theme.inputText, themeBackground(background, text));
493
+ },
494
+ }));
495
+ this.editor.setInlineDecorations(decorations);
496
+ }
497
+ invalidateDraftAsyncWork() {
498
+ this.draftGeneration++;
499
+ this.pasteOperations.invalidateAll();
500
+ this.editor.disableSubmit = false;
501
+ }
502
+ }
@@ -0,0 +1,194 @@
1
+ /**
2
+ * BubbleTuiController — the framework-neutral runtime orchestrator
3
+ * (design doc §8.1). Assembles the extracted sub-modules:
4
+ *
5
+ * - agent-event-reducer (stream/tool/turn semantics)
6
+ * - input-queue-machine (steer/queue lifecycle)
7
+ * - overlay-controller (blocking request lifecycle)
8
+ * - session-transition (two-phase atomic switch)
9
+ * - task-runtime-controller (task markers/wakes)
10
+ *
11
+ * The controller consumes an Agent event stream, applies effects, batches
12
+ * streaming updates behind the 40ms FlushScheduler, and publishes immutable
13
+ * snapshots. Renderers subscribe; they never mutate.
14
+ */
15
+ import type { Agent, AgentRunOptions } from "../../agent.js";
16
+ import type { WorkflowRunSnapshot } from "../../agent/workflow/control.js";
17
+ import type { BackgroundTaskInfo, ProcessManager } from "../../tasks/manager.js";
18
+ import { SessionManager } from "../../session.js";
19
+ import type { GoalStore } from "../../goal/store.js";
20
+ import type { BubbleTuiPorts } from "./ports.js";
21
+ import type { ControllerEffect } from "./effects.js";
22
+ import { type DisplayMessage, type DisplayMessagePart, type DisplayToolCall } from "../model/display-history.js";
23
+ import { type SubagentGroup } from "../model/subagent-view.js";
24
+ import type { SubmitPayload } from "../model/composer-types.js";
25
+ import type { PromotionChannel } from "../../tasks/promotion.js";
26
+ import { type RewindExecutionResult, type RewindScope } from "../../rewind.js";
27
+ import type { Message } from "../../types.js";
28
+ export interface TuiExitSummary {
29
+ reason: string;
30
+ wallMs: number;
31
+ }
32
+ export interface BubbleTuiControllerDeps {
33
+ readonly agent: Pick<Agent, "run" | "messages" | "setSessionID" | "listSubAgents" | "listWorkflows" | "getSubAgentMessages" | "closeSubAgent" | "closeWorkflow" | "resetContextUsageAnchor"> & {
34
+ messages: Message[];
35
+ backgroundTasks?: Agent["backgroundTasks"];
36
+ };
37
+ readonly sessionManager: SessionManager;
38
+ readonly goalStore?: GoalStore;
39
+ readonly processManager?: ProcessManager;
40
+ readonly tasksAutoResume?: boolean;
41
+ readonly promotionChannel?: PromotionChannel;
42
+ readonly workspaceCwd?: string;
43
+ readonly ports: BubbleTuiPorts;
44
+ readonly onEffect?: (effect: ControllerEffect) => void;
45
+ }
46
+ export interface TuiAgentRunOptions extends AgentRunOptions {
47
+ /** Internal Goal continuation; never forwarded to Agent.run(). */
48
+ goalRun?: boolean;
49
+ }
50
+ export interface CommandActivity {
51
+ kind: "compact";
52
+ status: "running" | "cancelling";
53
+ startedAt: number;
54
+ }
55
+ export declare class BubbleTuiController {
56
+ private readonly deps;
57
+ private readonly state;
58
+ private readonly listeners;
59
+ private readonly overlays;
60
+ private readonly queue;
61
+ private readonly sessionTransition;
62
+ private readonly startedAtMs;
63
+ private readonly goalRuntime?;
64
+ private readonly taskRuntime?;
65
+ private readonly pendingTaskAnnouncements;
66
+ private sessionManager;
67
+ private transcript;
68
+ private runActive;
69
+ private runState;
70
+ /** Background subagent updates can outlive the provider turn that launched
71
+ * them. Keep their latest synthetic tool snapshot in the live trace. */
72
+ private readonly liveSubagentTools;
73
+ /** Provider-turn accumulators for true child-session inspection. */
74
+ private readonly childRuns;
75
+ private activeInputController;
76
+ private activeAbortController;
77
+ private commandActivity;
78
+ /** False after a provider turn commits, so settled and live rows never coexist. */
79
+ private liveStreamVisible;
80
+ private readonly backgroundTaskUnsubscribe?;
81
+ private disposed;
82
+ constructor(deps: BubbleTuiControllerDeps);
83
+ private externalGeneration;
84
+ private liveSubagentVersion;
85
+ subscribe(listener: (version: number) => void): () => void;
86
+ getSnapshotVersion(): number;
87
+ getTranscript(): readonly DisplayMessage[];
88
+ getSessionManager(): SessionManager;
89
+ getGoalIndicator(): string | undefined;
90
+ handleGoalCommand(input: string, cwd: string): void;
91
+ getSubagentGroups(): SubagentGroup[];
92
+ getWorkflows(): WorkflowRunSnapshot[];
93
+ getBackgroundTasks(): BackgroundTaskInfo[];
94
+ getChildTranscript(agentId: string): DisplayMessage[];
95
+ getChildStreamingTail(agentId: string): {
96
+ content: string;
97
+ reasoning: string;
98
+ tools: DisplayToolCall[];
99
+ parts: DisplayMessagePart[];
100
+ } | null;
101
+ stopSubagent(agentId: string): void;
102
+ stopWorkflow(runId: string): void;
103
+ stopBackgroundTask(id: string): void;
104
+ getBackgroundTaskOutput(id: string): string;
105
+ /** Called by the host after graceful task reaping on TUI exit. */
106
+ persistFinalTaskMarkers(): void;
107
+ private appendTaskMarker;
108
+ private announceTaskCompletion;
109
+ /** Move the newest live Bash Execute into the unified task manager. */
110
+ promoteActiveBash(): string | undefined;
111
+ /** Drop every transcript row (/clear). */
112
+ clearTranscript(): void;
113
+ /** Re-project the visible transcript after a non-controller command rewrites Agent history. */
114
+ rebuildTranscriptFromAgent(): void;
115
+ /**
116
+ * Rewind persistence and every renderer-facing mirror as one observable
117
+ * transition. File restoration can take time, but no partial transcript is
118
+ * published while it runs.
119
+ */
120
+ rewindToTurn(targetId: string, scope: RewindScope): Promise<RewindExecutionResult>;
121
+ /** Host-side row injection (user echo, notices) — single append point. */
122
+ appendDisplayMessage(message: DisplayMessage): void;
123
+ isRunning(): boolean;
124
+ /** A slash command that owns the activity lane without masquerading as an
125
+ * Agent turn. This keeps streaming/steering state separate while still
126
+ * giving Escape and Ctrl+C one cancellation boundary. */
127
+ beginCommandActivity(kind: CommandActivity["kind"]): AbortSignal;
128
+ finishCommandActivity(kind: CommandActivity["kind"], event?: DisplayMessage): void;
129
+ getCommandActivity(): CommandActivity | null;
130
+ isBusy(): boolean;
131
+ /** Queue composer input while a command owns the pane. Grok keeps the
132
+ * composer available during Compact; the message starts after the command
133
+ * reaches its terminal event instead of racing the history rewrite. */
134
+ queueAfterCommand(input: string | SubmitPayload): boolean;
135
+ /** Queue a complete composer payload for the next provider turn. */
136
+ queueInput(input: string | SubmitPayload): void;
137
+ drainQueuedInputs(cwd: string, agentOptions?: AgentRunOptions): Promise<void>;
138
+ pendingSteerCount(): number;
139
+ queuedInputCount(): number;
140
+ private submitDisplayText;
141
+ private submitAgentInput;
142
+ /** Add input to the current Agent run without creating a second run that
143
+ * would overwrite the shared streaming accumulator. */
144
+ steer(content: string): boolean;
145
+ cancelActiveRun(reason?: string): boolean;
146
+ /**
147
+ * Live streaming tail for the render loop: the in-flight accumulator's
148
+ * content/reasoning/tool summary. Renderers draw it in the live region
149
+ * (never committed to scrollback) until the turn commits.
150
+ */
151
+ getStreamingTail(): {
152
+ content: string;
153
+ reasoning: string;
154
+ tools: DisplayToolCall[];
155
+ parts: DisplayMessagePart[];
156
+ phase: "thinking" | "working";
157
+ } | null;
158
+ pendingOverlayCount(): number;
159
+ /**
160
+ * Drive one agent run: reduce the event stream, apply effects, and finish.
161
+ * Mirrors runAgentInput (app.tsx:1438-1958) minus the rendering.
162
+ */
163
+ runTurn(input: unknown, cwd: string, options?: TuiAgentRunOptions): Promise<void>;
164
+ /** Apply one reducer transition and publish exactly one observable snapshot. */
165
+ private applyEffects;
166
+ /** Mutate for one effect; callers own the surrounding transaction + notify. */
167
+ private applyEffectMutation;
168
+ private notify;
169
+ private reduceChildEvent;
170
+ private isAbortLike;
171
+ /** Drain leftover steers at run end (cancelled drops, normal requeues). */
172
+ drainLeftovers(leftovers: Array<{
173
+ id: string;
174
+ content: string;
175
+ }>, cancelled: boolean): void;
176
+ /** Atomic session switch through the two-phase transaction. */
177
+ switchSession(plan: {
178
+ targetFile: string;
179
+ notice?: string;
180
+ }): {
181
+ ok: boolean;
182
+ error?: string;
183
+ };
184
+ /** Start an empty native session using the same atomic lifecycle as resume. */
185
+ createFreshSession(cwd: string, notice?: string): {
186
+ ok: boolean;
187
+ error?: string;
188
+ };
189
+ /**
190
+ * Shutdown: settle overlays, cancel any run, and report the exit summary.
191
+ * Idempotent — a second call is a no-op.
192
+ */
193
+ shutdown(reason: string): TuiExitSummary;
194
+ }