@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
@@ -18,14 +18,89 @@ import { feishuCommand } from "./feishu.js";
18
18
  import { GROK_LOCAL_COMMAND_HELP } from "../external-runtime/grok-input-policy.js";
19
19
  import { isGrokSubscriptionProviderId } from "../external-runtime/grok-provider.js";
20
20
  import { classifyExternalRuntimeBinding } from "../external-runtime/session-policy.js";
21
+ import { providerModelPolicyError } from "../provider-model-policy.js";
22
+ import { executeRewind } from "../rewind.js";
21
23
  const VALID_SCOPES = ["user", "project", "local"];
22
24
  const VALID_LISTS = ["allow", "deny"];
25
+ function isAbortLike(error) {
26
+ return error instanceof Error && (error.name === "AbortError" || error.name === "AgentAbortError");
27
+ }
28
+ function formatCompactDuration(elapsedMs) {
29
+ if (elapsedMs < 1_000)
30
+ return `${Math.max(0, Math.round(elapsedMs))}ms`;
31
+ return `${(elapsedMs / 1_000).toFixed(1)}s`;
32
+ }
23
33
  function isScope(value) {
24
34
  return VALID_SCOPES.includes(value);
25
35
  }
26
36
  function isList(value) {
27
37
  return VALID_LISTS.includes(value);
28
38
  }
39
+ async function handleRewindCommand(args, ctx) {
40
+ const session = ctx.sessionManager;
41
+ if (!session)
42
+ return "Rewind requires an active session.";
43
+ const turns = session.listUserTurns();
44
+ if (turns.length === 0)
45
+ return "Nothing to rewind: no user messages in this session.";
46
+ const tokens = args.trim().split(/\s+/).filter(Boolean);
47
+ const flags = tokens.filter((token) => token.startsWith("--"));
48
+ const positional = tokens.filter((token) => !token.startsWith("--"));
49
+ const checkpoints = session.getCheckpoints();
50
+ if (positional.length === 0) {
51
+ if (ctx.openRewindPicker) {
52
+ ctx.openRewindPicker();
53
+ return;
54
+ }
55
+ const lines = ["Rewind points (oldest first):", ""];
56
+ turns.forEach((turn, index) => {
57
+ const time = new Date(turn.timestamp).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
58
+ const files = checkpoints.filesTouchedAt(turn.id).length;
59
+ const fileNote = files > 0 ? ` [${files} file${files === 1 ? "" : "s"} changed]` : "";
60
+ lines.push(` ${index + 1}. ${time} ${turn.preview}${fileNote}`);
61
+ });
62
+ lines.push("", "Usage:", " /rewind <n> restore conversation AND files to just before message n", " /rewind <n> --chat conversation only", " /rewind <n> --code files only", "", "Note: only edits made by the edit/write tools are tracked; changes from", "bash commands are not. Checkpoints complement git, they don't replace it.");
63
+ return lines.join("\n");
64
+ }
65
+ const n = Number(positional[0]);
66
+ if (!Number.isInteger(n) || n < 1 || n > turns.length) {
67
+ return `Invalid rewind point "${positional[0]}". Run /rewind to list points (1-${turns.length}).`;
68
+ }
69
+ const target = turns[n - 1];
70
+ const codeOnly = flags.includes("--code");
71
+ const chatOnly = flags.includes("--chat") || flags.includes("--conversation");
72
+ if (codeOnly && chatOnly)
73
+ return "Pick at most one of --code / --chat.";
74
+ const scope = codeOnly ? "code" : chatOnly ? "chat" : "all";
75
+ const result = await executeRewind(session, ctx.agent, target.id, scope);
76
+ const lines = [
77
+ codeOnly
78
+ ? `Files restored to just before: ${target.preview}`
79
+ : `⏪ Rewound to before: ${target.preview}`,
80
+ ];
81
+ if (scope !== "chat") {
82
+ const touched = result.files.restored.length + result.files.deleted.length;
83
+ if (touched === 0 && result.files.failed.length === 0) {
84
+ lines.push("Files: no tracked edits to undo.");
85
+ }
86
+ else {
87
+ for (const file of result.files.restored)
88
+ lines.push(`Restored ${file}`);
89
+ for (const file of result.files.deleted)
90
+ lines.push(`Deleted ${file} (created after this point)`);
91
+ for (const file of result.files.failed)
92
+ lines.push(`FAILED to restore ${file}`);
93
+ }
94
+ }
95
+ if (scope !== "code") {
96
+ ctx.rebuildTranscript?.();
97
+ if (ctx.fillComposer)
98
+ ctx.fillComposer(target.text);
99
+ else
100
+ lines.push("", "Rewound message (copy to re-edit):", target.text);
101
+ }
102
+ return lines.join("\n");
103
+ }
29
104
  function handlePermissionsMutation(sub, tokens, ctx) {
30
105
  if (!ctx.settingsManager) {
31
106
  return "No settings manager is attached to this session.";
@@ -449,7 +524,12 @@ const builtinSlashCommandEntries = [
449
524
  name: "context",
450
525
  description: "Show current context window usage and breakdown",
451
526
  async handler(_args, ctx) {
452
- return `${formatContextUsage(ctx.agent.getContextUsageSnapshot())}\n\n${formatMcpContextStatus(ctx)}`;
527
+ const snapshot = ctx.agent.getContextUsageSnapshot();
528
+ if (ctx.openContextInfo) {
529
+ ctx.openContextInfo(snapshot);
530
+ return;
531
+ }
532
+ return `${formatContextUsage(snapshot)}\n\n${formatMcpContextStatus(ctx)}`;
453
533
  },
454
534
  },
455
535
  {
@@ -496,81 +576,12 @@ const builtinSlashCommandEntries = [
496
576
  {
497
577
  name: "rewind",
498
578
  description: "Rewind conversation and/or file edits to before an earlier message. Usage: /rewind [n] [--code|--chat]",
499
- async handler(args, ctx) {
500
- const session = ctx.sessionManager;
501
- if (!session) {
502
- return "Rewind requires an active session.";
503
- }
504
- const turns = session.listUserTurns();
505
- if (turns.length === 0) {
506
- return "Nothing to rewind: no user messages in this session.";
507
- }
508
- const tokens = args.trim().split(/\s+/).filter(Boolean);
509
- const flags = tokens.filter((token) => token.startsWith("--"));
510
- const positional = tokens.filter((token) => !token.startsWith("--"));
511
- const checkpoints = session.getCheckpoints();
512
- if (positional.length === 0) {
513
- if (ctx.openRewindPicker) {
514
- ctx.openRewindPicker();
515
- return;
516
- }
517
- const lines = ["Rewind points (oldest first):", ""];
518
- turns.forEach((turn, index) => {
519
- const time = new Date(turn.timestamp).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
520
- const files = checkpoints.filesTouchedAt(turn.id).length;
521
- const fileNote = files > 0 ? ` [${files} file${files === 1 ? "" : "s"} changed]` : "";
522
- lines.push(` ${index + 1}. ${time} ${turn.preview}${fileNote}`);
523
- });
524
- lines.push("", "Usage:", " /rewind <n> restore conversation AND files to just before message n", " /rewind <n> --chat conversation only", " /rewind <n> --code files only", "", "Note: only edits made by the edit/write tools are tracked; changes from", "bash commands are not. Checkpoints complement git, they don't replace it.");
525
- return lines.join("\n");
526
- }
527
- const n = Number(positional[0]);
528
- if (!Number.isInteger(n) || n < 1 || n > turns.length) {
529
- return `Invalid rewind point "${positional[0]}". Run /rewind to list points (1-${turns.length}).`;
530
- }
531
- const target = turns[n - 1];
532
- const codeOnly = flags.includes("--code");
533
- const chatOnly = flags.includes("--chat") || flags.includes("--conversation");
534
- if (codeOnly && chatOnly) {
535
- return "Pick at most one of --code / --chat.";
536
- }
537
- // The "⏪" prefix is recognized by the TUIs: they rebuild the visible
538
- // transcript from the rewound agent.messages before showing this text.
539
- const lines = [
540
- codeOnly
541
- ? `Files restored to just before: ${target.preview}`
542
- : `⏪ Rewound to before: ${target.preview}`,
543
- ];
544
- if (!chatOnly) {
545
- const restore = await checkpoints.restoreTo(target.id);
546
- const touched = restore.restored.length + restore.deleted.length;
547
- if (touched === 0 && restore.failed.length === 0) {
548
- lines.push("Files: no tracked edits to undo.");
549
- }
550
- else {
551
- for (const file of restore.restored)
552
- lines.push(`Restored ${file}`);
553
- for (const file of restore.deleted)
554
- lines.push(`Deleted ${file} (created after this point)`);
555
- for (const file of restore.failed)
556
- lines.push(`FAILED to restore ${file}`);
557
- }
558
- }
559
- if (!codeOnly) {
560
- session.rewindToEntry(target.id);
561
- const head = ctx.agent.messages.filter((m) => m.role === "system" || m.role === "meta");
562
- ctx.agent.messages = [...head, ...session.getMessages()];
563
- ctx.agent.resetContextUsageAnchor();
564
- if (ctx.fillComposer) {
565
- // Put the rewound message back into the input box for re-editing.
566
- ctx.fillComposer(target.text);
567
- }
568
- else {
569
- lines.push("", "Rewound message (copy to re-edit):", target.text);
570
- }
571
- }
572
- return lines.join("\n");
573
- },
579
+ handler: handleRewindCommand,
580
+ },
581
+ {
582
+ name: "undo",
583
+ description: "Alias for /rewind",
584
+ handler: handleRewindCommand,
574
585
  },
575
586
  {
576
587
  name: "session",
@@ -796,6 +807,9 @@ const builtinSlashCommandEntries = [
796
807
  const next = parsed.model.includes(":") ? parsed.model : encodeModel(defaultProvider, parsed.model);
797
808
  const { providerId, modelId } = decodeModel(next);
798
809
  const targetProviderId = providerId || defaultProvider;
810
+ const modelPolicyError = providerModelPolicyError(targetProviderId, modelId);
811
+ if (modelPolicyError)
812
+ return modelPolicyError;
799
813
  await ctx.registry.prepareProvider(targetProviderId);
800
814
  const targetProvider = ctx.registry.getConfigured().find((item) => item.id === targetProviderId);
801
815
  if (!targetProvider?.apiKey) {
@@ -842,6 +856,15 @@ const builtinSlashCommandEntries = [
842
856
  return `OAuth credentials for ${providerId} removed.`;
843
857
  },
844
858
  },
859
+ {
860
+ name: "goal",
861
+ description: "Set, manage, or inspect an autonomous goal. Usage: /goal <objective> [--budget N] | status | pause | resume | edit | clear",
862
+ async handler(args, ctx) {
863
+ if (!ctx.handleGoalCommand)
864
+ return "Goals are not available in this host.";
865
+ await ctx.handleGoalCommand(`/goal${args.trim() ? ` ${args.trim()}` : ""}`);
866
+ },
867
+ },
845
868
  {
846
869
  name: "plan",
847
870
  description: "Toggle plan mode on/off (Tab switches Build/Plan)",
@@ -1068,8 +1091,8 @@ const builtinSlashCommandEntries = [
1068
1091
  },
1069
1092
  {
1070
1093
  name: "compact",
1071
- description: "Manually compact the current session context",
1072
- async handler(_args, ctx) {
1094
+ description: "Compact session context; optional text says what to preserve",
1095
+ async handler(args, ctx) {
1073
1096
  if (!ctx.sessionManager) {
1074
1097
  return "Compaction requires session persistence. Start an interactive session first.";
1075
1098
  }
@@ -1087,6 +1110,8 @@ const builtinSlashCommandEntries = [
1087
1110
  if (preHook?.decision === "deny") {
1088
1111
  return preHook.reason ?? `Compaction blocked by hook ${preHook.sourceHookId ?? "<unknown>"}.`;
1089
1112
  }
1113
+ if (ctx.compactionAbortSignal?.aborted)
1114
+ return "Compaction cancelled.";
1090
1115
  // Plan first so we can report "already compact" without spending a model
1091
1116
  // call, and so the LLM summarizer gets the exact set of evicted messages.
1092
1117
  const plan = ctx.sessionManager.getCompactionPlan();
@@ -1105,15 +1130,23 @@ const builtinSlashCommandEntries = [
1105
1130
  // On any failure (or empty output) fall back to the instant heuristic
1106
1131
  // compaction so /compact always makes progress.
1107
1132
  let result;
1133
+ const startedAt = Date.now();
1108
1134
  try {
1109
1135
  ctx.compactionProgress?.({ phase: "collecting", streamedChars: 0 });
1110
1136
  let summary = "";
1111
1137
  try {
1112
1138
  summary = await ctx.agent.summarizeForCompaction(plan.oldMessages, (full) => {
1113
1139
  ctx.compactionProgress?.({ phase: "summarizing", streamedChars: full.length });
1114
- });
1140
+ }, ctx.compactionAbortSignal, args);
1141
+ // The signal is authoritative even if a provider finishes normally
1142
+ // after ignoring or racing its abort notification.
1143
+ if (ctx.compactionAbortSignal?.aborted)
1144
+ return "Compaction cancelled.";
1115
1145
  }
1116
- catch {
1146
+ catch (error) {
1147
+ if (ctx.compactionAbortSignal?.aborted || isAbortLike(error)) {
1148
+ return "Compaction cancelled.";
1149
+ }
1117
1150
  summary = "";
1118
1151
  }
1119
1152
  if (summary) {
@@ -1160,7 +1193,13 @@ const builtinSlashCommandEntries = [
1160
1193
  droppedEntries: dropped,
1161
1194
  },
1162
1195
  });
1163
- return `✓ Compaction complete · ${dropped} log entr${dropped === 1 ? "y" : "ies"} summarized`;
1196
+ return {
1197
+ result: `Compaction completed in ${formatCompactDuration(Date.now() - startedAt)}.`,
1198
+ detail: {
1199
+ kind: "compaction-summary",
1200
+ content: result.summary ?? "",
1201
+ },
1202
+ };
1164
1203
  },
1165
1204
  },
1166
1205
  {
@@ -1,4 +1,4 @@
1
- import type { SlashCommand, SlashCommandContext } from "./types.js";
1
+ import type { SlashCommand, SlashCommandContext, SlashCommandResultDetail } from "./types.js";
2
2
  import { type CommandSource, type UnifiedCommand } from "./unified.js";
3
3
  /**
4
4
  * Dynamic source: called at lookup time to produce extra commands (e.g. MCP
@@ -27,5 +27,6 @@ export declare class SlashCommandRegistry {
27
27
  handled: boolean;
28
28
  result?: string;
29
29
  inject?: string;
30
+ detail?: SlashCommandResultDetail;
30
31
  }>;
31
32
  }
@@ -61,6 +61,9 @@ export class SlashCommandRegistry {
61
61
  if (output && typeof output === "object" && "inject" in output) {
62
62
  return { handled: true, inject: output.inject };
63
63
  }
64
+ if (output && typeof output === "object" && "result" in output) {
65
+ return { handled: true, result: output.result, detail: output.detail };
66
+ }
64
67
  return { handled: true, result: typeof output === "string" ? output : undefined };
65
68
  }
66
69
  catch (err) {
@@ -11,16 +11,21 @@ import type { MemoryScope } from "../memory/index.js";
11
11
  import type { ThemeMode } from "../config.js";
12
12
  import type { ExternalHookController } from "../hooks/controller.js";
13
13
  import type { ExternalRuntimeManager } from "../external-runtime/types.js";
14
+ import type { ContextUsageSnapshot } from "../context/usage.js";
14
15
  /**
15
- * Live progress for a manual `/compact` run, pushed to the TUI so it can render
16
- * a progress bar. `phase` advances collecting → summarizing → applying;
17
- * `streamedChars` is the running length of the streamed summary (drives the
18
- * bar's fill within the summarizing phase). Hosts without a UI omit the sink.
16
+ * Live progress for a manual `/compact` run. `phase` advances collecting →
17
+ * summarizing → applying; interactive hosts can use it for diagnostics while
18
+ * the visible Grok-style activity lane remains a stable `Compacting…` state.
19
+ * Hosts without a UI omit the sink.
19
20
  */
20
21
  export interface CompactionProgress {
21
22
  phase: "collecting" | "summarizing" | "applying";
22
23
  streamedChars: number;
23
24
  }
25
+ export interface SlashCommandResultDetail {
26
+ kind: "compaction-summary";
27
+ content: string;
28
+ }
24
29
  export interface SlashCommandContext {
25
30
  agent: Agent;
26
31
  addMessage: (role: "user" | "assistant" | "error", content: string) => void;
@@ -55,13 +60,21 @@ export interface SlashCommandContext {
55
60
  openSessionPicker?: () => void;
56
61
  /** Replace the composer/input box content (e.g. /rewind restores the rewound message for re-editing). */
57
62
  fillComposer?: (text: string) => void;
63
+ /** Re-project host transcript state after a command rewrites agent.messages. */
64
+ rebuildTranscript?: () => void;
58
65
  /** Open the interactive usage stats panel. */
59
66
  openStats?: () => void;
67
+ /** Open the interactive context-usage panel. Text-only hosts omit this. */
68
+ openContextInfo?: (snapshot: ContextUsageSnapshot) => void;
69
+ /** Execute the persistent autonomous Goal lifecycle in an interactive host. */
70
+ handleGoalCommand?: (input: string) => void | Promise<void>;
60
71
  /**
61
72
  * Push live compaction progress to the running TUI. Pass a progress object
62
73
  * while compacting and `null` to clear the indicator. Absent in non-TUI hosts.
63
74
  */
64
75
  compactionProgress?: (progress: CompactionProgress | null) => void;
76
+ /** Cancellation signal owned by the interactive host's Compact activity. */
77
+ compactionAbortSignal?: AbortSignal;
65
78
  /** External agent runtime used by Grok subscription chat. */
66
79
  externalRuntime?: ExternalRuntimeManager;
67
80
  /**
@@ -80,9 +93,14 @@ export interface SlashCommandContext {
80
93
  * - string | void: the string (if any) is displayed as an assistant message
81
94
  * - { inject }: the content is sent to the agent as the user's next turn
82
95
  * (used by MCP prompts that expand a template into a user message)
96
+ * - { result, detail }: keep the visible result terse while exposing
97
+ * structured, host-rendered detail such as an inspectable Compact summary
83
98
  */
84
99
  export type SlashCommandOutput = string | void | {
85
100
  inject: string;
101
+ } | {
102
+ result: string;
103
+ detail?: SlashCommandResultDetail;
86
104
  };
87
105
  export interface SlashCommand {
88
106
  name: string;
@@ -51,7 +51,9 @@ export declare function collectUsageStatsBundle(options?: {
51
51
  sessionsRoot?: string;
52
52
  }): UsageStatsBundle;
53
53
  export declare function formatStatsText(bundle: UsageStatsBundle, range?: StatsRange, width?: number): string;
54
- export declare function formatStatsPanelBody(stats: UsageStats, width?: number): string;
54
+ export declare function formatStatsPanelBody(stats: UsageStats, width?: number, options?: {
55
+ expandedModels?: boolean;
56
+ }): string;
55
57
  export declare function rangeLabel(range: StatsRange): string;
56
58
  export declare function formatCompactNumber(value: number): string;
57
59
  export declare function formatCurrency(value: number): string;
@@ -9,7 +9,7 @@ const RANGES = [
9
9
  ];
10
10
  const WEEKDAY_LABELS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
11
11
  const EMPTY_CELL = " ";
12
- const HEAT_LEVELS = [".", "o", "O", "@"];
12
+ const HEAT_LEVELS = ["·", "○", "◉", "●"];
13
13
  const MAX_MODEL_ROWS = 5;
14
14
  export function collectUsageStatsBundle(options = {}) {
15
15
  const now = options.now ?? new Date();
@@ -34,14 +34,14 @@ export function formatStatsText(bundle, range = "30d", width = 78) {
34
34
  formatStatsPanelBody(stats, width),
35
35
  ].join("\n");
36
36
  }
37
- export function formatStatsPanelBody(stats, width = 72) {
37
+ export function formatStatsPanelBody(stats, width = 72, options = {}) {
38
38
  const bodyWidth = Math.max(48, width);
39
39
  const lines = [];
40
40
  lines.push("Activity");
41
41
  lines.push(...formatHeatmapLines(stats));
42
42
  lines.push("");
43
43
  lines.push("Model usage");
44
- lines.push(...formatModelUsageLines(stats, bodyWidth));
44
+ lines.push(...formatModelUsageLines(stats, bodyWidth, options.expandedModels ?? false));
45
45
  lines.push("");
46
46
  lines.push("Summary");
47
47
  lines.push(...formatSummaryLines(stats, bodyWidth));
@@ -131,7 +131,7 @@ function processSessionFile(file, accumulators) {
131
131
  markActiveDay(accumulator, timestamp, usage);
132
132
  if (message && usage && model) {
133
133
  flags.hasUsage = true;
134
- addModelUsage(accumulator, model, message, usage);
134
+ addModelUsage(accumulator, model, message, usage, timestamp);
135
135
  }
136
136
  }
137
137
  }
@@ -172,7 +172,7 @@ function finalizeAccumulator(accumulator) {
172
172
  sessionsWithoutTokenData: accumulator.sessionsWithoutTokenData,
173
173
  };
174
174
  }
175
- function addModelUsage(accumulator, model, message, usage) {
175
+ function addModelUsage(accumulator, model, message, usage, timestamp) {
176
176
  const decoded = decodeModel(model);
177
177
  const providerId = typeof message.providerId === "string" ? message.providerId : decoded.providerId;
178
178
  const modelId = typeof message.modelId === "string" ? message.modelId : decoded.modelId;
@@ -200,7 +200,7 @@ function addModelUsage(accumulator, model, message, usage) {
200
200
  existing.reasoningTokens += usage.reasoningTokens ?? 0;
201
201
  existing.totalTokens += tokenTotal(usage);
202
202
  if (providerId && modelId) {
203
- const cost = calculateUsageCost(providerId, modelId, usage);
203
+ const cost = calculateUsageCost(providerId, modelId, usage, timestamp);
204
204
  if (cost) {
205
205
  existing.cost = (existing.cost ?? 0) + cost.cost;
206
206
  existing.costCurrency = cost.currency;
@@ -253,28 +253,34 @@ function formatHeatmapLines(stats) {
253
253
  lines.push(` Less ${HEAT_LEVELS.join(" ")} More`);
254
254
  return lines;
255
255
  }
256
- function formatModelUsageLines(stats, width) {
256
+ function formatModelUsageLines(stats, width, expanded) {
257
257
  if (stats.models.length === 0) {
258
258
  return [" No precise token usage recorded yet."];
259
259
  }
260
260
  const showCost = stats.models.some((model) => model.cost !== undefined);
261
- const overhead = showCost ? 29 : 21;
262
- const minBarWidth = 6;
263
- const labelWidth = Math.max(12, Math.min(28, Math.floor((width - overhead - minBarWidth) * 0.65)));
261
+ const visibleModels = expanded ? stats.models : stats.models.slice(0, MAX_MODEL_ROWS);
262
+ const turnsWidth = Math.max(6, ...visibleModels.map((model) => formatTurnCount(model.turns).length));
263
+ const overhead = (showCost ? 25 : 17) + turnsWidth;
264
+ const minBarWidth = 4;
265
+ const longestLabelWidth = Math.max(...visibleModels.map((model) => model.displayName.length));
266
+ const labelWidth = Math.max(8, Math.min(longestLabelWidth, width - overhead - minBarWidth));
264
267
  const barWidth = Math.max(minBarWidth, Math.min(20, width - labelWidth - overhead));
265
- const rows = stats.models.slice(0, MAX_MODEL_ROWS).map((model) => {
268
+ const rows = visibleModels.map((model) => {
266
269
  const percent = stats.totalTokens > 0 ? model.totalTokens / stats.totalTokens : 0;
267
270
  const bar = usageBar(percent, barWidth);
268
271
  const percentText = `${Math.round(percent * 100)}%`.padStart(4, " ");
269
272
  const tokenText = formatCompactNumber(model.totalTokens).padStart(6, " ");
270
- const turnsText = `${model.turns}t`.padStart(4, " ");
273
+ const turnsText = formatTurnCount(model.turns).padStart(turnsWidth, " ");
271
274
  const costText = showCost
272
275
  ? ` ${(model.cost !== undefined ? formatCurrencyFor(model.cost, model.costCurrency ?? "USD") : "").padStart(7, " ")}`
273
276
  : "";
274
277
  return ` ${truncate(model.displayName, labelWidth).padEnd(labelWidth, " ")} ${bar} ${percentText} ${tokenText} ${turnsText}${costText}`.trimEnd();
275
278
  });
276
279
  if (stats.models.length > MAX_MODEL_ROWS) {
277
- rows.push(` ...and ${stats.models.length - MAX_MODEL_ROWS} more model${stats.models.length - MAX_MODEL_ROWS === 1 ? "" : "s"}`);
280
+ const remaining = stats.models.length - MAX_MODEL_ROWS;
281
+ rows.push(expanded
282
+ ? " ⌃ Show fewer models"
283
+ : ` › Show ${remaining} more model${remaining === 1 ? "" : "s"}`);
278
284
  }
279
285
  return rows;
280
286
  }
@@ -356,6 +362,9 @@ function usageBar(percent, width) {
356
362
  filled = Math.max(0, Math.min(width, filled));
357
363
  return "█".repeat(filled) + "░".repeat(width - filled);
358
364
  }
365
+ function formatTurnCount(turns) {
366
+ return `${turns} ${turns === 1 ? "turn" : "turns"}`;
367
+ }
359
368
  function assistantPayload(entry) {
360
369
  if (entry.type === "assistant_message")
361
370
  return entry.message;
@@ -65,6 +65,8 @@ export interface BackgroundTaskInfo {
65
65
  startedAt: number;
66
66
  endedAt?: number;
67
67
  outputTruncated: boolean;
68
+ /** Total stdout/stderr lines observed, including lines no longer in the tail buffer. */
69
+ outputLines: number;
68
70
  /** Wake fired or model read the task via task_output (design §2.3a). */
69
71
  deliveredAt?: number;
70
72
  ownerSessionId?: string;
@@ -76,7 +78,7 @@ export interface StartBackgroundTaskInput {
76
78
  ownerSessionId?: string;
77
79
  }
78
80
  export interface AdoptBackgroundTaskInput extends StartBackgroundTaskInput {
79
- /** Already-running child handed over by Ctrl+G promotion (design §2.5). */
81
+ /** Already-running child handed over by Ctrl+B promotion (design §2.5). */
80
82
  child: ChildProcess;
81
83
  /** Output accumulated before promotion, seeds the ring buffer. */
82
84
  outputSoFar?: string;
@@ -93,7 +95,7 @@ export declare class ProcessManager {
93
95
  private readonly finishListeners;
94
96
  getTaskStateVersion(): number;
95
97
  startTask(input: StartBackgroundTaskInput): BackgroundTaskInfo;
96
- /** Ctrl+G promotion: adopt a child the bash tool already spawned (§2.5). */
98
+ /** Ctrl+B promotion: adopt a child the bash tool already spawned (§2.5). */
97
99
  adoptTask(input: AdoptBackgroundTaskInput): BackgroundTaskInfo;
98
100
  private reserveTaskSlot;
99
101
  private registerTaskChild;
@@ -30,6 +30,19 @@ const MAX_LOG_BYTES = 96 * 1024;
30
30
  const STOP_FORCE_AFTER_MS = 1000;
31
31
  const MAX_RUNNING_TASKS_PER_SESSION = 8;
32
32
  const MAX_FINISHED_TASKS = 20;
33
+ function countLineBreaks(value) {
34
+ let count = 0;
35
+ for (let index = 0; index < value.length; index += 1) {
36
+ if (value.charCodeAt(index) === 10)
37
+ count += 1;
38
+ }
39
+ return count;
40
+ }
41
+ function logicalLineCount(lineBreaks, hasData, endsWithNewline) {
42
+ if (!hasData)
43
+ return 0;
44
+ return lineBreaks + (endsWithNewline ? 0 : 1);
45
+ }
33
46
  // ---------------------------------------------------------------------------
34
47
  // Manager
35
48
  // ---------------------------------------------------------------------------
@@ -72,7 +85,7 @@ export class ProcessManager {
72
85
  }
73
86
  return this.registerTaskChild(child, { ...input, command });
74
87
  }
75
- /** Ctrl+G promotion: adopt a child the bash tool already spawned (§2.5). */
88
+ /** Ctrl+B promotion: adopt a child the bash tool already spawned (§2.5). */
76
89
  adoptTask(input) {
77
90
  this.reserveTaskSlot(input.ownerSessionId);
78
91
  return this.registerTaskChild(input.child, input, {
@@ -89,6 +102,8 @@ export class ProcessManager {
89
102
  }
90
103
  registerTaskChild(child, input, seed) {
91
104
  const id = `task_${String(this.nextTaskId++).padStart(4, "0")}`;
105
+ const seedOutput = seed?.outputSoFar ?? "";
106
+ const seedLineBreaks = countLineBreaks(seedOutput);
92
107
  const record = {
93
108
  kind: "task",
94
109
  id,
@@ -98,15 +113,26 @@ export class ProcessManager {
98
113
  pid: child.pid,
99
114
  status: "running",
100
115
  startedAt: seed?.startedAt ?? Date.now(),
101
- output: seed?.outputSoFar ?? "",
116
+ output: seedOutput,
102
117
  outputTruncated: false,
118
+ outputLines: logicalLineCount(seedLineBreaks, seedOutput.length > 0, seedOutput.endsWith("\n")),
119
+ outputLineBreaks: seedLineBreaks,
120
+ outputHasData: seedOutput.length > 0,
121
+ outputEndsWithNewline: seedOutput.endsWith("\n"),
103
122
  ownerSessionId: input.ownerSessionId,
104
123
  child,
105
124
  };
106
125
  this.registry.set(id, record);
107
126
  const append = (data) => {
127
+ const chunk = data.toString();
108
128
  const before = record.output;
109
- record.output = appendTailCapped(record.output, data.toString(), MAX_LOG_BYTES);
129
+ record.output = appendTailCapped(record.output, chunk, MAX_LOG_BYTES);
130
+ record.outputLineBreaks += countLineBreaks(chunk);
131
+ if (chunk.length > 0) {
132
+ record.outputHasData = true;
133
+ record.outputEndsWithNewline = chunk.endsWith("\n");
134
+ }
135
+ record.outputLines = logicalLineCount(record.outputLineBreaks, record.outputHasData, record.outputEndsWithNewline);
110
136
  if (!record.outputTruncated && before.length + data.length > record.output.length) {
111
137
  record.outputTruncated = true;
112
138
  }
@@ -114,7 +140,7 @@ export class ProcessManager {
114
140
  child.stdout?.on("data", append);
115
141
  child.stderr?.on("data", append);
116
142
  child.once("error", (error) => {
117
- record.output = appendTailCapped(record.output, `\n[task failed to start: ${error.message}]\n`, MAX_LOG_BYTES);
143
+ append(Buffer.from(`\n[task failed to start: ${error.message}]\n`));
118
144
  this.finalizeTask(record, "failed", null);
119
145
  });
120
146
  child.once("exit", (code) => {
@@ -169,10 +195,9 @@ export class ProcessManager {
169
195
  return;
170
196
  if (record.deliveredAt === undefined) {
171
197
  record.deliveredAt = Date.now();
172
- // Delivered tasks drop their output to bound memory (design §2.2d);
173
- // keep the metadata line for the transcript/reminder demotion.
174
- if (record.status !== "running")
175
- record.output = "";
198
+ // Delivery suppresses duplicate Agent wakes, but the task inspector and
199
+ // `y` copy action must retain the output for the complete UI lifecycle.
200
+ // The existing 96KB-per-task cap and 20-task eviction bound memory.
176
201
  }
177
202
  }
178
203
  async waitTasks(ids, options = {}) {
@@ -293,7 +318,7 @@ export class ProcessManager {
293
318
  return [...this.registry.values()].filter((record) => record.kind === "task");
294
319
  }
295
320
  publicTask(record) {
296
- const { child: _child, output: _output, ...info } = record;
321
+ const { child: _child, output: _output, outputLineBreaks: _outputLineBreaks, outputHasData: _outputHasData, outputEndsWithNewline: _outputEndsWithNewline, ...info } = record;
297
322
  return { ...info };
298
323
  }
299
324
  // -- servers (moved verbatim from server-manager.ts, kind-filtered) --------
@@ -1,9 +1,9 @@
1
1
  /**
2
- * Ctrl+G send-to-background promotion channel (background-tasks design §2.5).
2
+ * Ctrl+B send-to-background promotion channel (background-tasks design §2.5).
3
3
  *
4
4
  * A running foreground bash tool call registers a promotion handler keyed by
5
5
  * its toolCall id at spawn; the TUI requests promotion when the user presses
6
- * Ctrl+G. The handler returns the new task id on success, or undefined when
6
+ * Ctrl+B. The handler returns the new task id on success, or undefined when
7
7
  * it is too late (the command already reached a terminal state — exit,
8
8
  * timeout, cancel — a benign race, not an error).
9
9
  */
@@ -1,9 +1,9 @@
1
1
  /**
2
- * Ctrl+G send-to-background promotion channel (background-tasks design §2.5).
2
+ * Ctrl+B send-to-background promotion channel (background-tasks design §2.5).
3
3
  *
4
4
  * A running foreground bash tool call registers a promotion handler keyed by
5
5
  * its toolCall id at spawn; the TUI requests promotion when the user presses
6
- * Ctrl+G. The handler returns the new task id on success, or undefined when
6
+ * Ctrl+B. The handler returns the new task id on success, or undefined when
7
7
  * it is too late (the command already reached a terminal state — exit,
8
8
  * timeout, cancel — a benign race, not an error).
9
9
  */
@@ -700,6 +700,7 @@ function formatRouteLines(snapshot) {
700
700
  function snapshotToMetadata(snapshot) {
701
701
  return {
702
702
  subAgentId: snapshot.agentId,
703
+ runId: snapshot.runId,
703
704
  agentName: snapshot.agentName,
704
705
  nickname: snapshot.nickname,
705
706
  status: snapshot.status === "closed" ? "cancelled" : snapshot.status,
@@ -707,12 +708,15 @@ function snapshotToMetadata(snapshot) {
707
708
  resumable: snapshot.resumable,
708
709
  profileSource: snapshot.profileSource,
709
710
  category: snapshot.category,
711
+ phase: snapshot.phase,
710
712
  route: snapshot.route,
711
713
  task: snapshot.task,
712
714
  summary: snapshot.summary,
713
715
  toolNotes: snapshot.toolNotes,
714
716
  usage: snapshot.usage,
715
717
  error: snapshot.error,
718
+ createdAt: snapshot.createdAt,
719
+ updatedAt: snapshot.updatedAt,
716
720
  };
717
721
  }
718
722
  function unsupportedProfile(profile) {