@astralyn/pi 0.83.0 → 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 (739) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/dist/bun/cli.d.ts.map +1 -1
  3. package/dist/bun/cli.js.map +1 -1
  4. package/dist/bun/register-bedrock.d.ts.map +1 -1
  5. package/dist/bun/restore-sandbox-env.d.ts.map +1 -1
  6. package/dist/bun/restore-sandbox-env.js.map +1 -1
  7. package/dist/cli/args.d.ts +2 -0
  8. package/dist/cli/args.d.ts.map +1 -1
  9. package/dist/cli/args.js +19 -0
  10. package/dist/cli/args.js.map +1 -1
  11. package/dist/cli/config-selector.d.ts.map +1 -1
  12. package/dist/cli/config-selector.js +2 -2
  13. package/dist/cli/config-selector.js.map +1 -1
  14. package/dist/cli/credential-print.d.ts +1 -1
  15. package/dist/cli/credential-print.d.ts.map +1 -1
  16. package/dist/cli/credential-print.js +6 -5
  17. package/dist/cli/credential-print.js.map +1 -1
  18. package/dist/cli/experimental/auth.d.ts +16 -0
  19. package/dist/cli/experimental/auth.d.ts.map +1 -0
  20. package/dist/cli/experimental/auth.js +13 -0
  21. package/dist/cli/experimental/auth.js.map +1 -0
  22. package/dist/cli/experimental/cli.d.ts +6 -0
  23. package/dist/cli/experimental/cli.d.ts.map +1 -0
  24. package/dist/cli/experimental/cli.js +5 -0
  25. package/dist/cli/experimental/cli.js.map +1 -0
  26. package/dist/cli/experimental/command-options.d.ts +17 -0
  27. package/dist/cli/experimental/command-options.d.ts.map +1 -0
  28. package/dist/cli/experimental/command-options.js +35 -0
  29. package/dist/cli/experimental/command-options.js.map +1 -0
  30. package/dist/cli/experimental/command.d.ts +63 -0
  31. package/dist/cli/experimental/command.d.ts.map +1 -0
  32. package/dist/cli/experimental/command.js +127 -0
  33. package/dist/cli/experimental/command.js.map +1 -0
  34. package/dist/cli/experimental/commands/client.d.ts +13 -0
  35. package/dist/cli/experimental/commands/client.d.ts.map +1 -0
  36. package/dist/cli/experimental/commands/client.js +25 -0
  37. package/dist/cli/experimental/commands/client.js.map +1 -0
  38. package/dist/cli/experimental/commands/pi.d.ts +15 -0
  39. package/dist/cli/experimental/commands/pi.d.ts.map +1 -0
  40. package/dist/cli/experimental/commands/pi.js +28 -0
  41. package/dist/cli/experimental/commands/pi.js.map +1 -0
  42. package/dist/cli/experimental/commands/server.d.ts +13 -0
  43. package/dist/cli/experimental/commands/server.d.ts.map +1 -0
  44. package/dist/cli/experimental/commands/server.js +25 -0
  45. package/dist/cli/experimental/commands/server.js.map +1 -0
  46. package/dist/cli/experimental/transport-address.d.ts +10 -0
  47. package/dist/cli/experimental/transport-address.d.ts.map +1 -0
  48. package/dist/cli/experimental/transport-address.js +38 -0
  49. package/dist/cli/experimental/transport-address.js.map +1 -0
  50. package/dist/cli/file-processor.d.ts.map +1 -1
  51. package/dist/cli/file-processor.js.map +1 -1
  52. package/dist/cli/initial-message.d.ts +1 -1
  53. package/dist/cli/initial-message.d.ts.map +1 -1
  54. package/dist/cli/initial-message.js.map +1 -1
  55. package/dist/cli/list-models.d.ts +1 -1
  56. package/dist/cli/list-models.d.ts.map +1 -1
  57. package/dist/cli/list-models.js +2 -2
  58. package/dist/cli/list-models.js.map +1 -1
  59. package/dist/cli/project-trust.d.ts.map +1 -1
  60. package/dist/cli/project-trust.js.map +1 -1
  61. package/dist/cli/session-picker.d.ts.map +1 -1
  62. package/dist/cli/session-picker.js.map +1 -1
  63. package/dist/cli/startup-ui.d.ts +1 -1
  64. package/dist/cli/startup-ui.d.ts.map +1 -1
  65. package/dist/cli/startup-ui.js +2 -2
  66. package/dist/cli/startup-ui.js.map +1 -1
  67. package/dist/cli.d.ts.map +1 -1
  68. package/dist/cli.js +1 -0
  69. package/dist/cli.js.map +1 -1
  70. package/dist/client/index.d.ts +3 -0
  71. package/dist/client/index.d.ts.map +1 -0
  72. package/dist/client/index.js +3 -0
  73. package/dist/client/index.js.map +1 -0
  74. package/dist/client/remote-session.d.ts +53 -0
  75. package/dist/client/remote-session.d.ts.map +1 -0
  76. package/dist/client/remote-session.js +340 -0
  77. package/dist/client/remote-session.js.map +1 -0
  78. package/dist/client/transcript.d.ts +12 -0
  79. package/dist/client/transcript.d.ts.map +1 -0
  80. package/dist/client/transcript.js +98 -0
  81. package/dist/client/transcript.js.map +1 -0
  82. package/dist/config.d.ts.map +1 -1
  83. package/dist/config.js.map +1 -1
  84. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  85. package/dist/core/agent-session-runtime.js +0 -8
  86. package/dist/core/agent-session-runtime.js.map +1 -1
  87. package/dist/core/agent-session-services.d.ts +1 -0
  88. package/dist/core/agent-session-services.d.ts.map +1 -1
  89. package/dist/core/agent-session-services.js +1 -0
  90. package/dist/core/agent-session-services.js.map +1 -1
  91. package/dist/core/agent-session.d.ts +30 -10
  92. package/dist/core/agent-session.d.ts.map +1 -1
  93. package/dist/core/agent-session.js +177 -187
  94. package/dist/core/agent-session.js.map +1 -1
  95. package/dist/core/auth-guidance.d.ts.map +1 -1
  96. package/dist/core/auth-guidance.js.map +1 -1
  97. package/dist/core/auth-storage.d.ts +15 -9
  98. package/dist/core/auth-storage.d.ts.map +1 -1
  99. package/dist/core/auth-storage.js +159 -41
  100. package/dist/core/auth-storage.js.map +1 -1
  101. package/dist/core/bash-executor.d.ts.map +1 -1
  102. package/dist/core/bash-executor.js.map +1 -1
  103. package/dist/core/cache-stats.d.ts.map +1 -1
  104. package/dist/core/cache-stats.js.map +1 -1
  105. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  106. package/dist/core/compaction/branch-summarization.js.map +1 -1
  107. package/dist/core/compaction/compaction.d.ts.map +1 -1
  108. package/dist/core/compaction/compaction.js.map +1 -1
  109. package/dist/core/compaction/index.d.ts.map +1 -1
  110. package/dist/core/compaction/utils.d.ts.map +1 -1
  111. package/dist/core/compaction/utils.js.map +1 -1
  112. package/dist/core/defaults.d.ts.map +1 -1
  113. package/dist/core/diagnostics.d.ts.map +1 -1
  114. package/dist/core/event-bus.d.ts.map +1 -1
  115. package/dist/core/event-bus.js.map +1 -1
  116. package/dist/core/exec.d.ts.map +1 -1
  117. package/dist/core/exec.js.map +1 -1
  118. package/dist/core/experimental.d.ts.map +1 -1
  119. package/dist/core/experimental.js.map +1 -1
  120. package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
  121. package/dist/core/export-html/ansi-to-html.js.map +1 -1
  122. package/dist/core/export-html/index.d.ts.map +1 -1
  123. package/dist/core/export-html/index.js.map +1 -1
  124. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  125. package/dist/core/export-html/tool-renderer.js.map +1 -1
  126. package/dist/core/extensions/index.d.ts +1 -1
  127. package/dist/core/extensions/index.d.ts.map +1 -1
  128. package/dist/core/extensions/index.js.map +1 -1
  129. package/dist/core/extensions/loader.d.ts.map +1 -1
  130. package/dist/core/extensions/loader.js +43 -20
  131. package/dist/core/extensions/loader.js.map +1 -1
  132. package/dist/core/extensions/runner.d.ts +2 -1
  133. package/dist/core/extensions/runner.d.ts.map +1 -1
  134. package/dist/core/extensions/runner.js +25 -29
  135. package/dist/core/extensions/runner.js.map +1 -1
  136. package/dist/core/extensions/types.d.ts +21 -3
  137. package/dist/core/extensions/types.d.ts.map +1 -1
  138. package/dist/core/extensions/types.js.map +1 -1
  139. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  140. package/dist/core/extensions/wrapper.js.map +1 -1
  141. package/dist/core/footer-data-provider.d.ts.map +1 -1
  142. package/dist/core/footer-data-provider.js +17 -18
  143. package/dist/core/footer-data-provider.js.map +1 -1
  144. package/dist/core/http-dispatcher.d.ts.map +1 -1
  145. package/dist/core/http-dispatcher.js +5 -0
  146. package/dist/core/http-dispatcher.js.map +1 -1
  147. package/dist/core/index.d.ts.map +1 -1
  148. package/dist/core/keybindings.d.ts +157 -125
  149. package/dist/core/keybindings.d.ts.map +1 -1
  150. package/dist/core/keybindings.js +0 -1
  151. package/dist/core/keybindings.js.map +1 -1
  152. package/dist/core/messages.d.ts.map +1 -1
  153. package/dist/core/messages.js.map +1 -1
  154. package/dist/core/model-config.d.ts +37 -13
  155. package/dist/core/model-config.d.ts.map +1 -1
  156. package/dist/core/model-config.js +4 -2
  157. package/dist/core/model-config.js.map +1 -1
  158. package/dist/core/model-registry.d.ts +5 -3
  159. package/dist/core/model-registry.d.ts.map +1 -1
  160. package/dist/core/model-registry.js +13 -11
  161. package/dist/core/model-registry.js.map +1 -1
  162. package/dist/core/model-resolver.d.ts +4 -3
  163. package/dist/core/model-resolver.d.ts.map +1 -1
  164. package/dist/core/model-resolver.js +41 -10
  165. package/dist/core/model-resolver.js.map +1 -1
  166. package/dist/core/model-runtime.d.ts +28 -13
  167. package/dist/core/model-runtime.d.ts.map +1 -1
  168. package/dist/core/model-runtime.js +239 -91
  169. package/dist/core/model-runtime.js.map +1 -1
  170. package/dist/core/models-store.d.ts +12 -7
  171. package/dist/core/models-store.d.ts.map +1 -1
  172. package/dist/core/models-store.js +84 -16
  173. package/dist/core/models-store.js.map +1 -1
  174. package/dist/core/output-guard.d.ts.map +1 -1
  175. package/dist/core/output-guard.js.map +1 -1
  176. package/dist/core/package-manager.d.ts +4 -1
  177. package/dist/core/package-manager.d.ts.map +1 -1
  178. package/dist/core/package-manager.js +63 -42
  179. package/dist/core/package-manager.js.map +1 -1
  180. package/dist/core/pi-manifest.d.ts +8 -0
  181. package/dist/core/pi-manifest.d.ts.map +1 -0
  182. package/dist/core/pi-manifest.js +25 -0
  183. package/dist/core/pi-manifest.js.map +1 -0
  184. package/dist/core/project-trust.d.ts.map +1 -1
  185. package/dist/core/project-trust.js.map +1 -1
  186. package/dist/core/prompt-templates.d.ts.map +1 -1
  187. package/dist/core/prompt-templates.js.map +1 -1
  188. package/dist/core/provider-attribution.d.ts.map +1 -1
  189. package/dist/core/provider-attribution.js.map +1 -1
  190. package/dist/core/provider-composer.d.ts +4 -1
  191. package/dist/core/provider-composer.d.ts.map +1 -1
  192. package/dist/core/provider-composer.js +36 -15
  193. package/dist/core/provider-composer.js.map +1 -1
  194. package/dist/core/radius.d.ts.map +1 -1
  195. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  196. package/dist/core/remote-catalog-provider.js +73 -67
  197. package/dist/core/remote-catalog-provider.js.map +1 -1
  198. package/dist/core/resolve-config-value.d.ts.map +1 -1
  199. package/dist/core/resolve-config-value.js.map +1 -1
  200. package/dist/core/resource-loader.d.ts.map +1 -1
  201. package/dist/core/resource-loader.js +2 -46
  202. package/dist/core/resource-loader.js.map +1 -1
  203. package/dist/core/runtime-credentials.d.ts +5 -5
  204. package/dist/core/runtime-credentials.d.ts.map +1 -1
  205. package/dist/core/runtime-credentials.js +12 -10
  206. package/dist/core/runtime-credentials.js.map +1 -1
  207. package/dist/core/sdk.d.ts.map +1 -1
  208. package/dist/core/sdk.js.map +1 -1
  209. package/dist/core/session-cwd.d.ts.map +1 -1
  210. package/dist/core/session-cwd.js +0 -1
  211. package/dist/core/session-cwd.js.map +1 -1
  212. package/dist/core/session-manager.d.ts.map +1 -1
  213. package/dist/core/session-manager.js +10 -12
  214. package/dist/core/session-manager.js.map +1 -1
  215. package/dist/core/settings-manager.d.ts +12 -0
  216. package/dist/core/settings-manager.d.ts.map +1 -1
  217. package/dist/core/settings-manager.js +47 -33
  218. package/dist/core/settings-manager.js.map +1 -1
  219. package/dist/core/skills.d.ts.map +1 -1
  220. package/dist/core/skills.js.map +1 -1
  221. package/dist/core/slash-commands.d.ts.map +1 -1
  222. package/dist/core/source-info.d.ts.map +1 -1
  223. package/dist/core/source-info.js.map +1 -1
  224. package/dist/core/system-prompt.d.ts.map +1 -1
  225. package/dist/core/system-prompt.js.map +1 -1
  226. package/dist/core/telemetry.d.ts.map +1 -1
  227. package/dist/core/telemetry.js.map +1 -1
  228. package/dist/core/timings.d.ts.map +1 -1
  229. package/dist/core/timings.js.map +1 -1
  230. package/dist/core/tools/bash.d.ts.map +1 -1
  231. package/dist/core/tools/bash.js +12 -10
  232. package/dist/core/tools/bash.js.map +1 -1
  233. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  234. package/dist/core/tools/edit-diff.js.map +1 -1
  235. package/dist/core/tools/edit.d.ts.map +1 -1
  236. package/dist/core/tools/edit.js +4 -3
  237. package/dist/core/tools/edit.js.map +1 -1
  238. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  239. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  240. package/dist/core/tools/find.d.ts +3 -0
  241. package/dist/core/tools/find.d.ts.map +1 -1
  242. package/dist/core/tools/find.js +13 -16
  243. package/dist/core/tools/find.js.map +1 -1
  244. package/dist/core/tools/grep.d.ts.map +1 -1
  245. package/dist/core/tools/grep.js.map +1 -1
  246. package/dist/core/tools/index.d.ts.map +1 -1
  247. package/dist/core/tools/index.js.map +1 -1
  248. package/dist/core/tools/ls.d.ts.map +1 -1
  249. package/dist/core/tools/ls.js.map +1 -1
  250. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  251. package/dist/core/tools/output-accumulator.js +12 -18
  252. package/dist/core/tools/output-accumulator.js.map +1 -1
  253. package/dist/core/tools/path-utils.d.ts.map +1 -1
  254. package/dist/core/tools/path-utils.js.map +1 -1
  255. package/dist/core/tools/read.d.ts.map +1 -1
  256. package/dist/core/tools/read.js +1 -1
  257. package/dist/core/tools/read.js.map +1 -1
  258. package/dist/core/tools/render-utils.d.ts.map +1 -1
  259. package/dist/core/tools/render-utils.js.map +1 -1
  260. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  261. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  262. package/dist/core/tools/truncate.d.ts.map +1 -1
  263. package/dist/core/tools/truncate.js.map +1 -1
  264. package/dist/core/tools/write.d.ts.map +1 -1
  265. package/dist/core/tools/write.js +0 -1
  266. package/dist/core/tools/write.js.map +1 -1
  267. package/dist/core/trust-manager.d.ts.map +1 -1
  268. package/dist/core/trust-manager.js +0 -1
  269. package/dist/core/trust-manager.js.map +1 -1
  270. package/dist/core/usage-totals.d.ts.map +1 -1
  271. package/dist/core/usage-totals.js.map +1 -1
  272. package/dist/extensions/biu/index.d.ts +19 -0
  273. package/dist/extensions/biu/index.d.ts.map +1 -0
  274. package/dist/extensions/biu/index.js +350 -0
  275. package/dist/extensions/biu/index.js.map +1 -0
  276. package/dist/extensions/biu/prompts.d.ts +26 -0
  277. package/dist/extensions/biu/prompts.d.ts.map +1 -0
  278. package/dist/extensions/biu/prompts.js +260 -0
  279. package/dist/extensions/biu/prompts.js.map +1 -0
  280. package/dist/extensions/biu/workspace.d.ts +122 -0
  281. package/dist/extensions/biu/workspace.d.ts.map +1 -0
  282. package/dist/extensions/biu/workspace.js +404 -0
  283. package/dist/extensions/biu/workspace.js.map +1 -0
  284. package/dist/extensions/deepwiki/client.d.ts.map +1 -1
  285. package/dist/extensions/deepwiki/client.js.map +1 -1
  286. package/dist/extensions/deepwiki/constants.d.ts.map +1 -1
  287. package/dist/extensions/deepwiki/constants.js.map +1 -1
  288. package/dist/extensions/deepwiki/contents.d.ts.map +1 -1
  289. package/dist/extensions/deepwiki/contents.js.map +1 -1
  290. package/dist/extensions/deepwiki/execute.d.ts.map +1 -1
  291. package/dist/extensions/deepwiki/execute.js.map +1 -1
  292. package/dist/extensions/deepwiki/http.d.ts.map +1 -1
  293. package/dist/extensions/deepwiki/http.js.map +1 -1
  294. package/dist/extensions/deepwiki/index.d.ts.map +1 -1
  295. package/dist/extensions/deepwiki/index.js.map +1 -1
  296. package/dist/extensions/deepwiki/render.d.ts.map +1 -1
  297. package/dist/extensions/deepwiki/render.js.map +1 -1
  298. package/dist/extensions/deepwiki/schema.d.ts +1 -1
  299. package/dist/extensions/deepwiki/schema.d.ts.map +1 -1
  300. package/dist/extensions/deepwiki/schema.js.map +1 -1
  301. package/dist/extensions/index.d.ts.map +1 -1
  302. package/dist/extensions/index.js +2 -0
  303. package/dist/extensions/index.js.map +1 -1
  304. package/dist/extensions/llama/client.d.ts.map +1 -1
  305. package/dist/extensions/llama/client.js +0 -2
  306. package/dist/extensions/llama/client.js.map +1 -1
  307. package/dist/extensions/llama/huggingface.d.ts.map +1 -1
  308. package/dist/extensions/llama/huggingface.js +0 -2
  309. package/dist/extensions/llama/huggingface.js.map +1 -1
  310. package/dist/extensions/llama/index.d.ts.map +1 -1
  311. package/dist/extensions/llama/index.js +11 -2
  312. package/dist/extensions/llama/index.js.map +1 -1
  313. package/dist/extensions/llama/provider.d.ts.map +1 -1
  314. package/dist/extensions/llama/provider.js +21 -7
  315. package/dist/extensions/llama/provider.js.map +1 -1
  316. package/dist/extensions/llama/ui.d.ts.map +1 -1
  317. package/dist/extensions/llama/ui.js +12 -28
  318. package/dist/extensions/llama/ui.js.map +1 -1
  319. package/dist/extensions/question/constants.d.ts.map +1 -1
  320. package/dist/extensions/question/constants.js.map +1 -1
  321. package/dist/extensions/question/dialog-primitives.d.ts.map +1 -1
  322. package/dist/extensions/question/dialog-primitives.js.map +1 -1
  323. package/dist/extensions/question/dialog.d.ts.map +1 -1
  324. package/dist/extensions/question/dialog.js.map +1 -1
  325. package/dist/extensions/question/index.d.ts.map +1 -1
  326. package/dist/extensions/question/index.js.map +1 -1
  327. package/dist/extensions/question/limits.d.ts.map +1 -1
  328. package/dist/extensions/question/render-cache.d.ts.map +1 -1
  329. package/dist/extensions/question/render-cache.js +3 -4
  330. package/dist/extensions/question/render-cache.js.map +1 -1
  331. package/dist/extensions/question/render.d.ts.map +1 -1
  332. package/dist/extensions/question/render.js.map +1 -1
  333. package/dist/extensions/question/results.d.ts.map +1 -1
  334. package/dist/extensions/question/results.js.map +1 -1
  335. package/dist/extensions/question/schema.d.ts.map +1 -1
  336. package/dist/extensions/question/schema.js.map +1 -1
  337. package/dist/extensions/question/state.d.ts.map +1 -1
  338. package/dist/extensions/question/state.js.map +1 -1
  339. package/dist/extensions/question/types.d.ts.map +1 -1
  340. package/dist/extensions/rewind/anchor.d.ts.map +1 -1
  341. package/dist/extensions/rewind/anchor.js.map +1 -1
  342. package/dist/extensions/rewind/config.d.ts.map +1 -1
  343. package/dist/extensions/rewind/config.js.map +1 -1
  344. package/dist/extensions/rewind/engine.d.ts.map +1 -1
  345. package/dist/extensions/rewind/engine.js.map +1 -1
  346. package/dist/extensions/rewind/gc.d.ts.map +1 -1
  347. package/dist/extensions/rewind/gc.js.map +1 -1
  348. package/dist/extensions/rewind/index.d.ts.map +1 -1
  349. package/dist/extensions/rewind/index.js.map +1 -1
  350. package/dist/extensions/rewind/menu.d.ts.map +1 -1
  351. package/dist/extensions/rewind/menu.js.map +1 -1
  352. package/dist/extensions/rewind/paths.d.ts.map +1 -1
  353. package/dist/extensions/rewind/paths.js.map +1 -1
  354. package/dist/extensions/rewind/restore.d.ts.map +1 -1
  355. package/dist/extensions/rewind/restore.js.map +1 -1
  356. package/dist/extensions/rewind/snapshot.d.ts.map +1 -1
  357. package/dist/extensions/rewind/snapshot.js.map +1 -1
  358. package/dist/extensions/rewind/storage.d.ts.map +1 -1
  359. package/dist/extensions/rewind/storage.js.map +1 -1
  360. package/dist/extensions/rewind/text.d.ts.map +1 -1
  361. package/dist/extensions/rewind/text.js.map +1 -1
  362. package/dist/extensions/rewind/tool-path.d.ts.map +1 -1
  363. package/dist/extensions/rewind/tool-path.js.map +1 -1
  364. package/dist/extensions/router/constants.d.ts +3 -0
  365. package/dist/extensions/router/constants.d.ts.map +1 -1
  366. package/dist/extensions/router/constants.js +3 -0
  367. package/dist/extensions/router/constants.js.map +1 -1
  368. package/dist/extensions/router/dialog.d.ts +14 -7
  369. package/dist/extensions/router/dialog.d.ts.map +1 -1
  370. package/dist/extensions/router/dialog.js +70 -132
  371. package/dist/extensions/router/dialog.js.map +1 -1
  372. package/dist/extensions/router/index.d.ts.map +1 -1
  373. package/dist/extensions/router/index.js.map +1 -1
  374. package/dist/extensions/router/presets.d.ts +8 -3
  375. package/dist/extensions/router/presets.d.ts.map +1 -1
  376. package/dist/extensions/router/presets.js +33 -17
  377. package/dist/extensions/router/presets.js.map +1 -1
  378. package/dist/extensions/router/probe.d.ts.map +1 -1
  379. package/dist/extensions/router/probe.js.map +1 -1
  380. package/dist/extensions/router/register.d.ts +3 -3
  381. package/dist/extensions/router/register.d.ts.map +1 -1
  382. package/dist/extensions/router/register.js.map +1 -1
  383. package/dist/extensions/router/store.d.ts.map +1 -1
  384. package/dist/extensions/router/store.js.map +1 -1
  385. package/dist/extensions/router/stream.d.ts.map +1 -1
  386. package/dist/extensions/router/stream.js.map +1 -1
  387. package/dist/extensions/router/types.d.ts.map +1 -1
  388. package/dist/extensions/router/ui.d.ts +11 -2
  389. package/dist/extensions/router/ui.d.ts.map +1 -1
  390. package/dist/extensions/router/ui.js +316 -171
  391. package/dist/extensions/router/ui.js.map +1 -1
  392. package/dist/extensions/statusline/index.d.ts.map +1 -1
  393. package/dist/extensions/statusline/index.js +17 -9
  394. package/dist/extensions/statusline/index.js.map +1 -1
  395. package/dist/extensions/subagent/activity.d.ts.map +1 -1
  396. package/dist/extensions/subagent/activity.js.map +1 -1
  397. package/dist/extensions/subagent/agents.d.ts.map +1 -1
  398. package/dist/extensions/subagent/agents.js.map +1 -1
  399. package/dist/extensions/subagent/constants.d.ts.map +1 -1
  400. package/dist/extensions/subagent/index.d.ts +3 -0
  401. package/dist/extensions/subagent/index.d.ts.map +1 -1
  402. package/dist/extensions/subagent/index.js +83 -12
  403. package/dist/extensions/subagent/index.js.map +1 -1
  404. package/dist/extensions/subagent/picker.d.ts.map +1 -1
  405. package/dist/extensions/subagent/picker.js +2 -9
  406. package/dist/extensions/subagent/picker.js.map +1 -1
  407. package/dist/extensions/subagent/render.d.ts.map +1 -1
  408. package/dist/extensions/subagent/render.js +33 -9
  409. package/dist/extensions/subagent/render.js.map +1 -1
  410. package/dist/extensions/subagent/resolve.d.ts.map +1 -1
  411. package/dist/extensions/subagent/resolve.js.map +1 -1
  412. package/dist/extensions/subagent/retry.d.ts.map +1 -1
  413. package/dist/extensions/subagent/retry.js.map +1 -1
  414. package/dist/extensions/subagent/runner.d.ts +2 -1
  415. package/dist/extensions/subagent/runner.d.ts.map +1 -1
  416. package/dist/extensions/subagent/runner.js +10 -12
  417. package/dist/extensions/subagent/runner.js.map +1 -1
  418. package/dist/extensions/subagent/schema.d.ts.map +1 -1
  419. package/dist/extensions/subagent/schema.js.map +1 -1
  420. package/dist/extensions/subagent/sdk-runner.d.ts.map +1 -1
  421. package/dist/extensions/subagent/sdk-runner.js +41 -1
  422. package/dist/extensions/subagent/sdk-runner.js.map +1 -1
  423. package/dist/extensions/subagent/settings.d.ts.map +1 -1
  424. package/dist/extensions/subagent/settings.js +46 -36
  425. package/dist/extensions/subagent/settings.js.map +1 -1
  426. package/dist/extensions/subagent/types.d.ts +0 -1
  427. package/dist/extensions/subagent/types.d.ts.map +1 -1
  428. package/dist/extensions/subagent/types.js.map +1 -1
  429. package/dist/extensions/todo/constants.d.ts.map +1 -1
  430. package/dist/extensions/todo/constants.js.map +1 -1
  431. package/dist/extensions/todo/index.d.ts.map +1 -1
  432. package/dist/extensions/todo/index.js.map +1 -1
  433. package/dist/extensions/todo/overlay.d.ts.map +1 -1
  434. package/dist/extensions/todo/overlay.js +6 -10
  435. package/dist/extensions/todo/overlay.js.map +1 -1
  436. package/dist/extensions/todo/schema.d.ts +2 -2
  437. package/dist/extensions/todo/schema.d.ts.map +1 -1
  438. package/dist/extensions/todo/state.d.ts.map +1 -1
  439. package/dist/extensions/todo/state.js.map +1 -1
  440. package/dist/extensions/todo/view.d.ts.map +1 -1
  441. package/dist/extensions/todo/view.js.map +1 -1
  442. package/dist/index.d.ts +4 -4
  443. package/dist/index.d.ts.map +1 -1
  444. package/dist/index.js +1 -1
  445. package/dist/index.js.map +1 -1
  446. package/dist/main.d.ts.map +1 -1
  447. package/dist/main.js +16 -7
  448. package/dist/main.js.map +1 -1
  449. package/dist/migrations.d.ts.map +1 -1
  450. package/dist/migrations.js.map +1 -1
  451. package/dist/modes/index.d.ts +1 -0
  452. package/dist/modes/index.d.ts.map +1 -1
  453. package/dist/modes/index.js.map +1 -1
  454. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  455. package/dist/modes/interactive/components/armin.js +6 -10
  456. package/dist/modes/interactive/components/armin.js.map +1 -1
  457. package/dist/modes/interactive/components/assistant-message.d.ts +5 -2
  458. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  459. package/dist/modes/interactive/components/assistant-message.js +13 -11
  460. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  461. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  462. package/dist/modes/interactive/components/bash-execution.js +4 -10
  463. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  464. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  465. package/dist/modes/interactive/components/bordered-loader.js +0 -3
  466. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  467. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  468. package/dist/modes/interactive/components/branch-summary-message.js +1 -3
  469. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  470. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  471. package/dist/modes/interactive/components/compaction-summary-message.js +1 -3
  472. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  473. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  474. package/dist/modes/interactive/components/config-selector.js +5 -22
  475. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  476. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
  477. package/dist/modes/interactive/components/countdown-timer.js +1 -7
  478. package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
  479. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  480. package/dist/modes/interactive/components/custom-editor.js +8 -8
  481. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  482. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
  483. package/dist/modes/interactive/components/custom-entry.js +1 -4
  484. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  485. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  486. package/dist/modes/interactive/components/custom-message.js +1 -7
  487. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  488. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
  489. package/dist/modes/interactive/components/daxnuts.js +6 -8
  490. package/dist/modes/interactive/components/daxnuts.js.map +1 -1
  491. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  492. package/dist/modes/interactive/components/diff.js.map +1 -1
  493. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  494. package/dist/modes/interactive/components/dynamic-border.js +0 -1
  495. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  496. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -1
  497. package/dist/modes/interactive/components/earendil-announcement.js.map +1 -1
  498. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  499. package/dist/modes/interactive/components/extension-editor.js +1 -7
  500. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  501. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  502. package/dist/modes/interactive/components/extension-input.js +2 -8
  503. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  504. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  505. package/dist/modes/interactive/components/extension-selector.js +1 -9
  506. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  507. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
  508. package/dist/modes/interactive/components/first-time-setup.js +2 -4
  509. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  510. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  511. package/dist/modes/interactive/components/footer.js +2 -4
  512. package/dist/modes/interactive/components/footer.js.map +1 -1
  513. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  514. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  515. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  516. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  517. package/dist/modes/interactive/components/login-dialog.js +3 -9
  518. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  519. package/dist/modes/interactive/components/markdown-transform.d.ts +3 -0
  520. package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -0
  521. package/dist/modes/interactive/components/markdown-transform.js +19 -0
  522. package/dist/modes/interactive/components/markdown-transform.js.map +1 -0
  523. package/dist/modes/interactive/components/mermaid.d.ts +11 -0
  524. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -0
  525. package/dist/modes/interactive/components/mermaid.js +75 -0
  526. package/dist/modes/interactive/components/mermaid.js.map +1 -0
  527. package/dist/modes/interactive/components/model-selector.d.ts +1 -1
  528. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  529. package/dist/modes/interactive/components/model-selector.js +28 -29
  530. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  531. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  532. package/dist/modes/interactive/components/oauth-selector.js +3 -11
  533. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  534. package/dist/modes/interactive/components/scoped-models-selector.d.ts +4 -0
  535. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  536. package/dist/modes/interactive/components/scoped-models-selector.js +34 -13
  537. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  538. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  539. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  540. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  541. package/dist/modes/interactive/components/session-selector.js +35 -60
  542. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  543. package/dist/modes/interactive/components/settings-selector.d.ts +8 -2
  544. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  545. package/dist/modes/interactive/components/settings-selector.js +30 -14
  546. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  547. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  548. package/dist/modes/interactive/components/show-images-selector.js +0 -1
  549. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  550. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  551. package/dist/modes/interactive/components/skill-invocation-message.js +1 -3
  552. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  553. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  554. package/dist/modes/interactive/components/status-indicator.js +0 -2
  555. package/dist/modes/interactive/components/status-indicator.js.map +1 -1
  556. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  557. package/dist/modes/interactive/components/theme-selector.js +0 -2
  558. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  559. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  560. package/dist/modes/interactive/components/thinking-selector.js +0 -1
  561. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  562. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  563. package/dist/modes/interactive/components/tool-execution.js +18 -36
  564. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  565. package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
  566. package/dist/modes/interactive/components/tool-group.js +2 -3
  567. package/dist/modes/interactive/components/tool-group.js.map +1 -1
  568. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  569. package/dist/modes/interactive/components/tree-selector.js +19 -39
  570. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  571. package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -1
  572. package/dist/modes/interactive/components/trust-selector.js +0 -6
  573. package/dist/modes/interactive/components/trust-selector.js.map +1 -1
  574. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  575. package/dist/modes/interactive/components/user-message-selector.js +3 -6
  576. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  577. package/dist/modes/interactive/components/user-message.d.ts +3 -1
  578. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  579. package/dist/modes/interactive/components/user-message.js +8 -5
  580. package/dist/modes/interactive/components/user-message.js.map +1 -1
  581. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
  582. package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
  583. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  584. package/dist/modes/interactive/external-editor.js.map +1 -1
  585. package/dist/modes/interactive/interactive-mode.d.ts +46 -4
  586. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  587. package/dist/modes/interactive/interactive-mode.js +518 -269
  588. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  589. package/dist/modes/interactive/model-search.d.ts.map +1 -1
  590. package/dist/modes/interactive/model-search.js.map +1 -1
  591. package/dist/modes/interactive/theme/dark.json +1 -0
  592. package/dist/modes/interactive/theme/light.json +1 -0
  593. package/dist/modes/interactive/theme/theme-controller.d.ts +3 -0
  594. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  595. package/dist/modes/interactive/theme/theme-controller.js +11 -8
  596. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  597. package/dist/modes/interactive/theme/theme-schema.json +5 -1
  598. package/dist/modes/interactive/theme/theme.d.ts +4 -4
  599. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  600. package/dist/modes/interactive/theme/theme.js +13 -9
  601. package/dist/modes/interactive/theme/theme.js.map +1 -1
  602. package/dist/modes/json-event.d.ts +28 -0
  603. package/dist/modes/json-event.d.ts.map +1 -0
  604. package/dist/modes/json-event.js +12 -0
  605. package/dist/modes/json-event.js.map +1 -0
  606. package/dist/modes/print-mode.d.ts.map +1 -1
  607. package/dist/modes/print-mode.js +12 -2
  608. package/dist/modes/print-mode.js.map +1 -1
  609. package/dist/modes/rpc/jsonl.d.ts.map +1 -1
  610. package/dist/modes/rpc/jsonl.js.map +1 -1
  611. package/dist/modes/rpc/rpc-client.d.ts +5 -4
  612. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  613. package/dist/modes/rpc/rpc-client.js +7 -8
  614. package/dist/modes/rpc/rpc-client.js.map +1 -1
  615. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  616. package/dist/modes/rpc/rpc-mode.js +4 -3
  617. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  618. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  619. package/dist/package-manager-cli.d.ts.map +1 -1
  620. package/dist/package-manager-cli.js +11 -9
  621. package/dist/package-manager-cli.js.map +1 -1
  622. package/dist/rpc-entry.d.ts.map +1 -1
  623. package/dist/rpc-entry.js +1 -0
  624. package/dist/rpc-entry.js.map +1 -1
  625. package/dist/utils/abort.d.ts +5 -0
  626. package/dist/utils/abort.d.ts.map +1 -0
  627. package/dist/utils/abort.js +48 -0
  628. package/dist/utils/abort.js.map +1 -0
  629. package/dist/utils/ansi.d.ts.map +1 -1
  630. package/dist/utils/ansi.js.map +1 -1
  631. package/dist/utils/changelog.d.ts.map +1 -1
  632. package/dist/utils/changelog.js.map +1 -1
  633. package/dist/utils/child-process.d.ts.map +1 -1
  634. package/dist/utils/child-process.js.map +1 -1
  635. package/dist/utils/clipboard-image.d.ts.map +1 -1
  636. package/dist/utils/clipboard-image.js.map +1 -1
  637. package/dist/utils/clipboard-native.d.ts.map +1 -1
  638. package/dist/utils/clipboard-native.js.map +1 -1
  639. package/dist/utils/clipboard.d.ts +1 -1
  640. package/dist/utils/clipboard.d.ts.map +1 -1
  641. package/dist/utils/clipboard.js +22 -2
  642. package/dist/utils/clipboard.js.map +1 -1
  643. package/dist/utils/coalescing-terminal.d.ts +1 -0
  644. package/dist/utils/coalescing-terminal.d.ts.map +1 -1
  645. package/dist/utils/coalescing-terminal.js +16 -8
  646. package/dist/utils/coalescing-terminal.js.map +1 -1
  647. package/dist/utils/deprecation.d.ts.map +1 -1
  648. package/dist/utils/deprecation.js.map +1 -1
  649. package/dist/utils/exif-orientation.d.ts.map +1 -1
  650. package/dist/utils/exif-orientation.js.map +1 -1
  651. package/dist/utils/frontmatter.d.ts.map +1 -1
  652. package/dist/utils/frontmatter.js.map +1 -1
  653. package/dist/utils/fs-watch.d.ts.map +1 -1
  654. package/dist/utils/fs-watch.js.map +1 -1
  655. package/dist/utils/git.d.ts.map +1 -1
  656. package/dist/utils/git.js.map +1 -1
  657. package/dist/utils/html.d.ts.map +1 -1
  658. package/dist/utils/html.js.map +1 -1
  659. package/dist/utils/image-convert.d.ts.map +1 -1
  660. package/dist/utils/image-convert.js.map +1 -1
  661. package/dist/utils/image-process.d.ts.map +1 -1
  662. package/dist/utils/image-process.js.map +1 -1
  663. package/dist/utils/image-resize-core.d.ts.map +1 -1
  664. package/dist/utils/image-resize-core.js.map +1 -1
  665. package/dist/utils/image-resize-worker.d.ts.map +1 -1
  666. package/dist/utils/image-resize-worker.js.map +1 -1
  667. package/dist/utils/image-resize.d.ts.map +1 -1
  668. package/dist/utils/image-resize.js.map +1 -1
  669. package/dist/utils/json.d.ts.map +1 -1
  670. package/dist/utils/json.js.map +1 -1
  671. package/dist/utils/management-http.d.ts +23 -0
  672. package/dist/utils/management-http.d.ts.map +1 -0
  673. package/dist/utils/management-http.js +50 -0
  674. package/dist/utils/management-http.js.map +1 -0
  675. package/dist/utils/mime.d.ts.map +1 -1
  676. package/dist/utils/mime.js.map +1 -1
  677. package/dist/utils/open-browser.d.ts.map +1 -1
  678. package/dist/utils/open-browser.js.map +1 -1
  679. package/dist/utils/paths.d.ts +3 -0
  680. package/dist/utils/paths.d.ts.map +1 -1
  681. package/dist/utils/paths.js +23 -1
  682. package/dist/utils/paths.js.map +1 -1
  683. package/dist/utils/photon.d.ts.map +1 -1
  684. package/dist/utils/photon.js.map +1 -1
  685. package/dist/utils/pi-user-agent.d.ts.map +1 -1
  686. package/dist/utils/pi-user-agent.js.map +1 -1
  687. package/dist/utils/shell.d.ts.map +1 -1
  688. package/dist/utils/shell.js.map +1 -1
  689. package/dist/utils/sleep.d.ts.map +1 -1
  690. package/dist/utils/sleep.js.map +1 -1
  691. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  692. package/dist/utils/syntax-highlight.js.map +1 -1
  693. package/dist/utils/tool-result-images.d.ts +19 -0
  694. package/dist/utils/tool-result-images.d.ts.map +1 -0
  695. package/dist/utils/tool-result-images.js +45 -0
  696. package/dist/utils/tool-result-images.js.map +1 -0
  697. package/dist/utils/tools-manager.d.ts.map +1 -1
  698. package/dist/utils/tools-manager.js +4 -6
  699. package/dist/utils/tools-manager.js.map +1 -1
  700. package/dist/utils/version-check.d.ts +4 -0
  701. package/dist/utils/version-check.d.ts.map +1 -1
  702. package/dist/utils/version-check.js +20 -2
  703. package/dist/utils/version-check.js.map +1 -1
  704. package/dist/utils/windows-self-update.d.ts.map +1 -1
  705. package/dist/utils/windows-self-update.js.map +1 -1
  706. package/docs/bundled/README.md +1 -0
  707. package/docs/bundled/extensions/biu.md +63 -0
  708. package/docs/bundled/extensions/router.md +20 -14
  709. package/docs/bundled/extensions/statusline.md +7 -5
  710. package/docs/custom-provider.md +123 -2
  711. package/docs/development.md +83 -0
  712. package/docs/docs.json +8 -4
  713. package/docs/extensions.md +27 -3
  714. package/docs/json.md +21 -2
  715. package/docs/keybindings.md +38 -10
  716. package/docs/models.md +21 -3
  717. package/docs/providers.md +1 -0
  718. package/docs/quickstart.md +2 -0
  719. package/docs/rpc.md +12 -11
  720. package/docs/sdk.md +46 -0
  721. package/docs/security.md +1 -1
  722. package/docs/settings.md +4 -1
  723. package/docs/themes.md +7 -5
  724. package/docs/usage.md +8 -0
  725. package/examples/extensions/custom-compaction.ts +1 -16
  726. package/examples/extensions/custom-provider-anthropic/index.ts +2 -1
  727. package/examples/extensions/custom-provider-gitlab-duo/index.ts +2 -1
  728. package/examples/extensions/doom-overlay/wad-finder.ts +7 -3
  729. package/examples/extensions/dynamic-resources/dynamic.json +1 -1
  730. package/examples/extensions/handoff.ts +2 -11
  731. package/examples/extensions/qna.ts +3 -7
  732. package/examples/extensions/summarize.ts +8 -18
  733. package/examples/rpc-extension-ui.ts +11 -2
  734. package/examples/sdk/02-custom-model.ts +1 -2
  735. package/examples/sdk/09-api-keys-and-oauth.ts +1 -1
  736. package/examples/sdk/12-full-control.ts +1 -1
  737. package/examples/sdk/README.md +1 -0
  738. package/npm-shrinkwrap.json +193 -264
  739. package/package.json +15 -8
@@ -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) => {
@@ -1259,6 +1378,7 @@ export class InteractiveMode {
1259
1378
  if (result.cancelled) {
1260
1379
  return { cancelled: true };
1261
1380
  }
1381
+ this.coalescingTerminal.passNextFullRedraw();
1262
1382
  this.clearChat();
1263
1383
  this.renderInitialMessages();
1264
1384
  if (result.editorText && !this.editor.getText().trim()) {
@@ -1292,8 +1412,12 @@ export class InteractiveMode {
1292
1412
  this.showLoadedResources({ force: false, showDiagnosticsWhenQuiet: true });
1293
1413
  this.showStartupNoticesIfNeeded();
1294
1414
  }
1415
+ applyFullscreenScrollbarSetting() {
1416
+ this.transcriptScrollView?.setScrollbar(this.settingsManager.getFullscreenScrollbar());
1417
+ }
1295
1418
  applyRuntimeSettings() {
1296
1419
  configureHttpDispatcher(this.settingsManager.getHttpIdleTimeoutMs());
1420
+ this.applyFullscreenScrollbarSetting();
1297
1421
  this.footer.setSession(this.session);
1298
1422
  this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled);
1299
1423
  this.footerDataProvider.setCwd(this.sessionManager.getCwd());
@@ -1362,6 +1486,10 @@ export class InteractiveMode {
1362
1486
  this.pendingTools.clear();
1363
1487
  }
1364
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();
1365
1493
  this.loadedResourcesContainer.clear();
1366
1494
  this.clearChat();
1367
1495
  this.pendingMessagesContainer.clear();
@@ -1405,6 +1533,9 @@ export class InteractiveMode {
1405
1533
  }
1406
1534
  this.chatContainer.addChild(component);
1407
1535
  }
1536
+ getMarkdownTransformers() {
1537
+ return [this.mermaidMarkdownTransformer, ...this.session.extensionRunner.getMarkdownTransformers()];
1538
+ }
1408
1539
  /**
1409
1540
  * Set up keyboard shortcuts registered by extensions.
1410
1541
  */
@@ -1484,7 +1615,7 @@ export class InteractiveMode {
1484
1615
  this.activeStatusIndicator?.dispose();
1485
1616
  this.activeStatusIndicator = undefined;
1486
1617
  this.statusContainer.clear();
1487
- if (hadActiveStatusIndicator && this.ui.getClearOnShrink()) {
1618
+ if (hadActiveStatusIndicator && this.options.tuiMode === "regular" && this.ui.getClearOnShrink()) {
1488
1619
  this.statusContainer.addChild(this.idleStatus);
1489
1620
  }
1490
1621
  }
@@ -1598,7 +1729,7 @@ export class InteractiveMode {
1598
1729
  this.setHiddenThinkingLabel();
1599
1730
  }
1600
1731
  // Maximum total widget lines to prevent viewport overflow
1601
- static MAX_WIDGET_LINES = 10;
1732
+ static { this.MAX_WIDGET_LINES = 10; }
1602
1733
  /**
1603
1734
  * Render all extension widgets to the widget container.
1604
1735
  */
@@ -1632,22 +1763,16 @@ export class InteractiveMode {
1632
1763
  if (this.customFooter?.dispose) {
1633
1764
  this.customFooter.dispose();
1634
1765
  }
1635
- // Remove current footer from UI
1636
- if (this.customFooter) {
1637
- this.ui.removeChild(this.customFooter);
1638
- }
1639
- else {
1640
- this.ui.removeChild(this.footer);
1641
- }
1766
+ this.footerContainer.clear();
1642
1767
  if (factory) {
1643
1768
  // Create and add custom footer, passing the data provider
1644
1769
  this.customFooter = factory(this.ui, theme, this.footerDataProvider);
1645
- this.ui.addChild(this.customFooter);
1770
+ this.footerContainer.addChild(this.customFooter);
1646
1771
  }
1647
1772
  else {
1648
1773
  // Restore built-in footer
1649
1774
  this.customFooter = undefined;
1650
- this.ui.addChild(this.footer);
1775
+ this.footerContainer.addChild(this.footer);
1651
1776
  }
1652
1777
  this.ui.requestRender();
1653
1778
  }
@@ -1693,18 +1818,27 @@ export class InteractiveMode {
1693
1818
  this.ui.requestRender();
1694
1819
  }
1695
1820
  addExtensionTerminalInputListener(handler) {
1696
- const unsubscribe = this.ui.addInputListener(handler);
1697
- this.extensionTerminalInputUnsubscribers.add(unsubscribe);
1821
+ const subscription = { handler, unsubscribe: this.ui.addInputListener(handler) };
1822
+ this.extensionTerminalInputSubscriptions.add(subscription);
1698
1823
  return () => {
1699
- unsubscribe();
1700
- this.extensionTerminalInputUnsubscribers.delete(unsubscribe);
1824
+ subscription.unsubscribe();
1825
+ this.extensionTerminalInputSubscriptions.delete(subscription);
1701
1826
  };
1702
1827
  }
1703
- clearExtensionTerminalInputListeners() {
1704
- for (const unsubscribe of this.extensionTerminalInputUnsubscribers) {
1705
- 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);
1706
1836
  }
1707
- this.extensionTerminalInputUnsubscribers.clear();
1837
+ }
1838
+ clearExtensionTerminalInputListeners() {
1839
+ for (const subscription of this.extensionTerminalInputSubscriptions)
1840
+ subscription.unsubscribe();
1841
+ this.extensionTerminalInputSubscriptions.clear();
1708
1842
  }
1709
1843
  /**
1710
1844
  * Create the ExtensionUIContext for extensions.
@@ -1805,6 +1939,7 @@ export class InteractiveMode {
1805
1939
  cancelHint: opts?.cancelHint,
1806
1940
  onToggleToolsExpanded: () => this.toggleToolOutputExpansion(),
1807
1941
  });
1942
+ this.disposeActiveSelector();
1808
1943
  this.editorContainer.clear();
1809
1944
  this.editorContainer.addChild(this.extensionSelector);
1810
1945
  this.ui.setFocus(this.extensionSelector);
@@ -1826,7 +1961,9 @@ export class InteractiveMode {
1826
1961
  * Show a confirmation dialog for extensions.
1827
1962
  */
1828
1963
  async showExtensionConfirm(title, message, opts) {
1829
- 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 });
1830
1967
  return result === "Yes";
1831
1968
  }
1832
1969
  async promptForMissingSessionCwd(error) {
@@ -1856,6 +1993,7 @@ export class InteractiveMode {
1856
1993
  this.hideExtensionInput();
1857
1994
  resolve(undefined);
1858
1995
  }, { tui: this.ui, timeout: opts?.timeout });
1996
+ this.disposeActiveSelector();
1859
1997
  this.editorContainer.clear();
1860
1998
  this.editorContainer.addChild(this.extensionInput);
1861
1999
  this.ui.setFocus(this.extensionInput);
@@ -1885,6 +2023,7 @@ export class InteractiveMode {
1885
2023
  this.hideExtensionEditor();
1886
2024
  resolve(undefined);
1887
2025
  }, undefined, this.settingsManager.getExternalEditorCommand());
2026
+ this.disposeActiveSelector();
1888
2027
  this.editorContainer.clear();
1889
2028
  this.editorContainer.addChild(this.extensionEditor);
1890
2029
  this.ui.setFocus(this.extensionEditor);
@@ -1909,6 +2048,7 @@ export class InteractiveMode {
1909
2048
  this.editorComponentFactory = factory;
1910
2049
  // Save text from current editor before switching
1911
2050
  const currentText = this.editor.getText();
2051
+ this.disposeActiveSelector();
1912
2052
  this.editorContainer.clear();
1913
2053
  if (factory) {
1914
2054
  // Create the custom editor with tui, theme, and keybindings
@@ -1925,6 +2065,9 @@ export class InteractiveMode {
1925
2065
  if (newEditor.setPaddingX !== undefined) {
1926
2066
  newEditor.setPaddingX(this.defaultEditor.getPaddingX());
1927
2067
  }
2068
+ if (newEditor.setAutocompleteMaxVisible !== undefined) {
2069
+ newEditor.setAutocompleteMaxVisible(this.defaultEditor.getAutocompleteMaxVisible());
2070
+ }
1928
2071
  // Set autocomplete if supported
1929
2072
  if (newEditor.setAutocompleteProvider && this.autocompleteProvider) {
1930
2073
  newEditor.setAutocompleteProvider(this.autocompleteProvider);
@@ -2029,6 +2172,7 @@ export class InteractiveMode {
2029
2172
  options?.onHandle?.(handle);
2030
2173
  }
2031
2174
  else {
2175
+ this.disposeActiveSelector();
2032
2176
  this.editorContainer.clear();
2033
2177
  this.editorContainer.addChild(component);
2034
2178
  this.ui.setFocus(component);
@@ -2115,7 +2259,7 @@ export class InteractiveMode {
2115
2259
  this.defaultEditor.onAction("app.tools.expand", () => this.toggleToolOutputExpansion());
2116
2260
  this.defaultEditor.onAction("app.thinking.toggle", () => this.toggleThinkingBlockVisibility());
2117
2261
  this.defaultEditor.onAction("app.editor.external", () => void this.handleOpenExternalEditor());
2118
- this.defaultEditor.onAction("app.message.copy", () => void this.handleCopyCommand());
2262
+ this.defaultEditor.onAction("app.message.copy", () => void this.handleCopyCommand({ flashConfirmation: true }));
2119
2263
  this.defaultEditor.onAction("app.message.followUp", () => this.handleFollowUp());
2120
2264
  this.defaultEditor.onAction("app.message.dequeue", () => this.handleDequeue());
2121
2265
  this.defaultEditor.onAction("app.session.new", () => this.handleClearCommand());
@@ -2416,17 +2560,17 @@ export class InteractiveMode {
2416
2560
  this.ui.requestRender();
2417
2561
  }
2418
2562
  else if (event.message.role === "assistant") {
2419
- 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());
2420
2564
  this.streamingMessage = event.message;
2421
2565
  this.chatContainer.addChild(this.streamingComponent);
2422
- this.streamingComponent.updateContent(this.streamingMessage);
2566
+ this.streamingComponent.updateContent(this.streamingMessage, true);
2423
2567
  this.ui.requestRender();
2424
2568
  }
2425
2569
  break;
2426
2570
  case "message_update":
2427
2571
  if (this.streamingComponent && event.message.role === "assistant") {
2428
2572
  this.streamingMessage = event.message;
2429
- this.streamingComponent.updateContent(this.streamingMessage);
2573
+ this.streamingComponent.updateContent(this.streamingMessage, true);
2430
2574
  for (const content of this.streamingMessage.content) {
2431
2575
  if (content.type === "toolCall") {
2432
2576
  if (!this.pendingTools.has(content.id)) {
@@ -2459,7 +2603,7 @@ export class InteractiveMode {
2459
2603
  : "Operation aborted";
2460
2604
  this.streamingMessage.errorMessage = errorMessage;
2461
2605
  }
2462
- this.streamingComponent.updateContent(this.streamingMessage);
2606
+ this.streamingComponent.updateContent(this.streamingMessage, false);
2463
2607
  if (this.streamingMessage.stopReason === "aborted" || this.streamingMessage.stopReason === "error") {
2464
2608
  if (!errorMessage) {
2465
2609
  errorMessage = this.streamingMessage.errorMessage || "Error";
@@ -2735,12 +2879,12 @@ export class InteractiveMode {
2735
2879
  // Render user message separately if present
2736
2880
  if (skillBlock.userMessage) {
2737
2881
  this.chatContainer.addChild(new Spacer(1));
2738
- const userComponent = new UserMessageComponent(skillBlock.userMessage, this.getMarkdownThemeWithSettings(), this.outputPad);
2882
+ const userComponent = new UserMessageComponent(skillBlock.userMessage, this.getMarkdownThemeWithSettings(), this.outputPad, this.getMarkdownTransformers());
2739
2883
  this.chatContainer.addChild(userComponent);
2740
2884
  }
2741
2885
  }
2742
2886
  else {
2743
- const userComponent = new UserMessageComponent(textContent, this.getMarkdownThemeWithSettings(), this.outputPad);
2887
+ const userComponent = new UserMessageComponent(textContent, this.getMarkdownThemeWithSettings(), this.outputPad, this.getMarkdownTransformers());
2744
2888
  this.chatContainer.addChild(userComponent);
2745
2889
  }
2746
2890
  if (options?.populateHistory) {
@@ -2750,7 +2894,7 @@ export class InteractiveMode {
2750
2894
  break;
2751
2895
  }
2752
2896
  case "assistant": {
2753
- 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());
2754
2898
  this.chatContainer.addChild(assistantComponent);
2755
2899
  break;
2756
2900
  }
@@ -2933,12 +3077,6 @@ export class InteractiveMode {
2933
3077
  // Only called when editor is empty (enforced by CustomEditor)
2934
3078
  void this.shutdown();
2935
3079
  }
2936
- /**
2937
- * Gracefully shutdown the agent.
2938
- * Stops the TUI before emitting shutdown events so extension UI cleanup cannot
2939
- * repaint the final frame while the process is exiting.
2940
- */
2941
- isShuttingDown = false;
2942
3080
  async shutdown(options) {
2943
3081
  if (this.isShuttingDown)
2944
3082
  return;
@@ -3180,6 +3318,8 @@ export class InteractiveMode {
3180
3318
  this.setToolsExpanded(!this.toolOutputExpanded);
3181
3319
  }
3182
3320
  setToolsExpanded(expanded) {
3321
+ if (expanded === this.toolOutputExpanded)
3322
+ return;
3183
3323
  this.toolOutputExpanded = expanded;
3184
3324
  // An explicit toggle prefers upstream's clean wipe-and-replay even
3185
3325
  // mid-run: the user just pressed the key, so they are interacting at
@@ -3242,7 +3382,7 @@ export class InteractiveMode {
3242
3382
  }
3243
3383
  showError(errorMessage) {
3244
3384
  this.chatContainer.addChild(new Spacer(1));
3245
- 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));
3246
3386
  this.ui.requestRender();
3247
3387
  }
3248
3388
  showWarning(warningMessage) {
@@ -3448,52 +3588,50 @@ export class InteractiveMode {
3448
3588
  // =========================================================================
3449
3589
  // Selectors
3450
3590
  // =========================================================================
3591
+ disposeActiveSelector() {
3592
+ const dispose = this.activeSelectorDispose;
3593
+ this.activeSelectorToken = undefined;
3594
+ this.activeSelectorDispose = undefined;
3595
+ dispose?.();
3596
+ }
3451
3597
  /**
3452
3598
  * Shows a selector component in place of the editor.
3453
3599
  * @param create Factory that receives a `done` callback and returns the component and focus target
3454
3600
  */
3455
3601
  showSelector(create) {
3456
- this.activeSelectorCleanup?.();
3457
- this.activeSelectorCleanup = null;
3458
- this.activeSelector = null;
3459
- let selector;
3602
+ const token = {};
3603
+ let dispose;
3460
3604
  let disposed = false;
3461
- let closed = false;
3462
- const dispose = () => {
3463
- if (disposed || !selector)
3605
+ const disposeOnce = () => {
3606
+ if (disposed)
3464
3607
  return;
3465
3608
  disposed = true;
3466
- selector.dispose?.();
3609
+ dispose?.();
3467
3610
  };
3468
3611
  const done = () => {
3469
- if (closed)
3612
+ disposeOnce();
3613
+ if (this.activeSelectorToken !== token)
3470
3614
  return;
3471
- closed = true;
3472
- dispose();
3473
- if (!selector || this.activeSelector === selector) {
3474
- this.activeSelector = null;
3475
- this.activeSelectorCleanup = null;
3476
- this.editorContainer.clear();
3477
- this.editorContainer.addChild(this.editor);
3478
- this.ui.setFocus(this.editor);
3479
- }
3615
+ this.activeSelectorToken = undefined;
3616
+ this.activeSelectorDispose = undefined;
3617
+ this.editorContainer.clear();
3618
+ this.editorContainer.addChild(this.editor);
3619
+ this.ui.setFocus(this.editor);
3480
3620
  };
3481
3621
  const created = create(done);
3482
- selector = created.component;
3483
- if (closed) {
3484
- dispose();
3485
- return;
3486
- }
3487
- this.activeSelector = selector;
3488
- this.activeSelectorCleanup = dispose;
3622
+ dispose = created.dispose;
3623
+ this.disposeActiveSelector();
3624
+ this.activeSelectorToken = token;
3625
+ this.activeSelectorDispose = disposeOnce;
3489
3626
  this.editorContainer.clear();
3490
- this.editorContainer.addChild(selector);
3627
+ this.editorContainer.addChild(created.component);
3491
3628
  this.ui.setFocus(created.focus);
3492
3629
  this.ui.requestRender();
3493
3630
  }
3494
3631
  showSettingsSelector() {
3495
3632
  this.showSelector((done) => {
3496
- const selector = new SettingsSelectorComponent({
3633
+ let selector;
3634
+ selector = new SettingsSelectorComponent({
3497
3635
  autoCompact: this.session.autoCompactionEnabled,
3498
3636
  showImages: this.settingsManager.getShowImages(),
3499
3637
  imageWidthCells: this.settingsManager.getImageWidthCells(),
@@ -3510,6 +3648,7 @@ export class InteractiveMode {
3510
3648
  terminalTheme: this.themeController.getTerminalTheme(),
3511
3649
  availableThemes: getAvailableThemes(),
3512
3650
  hideThinkingBlock: this.hideThinkingBlock,
3651
+ mermaidRenderingMode: this.settingsManager.getMermaidRenderingMode(),
3513
3652
  collapseChangelog: this.settingsManager.getCollapseChangelog(),
3514
3653
  enableInstallTelemetry: this.settingsManager.getEnableInstallTelemetry(),
3515
3654
  doubleEscapeAction: this.settingsManager.getDoubleEscapeAction(),
@@ -3523,6 +3662,8 @@ export class InteractiveMode {
3523
3662
  quietStartup: this.settingsManager.getQuietStartup(),
3524
3663
  clearOnShrink: this.settingsManager.getClearOnShrink(),
3525
3664
  showTerminalProgress: this.settingsManager.getShowTerminalProgress(),
3665
+ tuiMode: this.ui.mode,
3666
+ fullscreenScrollbar: this.settingsManager.getFullscreenScrollbar(),
3526
3667
  warnings: this.settingsManager.getWarnings(),
3527
3668
  }, {
3528
3669
  onAutoCompactChange: (enabled) => {
@@ -3591,6 +3732,11 @@ export class InteractiveMode {
3591
3732
  this.clearChat();
3592
3733
  this.rebuildChatFromMessages();
3593
3734
  },
3735
+ onMermaidRenderingModeChange: (mode) => {
3736
+ this.settingsManager.setMermaidRenderingMode(mode);
3737
+ this.chatContainer.invalidate();
3738
+ this.ui.requestRender();
3739
+ },
3594
3740
  onShowCacheMissNoticesChange: (shown) => {
3595
3741
  this.settingsManager.setShowCacheMissNotices(shown);
3596
3742
  this.rebuildChatFromMessages();
@@ -3660,6 +3806,21 @@ export class InteractiveMode {
3660
3806
  onShowTerminalProgressChange: (enabled) => {
3661
3807
  this.settingsManager.setShowTerminalProgress(enabled);
3662
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
+ },
3663
3824
  onWarningsChange: (warnings) => {
3664
3825
  this.settingsManager.setWarnings(warnings);
3665
3826
  },
@@ -3694,20 +3855,37 @@ export class InteractiveMode {
3694
3855
  this.showModelSelector(searchTerm);
3695
3856
  }
3696
3857
  async findExactModelMatch(searchTerm) {
3697
- const models = await this.getModelCandidates();
3698
- return findExactModelReferenceMatch(searchTerm, models);
3699
- }
3700
- async getModelCandidates() {
3701
- if (this.session.scopedModels.length > 0) {
3702
- return this.session.scopedModels.map((scoped) => scoped.model);
3703
- }
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);
3704
3871
  try {
3705
- await this.session.modelRuntime.refresh();
3706
- 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
+ }
3707
3879
  }
3708
- catch {
3709
- 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)}`);
3710
3884
  }
3885
+ finally {
3886
+ clearTimeout(timeout);
3887
+ }
3888
+ return findExactModelReferenceMatch(searchTerm, [...this.session.modelRuntime.getAvailableSnapshot()]);
3711
3889
  }
3712
3890
  /** Update the footer's available provider count from the current snapshot without refreshing catalogs. */
3713
3891
  updateAvailableProviderCount() {
@@ -3809,73 +3987,67 @@ export class InteractiveMode {
3809
3987
  done();
3810
3988
  this.ui.requestRender();
3811
3989
  }, initialSearchInput);
3812
- return { component: selector, focus: selector };
3990
+ return { component: selector, focus: selector, dispose: () => selector.dispose() };
3813
3991
  });
3814
3992
  }
3815
- async showModelsSelector() {
3816
- // Get all available models
3817
- await this.session.modelRuntime.refresh();
3818
- const allModels = [...(await this.session.modelRuntime.getAvailable())];
3819
- 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}`));
3820
3996
  const configuredPatterns = this.settingsManager.getEnabledModels();
3821
3997
  const sessionScopedModels = this.session.scopedModels;
3822
- if (allModels.length === 0 && !configuredPatterns?.length && sessionScopedModels.length === 0) {
3823
- this.showStatus("No models available");
3824
- return;
3825
- }
3826
- const configuredScope = configuredPatterns?.length
3827
- ? await resolveModelScopeWithDiagnostics(configuredPatterns, this.session.modelRuntime)
3828
- : undefined;
3829
- // Check if session has scoped models (from previous session-only changes or CLI --models)
3830
- const hasSessionScope = sessionScopedModels.length > 0;
3831
- // Build enabled model IDs from session state or settings
3832
- let currentEnabledIds = null;
3833
- if (hasSessionScope) {
3834
- // Use current session's scoped models
3835
- currentEnabledIds = sessionScopedModels.map((scoped) => `${scoped.model.provider}/${scoped.model.id}`);
3836
- }
3837
- else if (configuredScope) {
3838
- currentEnabledIds = configuredScope.scopedModels.map((scoped) => `${scoped.model.provider}/${scoped.model.id}`);
3839
- }
3840
- for (const diagnostic of configuredScope?.diagnostics ?? []) {
3841
- if (diagnostic.code !== "no-match")
3842
- continue;
3843
- currentEnabledIds ??= [];
3844
- if (!currentEnabledIds.includes(diagnostic.pattern))
3845
- currentEnabledIds.push(diagnostic.pattern);
3846
- }
3847
- // Helper to update session's scoped models (session-only, no persist)
3848
- 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) => {
3849
4014
  currentEnabledIds = enabledIds === null ? null : [...enabledIds];
3850
- const hasEnabledAvailableModel = enabledIds?.some((id) => allModelIds.has(id)) ?? false;
3851
- 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));
3852
4017
  if (enabledIds && hasEnabledAvailableModel && !allAvailableModelsEnabled) {
3853
- const newScopedModels = await resolveModelScope(enabledIds, this.session.modelRuntime);
3854
- this.session.setScopedModels(newScopedModels.map((sm) => ({
3855
- model: sm.model,
3856
- 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,
3857
4022
  })));
3858
4023
  }
3859
4024
  else {
3860
- // All enabled or none enabled = no filter
3861
4025
  this.session.setScopedModels([]);
3862
4026
  }
3863
- await this.updateAvailableProviderCount();
4027
+ this.updateAvailableProviderCount();
3864
4028
  this.ui.requestRender();
3865
4029
  };
3866
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);
3867
4038
  const selector = new ScopedModelsSelectorComponent({
3868
- allModels,
4039
+ allModels: availableModels,
3869
4040
  enabledModelIds: currentEnabledIds,
4041
+ refreshStatus: "Refreshing model catalogs…",
3870
4042
  }, {
3871
- onChange: async (enabledIds) => {
3872
- await updateSessionModels(enabledIds);
4043
+ onChange: (enabledIds) => {
4044
+ selectionChanged = true;
4045
+ updateSessionModels(enabledIds);
3873
4046
  },
3874
4047
  onPersist: (enabledIds) => {
3875
- // Persist to settings
3876
4048
  const allEnabled = enabledIds !== null &&
3877
- enabledIds.length === allModels.length &&
3878
- enabledIds.every((id) => allModelIds.has(id));
4049
+ enabledIds.length === availableModels.length &&
4050
+ enabledIds.every((id) => availableModelIds.has(id));
3879
4051
  const newPatterns = enabledIds === null || allEnabled ? undefined : enabledIds;
3880
4052
  this.settingsManager.setEnabledModels(newPatterns ? [...newPatterns] : undefined);
3881
4053
  this.showStatus("Model selection saved to settings");
@@ -3885,7 +4057,51 @@ export class InteractiveMode {
3885
4057
  this.ui.requestRender();
3886
4058
  },
3887
4059
  });
3888
- 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
+ };
3889
4105
  });
3890
4106
  }
3891
4107
  showUserMessageSelector() {
@@ -4014,6 +4230,9 @@ export class InteractiveMode {
4014
4230
  this.showStatus("Navigation cancelled");
4015
4231
  return;
4016
4232
  }
4233
+ // User-committed tree navigation rebuilds the transcript; its
4234
+ // full redraw bypasses scrollback preservation.
4235
+ this.coalescingTerminal.passNextFullRedraw();
4017
4236
  // Update UI
4018
4237
  this.clearChat();
4019
4238
  this.renderInitialMessages();
@@ -4147,7 +4366,7 @@ export class InteractiveMode {
4147
4366
  return options.sort((a, b) => a.name.localeCompare(b.name));
4148
4367
  }
4149
4368
  async getLogoutProviderOptions() {
4150
- return (await this.session.modelRuntime.listCredentials())
4369
+ return (await this.session.modelRuntime.listCredentials({ signal: AbortSignal.timeout(15_000) }))
4151
4370
  .map(({ providerId, type }) => ({
4152
4371
  id: providerId,
4153
4372
  name: this.session.modelRuntime.getProvider(providerId)?.name ?? providerId,
@@ -4165,7 +4384,6 @@ export class InteractiveMode {
4165
4384
  provider.name.toLowerCase() === normalizedProviderRef);
4166
4385
  }
4167
4386
  async handleLoginCommand(providerRef) {
4168
- await this.session.modelRuntime.getAvailable();
4169
4387
  if (!providerRef) {
4170
4388
  this.showLoginAuthTypeSelector();
4171
4389
  return;
@@ -4279,7 +4497,14 @@ export class InteractiveMode {
4279
4497
  this.showLoginAuthTypeSelector();
4280
4498
  return;
4281
4499
  }
4282
- 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
+ }
4283
4508
  if (providerOptions.length === 0) {
4284
4509
  this.showStatus("No stored credentials to remove. /logout only removes credentials saved by /login; environment variables and models.json config are unchanged.");
4285
4510
  return;
@@ -4292,7 +4517,9 @@ export class InteractiveMode {
4292
4517
  return;
4293
4518
  }
4294
4519
  try {
4295
- await this.session.modelRuntime.logout(providerOption.id);
4520
+ await this.session.modelRuntime.logout(providerOption.id, {
4521
+ signal: AbortSignal.timeout(15_000),
4522
+ });
4296
4523
  await this.updateAvailableProviderCount();
4297
4524
  const message = providerOption.authType === "oauth"
4298
4525
  ? `Logged out of ${providerOption.name}`
@@ -4300,7 +4527,10 @@ export class InteractiveMode {
4300
4527
  this.showStatus(message);
4301
4528
  }
4302
4529
  catch (error) {
4303
- 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}`);
4304
4534
  }
4305
4535
  }, () => {
4306
4536
  done();
@@ -4310,12 +4540,11 @@ export class InteractiveMode {
4310
4540
  });
4311
4541
  }
4312
4542
  async completeProviderAuthentication(providerId, providerName, authType, previousModel) {
4313
- await this.session.modelRuntime.getAvailable();
4314
4543
  const actionLabel = authType === "oauth" ? `Logged in to ${providerName}` : `Saved API key for ${providerName}`;
4315
4544
  let selectedModel;
4316
4545
  let selectionError;
4317
4546
  if (isUnknownModel(previousModel)) {
4318
- const availableModels = await this.session.modelRuntime.getAvailable();
4547
+ const availableModels = this.session.modelRuntime.getAvailableSnapshot();
4319
4548
  const providerModels = availableModels.filter((model) => model.provider === providerId);
4320
4549
  if (!hasDefaultModelProvider(providerId)) {
4321
4550
  selectionError = `${actionLabel}, but no default model is configured for provider "${providerId}". Use /model to select a model.`;
@@ -4358,6 +4587,25 @@ export class InteractiveMode {
4358
4587
  void this.maybeWarnAboutAnthropicSubscriptionAuth();
4359
4588
  }
4360
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));
4361
4609
  }
4362
4610
  showAmbientAuthDialog(providerOption) {
4363
4611
  const restoreEditor = () => {
@@ -4403,7 +4651,10 @@ export class InteractiveMode {
4403
4651
  catch (error) {
4404
4652
  restoreEditor();
4405
4653
  const errorMsg = error instanceof Error ? error.message : String(error);
4406
- 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") {
4407
4658
  this.showError(`Failed to save API key for ${providerName}: ${errorMsg}`);
4408
4659
  }
4409
4660
  }
@@ -4506,7 +4757,10 @@ export class InteractiveMode {
4506
4757
  catch (error) {
4507
4758
  restoreEditor();
4508
4759
  const errorMsg = error instanceof Error ? error.message : String(error);
4509
- 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") {
4510
4764
  this.showError(`Failed to login to ${providerName}: ${errorMsg}`);
4511
4765
  }
4512
4766
  }
@@ -4551,13 +4805,16 @@ export class InteractiveMode {
4551
4805
  }
4552
4806
  this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
4553
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();
4554
4812
  this.rebuildChatFromMessages();
4555
4813
  chatRestoredBeforeSessionStart = true;
4556
4814
  };
4557
4815
  try {
4558
4816
  await this.session.reload({ beforeSessionStart: restoreChatBeforeSessionStart });
4559
4817
  restoreChatBeforeSessionStart();
4560
- configureHttpDispatcher(this.settingsManager.getHttpIdleTimeoutMs());
4561
4818
  this.keybindings.reload();
4562
4819
  const activeHeader = this.customHeader ?? this.builtInHeader;
4563
4820
  if (isExpandable(activeHeader)) {
@@ -4565,20 +4822,7 @@ export class InteractiveMode {
4565
4822
  }
4566
4823
  setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
4567
4824
  await this.themeController.applyFromSettings();
4568
- const editorPaddingX = this.settingsManager.getEditorPaddingX();
4569
- const autocompleteMaxVisible = this.settingsManager.getAutocompleteMaxVisible();
4570
- this.defaultEditor.setPaddingX(editorPaddingX);
4571
- this.defaultEditor.setAutocompleteMaxVisible(autocompleteMaxVisible);
4572
- if (this.editor !== this.defaultEditor) {
4573
- this.editor.setPaddingX?.(editorPaddingX);
4574
- this.editor.setAutocompleteMaxVisible?.(autocompleteMaxVisible);
4575
- }
4576
- this.ui.setShowHardwareCursor(this.settingsManager.getShowHardwareCursor());
4577
- const clearOnShrink = this.settingsManager.getClearOnShrink();
4578
- this.ui.setClearOnShrink(clearOnShrink);
4579
- if (!clearOnShrink && !this.activeStatusIndicator) {
4580
- this.statusContainer.clear();
4581
- }
4825
+ this.applyRuntimeSettings();
4582
4826
  this.setupAutocompleteProvider();
4583
4827
  const runner = this.session.extensionRunner;
4584
4828
  this.setupExtensionShortcuts(runner);
@@ -4774,7 +5018,7 @@ export class InteractiveMode {
4774
5018
  }
4775
5019
  }
4776
5020
  }
4777
- async handleCopyCommand() {
5021
+ async handleCopyCommand(options = {}) {
4778
5022
  const text = this.session.getLastAssistantText();
4779
5023
  if (!text) {
4780
5024
  this.showError("No agent messages to copy yet.");
@@ -4782,7 +5026,12 @@ export class InteractiveMode {
4782
5026
  }
4783
5027
  try {
4784
5028
  await copyToClipboard(text);
4785
- 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
+ }
4786
5035
  }
4787
5036
  catch (error) {
4788
5037
  this.showError(error instanceof Error ? error.message : String(error));
@@ -5145,15 +5394,15 @@ export class InteractiveMode {
5145
5394
  }
5146
5395
  }
5147
5396
  stop() {
5148
- this.activeSelectorCleanup?.();
5149
- this.activeSelectorCleanup = null;
5150
- this.activeSelector = null;
5397
+ this.disposeActiveSelector();
5151
5398
  if (this.settingsManager.getShowTerminalProgress()) {
5152
5399
  this.ui.terminal.setProgress(false);
5153
5400
  }
5154
5401
  this.clearStatusIndicator();
5155
5402
  this.themeController.disableAutoSync();
5156
5403
  this.clearExtensionTerminalInputListeners();
5404
+ this.scrollbackPreservationInputUnsubscribe?.();
5405
+ this.scrollbackPreservationInputUnsubscribe = undefined;
5157
5406
  this.clearPendingTools();
5158
5407
  this.disposeChatToolComponents();
5159
5408
  this.footer.dispose();
@@ -5162,7 +5411,7 @@ export class InteractiveMode {
5162
5411
  this.unsubscribe();
5163
5412
  }
5164
5413
  if (this.isInitialized) {
5165
- this.ui.stop();
5414
+ this.stopInteractiveTui();
5166
5415
  this.isInitialized = false;
5167
5416
  }
5168
5417
  this.unregisterSignalHandlers();