@astralyn/pi 0.83.0 → 0.84.1

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 (768) hide show
  1. package/CHANGELOG.md +66 -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 +22 -3
  10. package/dist/cli/args.js.map +1 -1
  11. package/dist/cli/auth-check.d.ts +19 -0
  12. package/dist/cli/auth-check.d.ts.map +1 -0
  13. package/dist/cli/auth-check.js +50 -0
  14. package/dist/cli/auth-check.js.map +1 -0
  15. package/dist/cli/auth-command.d.ts +24 -0
  16. package/dist/cli/auth-command.d.ts.map +1 -0
  17. package/dist/cli/auth-command.js +104 -0
  18. package/dist/cli/auth-command.js.map +1 -0
  19. package/dist/cli/config-selector.d.ts.map +1 -1
  20. package/dist/cli/config-selector.js +2 -2
  21. package/dist/cli/config-selector.js.map +1 -1
  22. package/dist/cli/credential-print.d.ts +5 -15
  23. package/dist/cli/credential-print.d.ts.map +1 -1
  24. package/dist/cli/credential-print.js +42 -82
  25. package/dist/cli/credential-print.js.map +1 -1
  26. package/dist/cli/experimental/auth.d.ts +16 -0
  27. package/dist/cli/experimental/auth.d.ts.map +1 -0
  28. package/dist/cli/experimental/auth.js +13 -0
  29. package/dist/cli/experimental/auth.js.map +1 -0
  30. package/dist/cli/experimental/cli.d.ts +6 -0
  31. package/dist/cli/experimental/cli.d.ts.map +1 -0
  32. package/dist/cli/experimental/cli.js +5 -0
  33. package/dist/cli/experimental/cli.js.map +1 -0
  34. package/dist/cli/experimental/command-options.d.ts +17 -0
  35. package/dist/cli/experimental/command-options.d.ts.map +1 -0
  36. package/dist/cli/experimental/command-options.js +35 -0
  37. package/dist/cli/experimental/command-options.js.map +1 -0
  38. package/dist/cli/experimental/command.d.ts +63 -0
  39. package/dist/cli/experimental/command.d.ts.map +1 -0
  40. package/dist/cli/experimental/command.js +127 -0
  41. package/dist/cli/experimental/command.js.map +1 -0
  42. package/dist/cli/experimental/commands/client.d.ts +13 -0
  43. package/dist/cli/experimental/commands/client.d.ts.map +1 -0
  44. package/dist/cli/experimental/commands/client.js +25 -0
  45. package/dist/cli/experimental/commands/client.js.map +1 -0
  46. package/dist/cli/experimental/commands/pi.d.ts +15 -0
  47. package/dist/cli/experimental/commands/pi.d.ts.map +1 -0
  48. package/dist/cli/experimental/commands/pi.js +28 -0
  49. package/dist/cli/experimental/commands/pi.js.map +1 -0
  50. package/dist/cli/experimental/commands/server.d.ts +13 -0
  51. package/dist/cli/experimental/commands/server.d.ts.map +1 -0
  52. package/dist/cli/experimental/commands/server.js +25 -0
  53. package/dist/cli/experimental/commands/server.js.map +1 -0
  54. package/dist/cli/experimental/transport-address.d.ts +10 -0
  55. package/dist/cli/experimental/transport-address.d.ts.map +1 -0
  56. package/dist/cli/experimental/transport-address.js +38 -0
  57. package/dist/cli/experimental/transport-address.js.map +1 -0
  58. package/dist/cli/file-processor.d.ts.map +1 -1
  59. package/dist/cli/file-processor.js.map +1 -1
  60. package/dist/cli/initial-message.d.ts +1 -1
  61. package/dist/cli/initial-message.d.ts.map +1 -1
  62. package/dist/cli/initial-message.js.map +1 -1
  63. package/dist/cli/list-models.d.ts +1 -1
  64. package/dist/cli/list-models.d.ts.map +1 -1
  65. package/dist/cli/list-models.js +2 -2
  66. package/dist/cli/list-models.js.map +1 -1
  67. package/dist/cli/project-trust.d.ts.map +1 -1
  68. package/dist/cli/project-trust.js.map +1 -1
  69. package/dist/cli/session-picker.d.ts.map +1 -1
  70. package/dist/cli/session-picker.js.map +1 -1
  71. package/dist/cli/startup-ui.d.ts +1 -1
  72. package/dist/cli/startup-ui.d.ts.map +1 -1
  73. package/dist/cli/startup-ui.js +2 -2
  74. package/dist/cli/startup-ui.js.map +1 -1
  75. package/dist/cli.d.ts.map +1 -1
  76. package/dist/cli.js +1 -0
  77. package/dist/cli.js.map +1 -1
  78. package/dist/client/index.d.ts +3 -0
  79. package/dist/client/index.d.ts.map +1 -0
  80. package/dist/client/index.js +3 -0
  81. package/dist/client/index.js.map +1 -0
  82. package/dist/client/remote-session.d.ts +53 -0
  83. package/dist/client/remote-session.d.ts.map +1 -0
  84. package/dist/client/remote-session.js +340 -0
  85. package/dist/client/remote-session.js.map +1 -0
  86. package/dist/client/transcript.d.ts +12 -0
  87. package/dist/client/transcript.d.ts.map +1 -0
  88. package/dist/client/transcript.js +98 -0
  89. package/dist/client/transcript.js.map +1 -0
  90. package/dist/config.d.ts.map +1 -1
  91. package/dist/config.js.map +1 -1
  92. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  93. package/dist/core/agent-session-runtime.js +0 -8
  94. package/dist/core/agent-session-runtime.js.map +1 -1
  95. package/dist/core/agent-session-services.d.ts +1 -0
  96. package/dist/core/agent-session-services.d.ts.map +1 -1
  97. package/dist/core/agent-session-services.js +1 -0
  98. package/dist/core/agent-session-services.js.map +1 -1
  99. package/dist/core/agent-session.d.ts +30 -10
  100. package/dist/core/agent-session.d.ts.map +1 -1
  101. package/dist/core/agent-session.js +177 -187
  102. package/dist/core/agent-session.js.map +1 -1
  103. package/dist/core/auth-guidance.d.ts.map +1 -1
  104. package/dist/core/auth-guidance.js.map +1 -1
  105. package/dist/core/auth-storage.d.ts +25 -9
  106. package/dist/core/auth-storage.d.ts.map +1 -1
  107. package/dist/core/auth-storage.js +235 -42
  108. package/dist/core/auth-storage.js.map +1 -1
  109. package/dist/core/bash-executor.d.ts.map +1 -1
  110. package/dist/core/bash-executor.js.map +1 -1
  111. package/dist/core/cache-stats.d.ts.map +1 -1
  112. package/dist/core/cache-stats.js.map +1 -1
  113. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  114. package/dist/core/compaction/branch-summarization.js.map +1 -1
  115. package/dist/core/compaction/compaction.d.ts.map +1 -1
  116. package/dist/core/compaction/compaction.js.map +1 -1
  117. package/dist/core/compaction/index.d.ts.map +1 -1
  118. package/dist/core/compaction/utils.d.ts.map +1 -1
  119. package/dist/core/compaction/utils.js.map +1 -1
  120. package/dist/core/defaults.d.ts.map +1 -1
  121. package/dist/core/diagnostics.d.ts.map +1 -1
  122. package/dist/core/event-bus.d.ts.map +1 -1
  123. package/dist/core/event-bus.js.map +1 -1
  124. package/dist/core/exec.d.ts.map +1 -1
  125. package/dist/core/exec.js.map +1 -1
  126. package/dist/core/experimental.d.ts.map +1 -1
  127. package/dist/core/experimental.js.map +1 -1
  128. package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
  129. package/dist/core/export-html/ansi-to-html.js.map +1 -1
  130. package/dist/core/export-html/index.d.ts.map +1 -1
  131. package/dist/core/export-html/index.js.map +1 -1
  132. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  133. package/dist/core/export-html/tool-renderer.js.map +1 -1
  134. package/dist/core/extensions/index.d.ts +1 -1
  135. package/dist/core/extensions/index.d.ts.map +1 -1
  136. package/dist/core/extensions/index.js.map +1 -1
  137. package/dist/core/extensions/loader.d.ts.map +1 -1
  138. package/dist/core/extensions/loader.js +43 -20
  139. package/dist/core/extensions/loader.js.map +1 -1
  140. package/dist/core/extensions/runner.d.ts +2 -1
  141. package/dist/core/extensions/runner.d.ts.map +1 -1
  142. package/dist/core/extensions/runner.js +25 -29
  143. package/dist/core/extensions/runner.js.map +1 -1
  144. package/dist/core/extensions/types.d.ts +26 -3
  145. package/dist/core/extensions/types.d.ts.map +1 -1
  146. package/dist/core/extensions/types.js.map +1 -1
  147. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  148. package/dist/core/extensions/wrapper.js.map +1 -1
  149. package/dist/core/footer-data-provider.d.ts.map +1 -1
  150. package/dist/core/footer-data-provider.js +17 -18
  151. package/dist/core/footer-data-provider.js.map +1 -1
  152. package/dist/core/http-dispatcher.d.ts.map +1 -1
  153. package/dist/core/http-dispatcher.js +5 -0
  154. package/dist/core/http-dispatcher.js.map +1 -1
  155. package/dist/core/index.d.ts.map +1 -1
  156. package/dist/core/keybindings.d.ts +165 -125
  157. package/dist/core/keybindings.d.ts.map +1 -1
  158. package/dist/core/keybindings.js +0 -1
  159. package/dist/core/keybindings.js.map +1 -1
  160. package/dist/core/messages.d.ts.map +1 -1
  161. package/dist/core/messages.js.map +1 -1
  162. package/dist/core/model-config.d.ts +37 -13
  163. package/dist/core/model-config.d.ts.map +1 -1
  164. package/dist/core/model-config.js +4 -2
  165. package/dist/core/model-config.js.map +1 -1
  166. package/dist/core/model-registry.d.ts +5 -3
  167. package/dist/core/model-registry.d.ts.map +1 -1
  168. package/dist/core/model-registry.js +13 -11
  169. package/dist/core/model-registry.js.map +1 -1
  170. package/dist/core/model-resolver.d.ts +4 -3
  171. package/dist/core/model-resolver.d.ts.map +1 -1
  172. package/dist/core/model-resolver.js +42 -10
  173. package/dist/core/model-resolver.js.map +1 -1
  174. package/dist/core/model-runtime.d.ts +30 -13
  175. package/dist/core/model-runtime.d.ts.map +1 -1
  176. package/dist/core/model-runtime.js +241 -91
  177. package/dist/core/model-runtime.js.map +1 -1
  178. package/dist/core/models-store.d.ts +12 -7
  179. package/dist/core/models-store.d.ts.map +1 -1
  180. package/dist/core/models-store.js +84 -16
  181. package/dist/core/models-store.js.map +1 -1
  182. package/dist/core/output-guard.d.ts.map +1 -1
  183. package/dist/core/output-guard.js.map +1 -1
  184. package/dist/core/package-manager.d.ts +4 -1
  185. package/dist/core/package-manager.d.ts.map +1 -1
  186. package/dist/core/package-manager.js +63 -42
  187. package/dist/core/package-manager.js.map +1 -1
  188. package/dist/core/pi-manifest.d.ts +8 -0
  189. package/dist/core/pi-manifest.d.ts.map +1 -0
  190. package/dist/core/pi-manifest.js +25 -0
  191. package/dist/core/pi-manifest.js.map +1 -0
  192. package/dist/core/project-trust.d.ts.map +1 -1
  193. package/dist/core/project-trust.js.map +1 -1
  194. package/dist/core/prompt-templates.d.ts.map +1 -1
  195. package/dist/core/prompt-templates.js.map +1 -1
  196. package/dist/core/provider-attribution.d.ts.map +1 -1
  197. package/dist/core/provider-attribution.js.map +1 -1
  198. package/dist/core/provider-composer.d.ts +4 -1
  199. package/dist/core/provider-composer.d.ts.map +1 -1
  200. package/dist/core/provider-composer.js +36 -15
  201. package/dist/core/provider-composer.js.map +1 -1
  202. package/dist/core/radius.d.ts.map +1 -1
  203. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  204. package/dist/core/remote-catalog-provider.js +73 -67
  205. package/dist/core/remote-catalog-provider.js.map +1 -1
  206. package/dist/core/resolve-config-value.d.ts.map +1 -1
  207. package/dist/core/resolve-config-value.js.map +1 -1
  208. package/dist/core/resource-loader.d.ts.map +1 -1
  209. package/dist/core/resource-loader.js +2 -46
  210. package/dist/core/resource-loader.js.map +1 -1
  211. package/dist/core/runtime-credentials.d.ts +5 -5
  212. package/dist/core/runtime-credentials.d.ts.map +1 -1
  213. package/dist/core/runtime-credentials.js +12 -10
  214. package/dist/core/runtime-credentials.js.map +1 -1
  215. package/dist/core/sdk.d.ts.map +1 -1
  216. package/dist/core/sdk.js.map +1 -1
  217. package/dist/core/session-cwd.d.ts.map +1 -1
  218. package/dist/core/session-cwd.js +0 -1
  219. package/dist/core/session-cwd.js.map +1 -1
  220. package/dist/core/session-manager.d.ts.map +1 -1
  221. package/dist/core/session-manager.js +10 -12
  222. package/dist/core/session-manager.js.map +1 -1
  223. package/dist/core/settings-manager.d.ts +12 -0
  224. package/dist/core/settings-manager.d.ts.map +1 -1
  225. package/dist/core/settings-manager.js +47 -33
  226. package/dist/core/settings-manager.js.map +1 -1
  227. package/dist/core/skills.d.ts.map +1 -1
  228. package/dist/core/skills.js.map +1 -1
  229. package/dist/core/slash-commands.d.ts.map +1 -1
  230. package/dist/core/source-info.d.ts.map +1 -1
  231. package/dist/core/source-info.js.map +1 -1
  232. package/dist/core/system-prompt.d.ts.map +1 -1
  233. package/dist/core/system-prompt.js.map +1 -1
  234. package/dist/core/telemetry.d.ts.map +1 -1
  235. package/dist/core/telemetry.js.map +1 -1
  236. package/dist/core/timings.d.ts.map +1 -1
  237. package/dist/core/timings.js.map +1 -1
  238. package/dist/core/tools/bash.d.ts +4 -0
  239. package/dist/core/tools/bash.d.ts.map +1 -1
  240. package/dist/core/tools/bash.js +18 -14
  241. package/dist/core/tools/bash.js.map +1 -1
  242. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  243. package/dist/core/tools/edit-diff.js.map +1 -1
  244. package/dist/core/tools/edit.d.ts +4 -0
  245. package/dist/core/tools/edit.d.ts.map +1 -1
  246. package/dist/core/tools/edit.js +15 -10
  247. package/dist/core/tools/edit.js.map +1 -1
  248. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  249. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  250. package/dist/core/tools/find.d.ts +7 -0
  251. package/dist/core/tools/find.d.ts.map +1 -1
  252. package/dist/core/tools/find.js +18 -17
  253. package/dist/core/tools/find.js.map +1 -1
  254. package/dist/core/tools/grep.d.ts +4 -0
  255. package/dist/core/tools/grep.d.ts.map +1 -1
  256. package/dist/core/tools/grep.js +5 -1
  257. package/dist/core/tools/grep.js.map +1 -1
  258. package/dist/core/tools/index.d.ts.map +1 -1
  259. package/dist/core/tools/index.js.map +1 -1
  260. package/dist/core/tools/ls.d.ts +4 -0
  261. package/dist/core/tools/ls.d.ts.map +1 -1
  262. package/dist/core/tools/ls.js +5 -1
  263. package/dist/core/tools/ls.js.map +1 -1
  264. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  265. package/dist/core/tools/output-accumulator.js +12 -18
  266. package/dist/core/tools/output-accumulator.js.map +1 -1
  267. package/dist/core/tools/path-utils.d.ts.map +1 -1
  268. package/dist/core/tools/path-utils.js.map +1 -1
  269. package/dist/core/tools/read.d.ts +4 -0
  270. package/dist/core/tools/read.d.ts.map +1 -1
  271. package/dist/core/tools/read.js +7 -3
  272. package/dist/core/tools/read.js.map +1 -1
  273. package/dist/core/tools/render-utils.d.ts.map +1 -1
  274. package/dist/core/tools/render-utils.js.map +1 -1
  275. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  276. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  277. package/dist/core/tools/truncate.d.ts.map +1 -1
  278. package/dist/core/tools/truncate.js.map +1 -1
  279. package/dist/core/tools/write.d.ts +4 -0
  280. package/dist/core/tools/write.d.ts.map +1 -1
  281. package/dist/core/tools/write.js +6 -3
  282. package/dist/core/tools/write.js.map +1 -1
  283. package/dist/core/trust-manager.d.ts.map +1 -1
  284. package/dist/core/trust-manager.js +0 -1
  285. package/dist/core/trust-manager.js.map +1 -1
  286. package/dist/core/usage-totals.d.ts.map +1 -1
  287. package/dist/core/usage-totals.js.map +1 -1
  288. package/dist/extensions/biu/index.d.ts +19 -0
  289. package/dist/extensions/biu/index.d.ts.map +1 -0
  290. package/dist/extensions/biu/index.js +350 -0
  291. package/dist/extensions/biu/index.js.map +1 -0
  292. package/dist/extensions/biu/prompts.d.ts +26 -0
  293. package/dist/extensions/biu/prompts.d.ts.map +1 -0
  294. package/dist/extensions/biu/prompts.js +260 -0
  295. package/dist/extensions/biu/prompts.js.map +1 -0
  296. package/dist/extensions/biu/workspace.d.ts +122 -0
  297. package/dist/extensions/biu/workspace.d.ts.map +1 -0
  298. package/dist/extensions/biu/workspace.js +404 -0
  299. package/dist/extensions/biu/workspace.js.map +1 -0
  300. package/dist/extensions/deepwiki/client.d.ts.map +1 -1
  301. package/dist/extensions/deepwiki/client.js.map +1 -1
  302. package/dist/extensions/deepwiki/constants.d.ts.map +1 -1
  303. package/dist/extensions/deepwiki/constants.js.map +1 -1
  304. package/dist/extensions/deepwiki/contents.d.ts.map +1 -1
  305. package/dist/extensions/deepwiki/contents.js.map +1 -1
  306. package/dist/extensions/deepwiki/execute.d.ts.map +1 -1
  307. package/dist/extensions/deepwiki/execute.js.map +1 -1
  308. package/dist/extensions/deepwiki/http.d.ts.map +1 -1
  309. package/dist/extensions/deepwiki/http.js.map +1 -1
  310. package/dist/extensions/deepwiki/index.d.ts.map +1 -1
  311. package/dist/extensions/deepwiki/index.js.map +1 -1
  312. package/dist/extensions/deepwiki/render.d.ts.map +1 -1
  313. package/dist/extensions/deepwiki/render.js.map +1 -1
  314. package/dist/extensions/deepwiki/schema.d.ts +1 -1
  315. package/dist/extensions/deepwiki/schema.d.ts.map +1 -1
  316. package/dist/extensions/deepwiki/schema.js.map +1 -1
  317. package/dist/extensions/index.d.ts.map +1 -1
  318. package/dist/extensions/index.js +2 -0
  319. package/dist/extensions/index.js.map +1 -1
  320. package/dist/extensions/llama/client.d.ts.map +1 -1
  321. package/dist/extensions/llama/client.js +0 -2
  322. package/dist/extensions/llama/client.js.map +1 -1
  323. package/dist/extensions/llama/huggingface.d.ts.map +1 -1
  324. package/dist/extensions/llama/huggingface.js +0 -2
  325. package/dist/extensions/llama/huggingface.js.map +1 -1
  326. package/dist/extensions/llama/index.d.ts.map +1 -1
  327. package/dist/extensions/llama/index.js +11 -2
  328. package/dist/extensions/llama/index.js.map +1 -1
  329. package/dist/extensions/llama/provider.d.ts.map +1 -1
  330. package/dist/extensions/llama/provider.js +21 -7
  331. package/dist/extensions/llama/provider.js.map +1 -1
  332. package/dist/extensions/llama/ui.d.ts.map +1 -1
  333. package/dist/extensions/llama/ui.js +12 -28
  334. package/dist/extensions/llama/ui.js.map +1 -1
  335. package/dist/extensions/question/constants.d.ts.map +1 -1
  336. package/dist/extensions/question/constants.js.map +1 -1
  337. package/dist/extensions/question/dialog-primitives.d.ts.map +1 -1
  338. package/dist/extensions/question/dialog-primitives.js.map +1 -1
  339. package/dist/extensions/question/dialog.d.ts.map +1 -1
  340. package/dist/extensions/question/dialog.js.map +1 -1
  341. package/dist/extensions/question/index.d.ts.map +1 -1
  342. package/dist/extensions/question/index.js.map +1 -1
  343. package/dist/extensions/question/limits.d.ts.map +1 -1
  344. package/dist/extensions/question/render-cache.d.ts.map +1 -1
  345. package/dist/extensions/question/render-cache.js +3 -4
  346. package/dist/extensions/question/render-cache.js.map +1 -1
  347. package/dist/extensions/question/render.d.ts.map +1 -1
  348. package/dist/extensions/question/render.js.map +1 -1
  349. package/dist/extensions/question/results.d.ts.map +1 -1
  350. package/dist/extensions/question/results.js.map +1 -1
  351. package/dist/extensions/question/schema.d.ts.map +1 -1
  352. package/dist/extensions/question/schema.js.map +1 -1
  353. package/dist/extensions/question/state.d.ts.map +1 -1
  354. package/dist/extensions/question/state.js.map +1 -1
  355. package/dist/extensions/question/types.d.ts.map +1 -1
  356. package/dist/extensions/rewind/anchor.d.ts.map +1 -1
  357. package/dist/extensions/rewind/anchor.js.map +1 -1
  358. package/dist/extensions/rewind/config.d.ts.map +1 -1
  359. package/dist/extensions/rewind/config.js.map +1 -1
  360. package/dist/extensions/rewind/engine.d.ts.map +1 -1
  361. package/dist/extensions/rewind/engine.js.map +1 -1
  362. package/dist/extensions/rewind/gc.d.ts.map +1 -1
  363. package/dist/extensions/rewind/gc.js.map +1 -1
  364. package/dist/extensions/rewind/index.d.ts.map +1 -1
  365. package/dist/extensions/rewind/index.js.map +1 -1
  366. package/dist/extensions/rewind/menu.d.ts.map +1 -1
  367. package/dist/extensions/rewind/menu.js.map +1 -1
  368. package/dist/extensions/rewind/paths.d.ts.map +1 -1
  369. package/dist/extensions/rewind/paths.js.map +1 -1
  370. package/dist/extensions/rewind/restore.d.ts.map +1 -1
  371. package/dist/extensions/rewind/restore.js.map +1 -1
  372. package/dist/extensions/rewind/snapshot.d.ts.map +1 -1
  373. package/dist/extensions/rewind/snapshot.js.map +1 -1
  374. package/dist/extensions/rewind/storage.d.ts.map +1 -1
  375. package/dist/extensions/rewind/storage.js.map +1 -1
  376. package/dist/extensions/rewind/text.d.ts.map +1 -1
  377. package/dist/extensions/rewind/text.js.map +1 -1
  378. package/dist/extensions/rewind/tool-path.d.ts.map +1 -1
  379. package/dist/extensions/rewind/tool-path.js.map +1 -1
  380. package/dist/extensions/router/constants.d.ts +3 -0
  381. package/dist/extensions/router/constants.d.ts.map +1 -1
  382. package/dist/extensions/router/constants.js +3 -0
  383. package/dist/extensions/router/constants.js.map +1 -1
  384. package/dist/extensions/router/dialog.d.ts +14 -7
  385. package/dist/extensions/router/dialog.d.ts.map +1 -1
  386. package/dist/extensions/router/dialog.js +70 -132
  387. package/dist/extensions/router/dialog.js.map +1 -1
  388. package/dist/extensions/router/index.d.ts.map +1 -1
  389. package/dist/extensions/router/index.js.map +1 -1
  390. package/dist/extensions/router/presets.d.ts +8 -3
  391. package/dist/extensions/router/presets.d.ts.map +1 -1
  392. package/dist/extensions/router/presets.js +33 -17
  393. package/dist/extensions/router/presets.js.map +1 -1
  394. package/dist/extensions/router/probe.d.ts.map +1 -1
  395. package/dist/extensions/router/probe.js.map +1 -1
  396. package/dist/extensions/router/register.d.ts +3 -3
  397. package/dist/extensions/router/register.d.ts.map +1 -1
  398. package/dist/extensions/router/register.js.map +1 -1
  399. package/dist/extensions/router/store.d.ts.map +1 -1
  400. package/dist/extensions/router/store.js.map +1 -1
  401. package/dist/extensions/router/stream.d.ts.map +1 -1
  402. package/dist/extensions/router/stream.js.map +1 -1
  403. package/dist/extensions/router/types.d.ts.map +1 -1
  404. package/dist/extensions/router/ui.d.ts +11 -2
  405. package/dist/extensions/router/ui.d.ts.map +1 -1
  406. package/dist/extensions/router/ui.js +316 -171
  407. package/dist/extensions/router/ui.js.map +1 -1
  408. package/dist/extensions/statusline/index.d.ts.map +1 -1
  409. package/dist/extensions/statusline/index.js +17 -9
  410. package/dist/extensions/statusline/index.js.map +1 -1
  411. package/dist/extensions/subagent/activity.d.ts.map +1 -1
  412. package/dist/extensions/subagent/activity.js.map +1 -1
  413. package/dist/extensions/subagent/agents.d.ts.map +1 -1
  414. package/dist/extensions/subagent/agents.js.map +1 -1
  415. package/dist/extensions/subagent/constants.d.ts.map +1 -1
  416. package/dist/extensions/subagent/index.d.ts +3 -0
  417. package/dist/extensions/subagent/index.d.ts.map +1 -1
  418. package/dist/extensions/subagent/index.js +83 -12
  419. package/dist/extensions/subagent/index.js.map +1 -1
  420. package/dist/extensions/subagent/picker.d.ts.map +1 -1
  421. package/dist/extensions/subagent/picker.js +2 -9
  422. package/dist/extensions/subagent/picker.js.map +1 -1
  423. package/dist/extensions/subagent/render.d.ts.map +1 -1
  424. package/dist/extensions/subagent/render.js +33 -9
  425. package/dist/extensions/subagent/render.js.map +1 -1
  426. package/dist/extensions/subagent/resolve.d.ts.map +1 -1
  427. package/dist/extensions/subagent/resolve.js.map +1 -1
  428. package/dist/extensions/subagent/retry.d.ts.map +1 -1
  429. package/dist/extensions/subagent/retry.js.map +1 -1
  430. package/dist/extensions/subagent/runner.d.ts +2 -1
  431. package/dist/extensions/subagent/runner.d.ts.map +1 -1
  432. package/dist/extensions/subagent/runner.js +10 -12
  433. package/dist/extensions/subagent/runner.js.map +1 -1
  434. package/dist/extensions/subagent/schema.d.ts.map +1 -1
  435. package/dist/extensions/subagent/schema.js.map +1 -1
  436. package/dist/extensions/subagent/sdk-runner.d.ts.map +1 -1
  437. package/dist/extensions/subagent/sdk-runner.js +41 -1
  438. package/dist/extensions/subagent/sdk-runner.js.map +1 -1
  439. package/dist/extensions/subagent/settings.d.ts.map +1 -1
  440. package/dist/extensions/subagent/settings.js +46 -36
  441. package/dist/extensions/subagent/settings.js.map +1 -1
  442. package/dist/extensions/subagent/types.d.ts +0 -1
  443. package/dist/extensions/subagent/types.d.ts.map +1 -1
  444. package/dist/extensions/subagent/types.js.map +1 -1
  445. package/dist/extensions/todo/constants.d.ts.map +1 -1
  446. package/dist/extensions/todo/constants.js.map +1 -1
  447. package/dist/extensions/todo/index.d.ts.map +1 -1
  448. package/dist/extensions/todo/index.js.map +1 -1
  449. package/dist/extensions/todo/overlay.d.ts.map +1 -1
  450. package/dist/extensions/todo/overlay.js +6 -10
  451. package/dist/extensions/todo/overlay.js.map +1 -1
  452. package/dist/extensions/todo/schema.d.ts +2 -2
  453. package/dist/extensions/todo/schema.d.ts.map +1 -1
  454. package/dist/extensions/todo/state.d.ts.map +1 -1
  455. package/dist/extensions/todo/state.js.map +1 -1
  456. package/dist/extensions/todo/view.d.ts.map +1 -1
  457. package/dist/extensions/todo/view.js.map +1 -1
  458. package/dist/index.d.ts +4 -4
  459. package/dist/index.d.ts.map +1 -1
  460. package/dist/index.js +1 -1
  461. package/dist/index.js.map +1 -1
  462. package/dist/main.d.ts.map +1 -1
  463. package/dist/main.js +70 -25
  464. package/dist/main.js.map +1 -1
  465. package/dist/migrations.d.ts.map +1 -1
  466. package/dist/migrations.js.map +1 -1
  467. package/dist/modes/index.d.ts +1 -0
  468. package/dist/modes/index.d.ts.map +1 -1
  469. package/dist/modes/index.js.map +1 -1
  470. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  471. package/dist/modes/interactive/components/armin.js +6 -10
  472. package/dist/modes/interactive/components/armin.js.map +1 -1
  473. package/dist/modes/interactive/components/assistant-message.d.ts +5 -2
  474. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  475. package/dist/modes/interactive/components/assistant-message.js +13 -11
  476. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  477. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  478. package/dist/modes/interactive/components/bash-execution.js +4 -10
  479. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  480. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  481. package/dist/modes/interactive/components/bordered-loader.js +0 -3
  482. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  483. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  484. package/dist/modes/interactive/components/branch-summary-message.js +1 -3
  485. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  486. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  487. package/dist/modes/interactive/components/compaction-summary-message.js +1 -3
  488. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  489. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  490. package/dist/modes/interactive/components/config-selector.js +5 -22
  491. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  492. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
  493. package/dist/modes/interactive/components/countdown-timer.js +1 -7
  494. package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
  495. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  496. package/dist/modes/interactive/components/custom-editor.js +8 -8
  497. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  498. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
  499. package/dist/modes/interactive/components/custom-entry.js +1 -4
  500. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  501. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  502. package/dist/modes/interactive/components/custom-message.js +1 -7
  503. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  504. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
  505. package/dist/modes/interactive/components/daxnuts.js +6 -8
  506. package/dist/modes/interactive/components/daxnuts.js.map +1 -1
  507. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  508. package/dist/modes/interactive/components/diff.js.map +1 -1
  509. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  510. package/dist/modes/interactive/components/dynamic-border.js +0 -1
  511. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  512. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -1
  513. package/dist/modes/interactive/components/earendil-announcement.js.map +1 -1
  514. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  515. package/dist/modes/interactive/components/extension-editor.js +1 -7
  516. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  517. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  518. package/dist/modes/interactive/components/extension-input.js +2 -8
  519. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  520. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  521. package/dist/modes/interactive/components/extension-selector.js +1 -9
  522. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  523. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
  524. package/dist/modes/interactive/components/first-time-setup.js +2 -4
  525. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  526. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  527. package/dist/modes/interactive/components/footer.js +2 -4
  528. package/dist/modes/interactive/components/footer.js.map +1 -1
  529. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  530. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  531. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  532. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  533. package/dist/modes/interactive/components/login-dialog.js +3 -9
  534. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  535. package/dist/modes/interactive/components/markdown-transform.d.ts +3 -0
  536. package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -0
  537. package/dist/modes/interactive/components/markdown-transform.js +19 -0
  538. package/dist/modes/interactive/components/markdown-transform.js.map +1 -0
  539. package/dist/modes/interactive/components/mermaid.d.ts +11 -0
  540. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -0
  541. package/dist/modes/interactive/components/mermaid.js +75 -0
  542. package/dist/modes/interactive/components/mermaid.js.map +1 -0
  543. package/dist/modes/interactive/components/model-selector.d.ts +1 -1
  544. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  545. package/dist/modes/interactive/components/model-selector.js +28 -29
  546. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  547. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  548. package/dist/modes/interactive/components/oauth-selector.js +3 -11
  549. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  550. package/dist/modes/interactive/components/scoped-models-selector.d.ts +4 -0
  551. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  552. package/dist/modes/interactive/components/scoped-models-selector.js +34 -13
  553. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  554. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  555. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  556. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  557. package/dist/modes/interactive/components/session-selector.js +35 -60
  558. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  559. package/dist/modes/interactive/components/settings-selector.d.ts +8 -2
  560. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  561. package/dist/modes/interactive/components/settings-selector.js +30 -14
  562. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  563. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  564. package/dist/modes/interactive/components/show-images-selector.js +0 -1
  565. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  566. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  567. package/dist/modes/interactive/components/skill-invocation-message.js +1 -3
  568. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  569. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  570. package/dist/modes/interactive/components/status-indicator.js +0 -2
  571. package/dist/modes/interactive/components/status-indicator.js.map +1 -1
  572. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  573. package/dist/modes/interactive/components/theme-selector.js +0 -2
  574. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  575. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  576. package/dist/modes/interactive/components/thinking-selector.js +0 -1
  577. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  578. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  579. package/dist/modes/interactive/components/tool-execution.js +18 -36
  580. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  581. package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
  582. package/dist/modes/interactive/components/tool-group.js +2 -3
  583. package/dist/modes/interactive/components/tool-group.js.map +1 -1
  584. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  585. package/dist/modes/interactive/components/tree-selector.js +19 -39
  586. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  587. package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -1
  588. package/dist/modes/interactive/components/trust-selector.js +0 -6
  589. package/dist/modes/interactive/components/trust-selector.js.map +1 -1
  590. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  591. package/dist/modes/interactive/components/user-message-selector.js +3 -6
  592. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  593. package/dist/modes/interactive/components/user-message.d.ts +3 -1
  594. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  595. package/dist/modes/interactive/components/user-message.js +8 -5
  596. package/dist/modes/interactive/components/user-message.js.map +1 -1
  597. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
  598. package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
  599. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  600. package/dist/modes/interactive/external-editor.js.map +1 -1
  601. package/dist/modes/interactive/interactive-mode.d.ts +46 -5
  602. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  603. package/dist/modes/interactive/interactive-mode.js +538 -282
  604. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  605. package/dist/modes/interactive/model-search.d.ts.map +1 -1
  606. package/dist/modes/interactive/model-search.js.map +1 -1
  607. package/dist/modes/interactive/theme/dark.json +1 -0
  608. package/dist/modes/interactive/theme/light.json +1 -0
  609. package/dist/modes/interactive/theme/theme-controller.d.ts +3 -0
  610. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  611. package/dist/modes/interactive/theme/theme-controller.js +11 -8
  612. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  613. package/dist/modes/interactive/theme/theme-schema.json +5 -1
  614. package/dist/modes/interactive/theme/theme.d.ts +4 -4
  615. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  616. package/dist/modes/interactive/theme/theme.js +24 -12
  617. package/dist/modes/interactive/theme/theme.js.map +1 -1
  618. package/dist/modes/json-event.d.ts +28 -0
  619. package/dist/modes/json-event.d.ts.map +1 -0
  620. package/dist/modes/json-event.js +12 -0
  621. package/dist/modes/json-event.js.map +1 -0
  622. package/dist/modes/print-mode.d.ts.map +1 -1
  623. package/dist/modes/print-mode.js +12 -2
  624. package/dist/modes/print-mode.js.map +1 -1
  625. package/dist/modes/rpc/jsonl.d.ts.map +1 -1
  626. package/dist/modes/rpc/jsonl.js.map +1 -1
  627. package/dist/modes/rpc/rpc-client.d.ts +5 -4
  628. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  629. package/dist/modes/rpc/rpc-client.js +7 -8
  630. package/dist/modes/rpc/rpc-client.js.map +1 -1
  631. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  632. package/dist/modes/rpc/rpc-mode.js +4 -3
  633. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  634. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  635. package/dist/package-manager-cli.d.ts.map +1 -1
  636. package/dist/package-manager-cli.js +11 -9
  637. package/dist/package-manager-cli.js.map +1 -1
  638. package/dist/rpc-entry.d.ts.map +1 -1
  639. package/dist/rpc-entry.js +1 -0
  640. package/dist/rpc-entry.js.map +1 -1
  641. package/dist/server/create-harness.d.ts +26 -0
  642. package/dist/server/create-harness.d.ts.map +1 -0
  643. package/dist/server/create-harness.js +104 -0
  644. package/dist/server/create-harness.js.map +1 -0
  645. package/dist/utils/abort.d.ts +5 -0
  646. package/dist/utils/abort.d.ts.map +1 -0
  647. package/dist/utils/abort.js +48 -0
  648. package/dist/utils/abort.js.map +1 -0
  649. package/dist/utils/ansi.d.ts.map +1 -1
  650. package/dist/utils/ansi.js.map +1 -1
  651. package/dist/utils/changelog.d.ts.map +1 -1
  652. package/dist/utils/changelog.js.map +1 -1
  653. package/dist/utils/child-process.d.ts.map +1 -1
  654. package/dist/utils/child-process.js.map +1 -1
  655. package/dist/utils/clipboard-image.d.ts.map +1 -1
  656. package/dist/utils/clipboard-image.js.map +1 -1
  657. package/dist/utils/clipboard-native.d.ts.map +1 -1
  658. package/dist/utils/clipboard-native.js.map +1 -1
  659. package/dist/utils/clipboard.d.ts +1 -1
  660. package/dist/utils/clipboard.d.ts.map +1 -1
  661. package/dist/utils/clipboard.js +22 -2
  662. package/dist/utils/clipboard.js.map +1 -1
  663. package/dist/utils/coalescing-terminal.d.ts +20 -4
  664. package/dist/utils/coalescing-terminal.d.ts.map +1 -1
  665. package/dist/utils/coalescing-terminal.js +48 -12
  666. package/dist/utils/coalescing-terminal.js.map +1 -1
  667. package/dist/utils/deprecation.d.ts.map +1 -1
  668. package/dist/utils/deprecation.js.map +1 -1
  669. package/dist/utils/exif-orientation.d.ts.map +1 -1
  670. package/dist/utils/exif-orientation.js.map +1 -1
  671. package/dist/utils/frontmatter.d.ts.map +1 -1
  672. package/dist/utils/frontmatter.js.map +1 -1
  673. package/dist/utils/fs-watch.d.ts.map +1 -1
  674. package/dist/utils/fs-watch.js.map +1 -1
  675. package/dist/utils/git.d.ts.map +1 -1
  676. package/dist/utils/git.js.map +1 -1
  677. package/dist/utils/html.d.ts.map +1 -1
  678. package/dist/utils/html.js.map +1 -1
  679. package/dist/utils/image-convert.d.ts.map +1 -1
  680. package/dist/utils/image-convert.js.map +1 -1
  681. package/dist/utils/image-process.d.ts.map +1 -1
  682. package/dist/utils/image-process.js.map +1 -1
  683. package/dist/utils/image-resize-core.d.ts.map +1 -1
  684. package/dist/utils/image-resize-core.js.map +1 -1
  685. package/dist/utils/image-resize-worker.d.ts.map +1 -1
  686. package/dist/utils/image-resize-worker.js.map +1 -1
  687. package/dist/utils/image-resize.d.ts.map +1 -1
  688. package/dist/utils/image-resize.js.map +1 -1
  689. package/dist/utils/json.d.ts.map +1 -1
  690. package/dist/utils/json.js.map +1 -1
  691. package/dist/utils/management-http.d.ts +23 -0
  692. package/dist/utils/management-http.d.ts.map +1 -0
  693. package/dist/utils/management-http.js +50 -0
  694. package/dist/utils/management-http.js.map +1 -0
  695. package/dist/utils/mime.d.ts.map +1 -1
  696. package/dist/utils/mime.js.map +1 -1
  697. package/dist/utils/open-browser.d.ts.map +1 -1
  698. package/dist/utils/open-browser.js.map +1 -1
  699. package/dist/utils/paths.d.ts +3 -0
  700. package/dist/utils/paths.d.ts.map +1 -1
  701. package/dist/utils/paths.js +23 -1
  702. package/dist/utils/paths.js.map +1 -1
  703. package/dist/utils/photon.d.ts.map +1 -1
  704. package/dist/utils/photon.js.map +1 -1
  705. package/dist/utils/pi-user-agent.d.ts.map +1 -1
  706. package/dist/utils/pi-user-agent.js.map +1 -1
  707. package/dist/utils/shell.d.ts.map +1 -1
  708. package/dist/utils/shell.js.map +1 -1
  709. package/dist/utils/sleep.d.ts.map +1 -1
  710. package/dist/utils/sleep.js.map +1 -1
  711. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  712. package/dist/utils/syntax-highlight.js.map +1 -1
  713. package/dist/utils/tool-result-images.d.ts +19 -0
  714. package/dist/utils/tool-result-images.d.ts.map +1 -0
  715. package/dist/utils/tool-result-images.js +45 -0
  716. package/dist/utils/tool-result-images.js.map +1 -0
  717. package/dist/utils/tools-manager.d.ts.map +1 -1
  718. package/dist/utils/tools-manager.js +4 -6
  719. package/dist/utils/tools-manager.js.map +1 -1
  720. package/dist/utils/version-check.d.ts +4 -0
  721. package/dist/utils/version-check.d.ts.map +1 -1
  722. package/dist/utils/version-check.js +20 -2
  723. package/dist/utils/version-check.js.map +1 -1
  724. package/dist/utils/windows-self-update.d.ts.map +1 -1
  725. package/dist/utils/windows-self-update.js.map +1 -1
  726. package/docs/bundled/README.md +1 -0
  727. package/docs/bundled/extensions/biu.md +63 -0
  728. package/docs/bundled/extensions/router.md +20 -14
  729. package/docs/bundled/extensions/statusline.md +7 -5
  730. package/docs/custom-provider.md +123 -2
  731. package/docs/development.md +83 -0
  732. package/docs/docs.json +8 -4
  733. package/docs/extensions.md +30 -5
  734. package/docs/json.md +21 -2
  735. package/docs/keybindings.md +46 -14
  736. package/docs/models.md +21 -3
  737. package/docs/providers.md +9 -1
  738. package/docs/quickstart.md +2 -0
  739. package/docs/rpc.md +12 -11
  740. package/docs/sdk.md +46 -0
  741. package/docs/security.md +1 -1
  742. package/docs/settings.md +4 -1
  743. package/docs/themes.md +7 -5
  744. package/docs/usage.md +8 -0
  745. package/examples/extensions/custom-compaction.ts +1 -16
  746. package/examples/extensions/custom-provider-anthropic/index.ts +2 -1
  747. package/examples/extensions/custom-provider-anthropic/package-lock.json +5 -5
  748. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  749. package/examples/extensions/custom-provider-gitlab-duo/index.ts +2 -1
  750. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  751. package/examples/extensions/doom-overlay/wad-finder.ts +7 -3
  752. package/examples/extensions/dynamic-resources/dynamic.json +1 -1
  753. package/examples/extensions/gondolin/package-lock.json +2 -2
  754. package/examples/extensions/gondolin/package.json +1 -1
  755. package/examples/extensions/handoff.ts +2 -11
  756. package/examples/extensions/qna.ts +3 -7
  757. package/examples/extensions/sandbox/package-lock.json +3 -3
  758. package/examples/extensions/sandbox/package.json +1 -1
  759. package/examples/extensions/summarize.ts +8 -18
  760. package/examples/extensions/with-deps/package-lock.json +4 -4
  761. package/examples/extensions/with-deps/package.json +1 -1
  762. package/examples/rpc-extension-ui.ts +11 -2
  763. package/examples/sdk/02-custom-model.ts +1 -2
  764. package/examples/sdk/09-api-keys-and-oauth.ts +1 -1
  765. package/examples/sdk/12-full-control.ts +1 -1
  766. package/examples/sdk/README.md +1 -0
  767. package/npm-shrinkwrap.json +193 -264
  768. 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,49 @@ 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, {
171
+ openUrl: openBrowser,
172
+ onRightClickPaste: options.onRightClickPaste,
173
+ });
174
+ }
175
+ return new TuiMainScreen(terminal, options.showHardwareCursor, options.logDirectory);
176
+ }
177
+ /** Stable reference for components while InteractiveMode replaces the active renderer. */
178
+ export function createInteractiveTuiReference(getTui) {
179
+ return new Proxy({}, {
180
+ get: (_target, property) => {
181
+ const tui = getTui();
182
+ const value = Reflect.get(tui, property, tui);
183
+ if (typeof value !== "function")
184
+ return value;
185
+ let methodTui = tui;
186
+ let method = value;
187
+ return (...args) => {
188
+ const currentTui = getTui();
189
+ if (currentTui !== methodTui) {
190
+ const currentMethod = Reflect.get(currentTui, property, currentTui);
191
+ if (typeof currentMethod !== "function") {
192
+ throw new TypeError(`TUI property ${String(property)} is not callable`);
193
+ }
194
+ methodTui = currentTui;
195
+ method = currentMethod;
196
+ }
197
+ return Reflect.apply(method, methodTui, args);
198
+ };
199
+ },
200
+ set: (_target, property, value) => {
201
+ const tui = getTui();
202
+ return Reflect.set(tui, property, value, tui);
203
+ },
204
+ has: (_target, property) => Reflect.has(getTui(), property),
205
+ getPrototypeOf: () => Reflect.getPrototypeOf(getTui()),
206
+ });
207
+ }
164
208
  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
209
  // Convenience accessors
257
210
  get session() {
258
211
  return this.runtimeHost.session;
@@ -267,8 +220,78 @@ export class InteractiveMode {
267
220
  return this.session.settingsManager;
268
221
  }
269
222
  constructor(runtimeHost, options = {}) {
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
+ this.onRightClickPaste = () => {
284
+ void this.handleRightClickPaste();
285
+ };
286
+ /**
287
+ * Gracefully shutdown the agent.
288
+ * Stops the TUI before emitting shutdown events so extension UI cleanup cannot
289
+ * repaint the final frame while the process is exiting.
290
+ */
291
+ this.isShuttingDown = false;
270
292
  this.runtimeHost = runtimeHost;
271
- this.options = options;
293
+ const tuiMode = options.tuiMode ?? this.settingsManager.getTuiMode();
294
+ this.options = { ...options, tuiMode };
272
295
  this.autoTrustOnReloadCwd = options.autoTrustOnReloadCwd;
273
296
  this.runtimeHost.setBeforeSessionInvalidate(() => {
274
297
  this.resetExtensionUI();
@@ -279,27 +302,30 @@ export class InteractiveMode {
279
302
  this.version = VERSION;
280
303
  const terminal = new CoalescingTerminal();
281
304
  this.coalescingTerminal = terminal;
282
- this.ui = new TUI(terminal, this.settingsManager.getShowHardwareCursor(), getAgentDir());
283
- // Lets full-redraw rewrites scroll grown content into scrollback
284
- // instead of dropping the lines pushed above the screen.
285
- // previousViewportTop is TS-private but a plain runtime field, and
286
- // pi-tui writes each full-redraw frame before updating it, so the
287
- // wrapper observes the pre-frame value; if either assumption breaks,
288
- // readViewportTop falls back to the bottom-anchored repaint.
289
- terminal.setViewportTopProvider(() => this.ui.previousViewportTop);
290
- // Scrollback preservation stays on from agent_start until the user's
291
- // next input after the run settles: post-run reflow frames must not
292
- // yank a reader who is still scrolled up, but once the user acts they
293
- // 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;
305
+ this.renderer = createInteractiveTui({
306
+ tuiMode,
307
+ showHardwareCursor: this.settingsManager.getShowHardwareCursor(),
308
+ logDirectory: getAgentDir(),
309
+ terminal,
310
+ onRightClickPaste: this.onRightClickPaste,
298
311
  });
312
+ this.ui = createInteractiveTuiReference(() => this.renderer);
313
+ // Lets full-redraw rewrites scroll grown content into scrollback
314
+ // instead of dropping the lines pushed above the screen. The render
315
+ // state comes from pi-tui's public captureRenderState(); pi-tui
316
+ // writes each full-redraw frame before updating its bookkeeping, so
317
+ // the wrapper observes the pre-frame viewport top. Fullscreen
318
+ // renderers return undefined (their frames do not match the rewrite
319
+ // shape anyway), falling back to the bottom-anchored repaint.
320
+ terminal.setViewportTopProvider(() => this.renderer instanceof TuiMainScreen ? this.renderer.captureRenderState().previousViewportTop : undefined);
299
321
  this.ui.setClearOnShrink(this.settingsManager.getClearOnShrink());
300
322
  this.headerContainer = new Container();
301
323
  this.loadedResourcesContainer = new Container();
302
324
  this.chatContainer = new Container();
325
+ this.documentContainer = new Container();
326
+ this.documentContainer.addChild(this.headerContainer);
327
+ this.documentContainer.addChild(this.loadedResourcesContainer);
328
+ this.documentContainer.addChild(this.chatContainer);
303
329
  this.pendingMessagesContainer = new Container();
304
330
  this.statusContainer = new Container();
305
331
  this.widgetContainerAbove = new Container();
@@ -318,6 +344,8 @@ export class InteractiveMode {
318
344
  this.footerDataProvider = new FooterDataProvider(this.sessionManager.getCwd());
319
345
  this.footer = new FooterComponent(this.session, this.footerDataProvider);
320
346
  this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled);
347
+ this.footerContainer = new Container();
348
+ this.footerContainer.addChild(this.footer);
321
349
  // Load hide thinking block setting
322
350
  this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
323
351
  this.outputPad = this.settingsManager.getOutputPad();
@@ -373,11 +401,10 @@ export class InteractiveMode {
373
401
  }));
374
402
  const modelCommand = slashCommands.find((command) => command.name === "model");
375
403
  if (modelCommand) {
376
- modelCommand.getArgumentCompletions = async (prefix) => {
377
- // Get available models (scoped or from registry)
404
+ modelCommand.getArgumentCompletions = (prefix) => {
378
405
  const models = this.session.scopedModels.length > 0
379
406
  ? this.session.scopedModels.map((s) => s.model)
380
- : await this.session.modelRuntime.getAvailable();
407
+ : this.session.modelRuntime.getAvailableSnapshot();
381
408
  if (models.length === 0)
382
409
  return null;
383
410
  // Create items with provider/id format
@@ -478,6 +505,73 @@ export class InteractiveMode {
478
505
  }
479
506
  this.chatContainer.addChild(new DynamicBorder());
480
507
  }
508
+ mountInteractiveTui(tui, components) {
509
+ for (const component of components)
510
+ tui.addChild(component);
511
+ if (TuiLayouts.isViewportTUI(tui)) {
512
+ if (!this.fullscreenLayoutRoot)
513
+ throw new Error("Fullscreen layout is not initialized");
514
+ tui.setLayoutRoot(this.fullscreenLayoutRoot);
515
+ }
516
+ }
517
+ stopInteractiveTui() {
518
+ if (this.renderer.mode === "fullscreen") {
519
+ while (this.renderer.hasOverlayEntries)
520
+ this.renderer.hideOverlay();
521
+ this.switchTuiMode("regular", false, false);
522
+ this.renderer.renderNow();
523
+ }
524
+ this.ui.stop();
525
+ }
526
+ switchTuiMode(mode, restoreProgress = true, startRenderer = true) {
527
+ const previousUi = this.renderer;
528
+ if (mode === previousUi.mode)
529
+ return true;
530
+ if (previousUi.hasOverlayEntries)
531
+ return false;
532
+ const components = [...previousUi.children];
533
+ const focus = previousUi.getFocusedComponent();
534
+ const terminal = previousUi.terminal;
535
+ const showHardwareCursor = previousUi.getShowHardwareCursor();
536
+ const clearOnShrink = previousUi.getClearOnShrink();
537
+ const onDebug = previousUi.onDebug;
538
+ if (previousUi instanceof TuiMainScreen) {
539
+ this.mainScreenRenderState = previousUi.captureRenderState();
540
+ }
541
+ previousUi.stop({ preserveScreen: true });
542
+ previousUi.setFocus(null);
543
+ previousUi.clear();
544
+ if (TuiLayouts.isViewportTUI(previousUi))
545
+ previousUi.setLayoutRoot(undefined);
546
+ const nextUi = createInteractiveTui({
547
+ tuiMode: mode,
548
+ showHardwareCursor,
549
+ logDirectory: getAgentDir(),
550
+ terminal,
551
+ onRightClickPaste: this.onRightClickPaste,
552
+ });
553
+ nextUi.setClearOnShrink(clearOnShrink);
554
+ nextUi.onDebug = onDebug;
555
+ if (nextUi instanceof TuiMainScreen && this.mainScreenRenderState) {
556
+ nextUi.restoreRenderState(this.mainScreenRenderState);
557
+ }
558
+ this.renderer = nextUi;
559
+ this.options.tuiMode = mode;
560
+ this.mountInteractiveTui(nextUi, components);
561
+ nextUi.invalidate();
562
+ nextUi.setFocus(focus);
563
+ if (!startRenderer)
564
+ return true;
565
+ nextUi.start();
566
+ this.themeController.rebindTui();
567
+ this.rebindExtensionTerminalInputListeners();
568
+ if (restoreProgress &&
569
+ this.settingsManager.getShowTerminalProgress() &&
570
+ (this.session.isStreaming || this.session.isCompacting)) {
571
+ terminal.setProgress(true);
572
+ }
573
+ return true;
574
+ }
481
575
  async init() {
482
576
  if (this.isInitialized)
483
577
  return;
@@ -501,18 +595,36 @@ export class InteractiveMode {
501
595
  : "";
502
596
  console.log(theme.fg("dim", `Model scope: ${modelList}${cycleHint}`));
503
597
  }
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);
598
+ // Keep one component tree and remount it when changing renderers.
511
599
  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);
600
+ this.transcriptScrollView = new TuiLayouts.ScrollView(this.documentContainer, {
601
+ follow: "end",
602
+ primary: true,
603
+ overscroll: "chain",
604
+ scrollbar: this.settingsManager.getFullscreenScrollbar(),
605
+ scrollbarStyle: (text) => theme.bg("scrollbarThumb", text),
606
+ });
607
+ const dock = new TuiLayouts.VStack([
608
+ { component: this.pendingMessagesContainer, shrink: 1, minSize: 0 },
609
+ { component: this.statusContainer, shrink: 1, minSize: 0 },
610
+ { component: this.widgetContainerAbove, shrink: 1, minSize: 0 },
611
+ { component: this.editorContainer, shrink: 1, minSize: 3 },
612
+ { component: this.widgetContainerBelow, shrink: 1, minSize: 0 },
613
+ { component: this.footerContainer, shrink: 1, minSize: 1 },
614
+ ]);
615
+ this.fullscreenLayoutRoot = new TuiLayouts.VStack([
616
+ { component: this.transcriptScrollView, basis: 0, grow: 1, shrink: 1, minSize: 1 },
617
+ { component: dock, basis: "auto", grow: 0, shrink: 1, minSize: 1 },
618
+ ]);
619
+ this.mountInteractiveTui(this.renderer, [
620
+ this.documentContainer,
621
+ this.pendingMessagesContainer,
622
+ this.statusContainer,
623
+ this.widgetContainerAbove,
624
+ this.editorContainer,
625
+ this.widgetContainerBelow,
626
+ this.footerContainer,
627
+ ]);
516
628
  this.ui.setFocus(this.editor);
517
629
  this.setupKeyHandlers();
518
630
  this.setupEditorSubmitHandler();
@@ -604,10 +716,13 @@ export class InteractiveMode {
604
716
  async run() {
605
717
  await this.init();
606
718
  if (!process.env.PI_OFFLINE) {
719
+ const controller = new AbortController();
720
+ const timeout = setTimeout(() => controller.abort(), 15_000);
607
721
  void this.session.modelRuntime
608
- .refresh()
722
+ .refresh({ signal: controller.signal })
609
723
  .then(() => this.updateAvailableProviderCount())
610
- .catch(() => { });
724
+ .catch(() => { })
725
+ .finally(() => clearTimeout(timeout));
611
726
  }
612
727
  // Start version check asynchronously
613
728
  checkForNewPiVersion(this.version).then((newRelease) => {
@@ -1259,6 +1374,7 @@ export class InteractiveMode {
1259
1374
  if (result.cancelled) {
1260
1375
  return { cancelled: true };
1261
1376
  }
1377
+ this.coalescingTerminal.passNextFullRedraw();
1262
1378
  this.clearChat();
1263
1379
  this.renderInitialMessages();
1264
1380
  if (result.editorText && !this.editor.getText().trim()) {
@@ -1292,8 +1408,12 @@ export class InteractiveMode {
1292
1408
  this.showLoadedResources({ force: false, showDiagnosticsWhenQuiet: true });
1293
1409
  this.showStartupNoticesIfNeeded();
1294
1410
  }
1411
+ applyFullscreenScrollbarSetting() {
1412
+ this.transcriptScrollView?.setScrollbar(this.settingsManager.getFullscreenScrollbar());
1413
+ }
1295
1414
  applyRuntimeSettings() {
1296
1415
  configureHttpDispatcher(this.settingsManager.getHttpIdleTimeoutMs());
1416
+ this.applyFullscreenScrollbarSetting();
1297
1417
  this.footer.setSession(this.session);
1298
1418
  this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled);
1299
1419
  this.footerDataProvider.setCwd(this.sessionManager.getCwd());
@@ -1362,6 +1482,10 @@ export class InteractiveMode {
1362
1482
  this.pendingTools.clear();
1363
1483
  }
1364
1484
  renderCurrentSessionState() {
1485
+ // Resuming, forking, or starting a new session rebuilds the transcript
1486
+ // at the user's request; the rebuild's full redraw keeps the clean
1487
+ // wipe-and-replay even if preservation is still windowed on.
1488
+ this.coalescingTerminal.passNextFullRedraw();
1365
1489
  this.loadedResourcesContainer.clear();
1366
1490
  this.clearChat();
1367
1491
  this.pendingMessagesContainer.clear();
@@ -1405,6 +1529,9 @@ export class InteractiveMode {
1405
1529
  }
1406
1530
  this.chatContainer.addChild(component);
1407
1531
  }
1532
+ getMarkdownTransformers() {
1533
+ return [this.mermaidMarkdownTransformer, ...this.session.extensionRunner.getMarkdownTransformers()];
1534
+ }
1408
1535
  /**
1409
1536
  * Set up keyboard shortcuts registered by extensions.
1410
1537
  */
@@ -1484,7 +1611,7 @@ export class InteractiveMode {
1484
1611
  this.activeStatusIndicator?.dispose();
1485
1612
  this.activeStatusIndicator = undefined;
1486
1613
  this.statusContainer.clear();
1487
- if (hadActiveStatusIndicator && this.ui.getClearOnShrink()) {
1614
+ if (hadActiveStatusIndicator && this.options.tuiMode === "regular" && this.ui.getClearOnShrink()) {
1488
1615
  this.statusContainer.addChild(this.idleStatus);
1489
1616
  }
1490
1617
  }
@@ -1598,7 +1725,7 @@ export class InteractiveMode {
1598
1725
  this.setHiddenThinkingLabel();
1599
1726
  }
1600
1727
  // Maximum total widget lines to prevent viewport overflow
1601
- static MAX_WIDGET_LINES = 10;
1728
+ static { this.MAX_WIDGET_LINES = 10; }
1602
1729
  /**
1603
1730
  * Render all extension widgets to the widget container.
1604
1731
  */
@@ -1632,22 +1759,16 @@ export class InteractiveMode {
1632
1759
  if (this.customFooter?.dispose) {
1633
1760
  this.customFooter.dispose();
1634
1761
  }
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
- }
1762
+ this.footerContainer.clear();
1642
1763
  if (factory) {
1643
1764
  // Create and add custom footer, passing the data provider
1644
1765
  this.customFooter = factory(this.ui, theme, this.footerDataProvider);
1645
- this.ui.addChild(this.customFooter);
1766
+ this.footerContainer.addChild(this.customFooter);
1646
1767
  }
1647
1768
  else {
1648
1769
  // Restore built-in footer
1649
1770
  this.customFooter = undefined;
1650
- this.ui.addChild(this.footer);
1771
+ this.footerContainer.addChild(this.footer);
1651
1772
  }
1652
1773
  this.ui.requestRender();
1653
1774
  }
@@ -1693,18 +1814,23 @@ export class InteractiveMode {
1693
1814
  this.ui.requestRender();
1694
1815
  }
1695
1816
  addExtensionTerminalInputListener(handler) {
1696
- const unsubscribe = this.ui.addInputListener(handler);
1697
- this.extensionTerminalInputUnsubscribers.add(unsubscribe);
1817
+ const subscription = { handler, unsubscribe: this.ui.addInputListener(handler) };
1818
+ this.extensionTerminalInputSubscriptions.add(subscription);
1698
1819
  return () => {
1699
- unsubscribe();
1700
- this.extensionTerminalInputUnsubscribers.delete(unsubscribe);
1820
+ subscription.unsubscribe();
1821
+ this.extensionTerminalInputSubscriptions.delete(subscription);
1701
1822
  };
1702
1823
  }
1703
- clearExtensionTerminalInputListeners() {
1704
- for (const unsubscribe of this.extensionTerminalInputUnsubscribers) {
1705
- unsubscribe();
1824
+ rebindExtensionTerminalInputListeners() {
1825
+ for (const subscription of this.extensionTerminalInputSubscriptions) {
1826
+ subscription.unsubscribe();
1827
+ subscription.unsubscribe = this.ui.addInputListener(subscription.handler);
1706
1828
  }
1707
- this.extensionTerminalInputUnsubscribers.clear();
1829
+ }
1830
+ clearExtensionTerminalInputListeners() {
1831
+ for (const subscription of this.extensionTerminalInputSubscriptions)
1832
+ subscription.unsubscribe();
1833
+ this.extensionTerminalInputSubscriptions.clear();
1708
1834
  }
1709
1835
  /**
1710
1836
  * Create the ExtensionUIContext for extensions.
@@ -1805,6 +1931,7 @@ export class InteractiveMode {
1805
1931
  cancelHint: opts?.cancelHint,
1806
1932
  onToggleToolsExpanded: () => this.toggleToolOutputExpansion(),
1807
1933
  });
1934
+ this.disposeActiveSelector();
1808
1935
  this.editorContainer.clear();
1809
1936
  this.editorContainer.addChild(this.extensionSelector);
1810
1937
  this.ui.setFocus(this.extensionSelector);
@@ -1826,7 +1953,9 @@ export class InteractiveMode {
1826
1953
  * Show a confirmation dialog for extensions.
1827
1954
  */
1828
1955
  async showExtensionConfirm(title, message, opts) {
1829
- const result = await this.showExtensionSelector(`${title}\n${message}`, ["Yes", "No"], opts);
1956
+ // The message is context, not a heading: render it as the selector's muted
1957
+ // subtitle instead of folding it into the accent-bold title.
1958
+ const result = await this.showExtensionSelector(title, ["Yes", "No"], { ...opts, subtitle: message });
1830
1959
  return result === "Yes";
1831
1960
  }
1832
1961
  async promptForMissingSessionCwd(error) {
@@ -1856,6 +1985,7 @@ export class InteractiveMode {
1856
1985
  this.hideExtensionInput();
1857
1986
  resolve(undefined);
1858
1987
  }, { tui: this.ui, timeout: opts?.timeout });
1988
+ this.disposeActiveSelector();
1859
1989
  this.editorContainer.clear();
1860
1990
  this.editorContainer.addChild(this.extensionInput);
1861
1991
  this.ui.setFocus(this.extensionInput);
@@ -1885,6 +2015,7 @@ export class InteractiveMode {
1885
2015
  this.hideExtensionEditor();
1886
2016
  resolve(undefined);
1887
2017
  }, undefined, this.settingsManager.getExternalEditorCommand());
2018
+ this.disposeActiveSelector();
1888
2019
  this.editorContainer.clear();
1889
2020
  this.editorContainer.addChild(this.extensionEditor);
1890
2021
  this.ui.setFocus(this.extensionEditor);
@@ -1909,6 +2040,7 @@ export class InteractiveMode {
1909
2040
  this.editorComponentFactory = factory;
1910
2041
  // Save text from current editor before switching
1911
2042
  const currentText = this.editor.getText();
2043
+ this.disposeActiveSelector();
1912
2044
  this.editorContainer.clear();
1913
2045
  if (factory) {
1914
2046
  // Create the custom editor with tui, theme, and keybindings
@@ -1925,6 +2057,9 @@ export class InteractiveMode {
1925
2057
  if (newEditor.setPaddingX !== undefined) {
1926
2058
  newEditor.setPaddingX(this.defaultEditor.getPaddingX());
1927
2059
  }
2060
+ if (newEditor.setAutocompleteMaxVisible !== undefined) {
2061
+ newEditor.setAutocompleteMaxVisible(this.defaultEditor.getAutocompleteMaxVisible());
2062
+ }
1928
2063
  // Set autocomplete if supported
1929
2064
  if (newEditor.setAutocompleteProvider && this.autocompleteProvider) {
1930
2065
  newEditor.setAutocompleteProvider(this.autocompleteProvider);
@@ -2029,6 +2164,7 @@ export class InteractiveMode {
2029
2164
  options?.onHandle?.(handle);
2030
2165
  }
2031
2166
  else {
2167
+ this.disposeActiveSelector();
2032
2168
  this.editorContainer.clear();
2033
2169
  this.editorContainer.addChild(component);
2034
2170
  this.ui.setFocus(component);
@@ -2115,7 +2251,7 @@ export class InteractiveMode {
2115
2251
  this.defaultEditor.onAction("app.tools.expand", () => this.toggleToolOutputExpansion());
2116
2252
  this.defaultEditor.onAction("app.thinking.toggle", () => this.toggleThinkingBlockVisibility());
2117
2253
  this.defaultEditor.onAction("app.editor.external", () => void this.handleOpenExternalEditor());
2118
- this.defaultEditor.onAction("app.message.copy", () => void this.handleCopyCommand());
2254
+ this.defaultEditor.onAction("app.message.copy", () => void this.handleCopyCommand({ flashConfirmation: true }));
2119
2255
  this.defaultEditor.onAction("app.message.followUp", () => this.handleFollowUp());
2120
2256
  this.defaultEditor.onAction("app.message.dequeue", () => this.handleDequeue());
2121
2257
  this.defaultEditor.onAction("app.session.new", () => this.handleClearCommand());
@@ -2135,6 +2271,22 @@ export class InteractiveMode {
2135
2271
  void this.handleClipboardPaste();
2136
2272
  };
2137
2273
  }
2274
+ async handleRightClickPaste() {
2275
+ const target = this.renderer.getFocusedComponent();
2276
+ const handleInput = target?.handleInput;
2277
+ if (!target || !handleInput)
2278
+ return;
2279
+ try {
2280
+ const text = await readClipboardText();
2281
+ if (!text || this.renderer.getFocusedComponent() !== target)
2282
+ return;
2283
+ handleInput.call(target, `\x1b[200~${text}\x1b[201~`);
2284
+ this.ui.requestRender();
2285
+ }
2286
+ catch {
2287
+ // Silently ignore clipboard errors (may not have permission, etc.)
2288
+ }
2289
+ }
2138
2290
  async handleClipboardPaste() {
2139
2291
  try {
2140
2292
  const image = await readClipboardImage();
@@ -2355,8 +2507,9 @@ export class InteractiveMode {
2355
2507
  this.footer.invalidate();
2356
2508
  switch (event.type) {
2357
2509
  case "agent_start":
2358
- this.agentRunActive = true;
2359
- this.coalescingTerminal.setScrollbackPreservation(true);
2510
+ // Opens the scrollback-preservation window; the terminal
2511
+ // closes it on the user's next input after the run settles.
2512
+ this.coalescingTerminal.setAgentRunActive(true);
2360
2513
  this.clearPendingTools();
2361
2514
  if (this.settingsManager.getShowTerminalProgress()) {
2362
2515
  this.ui.terminal.setProgress(true);
@@ -2416,17 +2569,17 @@ export class InteractiveMode {
2416
2569
  this.ui.requestRender();
2417
2570
  }
2418
2571
  else if (event.message.role === "assistant") {
2419
- this.streamingComponent = new AssistantMessageComponent(undefined, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel, this.outputPad);
2572
+ this.streamingComponent = new AssistantMessageComponent(undefined, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel, this.outputPad, this.getMarkdownTransformers());
2420
2573
  this.streamingMessage = event.message;
2421
2574
  this.chatContainer.addChild(this.streamingComponent);
2422
- this.streamingComponent.updateContent(this.streamingMessage);
2575
+ this.streamingComponent.updateContent(this.streamingMessage, true);
2423
2576
  this.ui.requestRender();
2424
2577
  }
2425
2578
  break;
2426
2579
  case "message_update":
2427
2580
  if (this.streamingComponent && event.message.role === "assistant") {
2428
2581
  this.streamingMessage = event.message;
2429
- this.streamingComponent.updateContent(this.streamingMessage);
2582
+ this.streamingComponent.updateContent(this.streamingMessage, true);
2430
2583
  for (const content of this.streamingMessage.content) {
2431
2584
  if (content.type === "toolCall") {
2432
2585
  if (!this.pendingTools.has(content.id)) {
@@ -2459,7 +2612,7 @@ export class InteractiveMode {
2459
2612
  : "Operation aborted";
2460
2613
  this.streamingMessage.errorMessage = errorMessage;
2461
2614
  }
2462
- this.streamingComponent.updateContent(this.streamingMessage);
2615
+ this.streamingComponent.updateContent(this.streamingMessage, false);
2463
2616
  if (this.streamingMessage.stopReason === "aborted" || this.streamingMessage.stopReason === "error") {
2464
2617
  if (!errorMessage) {
2465
2618
  errorMessage = this.streamingMessage.errorMessage || "Error";
@@ -2533,7 +2686,7 @@ export class InteractiveMode {
2533
2686
  // Preservation itself stays on until the next user input; the
2534
2687
  // run's trailing reflow frames may land after this event while
2535
2688
  // the reader is still scrolled up.
2536
- this.agentRunActive = false;
2689
+ this.coalescingTerminal.setAgentRunActive(false);
2537
2690
  await this.checkShutdownRequested();
2538
2691
  break;
2539
2692
  case "compaction_start": {
@@ -2735,12 +2888,12 @@ export class InteractiveMode {
2735
2888
  // Render user message separately if present
2736
2889
  if (skillBlock.userMessage) {
2737
2890
  this.chatContainer.addChild(new Spacer(1));
2738
- const userComponent = new UserMessageComponent(skillBlock.userMessage, this.getMarkdownThemeWithSettings(), this.outputPad);
2891
+ const userComponent = new UserMessageComponent(skillBlock.userMessage, this.getMarkdownThemeWithSettings(), this.outputPad, this.getMarkdownTransformers());
2739
2892
  this.chatContainer.addChild(userComponent);
2740
2893
  }
2741
2894
  }
2742
2895
  else {
2743
- const userComponent = new UserMessageComponent(textContent, this.getMarkdownThemeWithSettings(), this.outputPad);
2896
+ const userComponent = new UserMessageComponent(textContent, this.getMarkdownThemeWithSettings(), this.outputPad, this.getMarkdownTransformers());
2744
2897
  this.chatContainer.addChild(userComponent);
2745
2898
  }
2746
2899
  if (options?.populateHistory) {
@@ -2750,7 +2903,7 @@ export class InteractiveMode {
2750
2903
  break;
2751
2904
  }
2752
2905
  case "assistant": {
2753
- const assistantComponent = new AssistantMessageComponent(message, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel, this.outputPad);
2906
+ const assistantComponent = new AssistantMessageComponent(message, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel, this.outputPad, this.getMarkdownTransformers());
2754
2907
  this.chatContainer.addChild(assistantComponent);
2755
2908
  break;
2756
2909
  }
@@ -2933,12 +3086,6 @@ export class InteractiveMode {
2933
3086
  // Only called when editor is empty (enforced by CustomEditor)
2934
3087
  void this.shutdown();
2935
3088
  }
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
3089
  async shutdown(options) {
2943
3090
  if (this.isShuttingDown)
2944
3091
  return;
@@ -3180,6 +3327,8 @@ export class InteractiveMode {
3180
3327
  this.setToolsExpanded(!this.toolOutputExpanded);
3181
3328
  }
3182
3329
  setToolsExpanded(expanded) {
3330
+ if (expanded === this.toolOutputExpanded)
3331
+ return;
3183
3332
  this.toolOutputExpanded = expanded;
3184
3333
  // An explicit toggle prefers upstream's clean wipe-and-replay even
3185
3334
  // mid-run: the user just pressed the key, so they are interacting at
@@ -3242,7 +3391,7 @@ export class InteractiveMode {
3242
3391
  }
3243
3392
  showError(errorMessage) {
3244
3393
  this.chatContainer.addChild(new Spacer(1));
3245
- this.chatContainer.addChild(new Text(theme.fg("error", `Error: ${errorMessage}`), 1, 0));
3394
+ this.chatContainer.addChild(new Text(theme.fg("error", `Error: ${errorMessage}`), this.outputPad, 0));
3246
3395
  this.ui.requestRender();
3247
3396
  }
3248
3397
  showWarning(warningMessage) {
@@ -3448,52 +3597,50 @@ export class InteractiveMode {
3448
3597
  // =========================================================================
3449
3598
  // Selectors
3450
3599
  // =========================================================================
3600
+ disposeActiveSelector() {
3601
+ const dispose = this.activeSelectorDispose;
3602
+ this.activeSelectorToken = undefined;
3603
+ this.activeSelectorDispose = undefined;
3604
+ dispose?.();
3605
+ }
3451
3606
  /**
3452
3607
  * Shows a selector component in place of the editor.
3453
3608
  * @param create Factory that receives a `done` callback and returns the component and focus target
3454
3609
  */
3455
3610
  showSelector(create) {
3456
- this.activeSelectorCleanup?.();
3457
- this.activeSelectorCleanup = null;
3458
- this.activeSelector = null;
3459
- let selector;
3611
+ const token = {};
3612
+ let dispose;
3460
3613
  let disposed = false;
3461
- let closed = false;
3462
- const dispose = () => {
3463
- if (disposed || !selector)
3614
+ const disposeOnce = () => {
3615
+ if (disposed)
3464
3616
  return;
3465
3617
  disposed = true;
3466
- selector.dispose?.();
3618
+ dispose?.();
3467
3619
  };
3468
3620
  const done = () => {
3469
- if (closed)
3621
+ disposeOnce();
3622
+ if (this.activeSelectorToken !== token)
3470
3623
  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
- }
3624
+ this.activeSelectorToken = undefined;
3625
+ this.activeSelectorDispose = undefined;
3626
+ this.editorContainer.clear();
3627
+ this.editorContainer.addChild(this.editor);
3628
+ this.ui.setFocus(this.editor);
3480
3629
  };
3481
3630
  const created = create(done);
3482
- selector = created.component;
3483
- if (closed) {
3484
- dispose();
3485
- return;
3486
- }
3487
- this.activeSelector = selector;
3488
- this.activeSelectorCleanup = dispose;
3631
+ dispose = created.dispose;
3632
+ this.disposeActiveSelector();
3633
+ this.activeSelectorToken = token;
3634
+ this.activeSelectorDispose = disposeOnce;
3489
3635
  this.editorContainer.clear();
3490
- this.editorContainer.addChild(selector);
3636
+ this.editorContainer.addChild(created.component);
3491
3637
  this.ui.setFocus(created.focus);
3492
3638
  this.ui.requestRender();
3493
3639
  }
3494
3640
  showSettingsSelector() {
3495
3641
  this.showSelector((done) => {
3496
- const selector = new SettingsSelectorComponent({
3642
+ let selector;
3643
+ selector = new SettingsSelectorComponent({
3497
3644
  autoCompact: this.session.autoCompactionEnabled,
3498
3645
  showImages: this.settingsManager.getShowImages(),
3499
3646
  imageWidthCells: this.settingsManager.getImageWidthCells(),
@@ -3510,6 +3657,7 @@ export class InteractiveMode {
3510
3657
  terminalTheme: this.themeController.getTerminalTheme(),
3511
3658
  availableThemes: getAvailableThemes(),
3512
3659
  hideThinkingBlock: this.hideThinkingBlock,
3660
+ mermaidRenderingMode: this.settingsManager.getMermaidRenderingMode(),
3513
3661
  collapseChangelog: this.settingsManager.getCollapseChangelog(),
3514
3662
  enableInstallTelemetry: this.settingsManager.getEnableInstallTelemetry(),
3515
3663
  doubleEscapeAction: this.settingsManager.getDoubleEscapeAction(),
@@ -3523,6 +3671,8 @@ export class InteractiveMode {
3523
3671
  quietStartup: this.settingsManager.getQuietStartup(),
3524
3672
  clearOnShrink: this.settingsManager.getClearOnShrink(),
3525
3673
  showTerminalProgress: this.settingsManager.getShowTerminalProgress(),
3674
+ tuiMode: this.ui.mode,
3675
+ fullscreenScrollbar: this.settingsManager.getFullscreenScrollbar(),
3526
3676
  warnings: this.settingsManager.getWarnings(),
3527
3677
  }, {
3528
3678
  onAutoCompactChange: (enabled) => {
@@ -3591,6 +3741,11 @@ export class InteractiveMode {
3591
3741
  this.clearChat();
3592
3742
  this.rebuildChatFromMessages();
3593
3743
  },
3744
+ onMermaidRenderingModeChange: (mode) => {
3745
+ this.settingsManager.setMermaidRenderingMode(mode);
3746
+ this.chatContainer.invalidate();
3747
+ this.ui.requestRender();
3748
+ },
3594
3749
  onShowCacheMissNoticesChange: (shown) => {
3595
3750
  this.settingsManager.setShowCacheMissNotices(shown);
3596
3751
  this.rebuildChatFromMessages();
@@ -3660,6 +3815,21 @@ export class InteractiveMode {
3660
3815
  onShowTerminalProgressChange: (enabled) => {
3661
3816
  this.settingsManager.setShowTerminalProgress(enabled);
3662
3817
  },
3818
+ onTuiModeChange: (mode) => {
3819
+ if (!this.switchTuiMode(mode)) {
3820
+ selector?.getSettingsList().updateValue("tui-mode", this.ui.mode);
3821
+ this.showStatus("Close active overlays before changing TUI mode");
3822
+ return;
3823
+ }
3824
+ this.settingsManager.setTuiMode(mode);
3825
+ if (!this.activeStatusIndicator)
3826
+ this.statusContainer.clear();
3827
+ this.showStatus(`TUI mode: ${mode}`);
3828
+ },
3829
+ onFullscreenScrollbarChange: (mode) => {
3830
+ this.settingsManager.setFullscreenScrollbar(mode);
3831
+ this.applyFullscreenScrollbarSetting();
3832
+ },
3663
3833
  onWarningsChange: (warnings) => {
3664
3834
  this.settingsManager.setWarnings(warnings);
3665
3835
  },
@@ -3694,20 +3864,37 @@ export class InteractiveMode {
3694
3864
  this.showModelSelector(searchTerm);
3695
3865
  }
3696
3866
  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
- }
3867
+ const cachedModels = this.session.scopedModels.length > 0
3868
+ ? this.session.scopedModels.map((scoped) => scoped.model)
3869
+ : [...this.session.modelRuntime.getAvailableSnapshot()];
3870
+ const cachedMatch = findExactModelReferenceMatch(searchTerm, cachedModels);
3871
+ if (cachedMatch || this.session.scopedModels.length > 0)
3872
+ return cachedMatch;
3873
+ this.showStatus("Refreshing model catalogs…");
3874
+ const controller = new AbortController();
3875
+ let timedOut = false;
3876
+ const timeout = setTimeout(() => {
3877
+ timedOut = true;
3878
+ controller.abort();
3879
+ }, 15_000);
3704
3880
  try {
3705
- await this.session.modelRuntime.refresh();
3706
- return [...(await this.session.modelRuntime.getAvailable())];
3881
+ const result = await this.session.modelRuntime.refresh({ signal: controller.signal });
3882
+ if (result.aborted && timedOut) {
3883
+ this.showWarning("Model refresh timed out; searching cached models.");
3884
+ }
3885
+ else if (result.errors.size > 0) {
3886
+ this.showWarning(`Could not refresh ${[...result.errors.keys()].join(", ")}; searching cached models.`);
3887
+ }
3707
3888
  }
3708
- catch {
3709
- return [];
3889
+ catch (error) {
3890
+ this.showWarning(timedOut
3891
+ ? "Model refresh timed out; searching cached models."
3892
+ : `Could not refresh model catalogs: ${error instanceof Error ? error.message : String(error)}`);
3893
+ }
3894
+ finally {
3895
+ clearTimeout(timeout);
3710
3896
  }
3897
+ return findExactModelReferenceMatch(searchTerm, [...this.session.modelRuntime.getAvailableSnapshot()]);
3711
3898
  }
3712
3899
  /** Update the footer's available provider count from the current snapshot without refreshing catalogs. */
3713
3900
  updateAvailableProviderCount() {
@@ -3809,73 +3996,67 @@ export class InteractiveMode {
3809
3996
  done();
3810
3997
  this.ui.requestRender();
3811
3998
  }, initialSearchInput);
3812
- return { component: selector, focus: selector };
3999
+ return { component: selector, focus: selector, dispose: () => selector.dispose() };
3813
4000
  });
3814
4001
  }
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}`));
4002
+ showModelsSelector() {
4003
+ let availableModels = [...this.session.modelRuntime.getAvailableSnapshot()];
4004
+ let availableModelIds = new Set(availableModels.map((model) => `${model.provider}/${model.id}`));
3820
4005
  const configuredPatterns = this.settingsManager.getEnabledModels();
3821
4006
  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) => {
4007
+ const configuredEnabledIds = (models) => {
4008
+ if (!configuredPatterns?.length)
4009
+ return null;
4010
+ const resolved = resolveModelScopeFromModels(configuredPatterns, models);
4011
+ const ids = resolved.scopedModels.map((scoped) => `${scoped.model.provider}/${scoped.model.id}`);
4012
+ for (const diagnostic of resolved.diagnostics) {
4013
+ if (diagnostic.code === "no-match" && !ids.includes(diagnostic.pattern))
4014
+ ids.push(diagnostic.pattern);
4015
+ }
4016
+ return ids;
4017
+ };
4018
+ let currentEnabledIds = sessionScopedModels.length > 0
4019
+ ? sessionScopedModels.map((scoped) => `${scoped.model.provider}/${scoped.model.id}`)
4020
+ : configuredEnabledIds(availableModels);
4021
+ let selectionChanged = false;
4022
+ const updateSessionModels = (enabledIds) => {
3849
4023
  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));
4024
+ const hasEnabledAvailableModel = enabledIds?.some((id) => availableModelIds.has(id)) ?? false;
4025
+ const allAvailableModelsEnabled = enabledIds !== null && [...availableModelIds].every((id) => enabledIds.includes(id));
3852
4026
  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,
4027
+ const newScopedModels = resolveModelScopeFromModels(enabledIds, availableModels).scopedModels;
4028
+ this.session.setScopedModels(newScopedModels.map((scoped) => ({
4029
+ model: scoped.model,
4030
+ thinkingLevel: scoped.thinkingLevel,
3857
4031
  })));
3858
4032
  }
3859
4033
  else {
3860
- // All enabled or none enabled = no filter
3861
4034
  this.session.setScopedModels([]);
3862
4035
  }
3863
- await this.updateAvailableProviderCount();
4036
+ this.updateAvailableProviderCount();
3864
4037
  this.ui.requestRender();
3865
4038
  };
3866
4039
  this.showSelector((done) => {
4040
+ let disposed = false;
4041
+ let timedOut = false;
4042
+ const controller = new AbortController();
4043
+ const timeout = setTimeout(() => {
4044
+ timedOut = true;
4045
+ controller.abort();
4046
+ }, 15_000);
3867
4047
  const selector = new ScopedModelsSelectorComponent({
3868
- allModels,
4048
+ allModels: availableModels,
3869
4049
  enabledModelIds: currentEnabledIds,
4050
+ refreshStatus: "Refreshing model catalogs…",
3870
4051
  }, {
3871
- onChange: async (enabledIds) => {
3872
- await updateSessionModels(enabledIds);
4052
+ onChange: (enabledIds) => {
4053
+ selectionChanged = true;
4054
+ updateSessionModels(enabledIds);
3873
4055
  },
3874
4056
  onPersist: (enabledIds) => {
3875
- // Persist to settings
3876
4057
  const allEnabled = enabledIds !== null &&
3877
- enabledIds.length === allModels.length &&
3878
- enabledIds.every((id) => allModelIds.has(id));
4058
+ enabledIds.length === availableModels.length &&
4059
+ enabledIds.every((id) => availableModelIds.has(id));
3879
4060
  const newPatterns = enabledIds === null || allEnabled ? undefined : enabledIds;
3880
4061
  this.settingsManager.setEnabledModels(newPatterns ? [...newPatterns] : undefined);
3881
4062
  this.showStatus("Model selection saved to settings");
@@ -3885,7 +4066,51 @@ export class InteractiveMode {
3885
4066
  this.ui.requestRender();
3886
4067
  },
3887
4068
  });
3888
- return { component: selector, focus: selector };
4069
+ void this.session.modelRuntime
4070
+ .refresh({ signal: controller.signal })
4071
+ .then((result) => {
4072
+ if (disposed)
4073
+ return;
4074
+ availableModels = [...this.session.modelRuntime.getAvailableSnapshot()];
4075
+ availableModelIds = new Set(availableModels.map((model) => `${model.provider}/${model.id}`));
4076
+ if (!selectionChanged && sessionScopedModels.length === 0) {
4077
+ currentEnabledIds = configuredEnabledIds(availableModels);
4078
+ selector.updateModels(availableModels, currentEnabledIds);
4079
+ }
4080
+ else {
4081
+ selector.updateModels(availableModels);
4082
+ }
4083
+ if (currentEnabledIds !== null)
4084
+ updateSessionModels(currentEnabledIds);
4085
+ if (result.aborted && timedOut) {
4086
+ selector.setRefreshStatus("Model refresh timed out; showing cached models.", "warning");
4087
+ }
4088
+ else if (result.errors.size > 0) {
4089
+ selector.setRefreshStatus(`Could not refresh ${[...result.errors.keys()].join(", ")}; showing cached models.`, "warning");
4090
+ }
4091
+ else {
4092
+ selector.setRefreshStatus("Model catalogs refreshed.", "success");
4093
+ }
4094
+ this.ui.requestRender();
4095
+ })
4096
+ .catch((error) => {
4097
+ if (disposed)
4098
+ return;
4099
+ selector.setRefreshStatus(timedOut
4100
+ ? "Model refresh timed out; showing cached models."
4101
+ : `Could not refresh model catalogs: ${error instanceof Error ? error.message : String(error)}`, "warning");
4102
+ this.ui.requestRender();
4103
+ })
4104
+ .finally(() => clearTimeout(timeout));
4105
+ return {
4106
+ component: selector,
4107
+ focus: selector,
4108
+ dispose: () => {
4109
+ disposed = true;
4110
+ clearTimeout(timeout);
4111
+ controller.abort();
4112
+ },
4113
+ };
3889
4114
  });
3890
4115
  }
3891
4116
  showUserMessageSelector() {
@@ -4014,6 +4239,9 @@ export class InteractiveMode {
4014
4239
  this.showStatus("Navigation cancelled");
4015
4240
  return;
4016
4241
  }
4242
+ // User-committed tree navigation rebuilds the transcript; its
4243
+ // full redraw bypasses scrollback preservation.
4244
+ this.coalescingTerminal.passNextFullRedraw();
4017
4245
  // Update UI
4018
4246
  this.clearChat();
4019
4247
  this.renderInitialMessages();
@@ -4147,7 +4375,7 @@ export class InteractiveMode {
4147
4375
  return options.sort((a, b) => a.name.localeCompare(b.name));
4148
4376
  }
4149
4377
  async getLogoutProviderOptions() {
4150
- return (await this.session.modelRuntime.listCredentials())
4378
+ return (await this.session.modelRuntime.listCredentials({ signal: AbortSignal.timeout(15_000) }))
4151
4379
  .map(({ providerId, type }) => ({
4152
4380
  id: providerId,
4153
4381
  name: this.session.modelRuntime.getProvider(providerId)?.name ?? providerId,
@@ -4165,7 +4393,6 @@ export class InteractiveMode {
4165
4393
  provider.name.toLowerCase() === normalizedProviderRef);
4166
4394
  }
4167
4395
  async handleLoginCommand(providerRef) {
4168
- await this.session.modelRuntime.getAvailable();
4169
4396
  if (!providerRef) {
4170
4397
  this.showLoginAuthTypeSelector();
4171
4398
  return;
@@ -4279,7 +4506,14 @@ export class InteractiveMode {
4279
4506
  this.showLoginAuthTypeSelector();
4280
4507
  return;
4281
4508
  }
4282
- const providerOptions = await this.getLogoutProviderOptions();
4509
+ let providerOptions;
4510
+ try {
4511
+ providerOptions = await this.getLogoutProviderOptions();
4512
+ }
4513
+ catch (error) {
4514
+ this.showError(`Could not read stored credentials: ${error instanceof Error ? error.message : String(error)}`);
4515
+ return;
4516
+ }
4283
4517
  if (providerOptions.length === 0) {
4284
4518
  this.showStatus("No stored credentials to remove. /logout only removes credentials saved by /login; environment variables and models.json config are unchanged.");
4285
4519
  return;
@@ -4292,7 +4526,9 @@ export class InteractiveMode {
4292
4526
  return;
4293
4527
  }
4294
4528
  try {
4295
- await this.session.modelRuntime.logout(providerOption.id);
4529
+ await this.session.modelRuntime.logout(providerOption.id, {
4530
+ signal: AbortSignal.timeout(15_000),
4531
+ });
4296
4532
  await this.updateAvailableProviderCount();
4297
4533
  const message = providerOption.authType === "oauth"
4298
4534
  ? `Logged out of ${providerOption.name}`
@@ -4300,7 +4536,10 @@ export class InteractiveMode {
4300
4536
  this.showStatus(message);
4301
4537
  }
4302
4538
  catch (error) {
4303
- this.showError(`Logout failed: ${error instanceof Error ? error.message : String(error)}`);
4539
+ const message = error instanceof Error ? error.message : String(error);
4540
+ this.showError(error instanceof CredentialSynchronizationError
4541
+ ? `Credentials removed for ${providerOption.name}, but local model state could not be synchronized: ${message}`
4542
+ : `Logout failed: ${message}`);
4304
4543
  }
4305
4544
  }, () => {
4306
4545
  done();
@@ -4310,12 +4549,11 @@ export class InteractiveMode {
4310
4549
  });
4311
4550
  }
4312
4551
  async completeProviderAuthentication(providerId, providerName, authType, previousModel) {
4313
- await this.session.modelRuntime.getAvailable();
4314
4552
  const actionLabel = authType === "oauth" ? `Logged in to ${providerName}` : `Saved API key for ${providerName}`;
4315
4553
  let selectedModel;
4316
4554
  let selectionError;
4317
4555
  if (isUnknownModel(previousModel)) {
4318
- const availableModels = await this.session.modelRuntime.getAvailable();
4556
+ const availableModels = this.session.modelRuntime.getAvailableSnapshot();
4319
4557
  const providerModels = availableModels.filter((model) => model.provider === providerId);
4320
4558
  if (!hasDefaultModelProvider(providerId)) {
4321
4559
  selectionError = `${actionLabel}, but no default model is configured for provider "${providerId}". Use /model to select a model.`;
@@ -4358,6 +4596,25 @@ export class InteractiveMode {
4358
4596
  void this.maybeWarnAboutAnthropicSubscriptionAuth();
4359
4597
  }
4360
4598
  }
4599
+ const controller = new AbortController();
4600
+ const timeout = setTimeout(() => controller.abort(), 15_000);
4601
+ void this.session.modelRuntime
4602
+ .refresh({ providers: [providerId], signal: controller.signal })
4603
+ .then((result) => {
4604
+ if (result.aborted) {
4605
+ this.showWarning(`${actionLabel}, but its model catalog refresh timed out; using cached models.`);
4606
+ }
4607
+ else if (result.errors.size > 0) {
4608
+ this.showWarning(`${actionLabel}, but its model catalog could not be refreshed; using cached models.`);
4609
+ }
4610
+ this.updateAvailableProviderCount();
4611
+ this.footer.invalidate();
4612
+ this.ui.requestRender();
4613
+ })
4614
+ .catch((error) => {
4615
+ this.showWarning(`${actionLabel}, but its model catalog could not be refreshed: ${error instanceof Error ? error.message : String(error)}`);
4616
+ })
4617
+ .finally(() => clearTimeout(timeout));
4361
4618
  }
4362
4619
  showAmbientAuthDialog(providerOption) {
4363
4620
  const restoreEditor = () => {
@@ -4403,7 +4660,10 @@ export class InteractiveMode {
4403
4660
  catch (error) {
4404
4661
  restoreEditor();
4405
4662
  const errorMsg = error instanceof Error ? error.message : String(error);
4406
- if (errorMsg !== "Login cancelled") {
4663
+ if (error instanceof CredentialSynchronizationError) {
4664
+ this.showError(`Saved API key for ${providerName}, but local model state could not be synchronized: ${errorMsg}`);
4665
+ }
4666
+ else if (errorMsg !== "Login cancelled") {
4407
4667
  this.showError(`Failed to save API key for ${providerName}: ${errorMsg}`);
4408
4668
  }
4409
4669
  }
@@ -4506,7 +4766,10 @@ export class InteractiveMode {
4506
4766
  catch (error) {
4507
4767
  restoreEditor();
4508
4768
  const errorMsg = error instanceof Error ? error.message : String(error);
4509
- if (errorMsg !== "Login cancelled") {
4769
+ if (error instanceof CredentialSynchronizationError) {
4770
+ this.showError(`Logged in to ${providerName}, but local model state could not be synchronized: ${errorMsg}`);
4771
+ }
4772
+ else if (errorMsg !== "Login cancelled") {
4510
4773
  this.showError(`Failed to login to ${providerName}: ${errorMsg}`);
4511
4774
  }
4512
4775
  }
@@ -4551,13 +4814,16 @@ export class InteractiveMode {
4551
4814
  }
4552
4815
  this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
4553
4816
  this.outputPad = this.settingsManager.getOutputPad();
4817
+ // The user asked for this rebuild; its full redraw keeps the
4818
+ // upstream wipe-and-replay even if preservation is still windowed
4819
+ // on from the previous run.
4820
+ this.coalescingTerminal.passNextFullRedraw();
4554
4821
  this.rebuildChatFromMessages();
4555
4822
  chatRestoredBeforeSessionStart = true;
4556
4823
  };
4557
4824
  try {
4558
4825
  await this.session.reload({ beforeSessionStart: restoreChatBeforeSessionStart });
4559
4826
  restoreChatBeforeSessionStart();
4560
- configureHttpDispatcher(this.settingsManager.getHttpIdleTimeoutMs());
4561
4827
  this.keybindings.reload();
4562
4828
  const activeHeader = this.customHeader ?? this.builtInHeader;
4563
4829
  if (isExpandable(activeHeader)) {
@@ -4565,20 +4831,7 @@ export class InteractiveMode {
4565
4831
  }
4566
4832
  setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
4567
4833
  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
- }
4834
+ this.applyRuntimeSettings();
4582
4835
  this.setupAutocompleteProvider();
4583
4836
  const runner = this.session.extensionRunner;
4584
4837
  this.setupExtensionShortcuts(runner);
@@ -4774,7 +5027,7 @@ export class InteractiveMode {
4774
5027
  }
4775
5028
  }
4776
5029
  }
4777
- async handleCopyCommand() {
5030
+ async handleCopyCommand(options = {}) {
4778
5031
  const text = this.session.getLastAssistantText();
4779
5032
  if (!text) {
4780
5033
  this.showError("No agent messages to copy yet.");
@@ -4782,7 +5035,12 @@ export class InteractiveMode {
4782
5035
  }
4783
5036
  try {
4784
5037
  await copyToClipboard(text);
4785
- this.showStatus("Copied last agent message to clipboard");
5038
+ if (options.flashConfirmation && this.ui instanceof TuiAltScreen) {
5039
+ this.ui.flash("Copied!");
5040
+ }
5041
+ else {
5042
+ this.showStatus("Copied last agent message to clipboard");
5043
+ }
4786
5044
  }
4787
5045
  catch (error) {
4788
5046
  this.showError(error instanceof Error ? error.message : String(error));
@@ -5145,9 +5403,7 @@ export class InteractiveMode {
5145
5403
  }
5146
5404
  }
5147
5405
  stop() {
5148
- this.activeSelectorCleanup?.();
5149
- this.activeSelectorCleanup = null;
5150
- this.activeSelector = null;
5406
+ this.disposeActiveSelector();
5151
5407
  if (this.settingsManager.getShowTerminalProgress()) {
5152
5408
  this.ui.terminal.setProgress(false);
5153
5409
  }
@@ -5162,7 +5418,7 @@ export class InteractiveMode {
5162
5418
  this.unsubscribe();
5163
5419
  }
5164
5420
  if (this.isInitialized) {
5165
- this.ui.stop();
5421
+ this.stopInteractiveTui();
5166
5422
  this.isInitialized = false;
5167
5423
  }
5168
5424
  this.unregisterSignalHandlers();