@astralyn/pi 0.82.7 → 0.84.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 (781) hide show
  1. package/CHANGELOG.md +78 -5099
  2. package/README.md +12 -111
  3. package/dist/bun/cli.d.ts.map +1 -1
  4. package/dist/bun/cli.js.map +1 -1
  5. package/dist/bun/register-bedrock.d.ts.map +1 -1
  6. package/dist/bun/restore-sandbox-env.d.ts.map +1 -1
  7. package/dist/bun/restore-sandbox-env.js.map +1 -1
  8. package/dist/cli/args.d.ts +2 -0
  9. package/dist/cli/args.d.ts.map +1 -1
  10. package/dist/cli/args.js +28 -2
  11. package/dist/cli/args.js.map +1 -1
  12. package/dist/cli/config-selector.d.ts.map +1 -1
  13. package/dist/cli/config-selector.js +2 -2
  14. package/dist/cli/config-selector.js.map +1 -1
  15. package/dist/cli/credential-print.d.ts +23 -0
  16. package/dist/cli/credential-print.d.ts.map +1 -0
  17. package/dist/cli/credential-print.js +117 -0
  18. package/dist/cli/credential-print.js.map +1 -0
  19. package/dist/cli/experimental/auth.d.ts +16 -0
  20. package/dist/cli/experimental/auth.d.ts.map +1 -0
  21. package/dist/cli/experimental/auth.js +13 -0
  22. package/dist/cli/experimental/auth.js.map +1 -0
  23. package/dist/cli/experimental/cli.d.ts +6 -0
  24. package/dist/cli/experimental/cli.d.ts.map +1 -0
  25. package/dist/cli/experimental/cli.js +5 -0
  26. package/dist/cli/experimental/cli.js.map +1 -0
  27. package/dist/cli/experimental/command-options.d.ts +17 -0
  28. package/dist/cli/experimental/command-options.d.ts.map +1 -0
  29. package/dist/cli/experimental/command-options.js +35 -0
  30. package/dist/cli/experimental/command-options.js.map +1 -0
  31. package/dist/cli/experimental/command.d.ts +63 -0
  32. package/dist/cli/experimental/command.d.ts.map +1 -0
  33. package/dist/cli/experimental/command.js +127 -0
  34. package/dist/cli/experimental/command.js.map +1 -0
  35. package/dist/cli/experimental/commands/client.d.ts +13 -0
  36. package/dist/cli/experimental/commands/client.d.ts.map +1 -0
  37. package/dist/cli/experimental/commands/client.js +25 -0
  38. package/dist/cli/experimental/commands/client.js.map +1 -0
  39. package/dist/cli/experimental/commands/pi.d.ts +15 -0
  40. package/dist/cli/experimental/commands/pi.d.ts.map +1 -0
  41. package/dist/cli/experimental/commands/pi.js +28 -0
  42. package/dist/cli/experimental/commands/pi.js.map +1 -0
  43. package/dist/cli/experimental/commands/server.d.ts +13 -0
  44. package/dist/cli/experimental/commands/server.d.ts.map +1 -0
  45. package/dist/cli/experimental/commands/server.js +25 -0
  46. package/dist/cli/experimental/commands/server.js.map +1 -0
  47. package/dist/cli/experimental/transport-address.d.ts +10 -0
  48. package/dist/cli/experimental/transport-address.d.ts.map +1 -0
  49. package/dist/cli/experimental/transport-address.js +38 -0
  50. package/dist/cli/experimental/transport-address.js.map +1 -0
  51. package/dist/cli/file-processor.d.ts.map +1 -1
  52. package/dist/cli/file-processor.js.map +1 -1
  53. package/dist/cli/initial-message.d.ts +1 -1
  54. package/dist/cli/initial-message.d.ts.map +1 -1
  55. package/dist/cli/initial-message.js.map +1 -1
  56. package/dist/cli/list-models.d.ts +1 -1
  57. package/dist/cli/list-models.d.ts.map +1 -1
  58. package/dist/cli/list-models.js +2 -2
  59. package/dist/cli/list-models.js.map +1 -1
  60. package/dist/cli/project-trust.d.ts.map +1 -1
  61. package/dist/cli/project-trust.js.map +1 -1
  62. package/dist/cli/session-picker.d.ts.map +1 -1
  63. package/dist/cli/session-picker.js.map +1 -1
  64. package/dist/cli/startup-ui.d.ts +1 -1
  65. package/dist/cli/startup-ui.d.ts.map +1 -1
  66. package/dist/cli/startup-ui.js +2 -2
  67. package/dist/cli/startup-ui.js.map +1 -1
  68. package/dist/cli.d.ts.map +1 -1
  69. package/dist/cli.js +1 -0
  70. package/dist/cli.js.map +1 -1
  71. package/dist/client/index.d.ts +3 -0
  72. package/dist/client/index.d.ts.map +1 -0
  73. package/dist/client/index.js +3 -0
  74. package/dist/client/index.js.map +1 -0
  75. package/dist/client/remote-session.d.ts +53 -0
  76. package/dist/client/remote-session.d.ts.map +1 -0
  77. package/dist/client/remote-session.js +340 -0
  78. package/dist/client/remote-session.js.map +1 -0
  79. package/dist/client/transcript.d.ts +12 -0
  80. package/dist/client/transcript.d.ts.map +1 -0
  81. package/dist/client/transcript.js +98 -0
  82. package/dist/client/transcript.js.map +1 -0
  83. package/dist/config.d.ts.map +1 -1
  84. package/dist/config.js.map +1 -1
  85. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  86. package/dist/core/agent-session-runtime.js +3 -8
  87. package/dist/core/agent-session-runtime.js.map +1 -1
  88. package/dist/core/agent-session-services.d.ts +1 -0
  89. package/dist/core/agent-session-services.d.ts.map +1 -1
  90. package/dist/core/agent-session-services.js +1 -0
  91. package/dist/core/agent-session-services.js.map +1 -1
  92. package/dist/core/agent-session.d.ts +31 -11
  93. package/dist/core/agent-session.d.ts.map +1 -1
  94. package/dist/core/agent-session.js +189 -192
  95. package/dist/core/agent-session.js.map +1 -1
  96. package/dist/core/auth-guidance.d.ts.map +1 -1
  97. package/dist/core/auth-guidance.js.map +1 -1
  98. package/dist/core/auth-storage.d.ts +15 -9
  99. package/dist/core/auth-storage.d.ts.map +1 -1
  100. package/dist/core/auth-storage.js +159 -41
  101. package/dist/core/auth-storage.js.map +1 -1
  102. package/dist/core/bash-executor.d.ts.map +1 -1
  103. package/dist/core/bash-executor.js.map +1 -1
  104. package/dist/core/cache-stats.d.ts.map +1 -1
  105. package/dist/core/cache-stats.js.map +1 -1
  106. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  107. package/dist/core/compaction/branch-summarization.js.map +1 -1
  108. package/dist/core/compaction/compaction.d.ts.map +1 -1
  109. package/dist/core/compaction/compaction.js.map +1 -1
  110. package/dist/core/compaction/index.d.ts.map +1 -1
  111. package/dist/core/compaction/utils.d.ts.map +1 -1
  112. package/dist/core/compaction/utils.js.map +1 -1
  113. package/dist/core/defaults.d.ts.map +1 -1
  114. package/dist/core/diagnostics.d.ts.map +1 -1
  115. package/dist/core/event-bus.d.ts.map +1 -1
  116. package/dist/core/event-bus.js.map +1 -1
  117. package/dist/core/exec.d.ts.map +1 -1
  118. package/dist/core/exec.js.map +1 -1
  119. package/dist/core/experimental.d.ts.map +1 -1
  120. package/dist/core/experimental.js.map +1 -1
  121. package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
  122. package/dist/core/export-html/ansi-to-html.js.map +1 -1
  123. package/dist/core/export-html/index.d.ts.map +1 -1
  124. package/dist/core/export-html/index.js.map +1 -1
  125. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  126. package/dist/core/export-html/tool-renderer.js.map +1 -1
  127. package/dist/core/extensions/index.d.ts +1 -1
  128. package/dist/core/extensions/index.d.ts.map +1 -1
  129. package/dist/core/extensions/index.js.map +1 -1
  130. package/dist/core/extensions/loader.d.ts.map +1 -1
  131. package/dist/core/extensions/loader.js +43 -20
  132. package/dist/core/extensions/loader.js.map +1 -1
  133. package/dist/core/extensions/runner.d.ts +3 -1
  134. package/dist/core/extensions/runner.d.ts.map +1 -1
  135. package/dist/core/extensions/runner.js +31 -28
  136. package/dist/core/extensions/runner.js.map +1 -1
  137. package/dist/core/extensions/types.d.ts +28 -3
  138. package/dist/core/extensions/types.d.ts.map +1 -1
  139. package/dist/core/extensions/types.js.map +1 -1
  140. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  141. package/dist/core/extensions/wrapper.js.map +1 -1
  142. package/dist/core/footer-data-provider.d.ts +10 -0
  143. package/dist/core/footer-data-provider.d.ts.map +1 -1
  144. package/dist/core/footer-data-provider.js +18 -19
  145. package/dist/core/footer-data-provider.js.map +1 -1
  146. package/dist/core/http-dispatcher.d.ts.map +1 -1
  147. package/dist/core/http-dispatcher.js +5 -0
  148. package/dist/core/http-dispatcher.js.map +1 -1
  149. package/dist/core/index.d.ts.map +1 -1
  150. package/dist/core/keybindings.d.ts +157 -125
  151. package/dist/core/keybindings.d.ts.map +1 -1
  152. package/dist/core/keybindings.js +0 -1
  153. package/dist/core/keybindings.js.map +1 -1
  154. package/dist/core/messages.d.ts.map +1 -1
  155. package/dist/core/messages.js.map +1 -1
  156. package/dist/core/model-config.d.ts +37 -13
  157. package/dist/core/model-config.d.ts.map +1 -1
  158. package/dist/core/model-config.js +4 -2
  159. package/dist/core/model-config.js.map +1 -1
  160. package/dist/core/model-registry.d.ts +5 -3
  161. package/dist/core/model-registry.d.ts.map +1 -1
  162. package/dist/core/model-registry.js +13 -11
  163. package/dist/core/model-registry.js.map +1 -1
  164. package/dist/core/model-resolver.d.ts +4 -3
  165. package/dist/core/model-resolver.d.ts.map +1 -1
  166. package/dist/core/model-resolver.js +41 -10
  167. package/dist/core/model-resolver.js.map +1 -1
  168. package/dist/core/model-runtime.d.ts +30 -13
  169. package/dist/core/model-runtime.d.ts.map +1 -1
  170. package/dist/core/model-runtime.js +239 -91
  171. package/dist/core/model-runtime.js.map +1 -1
  172. package/dist/core/models-store.d.ts +12 -7
  173. package/dist/core/models-store.d.ts.map +1 -1
  174. package/dist/core/models-store.js +84 -16
  175. package/dist/core/models-store.js.map +1 -1
  176. package/dist/core/output-guard.d.ts.map +1 -1
  177. package/dist/core/output-guard.js.map +1 -1
  178. package/dist/core/package-manager.d.ts +4 -1
  179. package/dist/core/package-manager.d.ts.map +1 -1
  180. package/dist/core/package-manager.js +76 -48
  181. package/dist/core/package-manager.js.map +1 -1
  182. package/dist/core/pi-manifest.d.ts +8 -0
  183. package/dist/core/pi-manifest.d.ts.map +1 -0
  184. package/dist/core/pi-manifest.js +25 -0
  185. package/dist/core/pi-manifest.js.map +1 -0
  186. package/dist/core/project-trust.d.ts.map +1 -1
  187. package/dist/core/project-trust.js.map +1 -1
  188. package/dist/core/prompt-templates.d.ts.map +1 -1
  189. package/dist/core/prompt-templates.js.map +1 -1
  190. package/dist/core/provider-attribution.d.ts.map +1 -1
  191. package/dist/core/provider-attribution.js.map +1 -1
  192. package/dist/core/provider-composer.d.ts +4 -1
  193. package/dist/core/provider-composer.d.ts.map +1 -1
  194. package/dist/core/provider-composer.js +36 -15
  195. package/dist/core/provider-composer.js.map +1 -1
  196. package/dist/core/radius.d.ts.map +1 -1
  197. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  198. package/dist/core/remote-catalog-provider.js +73 -67
  199. package/dist/core/remote-catalog-provider.js.map +1 -1
  200. package/dist/core/resolve-config-value.d.ts.map +1 -1
  201. package/dist/core/resolve-config-value.js.map +1 -1
  202. package/dist/core/resource-loader.d.ts +15 -0
  203. package/dist/core/resource-loader.d.ts.map +1 -1
  204. package/dist/core/resource-loader.js +68 -51
  205. package/dist/core/resource-loader.js.map +1 -1
  206. package/dist/core/runtime-credentials.d.ts +5 -5
  207. package/dist/core/runtime-credentials.d.ts.map +1 -1
  208. package/dist/core/runtime-credentials.js +12 -10
  209. package/dist/core/runtime-credentials.js.map +1 -1
  210. package/dist/core/sdk.d.ts.map +1 -1
  211. package/dist/core/sdk.js.map +1 -1
  212. package/dist/core/session-cwd.d.ts.map +1 -1
  213. package/dist/core/session-cwd.js +0 -1
  214. package/dist/core/session-cwd.js.map +1 -1
  215. package/dist/core/session-manager.d.ts.map +1 -1
  216. package/dist/core/session-manager.js +10 -12
  217. package/dist/core/session-manager.js.map +1 -1
  218. package/dist/core/settings-manager.d.ts +12 -0
  219. package/dist/core/settings-manager.d.ts.map +1 -1
  220. package/dist/core/settings-manager.js +47 -33
  221. package/dist/core/settings-manager.js.map +1 -1
  222. package/dist/core/skills.d.ts.map +1 -1
  223. package/dist/core/skills.js.map +1 -1
  224. package/dist/core/slash-commands.d.ts.map +1 -1
  225. package/dist/core/source-info.d.ts.map +1 -1
  226. package/dist/core/source-info.js.map +1 -1
  227. package/dist/core/system-prompt.d.ts.map +1 -1
  228. package/dist/core/system-prompt.js.map +1 -1
  229. package/dist/core/telemetry.d.ts.map +1 -1
  230. package/dist/core/telemetry.js.map +1 -1
  231. package/dist/core/timings.d.ts.map +1 -1
  232. package/dist/core/timings.js.map +1 -1
  233. package/dist/core/tools/bash.d.ts.map +1 -1
  234. package/dist/core/tools/bash.js +12 -10
  235. package/dist/core/tools/bash.js.map +1 -1
  236. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  237. package/dist/core/tools/edit-diff.js.map +1 -1
  238. package/dist/core/tools/edit.d.ts.map +1 -1
  239. package/dist/core/tools/edit.js +4 -3
  240. package/dist/core/tools/edit.js.map +1 -1
  241. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  242. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  243. package/dist/core/tools/find.d.ts +3 -0
  244. package/dist/core/tools/find.d.ts.map +1 -1
  245. package/dist/core/tools/find.js +47 -20
  246. package/dist/core/tools/find.js.map +1 -1
  247. package/dist/core/tools/grep.d.ts.map +1 -1
  248. package/dist/core/tools/grep.js.map +1 -1
  249. package/dist/core/tools/index.d.ts.map +1 -1
  250. package/dist/core/tools/index.js.map +1 -1
  251. package/dist/core/tools/ls.d.ts.map +1 -1
  252. package/dist/core/tools/ls.js.map +1 -1
  253. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  254. package/dist/core/tools/output-accumulator.js +12 -18
  255. package/dist/core/tools/output-accumulator.js.map +1 -1
  256. package/dist/core/tools/path-utils.d.ts.map +1 -1
  257. package/dist/core/tools/path-utils.js.map +1 -1
  258. package/dist/core/tools/read.d.ts.map +1 -1
  259. package/dist/core/tools/read.js +1 -1
  260. package/dist/core/tools/read.js.map +1 -1
  261. package/dist/core/tools/render-utils.d.ts.map +1 -1
  262. package/dist/core/tools/render-utils.js.map +1 -1
  263. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  264. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  265. package/dist/core/tools/truncate.d.ts.map +1 -1
  266. package/dist/core/tools/truncate.js.map +1 -1
  267. package/dist/core/tools/write.d.ts.map +1 -1
  268. package/dist/core/tools/write.js +0 -1
  269. package/dist/core/tools/write.js.map +1 -1
  270. package/dist/core/trust-manager.d.ts.map +1 -1
  271. package/dist/core/trust-manager.js +48 -10
  272. package/dist/core/trust-manager.js.map +1 -1
  273. package/dist/core/usage-totals.d.ts.map +1 -1
  274. package/dist/core/usage-totals.js.map +1 -1
  275. package/dist/extensions/biu/index.d.ts +19 -0
  276. package/dist/extensions/biu/index.d.ts.map +1 -0
  277. package/dist/extensions/biu/index.js +350 -0
  278. package/dist/extensions/biu/index.js.map +1 -0
  279. package/dist/extensions/biu/prompts.d.ts +26 -0
  280. package/dist/extensions/biu/prompts.d.ts.map +1 -0
  281. package/dist/extensions/biu/prompts.js +260 -0
  282. package/dist/extensions/biu/prompts.js.map +1 -0
  283. package/dist/extensions/biu/workspace.d.ts +122 -0
  284. package/dist/extensions/biu/workspace.d.ts.map +1 -0
  285. package/dist/extensions/biu/workspace.js +404 -0
  286. package/dist/extensions/biu/workspace.js.map +1 -0
  287. package/dist/extensions/deepwiki/client.d.ts.map +1 -1
  288. package/dist/extensions/deepwiki/client.js.map +1 -1
  289. package/dist/extensions/deepwiki/constants.d.ts.map +1 -1
  290. package/dist/extensions/deepwiki/constants.js.map +1 -1
  291. package/dist/extensions/deepwiki/contents.d.ts.map +1 -1
  292. package/dist/extensions/deepwiki/contents.js.map +1 -1
  293. package/dist/extensions/deepwiki/execute.d.ts.map +1 -1
  294. package/dist/extensions/deepwiki/execute.js.map +1 -1
  295. package/dist/extensions/deepwiki/http.d.ts.map +1 -1
  296. package/dist/extensions/deepwiki/http.js.map +1 -1
  297. package/dist/extensions/deepwiki/index.d.ts.map +1 -1
  298. package/dist/extensions/deepwiki/index.js.map +1 -1
  299. package/dist/extensions/deepwiki/render.d.ts.map +1 -1
  300. package/dist/extensions/deepwiki/render.js.map +1 -1
  301. package/dist/extensions/deepwiki/schema.d.ts +1 -1
  302. package/dist/extensions/deepwiki/schema.d.ts.map +1 -1
  303. package/dist/extensions/deepwiki/schema.js.map +1 -1
  304. package/dist/extensions/index.d.ts.map +1 -1
  305. package/dist/extensions/index.js +2 -2
  306. package/dist/extensions/index.js.map +1 -1
  307. package/dist/extensions/llama/client.d.ts.map +1 -1
  308. package/dist/extensions/llama/client.js +0 -2
  309. package/dist/extensions/llama/client.js.map +1 -1
  310. package/dist/extensions/llama/huggingface.d.ts.map +1 -1
  311. package/dist/extensions/llama/huggingface.js +0 -2
  312. package/dist/extensions/llama/huggingface.js.map +1 -1
  313. package/dist/extensions/llama/index.d.ts.map +1 -1
  314. package/dist/extensions/llama/index.js +11 -2
  315. package/dist/extensions/llama/index.js.map +1 -1
  316. package/dist/extensions/llama/provider.d.ts.map +1 -1
  317. package/dist/extensions/llama/provider.js +22 -8
  318. package/dist/extensions/llama/provider.js.map +1 -1
  319. package/dist/extensions/llama/ui.d.ts.map +1 -1
  320. package/dist/extensions/llama/ui.js +12 -28
  321. package/dist/extensions/llama/ui.js.map +1 -1
  322. package/dist/extensions/question/constants.d.ts.map +1 -1
  323. package/dist/extensions/question/constants.js.map +1 -1
  324. package/dist/extensions/question/dialog-primitives.d.ts.map +1 -1
  325. package/dist/extensions/question/dialog-primitives.js.map +1 -1
  326. package/dist/extensions/question/dialog.d.ts.map +1 -1
  327. package/dist/extensions/question/dialog.js.map +1 -1
  328. package/dist/extensions/question/index.d.ts.map +1 -1
  329. package/dist/extensions/question/index.js.map +1 -1
  330. package/dist/extensions/question/limits.d.ts.map +1 -1
  331. package/dist/extensions/question/render-cache.d.ts.map +1 -1
  332. package/dist/extensions/question/render-cache.js +3 -4
  333. package/dist/extensions/question/render-cache.js.map +1 -1
  334. package/dist/extensions/question/render.d.ts.map +1 -1
  335. package/dist/extensions/question/render.js.map +1 -1
  336. package/dist/extensions/question/results.d.ts.map +1 -1
  337. package/dist/extensions/question/results.js.map +1 -1
  338. package/dist/extensions/question/schema.d.ts.map +1 -1
  339. package/dist/extensions/question/schema.js.map +1 -1
  340. package/dist/extensions/question/state.d.ts.map +1 -1
  341. package/dist/extensions/question/state.js.map +1 -1
  342. package/dist/extensions/question/types.d.ts.map +1 -1
  343. package/dist/extensions/rewind/anchor.d.ts.map +1 -1
  344. package/dist/extensions/rewind/anchor.js.map +1 -1
  345. package/dist/extensions/rewind/config.d.ts.map +1 -1
  346. package/dist/extensions/rewind/config.js.map +1 -1
  347. package/dist/extensions/rewind/engine.d.ts.map +1 -1
  348. package/dist/extensions/rewind/engine.js.map +1 -1
  349. package/dist/extensions/rewind/gc.d.ts.map +1 -1
  350. package/dist/extensions/rewind/gc.js.map +1 -1
  351. package/dist/extensions/rewind/index.d.ts.map +1 -1
  352. package/dist/extensions/rewind/index.js.map +1 -1
  353. package/dist/extensions/rewind/menu.d.ts.map +1 -1
  354. package/dist/extensions/rewind/menu.js.map +1 -1
  355. package/dist/extensions/rewind/paths.d.ts.map +1 -1
  356. package/dist/extensions/rewind/paths.js.map +1 -1
  357. package/dist/extensions/rewind/restore.d.ts.map +1 -1
  358. package/dist/extensions/rewind/restore.js.map +1 -1
  359. package/dist/extensions/rewind/snapshot.d.ts.map +1 -1
  360. package/dist/extensions/rewind/snapshot.js.map +1 -1
  361. package/dist/extensions/rewind/storage.d.ts.map +1 -1
  362. package/dist/extensions/rewind/storage.js.map +1 -1
  363. package/dist/extensions/rewind/text.d.ts.map +1 -1
  364. package/dist/extensions/rewind/text.js.map +1 -1
  365. package/dist/extensions/rewind/tool-path.d.ts.map +1 -1
  366. package/dist/extensions/rewind/tool-path.js.map +1 -1
  367. package/dist/extensions/router/constants.d.ts +3 -0
  368. package/dist/extensions/router/constants.d.ts.map +1 -1
  369. package/dist/extensions/router/constants.js +3 -0
  370. package/dist/extensions/router/constants.js.map +1 -1
  371. package/dist/extensions/router/dialog.d.ts +14 -7
  372. package/dist/extensions/router/dialog.d.ts.map +1 -1
  373. package/dist/extensions/router/dialog.js +70 -132
  374. package/dist/extensions/router/dialog.js.map +1 -1
  375. package/dist/extensions/router/index.d.ts.map +1 -1
  376. package/dist/extensions/router/index.js.map +1 -1
  377. package/dist/extensions/router/presets.d.ts +8 -3
  378. package/dist/extensions/router/presets.d.ts.map +1 -1
  379. package/dist/extensions/router/presets.js +33 -17
  380. package/dist/extensions/router/presets.js.map +1 -1
  381. package/dist/extensions/router/probe.d.ts.map +1 -1
  382. package/dist/extensions/router/probe.js.map +1 -1
  383. package/dist/extensions/router/register.d.ts +3 -3
  384. package/dist/extensions/router/register.d.ts.map +1 -1
  385. package/dist/extensions/router/register.js.map +1 -1
  386. package/dist/extensions/router/store.d.ts.map +1 -1
  387. package/dist/extensions/router/store.js.map +1 -1
  388. package/dist/extensions/router/stream.d.ts.map +1 -1
  389. package/dist/extensions/router/stream.js.map +1 -1
  390. package/dist/extensions/router/types.d.ts.map +1 -1
  391. package/dist/extensions/router/ui.d.ts +11 -2
  392. package/dist/extensions/router/ui.d.ts.map +1 -1
  393. package/dist/extensions/router/ui.js +316 -171
  394. package/dist/extensions/router/ui.js.map +1 -1
  395. package/dist/extensions/statusline/index.d.ts.map +1 -1
  396. package/dist/extensions/statusline/index.js +17 -9
  397. package/dist/extensions/statusline/index.js.map +1 -1
  398. package/dist/extensions/subagent/activity.d.ts.map +1 -1
  399. package/dist/extensions/subagent/activity.js.map +1 -1
  400. package/dist/extensions/subagent/agents.d.ts.map +1 -1
  401. package/dist/extensions/subagent/agents.js.map +1 -1
  402. package/dist/extensions/subagent/constants.d.ts.map +1 -1
  403. package/dist/extensions/subagent/index.d.ts +3 -0
  404. package/dist/extensions/subagent/index.d.ts.map +1 -1
  405. package/dist/extensions/subagent/index.js +83 -12
  406. package/dist/extensions/subagent/index.js.map +1 -1
  407. package/dist/extensions/subagent/picker.d.ts.map +1 -1
  408. package/dist/extensions/subagent/picker.js +2 -9
  409. package/dist/extensions/subagent/picker.js.map +1 -1
  410. package/dist/extensions/subagent/render.d.ts.map +1 -1
  411. package/dist/extensions/subagent/render.js +33 -9
  412. package/dist/extensions/subagent/render.js.map +1 -1
  413. package/dist/extensions/subagent/resolve.d.ts.map +1 -1
  414. package/dist/extensions/subagent/resolve.js.map +1 -1
  415. package/dist/extensions/subagent/retry.d.ts.map +1 -1
  416. package/dist/extensions/subagent/retry.js.map +1 -1
  417. package/dist/extensions/subagent/runner.d.ts +2 -1
  418. package/dist/extensions/subagent/runner.d.ts.map +1 -1
  419. package/dist/extensions/subagent/runner.js +10 -12
  420. package/dist/extensions/subagent/runner.js.map +1 -1
  421. package/dist/extensions/subagent/schema.d.ts.map +1 -1
  422. package/dist/extensions/subagent/schema.js.map +1 -1
  423. package/dist/extensions/subagent/sdk-runner.d.ts.map +1 -1
  424. package/dist/extensions/subagent/sdk-runner.js +41 -1
  425. package/dist/extensions/subagent/sdk-runner.js.map +1 -1
  426. package/dist/extensions/subagent/settings.d.ts.map +1 -1
  427. package/dist/extensions/subagent/settings.js +46 -36
  428. package/dist/extensions/subagent/settings.js.map +1 -1
  429. package/dist/extensions/subagent/types.d.ts +0 -1
  430. package/dist/extensions/subagent/types.d.ts.map +1 -1
  431. package/dist/extensions/subagent/types.js.map +1 -1
  432. package/dist/extensions/todo/constants.d.ts.map +1 -1
  433. package/dist/extensions/todo/constants.js.map +1 -1
  434. package/dist/extensions/todo/index.d.ts.map +1 -1
  435. package/dist/extensions/todo/index.js.map +1 -1
  436. package/dist/extensions/todo/overlay.d.ts.map +1 -1
  437. package/dist/extensions/todo/overlay.js +6 -10
  438. package/dist/extensions/todo/overlay.js.map +1 -1
  439. package/dist/extensions/todo/schema.d.ts +2 -2
  440. package/dist/extensions/todo/schema.d.ts.map +1 -1
  441. package/dist/extensions/todo/state.d.ts.map +1 -1
  442. package/dist/extensions/todo/state.js.map +1 -1
  443. package/dist/extensions/todo/view.d.ts.map +1 -1
  444. package/dist/extensions/todo/view.js.map +1 -1
  445. package/dist/index.d.ts +4 -4
  446. package/dist/index.d.ts.map +1 -1
  447. package/dist/index.js +1 -1
  448. package/dist/index.js.map +1 -1
  449. package/dist/main.d.ts.map +1 -1
  450. package/dist/main.js +57 -5
  451. package/dist/main.js.map +1 -1
  452. package/dist/migrations.d.ts.map +1 -1
  453. package/dist/migrations.js.map +1 -1
  454. package/dist/modes/index.d.ts +1 -0
  455. package/dist/modes/index.d.ts.map +1 -1
  456. package/dist/modes/index.js.map +1 -1
  457. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  458. package/dist/modes/interactive/components/armin.js +6 -10
  459. package/dist/modes/interactive/components/armin.js.map +1 -1
  460. package/dist/modes/interactive/components/assistant-message.d.ts +5 -2
  461. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  462. package/dist/modes/interactive/components/assistant-message.js +13 -11
  463. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  464. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  465. package/dist/modes/interactive/components/bash-execution.js +4 -10
  466. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  467. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  468. package/dist/modes/interactive/components/bordered-loader.js +0 -3
  469. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  470. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  471. package/dist/modes/interactive/components/branch-summary-message.js +1 -3
  472. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  473. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  474. package/dist/modes/interactive/components/compaction-summary-message.js +1 -3
  475. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  476. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  477. package/dist/modes/interactive/components/config-selector.js +5 -22
  478. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  479. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
  480. package/dist/modes/interactive/components/countdown-timer.js +1 -7
  481. package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
  482. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  483. package/dist/modes/interactive/components/custom-editor.js +8 -8
  484. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  485. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
  486. package/dist/modes/interactive/components/custom-entry.js +1 -4
  487. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  488. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  489. package/dist/modes/interactive/components/custom-message.js +1 -7
  490. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  491. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
  492. package/dist/modes/interactive/components/daxnuts.js +6 -8
  493. package/dist/modes/interactive/components/daxnuts.js.map +1 -1
  494. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  495. package/dist/modes/interactive/components/diff.js.map +1 -1
  496. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  497. package/dist/modes/interactive/components/dynamic-border.js +0 -1
  498. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  499. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -1
  500. package/dist/modes/interactive/components/earendil-announcement.js.map +1 -1
  501. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  502. package/dist/modes/interactive/components/extension-editor.js +1 -7
  503. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  504. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  505. package/dist/modes/interactive/components/extension-input.js +2 -8
  506. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  507. package/dist/modes/interactive/components/extension-selector.d.ts +1 -1
  508. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  509. package/dist/modes/interactive/components/extension-selector.js +1 -9
  510. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  511. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
  512. package/dist/modes/interactive/components/first-time-setup.js +2 -4
  513. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  514. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  515. package/dist/modes/interactive/components/footer.js +2 -4
  516. package/dist/modes/interactive/components/footer.js.map +1 -1
  517. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  518. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  519. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  520. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  521. package/dist/modes/interactive/components/login-dialog.js +3 -9
  522. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  523. package/dist/modes/interactive/components/markdown-transform.d.ts +3 -0
  524. package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -0
  525. package/dist/modes/interactive/components/markdown-transform.js +19 -0
  526. package/dist/modes/interactive/components/markdown-transform.js.map +1 -0
  527. package/dist/modes/interactive/components/mermaid.d.ts +11 -0
  528. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -0
  529. package/dist/modes/interactive/components/mermaid.js +75 -0
  530. package/dist/modes/interactive/components/mermaid.js.map +1 -0
  531. package/dist/modes/interactive/components/model-selector.d.ts +1 -1
  532. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  533. package/dist/modes/interactive/components/model-selector.js +32 -30
  534. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  535. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  536. package/dist/modes/interactive/components/oauth-selector.js +3 -11
  537. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  538. package/dist/modes/interactive/components/scoped-models-selector.d.ts +4 -0
  539. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  540. package/dist/modes/interactive/components/scoped-models-selector.js +34 -13
  541. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  542. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  543. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  544. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  545. package/dist/modes/interactive/components/session-selector.js +35 -60
  546. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  547. package/dist/modes/interactive/components/settings-selector.d.ts +8 -2
  548. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  549. package/dist/modes/interactive/components/settings-selector.js +30 -14
  550. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  551. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  552. package/dist/modes/interactive/components/show-images-selector.js +0 -1
  553. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  554. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  555. package/dist/modes/interactive/components/skill-invocation-message.js +1 -3
  556. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  557. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  558. package/dist/modes/interactive/components/status-indicator.js +0 -2
  559. package/dist/modes/interactive/components/status-indicator.js.map +1 -1
  560. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  561. package/dist/modes/interactive/components/theme-selector.js +0 -2
  562. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  563. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  564. package/dist/modes/interactive/components/thinking-selector.js +0 -1
  565. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  566. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  567. package/dist/modes/interactive/components/tool-execution.js +18 -36
  568. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  569. package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
  570. package/dist/modes/interactive/components/tool-group.js +2 -3
  571. package/dist/modes/interactive/components/tool-group.js.map +1 -1
  572. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  573. package/dist/modes/interactive/components/tree-selector.js +19 -39
  574. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  575. package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -1
  576. package/dist/modes/interactive/components/trust-selector.js +0 -6
  577. package/dist/modes/interactive/components/trust-selector.js.map +1 -1
  578. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  579. package/dist/modes/interactive/components/user-message-selector.js +3 -6
  580. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  581. package/dist/modes/interactive/components/user-message.d.ts +3 -1
  582. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  583. package/dist/modes/interactive/components/user-message.js +8 -5
  584. package/dist/modes/interactive/components/user-message.js.map +1 -1
  585. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
  586. package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
  587. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  588. package/dist/modes/interactive/external-editor.js +40 -3
  589. package/dist/modes/interactive/external-editor.js.map +1 -1
  590. package/dist/modes/interactive/interactive-mode.d.ts +46 -4
  591. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  592. package/dist/modes/interactive/interactive-mode.js +538 -275
  593. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  594. package/dist/modes/interactive/model-search.d.ts.map +1 -1
  595. package/dist/modes/interactive/model-search.js.map +1 -1
  596. package/dist/modes/interactive/theme/dark.json +1 -0
  597. package/dist/modes/interactive/theme/light.json +1 -0
  598. package/dist/modes/interactive/theme/theme-controller.d.ts +3 -0
  599. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  600. package/dist/modes/interactive/theme/theme-controller.js +11 -8
  601. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  602. package/dist/modes/interactive/theme/theme-schema.json +5 -1
  603. package/dist/modes/interactive/theme/theme.d.ts +4 -4
  604. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  605. package/dist/modes/interactive/theme/theme.js +13 -9
  606. package/dist/modes/interactive/theme/theme.js.map +1 -1
  607. package/dist/modes/json-event.d.ts +28 -0
  608. package/dist/modes/json-event.d.ts.map +1 -0
  609. package/dist/modes/json-event.js +12 -0
  610. package/dist/modes/json-event.js.map +1 -0
  611. package/dist/modes/print-mode.d.ts.map +1 -1
  612. package/dist/modes/print-mode.js +12 -2
  613. package/dist/modes/print-mode.js.map +1 -1
  614. package/dist/modes/rpc/jsonl.d.ts.map +1 -1
  615. package/dist/modes/rpc/jsonl.js.map +1 -1
  616. package/dist/modes/rpc/rpc-client.d.ts +5 -4
  617. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  618. package/dist/modes/rpc/rpc-client.js +7 -8
  619. package/dist/modes/rpc/rpc-client.js.map +1 -1
  620. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  621. package/dist/modes/rpc/rpc-mode.js +17 -3
  622. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  623. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  624. package/dist/package-manager-cli.d.ts.map +1 -1
  625. package/dist/package-manager-cli.js +11 -9
  626. package/dist/package-manager-cli.js.map +1 -1
  627. package/dist/rpc-entry.d.ts.map +1 -1
  628. package/dist/rpc-entry.js +1 -0
  629. package/dist/rpc-entry.js.map +1 -1
  630. package/dist/utils/abort.d.ts +5 -0
  631. package/dist/utils/abort.d.ts.map +1 -0
  632. package/dist/utils/abort.js +48 -0
  633. package/dist/utils/abort.js.map +1 -0
  634. package/dist/utils/ansi.d.ts.map +1 -1
  635. package/dist/utils/ansi.js.map +1 -1
  636. package/dist/utils/changelog.d.ts.map +1 -1
  637. package/dist/utils/changelog.js.map +1 -1
  638. package/dist/utils/child-process.d.ts.map +1 -1
  639. package/dist/utils/child-process.js.map +1 -1
  640. package/dist/utils/clipboard-image.d.ts.map +1 -1
  641. package/dist/utils/clipboard-image.js.map +1 -1
  642. package/dist/utils/clipboard-native.d.ts.map +1 -1
  643. package/dist/utils/clipboard-native.js.map +1 -1
  644. package/dist/utils/clipboard.d.ts +1 -1
  645. package/dist/utils/clipboard.d.ts.map +1 -1
  646. package/dist/utils/clipboard.js +22 -2
  647. package/dist/utils/clipboard.js.map +1 -1
  648. package/dist/utils/coalescing-terminal.d.ts +1 -0
  649. package/dist/utils/coalescing-terminal.d.ts.map +1 -1
  650. package/dist/utils/coalescing-terminal.js +16 -8
  651. package/dist/utils/coalescing-terminal.js.map +1 -1
  652. package/dist/utils/deprecation.d.ts.map +1 -1
  653. package/dist/utils/deprecation.js.map +1 -1
  654. package/dist/utils/exif-orientation.d.ts.map +1 -1
  655. package/dist/utils/exif-orientation.js.map +1 -1
  656. package/dist/utils/frontmatter.d.ts.map +1 -1
  657. package/dist/utils/frontmatter.js.map +1 -1
  658. package/dist/utils/fs-watch.d.ts.map +1 -1
  659. package/dist/utils/fs-watch.js.map +1 -1
  660. package/dist/utils/git.d.ts.map +1 -1
  661. package/dist/utils/git.js.map +1 -1
  662. package/dist/utils/html.d.ts.map +1 -1
  663. package/dist/utils/html.js.map +1 -1
  664. package/dist/utils/image-convert.d.ts.map +1 -1
  665. package/dist/utils/image-convert.js.map +1 -1
  666. package/dist/utils/image-process.d.ts.map +1 -1
  667. package/dist/utils/image-process.js.map +1 -1
  668. package/dist/utils/image-resize-core.d.ts.map +1 -1
  669. package/dist/utils/image-resize-core.js.map +1 -1
  670. package/dist/utils/image-resize-worker.d.ts.map +1 -1
  671. package/dist/utils/image-resize-worker.js.map +1 -1
  672. package/dist/utils/image-resize.d.ts.map +1 -1
  673. package/dist/utils/image-resize.js.map +1 -1
  674. package/dist/utils/json.d.ts.map +1 -1
  675. package/dist/utils/json.js.map +1 -1
  676. package/dist/utils/management-http.d.ts +23 -0
  677. package/dist/utils/management-http.d.ts.map +1 -0
  678. package/dist/utils/management-http.js +50 -0
  679. package/dist/utils/management-http.js.map +1 -0
  680. package/dist/utils/mime.d.ts.map +1 -1
  681. package/dist/utils/mime.js.map +1 -1
  682. package/dist/utils/open-browser.d.ts.map +1 -1
  683. package/dist/utils/open-browser.js.map +1 -1
  684. package/dist/utils/paths.d.ts +5 -3
  685. package/dist/utils/paths.d.ts.map +1 -1
  686. package/dist/utils/paths.js +25 -4
  687. package/dist/utils/paths.js.map +1 -1
  688. package/dist/utils/photon.d.ts.map +1 -1
  689. package/dist/utils/photon.js.map +1 -1
  690. package/dist/utils/pi-user-agent.d.ts.map +1 -1
  691. package/dist/utils/pi-user-agent.js.map +1 -1
  692. package/dist/utils/shell.d.ts.map +1 -1
  693. package/dist/utils/shell.js.map +1 -1
  694. package/dist/utils/sleep.d.ts.map +1 -1
  695. package/dist/utils/sleep.js.map +1 -1
  696. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  697. package/dist/utils/syntax-highlight.js.map +1 -1
  698. package/dist/utils/tool-result-images.d.ts +19 -0
  699. package/dist/utils/tool-result-images.d.ts.map +1 -0
  700. package/dist/utils/tool-result-images.js +45 -0
  701. package/dist/utils/tool-result-images.js.map +1 -0
  702. package/dist/utils/tools-manager.d.ts.map +1 -1
  703. package/dist/utils/tools-manager.js +4 -6
  704. package/dist/utils/tools-manager.js.map +1 -1
  705. package/dist/utils/version-check.d.ts +4 -0
  706. package/dist/utils/version-check.d.ts.map +1 -1
  707. package/dist/utils/version-check.js +20 -2
  708. package/dist/utils/version-check.js.map +1 -1
  709. package/dist/utils/windows-self-update.d.ts.map +1 -1
  710. package/dist/utils/windows-self-update.js.map +1 -1
  711. package/docs/bundled/README.md +14 -16
  712. package/docs/bundled/extensions/biu.md +63 -0
  713. package/docs/bundled/extensions/router.md +20 -14
  714. package/docs/bundled/extensions/statusline.md +7 -5
  715. package/docs/bundled/themes.md +1 -1
  716. package/docs/compaction.md +25 -30
  717. package/docs/custom-provider.md +303 -467
  718. package/docs/development.md +83 -0
  719. package/docs/docs.json +6 -10
  720. package/docs/extensions.md +139 -119
  721. package/docs/index.md +18 -74
  722. package/docs/json.md +40 -15
  723. package/docs/keybindings.md +38 -10
  724. package/docs/models.md +210 -150
  725. package/docs/providers.md +3 -1
  726. package/docs/quickstart.md +5 -3
  727. package/docs/rpc.md +177 -134
  728. package/docs/sdk.md +165 -178
  729. package/docs/security.md +2 -2
  730. package/docs/session-format.md +139 -119
  731. package/docs/settings.md +4 -1
  732. package/docs/skills.md +0 -1
  733. package/docs/themes.md +5 -3
  734. package/docs/tui.md +411 -549
  735. package/docs/usage.md +11 -11
  736. package/examples/README.md +6 -1
  737. package/examples/extensions/README.md +13 -33
  738. package/examples/extensions/custom-compaction.ts +1 -16
  739. package/examples/extensions/custom-provider-anthropic/index.ts +11 -4
  740. package/examples/extensions/custom-provider-gitlab-duo/index.ts +2 -1
  741. package/examples/extensions/doom-overlay/wad-finder.ts +7 -3
  742. package/examples/extensions/handoff.ts +2 -11
  743. package/examples/extensions/qna.ts +3 -7
  744. package/examples/extensions/summarize.ts +8 -18
  745. package/examples/extensions/truncated-tool.ts +2 -2
  746. package/examples/rpc-extension-ui.ts +11 -2
  747. package/examples/sdk/02-custom-model.ts +1 -2
  748. package/examples/sdk/09-api-keys-and-oauth.ts +1 -1
  749. package/examples/sdk/12-full-control.ts +3 -1
  750. package/examples/sdk/README.md +1 -0
  751. package/npm-shrinkwrap.json +199 -270
  752. package/package.json +16 -9
  753. package/dist/extensions/plan/constants.d.ts +0 -68
  754. package/dist/extensions/plan/constants.d.ts.map +0 -1
  755. package/dist/extensions/plan/constants.js +0 -100
  756. package/dist/extensions/plan/constants.js.map +0 -1
  757. package/dist/extensions/plan/index.d.ts +0 -30
  758. package/dist/extensions/plan/index.d.ts.map +0 -1
  759. package/dist/extensions/plan/index.js +0 -429
  760. package/dist/extensions/plan/index.js.map +0 -1
  761. package/dist/extensions/plan/schema.d.ts +0 -20
  762. package/dist/extensions/plan/schema.d.ts.map +0 -1
  763. package/dist/extensions/plan/schema.js +0 -13
  764. package/dist/extensions/plan/schema.js.map +0 -1
  765. package/dist/extensions/plan/state.d.ts +0 -38
  766. package/dist/extensions/plan/state.d.ts.map +0 -1
  767. package/dist/extensions/plan/state.js +0 -96
  768. package/dist/extensions/plan/state.js.map +0 -1
  769. package/dist/extensions/plan/storage.d.ts +0 -26
  770. package/dist/extensions/plan/storage.d.ts.map +0 -1
  771. package/dist/extensions/plan/storage.js +0 -83
  772. package/dist/extensions/plan/storage.js.map +0 -1
  773. package/dist/extensions/plan/view.d.ts +0 -44
  774. package/dist/extensions/plan/view.d.ts.map +0 -1
  775. package/dist/extensions/plan/view.js +0 -149
  776. package/dist/extensions/plan/view.js.map +0 -1
  777. package/docs/bundled/extensions/README.md +0 -19
  778. package/docs/bundled/extensions/plan.md +0 -34
  779. package/examples/extensions/plan-mode/README.md +0 -66
  780. package/examples/extensions/plan-mode/index.ts +0 -390
  781. package/examples/extensions/plan-mode/utils.ts +0 -168
@@ -6,7 +6,8 @@ import * as crypto from "node:crypto";
6
6
  import * as fs from "node:fs";
7
7
  import * as os from "node:os";
8
8
  import * as path from "node:path";
9
- import { CombinedAutocompleteProvider, Container, fuzzyFilter, Markdown, matchesKey, Spacer, setKeybindings, Text, TruncatedText, TUI, visibleWidth, } from "@earendil-works/pi-tui";
9
+ import * as TuiLayouts from "@earendil-works/pi-tui";
10
+ import { CombinedAutocompleteProvider, Container, fuzzyFilter, Markdown, matchesKey, ProcessTerminal, Spacer, setKeybindings, Text, TruncatedText, TuiAltScreen, TuiMainScreen, visibleWidth, } from "@earendil-works/pi-tui";
10
11
  import chalk from "chalk";
11
12
  import { spawn, spawnSync } from "child_process";
12
13
  import { APP_NAME, APP_TITLE, CONFIG_DIR_NAME, getAgentDir, getAuthPath, getDebugLogPath, getDocsPath, getShareViewerUrl, VERSION, } from "../../config.js";
@@ -17,7 +18,8 @@ import { FooterDataProvider } from "../../core/footer-data-provider.js";
17
18
  import { configureHttpDispatcher, formatHttpIdleTimeoutMs } from "../../core/http-dispatcher.js";
18
19
  import { KeybindingsManager } from "../../core/keybindings.js";
19
20
  import { createCompactionSummaryMessage } from "../../core/messages.js";
20
- import { defaultModelPerProvider, findExactModelReferenceMatch, resolveModelScope, resolveModelScopeWithDiagnostics, } from "../../core/model-resolver.js";
21
+ import { defaultModelPerProvider, findExactModelReferenceMatch, resolveModelScopeFromModels, } from "../../core/model-resolver.js";
22
+ import { CredentialSynchronizationError } from "../../core/model-runtime.js";
21
23
  import { DefaultPackageManager } from "../../core/package-manager.js";
22
24
  import { formatMissingSessionCwdPrompt, MissingSessionCwdError } from "../../core/session-cwd.js";
23
25
  import { SessionManager, sessionEntryToContextMessages } from "../../core/session-manager.js";
@@ -29,6 +31,7 @@ import { copyToClipboard, readClipboardText } from "../../utils/clipboard.js";
29
31
  import { extensionForImageMimeType, readClipboardImage } from "../../utils/clipboard-image.js";
30
32
  import { CoalescingTerminal } from "../../utils/coalescing-terminal.js";
31
33
  import { parseGitUrl } from "../../utils/git.js";
34
+ import { openBrowser } from "../../utils/open-browser.js";
32
35
  import { getCwdRelativePath } from "../../utils/paths.js";
33
36
  import { killTrackedDetachedChildren } from "../../utils/shell.js";
34
37
  import { ensureTool } from "../../utils/tools-manager.js";
@@ -51,6 +54,7 @@ import { ExtensionSelectorComponent } from "./components/extension-selector.js";
51
54
  import { FooterComponent, formatTokens } from "./components/footer.js";
52
55
  import { formatKeyText, keyDisplayText, keyHint, keyText, rawKeyHint } from "./components/keybinding-hints.js";
53
56
  import { LoginDialogComponent } from "./components/login-dialog.js";
57
+ import { createMermaidMarkdownTransformer } from "./components/mermaid.js";
54
58
  import { ModelSelectorComponent } from "./components/model-selector.js";
55
59
  import { formatAuthSelectorProviderType, OAuthSelectorComponent, } from "./components/oauth-selector.js";
56
60
  import { ScopedModelsSelectorComponent } from "./components/scoped-models-selector.js";
@@ -72,8 +76,6 @@ function isExpandable(obj) {
72
76
  return typeof obj === "object" && obj !== null && "setExpanded" in obj && typeof obj.setExpanded === "function";
73
77
  }
74
78
  class ExpandableText extends Text {
75
- getCollapsedText;
76
- getExpandedText;
77
79
  constructor(getCollapsedText, getExpandedText, expanded = false, paddingX = 0, paddingY = 0) {
78
80
  super(expanded ? getExpandedText() : getCollapsedText(), paddingX, paddingY);
79
81
  this.getCollapsedText = getCollapsedText;
@@ -161,98 +163,39 @@ function formatLoginProviderCompletionDescription(provider) {
161
163
  const authTypes = provider.authTypes.map(formatAuthSelectorProviderType).join("/");
162
164
  return provider.name === provider.id ? authTypes : `${provider.name} · ${authTypes}`;
163
165
  }
166
+ /** Composition root for selecting the interactive terminal renderer. */
167
+ export function createInteractiveTui(options) {
168
+ const terminal = options.terminal ?? new ProcessTerminal();
169
+ if (options.tuiMode === "fullscreen") {
170
+ return new TuiAltScreen(terminal, options.showHardwareCursor, options.logDirectory, { openUrl: openBrowser });
171
+ }
172
+ return new TuiMainScreen(terminal, options.showHardwareCursor, options.logDirectory);
173
+ }
174
+ /** Stable reference for components while InteractiveMode replaces the active renderer. */
175
+ export function createInteractiveTuiReference(getTui) {
176
+ return new Proxy({}, {
177
+ get: (_target, property) => {
178
+ const tui = getTui();
179
+ const value = Reflect.get(tui, property, tui);
180
+ if (typeof value !== "function")
181
+ return value;
182
+ return (...args) => {
183
+ const tui = getTui();
184
+ const method = Reflect.get(tui, property, tui);
185
+ if (typeof method !== "function")
186
+ throw new TypeError(`TUI property ${String(property)} is not callable`);
187
+ return Reflect.apply(method, tui, args);
188
+ };
189
+ },
190
+ set: (_target, property, value) => {
191
+ const tui = getTui();
192
+ return Reflect.set(tui, property, value, tui);
193
+ },
194
+ has: (_target, property) => Reflect.has(getTui(), property),
195
+ getPrototypeOf: () => Reflect.getPrototypeOf(getTui()),
196
+ });
197
+ }
164
198
  export class InteractiveMode {
165
- runtimeHost;
166
- ui;
167
- coalescingTerminal;
168
- agentRunActive = false;
169
- loadedResourcesContainer;
170
- chatContainer;
171
- pendingMessagesContainer;
172
- statusContainer;
173
- defaultEditor;
174
- editor;
175
- editorComponentFactory;
176
- autocompleteProvider;
177
- autocompleteProviderWrappers = [];
178
- fdPath;
179
- editorContainer;
180
- footer;
181
- footerDataProvider;
182
- // Stored so the same manager can be injected into custom editors, selectors, and extension UI.
183
- keybindings;
184
- version;
185
- isInitialized = false;
186
- onInputCallback;
187
- pendingUserInputs = [];
188
- activeStatusIndicator = undefined;
189
- activeSelector = null;
190
- activeSelectorCleanup = null;
191
- idleStatus = new IdleStatus();
192
- workingMessage = undefined;
193
- workingVisible = true;
194
- workingIndicatorOptions = undefined;
195
- defaultWorkingMessage = "Working...";
196
- defaultHiddenThinkingLabel = "Thinking...";
197
- hiddenThinkingLabel = this.defaultHiddenThinkingLabel;
198
- lastSigintTime = 0;
199
- lastEscapeTime = 0;
200
- changelogMarkdown = undefined;
201
- startupNoticesShown = false;
202
- anthropicSubscriptionWarningShown = false;
203
- // Status line tracking (for mutating immediately-sequential status updates)
204
- lastStatusSpacer = undefined;
205
- lastStatusText = undefined;
206
- // Streaming message tracking
207
- streamingComponent = undefined;
208
- streamingMessage = undefined;
209
- // Tool execution tracking: toolCallId -> component
210
- pendingTools = new Map();
211
- // Tool output expansion state
212
- toolOutputExpanded = false;
213
- // Thinking block visibility state
214
- hideThinkingBlock = false;
215
- outputPad = 1;
216
- // Skill commands: command name -> skill file path
217
- skillCommands = new Map();
218
- // Agent subscription unsubscribe function
219
- unsubscribe;
220
- signalCleanupHandlers = [];
221
- // Track if editor is in bash mode (text starts with !)
222
- isBashMode = false;
223
- // Track current bash execution component
224
- bashComponent = undefined;
225
- // Track pending bash components (shown in pending area, moved to chat on submit)
226
- pendingBashComponents = [];
227
- // Auto-compaction state
228
- autoCompactionEscapeHandler;
229
- // Auto-retry state
230
- retryEscapeHandler;
231
- // Messages queued while compaction is running
232
- compactionQueuedMessages = [];
233
- // Shutdown state
234
- shutdownRequested = false;
235
- // Extension UI state
236
- extensionSelector = undefined;
237
- extensionInput = undefined;
238
- extensionEditor = undefined;
239
- extensionTerminalInputUnsubscribers = new Set();
240
- // Extension widgets (components rendered above/below the editor)
241
- extensionWidgetsAbove = new Map();
242
- extensionWidgetsBelow = new Map();
243
- widgetContainerAbove;
244
- widgetContainerBelow;
245
- // Custom footer from extension (undefined = use built-in footer)
246
- customFooter = undefined;
247
- // Header container that holds the built-in or custom header
248
- headerContainer;
249
- // Built-in header (logo + keybinding hints + changelog)
250
- builtInHeader = undefined;
251
- // Custom header from extension (undefined = use built-in header)
252
- customHeader = undefined;
253
- options;
254
- autoTrustOnReloadCwd;
255
- themeController;
256
199
  // Convenience accessors
257
200
  get session() {
258
201
  return this.runtimeHost.session;
@@ -267,8 +210,85 @@ export class InteractiveMode {
267
210
  return this.session.settingsManager;
268
211
  }
269
212
  constructor(runtimeHost, options = {}) {
213
+ // Input listeners live on the TUI renderer instance, which switchTuiMode
214
+ // replaces; this pair tracks the scrollback-preservation listener so it
215
+ // can be unsubscribed from the outgoing renderer and re-registered on the
216
+ // incoming one without duplicates.
217
+ this.scrollbackPreservationInputHandler = () => {
218
+ if (!this.agentRunActive)
219
+ this.coalescingTerminal.setScrollbackPreservation(false);
220
+ return undefined;
221
+ };
222
+ this.agentRunActive = false;
223
+ this.autocompleteProviderWrappers = [];
224
+ this.isInitialized = false;
225
+ this.pendingUserInputs = [];
226
+ this.activeStatusIndicator = undefined;
227
+ this.idleStatus = new IdleStatus();
228
+ this.workingMessage = undefined;
229
+ this.workingVisible = true;
230
+ this.workingIndicatorOptions = undefined;
231
+ this.defaultWorkingMessage = "Working...";
232
+ this.defaultHiddenThinkingLabel = "Thinking...";
233
+ this.hiddenThinkingLabel = this.defaultHiddenThinkingLabel;
234
+ this.lastSigintTime = 0;
235
+ this.lastEscapeTime = 0;
236
+ this.changelogMarkdown = undefined;
237
+ this.startupNoticesShown = false;
238
+ this.anthropicSubscriptionWarningShown = false;
239
+ // Status line tracking (for mutating immediately-sequential status updates)
240
+ this.lastStatusSpacer = undefined;
241
+ this.lastStatusText = undefined;
242
+ // Streaming message tracking
243
+ this.streamingComponent = undefined;
244
+ this.streamingMessage = undefined;
245
+ // Tool execution tracking: toolCallId -> component
246
+ this.pendingTools = new Map();
247
+ // Tool output expansion state
248
+ this.toolOutputExpanded = false;
249
+ // Thinking block visibility state
250
+ this.hideThinkingBlock = false;
251
+ this.outputPad = 1;
252
+ this.mermaidMarkdownTransformer = createMermaidMarkdownTransformer({
253
+ getMode: () => this.settingsManager.getMermaidRenderingMode(),
254
+ theme,
255
+ });
256
+ // Skill commands: command name -> skill file path
257
+ this.skillCommands = new Map();
258
+ this.signalCleanupHandlers = [];
259
+ // Track if editor is in bash mode (text starts with !)
260
+ this.isBashMode = false;
261
+ // Track current bash execution component
262
+ this.bashComponent = undefined;
263
+ // Track pending bash components (shown in pending area, moved to chat on submit)
264
+ this.pendingBashComponents = [];
265
+ // Messages queued while compaction is running
266
+ this.compactionQueuedMessages = [];
267
+ // Shutdown state
268
+ this.shutdownRequested = false;
269
+ // Extension UI state
270
+ this.extensionSelector = undefined;
271
+ this.extensionInput = undefined;
272
+ this.extensionEditor = undefined;
273
+ this.extensionTerminalInputSubscriptions = new Set();
274
+ // Extension widgets (components rendered above/below the editor)
275
+ this.extensionWidgetsAbove = new Map();
276
+ this.extensionWidgetsBelow = new Map();
277
+ // Custom footer from extension (undefined = use built-in footer)
278
+ this.customFooter = undefined;
279
+ // Built-in header (logo + keybinding hints + changelog)
280
+ this.builtInHeader = undefined;
281
+ // Custom header from extension (undefined = use built-in header)
282
+ this.customHeader = undefined;
283
+ /**
284
+ * Gracefully shutdown the agent.
285
+ * Stops the TUI before emitting shutdown events so extension UI cleanup cannot
286
+ * repaint the final frame while the process is exiting.
287
+ */
288
+ this.isShuttingDown = false;
270
289
  this.runtimeHost = runtimeHost;
271
- this.options = options;
290
+ const tuiMode = options.tuiMode ?? this.settingsManager.getTuiMode();
291
+ this.options = { ...options, tuiMode };
272
292
  this.autoTrustOnReloadCwd = options.autoTrustOnReloadCwd;
273
293
  this.runtimeHost.setBeforeSessionInvalidate(() => {
274
294
  this.resetExtensionUI();
@@ -279,7 +299,13 @@ export class InteractiveMode {
279
299
  this.version = VERSION;
280
300
  const terminal = new CoalescingTerminal();
281
301
  this.coalescingTerminal = terminal;
282
- this.ui = new TUI(terminal, this.settingsManager.getShowHardwareCursor(), getAgentDir());
302
+ this.renderer = createInteractiveTui({
303
+ tuiMode,
304
+ showHardwareCursor: this.settingsManager.getShowHardwareCursor(),
305
+ logDirectory: getAgentDir(),
306
+ terminal,
307
+ });
308
+ this.ui = createInteractiveTuiReference(() => this.renderer);
283
309
  // Lets full-redraw rewrites scroll grown content into scrollback
284
310
  // instead of dropping the lines pushed above the screen.
285
311
  // previousViewportTop is TS-private but a plain runtime field, and
@@ -291,15 +317,17 @@ export class InteractiveMode {
291
317
  // next input after the run settles: post-run reflow frames must not
292
318
  // yank a reader who is still scrolled up, but once the user acts they
293
319
  // are back at the bottom and upstream's clean wipe-and-replay wins.
294
- this.ui.addInputListener(() => {
295
- if (!this.agentRunActive)
296
- this.coalescingTerminal.setScrollbackPreservation(false);
297
- return undefined;
298
- });
320
+ // The listener is registered on the initial renderer and rebound by
321
+ // switchTuiMode whenever the renderer is replaced.
322
+ this.scrollbackPreservationInputUnsubscribe = this.ui.addInputListener(this.scrollbackPreservationInputHandler);
299
323
  this.ui.setClearOnShrink(this.settingsManager.getClearOnShrink());
300
324
  this.headerContainer = new Container();
301
325
  this.loadedResourcesContainer = new Container();
302
326
  this.chatContainer = new Container();
327
+ this.documentContainer = new Container();
328
+ this.documentContainer.addChild(this.headerContainer);
329
+ this.documentContainer.addChild(this.loadedResourcesContainer);
330
+ this.documentContainer.addChild(this.chatContainer);
303
331
  this.pendingMessagesContainer = new Container();
304
332
  this.statusContainer = new Container();
305
333
  this.widgetContainerAbove = new Container();
@@ -318,6 +346,8 @@ export class InteractiveMode {
318
346
  this.footerDataProvider = new FooterDataProvider(this.sessionManager.getCwd());
319
347
  this.footer = new FooterComponent(this.session, this.footerDataProvider);
320
348
  this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled);
349
+ this.footerContainer = new Container();
350
+ this.footerContainer.addChild(this.footer);
321
351
  // Load hide thinking block setting
322
352
  this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
323
353
  this.outputPad = this.settingsManager.getOutputPad();
@@ -373,11 +403,10 @@ export class InteractiveMode {
373
403
  }));
374
404
  const modelCommand = slashCommands.find((command) => command.name === "model");
375
405
  if (modelCommand) {
376
- modelCommand.getArgumentCompletions = async (prefix) => {
377
- // Get available models (scoped or from registry)
406
+ modelCommand.getArgumentCompletions = (prefix) => {
378
407
  const models = this.session.scopedModels.length > 0
379
408
  ? this.session.scopedModels.map((s) => s.model)
380
- : await this.session.modelRuntime.getAvailable();
409
+ : this.session.modelRuntime.getAvailableSnapshot();
381
410
  if (models.length === 0)
382
411
  return null;
383
412
  // Create items with provider/id format
@@ -478,6 +507,75 @@ export class InteractiveMode {
478
507
  }
479
508
  this.chatContainer.addChild(new DynamicBorder());
480
509
  }
510
+ mountInteractiveTui(tui, components) {
511
+ for (const component of components)
512
+ tui.addChild(component);
513
+ if (TuiLayouts.isViewportTUI(tui)) {
514
+ if (!this.fullscreenLayoutRoot)
515
+ throw new Error("Fullscreen layout is not initialized");
516
+ tui.setLayoutRoot(this.fullscreenLayoutRoot);
517
+ }
518
+ }
519
+ stopInteractiveTui() {
520
+ if (this.renderer.mode === "fullscreen") {
521
+ while (this.renderer.hasOverlayEntries)
522
+ this.renderer.hideOverlay();
523
+ this.switchTuiMode("regular", false, false);
524
+ this.renderer.renderNow();
525
+ }
526
+ this.ui.stop();
527
+ }
528
+ switchTuiMode(mode, restoreProgress = true, startRenderer = true) {
529
+ const previousUi = this.renderer;
530
+ if (mode === previousUi.mode)
531
+ return true;
532
+ if (previousUi.hasOverlayEntries)
533
+ return false;
534
+ const components = [...previousUi.children];
535
+ const focus = previousUi.getFocusedComponent();
536
+ const terminal = previousUi.terminal;
537
+ const showHardwareCursor = previousUi.getShowHardwareCursor();
538
+ const clearOnShrink = previousUi.getClearOnShrink();
539
+ const onDebug = previousUi.onDebug;
540
+ if (previousUi instanceof TuiMainScreen) {
541
+ this.mainScreenRenderState = previousUi.captureRenderState();
542
+ }
543
+ previousUi.stop({ preserveScreen: true });
544
+ previousUi.setFocus(null);
545
+ previousUi.clear();
546
+ if (TuiLayouts.isViewportTUI(previousUi))
547
+ previousUi.setLayoutRoot(undefined);
548
+ const nextUi = createInteractiveTui({
549
+ tuiMode: mode,
550
+ showHardwareCursor,
551
+ logDirectory: getAgentDir(),
552
+ terminal,
553
+ });
554
+ nextUi.setClearOnShrink(clearOnShrink);
555
+ nextUi.onDebug = onDebug;
556
+ if (nextUi instanceof TuiMainScreen && this.mainScreenRenderState) {
557
+ nextUi.restoreRenderState(this.mainScreenRenderState);
558
+ }
559
+ this.renderer = nextUi;
560
+ // Renderers own their input-listener sets; move the preservation
561
+ // listener onto the incoming renderer before anything else touches it.
562
+ this.rebindScrollbackPreservationInputListener();
563
+ this.options.tuiMode = mode;
564
+ this.mountInteractiveTui(nextUi, components);
565
+ nextUi.invalidate();
566
+ nextUi.setFocus(focus);
567
+ if (!startRenderer)
568
+ return true;
569
+ nextUi.start();
570
+ this.themeController.rebindTui();
571
+ this.rebindExtensionTerminalInputListeners();
572
+ if (restoreProgress &&
573
+ this.settingsManager.getShowTerminalProgress() &&
574
+ (this.session.isStreaming || this.session.isCompacting)) {
575
+ terminal.setProgress(true);
576
+ }
577
+ return true;
578
+ }
481
579
  async init() {
482
580
  if (this.isInitialized)
483
581
  return;
@@ -501,18 +599,36 @@ export class InteractiveMode {
501
599
  : "";
502
600
  console.log(theme.fg("dim", `Model scope: ${modelList}${cycleHint}`));
503
601
  }
504
- // Add header container as first child. Populate it after applying theme settings.
505
- // Keep loaded resources before chat so restored session messages never precede them.
506
- this.ui.addChild(this.headerContainer);
507
- this.ui.addChild(this.loadedResourcesContainer);
508
- this.ui.addChild(this.chatContainer);
509
- this.ui.addChild(this.pendingMessagesContainer);
510
- this.ui.addChild(this.statusContainer);
602
+ // Keep one component tree and remount it when changing renderers.
511
603
  this.renderWidgets(); // Initialize with default spacer
512
- this.ui.addChild(this.widgetContainerAbove);
513
- this.ui.addChild(this.editorContainer);
514
- this.ui.addChild(this.widgetContainerBelow);
515
- this.ui.addChild(this.footer);
604
+ this.transcriptScrollView = new TuiLayouts.ScrollView(this.documentContainer, {
605
+ follow: "end",
606
+ primary: true,
607
+ overscroll: "chain",
608
+ scrollbar: this.settingsManager.getFullscreenScrollbar(),
609
+ scrollbarStyle: (text) => theme.bg("scrollbarThumb", text),
610
+ });
611
+ const dock = new TuiLayouts.VStack([
612
+ { component: this.pendingMessagesContainer, shrink: 1, minSize: 0 },
613
+ { component: this.statusContainer, shrink: 1, minSize: 0 },
614
+ { component: this.widgetContainerAbove, shrink: 1, minSize: 0 },
615
+ { component: this.editorContainer, shrink: 1, minSize: 3 },
616
+ { component: this.widgetContainerBelow, shrink: 1, minSize: 0 },
617
+ { component: this.footerContainer, shrink: 1, minSize: 1 },
618
+ ]);
619
+ this.fullscreenLayoutRoot = new TuiLayouts.VStack([
620
+ { component: this.transcriptScrollView, basis: 0, grow: 1, shrink: 1, minSize: 1 },
621
+ { component: dock, basis: "auto", grow: 0, shrink: 1, minSize: 1 },
622
+ ]);
623
+ this.mountInteractiveTui(this.renderer, [
624
+ this.documentContainer,
625
+ this.pendingMessagesContainer,
626
+ this.statusContainer,
627
+ this.widgetContainerAbove,
628
+ this.editorContainer,
629
+ this.widgetContainerBelow,
630
+ this.footerContainer,
631
+ ]);
516
632
  this.ui.setFocus(this.editor);
517
633
  this.setupKeyHandlers();
518
634
  this.setupEditorSubmitHandler();
@@ -604,10 +720,13 @@ export class InteractiveMode {
604
720
  async run() {
605
721
  await this.init();
606
722
  if (!process.env.PI_OFFLINE) {
723
+ const controller = new AbortController();
724
+ const timeout = setTimeout(() => controller.abort(), 15_000);
607
725
  void this.session.modelRuntime
608
- .refresh()
726
+ .refresh({ signal: controller.signal })
609
727
  .then(() => this.updateAvailableProviderCount())
610
- .catch(() => { });
728
+ .catch(() => { })
729
+ .finally(() => clearTimeout(timeout));
611
730
  }
612
731
  // Start version check asynchronously
613
732
  checkForNewPiVersion(this.version).then((newRelease) => {
@@ -1110,7 +1229,12 @@ export class InteractiveMode {
1110
1229
  }
1111
1230
  }
1112
1231
  if (showListing) {
1113
- const contextFiles = this.session.resourceLoader.getAgentsFiles().agentsFiles;
1232
+ const systemPromptSource = this.session.resourceLoader.getSystemPromptSource();
1233
+ const contextFiles = [
1234
+ ...(systemPromptSource ? [systemPromptSource] : []),
1235
+ ...this.session.resourceLoader.getAppendSystemPromptSources(),
1236
+ ...this.session.resourceLoader.getAgentsFiles().agentsFiles,
1237
+ ];
1114
1238
  if (contextFiles.length > 0) {
1115
1239
  this.loadedResourcesContainer.addChild(new Spacer(1));
1116
1240
  const contextList = contextFiles
@@ -1254,6 +1378,7 @@ export class InteractiveMode {
1254
1378
  if (result.cancelled) {
1255
1379
  return { cancelled: true };
1256
1380
  }
1381
+ this.coalescingTerminal.passNextFullRedraw();
1257
1382
  this.clearChat();
1258
1383
  this.renderInitialMessages();
1259
1384
  if (result.editorText && !this.editor.getText().trim()) {
@@ -1287,8 +1412,12 @@ export class InteractiveMode {
1287
1412
  this.showLoadedResources({ force: false, showDiagnosticsWhenQuiet: true });
1288
1413
  this.showStartupNoticesIfNeeded();
1289
1414
  }
1415
+ applyFullscreenScrollbarSetting() {
1416
+ this.transcriptScrollView?.setScrollbar(this.settingsManager.getFullscreenScrollbar());
1417
+ }
1290
1418
  applyRuntimeSettings() {
1291
1419
  configureHttpDispatcher(this.settingsManager.getHttpIdleTimeoutMs());
1420
+ this.applyFullscreenScrollbarSetting();
1292
1421
  this.footer.setSession(this.session);
1293
1422
  this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled);
1294
1423
  this.footerDataProvider.setCwd(this.sessionManager.getCwd());
@@ -1310,16 +1439,19 @@ export class InteractiveMode {
1310
1439
  }
1311
1440
  }
1312
1441
  async rebindCurrentSession(options = {}) {
1442
+ const session = this.session;
1313
1443
  this.unsubscribe?.();
1314
1444
  this.unsubscribe = undefined;
1315
1445
  this.applyRuntimeSettings();
1316
1446
  if (options.renderBeforeBind) {
1317
1447
  this.renderCurrentSessionState();
1318
1448
  this.subscribeToAgent();
1319
- await this.bindCurrentSessionExtensions();
1320
1449
  }
1321
- else {
1322
- await this.bindCurrentSessionExtensions();
1450
+ await this.bindCurrentSessionExtensions();
1451
+ if (this.session !== session) {
1452
+ return;
1453
+ }
1454
+ if (!options.renderBeforeBind) {
1323
1455
  this.subscribeToAgent();
1324
1456
  }
1325
1457
  await this.updateAvailableProviderCount();
@@ -1354,6 +1486,10 @@ export class InteractiveMode {
1354
1486
  this.pendingTools.clear();
1355
1487
  }
1356
1488
  renderCurrentSessionState() {
1489
+ // Resuming, forking, or starting a new session rebuilds the transcript
1490
+ // at the user's request; the rebuild's full redraw keeps the clean
1491
+ // wipe-and-replay even if preservation is still windowed on.
1492
+ this.coalescingTerminal.passNextFullRedraw();
1357
1493
  this.loadedResourcesContainer.clear();
1358
1494
  this.clearChat();
1359
1495
  this.pendingMessagesContainer.clear();
@@ -1397,6 +1533,9 @@ export class InteractiveMode {
1397
1533
  }
1398
1534
  this.chatContainer.addChild(component);
1399
1535
  }
1536
+ getMarkdownTransformers() {
1537
+ return [this.mermaidMarkdownTransformer, ...this.session.extensionRunner.getMarkdownTransformers()];
1538
+ }
1400
1539
  /**
1401
1540
  * Set up keyboard shortcuts registered by extensions.
1402
1541
  */
@@ -1413,6 +1552,7 @@ export class InteractiveMode {
1413
1552
  sessionManager: this.sessionManager,
1414
1553
  modelRegistry: extensionRunner.getModelRegistry(),
1415
1554
  model: this.session.model,
1555
+ scopedModels: this.session.scopedModels,
1416
1556
  thinkingLevel: this.session.thinkingLevel,
1417
1557
  isIdle: () => this.session.isIdle,
1418
1558
  isProjectTrusted: () => this.settingsManager.isProjectTrusted(),
@@ -1475,7 +1615,7 @@ export class InteractiveMode {
1475
1615
  this.activeStatusIndicator?.dispose();
1476
1616
  this.activeStatusIndicator = undefined;
1477
1617
  this.statusContainer.clear();
1478
- if (hadActiveStatusIndicator && this.ui.getClearOnShrink()) {
1618
+ if (hadActiveStatusIndicator && this.options.tuiMode === "regular" && this.ui.getClearOnShrink()) {
1479
1619
  this.statusContainer.addChild(this.idleStatus);
1480
1620
  }
1481
1621
  }
@@ -1589,7 +1729,7 @@ export class InteractiveMode {
1589
1729
  this.setHiddenThinkingLabel();
1590
1730
  }
1591
1731
  // Maximum total widget lines to prevent viewport overflow
1592
- static MAX_WIDGET_LINES = 10;
1732
+ static { this.MAX_WIDGET_LINES = 10; }
1593
1733
  /**
1594
1734
  * Render all extension widgets to the widget container.
1595
1735
  */
@@ -1623,22 +1763,16 @@ export class InteractiveMode {
1623
1763
  if (this.customFooter?.dispose) {
1624
1764
  this.customFooter.dispose();
1625
1765
  }
1626
- // Remove current footer from UI
1627
- if (this.customFooter) {
1628
- this.ui.removeChild(this.customFooter);
1629
- }
1630
- else {
1631
- this.ui.removeChild(this.footer);
1632
- }
1766
+ this.footerContainer.clear();
1633
1767
  if (factory) {
1634
1768
  // Create and add custom footer, passing the data provider
1635
1769
  this.customFooter = factory(this.ui, theme, this.footerDataProvider);
1636
- this.ui.addChild(this.customFooter);
1770
+ this.footerContainer.addChild(this.customFooter);
1637
1771
  }
1638
1772
  else {
1639
1773
  // Restore built-in footer
1640
1774
  this.customFooter = undefined;
1641
- this.ui.addChild(this.footer);
1775
+ this.footerContainer.addChild(this.footer);
1642
1776
  }
1643
1777
  this.ui.requestRender();
1644
1778
  }
@@ -1684,18 +1818,27 @@ export class InteractiveMode {
1684
1818
  this.ui.requestRender();
1685
1819
  }
1686
1820
  addExtensionTerminalInputListener(handler) {
1687
- const unsubscribe = this.ui.addInputListener(handler);
1688
- this.extensionTerminalInputUnsubscribers.add(unsubscribe);
1821
+ const subscription = { handler, unsubscribe: this.ui.addInputListener(handler) };
1822
+ this.extensionTerminalInputSubscriptions.add(subscription);
1689
1823
  return () => {
1690
- unsubscribe();
1691
- this.extensionTerminalInputUnsubscribers.delete(unsubscribe);
1824
+ subscription.unsubscribe();
1825
+ this.extensionTerminalInputSubscriptions.delete(subscription);
1692
1826
  };
1693
1827
  }
1694
- clearExtensionTerminalInputListeners() {
1695
- for (const unsubscribe of this.extensionTerminalInputUnsubscribers) {
1696
- unsubscribe();
1828
+ rebindScrollbackPreservationInputListener() {
1829
+ this.scrollbackPreservationInputUnsubscribe?.();
1830
+ this.scrollbackPreservationInputUnsubscribe = this.ui.addInputListener(this.scrollbackPreservationInputHandler);
1831
+ }
1832
+ rebindExtensionTerminalInputListeners() {
1833
+ for (const subscription of this.extensionTerminalInputSubscriptions) {
1834
+ subscription.unsubscribe();
1835
+ subscription.unsubscribe = this.ui.addInputListener(subscription.handler);
1697
1836
  }
1698
- this.extensionTerminalInputUnsubscribers.clear();
1837
+ }
1838
+ clearExtensionTerminalInputListeners() {
1839
+ for (const subscription of this.extensionTerminalInputSubscriptions)
1840
+ subscription.unsubscribe();
1841
+ this.extensionTerminalInputSubscriptions.clear();
1699
1842
  }
1700
1843
  /**
1701
1844
  * Create the ExtensionUIContext for extensions.
@@ -1796,6 +1939,7 @@ export class InteractiveMode {
1796
1939
  cancelHint: opts?.cancelHint,
1797
1940
  onToggleToolsExpanded: () => this.toggleToolOutputExpansion(),
1798
1941
  });
1942
+ this.disposeActiveSelector();
1799
1943
  this.editorContainer.clear();
1800
1944
  this.editorContainer.addChild(this.extensionSelector);
1801
1945
  this.ui.setFocus(this.extensionSelector);
@@ -1817,7 +1961,9 @@ export class InteractiveMode {
1817
1961
  * Show a confirmation dialog for extensions.
1818
1962
  */
1819
1963
  async showExtensionConfirm(title, message, opts) {
1820
- const result = await this.showExtensionSelector(`${title}\n${message}`, ["Yes", "No"], opts);
1964
+ // The message is context, not a heading: render it as the selector's muted
1965
+ // subtitle instead of folding it into the accent-bold title.
1966
+ const result = await this.showExtensionSelector(title, ["Yes", "No"], { ...opts, subtitle: message });
1821
1967
  return result === "Yes";
1822
1968
  }
1823
1969
  async promptForMissingSessionCwd(error) {
@@ -1847,6 +1993,7 @@ export class InteractiveMode {
1847
1993
  this.hideExtensionInput();
1848
1994
  resolve(undefined);
1849
1995
  }, { tui: this.ui, timeout: opts?.timeout });
1996
+ this.disposeActiveSelector();
1850
1997
  this.editorContainer.clear();
1851
1998
  this.editorContainer.addChild(this.extensionInput);
1852
1999
  this.ui.setFocus(this.extensionInput);
@@ -1876,6 +2023,7 @@ export class InteractiveMode {
1876
2023
  this.hideExtensionEditor();
1877
2024
  resolve(undefined);
1878
2025
  }, undefined, this.settingsManager.getExternalEditorCommand());
2026
+ this.disposeActiveSelector();
1879
2027
  this.editorContainer.clear();
1880
2028
  this.editorContainer.addChild(this.extensionEditor);
1881
2029
  this.ui.setFocus(this.extensionEditor);
@@ -1900,6 +2048,7 @@ export class InteractiveMode {
1900
2048
  this.editorComponentFactory = factory;
1901
2049
  // Save text from current editor before switching
1902
2050
  const currentText = this.editor.getText();
2051
+ this.disposeActiveSelector();
1903
2052
  this.editorContainer.clear();
1904
2053
  if (factory) {
1905
2054
  // Create the custom editor with tui, theme, and keybindings
@@ -1916,6 +2065,9 @@ export class InteractiveMode {
1916
2065
  if (newEditor.setPaddingX !== undefined) {
1917
2066
  newEditor.setPaddingX(this.defaultEditor.getPaddingX());
1918
2067
  }
2068
+ if (newEditor.setAutocompleteMaxVisible !== undefined) {
2069
+ newEditor.setAutocompleteMaxVisible(this.defaultEditor.getAutocompleteMaxVisible());
2070
+ }
1919
2071
  // Set autocomplete if supported
1920
2072
  if (newEditor.setAutocompleteProvider && this.autocompleteProvider) {
1921
2073
  newEditor.setAutocompleteProvider(this.autocompleteProvider);
@@ -2020,6 +2172,7 @@ export class InteractiveMode {
2020
2172
  options?.onHandle?.(handle);
2021
2173
  }
2022
2174
  else {
2175
+ this.disposeActiveSelector();
2023
2176
  this.editorContainer.clear();
2024
2177
  this.editorContainer.addChild(component);
2025
2178
  this.ui.setFocus(component);
@@ -2106,7 +2259,7 @@ export class InteractiveMode {
2106
2259
  this.defaultEditor.onAction("app.tools.expand", () => this.toggleToolOutputExpansion());
2107
2260
  this.defaultEditor.onAction("app.thinking.toggle", () => this.toggleThinkingBlockVisibility());
2108
2261
  this.defaultEditor.onAction("app.editor.external", () => void this.handleOpenExternalEditor());
2109
- this.defaultEditor.onAction("app.message.copy", () => void this.handleCopyCommand());
2262
+ this.defaultEditor.onAction("app.message.copy", () => void this.handleCopyCommand({ flashConfirmation: true }));
2110
2263
  this.defaultEditor.onAction("app.message.followUp", () => this.handleFollowUp());
2111
2264
  this.defaultEditor.onAction("app.message.dequeue", () => this.handleDequeue());
2112
2265
  this.defaultEditor.onAction("app.session.new", () => this.handleClearCommand());
@@ -2407,17 +2560,17 @@ export class InteractiveMode {
2407
2560
  this.ui.requestRender();
2408
2561
  }
2409
2562
  else if (event.message.role === "assistant") {
2410
- this.streamingComponent = new AssistantMessageComponent(undefined, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel, this.outputPad);
2563
+ this.streamingComponent = new AssistantMessageComponent(undefined, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel, this.outputPad, this.getMarkdownTransformers());
2411
2564
  this.streamingMessage = event.message;
2412
2565
  this.chatContainer.addChild(this.streamingComponent);
2413
- this.streamingComponent.updateContent(this.streamingMessage);
2566
+ this.streamingComponent.updateContent(this.streamingMessage, true);
2414
2567
  this.ui.requestRender();
2415
2568
  }
2416
2569
  break;
2417
2570
  case "message_update":
2418
2571
  if (this.streamingComponent && event.message.role === "assistant") {
2419
2572
  this.streamingMessage = event.message;
2420
- this.streamingComponent.updateContent(this.streamingMessage);
2573
+ this.streamingComponent.updateContent(this.streamingMessage, true);
2421
2574
  for (const content of this.streamingMessage.content) {
2422
2575
  if (content.type === "toolCall") {
2423
2576
  if (!this.pendingTools.has(content.id)) {
@@ -2450,7 +2603,7 @@ export class InteractiveMode {
2450
2603
  : "Operation aborted";
2451
2604
  this.streamingMessage.errorMessage = errorMessage;
2452
2605
  }
2453
- this.streamingComponent.updateContent(this.streamingMessage);
2606
+ this.streamingComponent.updateContent(this.streamingMessage, false);
2454
2607
  if (this.streamingMessage.stopReason === "aborted" || this.streamingMessage.stopReason === "error") {
2455
2608
  if (!errorMessage) {
2456
2609
  errorMessage = this.streamingMessage.errorMessage || "Error";
@@ -2726,12 +2879,12 @@ export class InteractiveMode {
2726
2879
  // Render user message separately if present
2727
2880
  if (skillBlock.userMessage) {
2728
2881
  this.chatContainer.addChild(new Spacer(1));
2729
- const userComponent = new UserMessageComponent(skillBlock.userMessage, this.getMarkdownThemeWithSettings(), this.outputPad);
2882
+ const userComponent = new UserMessageComponent(skillBlock.userMessage, this.getMarkdownThemeWithSettings(), this.outputPad, this.getMarkdownTransformers());
2730
2883
  this.chatContainer.addChild(userComponent);
2731
2884
  }
2732
2885
  }
2733
2886
  else {
2734
- const userComponent = new UserMessageComponent(textContent, this.getMarkdownThemeWithSettings(), this.outputPad);
2887
+ const userComponent = new UserMessageComponent(textContent, this.getMarkdownThemeWithSettings(), this.outputPad, this.getMarkdownTransformers());
2735
2888
  this.chatContainer.addChild(userComponent);
2736
2889
  }
2737
2890
  if (options?.populateHistory) {
@@ -2741,7 +2894,7 @@ export class InteractiveMode {
2741
2894
  break;
2742
2895
  }
2743
2896
  case "assistant": {
2744
- const assistantComponent = new AssistantMessageComponent(message, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel, this.outputPad);
2897
+ const assistantComponent = new AssistantMessageComponent(message, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel, this.outputPad, this.getMarkdownTransformers());
2745
2898
  this.chatContainer.addChild(assistantComponent);
2746
2899
  break;
2747
2900
  }
@@ -2924,12 +3077,6 @@ export class InteractiveMode {
2924
3077
  // Only called when editor is empty (enforced by CustomEditor)
2925
3078
  void this.shutdown();
2926
3079
  }
2927
- /**
2928
- * Gracefully shutdown the agent.
2929
- * Stops the TUI before emitting shutdown events so extension UI cleanup cannot
2930
- * repaint the final frame while the process is exiting.
2931
- */
2932
- isShuttingDown = false;
2933
3080
  async shutdown(options) {
2934
3081
  if (this.isShuttingDown)
2935
3082
  return;
@@ -3171,6 +3318,8 @@ export class InteractiveMode {
3171
3318
  this.setToolsExpanded(!this.toolOutputExpanded);
3172
3319
  }
3173
3320
  setToolsExpanded(expanded) {
3321
+ if (expanded === this.toolOutputExpanded)
3322
+ return;
3174
3323
  this.toolOutputExpanded = expanded;
3175
3324
  // An explicit toggle prefers upstream's clean wipe-and-replay even
3176
3325
  // mid-run: the user just pressed the key, so they are interacting at
@@ -3188,7 +3337,7 @@ export class InteractiveMode {
3188
3337
  }
3189
3338
  }
3190
3339
  }
3191
- this.ui.requestRender();
3340
+ this.showStatus(`Tool output: ${expanded ? "expanded" : "collapsed"}`);
3192
3341
  }
3193
3342
  toggleThinkingBlockVisibility() {
3194
3343
  this.hideThinkingBlock = !this.hideThinkingBlock;
@@ -3233,7 +3382,7 @@ export class InteractiveMode {
3233
3382
  }
3234
3383
  showError(errorMessage) {
3235
3384
  this.chatContainer.addChild(new Spacer(1));
3236
- this.chatContainer.addChild(new Text(theme.fg("error", `Error: ${errorMessage}`), 1, 0));
3385
+ this.chatContainer.addChild(new Text(theme.fg("error", `Error: ${errorMessage}`), this.outputPad, 0));
3237
3386
  this.ui.requestRender();
3238
3387
  }
3239
3388
  showWarning(warningMessage) {
@@ -3439,52 +3588,50 @@ export class InteractiveMode {
3439
3588
  // =========================================================================
3440
3589
  // Selectors
3441
3590
  // =========================================================================
3591
+ disposeActiveSelector() {
3592
+ const dispose = this.activeSelectorDispose;
3593
+ this.activeSelectorToken = undefined;
3594
+ this.activeSelectorDispose = undefined;
3595
+ dispose?.();
3596
+ }
3442
3597
  /**
3443
3598
  * Shows a selector component in place of the editor.
3444
3599
  * @param create Factory that receives a `done` callback and returns the component and focus target
3445
3600
  */
3446
3601
  showSelector(create) {
3447
- this.activeSelectorCleanup?.();
3448
- this.activeSelectorCleanup = null;
3449
- this.activeSelector = null;
3450
- let selector;
3602
+ const token = {};
3603
+ let dispose;
3451
3604
  let disposed = false;
3452
- let closed = false;
3453
- const dispose = () => {
3454
- if (disposed || !selector)
3605
+ const disposeOnce = () => {
3606
+ if (disposed)
3455
3607
  return;
3456
3608
  disposed = true;
3457
- selector.dispose?.();
3609
+ dispose?.();
3458
3610
  };
3459
3611
  const done = () => {
3460
- if (closed)
3612
+ disposeOnce();
3613
+ if (this.activeSelectorToken !== token)
3461
3614
  return;
3462
- closed = true;
3463
- dispose();
3464
- if (!selector || this.activeSelector === selector) {
3465
- this.activeSelector = null;
3466
- this.activeSelectorCleanup = null;
3467
- this.editorContainer.clear();
3468
- this.editorContainer.addChild(this.editor);
3469
- this.ui.setFocus(this.editor);
3470
- }
3615
+ this.activeSelectorToken = undefined;
3616
+ this.activeSelectorDispose = undefined;
3617
+ this.editorContainer.clear();
3618
+ this.editorContainer.addChild(this.editor);
3619
+ this.ui.setFocus(this.editor);
3471
3620
  };
3472
3621
  const created = create(done);
3473
- selector = created.component;
3474
- if (closed) {
3475
- dispose();
3476
- return;
3477
- }
3478
- this.activeSelector = selector;
3479
- this.activeSelectorCleanup = dispose;
3622
+ dispose = created.dispose;
3623
+ this.disposeActiveSelector();
3624
+ this.activeSelectorToken = token;
3625
+ this.activeSelectorDispose = disposeOnce;
3480
3626
  this.editorContainer.clear();
3481
- this.editorContainer.addChild(selector);
3627
+ this.editorContainer.addChild(created.component);
3482
3628
  this.ui.setFocus(created.focus);
3483
3629
  this.ui.requestRender();
3484
3630
  }
3485
3631
  showSettingsSelector() {
3486
3632
  this.showSelector((done) => {
3487
- const selector = new SettingsSelectorComponent({
3633
+ let selector;
3634
+ selector = new SettingsSelectorComponent({
3488
3635
  autoCompact: this.session.autoCompactionEnabled,
3489
3636
  showImages: this.settingsManager.getShowImages(),
3490
3637
  imageWidthCells: this.settingsManager.getImageWidthCells(),
@@ -3501,6 +3648,7 @@ export class InteractiveMode {
3501
3648
  terminalTheme: this.themeController.getTerminalTheme(),
3502
3649
  availableThemes: getAvailableThemes(),
3503
3650
  hideThinkingBlock: this.hideThinkingBlock,
3651
+ mermaidRenderingMode: this.settingsManager.getMermaidRenderingMode(),
3504
3652
  collapseChangelog: this.settingsManager.getCollapseChangelog(),
3505
3653
  enableInstallTelemetry: this.settingsManager.getEnableInstallTelemetry(),
3506
3654
  doubleEscapeAction: this.settingsManager.getDoubleEscapeAction(),
@@ -3514,6 +3662,8 @@ export class InteractiveMode {
3514
3662
  quietStartup: this.settingsManager.getQuietStartup(),
3515
3663
  clearOnShrink: this.settingsManager.getClearOnShrink(),
3516
3664
  showTerminalProgress: this.settingsManager.getShowTerminalProgress(),
3665
+ tuiMode: this.ui.mode,
3666
+ fullscreenScrollbar: this.settingsManager.getFullscreenScrollbar(),
3517
3667
  warnings: this.settingsManager.getWarnings(),
3518
3668
  }, {
3519
3669
  onAutoCompactChange: (enabled) => {
@@ -3582,6 +3732,11 @@ export class InteractiveMode {
3582
3732
  this.clearChat();
3583
3733
  this.rebuildChatFromMessages();
3584
3734
  },
3735
+ onMermaidRenderingModeChange: (mode) => {
3736
+ this.settingsManager.setMermaidRenderingMode(mode);
3737
+ this.chatContainer.invalidate();
3738
+ this.ui.requestRender();
3739
+ },
3585
3740
  onShowCacheMissNoticesChange: (shown) => {
3586
3741
  this.settingsManager.setShowCacheMissNotices(shown);
3587
3742
  this.rebuildChatFromMessages();
@@ -3651,6 +3806,21 @@ export class InteractiveMode {
3651
3806
  onShowTerminalProgressChange: (enabled) => {
3652
3807
  this.settingsManager.setShowTerminalProgress(enabled);
3653
3808
  },
3809
+ onTuiModeChange: (mode) => {
3810
+ if (!this.switchTuiMode(mode)) {
3811
+ selector?.getSettingsList().updateValue("tui-mode", this.ui.mode);
3812
+ this.showStatus("Close active overlays before changing TUI mode");
3813
+ return;
3814
+ }
3815
+ this.settingsManager.setTuiMode(mode);
3816
+ if (!this.activeStatusIndicator)
3817
+ this.statusContainer.clear();
3818
+ this.showStatus(`TUI mode: ${mode}`);
3819
+ },
3820
+ onFullscreenScrollbarChange: (mode) => {
3821
+ this.settingsManager.setFullscreenScrollbar(mode);
3822
+ this.applyFullscreenScrollbarSetting();
3823
+ },
3654
3824
  onWarningsChange: (warnings) => {
3655
3825
  this.settingsManager.setWarnings(warnings);
3656
3826
  },
@@ -3685,20 +3855,37 @@ export class InteractiveMode {
3685
3855
  this.showModelSelector(searchTerm);
3686
3856
  }
3687
3857
  async findExactModelMatch(searchTerm) {
3688
- const models = await this.getModelCandidates();
3689
- return findExactModelReferenceMatch(searchTerm, models);
3690
- }
3691
- async getModelCandidates() {
3692
- if (this.session.scopedModels.length > 0) {
3693
- return this.session.scopedModels.map((scoped) => scoped.model);
3694
- }
3858
+ const cachedModels = this.session.scopedModels.length > 0
3859
+ ? this.session.scopedModels.map((scoped) => scoped.model)
3860
+ : [...this.session.modelRuntime.getAvailableSnapshot()];
3861
+ const cachedMatch = findExactModelReferenceMatch(searchTerm, cachedModels);
3862
+ if (cachedMatch || this.session.scopedModels.length > 0)
3863
+ return cachedMatch;
3864
+ this.showStatus("Refreshing model catalogs…");
3865
+ const controller = new AbortController();
3866
+ let timedOut = false;
3867
+ const timeout = setTimeout(() => {
3868
+ timedOut = true;
3869
+ controller.abort();
3870
+ }, 15_000);
3695
3871
  try {
3696
- await this.session.modelRuntime.refresh();
3697
- return [...(await this.session.modelRuntime.getAvailable())];
3872
+ const result = await this.session.modelRuntime.refresh({ signal: controller.signal });
3873
+ if (result.aborted && timedOut) {
3874
+ this.showWarning("Model refresh timed out; searching cached models.");
3875
+ }
3876
+ else if (result.errors.size > 0) {
3877
+ this.showWarning(`Could not refresh ${[...result.errors.keys()].join(", ")}; searching cached models.`);
3878
+ }
3698
3879
  }
3699
- catch {
3700
- return [];
3880
+ catch (error) {
3881
+ this.showWarning(timedOut
3882
+ ? "Model refresh timed out; searching cached models."
3883
+ : `Could not refresh model catalogs: ${error instanceof Error ? error.message : String(error)}`);
3884
+ }
3885
+ finally {
3886
+ clearTimeout(timeout);
3701
3887
  }
3888
+ return findExactModelReferenceMatch(searchTerm, [...this.session.modelRuntime.getAvailableSnapshot()]);
3702
3889
  }
3703
3890
  /** Update the footer's available provider count from the current snapshot without refreshing catalogs. */
3704
3891
  updateAvailableProviderCount() {
@@ -3800,73 +3987,67 @@ export class InteractiveMode {
3800
3987
  done();
3801
3988
  this.ui.requestRender();
3802
3989
  }, initialSearchInput);
3803
- return { component: selector, focus: selector };
3990
+ return { component: selector, focus: selector, dispose: () => selector.dispose() };
3804
3991
  });
3805
3992
  }
3806
- async showModelsSelector() {
3807
- // Get all available models
3808
- await this.session.modelRuntime.refresh();
3809
- const allModels = [...(await this.session.modelRuntime.getAvailable())];
3810
- const allModelIds = new Set(allModels.map((model) => `${model.provider}/${model.id}`));
3993
+ showModelsSelector() {
3994
+ let availableModels = [...this.session.modelRuntime.getAvailableSnapshot()];
3995
+ let availableModelIds = new Set(availableModels.map((model) => `${model.provider}/${model.id}`));
3811
3996
  const configuredPatterns = this.settingsManager.getEnabledModels();
3812
3997
  const sessionScopedModels = this.session.scopedModels;
3813
- if (allModels.length === 0 && !configuredPatterns?.length && sessionScopedModels.length === 0) {
3814
- this.showStatus("No models available");
3815
- return;
3816
- }
3817
- const configuredScope = configuredPatterns?.length
3818
- ? await resolveModelScopeWithDiagnostics(configuredPatterns, this.session.modelRuntime)
3819
- : undefined;
3820
- // Check if session has scoped models (from previous session-only changes or CLI --models)
3821
- const hasSessionScope = sessionScopedModels.length > 0;
3822
- // Build enabled model IDs from session state or settings
3823
- let currentEnabledIds = null;
3824
- if (hasSessionScope) {
3825
- // Use current session's scoped models
3826
- currentEnabledIds = sessionScopedModels.map((scoped) => `${scoped.model.provider}/${scoped.model.id}`);
3827
- }
3828
- else if (configuredScope) {
3829
- currentEnabledIds = configuredScope.scopedModels.map((scoped) => `${scoped.model.provider}/${scoped.model.id}`);
3830
- }
3831
- for (const diagnostic of configuredScope?.diagnostics ?? []) {
3832
- if (diagnostic.code !== "no-match")
3833
- continue;
3834
- currentEnabledIds ??= [];
3835
- if (!currentEnabledIds.includes(diagnostic.pattern))
3836
- currentEnabledIds.push(diagnostic.pattern);
3837
- }
3838
- // Helper to update session's scoped models (session-only, no persist)
3839
- const updateSessionModels = async (enabledIds) => {
3998
+ const configuredEnabledIds = (models) => {
3999
+ if (!configuredPatterns?.length)
4000
+ return null;
4001
+ const resolved = resolveModelScopeFromModels(configuredPatterns, models);
4002
+ const ids = resolved.scopedModels.map((scoped) => `${scoped.model.provider}/${scoped.model.id}`);
4003
+ for (const diagnostic of resolved.diagnostics) {
4004
+ if (diagnostic.code === "no-match" && !ids.includes(diagnostic.pattern))
4005
+ ids.push(diagnostic.pattern);
4006
+ }
4007
+ return ids;
4008
+ };
4009
+ let currentEnabledIds = sessionScopedModels.length > 0
4010
+ ? sessionScopedModels.map((scoped) => `${scoped.model.provider}/${scoped.model.id}`)
4011
+ : configuredEnabledIds(availableModels);
4012
+ let selectionChanged = false;
4013
+ const updateSessionModels = (enabledIds) => {
3840
4014
  currentEnabledIds = enabledIds === null ? null : [...enabledIds];
3841
- const hasEnabledAvailableModel = enabledIds?.some((id) => allModelIds.has(id)) ?? false;
3842
- const allAvailableModelsEnabled = enabledIds !== null && [...allModelIds].every((id) => enabledIds.includes(id));
4015
+ const hasEnabledAvailableModel = enabledIds?.some((id) => availableModelIds.has(id)) ?? false;
4016
+ const allAvailableModelsEnabled = enabledIds !== null && [...availableModelIds].every((id) => enabledIds.includes(id));
3843
4017
  if (enabledIds && hasEnabledAvailableModel && !allAvailableModelsEnabled) {
3844
- const newScopedModels = await resolveModelScope(enabledIds, this.session.modelRuntime);
3845
- this.session.setScopedModels(newScopedModels.map((sm) => ({
3846
- model: sm.model,
3847
- thinkingLevel: sm.thinkingLevel,
4018
+ const newScopedModels = resolveModelScopeFromModels(enabledIds, availableModels).scopedModels;
4019
+ this.session.setScopedModels(newScopedModels.map((scoped) => ({
4020
+ model: scoped.model,
4021
+ thinkingLevel: scoped.thinkingLevel,
3848
4022
  })));
3849
4023
  }
3850
4024
  else {
3851
- // All enabled or none enabled = no filter
3852
4025
  this.session.setScopedModels([]);
3853
4026
  }
3854
- await this.updateAvailableProviderCount();
4027
+ this.updateAvailableProviderCount();
3855
4028
  this.ui.requestRender();
3856
4029
  };
3857
4030
  this.showSelector((done) => {
4031
+ let disposed = false;
4032
+ let timedOut = false;
4033
+ const controller = new AbortController();
4034
+ const timeout = setTimeout(() => {
4035
+ timedOut = true;
4036
+ controller.abort();
4037
+ }, 15_000);
3858
4038
  const selector = new ScopedModelsSelectorComponent({
3859
- allModels,
4039
+ allModels: availableModels,
3860
4040
  enabledModelIds: currentEnabledIds,
4041
+ refreshStatus: "Refreshing model catalogs…",
3861
4042
  }, {
3862
- onChange: async (enabledIds) => {
3863
- await updateSessionModels(enabledIds);
4043
+ onChange: (enabledIds) => {
4044
+ selectionChanged = true;
4045
+ updateSessionModels(enabledIds);
3864
4046
  },
3865
4047
  onPersist: (enabledIds) => {
3866
- // Persist to settings
3867
4048
  const allEnabled = enabledIds !== null &&
3868
- enabledIds.length === allModels.length &&
3869
- enabledIds.every((id) => allModelIds.has(id));
4049
+ enabledIds.length === availableModels.length &&
4050
+ enabledIds.every((id) => availableModelIds.has(id));
3870
4051
  const newPatterns = enabledIds === null || allEnabled ? undefined : enabledIds;
3871
4052
  this.settingsManager.setEnabledModels(newPatterns ? [...newPatterns] : undefined);
3872
4053
  this.showStatus("Model selection saved to settings");
@@ -3876,7 +4057,51 @@ export class InteractiveMode {
3876
4057
  this.ui.requestRender();
3877
4058
  },
3878
4059
  });
3879
- return { component: selector, focus: selector };
4060
+ void this.session.modelRuntime
4061
+ .refresh({ signal: controller.signal })
4062
+ .then((result) => {
4063
+ if (disposed)
4064
+ return;
4065
+ availableModels = [...this.session.modelRuntime.getAvailableSnapshot()];
4066
+ availableModelIds = new Set(availableModels.map((model) => `${model.provider}/${model.id}`));
4067
+ if (!selectionChanged && sessionScopedModels.length === 0) {
4068
+ currentEnabledIds = configuredEnabledIds(availableModels);
4069
+ selector.updateModels(availableModels, currentEnabledIds);
4070
+ }
4071
+ else {
4072
+ selector.updateModels(availableModels);
4073
+ }
4074
+ if (currentEnabledIds !== null)
4075
+ updateSessionModels(currentEnabledIds);
4076
+ if (result.aborted && timedOut) {
4077
+ selector.setRefreshStatus("Model refresh timed out; showing cached models.", "warning");
4078
+ }
4079
+ else if (result.errors.size > 0) {
4080
+ selector.setRefreshStatus(`Could not refresh ${[...result.errors.keys()].join(", ")}; showing cached models.`, "warning");
4081
+ }
4082
+ else {
4083
+ selector.setRefreshStatus("Model catalogs refreshed.", "success");
4084
+ }
4085
+ this.ui.requestRender();
4086
+ })
4087
+ .catch((error) => {
4088
+ if (disposed)
4089
+ return;
4090
+ selector.setRefreshStatus(timedOut
4091
+ ? "Model refresh timed out; showing cached models."
4092
+ : `Could not refresh model catalogs: ${error instanceof Error ? error.message : String(error)}`, "warning");
4093
+ this.ui.requestRender();
4094
+ })
4095
+ .finally(() => clearTimeout(timeout));
4096
+ return {
4097
+ component: selector,
4098
+ focus: selector,
4099
+ dispose: () => {
4100
+ disposed = true;
4101
+ clearTimeout(timeout);
4102
+ controller.abort();
4103
+ },
4104
+ };
3880
4105
  });
3881
4106
  }
3882
4107
  showUserMessageSelector() {
@@ -3938,7 +4163,7 @@ export class InteractiveMode {
3938
4163
  this.showSelector((done) => {
3939
4164
  const selector = new TreeSelectorComponent(tree, realLeafId, this.ui.terminal.rows, async (entryId) => {
3940
4165
  // Selecting the current leaf is a no-op (already there)
3941
- if (entryId === realLeafId) {
4166
+ if (entryId === this.sessionManager.getLeafId()) {
3942
4167
  done();
3943
4168
  this.showStatus("Already at this point");
3944
4169
  return;
@@ -3973,6 +4198,11 @@ export class InteractiveMode {
3973
4198
  break;
3974
4199
  }
3975
4200
  }
4201
+ // The user committed to navigating: stop the active response first.
4202
+ if (this.session.isStreaming) {
4203
+ this.restoreQueuedMessagesToEditor();
4204
+ await this.session.abort();
4205
+ }
3976
4206
  // Set up escape handler and status indicator if summarizing
3977
4207
  let showingSummaryIndicator = false;
3978
4208
  const originalOnEscape = this.defaultEditor.onEscape;
@@ -4000,6 +4230,9 @@ export class InteractiveMode {
4000
4230
  this.showStatus("Navigation cancelled");
4001
4231
  return;
4002
4232
  }
4233
+ // User-committed tree navigation rebuilds the transcript; its
4234
+ // full redraw bypasses scrollback preservation.
4235
+ this.coalescingTerminal.passNextFullRedraw();
4003
4236
  // Update UI
4004
4237
  this.clearChat();
4005
4238
  this.renderInitialMessages();
@@ -4133,7 +4366,7 @@ export class InteractiveMode {
4133
4366
  return options.sort((a, b) => a.name.localeCompare(b.name));
4134
4367
  }
4135
4368
  async getLogoutProviderOptions() {
4136
- return (await this.session.modelRuntime.listCredentials())
4369
+ return (await this.session.modelRuntime.listCredentials({ signal: AbortSignal.timeout(15_000) }))
4137
4370
  .map(({ providerId, type }) => ({
4138
4371
  id: providerId,
4139
4372
  name: this.session.modelRuntime.getProvider(providerId)?.name ?? providerId,
@@ -4151,7 +4384,6 @@ export class InteractiveMode {
4151
4384
  provider.name.toLowerCase() === normalizedProviderRef);
4152
4385
  }
4153
4386
  async handleLoginCommand(providerRef) {
4154
- await this.session.modelRuntime.getAvailable();
4155
4387
  if (!providerRef) {
4156
4388
  this.showLoginAuthTypeSelector();
4157
4389
  return;
@@ -4265,7 +4497,14 @@ export class InteractiveMode {
4265
4497
  this.showLoginAuthTypeSelector();
4266
4498
  return;
4267
4499
  }
4268
- const providerOptions = await this.getLogoutProviderOptions();
4500
+ let providerOptions;
4501
+ try {
4502
+ providerOptions = await this.getLogoutProviderOptions();
4503
+ }
4504
+ catch (error) {
4505
+ this.showError(`Could not read stored credentials: ${error instanceof Error ? error.message : String(error)}`);
4506
+ return;
4507
+ }
4269
4508
  if (providerOptions.length === 0) {
4270
4509
  this.showStatus("No stored credentials to remove. /logout only removes credentials saved by /login; environment variables and models.json config are unchanged.");
4271
4510
  return;
@@ -4278,7 +4517,9 @@ export class InteractiveMode {
4278
4517
  return;
4279
4518
  }
4280
4519
  try {
4281
- await this.session.modelRuntime.logout(providerOption.id);
4520
+ await this.session.modelRuntime.logout(providerOption.id, {
4521
+ signal: AbortSignal.timeout(15_000),
4522
+ });
4282
4523
  await this.updateAvailableProviderCount();
4283
4524
  const message = providerOption.authType === "oauth"
4284
4525
  ? `Logged out of ${providerOption.name}`
@@ -4286,7 +4527,10 @@ export class InteractiveMode {
4286
4527
  this.showStatus(message);
4287
4528
  }
4288
4529
  catch (error) {
4289
- this.showError(`Logout failed: ${error instanceof Error ? error.message : String(error)}`);
4530
+ const message = error instanceof Error ? error.message : String(error);
4531
+ this.showError(error instanceof CredentialSynchronizationError
4532
+ ? `Credentials removed for ${providerOption.name}, but local model state could not be synchronized: ${message}`
4533
+ : `Logout failed: ${message}`);
4290
4534
  }
4291
4535
  }, () => {
4292
4536
  done();
@@ -4296,12 +4540,11 @@ export class InteractiveMode {
4296
4540
  });
4297
4541
  }
4298
4542
  async completeProviderAuthentication(providerId, providerName, authType, previousModel) {
4299
- await this.session.modelRuntime.getAvailable();
4300
4543
  const actionLabel = authType === "oauth" ? `Logged in to ${providerName}` : `Saved API key for ${providerName}`;
4301
4544
  let selectedModel;
4302
4545
  let selectionError;
4303
4546
  if (isUnknownModel(previousModel)) {
4304
- const availableModels = await this.session.modelRuntime.getAvailable();
4547
+ const availableModels = this.session.modelRuntime.getAvailableSnapshot();
4305
4548
  const providerModels = availableModels.filter((model) => model.provider === providerId);
4306
4549
  if (!hasDefaultModelProvider(providerId)) {
4307
4550
  selectionError = `${actionLabel}, but no default model is configured for provider "${providerId}". Use /model to select a model.`;
@@ -4344,6 +4587,25 @@ export class InteractiveMode {
4344
4587
  void this.maybeWarnAboutAnthropicSubscriptionAuth();
4345
4588
  }
4346
4589
  }
4590
+ const controller = new AbortController();
4591
+ const timeout = setTimeout(() => controller.abort(), 15_000);
4592
+ void this.session.modelRuntime
4593
+ .refresh({ providers: [providerId], signal: controller.signal })
4594
+ .then((result) => {
4595
+ if (result.aborted) {
4596
+ this.showWarning(`${actionLabel}, but its model catalog refresh timed out; using cached models.`);
4597
+ }
4598
+ else if (result.errors.size > 0) {
4599
+ this.showWarning(`${actionLabel}, but its model catalog could not be refreshed; using cached models.`);
4600
+ }
4601
+ this.updateAvailableProviderCount();
4602
+ this.footer.invalidate();
4603
+ this.ui.requestRender();
4604
+ })
4605
+ .catch((error) => {
4606
+ this.showWarning(`${actionLabel}, but its model catalog could not be refreshed: ${error instanceof Error ? error.message : String(error)}`);
4607
+ })
4608
+ .finally(() => clearTimeout(timeout));
4347
4609
  }
4348
4610
  showAmbientAuthDialog(providerOption) {
4349
4611
  const restoreEditor = () => {
@@ -4389,7 +4651,10 @@ export class InteractiveMode {
4389
4651
  catch (error) {
4390
4652
  restoreEditor();
4391
4653
  const errorMsg = error instanceof Error ? error.message : String(error);
4392
- if (errorMsg !== "Login cancelled") {
4654
+ if (error instanceof CredentialSynchronizationError) {
4655
+ this.showError(`Saved API key for ${providerName}, but local model state could not be synchronized: ${errorMsg}`);
4656
+ }
4657
+ else if (errorMsg !== "Login cancelled") {
4393
4658
  this.showError(`Failed to save API key for ${providerName}: ${errorMsg}`);
4394
4659
  }
4395
4660
  }
@@ -4492,7 +4757,10 @@ export class InteractiveMode {
4492
4757
  catch (error) {
4493
4758
  restoreEditor();
4494
4759
  const errorMsg = error instanceof Error ? error.message : String(error);
4495
- if (errorMsg !== "Login cancelled") {
4760
+ if (error instanceof CredentialSynchronizationError) {
4761
+ this.showError(`Logged in to ${providerName}, but local model state could not be synchronized: ${errorMsg}`);
4762
+ }
4763
+ else if (errorMsg !== "Login cancelled") {
4496
4764
  this.showError(`Failed to login to ${providerName}: ${errorMsg}`);
4497
4765
  }
4498
4766
  }
@@ -4537,13 +4805,16 @@ export class InteractiveMode {
4537
4805
  }
4538
4806
  this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
4539
4807
  this.outputPad = this.settingsManager.getOutputPad();
4808
+ // The user asked for this rebuild; its full redraw keeps the
4809
+ // upstream wipe-and-replay even if preservation is still windowed
4810
+ // on from the previous run.
4811
+ this.coalescingTerminal.passNextFullRedraw();
4540
4812
  this.rebuildChatFromMessages();
4541
4813
  chatRestoredBeforeSessionStart = true;
4542
4814
  };
4543
4815
  try {
4544
4816
  await this.session.reload({ beforeSessionStart: restoreChatBeforeSessionStart });
4545
4817
  restoreChatBeforeSessionStart();
4546
- configureHttpDispatcher(this.settingsManager.getHttpIdleTimeoutMs());
4547
4818
  this.keybindings.reload();
4548
4819
  const activeHeader = this.customHeader ?? this.builtInHeader;
4549
4820
  if (isExpandable(activeHeader)) {
@@ -4551,20 +4822,7 @@ export class InteractiveMode {
4551
4822
  }
4552
4823
  setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
4553
4824
  await this.themeController.applyFromSettings();
4554
- const editorPaddingX = this.settingsManager.getEditorPaddingX();
4555
- const autocompleteMaxVisible = this.settingsManager.getAutocompleteMaxVisible();
4556
- this.defaultEditor.setPaddingX(editorPaddingX);
4557
- this.defaultEditor.setAutocompleteMaxVisible(autocompleteMaxVisible);
4558
- if (this.editor !== this.defaultEditor) {
4559
- this.editor.setPaddingX?.(editorPaddingX);
4560
- this.editor.setAutocompleteMaxVisible?.(autocompleteMaxVisible);
4561
- }
4562
- this.ui.setShowHardwareCursor(this.settingsManager.getShowHardwareCursor());
4563
- const clearOnShrink = this.settingsManager.getClearOnShrink();
4564
- this.ui.setClearOnShrink(clearOnShrink);
4565
- if (!clearOnShrink && !this.activeStatusIndicator) {
4566
- this.statusContainer.clear();
4567
- }
4825
+ this.applyRuntimeSettings();
4568
4826
  this.setupAutocompleteProvider();
4569
4827
  const runner = this.session.extensionRunner;
4570
4828
  this.setupExtensionShortcuts(runner);
@@ -4760,7 +5018,7 @@ export class InteractiveMode {
4760
5018
  }
4761
5019
  }
4762
5020
  }
4763
- async handleCopyCommand() {
5021
+ async handleCopyCommand(options = {}) {
4764
5022
  const text = this.session.getLastAssistantText();
4765
5023
  if (!text) {
4766
5024
  this.showError("No agent messages to copy yet.");
@@ -4768,7 +5026,12 @@ export class InteractiveMode {
4768
5026
  }
4769
5027
  try {
4770
5028
  await copyToClipboard(text);
4771
- this.showStatus("Copied last agent message to clipboard");
5029
+ if (options.flashConfirmation && this.ui instanceof TuiAltScreen) {
5030
+ this.ui.flash("Copied!");
5031
+ }
5032
+ else {
5033
+ this.showStatus("Copied last agent message to clipboard");
5034
+ }
4772
5035
  }
4773
5036
  catch (error) {
4774
5037
  this.showError(error instanceof Error ? error.message : String(error));
@@ -5131,15 +5394,15 @@ export class InteractiveMode {
5131
5394
  }
5132
5395
  }
5133
5396
  stop() {
5134
- this.activeSelectorCleanup?.();
5135
- this.activeSelectorCleanup = null;
5136
- this.activeSelector = null;
5397
+ this.disposeActiveSelector();
5137
5398
  if (this.settingsManager.getShowTerminalProgress()) {
5138
5399
  this.ui.terminal.setProgress(false);
5139
5400
  }
5140
5401
  this.clearStatusIndicator();
5141
5402
  this.themeController.disableAutoSync();
5142
5403
  this.clearExtensionTerminalInputListeners();
5404
+ this.scrollbackPreservationInputUnsubscribe?.();
5405
+ this.scrollbackPreservationInputUnsubscribe = undefined;
5143
5406
  this.clearPendingTools();
5144
5407
  this.disposeChatToolComponents();
5145
5408
  this.footer.dispose();
@@ -5148,7 +5411,7 @@ export class InteractiveMode {
5148
5411
  this.unsubscribe();
5149
5412
  }
5150
5413
  if (this.isInitialized) {
5151
- this.ui.stop();
5414
+ this.stopInteractiveTui();
5152
5415
  this.isInitialized = false;
5153
5416
  }
5154
5417
  this.unregisterSignalHandlers();