@pentoshi/clai 2.0.61 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (462) hide show
  1. package/README.md +262 -368
  2. package/dist/agent/context-manager.d.ts +5 -0
  3. package/dist/agent/context-manager.js +14 -2
  4. package/dist/agent/context-manager.js.map +1 -1
  5. package/dist/agent/events.d.ts +4 -1
  6. package/dist/agent/runner.js +210 -91
  7. package/dist/agent/runner.js.map +1 -1
  8. package/dist/agent/tool-call-parser.d.ts +15 -0
  9. package/dist/agent/tool-call-parser.js +171 -2
  10. package/dist/agent/tool-call-parser.js.map +1 -1
  11. package/dist/app/adapters/agent-event-adapter.d.ts +29 -0
  12. package/dist/app/adapters/agent-event-adapter.js +143 -0
  13. package/dist/app/adapters/agent-event-adapter.js.map +1 -0
  14. package/dist/app/adapters/current-agent-adapter.d.ts +7 -0
  15. package/dist/app/adapters/current-agent-adapter.js +27 -0
  16. package/dist/app/adapters/current-agent-adapter.js.map +1 -0
  17. package/dist/app/adapters/current-jobs-adapter.d.ts +4 -0
  18. package/dist/app/adapters/current-jobs-adapter.js +13 -0
  19. package/dist/app/adapters/current-jobs-adapter.js.map +1 -0
  20. package/dist/app/adapters/current-store-adapter.d.ts +3 -0
  21. package/dist/app/adapters/current-store-adapter.js +22 -0
  22. package/dist/app/adapters/current-store-adapter.js.map +1 -0
  23. package/dist/app/adapters/current-terminal-adapter.d.ts +9 -0
  24. package/dist/app/adapters/current-terminal-adapter.js +31 -0
  25. package/dist/app/adapters/current-terminal-adapter.js.map +1 -0
  26. package/dist/app/adapters/current-updates-adapter.d.ts +7 -0
  27. package/dist/app/adapters/current-updates-adapter.js +31 -0
  28. package/dist/app/adapters/current-updates-adapter.js.map +1 -0
  29. package/dist/app/adapters/in-memory-clipboard-adapter.d.ts +10 -0
  30. package/dist/app/adapters/in-memory-clipboard-adapter.js +20 -0
  31. package/dist/app/adapters/in-memory-clipboard-adapter.js.map +1 -0
  32. package/dist/app/commands/command.d.ts +24 -0
  33. package/dist/app/commands/command.js +4 -0
  34. package/dist/app/commands/command.js.map +1 -0
  35. package/dist/app/commands/registry.d.ts +45 -0
  36. package/dist/app/commands/registry.js +164 -0
  37. package/dist/app/commands/registry.js.map +1 -0
  38. package/dist/app/controllers/disposable.d.ts +15 -0
  39. package/dist/app/controllers/disposable.js +38 -0
  40. package/dist/app/controllers/disposable.js.map +1 -0
  41. package/dist/app/controllers/job-controller.d.ts +22 -0
  42. package/dist/app/controllers/job-controller.js +35 -0
  43. package/dist/app/controllers/job-controller.js.map +1 -0
  44. package/dist/app/controllers/plan-controller.d.ts +31 -0
  45. package/dist/app/controllers/plan-controller.js +69 -0
  46. package/dist/app/controllers/plan-controller.js.map +1 -0
  47. package/dist/app/controllers/session-controller.d.ts +167 -0
  48. package/dist/app/controllers/session-controller.js +467 -0
  49. package/dist/app/controllers/session-controller.js.map +1 -0
  50. package/dist/app/controllers/turn-controller.d.ts +52 -0
  51. package/dist/app/controllers/turn-controller.js +118 -0
  52. package/dist/app/controllers/turn-controller.js.map +1 -0
  53. package/dist/app/events/app-event.d.ts +118 -0
  54. package/dist/app/events/app-event.js +25 -0
  55. package/dist/app/events/app-event.js.map +1 -0
  56. package/dist/app/events/event-buffer.d.ts +51 -0
  57. package/dist/app/events/event-buffer.js +109 -0
  58. package/dist/app/events/event-buffer.js.map +1 -0
  59. package/dist/app/events/sequencer.d.ts +32 -0
  60. package/dist/app/events/sequencer.js +55 -0
  61. package/dist/app/events/sequencer.js.map +1 -0
  62. package/dist/app/ports/agent-port.d.ts +29 -0
  63. package/dist/app/ports/agent-port.js +2 -0
  64. package/dist/app/ports/agent-port.js.map +1 -0
  65. package/dist/app/ports/clipboard-port.d.ts +9 -0
  66. package/dist/app/ports/clipboard-port.js +2 -0
  67. package/dist/app/ports/clipboard-port.js.map +1 -0
  68. package/dist/app/ports/confirm-port.d.ts +17 -0
  69. package/dist/app/ports/confirm-port.js +2 -0
  70. package/dist/app/ports/confirm-port.js.map +1 -0
  71. package/dist/app/ports/jobs-port.d.ts +18 -0
  72. package/dist/app/ports/jobs-port.js +2 -0
  73. package/dist/app/ports/jobs-port.js.map +1 -0
  74. package/dist/app/ports/persistence-port.d.ts +21 -0
  75. package/dist/app/ports/persistence-port.js +2 -0
  76. package/dist/app/ports/persistence-port.js.map +1 -0
  77. package/dist/app/ports/secret-port.d.ts +12 -0
  78. package/dist/app/ports/secret-port.js +2 -0
  79. package/dist/app/ports/secret-port.js.map +1 -0
  80. package/dist/app/ports/terminal-port.d.ts +18 -0
  81. package/dist/app/ports/terminal-port.js +2 -0
  82. package/dist/app/ports/terminal-port.js.map +1 -0
  83. package/dist/app/ports/updates-port.d.ts +12 -0
  84. package/dist/app/ports/updates-port.js +2 -0
  85. package/dist/app/ports/updates-port.js.map +1 -0
  86. package/dist/commands/doctor.js +9 -0
  87. package/dist/commands/doctor.js.map +1 -1
  88. package/dist/commands/update.js +1 -1
  89. package/dist/commands/update.js.map +1 -1
  90. package/dist/index.js +9 -6
  91. package/dist/index.js.map +1 -1
  92. package/dist/llm/router.js +4 -2
  93. package/dist/llm/router.js.map +1 -1
  94. package/dist/prompts/index.d.ts +1 -1
  95. package/dist/prompts/index.js +5 -3
  96. package/dist/prompts/index.js.map +1 -1
  97. package/dist/repl/slash-commands.js +1 -1
  98. package/dist/repl/slash-commands.js.map +1 -1
  99. package/dist/repl.js +35 -107
  100. package/dist/repl.js.map +1 -1
  101. package/dist/store/config.js +3 -1
  102. package/dist/store/config.js.map +1 -1
  103. package/dist/store/history.d.ts +26 -2
  104. package/dist/store/history.js +383 -72
  105. package/dist/store/history.js.map +1 -1
  106. package/dist/store/logs.js +3 -3
  107. package/dist/store/logs.js.map +1 -1
  108. package/dist/store/paths.d.ts +6 -0
  109. package/dist/store/paths.js +38 -0
  110. package/dist/store/paths.js.map +1 -0
  111. package/dist/store/plan.js +8 -5
  112. package/dist/store/plan.js.map +1 -1
  113. package/dist/tools/jobs.js +2 -2
  114. package/dist/tools/jobs.js.map +1 -1
  115. package/dist/tools/registry.js +117 -46
  116. package/dist/tools/registry.js.map +1 -1
  117. package/dist/tools/shell.js +2 -2
  118. package/dist/tools/shell.js.map +1 -1
  119. package/dist/tui/state.js +20 -17
  120. package/dist/tui/state.js.map +1 -1
  121. package/dist/tui-v2/actions/action-id.d.ts +14 -0
  122. package/dist/tui-v2/actions/action-id.js +109 -0
  123. package/dist/tui-v2/actions/action-id.js.map +1 -0
  124. package/dist/tui-v2/actions/action-router.d.ts +18 -0
  125. package/dist/tui-v2/actions/action-router.js +62 -0
  126. package/dist/tui-v2/actions/action-router.js.map +1 -0
  127. package/dist/tui-v2/actions/chord-from-key.d.ts +26 -0
  128. package/dist/tui-v2/actions/chord-from-key.js +45 -0
  129. package/dist/tui-v2/actions/chord-from-key.js.map +1 -0
  130. package/dist/tui-v2/actions/keymap.d.ts +24 -0
  131. package/dist/tui-v2/actions/keymap.js +134 -0
  132. package/dist/tui-v2/actions/keymap.js.map +1 -0
  133. package/dist/tui-v2/app/App.d.ts +13 -0
  134. package/dist/tui-v2/app/App.js +320 -0
  135. package/dist/tui-v2/app/App.js.map +1 -0
  136. package/dist/tui-v2/app/command-handlers.d.ts +8 -0
  137. package/dist/tui-v2/app/command-handlers.js +66 -0
  138. package/dist/tui-v2/app/command-handlers.js.map +1 -0
  139. package/dist/tui-v2/app/commands/config-commands.d.ts +14 -0
  140. package/dist/tui-v2/app/commands/config-commands.js +161 -0
  141. package/dist/tui-v2/app/commands/config-commands.js.map +1 -0
  142. package/dist/tui-v2/app/commands/key-commands.d.ts +9 -0
  143. package/dist/tui-v2/app/commands/key-commands.js +263 -0
  144. package/dist/tui-v2/app/commands/key-commands.js.map +1 -0
  145. package/dist/tui-v2/app/commands/picker-commands.d.ts +24 -0
  146. package/dist/tui-v2/app/commands/picker-commands.js +423 -0
  147. package/dist/tui-v2/app/commands/picker-commands.js.map +1 -0
  148. package/dist/tui-v2/app/commands/session-commands.d.ts +19 -0
  149. package/dist/tui-v2/app/commands/session-commands.js +162 -0
  150. package/dist/tui-v2/app/commands/session-commands.js.map +1 -0
  151. package/dist/tui-v2/app/plan-lifecycle.d.ts +16 -0
  152. package/dist/tui-v2/app/plan-lifecycle.js +59 -0
  153. package/dist/tui-v2/app/plan-lifecycle.js.map +1 -0
  154. package/dist/tui-v2/app/providers.d.ts +17 -0
  155. package/dist/tui-v2/app/providers.js +32 -0
  156. package/dist/tui-v2/app/providers.js.map +1 -0
  157. package/dist/tui-v2/bootstrap/capabilities.d.ts +35 -0
  158. package/dist/tui-v2/bootstrap/capabilities.js +93 -0
  159. package/dist/tui-v2/bootstrap/capabilities.js.map +1 -0
  160. package/dist/tui-v2/bootstrap/composition-root.d.ts +85 -0
  161. package/dist/tui-v2/bootstrap/composition-root.js +131 -0
  162. package/dist/tui-v2/bootstrap/composition-root.js.map +1 -0
  163. package/dist/tui-v2/bootstrap/disable-native-selection.d.ts +11 -0
  164. package/dist/tui-v2/bootstrap/disable-native-selection.js +13 -0
  165. package/dist/tui-v2/bootstrap/disable-native-selection.js.map +1 -0
  166. package/dist/tui-v2/bootstrap/lifecycle.d.ts +62 -0
  167. package/dist/tui-v2/bootstrap/lifecycle.js +123 -0
  168. package/dist/tui-v2/bootstrap/lifecycle.js.map +1 -0
  169. package/dist/tui-v2/bootstrap/osc52-clipboard.d.ts +28 -0
  170. package/dist/tui-v2/bootstrap/osc52-clipboard.js +44 -0
  171. package/dist/tui-v2/bootstrap/osc52-clipboard.js.map +1 -0
  172. package/dist/tui-v2/bootstrap/overlay-ports.d.ts +12 -0
  173. package/dist/{tui/confirm.js → tui-v2/bootstrap/overlay-ports.js} +17 -25
  174. package/dist/tui-v2/bootstrap/overlay-ports.js.map +1 -0
  175. package/dist/tui-v2/bootstrap/pager-export.d.ts +24 -0
  176. package/dist/tui-v2/bootstrap/pager-export.js +87 -0
  177. package/dist/tui-v2/bootstrap/pager-export.js.map +1 -0
  178. package/dist/tui-v2/bootstrap/start-tui-v2.d.ts +15 -0
  179. package/dist/tui-v2/bootstrap/start-tui-v2.js +95 -0
  180. package/dist/tui-v2/bootstrap/start-tui-v2.js.map +1 -0
  181. package/dist/tui-v2/bootstrap/ui-selection.d.ts +30 -0
  182. package/dist/tui-v2/bootstrap/ui-selection.js +59 -0
  183. package/dist/tui-v2/bootstrap/ui-selection.js.map +1 -0
  184. package/dist/tui-v2/components/completion/completion-menu.d.ts +23 -0
  185. package/dist/tui-v2/components/completion/completion-menu.js +84 -0
  186. package/dist/tui-v2/components/completion/completion-menu.js.map +1 -0
  187. package/dist/tui-v2/components/jobs/jobs-panel.d.ts +16 -0
  188. package/dist/tui-v2/components/jobs/jobs-panel.js +92 -0
  189. package/dist/tui-v2/components/jobs/jobs-panel.js.map +1 -0
  190. package/dist/tui-v2/components/modal/confirm-modal.d.ts +21 -0
  191. package/dist/tui-v2/components/modal/confirm-modal.js +71 -0
  192. package/dist/tui-v2/components/modal/confirm-modal.js.map +1 -0
  193. package/dist/tui-v2/components/modal/prompt-actions-modal.d.ts +15 -0
  194. package/dist/tui-v2/components/modal/prompt-actions-modal.js +80 -0
  195. package/dist/tui-v2/components/modal/prompt-actions-modal.js.map +1 -0
  196. package/dist/tui-v2/components/modal/secret-modal.d.ts +24 -0
  197. package/dist/tui-v2/components/modal/secret-modal.js +50 -0
  198. package/dist/tui-v2/components/modal/secret-modal.js.map +1 -0
  199. package/dist/tui-v2/components/overlay/overlay-host.d.ts +17 -0
  200. package/dist/tui-v2/components/overlay/overlay-host.js +28 -0
  201. package/dist/tui-v2/components/overlay/overlay-host.js.map +1 -0
  202. package/dist/tui-v2/components/pager/pager.d.ts +20 -0
  203. package/dist/tui-v2/components/pager/pager.js +396 -0
  204. package/dist/tui-v2/components/pager/pager.js.map +1 -0
  205. package/dist/tui-v2/components/picker/picker.d.ts +17 -0
  206. package/dist/tui-v2/components/picker/picker.js +222 -0
  207. package/dist/tui-v2/components/picker/picker.js.map +1 -0
  208. package/dist/tui-v2/components/plan/plan-view.d.ts +20 -0
  209. package/dist/tui-v2/components/plan/plan-view.js +116 -0
  210. package/dist/tui-v2/components/plan/plan-view.js.map +1 -0
  211. package/dist/tui-v2/components/queue/queue-panel.d.ts +23 -0
  212. package/dist/tui-v2/components/queue/queue-panel.js +58 -0
  213. package/dist/tui-v2/components/queue/queue-panel.js.map +1 -0
  214. package/dist/tui-v2/components/status/status-line.d.ts +27 -0
  215. package/dist/tui-v2/components/status/status-line.js +158 -0
  216. package/dist/tui-v2/components/status/status-line.js.map +1 -0
  217. package/dist/tui-v2/components/toast/toast-host.d.ts +15 -0
  218. package/dist/tui-v2/components/toast/toast-host.js +48 -0
  219. package/dist/tui-v2/components/toast/toast-host.js.map +1 -0
  220. package/dist/tui-v2/components/transcript/assistant-message.d.ts +20 -0
  221. package/dist/tui-v2/components/transcript/assistant-message.js +35 -0
  222. package/dist/tui-v2/components/transcript/assistant-message.js.map +1 -0
  223. package/dist/tui-v2/components/transcript/compacted-row.d.ts +19 -0
  224. package/dist/tui-v2/components/transcript/compacted-row.js +94 -0
  225. package/dist/tui-v2/components/transcript/compacted-row.js.map +1 -0
  226. package/dist/tui-v2/components/transcript/intro-card.d.ts +19 -0
  227. package/dist/tui-v2/components/transcript/intro-card.js +50 -0
  228. package/dist/tui-v2/components/transcript/intro-card.js.map +1 -0
  229. package/dist/tui-v2/components/transcript/linkable-text.d.ts +21 -0
  230. package/dist/tui-v2/components/transcript/linkable-text.js +46 -0
  231. package/dist/tui-v2/components/transcript/linkable-text.js.map +1 -0
  232. package/dist/tui-v2/components/transcript/notice-row.d.ts +14 -0
  233. package/dist/tui-v2/components/transcript/notice-row.js +40 -0
  234. package/dist/tui-v2/components/transcript/notice-row.js.map +1 -0
  235. package/dist/tui-v2/components/transcript/search-bar.d.ts +19 -0
  236. package/dist/tui-v2/components/transcript/search-bar.js +7 -0
  237. package/dist/tui-v2/components/transcript/search-bar.js.map +1 -0
  238. package/dist/tui-v2/components/transcript/thinking-block.d.ts +22 -0
  239. package/dist/tui-v2/components/transcript/thinking-block.js +27 -0
  240. package/dist/tui-v2/components/transcript/thinking-block.js.map +1 -0
  241. package/dist/tui-v2/components/transcript/tool-card.d.ts +26 -0
  242. package/dist/tui-v2/components/transcript/tool-card.js +175 -0
  243. package/dist/tui-v2/components/transcript/tool-card.js.map +1 -0
  244. package/dist/tui-v2/components/transcript/transcript-row.d.ts +25 -0
  245. package/dist/tui-v2/components/transcript/transcript-row.js +30 -0
  246. package/dist/tui-v2/components/transcript/transcript-row.js.map +1 -0
  247. package/dist/tui-v2/components/transcript/transcript-scroll-port.d.ts +52 -0
  248. package/dist/tui-v2/components/transcript/transcript-scroll-port.js +86 -0
  249. package/dist/tui-v2/components/transcript/transcript-scroll-port.js.map +1 -0
  250. package/dist/tui-v2/components/transcript/transcript-view.d.ts +24 -0
  251. package/dist/tui-v2/components/transcript/transcript-view.js +403 -0
  252. package/dist/tui-v2/components/transcript/transcript-view.js.map +1 -0
  253. package/dist/tui-v2/components/transcript/use-click-without-drag.d.ts +13 -0
  254. package/dist/tui-v2/components/transcript/use-click-without-drag.js +35 -0
  255. package/dist/tui-v2/components/transcript/use-click-without-drag.js.map +1 -0
  256. package/dist/tui-v2/components/transcript/use-native-selection-copy.d.ts +10 -0
  257. package/dist/tui-v2/components/transcript/use-native-selection-copy.js +37 -0
  258. package/dist/tui-v2/components/transcript/use-native-selection-copy.js.map +1 -0
  259. package/dist/tui-v2/components/transcript/use-transcript-selection.d.ts +23 -0
  260. package/dist/tui-v2/components/transcript/use-transcript-selection.js +136 -0
  261. package/dist/tui-v2/components/transcript/use-transcript-selection.js.map +1 -0
  262. package/dist/tui-v2/components/transcript/user-message.d.ts +10 -0
  263. package/dist/tui-v2/components/transcript/user-message.js +23 -0
  264. package/dist/tui-v2/components/transcript/user-message.js.map +1 -0
  265. package/dist/tui-v2/composer/arrow-intent.d.ts +23 -0
  266. package/dist/tui-v2/composer/arrow-intent.js +35 -0
  267. package/dist/tui-v2/composer/arrow-intent.js.map +1 -0
  268. package/dist/tui-v2/composer/completion.d.ts +37 -0
  269. package/dist/tui-v2/composer/completion.js +67 -0
  270. package/dist/tui-v2/composer/completion.js.map +1 -0
  271. package/dist/tui-v2/composer/composer-editor.d.ts +33 -0
  272. package/dist/tui-v2/composer/composer-editor.js +620 -0
  273. package/dist/tui-v2/composer/composer-editor.js.map +1 -0
  274. package/dist/tui-v2/composer/composer-height.d.ts +21 -0
  275. package/dist/tui-v2/composer/composer-height.js +29 -0
  276. package/dist/tui-v2/composer/composer-height.js.map +1 -0
  277. package/dist/tui-v2/composer/composer-meta.d.ts +9 -0
  278. package/dist/tui-v2/composer/composer-meta.js +38 -0
  279. package/dist/tui-v2/composer/composer-meta.js.map +1 -0
  280. package/dist/tui-v2/composer/history-nav.d.ts +15 -0
  281. package/dist/tui-v2/composer/history-nav.js +16 -0
  282. package/dist/tui-v2/composer/history-nav.js.map +1 -0
  283. package/dist/tui-v2/composer/newline-hint.d.ts +13 -0
  284. package/dist/tui-v2/composer/newline-hint.js +13 -0
  285. package/dist/tui-v2/composer/newline-hint.js.map +1 -0
  286. package/dist/tui-v2/composer/paste-placeholder.d.ts +35 -0
  287. package/dist/tui-v2/composer/paste-placeholder.js +55 -0
  288. package/dist/tui-v2/composer/paste-placeholder.js.map +1 -0
  289. package/dist/tui-v2/composer/prompt-history.d.ts +22 -0
  290. package/dist/tui-v2/composer/prompt-history.js +51 -0
  291. package/dist/tui-v2/composer/prompt-history.js.map +1 -0
  292. package/dist/tui-v2/composer/secret-buffer.d.ts +20 -0
  293. package/dist/tui-v2/composer/secret-buffer.js +42 -0
  294. package/dist/tui-v2/composer/secret-buffer.js.map +1 -0
  295. package/dist/tui-v2/composer/textarea-keybindings.d.ts +22 -0
  296. package/dist/tui-v2/composer/textarea-keybindings.js +27 -0
  297. package/dist/tui-v2/composer/textarea-keybindings.js.map +1 -0
  298. package/dist/tui-v2/controllers/focus-controller.d.ts +30 -0
  299. package/dist/tui-v2/controllers/focus-controller.js +80 -0
  300. package/dist/tui-v2/controllers/focus-controller.js.map +1 -0
  301. package/dist/tui-v2/controllers/overlay-controller.d.ts +99 -0
  302. package/dist/tui-v2/controllers/overlay-controller.js +195 -0
  303. package/dist/tui-v2/controllers/overlay-controller.js.map +1 -0
  304. package/dist/tui-v2/controllers/selection-controller.d.ts +76 -0
  305. package/dist/tui-v2/controllers/selection-controller.js +238 -0
  306. package/dist/tui-v2/controllers/selection-controller.js.map +1 -0
  307. package/dist/tui-v2/controllers/toast-controller.d.ts +35 -0
  308. package/dist/tui-v2/controllers/toast-controller.js +88 -0
  309. package/dist/tui-v2/controllers/toast-controller.js.map +1 -0
  310. package/dist/tui-v2/layout/compute-layout.d.ts +59 -0
  311. package/dist/tui-v2/layout/compute-layout.js +170 -0
  312. package/dist/tui-v2/layout/compute-layout.js.map +1 -0
  313. package/dist/tui-v2/rendering/ansi-to-styled.d.ts +17 -0
  314. package/dist/tui-v2/rendering/ansi-to-styled.js +217 -0
  315. package/dist/tui-v2/rendering/ansi-to-styled.js.map +1 -0
  316. package/dist/tui-v2/rendering/batch-sections.d.ts +45 -0
  317. package/dist/tui-v2/rendering/batch-sections.js +109 -0
  318. package/dist/tui-v2/rendering/batch-sections.js.map +1 -0
  319. package/dist/tui-v2/rendering/link-detector.d.ts +16 -0
  320. package/dist/tui-v2/rendering/link-detector.js +43 -0
  321. package/dist/tui-v2/rendering/link-detector.js.map +1 -0
  322. package/dist/tui-v2/rendering/open-tool-output.d.ts +28 -0
  323. package/dist/tui-v2/rendering/open-tool-output.js +138 -0
  324. package/dist/tui-v2/rendering/open-tool-output.js.map +1 -0
  325. package/dist/tui-v2/rendering/picker-filter.d.ts +22 -0
  326. package/dist/tui-v2/rendering/picker-filter.js +68 -0
  327. package/dist/tui-v2/rendering/picker-filter.js.map +1 -0
  328. package/dist/tui-v2/rendering/plan-view.d.ts +32 -0
  329. package/dist/tui-v2/rendering/plan-view.js +196 -0
  330. package/dist/tui-v2/rendering/plan-view.js.map +1 -0
  331. package/dist/tui-v2/rendering/render-markdown-lines.d.ts +29 -0
  332. package/dist/tui-v2/rendering/render-markdown-lines.js +46 -0
  333. package/dist/tui-v2/rendering/render-markdown-lines.js.map +1 -0
  334. package/dist/tui-v2/rendering/sanitize-display.d.ts +13 -0
  335. package/dist/tui-v2/rendering/sanitize-display.js +24 -0
  336. package/dist/tui-v2/rendering/sanitize-display.js.map +1 -0
  337. package/dist/tui-v2/rendering/theme.d.ts +67 -0
  338. package/dist/tui-v2/rendering/theme.js +74 -0
  339. package/dist/tui-v2/rendering/theme.js.map +1 -0
  340. package/dist/tui-v2/rendering/tool-presenter.d.ts +39 -0
  341. package/dist/tui-v2/rendering/tool-presenter.js +207 -0
  342. package/dist/tui-v2/rendering/tool-presenter.js.map +1 -0
  343. package/dist/tui-v2/rendering/transcript-export.d.ts +11 -0
  344. package/dist/tui-v2/rendering/transcript-export.js +18 -0
  345. package/dist/tui-v2/rendering/transcript-export.js.map +1 -0
  346. package/dist/tui-v2/rendering/transcript-semantic.d.ts +17 -0
  347. package/dist/tui-v2/rendering/transcript-semantic.js +67 -0
  348. package/dist/tui-v2/rendering/transcript-semantic.js.map +1 -0
  349. package/dist/tui-v2/state/pager-search.d.ts +22 -0
  350. package/dist/tui-v2/state/pager-search.js +78 -0
  351. package/dist/tui-v2/state/pager-search.js.map +1 -0
  352. package/dist/tui-v2/state/semantic-document.d.ts +34 -0
  353. package/dist/tui-v2/state/semantic-document.js +201 -0
  354. package/dist/tui-v2/state/semantic-document.js.map +1 -0
  355. package/dist/tui-v2/state/transcript-compaction.d.ts +24 -0
  356. package/dist/tui-v2/state/transcript-compaction.js +79 -0
  357. package/dist/tui-v2/state/transcript-compaction.js.map +1 -0
  358. package/dist/tui-v2/state/transcript-hydrate.d.ts +27 -0
  359. package/dist/tui-v2/state/transcript-hydrate.js +272 -0
  360. package/dist/tui-v2/state/transcript-hydrate.js.map +1 -0
  361. package/dist/tui-v2/state/transcript-reducer.d.ts +10 -0
  362. package/dist/tui-v2/state/transcript-reducer.js +281 -0
  363. package/dist/tui-v2/state/transcript-reducer.js.map +1 -0
  364. package/dist/tui-v2/state/transcript-search.d.ts +17 -0
  365. package/dist/tui-v2/state/transcript-search.js +38 -0
  366. package/dist/tui-v2/state/transcript-search.js.map +1 -0
  367. package/dist/tui-v2/state/transcript-store.d.ts +32 -0
  368. package/dist/tui-v2/state/transcript-store.js +66 -0
  369. package/dist/tui-v2/state/transcript-store.js.map +1 -0
  370. package/dist/tui-v2/state/transcript-struct.d.ts +15 -0
  371. package/dist/tui-v2/state/transcript-struct.js +133 -0
  372. package/dist/tui-v2/state/transcript-struct.js.map +1 -0
  373. package/dist/tui-v2/state/transcript-types.d.ts +76 -0
  374. package/dist/tui-v2/state/transcript-types.js +65 -0
  375. package/dist/tui-v2/state/transcript-types.js.map +1 -0
  376. package/dist/tui-v2/state/use-overlay.d.ts +3 -0
  377. package/dist/tui-v2/state/use-overlay.js +6 -0
  378. package/dist/tui-v2/state/use-overlay.js.map +1 -0
  379. package/dist/tui-v2/state/use-plan.d.ts +4 -0
  380. package/dist/tui-v2/state/use-plan.js +6 -0
  381. package/dist/tui-v2/state/use-plan.js.map +1 -0
  382. package/dist/tui-v2/state/use-session-state.d.ts +2 -0
  383. package/dist/tui-v2/state/use-session-state.js +7 -0
  384. package/dist/tui-v2/state/use-session-state.js.map +1 -0
  385. package/dist/tui-v2/state/use-toast.d.ts +3 -0
  386. package/dist/tui-v2/state/use-toast.js +15 -0
  387. package/dist/tui-v2/state/use-toast.js.map +1 -0
  388. package/dist/tui-v2/state/use-transcript-store.d.ts +10 -0
  389. package/dist/tui-v2/state/use-transcript-store.js +12 -0
  390. package/dist/tui-v2/state/use-transcript-store.js.map +1 -0
  391. package/dist/ui/intro-card.js +3 -3
  392. package/dist/ui/intro-card.js.map +1 -1
  393. package/dist/ui/intro-header.d.ts +23 -0
  394. package/dist/ui/intro-header.js +232 -0
  395. package/dist/ui/intro-header.js.map +1 -0
  396. package/dist/ui/markdown.js +0 -1
  397. package/dist/ui/markdown.js.map +1 -1
  398. package/dist/ui/mentions.d.ts +9 -2
  399. package/dist/ui/mentions.js +102 -4
  400. package/dist/ui/mentions.js.map +1 -1
  401. package/dist/ui/output-pane.js +1 -1
  402. package/dist/ui/output-pane.js.map +1 -1
  403. package/dist/ui/plan-pane.d.ts +8 -0
  404. package/dist/ui/plan-pane.js +38 -0
  405. package/dist/ui/plan-pane.js.map +1 -1
  406. package/dist/ui/wordmark.d.ts +5 -0
  407. package/dist/ui/wordmark.js +6 -1
  408. package/dist/ui/wordmark.js.map +1 -1
  409. package/package.json +14 -10
  410. package/dist/tui/App.d.ts +0 -12
  411. package/dist/tui/App.js +0 -2174
  412. package/dist/tui/App.js.map +0 -1
  413. package/dist/tui/components/ConfirmModal.d.ts +0 -9
  414. package/dist/tui/components/ConfirmModal.js +0 -55
  415. package/dist/tui/components/ConfirmModal.js.map +0 -1
  416. package/dist/tui/components/JobsPanel.d.ts +0 -11
  417. package/dist/tui/components/JobsPanel.js +0 -55
  418. package/dist/tui/components/JobsPanel.js.map +0 -1
  419. package/dist/tui/components/Pager.d.ts +0 -14
  420. package/dist/tui/components/Pager.js +0 -56
  421. package/dist/tui/components/Pager.js.map +0 -1
  422. package/dist/tui/components/PickerPanel.d.ts +0 -15
  423. package/dist/tui/components/PickerPanel.js +0 -126
  424. package/dist/tui/components/PickerPanel.js.map +0 -1
  425. package/dist/tui/components/PlanSidebar.d.ts +0 -6
  426. package/dist/tui/components/PlanSidebar.js +0 -99
  427. package/dist/tui/components/PlanSidebar.js.map +0 -1
  428. package/dist/tui/components/SecretInputPanel.d.ts +0 -7
  429. package/dist/tui/components/SecretInputPanel.js +0 -38
  430. package/dist/tui/components/SecretInputPanel.js.map +0 -1
  431. package/dist/tui/confirm.d.ts +0 -16
  432. package/dist/tui/confirm.js.map +0 -1
  433. package/dist/tui/default.d.ts +0 -6
  434. package/dist/tui/default.js +0 -11
  435. package/dist/tui/default.js.map +0 -1
  436. package/dist/tui/hooks/useAgentRunner.d.ts +0 -73
  437. package/dist/tui/hooks/useAgentRunner.js +0 -277
  438. package/dist/tui/hooks/useAgentRunner.js.map +0 -1
  439. package/dist/tui/hooks/useJobs.d.ts +0 -7
  440. package/dist/tui/hooks/useJobs.js +0 -39
  441. package/dist/tui/hooks/useJobs.js.map +0 -1
  442. package/dist/tui/hooks/useSpinner.d.ts +0 -5
  443. package/dist/tui/hooks/useSpinner.js +0 -21
  444. package/dist/tui/hooks/useSpinner.js.map +0 -1
  445. package/dist/tui/hooks/useTerminalSize.d.ts +0 -9
  446. package/dist/tui/hooks/useTerminalSize.js +0 -26
  447. package/dist/tui/hooks/useTerminalSize.js.map +0 -1
  448. package/dist/tui/index.d.ts +0 -10
  449. package/dist/tui/index.js +0 -37
  450. package/dist/tui/index.js.map +0 -1
  451. package/dist/tui/key-intent.d.ts +0 -36
  452. package/dist/tui/key-intent.js +0 -54
  453. package/dist/tui/key-intent.js.map +0 -1
  454. package/dist/tui/mouse.d.ts +0 -8
  455. package/dist/tui/mouse.js +0 -34
  456. package/dist/tui/mouse.js.map +0 -1
  457. package/dist/tui/plan-sidebar-lines.d.ts +0 -2
  458. package/dist/tui/plan-sidebar-lines.js +0 -140
  459. package/dist/tui/plan-sidebar-lines.js.map +0 -1
  460. package/dist/tui/render-lines.d.ts +0 -22
  461. package/dist/tui/render-lines.js +0 -611
  462. package/dist/tui/render-lines.js.map +0 -1
@@ -8,6 +8,11 @@ import type { ChatMessage } from "../types.js";
8
8
  */
9
9
  export declare function estimateTokens(text: string): number;
10
10
  export declare function estimateMessagesTokens(messages: ChatMessage[]): number;
11
+ /**
12
+ * Agent-loop auto-compact threshold (estimated tokens). Shared with `/context`
13
+ * so the reported % of budget matches when auto-compaction fires.
14
+ */
15
+ export declare const AUTO_COMPACT_TOKEN_BUDGET = 150000;
11
16
  export interface CompactOptions {
12
17
  /** Soft budget (tokens). When estimated tokens exceed this, compact. */
13
18
  budgetTokens?: number | undefined;
@@ -21,6 +21,11 @@ export function estimateMessagesTokens(messages) {
21
21
  }
22
22
  return sum;
23
23
  }
24
+ /**
25
+ * Agent-loop auto-compact threshold (estimated tokens). Shared with `/context`
26
+ * so the reported % of budget matches when auto-compaction fires.
27
+ */
28
+ export const AUTO_COMPACT_TOKEN_BUDGET = 150_000;
24
29
  const DEFAULT_BUDGET_TOKENS = 32_000;
25
30
  const DEFAULT_KEEP_RECENT = 6;
26
31
  /**
@@ -131,11 +136,18 @@ export async function compactMessagesWithSummary(messages, summarize, options =
131
136
  return `${message.role.toUpperCase()}: ${content}`;
132
137
  })
133
138
  .join("\n\n");
134
- const transcript = sessionTranscript?.trim()
139
+ // Prefer combining visual session material (tools/prompts) with older model
140
+ // turns so /compact after /history + new messages never loses either side.
141
+ const visual = sessionTranscript?.trim()
135
142
  ? redactSecrets(sessionTranscript.trim())
136
- : messageTranscript;
143
+ : "";
144
+ const fromMessages = messageTranscript.trim();
145
+ const transcript = visual && fromMessages
146
+ ? `${visual}\n\n---\n\nOLDER MODEL TURNS:\n\n${fromMessages}`
147
+ : visual || fromMessages;
137
148
  const prompt = [
138
149
  "Create a complete but compact continuation memory of the entire session below for another assistant that will continue it.",
150
+ "The material may include a resumed history session plus newer turns — treat it as one continuous conversation.",
139
151
  "Preserve user intentions and prompts, decisions, constraints, file paths, commands/tools run, steps taken, task states, outputs and results, errors and failed approaches, completed work, and exactly what remains.",
140
152
  "Organize the memory under concise sections: User goals, Decisions and constraints, Work completed, Commands/tools and results, Current state, Remaining work.",
141
153
  "Do not add facts, commentary, or markdown framing. Be concise but specific. Never include secrets or credentials.",
@@ -1 +1 @@
1
- {"version":3,"file":"context-manager.js","sourceRoot":"","sources":["../../src/agent/context-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"context-manager.js","sourceRoot":"","sources":["../../src/agent/context-manager.ts"],"names":[],"mappings":"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"}
@@ -26,10 +26,13 @@ export type AgentEvent = {
26
26
  id: string;
27
27
  name: string;
28
28
  argsDisplay: string;
29
- } | {
29
+ }
30
+ /** `replace: true` sets the full body (never append) so the UI never keeps a truncated live preview. */
31
+ | {
30
32
  type: "tool-output";
31
33
  id: string;
32
34
  chunk: string;
35
+ replace?: boolean;
33
36
  } | {
34
37
  type: "tool-result";
35
38
  id: string;
@@ -11,7 +11,7 @@ import { classifyToolCall, isPentestToolCall, scopeHint, scopeTargetForToolCall,
11
11
  import { availableToolNames, normalizeToolCall, runToolCall, BATCH_SAFE_TOOLS, } from "../tools/registry.js";
12
12
  import { looksInteractiveStdin } from "../tools/shell.js";
13
13
  import { formatViewportHint, registerViewport } from "../ui/output-pane.js";
14
- import { compactMessagesWithSummary, estimateTokens, estimateMessagesTokens, COMPACTION_MEMORY_PREFIX, } from "./context-manager.js";
14
+ import { compactMessagesWithSummary, estimateTokens, estimateMessagesTokens, AUTO_COMPACT_TOKEN_BUDGET, COMPACTION_MEMORY_PREFIX, } from "./context-manager.js";
15
15
  import { auditLog } from "../store/logs.js";
16
16
  import { loadProjectContext } from "../store/project.js";
17
17
  import { loadScope, isScopeActive, targetInScope } from "../store/scope.js";
@@ -24,7 +24,7 @@ import { analyzeTask } from "./task-analyzer.js";
24
24
  import { LoopGuard } from "./loop-guard.js";
25
25
  import { loadPlan } from "../store/plan.js";
26
26
  import { pathInsideSandbox, fsWrite } from "../tools/fs.js";
27
- import { stripSentinelTokens, parseToolCall, recognizeBareToolJson, looksLikeTruncatedToolCall, salvageTruncatedWrite, countToolFences, parseAllToolCalls, groupToolCallsForExecution, buildTurnHistory, collapseRepeatedText, textBeforeToolCall, formatToolArgs, looksLikePentestTask, looksLikeBuildTask, looksLikeInformationalQuery, looksLikeActionNarration, looksLikePlanNarration, requiresFreshWebSearch, freshnessGuardMessage, buildWorkflowDirective, pentestWorkflowDirective, shouldDimToolChatter, looksLikePromptLeak, } from "./tool-call-parser.js";
27
+ import { stripSentinelTokens, parseToolCall, recognizeBareToolJson, looksLikeTruncatedToolCall, salvageTruncatedWrite, countToolFences, parseAllToolCalls, groupToolCallsForExecution, buildTurnHistory, collapseRepeatedText, textBeforeToolCall, formatToolArgs, looksLikePentestTask, looksLikeBuildTask, looksLikeInformationalQuery, looksLikeIdleOrSocialPrompt, looksLikeActionNarration, looksLikeWebActionNarration, looksLikePlanNarration, requiresFreshWebSearch, freshnessGuardMessage, buildWorkflowDirective, pentestWorkflowDirective, shouldDimToolChatter, looksLikePromptLeak, } from "./tool-call-parser.js";
28
28
  import { createSessionPolicy, isPreApprovalAllowedTool, isPlanApprovedByStatus, planHasOpenWork, isAbortError, shouldEnableImageOcr, } from "./session-policy.js";
29
29
  import { saveToolOutput, summarizeOutput, formatToolContext, } from "./tool-output-formatting.js";
30
30
  import { planContextMessage, handlePlanTool, } from "./plan-tool.js";
@@ -114,6 +114,13 @@ function isScratchOnlyWrite(call, scratchDir) {
114
114
  export async function runAgentLoop(prompt, options = {}) {
115
115
  const writesDirectly = !options.onEvent;
116
116
  const emit = (event) => options.onEvent?.(event);
117
+ // Whether the CURRENT model iteration has already committed its visible
118
+ // prose to the transcript with an `assistant-message` event. The recovery
119
+ // paths preserve streamed prose before retrying (so it isn't wiped by the
120
+ // next tool-call/turn event); this flag stops them from re-committing prose
121
+ // the normal tool path already surfaced, which would render it twice. Reset
122
+ // at the top of every loop iteration.
123
+ let visibleCommitted = false;
117
124
  const noopSpinner = {
118
125
  setLabel: () => { },
119
126
  bumpReasoning: () => { },
@@ -121,7 +128,9 @@ export async function runAgentLoop(prompt, options = {}) {
121
128
  stop: () => { },
122
129
  };
123
130
  const writeStatus = (text, rendered = chalk.dim(text)) => {
124
- emit({ type: "status", text });
131
+ // Footer activity is single-line; strip classic stdout newlines/indents.
132
+ const cleaned = text.replace(/\s+/g, " ").trim();
133
+ emit({ type: "status", text: cleaned || text });
125
134
  if (writesDirectly)
126
135
  process.stdout.write(rendered);
127
136
  };
@@ -131,6 +140,11 @@ export async function runAgentLoop(prompt, options = {}) {
131
140
  process.stdout.write(rendered);
132
141
  };
133
142
  const writeAssistantMessage = (text) => {
143
+ // Never surface an empty message: the reducer drops it and a direct
144
+ // stdout writer would print a stray blank line.
145
+ if (!text.trim())
146
+ return;
147
+ visibleCommitted = true;
134
148
  emit({ type: "assistant-message", text });
135
149
  const rendered = renderMarkdown(text);
136
150
  if (writesDirectly) {
@@ -142,9 +156,14 @@ export async function runAgentLoop(prompt, options = {}) {
142
156
  if (writesDirectly)
143
157
  process.stdout.write(`${renderThinkingSummary(content)}\n`);
144
158
  };
145
- const writeToolOutput = (id, chunk, rendered) => {
146
- emit({ type: "tool-output", id, chunk });
147
- if (writesDirectly)
159
+ const writeToolOutput = (id, chunk, rendered, options) => {
160
+ emit({
161
+ type: "tool-output",
162
+ id,
163
+ chunk,
164
+ ...(options?.replace ? { replace: true } : {}),
165
+ });
166
+ if (writesDirectly && rendered)
148
167
  process.stdout.write(rendered);
149
168
  };
150
169
  const writeToolCall = (id, call, rendered) => {
@@ -245,8 +264,13 @@ export async function runAgentLoop(prompt, options = {}) {
245
264
  // brand-new plan (the exact failure where "what do u know till now"
246
265
  // triggered explore→plan and created an unrelated "Enhance clai" plan).
247
266
  const informationalQuery = looksLikeInformationalQuery(prompt);
267
+ // Greetings / thanks / short acks must never force tools, plans, or
268
+ // freshness retries — a false "act don't narrate" path burned tokens on
269
+ // web.search recovery loops after a simple "hi".
270
+ const idleOrSocialPrompt = looksLikeIdleOrSocialPrompt(prompt);
248
271
  const freshWebSearchRequired = !buildLikeTurn &&
249
272
  !pentestLikeTurn &&
273
+ !idleOrSocialPrompt &&
250
274
  toolNames.includes("web.search") &&
251
275
  requiresFreshWebSearch(prompt);
252
276
  let provider = options.provider ?? config.defaultProvider;
@@ -295,7 +319,10 @@ export async function runAgentLoop(prompt, options = {}) {
295
319
  // what's already there, create a comprehensive multi-task plan, then
296
320
  // implement task by task until the goal is met. This mirrors how a careful
297
321
  // coding agent (Claude Code) operates.
298
- if (buildLikeTurn && !activePlan && !informationalQuery) {
322
+ if (buildLikeTurn &&
323
+ !activePlan &&
324
+ !informationalQuery &&
325
+ !idleOrSocialPrompt) {
299
326
  systemSections.push(buildWorkflowDirective());
300
327
  }
301
328
  // Pentest / security engagements need a different shape than a coding
@@ -304,7 +331,10 @@ export async function runAgentLoop(prompt, options = {}) {
304
331
  // directive is only injected before a plan exists; once a plan is in
305
332
  // place (or being refined), the ACTIVE PLAN block already carries the
306
333
  // current task state and recon-vs-active-tool guidance.
307
- if (pentestLikeTurn && !activePlan && !informationalQuery) {
334
+ if (pentestLikeTurn &&
335
+ !activePlan &&
336
+ !informationalQuery &&
337
+ !idleOrSocialPrompt) {
308
338
  systemSections.push(pentestWorkflowDirective());
309
339
  }
310
340
  const renderedSystemPrompt = systemSections.join("\n\n");
@@ -346,7 +376,32 @@ export async function runAgentLoop(prompt, options = {}) {
346
376
  // which can cause every retry to return empty as well. Keep hidden thinking
347
377
  // out of history, but record a compact non-empty sentinel when there was no
348
378
  // visible output.
379
+ //
380
+ // The Ink reducer intentionally keeps streamed text transient until it
381
+ // receives `assistant-message`, because a stream may turn out to be raw
382
+ // tool JSON. Recovery paths used to add prose to model history and retry
383
+ // without that event, so the user could watch a valid-looking response
384
+ // vanish when the retry emitted its first tool call. Surface only prose
385
+ // that is safe to render; malformed/bare tool payloads remain hidden.
386
+ const recoveryProse = (content) => {
387
+ const text = textBeforeToolCall(stripSentinelTokens(content)).trim();
388
+ if (!text ||
389
+ /^```|^\{|<tool_call>|<\|tool_call(?:s_section)?_begin\|>/i.test(text) ||
390
+ /\n\s*\{[\s\S]*\}\s*$/.test(text)) {
391
+ return undefined;
392
+ }
393
+ return text;
394
+ };
349
395
  const pushAssistantHistory = (content) => {
396
+ // Preserve genuine streamed prose before a recovery retry so the visible
397
+ // text isn't wiped by the next tool-call/turn event. Skip when this
398
+ // iteration already surfaced its prose (the normal tool path commits
399
+ // `beforeTool` itself) so the same text is never rendered twice.
400
+ if (!visibleCommitted) {
401
+ const prose = recoveryProse(content);
402
+ if (prose)
403
+ writeAssistantMessage(prose);
404
+ }
350
405
  messages.push({
351
406
  role: "assistant",
352
407
  content: content.trim()
@@ -687,38 +742,20 @@ export async function runAgentLoop(prompt, options = {}) {
687
742
  parentSignal.addEventListener("abort", onParentAbort);
688
743
  let result;
689
744
  let liveBytes = 0;
690
- const liveCap = 16_000;
691
- let liveTruncatedNotified = false;
692
- let lastProgressAt = 0;
693
745
  const shouldDimLive = !interactiveCommand;
694
- const writeToolInfo = (text) => {
695
- writeToolOutput(toolEventId, `${text}\n`, chalk.dim(` ${text}\n`));
696
- };
746
+ // Stream every live byte — never drop mid-run. After the tool finishes we
747
+ // still replace the spool with the authoritative full `result.output`.
697
748
  const printLive = (chunk) => {
698
749
  if (call.name === "fs.read" ||
699
750
  call.name === "fs.list" ||
700
751
  call.name === "fs.search")
701
752
  return;
702
- if (liveBytes >= liveCap) {
703
- if (!liveTruncatedNotified) {
704
- liveTruncatedNotified = true;
705
- writeToolInfo("... live preview truncated, full output saved");
706
- writeToolInfo("(tool still running — ESC or Ctrl+C to abort)");
707
- lastProgressAt = Date.now();
708
- }
709
- const now = Date.now();
710
- if (now - lastProgressAt > 5_000) {
711
- lastProgressAt = now;
712
- writeToolOutput(toolEventId, ".", chalk.dim("."));
713
- }
753
+ if (!chunk)
714
754
  return;
715
- }
716
- const remaining = liveCap - liveBytes;
717
- const slice = chunk.length > remaining ? chunk.slice(0, remaining) : chunk;
718
- liveBytes += slice.length;
719
- const indented = slice.replace(/\r/g, "").replace(/\n(?!$)/g, "\n ");
755
+ liveBytes += chunk.length;
756
+ const indented = chunk.replace(/\r/g, "").replace(/\n(?!$)/g, "\n ");
720
757
  const body = indented.startsWith("\n") ? indented : ` ${indented}`;
721
- writeToolOutput(toolEventId, slice, shouldDimLive ? chalk.dim(body) : body);
758
+ writeToolOutput(toolEventId, chunk, shouldDimLive ? chalk.dim(body) : body);
722
759
  };
723
760
  const jobId = randomUUID().slice(0, 8);
724
761
  const backgroundJob = {
@@ -761,7 +798,7 @@ export async function runAgentLoop(prompt, options = {}) {
761
798
  confirmed: true,
762
799
  userPrompt: prompt,
763
800
  });
764
- if (liveBytes > 0 || liveTruncatedNotified) {
801
+ if (liveBytes > 0) {
765
802
  writeToolOutput(toolEventId, "\n", "\n");
766
803
  }
767
804
  jobManager.updateJobStatus(jobId, result.ok ? "exited" : "failed", result.exitCode);
@@ -802,11 +839,10 @@ export async function runAgentLoop(prompt, options = {}) {
802
839
  parentSignal.removeEventListener("abort", onParentAbort);
803
840
  }
804
841
  const output = result.output.trim();
805
- const displayMax = 6_000;
842
+ // Always keep a full on-disk copy of tool output (any size) so the
843
+ // pager never depends on a truncated in-memory preview.
806
844
  const savedOutputPath = result.outputPath ??
807
- (output.length > displayMax
808
- ? await saveToolOutput(call, output)
809
- : undefined);
845
+ (output ? await saveToolOutput(call, output) : undefined);
810
846
  const resultWithArtifact = {
811
847
  ...result,
812
848
  outputPath: savedOutputPath,
@@ -841,20 +877,30 @@ export async function runAgentLoop(prompt, options = {}) {
841
877
  }
842
878
  }
843
879
  const statusIcon = result.ok ? chalk.green(" ✓") : chalk.red(" ✗");
844
- writeToolOutput(toolEventId, result.ok ? "ok\n" : "failed\n", statusIcon + "\n");
880
+ // Classic stdout gets a short status glyph; the event stream / spool
881
+ // must NOT be polluted with "ok"/"failed" (the card already shows status).
882
+ if (writesDirectly) {
883
+ process.stdout.write(statusIcon + "\n");
884
+ }
845
885
  if (output) {
846
- const displaySummary = summarizeOutput(output, displayMax);
847
- const displayText = displaySummary.truncated
848
- ? `${displaySummary.text}${savedOutputPath ? chalk.dim(`\n ... full output saved to ${savedOutputPath}`) : chalk.dim("\n ... output truncated")}`
849
- : displaySummary.text;
850
- if (liveBytes > 0) {
851
- if (savedOutputPath) {
852
- writeToolInfo(`full output saved to ${savedOutputPath}`);
853
- }
886
+ // Authoritative FULL body — replace any live stream so the pager
887
+ // never shows a truncated mid-run preview. Never cap for the UI.
888
+ const fullChunk = output.endsWith("\n") ? output : `${output}\n`;
889
+ if (!writesDirectly) {
890
+ writeToolOutput(toolEventId, fullChunk, "", { replace: true });
854
891
  }
855
892
  else {
893
+ // Classic stdout: short preview only; full text is on disk.
894
+ const displayMax = 6_000;
895
+ const displaySummary = summarizeOutput(output, displayMax);
896
+ const displayText = displaySummary.truncated
897
+ ? `${displaySummary.text}${savedOutputPath ? chalk.dim(`\n ... full output saved to ${savedOutputPath}`) : ""}`
898
+ : displaySummary.text;
856
899
  const renderedOutput = indentAndWrapText(displayText);
857
- writeToolOutput(toolEventId, displayText, styleToolChatter(call, renderedOutput) + "\n");
900
+ process.stdout.write(styleToolChatter(call, renderedOutput) + "\n");
901
+ if (savedOutputPath && displaySummary.truncated) {
902
+ process.stdout.write(chalk.dim(` full output saved to ${savedOutputPath}\n`));
903
+ }
858
904
  }
859
905
  }
860
906
  if (output) {
@@ -880,7 +926,6 @@ export async function runAgentLoop(prompt, options = {}) {
880
926
  // what is done, and what remains. The estimate is chars/4; the budget is
881
927
  // deliberately conservative so we compact a little early rather than hit a
882
928
  // provider context-window error mid-task.
883
- const AUTO_COMPACT_TOKEN_BUDGET = 150_000;
884
929
  const AUTO_COMPACT_KEEP_RECENT = 6;
885
930
  let lastCompactionMsgCount = 0;
886
931
  const summarizeForCompaction = async (summaryPrompt) => {
@@ -916,6 +961,8 @@ export async function runAgentLoop(prompt, options = {}) {
916
961
  return;
917
962
  messages.splice(0, messages.length, ...result.messages);
918
963
  loopGuard.resetReadOnly();
964
+ // Token stats BEFORE plan re-injection so the reduction is accurate.
965
+ const compactedTokens = estimateMessagesTokens(messages);
919
966
  // Re-inject the live plan so the model keeps full plan awareness even
920
967
  // after older turns (which carried the plan context) were summarized.
921
968
  const livePlan = await loadPlan(session.sessionId).catch(() => undefined);
@@ -926,13 +973,11 @@ export async function runAgentLoop(prompt, options = {}) {
926
973
  });
927
974
  }
928
975
  lastCompactionMsgCount = messages.length;
929
- // Report the compacted token count BEFORE plan re-injection so the
930
- // compaction stats accurately show the reduction. Then report the
931
- // final count (which is what the model actually receives) separately.
932
- const compactedTokens = estimateMessagesTokens(messages);
976
+ // Final count the model actually receives (may include re-injected plan).
977
+ const afterTokens = estimateMessagesTokens(messages);
933
978
  await auditLog("agent.compact", {
934
979
  newLength: messages.length,
935
- estimatedTokens: compactedTokens,
980
+ estimatedTokens: afterTokens,
936
981
  reason,
937
982
  });
938
983
  // Extract the inserted compaction memory so we can surface the
@@ -944,12 +989,12 @@ export async function runAgentLoop(prompt, options = {}) {
944
989
  const summaryText = insertedSummary.startsWith(`${COMPACTION_MEMORY_PREFIX}\n\n`)
945
990
  ? insertedText(insertedSummary, `${COMPACTION_MEMORY_PREFIX}\n\n`)
946
991
  : insertedText(insertedSummary, COMPACTION_MEMORY_PREFIX);
947
- const afterTokens = estimateMessagesTokens(messages);
948
- writeCompacted(summaryText, beforeTokens, afterTokens);
992
+ // Card shows pre/post of the summarization; plan re-injection is noted.
993
+ writeCompacted(summaryText, beforeTokens, compactedTokens);
949
994
  const planNote = afterTokens > compactedTokens
950
995
  ? ` (compacted to ~${compactedTokens.toLocaleString()}, +plan → ~${afterTokens.toLocaleString()})`
951
996
  : "";
952
- writeNotice("info", `context auto-compacted to fit the window (~${beforeTokens.toLocaleString()} → ~${afterTokens.toLocaleString()} tokens${planNote})`, chalk.dim(` ℹ context auto-compacted (~${beforeTokens.toLocaleString()} → ~${afterTokens.toLocaleString()} tokens${planNote})\n`));
997
+ writeNotice("info", `context auto-compacted to fit the window (~${beforeTokens.toLocaleString()} → ~${compactedTokens.toLocaleString()} tokens${planNote})`, chalk.dim(` ℹ context auto-compacted (~${beforeTokens.toLocaleString()} → ~${compactedTokens.toLocaleString()} tokens${planNote})\n`));
953
998
  }
954
999
  catch (error) {
955
1000
  if (error instanceof Error &&
@@ -964,6 +1009,10 @@ export async function runAgentLoop(prompt, options = {}) {
964
1009
  }
965
1010
  }
966
1011
  for (let iteration = 0; iteration < maxIterations; iteration += 1) {
1012
+ // Each model round-trip re-decides whether its visible prose has been
1013
+ // committed, so recovery-prose preservation applies to THIS turn's
1014
+ // stream and not a prior one.
1015
+ visibleCommitted = false;
967
1016
  // `step` is the productive-step index (used for display + audit). It only
968
1017
  // advances when the previous iteration actually executed a tool.
969
1018
  step = productiveSteps;
@@ -1070,10 +1119,11 @@ export async function runAgentLoop(prompt, options = {}) {
1070
1119
  completion = await streamWithProvider({
1071
1120
  provider,
1072
1121
  model,
1073
- // The selected model is the first choice, but an agent must not
1074
- // end a turn with no answer if it only emits reasoning. Honor
1075
- // the user's providerFallback setting for that recovery path.
1076
- allowModelFallback: true,
1122
+ // Stay on the user's selected provider/model. Cross-provider
1123
+ // hops (e.g. bynara gemini on a 429) only happen when the
1124
+ // user has explicitly enabled `providerFallback` AND this is
1125
+ // the provider's default model. Never force fallback mid-turn.
1126
+ allowModelFallback: false,
1077
1127
  messages,
1078
1128
  // MiniMax M3 degenerates at the generic agent temperature. The
1079
1129
  // HTTP layer also applies its `top_p` override for both the
@@ -1440,28 +1490,49 @@ export async function runAgentLoop(prompt, options = {}) {
1440
1490
  // final answer ends the turn with nothing done and no real plan saved.
1441
1491
  // Nudge it to emit a real tool call, with a concrete example.
1442
1492
  const narratedAction = looksLikeActionNarration(cleaned);
1443
- // A plan whose OWN persisted status is "completed" has no more
1444
- // work to force treat this like "no active plan" for the
1445
- // act-don't-narrate nudge so a plain follow-up question (e.g. "what
1446
- // do you know so far") after the plan finished gets answered
1447
- // instead of being pushed to emit another tool call.
1448
- const planHasOpenWorkNow = planHasOpenWork(activePlan?.status);
1449
- // History-inherited build/pentest intent only forces action when
1450
- // THIS prompt is not itself a plain question. If the model does
1451
- // narrate a concrete next step ("let me read X"), narratedAction
1452
- // still forces it to actually run that step — even for a question —
1453
- // which is the desired "do what you said" behavior.
1454
- const wantsAction = narratedAction ||
1455
- freshWebSearchRequired ||
1493
+ const narratedWebAction = looksLikeWebActionNarration(cleaned);
1494
+ // `activePlan` is the snapshot loaded at the start of this turn.
1495
+ // A final task.update mutates and persists a separate plan instance,
1496
+ // so re-read it here before deciding whether a final response should
1497
+ // be forced back into execution. Without this, a completed plan
1498
+ // still appeared open and a short final summary such as "I'll
1499
+ // summarize the findings" could be discarded for an unnecessary
1500
+ // recovery turn.
1501
+ const livePlanAtCompletion = await loadPlan(session.sessionId).catch(() => undefined);
1502
+ const planStatusAtCompletion = livePlanAtCompletion?.status ?? activePlan?.status;
1503
+ const completedPlanDuringThisTurn = activePlan?.status !== "completed" &&
1504
+ planStatusAtCompletion === "completed";
1505
+ const planHasOpenWorkNow = planHasOpenWork(planStatusAtCompletion);
1506
+ // User-driven reasons to require tools this turn (build/pentest/
1507
+ // approved plan / freshness). Idle greetings never qualify.
1508
+ const userExpectsWork = freshWebSearchRequired ||
1456
1509
  (planHasOpenWorkNow && session.planApproved.value) ||
1457
- (!informationalQuery && (buildLikeTurn || pentestLikeTurn));
1510
+ (!informationalQuery &&
1511
+ !idleOrSocialPrompt &&
1512
+ (buildLikeTurn || pentestLikeTurn));
1513
+ // History-inherited build/pentest intent only forces action when
1514
+ // THIS prompt is not itself a plain question/idle turn. Narration
1515
+ // stalls ("I'll list the files") still force a tool when the user
1516
+ // is not asking an informational question — but capability menus
1517
+ // and greetings are filtered out by looksLikeActionNarration /
1518
+ // idleOrSocialPrompt so they cannot burn recovery turns.
1519
+ const wantsAction = !completedPlanDuringThisTurn &&
1520
+ !idleOrSocialPrompt &&
1521
+ (userExpectsWork ||
1522
+ (narratedAction && !informationalQuery) ||
1523
+ (narratedWebAction && !informationalQuery));
1458
1524
  const planNarrated = (buildLikeTurn || pentestLikeTurn) &&
1459
1525
  !activePlan &&
1460
1526
  looksLikePlanNarration(cleaned);
1527
+ // Once a real tool step has run, a no-plan task has no durable task
1528
+ // state to prove whether another action is needed. A tool-free reply
1529
+ // must therefore be allowed to finalize instead of turning a short
1530
+ // summary containing “I'll” into an implicit recovery request.
1531
+ const shouldRetryBeforeFinalizing = productiveSteps === 0 || planNarrated;
1461
1532
  if (wantsAction &&
1462
1533
  cleaned.trim().length > 0 &&
1463
1534
  actionIntentRetries < 3 &&
1464
- (productiveSteps === 0 || planNarrated || narratedAction)) {
1535
+ shouldRetryBeforeFinalizing) {
1465
1536
  actionIntentRetries += 1;
1466
1537
  let nudge;
1467
1538
  if (planHasOpenWorkNow && session.planApproved.value) {
@@ -1476,14 +1547,20 @@ export async function runAgentLoop(prompt, options = {}) {
1476
1547
  "Every turn MUST contain a ```tool block until the task is done.";
1477
1548
  writeNotice("warn", "described a security/pentest action but emitted no tool call — nudging it to run one", chalk.yellow(" ⚠ described a security/pentest action but emitted no tool call — nudging it to run one\n"));
1478
1549
  }
1479
- else if (!buildLikeTurn) {
1550
+ else if (freshWebSearchRequired || narratedWebAction) {
1551
+ // Web-specific recovery ONLY when the user asked for current
1552
+ // info or the model explicitly claimed a fetch/search step.
1553
+ // Previously every non-build stall used this path, so a "hi"
1554
+ // greeting that said "I'll start executing" was forced into
1555
+ // pointless web.search recovery loops.
1480
1556
  nudge =
1481
1557
  "You wrote that you would fetch/search/read something but emitted NO ```tool block, so NOTHING ran. Do NOT narrate the next browsing step — DO it. Emit exactly one valid ```tool block now. If you know the exact page, use:\n" +
1482
1558
  '```tool\n{"name":"web.fetch","args":{"url":"https://example.com/page","responseMode":"readable"}}\n```\n' +
1483
1559
  "If you do not know the exact page URL, use web.search first. After the tool output, answer from the fetched page content.";
1484
1560
  writeNotice("warn", "described a web action but emitted no tool call — nudging it to run one", chalk.yellow(" ⚠ described a web action but emitted no tool call — nudging it to run one\n"));
1485
1561
  }
1486
- else if (planNarrated || productiveSteps > 0) {
1562
+ else if (buildLikeTurn &&
1563
+ (planNarrated || productiveSteps > 0)) {
1487
1564
  const kind = pentestLikeTurn ? "pentest" : "coding";
1488
1565
  nudge =
1489
1566
  "You wrote the plan as PROSE but did NOT call plan.create, so no plan was saved and the user cannot /implement it. Emit it as a real tool call NOW — exactly one ```tool block:\n" +
@@ -1491,17 +1568,17 @@ export async function runAgentLoop(prompt, options = {}) {
1491
1568
  "Do not describe the plan again in prose — just emit the plan.create tool block.";
1492
1569
  writeNotice("warn", "plan was written as text, not created — nudging it to call plan.create", chalk.yellow(" ⚠ plan was written as text, not created — nudging it to call plan.create\n"));
1493
1570
  }
1571
+ else if (buildLikeTurn) {
1572
+ nudge =
1573
+ "You described what you will do but emitted NO ```tool block, so NOTHING actually happened — narration is not action. Emit a real tool call NOW. For this build task, explore first like this:\n" +
1574
+ '```tool\n{"name":"fs.list","args":{"path":"."}}\n```\n' +
1575
+ "Then read key files, and once you understand the directory, call plan.create. Every turn MUST contain a ```tool block until the task is done.";
1576
+ writeNotice("warn", "described an action but emitted no tool call — nudging it to run one", chalk.yellow(" ⚠ described an action but emitted no tool call — nudging it to run one\n"));
1577
+ }
1494
1578
  else {
1495
- if (pentestLikeTurn) {
1496
- nudge =
1497
- "You described what you will do but emitted NO ```tool block, so NOTHING actually happened — narration is not action. Emit a real tool call NOW. For this pentest task, explore/recon first, then call plan.create. Every turn MUST contain a ```tool block until the task is done.";
1498
- }
1499
- else {
1500
- nudge =
1501
- "You described what you will do but emitted NO ```tool block, so NOTHING actually happened — narration is not action. Emit a real tool call NOW. For this build task, explore first like this:\n" +
1502
- '```tool\n{"name":"fs.list","args":{"path":"."}}\n```\n' +
1503
- "Then read key files, and once you understand the directory, call plan.create. Every turn MUST contain a ```tool block until the task is done.";
1504
- }
1579
+ // Generic non-build, non-web stall (e.g. "I'll list the files").
1580
+ nudge =
1581
+ "You described what you will do but emitted NO ```tool block, so NOTHING actually happened — narration is not action. Emit a real tool call NOW for the step you just described. Every turn that claims an action MUST contain a ```tool block.";
1505
1582
  writeNotice("warn", "described an action but emitted no tool call — nudging it to run one", chalk.yellow(" ⚠ described an action but emitted no tool call — nudging it to run one\n"));
1506
1583
  }
1507
1584
  pushAssistantHistory(assistantText.visible);
@@ -1688,7 +1765,12 @@ export async function runAgentLoop(prompt, options = {}) {
1688
1765
  `${omittedCallCount} were not run. After reviewing results, issue a small, prioritized next batch.`,
1689
1766
  });
1690
1767
  }
1691
- // Now emit only the calls that will actually execute, after thinking
1768
+ // Notice BEFORE tool cards so the transcript reads:
1769
+ // thinking → response → "N tool calls…" → tool cards (not tools then info).
1770
+ if (allCalls.length > 1) {
1771
+ writeNotice("info", `${allCalls.length} tool calls in this message — running scoped (independent read-only lookups in parallel, everything else in order)`, chalk.dim(` ℹ ${allCalls.length} tool calls — read-only lookups in parallel, the rest in order\n`));
1772
+ }
1773
+ // Emit only the calls that will actually execute, after thinking
1692
1774
  // + assistant text so transcript order remains correct.
1693
1775
  for (const deferred of activeDeferredToolCalls.slice(0, allCalls.length)) {
1694
1776
  writeToolCall(deferred.eventId, deferred.call, deferred.rendered);
@@ -1698,9 +1780,6 @@ export async function runAgentLoop(prompt, options = {}) {
1698
1780
  .map((c) => `\`\`\`tool\n${JSON.stringify(c)}\n\`\`\``)
1699
1781
  .join("\n\n");
1700
1782
  pushAssistantHistory(standardizedContent);
1701
- if (allCalls.length > 1) {
1702
- writeNotice("info", `${allCalls.length} tool calls in this message — running scoped (independent read-only lookups in parallel, everything else in order)`, chalk.dim(` ℹ ${allCalls.length} tool calls — read-only lookups in parallel, the rest in order\n`));
1703
- }
1704
1783
  // Scoped-parallel batch execution
1705
1784
  // The model may emit several calls in one message. We partition them,
1706
1785
  // IN DOCUMENT ORDER, into segments:
@@ -1736,7 +1815,12 @@ export async function runAgentLoop(prompt, options = {}) {
1736
1815
  let blockedResult = null;
1737
1816
  let failed = false;
1738
1817
  let awaitingPlanApproval = false;
1818
+ /** Indices into allCalls that actually ran (got a tool-result). */
1819
+ const executedIndices = new Set();
1739
1820
  const recordResult = (res, continueAfterFailure = false) => {
1821
+ const idx = allCalls.indexOf(res.call);
1822
+ if (idx >= 0)
1823
+ executedIndices.add(idx);
1740
1824
  messages.push({
1741
1825
  role: "tool",
1742
1826
  content: `Tool ${res.call.name} result (exit=${res.result.exitCode ?? 0}, ok=${res.result.ok}):\n${res.contextOutput}`,
@@ -1801,6 +1885,41 @@ export async function runAgentLoop(prompt, options = {}) {
1801
1885
  recordResult(res, true);
1802
1886
  }
1803
1887
  }
1888
+ // Cards were emitted for every call up front. If the batch stopped
1889
+ // early (failure / abort / plan gate), any card still on "running"
1890
+ // must get a terminal result so the TUI never spins forever.
1891
+ for (let i = 0; i < allCalls.length; i += 1) {
1892
+ if (executedIndices.has(i))
1893
+ continue;
1894
+ const call = allCalls[i];
1895
+ if (i >= 0 && !callIds[i]) {
1896
+ callIds[i] = `tool-${++nextToolEventId}`;
1897
+ }
1898
+ const id = callIds[i];
1899
+ if (!alreadyPrintedIds.has(id)) {
1900
+ // Never shown in the transcript — skip.
1901
+ continue;
1902
+ }
1903
+ const reason = aborted
1904
+ ? "Cancelled — turn aborted before this call ran."
1905
+ : blocked
1906
+ ? "Cancelled — earlier tool was blocked or declined."
1907
+ : awaitingPlanApproval
1908
+ ? "Deferred — waiting for plan approval."
1909
+ : failed
1910
+ ? "Cancelled — earlier tool in this batch failed."
1911
+ : "Cancelled — not executed.";
1912
+ const result = {
1913
+ ok: false,
1914
+ output: reason,
1915
+ exitCode: 130,
1916
+ };
1917
+ emitToolResult(id, result, reason);
1918
+ messages.push({
1919
+ role: "tool",
1920
+ content: `Tool ${call.name} result (exit=130, ok=false):\n${reason}`,
1921
+ });
1922
+ }
1804
1923
  // plan.create is a hard transaction boundary. Its successful handler
1805
1924
  // persists and displays the plan; returning immediately prevents a
1806
1925
  // stale pre-loop activePlan snapshot from nudging a duplicate plan and