pi-namespace-patch 0.87.1-namespace.1 → 1.0.0-namespace.2

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 (754) hide show
  1. package/CHANGELOG.md +183 -0
  2. package/README.md +100 -25
  3. package/dist/bun/cli.d.ts.map +1 -1
  4. package/dist/bun/restore-sandbox-env.d.ts.map +1 -1
  5. package/dist/bun/restore-sandbox-env.js.map +1 -1
  6. package/dist/bun/runtime-setup.d.ts.map +1 -1
  7. package/dist/bun/runtime-setup.js +4 -1
  8. package/dist/bun/runtime-setup.js.map +1 -1
  9. package/dist/bun/sandbox-env-setup.d.ts.map +1 -1
  10. package/dist/bundle/chunks/anthropic-messages-UID2PALB.js +6 -0
  11. package/dist/bundle/chunks/anthropic.js +2 -2
  12. package/dist/bundle/chunks/azure-openai-responses-AFMVM6NP.js +2 -0
  13. package/dist/bundle/chunks/bedrock-converse-stream.js +2 -2
  14. package/dist/bundle/chunks/chunk-2KTBZM5G.js +132 -0
  15. package/dist/bundle/chunks/{chunk-WIUZI2CJ.js → chunk-2VNGUWBO.js} +3 -3
  16. package/dist/bundle/chunks/{chunk-FUXEF6JQ.js → chunk-3LH3ZQKY.js} +1 -1
  17. package/dist/bundle/chunks/chunk-4N5K4RKC.js +1204 -0
  18. package/dist/bundle/chunks/chunk-6D7LHLKG.js +2 -0
  19. package/dist/bundle/chunks/chunk-7FH3BDRG.js +82 -0
  20. package/dist/bundle/chunks/chunk-7JGR3GZN.js +11 -0
  21. package/dist/bundle/chunks/chunk-H3QXYIF7.js +31 -0
  22. package/dist/bundle/chunks/chunk-IBCPYVFK.js +19 -0
  23. package/dist/bundle/chunks/chunk-KDN6RCEQ.js +4 -0
  24. package/dist/bundle/chunks/chunk-LD2P6SFZ.js +2 -0
  25. package/dist/bundle/chunks/chunk-LTXEMVMA.js +127 -0
  26. package/dist/bundle/chunks/chunk-MJOHEBV7.js +2 -0
  27. package/dist/bundle/chunks/chunk-OSKPX3Z5.js +2 -0
  28. package/dist/bundle/chunks/chunk-PRD6WYBT.js +16 -0
  29. package/dist/bundle/chunks/{chunk-XDUWOHPL.js → chunk-S3GGRYIO.js} +2 -2
  30. package/dist/bundle/chunks/chunk-UTB4DTYQ.js +2 -0
  31. package/dist/bundle/chunks/chunk-VIV3CWXG.js +2 -0
  32. package/dist/bundle/chunks/cli-QOMC26IJ.js +51 -0
  33. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-NPQN263E.js +2 -0
  34. package/dist/bundle/chunks/codemode-worker.js +354 -0
  35. package/dist/bundle/chunks/execute-GVRSEGHL.js +367 -0
  36. package/dist/bundle/chunks/github-copilot.js +1 -1
  37. package/dist/bundle/chunks/google-generative-ai-APTPZOQL.js +2 -0
  38. package/dist/bundle/chunks/google-vertex-MXCOSOY3.js +2 -0
  39. package/dist/bundle/chunks/{lib-HGQMNYVT.js → lib-TEDK3E5I.js} +2 -2
  40. package/dist/bundle/chunks/llama-cpp-classify-XT44PI3C.js +22 -0
  41. package/dist/bundle/chunks/mistral-conversations-DKVFNQL6.js +5 -0
  42. package/dist/bundle/chunks/openai-chatgpt.js +75 -0
  43. package/dist/bundle/chunks/{openai-codex-responses-QDSOTBBO.js → openai-codex-responses-GK67DQQJ.js} +2 -2
  44. package/dist/bundle/chunks/openai-codex.js +2 -2
  45. package/dist/bundle/chunks/{openai-completions-OBX42CLD.js → openai-completions-JXDDPZ23.js} +2 -2
  46. package/dist/bundle/chunks/openai-responses-CQDDLDQF.js +3 -0
  47. package/dist/bundle/chunks/{openrouter-images-N4XVVFSD.js → openrouter-images-ZVXWCSIM.js} +1 -1
  48. package/dist/bundle/chunks/openrouter.js +2 -2
  49. package/dist/bundle/chunks/pi-logo-animation-MPKZE4EK.js +2 -0
  50. package/dist/bundle/chunks/{pi-messages-GFKBWJHZ.js → pi-messages-TM5SOOIW.js} +2 -2
  51. package/dist/bundle/chunks/radius.js +2 -2
  52. package/dist/bundle/chunks/runtime-2SO2JDWM.js +2 -0
  53. package/dist/bundle/chunks/typesafe-system-one-A4CZTQWZ.js +2 -0
  54. package/dist/bundle/chunks/virtual-modules-3THEGRQQ.js +2 -0
  55. package/dist/bundle/cli-runtime.js +1 -1
  56. package/dist/bundle/index.js +1 -1
  57. package/dist/bundle/rpc-entry.js +1 -1
  58. package/dist/cli/args.d.ts.map +1 -1
  59. package/dist/cli/args.js +6 -5
  60. package/dist/cli/args.js.map +1 -1
  61. package/dist/cli/auth-check.d.ts.map +1 -1
  62. package/dist/cli/auth-check.js.map +1 -1
  63. package/dist/cli/auth-command.d.ts.map +1 -1
  64. package/dist/cli/auth-command.js.map +1 -1
  65. package/dist/cli/config-selector.d.ts.map +1 -1
  66. package/dist/cli/config-selector.js.map +1 -1
  67. package/dist/cli/credential-print.d.ts.map +1 -1
  68. package/dist/cli/credential-print.js.map +1 -1
  69. package/dist/cli/file-processor.d.ts.map +1 -1
  70. package/dist/cli/file-processor.js.map +1 -1
  71. package/dist/cli/initial-message.d.ts +1 -1
  72. package/dist/cli/initial-message.d.ts.map +1 -1
  73. package/dist/cli/initial-message.js.map +1 -1
  74. package/dist/cli/list-models.d.ts.map +1 -1
  75. package/dist/cli/list-models.js.map +1 -1
  76. package/dist/cli/project-trust.d.ts.map +1 -1
  77. package/dist/cli/project-trust.js.map +1 -1
  78. package/dist/cli/session-picker.d.ts.map +1 -1
  79. package/dist/cli/session-picker.js.map +1 -1
  80. package/dist/cli/setup.d.ts.map +1 -1
  81. package/dist/cli/setup.js.map +1 -1
  82. package/dist/cli/startup-ui.d.ts.map +1 -1
  83. package/dist/cli/startup-ui.js +38 -30
  84. package/dist/cli/startup-ui.js.map +1 -1
  85. package/dist/cli.d.ts.map +1 -1
  86. package/dist/config.d.ts +15 -4
  87. package/dist/config.d.ts.map +1 -1
  88. package/dist/config.js +33 -4
  89. package/dist/config.js.map +1 -1
  90. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  91. package/dist/core/agent-session-runtime.js +1 -1
  92. package/dist/core/agent-session-runtime.js.map +1 -1
  93. package/dist/core/agent-session-services.d.ts.map +1 -1
  94. package/dist/core/agent-session-services.js +13 -0
  95. package/dist/core/agent-session-services.js.map +1 -1
  96. package/dist/core/agent-session.d.ts +150 -12
  97. package/dist/core/agent-session.d.ts.map +1 -1
  98. package/dist/core/agent-session.js +560 -263
  99. package/dist/core/agent-session.js.map +1 -1
  100. package/dist/core/auth-guidance.d.ts.map +1 -1
  101. package/dist/core/auth-guidance.js.map +1 -1
  102. package/dist/core/auth-storage.d.ts.map +1 -1
  103. package/dist/core/auth-storage.js.map +1 -1
  104. package/dist/core/bash-executor.d.ts.map +1 -1
  105. package/dist/core/bash-executor.js.map +1 -1
  106. package/dist/core/bug-report-upload.d.ts.map +1 -1
  107. package/dist/core/bug-report-upload.js.map +1 -1
  108. package/dist/core/bug-report.d.ts +1 -1
  109. package/dist/core/bug-report.d.ts.map +1 -1
  110. package/dist/core/bug-report.js +1 -1
  111. package/dist/core/bug-report.js.map +1 -1
  112. package/dist/core/cache-stats.d.ts.map +1 -1
  113. package/dist/core/cache-stats.js.map +1 -1
  114. package/dist/core/cache-warmer.d.ts.map +1 -1
  115. package/dist/core/cache-warmer.js.map +1 -1
  116. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  117. package/dist/core/compaction/branch-summarization.js.map +1 -1
  118. package/dist/core/compaction/compaction.d.ts.map +1 -1
  119. package/dist/core/compaction/compaction.js +1 -22
  120. package/dist/core/compaction/compaction.js.map +1 -1
  121. package/dist/core/compaction/index.d.ts.map +1 -1
  122. package/dist/core/compaction/utils.d.ts +2 -1
  123. package/dist/core/compaction/utils.d.ts.map +1 -1
  124. package/dist/core/compaction/utils.js +25 -18
  125. package/dist/core/compaction/utils.js.map +1 -1
  126. package/dist/core/crash-log.d.ts.map +1 -1
  127. package/dist/core/crash-log.js +2 -1
  128. package/dist/core/crash-log.js.map +1 -1
  129. package/dist/core/defaults.d.ts.map +1 -1
  130. package/dist/core/diagnostics.d.ts.map +1 -1
  131. package/dist/core/event-bus.d.ts.map +1 -1
  132. package/dist/core/event-bus.js.map +1 -1
  133. package/dist/core/exec.d.ts.map +1 -1
  134. package/dist/core/exec.js.map +1 -1
  135. package/dist/core/experimental.d.ts.map +1 -1
  136. package/dist/core/experimental.js.map +1 -1
  137. package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
  138. package/dist/core/export-html/ansi-to-html.js.map +1 -1
  139. package/dist/core/export-html/index.d.ts.map +1 -1
  140. package/dist/core/export-html/index.js.map +1 -1
  141. package/dist/core/export-html/template.css +10 -0
  142. package/dist/core/export-html/template.js +66 -17
  143. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  144. package/dist/core/export-html/tool-renderer.js.map +1 -1
  145. package/dist/core/extensions/index.d.ts +1 -1
  146. package/dist/core/extensions/index.d.ts.map +1 -1
  147. package/dist/core/extensions/index.js.map +1 -1
  148. package/dist/core/extensions/jiti-loader.d.ts.map +1 -1
  149. package/dist/core/extensions/jiti-static-loader.d.ts.map +1 -1
  150. package/dist/core/extensions/loader.d.ts.map +1 -1
  151. package/dist/core/extensions/loader.js +67 -5
  152. package/dist/core/extensions/loader.js.map +1 -1
  153. package/dist/core/extensions/runner.d.ts +18 -1
  154. package/dist/core/extensions/runner.d.ts.map +1 -1
  155. package/dist/core/extensions/runner.js +99 -0
  156. package/dist/core/extensions/runner.js.map +1 -1
  157. package/dist/core/extensions/types.d.ts +301 -22
  158. package/dist/core/extensions/types.d.ts.map +1 -1
  159. package/dist/core/extensions/types.js.map +1 -1
  160. package/dist/core/extensions/virtual-modules.d.ts.map +1 -1
  161. package/dist/core/extensions/wrapper.d.ts +2 -2
  162. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  163. package/dist/core/extensions/wrapper.js +3 -3
  164. package/dist/core/extensions/wrapper.js.map +1 -1
  165. package/dist/core/footer-data-provider.d.ts.map +1 -1
  166. package/dist/core/footer-data-provider.js.map +1 -1
  167. package/dist/core/http-dispatcher.d.ts.map +1 -1
  168. package/dist/core/http-dispatcher.js.map +1 -1
  169. package/dist/core/index.d.ts.map +1 -1
  170. package/dist/core/keybindings.d.ts +1 -1
  171. package/dist/core/keybindings.d.ts.map +1 -1
  172. package/dist/core/keybindings.js +1 -1
  173. package/dist/core/keybindings.js.map +1 -1
  174. package/dist/core/mcp-servers.d.ts +125 -0
  175. package/dist/core/mcp-servers.d.ts.map +1 -0
  176. package/dist/core/mcp-servers.js +198 -0
  177. package/dist/core/mcp-servers.js.map +1 -0
  178. package/dist/core/messages.d.ts.map +1 -1
  179. package/dist/core/messages.js.map +1 -1
  180. package/dist/core/model-config.d.ts.map +1 -1
  181. package/dist/core/model-config.js.map +1 -1
  182. package/dist/core/model-registry.d.ts +15 -1
  183. package/dist/core/model-registry.d.ts.map +1 -1
  184. package/dist/core/model-registry.js +29 -0
  185. package/dist/core/model-registry.js.map +1 -1
  186. package/dist/core/model-resolver.d.ts +2 -2
  187. package/dist/core/model-resolver.d.ts.map +1 -1
  188. package/dist/core/model-resolver.js +5 -5
  189. package/dist/core/model-resolver.js.map +1 -1
  190. package/dist/core/model-runtime.d.ts +47 -3
  191. package/dist/core/model-runtime.d.ts.map +1 -1
  192. package/dist/core/model-runtime.js +189 -35
  193. package/dist/core/model-runtime.js.map +1 -1
  194. package/dist/core/models-store.d.ts.map +1 -1
  195. package/dist/core/models-store.js.map +1 -1
  196. package/dist/core/nested-tool-calls.d.ts +102 -0
  197. package/dist/core/nested-tool-calls.d.ts.map +1 -0
  198. package/dist/core/nested-tool-calls.js +178 -0
  199. package/dist/core/nested-tool-calls.js.map +1 -0
  200. package/dist/core/output-guard.d.ts.map +1 -1
  201. package/dist/core/output-guard.js.map +1 -1
  202. package/dist/core/package-manager.d.ts +4 -0
  203. package/dist/core/package-manager.d.ts.map +1 -1
  204. package/dist/core/package-manager.js +59 -12
  205. package/dist/core/package-manager.js.map +1 -1
  206. package/dist/core/pi-manifest.d.ts.map +1 -1
  207. package/dist/core/pi-manifest.js.map +1 -1
  208. package/dist/core/project-trust.d.ts.map +1 -1
  209. package/dist/core/project-trust.js.map +1 -1
  210. package/dist/core/prompt-templates.d.ts.map +1 -1
  211. package/dist/core/prompt-templates.js.map +1 -1
  212. package/dist/core/provider-attribution.d.ts.map +1 -1
  213. package/dist/core/provider-attribution.js.map +1 -1
  214. package/dist/core/provider-composer.d.ts +40 -21
  215. package/dist/core/provider-composer.d.ts.map +1 -1
  216. package/dist/core/provider-composer.js +92 -40
  217. package/dist/core/provider-composer.js.map +1 -1
  218. package/dist/core/radius.d.ts +2 -0
  219. package/dist/core/radius.d.ts.map +1 -1
  220. package/dist/core/radius.js +2 -0
  221. package/dist/core/radius.js.map +1 -1
  222. package/dist/core/remote-catalog-provider.d.ts +8 -1
  223. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  224. package/dist/core/remote-catalog-provider.js +21 -11
  225. package/dist/core/remote-catalog-provider.js.map +1 -1
  226. package/dist/core/resolve-config-value.d.ts.map +1 -1
  227. package/dist/core/resolve-config-value.js.map +1 -1
  228. package/dist/core/resource-loader.d.ts +7 -1
  229. package/dist/core/resource-loader.d.ts.map +1 -1
  230. package/dist/core/resource-loader.js +161 -35
  231. package/dist/core/resource-loader.js.map +1 -1
  232. package/dist/core/runtime-credentials.d.ts.map +1 -1
  233. package/dist/core/runtime-credentials.js.map +1 -1
  234. package/dist/core/sdk.d.ts +1 -1
  235. package/dist/core/sdk.d.ts.map +1 -1
  236. package/dist/core/sdk.js +25 -6
  237. package/dist/core/sdk.js.map +1 -1
  238. package/dist/core/session-cwd.d.ts.map +1 -1
  239. package/dist/core/session-cwd.js.map +1 -1
  240. package/dist/core/session-export.d.ts.map +1 -1
  241. package/dist/core/session-export.js.map +1 -1
  242. package/dist/core/session-manager.d.ts +9 -0
  243. package/dist/core/session-manager.d.ts.map +1 -1
  244. package/dist/core/session-manager.js +22 -22
  245. package/dist/core/session-manager.js.map +1 -1
  246. package/dist/core/settings-diagnostics.d.ts.map +1 -1
  247. package/dist/core/settings-diagnostics.js.map +1 -1
  248. package/dist/core/settings-manager.d.ts +36 -4
  249. package/dist/core/settings-manager.d.ts.map +1 -1
  250. package/dist/core/settings-manager.js +75 -4
  251. package/dist/core/settings-manager.js.map +1 -1
  252. package/dist/core/skills.d.ts.map +1 -1
  253. package/dist/core/skills.js.map +1 -1
  254. package/dist/core/slash-commands.d.ts.map +1 -1
  255. package/dist/core/source-info.d.ts +8 -0
  256. package/dist/core/source-info.d.ts.map +1 -1
  257. package/dist/core/source-info.js +16 -0
  258. package/dist/core/source-info.js.map +1 -1
  259. package/dist/core/system-prompt.d.ts.map +1 -1
  260. package/dist/core/system-prompt.js +1 -1
  261. package/dist/core/system-prompt.js.map +1 -1
  262. package/dist/core/telemetry.d.ts.map +1 -1
  263. package/dist/core/telemetry.js.map +1 -1
  264. package/dist/core/timings.d.ts.map +1 -1
  265. package/dist/core/timings.js.map +1 -1
  266. package/dist/core/tools/bash.d.ts +12 -0
  267. package/dist/core/tools/bash.d.ts.map +1 -1
  268. package/dist/core/tools/bash.js +33 -2
  269. package/dist/core/tools/bash.js.map +1 -1
  270. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  271. package/dist/core/tools/edit-diff.js.map +1 -1
  272. package/dist/core/tools/edit.d.ts.map +1 -1
  273. package/dist/core/tools/edit.js.map +1 -1
  274. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  275. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  276. package/dist/core/tools/find.d.ts.map +1 -1
  277. package/dist/core/tools/find.js.map +1 -1
  278. package/dist/core/tools/grep.d.ts.map +1 -1
  279. package/dist/core/tools/grep.js.map +1 -1
  280. package/dist/core/tools/index.d.ts.map +1 -1
  281. package/dist/core/tools/index.js.map +1 -1
  282. package/dist/core/tools/ls.d.ts.map +1 -1
  283. package/dist/core/tools/ls.js.map +1 -1
  284. package/dist/core/tools/output-accumulator.d.ts +11 -0
  285. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  286. package/dist/core/tools/output-accumulator.js +36 -0
  287. package/dist/core/tools/output-accumulator.js.map +1 -1
  288. package/dist/core/tools/path-utils.d.ts.map +1 -1
  289. package/dist/core/tools/path-utils.js.map +1 -1
  290. package/dist/core/tools/powershell.d.ts.map +1 -1
  291. package/dist/core/tools/powershell.js.map +1 -1
  292. package/dist/core/tools/read.d.ts.map +1 -1
  293. package/dist/core/tools/read.js.map +1 -1
  294. package/dist/core/tools/render-utils.d.ts +6 -0
  295. package/dist/core/tools/render-utils.d.ts.map +1 -1
  296. package/dist/core/tools/render-utils.js +26 -0
  297. package/dist/core/tools/render-utils.js.map +1 -1
  298. package/dist/core/tools/renderers/bash.d.ts.map +1 -1
  299. package/dist/core/tools/renderers/bash.js +11 -32
  300. package/dist/core/tools/renderers/bash.js.map +1 -1
  301. package/dist/core/tools/renderers/edit.d.ts.map +1 -1
  302. package/dist/core/tools/renderers/edit.js.map +1 -1
  303. package/dist/core/tools/renderers/find.d.ts.map +1 -1
  304. package/dist/core/tools/renderers/find.js.map +1 -1
  305. package/dist/core/tools/renderers/grep.d.ts.map +1 -1
  306. package/dist/core/tools/renderers/grep.js.map +1 -1
  307. package/dist/core/tools/renderers/index.d.ts.map +1 -1
  308. package/dist/core/tools/renderers/index.js.map +1 -1
  309. package/dist/core/tools/renderers/ls.d.ts.map +1 -1
  310. package/dist/core/tools/renderers/ls.js.map +1 -1
  311. package/dist/core/tools/renderers/read.d.ts.map +1 -1
  312. package/dist/core/tools/renderers/read.js +3 -2
  313. package/dist/core/tools/renderers/read.js.map +1 -1
  314. package/dist/core/tools/renderers/write.d.ts.map +1 -1
  315. package/dist/core/tools/renderers/write.js.map +1 -1
  316. package/dist/core/tools/tool-definition-wrapper.d.ts +5 -3
  317. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  318. package/dist/core/tools/tool-definition-wrapper.js +3 -1
  319. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  320. package/dist/core/tools/truncate.d.ts +14 -0
  321. package/dist/core/tools/truncate.d.ts.map +1 -1
  322. package/dist/core/tools/truncate.js +29 -0
  323. package/dist/core/tools/truncate.js.map +1 -1
  324. package/dist/core/tools/write.d.ts.map +1 -1
  325. package/dist/core/tools/write.js.map +1 -1
  326. package/dist/core/trust-manager.d.ts.map +1 -1
  327. package/dist/core/trust-manager.js +1 -0
  328. package/dist/core/trust-manager.js.map +1 -1
  329. package/dist/core/usage-totals.d.ts +2 -0
  330. package/dist/core/usage-totals.d.ts.map +1 -1
  331. package/dist/core/usage-totals.js +23 -0
  332. package/dist/core/usage-totals.js.map +1 -1
  333. package/dist/core/virtual-models.d.ts +117 -0
  334. package/dist/core/virtual-models.d.ts.map +1 -0
  335. package/dist/core/virtual-models.js +124 -0
  336. package/dist/core/virtual-models.js.map +1 -0
  337. package/dist/extensions/codemode/execute.d.ts +16 -0
  338. package/dist/extensions/codemode/execute.d.ts.map +1 -0
  339. package/dist/extensions/codemode/execute.js +536 -0
  340. package/dist/extensions/codemode/execute.js.map +1 -0
  341. package/dist/extensions/codemode/execute.lazy.d.ts +3 -0
  342. package/dist/extensions/codemode/execute.lazy.d.ts.map +1 -0
  343. package/dist/extensions/codemode/execute.lazy.js +3 -0
  344. package/dist/extensions/codemode/execute.lazy.js.map +1 -0
  345. package/dist/extensions/codemode/index.d.ts +21 -0
  346. package/dist/extensions/codemode/index.d.ts.map +1 -0
  347. package/dist/extensions/codemode/index.js +31 -0
  348. package/dist/extensions/codemode/index.js.map +1 -0
  349. package/dist/extensions/codemode/renderer.d.ts +12 -0
  350. package/dist/extensions/codemode/renderer.d.ts.map +1 -0
  351. package/dist/extensions/codemode/renderer.js +137 -0
  352. package/dist/extensions/codemode/renderer.js.map +1 -0
  353. package/dist/extensions/codemode/tool.d.ts +123 -0
  354. package/dist/extensions/codemode/tool.d.ts.map +1 -0
  355. package/dist/extensions/codemode/tool.js +268 -0
  356. package/dist/extensions/codemode/tool.js.map +1 -0
  357. package/dist/extensions/codemode/worker.d.ts +7 -0
  358. package/dist/extensions/codemode/worker.d.ts.map +1 -0
  359. package/dist/extensions/codemode/worker.js +7 -0
  360. package/dist/extensions/codemode/worker.js.map +1 -0
  361. package/dist/extensions/index.d.ts.map +1 -1
  362. package/dist/extensions/index.js +11 -1
  363. package/dist/extensions/index.js.map +1 -1
  364. package/dist/extensions/llama/client.d.ts.map +1 -1
  365. package/dist/extensions/llama/client.js.map +1 -1
  366. package/dist/extensions/llama/huggingface.d.ts.map +1 -1
  367. package/dist/extensions/llama/huggingface.js.map +1 -1
  368. package/dist/extensions/llama/index.d.ts.map +1 -1
  369. package/dist/extensions/llama/index.js.map +1 -1
  370. package/dist/extensions/llama/provider.d.ts +1 -1
  371. package/dist/extensions/llama/provider.d.ts.map +1 -1
  372. package/dist/extensions/llama/provider.js +65 -13
  373. package/dist/extensions/llama/provider.js.map +1 -1
  374. package/dist/extensions/llama/ui.d.ts.map +1 -1
  375. package/dist/extensions/llama/ui.js.map +1 -1
  376. package/dist/extensions/mcp/cli.d.ts +21 -0
  377. package/dist/extensions/mcp/cli.d.ts.map +1 -0
  378. package/dist/extensions/mcp/cli.js +500 -0
  379. package/dist/extensions/mcp/cli.js.map +1 -0
  380. package/dist/extensions/mcp/cli.lazy.d.ts +3 -0
  381. package/dist/extensions/mcp/cli.lazy.d.ts.map +1 -0
  382. package/dist/extensions/mcp/cli.lazy.js +3 -0
  383. package/dist/extensions/mcp/cli.lazy.js.map +1 -0
  384. package/dist/extensions/mcp/config.d.ts +72 -0
  385. package/dist/extensions/mcp/config.d.ts.map +1 -0
  386. package/dist/extensions/mcp/config.js +158 -0
  387. package/dist/extensions/mcp/config.js.map +1 -0
  388. package/dist/extensions/mcp/index.d.ts +76 -0
  389. package/dist/extensions/mcp/index.d.ts.map +1 -0
  390. package/dist/extensions/mcp/index.js +1066 -0
  391. package/dist/extensions/mcp/index.js.map +1 -0
  392. package/dist/extensions/mcp/log.d.ts +16 -0
  393. package/dist/extensions/mcp/log.d.ts.map +1 -0
  394. package/dist/extensions/mcp/log.js +66 -0
  395. package/dist/extensions/mcp/log.js.map +1 -0
  396. package/dist/extensions/mcp/oauth.d.ts +97 -0
  397. package/dist/extensions/mcp/oauth.d.ts.map +1 -0
  398. package/dist/extensions/mcp/oauth.js +358 -0
  399. package/dist/extensions/mcp/oauth.js.map +1 -0
  400. package/dist/extensions/mcp/resources.d.ts +43 -0
  401. package/dist/extensions/mcp/resources.d.ts.map +1 -0
  402. package/dist/extensions/mcp/resources.js +262 -0
  403. package/dist/extensions/mcp/resources.js.map +1 -0
  404. package/dist/extensions/mcp/runtime.d.ts +98 -0
  405. package/dist/extensions/mcp/runtime.d.ts.map +1 -0
  406. package/dist/extensions/mcp/runtime.js +395 -0
  407. package/dist/extensions/mcp/runtime.js.map +1 -0
  408. package/dist/extensions/mcp/runtime.lazy.d.ts +3 -0
  409. package/dist/extensions/mcp/runtime.lazy.d.ts.map +1 -0
  410. package/dist/extensions/mcp/runtime.lazy.js +3 -0
  411. package/dist/extensions/mcp/runtime.lazy.js.map +1 -0
  412. package/dist/extensions/mcp/tools.d.ts +84 -0
  413. package/dist/extensions/mcp/tools.d.ts.map +1 -0
  414. package/dist/extensions/mcp/tools.js +251 -0
  415. package/dist/extensions/mcp/tools.js.map +1 -0
  416. package/dist/extensions/mcp/ui.d.ts +60 -0
  417. package/dist/extensions/mcp/ui.d.ts.map +1 -0
  418. package/dist/extensions/mcp/ui.js +174 -0
  419. package/dist/extensions/mcp/ui.js.map +1 -0
  420. package/dist/extensions/tool-search/index.d.ts +12 -0
  421. package/dist/extensions/tool-search/index.d.ts.map +1 -0
  422. package/dist/extensions/tool-search/index.js +15 -0
  423. package/dist/extensions/tool-search/index.js.map +1 -0
  424. package/dist/extensions/tool-search/tool.d.ts +73 -0
  425. package/dist/extensions/tool-search/tool.d.ts.map +1 -0
  426. package/dist/extensions/tool-search/tool.js +189 -0
  427. package/dist/extensions/tool-search/tool.js.map +1 -0
  428. package/dist/index.d.ts +10 -3
  429. package/dist/index.d.ts.map +1 -1
  430. package/dist/index.js +5 -0
  431. package/dist/index.js.map +1 -1
  432. package/dist/main.d.ts.map +1 -1
  433. package/dist/main.js +16 -0
  434. package/dist/main.js.map +1 -1
  435. package/dist/migrations.d.ts.map +1 -1
  436. package/dist/migrations.js.map +1 -1
  437. package/dist/modes/index.d.ts.map +1 -1
  438. package/dist/modes/interactive/bug-report.d.ts.map +1 -1
  439. package/dist/modes/interactive/bug-report.js.map +1 -1
  440. package/dist/modes/interactive/chat-viewport.d.ts.map +1 -1
  441. package/dist/modes/interactive/chat-viewport.js.map +1 -1
  442. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  443. package/dist/modes/interactive/components/armin.js.map +1 -1
  444. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  445. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  446. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  447. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  448. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  449. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  450. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  451. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  452. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  453. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  454. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  455. package/dist/modes/interactive/components/config-selector.js +13 -3
  456. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  457. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
  458. package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
  459. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  460. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  461. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
  462. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  463. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  464. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  465. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
  466. package/dist/modes/interactive/components/daxnuts.js.map +1 -1
  467. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  468. package/dist/modes/interactive/components/diff.js.map +1 -1
  469. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  470. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  471. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -1
  472. package/dist/modes/interactive/components/earendil-announcement.js.map +1 -1
  473. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  474. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  475. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  476. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  477. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  478. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  479. package/dist/modes/interactive/components/first-time-setup.d.ts +4 -4
  480. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
  481. package/dist/modes/interactive/components/first-time-setup.js +8 -2
  482. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  483. package/dist/modes/interactive/components/footer.d.ts +7 -0
  484. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  485. package/dist/modes/interactive/components/footer.js +43 -3
  486. package/dist/modes/interactive/components/footer.js.map +1 -1
  487. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  488. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  489. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  490. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  491. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  492. package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -1
  493. package/dist/modes/interactive/components/markdown-transform.js.map +1 -1
  494. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -1
  495. package/dist/modes/interactive/components/mermaid.js.map +1 -1
  496. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  497. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  498. package/dist/modes/interactive/components/oauth-selector.d.ts +8 -2
  499. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  500. package/dist/modes/interactive/components/oauth-selector.js +24 -21
  501. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  502. package/dist/modes/interactive/components/pi-logo-animation.d.ts +68 -0
  503. package/dist/modes/interactive/components/pi-logo-animation.d.ts.map +1 -0
  504. package/dist/modes/interactive/components/pi-logo-animation.js +1086 -0
  505. package/dist/modes/interactive/components/pi-logo-animation.js.map +1 -0
  506. package/dist/modes/interactive/components/pi-logo-animation.lazy.d.ts +7 -0
  507. package/dist/modes/interactive/components/pi-logo-animation.lazy.d.ts.map +1 -0
  508. package/dist/modes/interactive/components/pi-logo-animation.lazy.js +12 -0
  509. package/dist/modes/interactive/components/pi-logo-animation.lazy.js.map +1 -0
  510. package/dist/modes/interactive/components/pi-logo.d.ts +19 -0
  511. package/dist/modes/interactive/components/pi-logo.d.ts.map +1 -0
  512. package/dist/modes/interactive/components/pi-logo.js +37 -0
  513. package/dist/modes/interactive/components/pi-logo.js.map +1 -0
  514. package/dist/modes/interactive/components/radius-login-selector.d.ts +15 -0
  515. package/dist/modes/interactive/components/radius-login-selector.d.ts.map +1 -0
  516. package/dist/modes/interactive/components/radius-login-selector.js +85 -0
  517. package/dist/modes/interactive/components/radius-login-selector.js.map +1 -0
  518. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  519. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  520. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  521. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  522. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  523. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  524. package/dist/modes/interactive/components/settings-selector.d.ts +6 -4
  525. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  526. package/dist/modes/interactive/components/settings-selector.js +33 -11
  527. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  528. package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -1
  529. package/dist/modes/interactive/components/settings-submenu.js.map +1 -1
  530. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  531. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  532. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  533. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  534. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  535. package/dist/modes/interactive/components/status-indicator.js.map +1 -1
  536. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  537. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  538. package/dist/modes/interactive/components/themed-text.d.ts +17 -0
  539. package/dist/modes/interactive/components/themed-text.d.ts.map +1 -0
  540. package/dist/modes/interactive/components/themed-text.js +29 -0
  541. package/dist/modes/interactive/components/themed-text.js.map +1 -0
  542. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  543. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  544. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  545. package/dist/modes/interactive/components/tool-execution.js +2 -2
  546. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  547. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  548. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  549. package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -1
  550. package/dist/modes/interactive/components/trust-selector.js.map +1 -1
  551. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  552. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  553. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  554. package/dist/modes/interactive/components/user-message.js +5 -4
  555. package/dist/modes/interactive/components/user-message.js.map +1 -1
  556. package/dist/modes/interactive/components/visual-truncate.d.ts +27 -3
  557. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
  558. package/dist/modes/interactive/components/visual-truncate.js +39 -6
  559. package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
  560. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  561. package/dist/modes/interactive/external-editor.js.map +1 -1
  562. package/dist/modes/interactive/interactive-mode.d.ts +21 -0
  563. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  564. package/dist/modes/interactive/interactive-mode.js +348 -197
  565. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  566. package/dist/modes/interactive/model-catalog-refresh.d.ts.map +1 -1
  567. package/dist/modes/interactive/model-catalog-refresh.js.map +1 -1
  568. package/dist/modes/interactive/model-search.d.ts.map +1 -1
  569. package/dist/modes/interactive/model-search.js.map +1 -1
  570. package/dist/modes/interactive/session-share.d.ts.map +1 -1
  571. package/dist/modes/interactive/session-share.js.map +1 -1
  572. package/dist/modes/interactive/theme/dark.json +59 -72
  573. package/dist/modes/interactive/theme/light.json +57 -69
  574. package/dist/modes/interactive/theme/system-theme.d.ts +55 -0
  575. package/dist/modes/interactive/theme/system-theme.d.ts.map +1 -0
  576. package/dist/modes/interactive/theme/system-theme.js +546 -0
  577. package/dist/modes/interactive/theme/system-theme.js.map +1 -0
  578. package/dist/modes/interactive/theme/theme-controller.d.ts +46 -6
  579. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  580. package/dist/modes/interactive/theme/theme-controller.js +127 -47
  581. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  582. package/dist/modes/interactive/theme/theme-json.d.ts +1 -0
  583. package/dist/modes/interactive/theme/theme-json.d.ts.map +1 -1
  584. package/dist/modes/interactive/theme/theme-json.js +3 -1
  585. package/dist/modes/interactive/theme/theme-json.js.map +1 -1
  586. package/dist/modes/interactive/theme/theme-schema.json +7 -2
  587. package/dist/modes/interactive/theme/theme.d.ts +66 -39
  588. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  589. package/dist/modes/interactive/theme/theme.js +238 -317
  590. package/dist/modes/interactive/theme/theme.js.map +1 -1
  591. package/dist/modes/interactive/tui-renderer.d.ts +2 -1
  592. package/dist/modes/interactive/tui-renderer.d.ts.map +1 -1
  593. package/dist/modes/interactive/tui-renderer.js +1 -0
  594. package/dist/modes/interactive/tui-renderer.js.map +1 -1
  595. package/dist/modes/json-event.d.ts.map +1 -1
  596. package/dist/modes/json-event.js.map +1 -1
  597. package/dist/modes/print-mode.d.ts.map +1 -1
  598. package/dist/modes/print-mode.js.map +1 -1
  599. package/dist/modes/rpc/jsonl.d.ts.map +1 -1
  600. package/dist/modes/rpc/jsonl.js.map +1 -1
  601. package/dist/modes/rpc/rpc-client.d.ts +6 -6
  602. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  603. package/dist/modes/rpc/rpc-client.js +12 -8
  604. package/dist/modes/rpc/rpc-client.js.map +1 -1
  605. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  606. package/dist/modes/rpc/rpc-mode.js +7 -9
  607. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  608. package/dist/modes/rpc/rpc-types.d.ts +10 -1
  609. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  610. package/dist/modes/rpc/rpc-types.js.map +1 -1
  611. package/dist/package-manager-cli.d.ts.map +1 -1
  612. package/dist/package-manager-cli.js +6 -2
  613. package/dist/package-manager-cli.js.map +1 -1
  614. package/dist/rpc-entry.d.ts.map +1 -1
  615. package/dist/rpc-entry.js.map +1 -1
  616. package/dist/utils/abort.d.ts.map +1 -1
  617. package/dist/utils/abort.js.map +1 -1
  618. package/dist/utils/ansi.d.ts.map +1 -1
  619. package/dist/utils/ansi.js.map +1 -1
  620. package/dist/utils/changelog.d.ts.map +1 -1
  621. package/dist/utils/changelog.js.map +1 -1
  622. package/dist/utils/child-process.d.ts.map +1 -1
  623. package/dist/utils/child-process.js.map +1 -1
  624. package/dist/utils/clipboard-command.d.ts.map +1 -1
  625. package/dist/utils/clipboard-command.js.map +1 -1
  626. package/dist/utils/clipboard-image.d.ts.map +1 -1
  627. package/dist/utils/clipboard-image.js +14 -17
  628. package/dist/utils/clipboard-image.js.map +1 -1
  629. package/dist/utils/clipboard.d.ts +2 -0
  630. package/dist/utils/clipboard.d.ts.map +1 -1
  631. package/dist/utils/clipboard.js +5 -0
  632. package/dist/utils/clipboard.js.map +1 -1
  633. package/dist/utils/deprecation.d.ts.map +1 -1
  634. package/dist/utils/deprecation.js.map +1 -1
  635. package/dist/utils/exif-orientation.d.ts.map +1 -1
  636. package/dist/utils/exif-orientation.js.map +1 -1
  637. package/dist/utils/frontmatter.d.ts.map +1 -1
  638. package/dist/utils/frontmatter.js.map +1 -1
  639. package/dist/utils/fs-watch.d.ts.map +1 -1
  640. package/dist/utils/fs-watch.js.map +1 -1
  641. package/dist/utils/git.d.ts.map +1 -1
  642. package/dist/utils/git.js.map +1 -1
  643. package/dist/utils/html.d.ts.map +1 -1
  644. package/dist/utils/html.js.map +1 -1
  645. package/dist/utils/image-convert.d.ts.map +1 -1
  646. package/dist/utils/image-convert.js.map +1 -1
  647. package/dist/utils/image-process.d.ts.map +1 -1
  648. package/dist/utils/image-process.js.map +1 -1
  649. package/dist/utils/image-resize-core.d.ts.map +1 -1
  650. package/dist/utils/image-resize-core.js.map +1 -1
  651. package/dist/utils/image-resize-worker.d.ts.map +1 -1
  652. package/dist/utils/image-resize-worker.js.map +1 -1
  653. package/dist/utils/image-resize.d.ts.map +1 -1
  654. package/dist/utils/image-resize.js.map +1 -1
  655. package/dist/utils/json.d.ts.map +1 -1
  656. package/dist/utils/json.js.map +1 -1
  657. package/dist/utils/management-http.d.ts.map +1 -1
  658. package/dist/utils/management-http.js.map +1 -1
  659. package/dist/utils/mime.d.ts.map +1 -1
  660. package/dist/utils/mime.js.map +1 -1
  661. package/dist/utils/open-browser.d.ts.map +1 -1
  662. package/dist/utils/open-browser.js.map +1 -1
  663. package/dist/utils/paths.d.ts +3 -3
  664. package/dist/utils/paths.d.ts.map +1 -1
  665. package/dist/utils/paths.js +5 -4
  666. package/dist/utils/paths.js.map +1 -1
  667. package/dist/utils/photon.d.ts.map +1 -1
  668. package/dist/utils/photon.js.map +1 -1
  669. package/dist/utils/pi-user-agent.d.ts.map +1 -1
  670. package/dist/utils/pi-user-agent.js.map +1 -1
  671. package/dist/utils/shell.d.ts +1 -3
  672. package/dist/utils/shell.d.ts.map +1 -1
  673. package/dist/utils/shell.js +3 -30
  674. package/dist/utils/shell.js.map +1 -1
  675. package/dist/utils/sleep.d.ts.map +1 -1
  676. package/dist/utils/sleep.js.map +1 -1
  677. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  678. package/dist/utils/syntax-highlight.js +2 -0
  679. package/dist/utils/syntax-highlight.js.map +1 -1
  680. package/dist/utils/text.d.ts.map +1 -1
  681. package/dist/utils/text.js.map +1 -1
  682. package/dist/utils/tool-result-images.d.ts.map +1 -1
  683. package/dist/utils/tool-result-images.js.map +1 -1
  684. package/dist/utils/tools-manager.d.ts.map +1 -1
  685. package/dist/utils/tools-manager.js.map +1 -1
  686. package/dist/utils/version-check.d.ts.map +1 -1
  687. package/dist/utils/version-check.js.map +1 -1
  688. package/dist/utils/windows-self-update.d.ts.map +1 -1
  689. package/dist/utils/windows-self-update.js.map +1 -1
  690. package/dist/utils/wsl.d.ts.map +1 -1
  691. package/dist/utils/wsl.js.map +1 -1
  692. package/dist/utils/zip.d.ts.map +1 -1
  693. package/dist/utils/zip.js.map +1 -1
  694. package/docs/cli.md +58 -7
  695. package/docs/codemode.md +207 -0
  696. package/docs/configuration.md +2 -0
  697. package/docs/custom-provider.md +43 -4
  698. package/docs/docs.json +13 -1
  699. package/docs/environment-variables.md +2 -2
  700. package/docs/extensions.md +55 -0
  701. package/docs/index.md +1 -1
  702. package/docs/keybindings.md +1 -1
  703. package/docs/llama-cpp.md +13 -0
  704. package/docs/mcp.md +248 -0
  705. package/docs/models.md +57 -1
  706. package/docs/packages.md +4 -2
  707. package/docs/providers.md +19 -6
  708. package/docs/rpc-commands.md +9 -3
  709. package/docs/rpc.md +3 -1
  710. package/docs/sdk.md +8 -3
  711. package/docs/security.md +2 -0
  712. package/docs/session-format.md +5 -1
  713. package/docs/settings.md +24 -5
  714. package/docs/themes.md +33 -7
  715. package/docs/tui.md +18 -0
  716. package/docs/usage.md +1 -1
  717. package/docs/virtual-models.md +114 -0
  718. package/docs/windows.md +2 -0
  719. package/examples/README.md +1 -1
  720. package/examples/extensions/README.md +2 -0
  721. package/examples/extensions/built-in-tool-renderer.ts +16 -40
  722. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  723. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  724. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  725. package/examples/extensions/custom-provider-gitlab-duo/test.ts +5 -5
  726. package/examples/extensions/debug-provider.ts +90 -0
  727. package/examples/extensions/gondolin/package-lock.json +2 -2
  728. package/examples/extensions/gondolin/package.json +1 -1
  729. package/examples/extensions/jev-router.ts +113 -0
  730. package/examples/extensions/minimal-mode.ts +24 -96
  731. package/examples/extensions/sandbox/package-lock.json +2 -2
  732. package/examples/extensions/sandbox/package.json +1 -1
  733. package/examples/extensions/with-deps/package-lock.json +2 -2
  734. package/examples/extensions/with-deps/package.json +1 -1
  735. package/examples/rpc-client.ts +1 -1
  736. package/examples/rpc-extension-ui.ts +1 -1
  737. package/examples/sdk/14-codemode-mcp.ts +61 -0
  738. package/examples/sdk/README.md +2 -1
  739. package/npm-shrinkwrap.json +88 -43
  740. package/package.json +14 -12
  741. package/dist/bundle/chunks/anthropic-messages-J5WXPPPC.js +0 -6
  742. package/dist/bundle/chunks/azure-openai-responses-HUSQ3GP2.js +0 -2
  743. package/dist/bundle/chunks/chunk-6R7UI4IY.js +0 -2
  744. package/dist/bundle/chunks/chunk-FN7P5NHX.js +0 -1568
  745. package/dist/bundle/chunks/chunk-NUHFSC37.js +0 -25
  746. package/dist/bundle/chunks/chunk-RCZIEVGO.js +0 -11
  747. package/dist/bundle/chunks/chunk-S7SZN6Z3.js +0 -2
  748. package/dist/bundle/chunks/chunk-UXY3GQU2.js +0 -2
  749. package/dist/bundle/chunks/chunk-XNGRGP62.js +0 -2
  750. package/dist/bundle/chunks/google-generative-ai-IMS5EK2Y.js +0 -2
  751. package/dist/bundle/chunks/google-vertex-O4YJEQUW.js +0 -2
  752. package/dist/bundle/chunks/mistral-conversations-NOSQHBEY.js +0 -5
  753. package/dist/bundle/chunks/openai-responses-HWEUZ6WZ.js +0 -2
  754. package/dist/bundle/chunks/virtual-modules-WS3GCBF2.js +0 -2
@@ -25,6 +25,7 @@ import { createCompactionSummaryMessage, createCustomMessage } from "../../core/
25
25
  import { defaultModelPerProvider, findExactModelReferenceMatch, resolveModelScopeFromModels, } from "../../core/model-resolver.js";
26
26
  import { CredentialSynchronizationError } from "../../core/model-runtime.js";
27
27
  import { DefaultPackageManager } from "../../core/package-manager.js";
28
+ import { RADIUS_MCP_URL, RADIUS_PROVIDER_ID } from "../../core/radius.js";
28
29
  import { formatMissingSessionCwdPrompt, MissingSessionCwdError } from "../../core/session-cwd.js";
29
30
  import { SessionManager, sessionEntryToContextMessages, } from "../../core/session-manager.js";
30
31
  import { BUILTIN_SLASH_COMMANDS } from "../../core/slash-commands.js";
@@ -32,8 +33,9 @@ import { isInstallTelemetryEnabled } from "../../core/telemetry.js";
32
33
  import { withBuiltInRenderers } from "../../core/tools/renderers/index.js";
33
34
  import { hasTrustRequiringProjectResources, ProjectTrustStore } from "../../core/trust-manager.js";
34
35
  import { getUsageCostBreakdown } from "../../core/usage-totals.js";
36
+ import { addMcpServerConfig, loadMcpConfig } from "../../extensions/mcp/config.js";
35
37
  import { getChangelogPath, getNewEntries, normalizeChangelogLinks, parseChangelog } from "../../utils/changelog.js";
36
- import { copyToClipboard, readClipboardText } from "../../utils/clipboard.js";
38
+ import { copyToClipboard, readClipboardFilePaths, readClipboardText } from "../../utils/clipboard.js";
37
39
  import { extensionForImageMimeType, readClipboardImage } from "../../utils/clipboard-image.js";
38
40
  import { parseGitUrl } from "../../utils/git.js";
39
41
  import { getCwdRelativePath } from "../../utils/paths.js";
@@ -63,12 +65,16 @@ import { formatKeyText, keyDisplayText, keyHint, keyText, rawKeyHint } from "./c
63
65
  import { LoginDialogComponent } from "./components/login-dialog.js";
64
66
  import { createMermaidMarkdownTransformer } from "./components/mermaid.js";
65
67
  import { ModelSelectorComponent } from "./components/model-selector.js";
66
- import { formatAuthSelectorProviderType, OAuthSelectorComponent, } from "./components/oauth-selector.js";
68
+ import { formatAuthSelectorProviderStatus, formatAuthSelectorProviderType, OAuthSelectorComponent, } from "./components/oauth-selector.js";
69
+ import { piLogoLines, piWordmark, supportsPiLogo } from "./components/pi-logo.js";
70
+ import { playPiLogoAnimation } from "./components/pi-logo-animation.lazy.js";
71
+ import { createLoginMenuSelector } from "./components/radius-login-selector.js";
67
72
  import { ScopedModelsSelectorComponent } from "./components/scoped-models-selector.js";
68
73
  import { SessionSelectorComponent } from "./components/session-selector.js";
69
74
  import { SettingsSelectorComponent } from "./components/settings-selector.js";
70
75
  import { SkillInvocationMessageComponent } from "./components/skill-invocation-message.js";
71
76
  import { BranchSummaryStatusIndicator, CompactionStatusIndicator, IdleStatus, RetryStatusIndicator, WorkingStatusIndicator, } from "./components/status-indicator.js";
77
+ import { ThemedText } from "./components/themed-text.js";
72
78
  import { ThinkingSelectorComponent } from "./components/thinking-selector.js";
73
79
  import { ToolExecutionComponent } from "./components/tool-execution.js";
74
80
  import { TreeSelectorComponent } from "./components/tree-selector.js";
@@ -79,7 +85,7 @@ import { editInExternalEditor } from "./external-editor.js";
79
85
  import { refreshModelCatalogs } from "./model-catalog-refresh.js";
80
86
  import { getModelSearchText } from "./model-search.js";
81
87
  import { shareSession } from "./session-share.js";
82
- import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMarkdownTheme, getThemeByName, onThemeChange, setRegisteredThemes, stopThemeWatcher, Theme, theme, } from "./theme/theme.js";
88
+ import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMarkdownTheme, getThemeByName, onThemeChange, SYSTEM_THEME_NAME, setRegisteredThemes, stopThemeWatcher, Theme, theme, } from "./theme/theme.js";
83
89
  import { InteractiveThemeController } from "./theme/theme-controller.js";
84
90
  import { createInteractiveTui, createInteractiveTuiReference } from "./tui-renderer.js";
85
91
  export { createInteractiveTui, createInteractiveTuiReference } from "./tui-renderer.js";
@@ -92,16 +98,26 @@ function isWorkingStatusEditor(editor) {
92
98
  function isExpandable(obj) {
93
99
  return typeof obj === "object" && obj !== null && "setExpanded" in obj && typeof obj.setExpanded === "function";
94
100
  }
95
- class ExpandableText extends Text {
96
- getCollapsedText;
97
- getExpandedText;
101
+ class ExpandableText extends ThemedText {
102
+ state;
98
103
  constructor(getCollapsedText, getExpandedText, expanded = false, paddingX = 0, paddingY = 0) {
99
- super(expanded ? getExpandedText() : getCollapsedText(), paddingX, paddingY);
100
- this.getCollapsedText = getCollapsedText;
101
- this.getExpandedText = getExpandedText;
104
+ const state = { expanded };
105
+ super(() => (state.expanded ? getExpandedText() : getCollapsedText()), paddingX, paddingY);
106
+ this.state = state;
102
107
  }
103
108
  setExpanded(expanded) {
104
- this.setText(expanded ? this.getExpandedText() : this.getCollapsedText());
109
+ this.state.expanded = expanded;
110
+ this.invalidate();
111
+ }
112
+ }
113
+ /** The built-in header. Clicking its logo (the first two lines, after one column of padding) plays an easter egg. */
114
+ class BuiltInHeader extends ExpandableText {
115
+ onLogoClick;
116
+ handleMouse(event) {
117
+ if (event.type !== "click" || event.y > 1 || event.x < 1 || event.x > 4 || !this.onLogoClick)
118
+ return undefined;
119
+ this.onLogoClick(event.screenX - event.x + 1, event.screenY - event.y);
120
+ return { handled: true };
105
121
  }
106
122
  }
107
123
  function isCustomSessionEntry(item) {
@@ -173,6 +189,7 @@ function llamaCppPostLoginGuidance(actionLabel, loadedModelCount) {
173
189
  ? `${actionLabel}. No llama.cpp models are loaded. Use /llama to load a model, then /model to select it.`
174
190
  : `${actionLabel}. Use /model to select a loaded llama.cpp model, or /llama to manage models.`;
175
191
  }
192
+ const RADIUS_LOGIN_INTRO = "Radius is a service crafted for Pi by the builders of Pi, Earendil Works";
176
193
  const AUTH_TYPE_ORDER = { oauth: 0, api_key: 1 };
177
194
  function createFuzzyAutocompleteItems(items, prefix, getSearchText, toAutocompleteItem) {
178
195
  const filtered = fuzzyFilter(items, prefix, getSearchText);
@@ -195,18 +212,21 @@ function getLoginProviderCompletionOptions(providerOptions) {
195
212
  id: provider.id,
196
213
  name: provider.name,
197
214
  authTypes: [provider.authType],
215
+ subscription: provider.subscription,
198
216
  });
199
217
  }
200
218
  return Array.from(byId.values()).sort((a, b) => a.name.localeCompare(b.name));
201
219
  }
202
220
  function getLoginProviderSearchText(provider) {
203
221
  const authTypes = provider.authTypes
204
- .map((authType) => `${authType} ${formatAuthSelectorProviderType(authType)}`)
222
+ .map((authType) => `${authType} ${formatAuthSelectorProviderType(authType, provider.subscription)}`)
205
223
  .join(" ");
206
224
  return `${provider.id} ${provider.name} ${authTypes}`;
207
225
  }
208
226
  function formatLoginProviderCompletionDescription(provider) {
209
- const authTypes = provider.authTypes.map(formatAuthSelectorProviderType).join("/");
227
+ const authTypes = provider.authTypes
228
+ .map((authType) => formatAuthSelectorProviderType(authType, provider.subscription))
229
+ .join("/");
210
230
  return provider.name === provider.id ? authTypes : `${provider.name} · ${authTypes}`;
211
231
  }
212
232
  export class InteractiveMode {
@@ -256,6 +276,7 @@ export class InteractiveMode {
256
276
  // Status line tracking (for mutating immediately-sequential status updates)
257
277
  lastStatusSpacer = undefined;
258
278
  lastStatusText = undefined;
279
+ lastStatusMessage = "";
259
280
  managedToolStatusStarted = false;
260
281
  // Streaming message tracking
261
282
  streamingComponent = undefined;
@@ -341,7 +362,7 @@ export class InteractiveMode {
341
362
  });
342
363
  this.runtimeHost.setRebindSession(async () => {
343
364
  await this.rebindCurrentSession({ renderBeforeBind: true });
344
- await this.themeController.applyFromSettings();
365
+ this.themeController.applyFromSettings();
345
366
  });
346
367
  this.version = VERSION;
347
368
  this.renderer = createInteractiveTui({
@@ -351,6 +372,7 @@ export class InteractiveMode {
351
372
  terminal: options.terminal,
352
373
  onRightClickPaste: this.onRightClickPaste,
353
374
  fullscreenCopyOnSelect: this.settingsManager.getFullscreenCopyOnSelect(),
375
+ fullscreenWheelScrollLines: this.settingsManager.getFullscreenWheelScrollLines(),
354
376
  });
355
377
  this.ui = createInteractiveTuiReference(() => this.renderer);
356
378
  this.ui.setClearOnShrink(this.settingsManager.getClearOnShrink());
@@ -395,7 +417,8 @@ export class InteractiveMode {
395
417
  });
396
418
  }
397
419
  getAutocompleteSourceTag(sourceInfo) {
398
- if (!sourceInfo) {
420
+ // Built-in extension commands are untagged, like built-in commands.
421
+ if (!sourceInfo || sourceInfo.source === "builtin") {
399
422
  return undefined;
400
423
  }
401
424
  const scopePrefix = sourceInfo.scope === "user" ? "u" : sourceInfo.scope === "project" ? "p" : "t";
@@ -558,7 +581,7 @@ export class InteractiveMode {
558
581
  this.chatContainer.addChild(new Text(condensedText, 1, 0));
559
582
  }
560
583
  else {
561
- this.chatContainer.addChild(new Text(theme.bold(theme.fg("accent", "What's New")), 1, 0));
584
+ this.chatContainer.addChild(new ThemedText(() => theme.bold(theme.fg("accent", "What's New")), 1, 0));
562
585
  this.chatContainer.addChild(new Spacer(1));
563
586
  this.chatContainer.addChild(new Markdown(this.changelogMarkdown.trim(), 1, 0, this.getMarkdownThemeWithSettings()));
564
587
  this.chatContainer.addChild(new Spacer(1));
@@ -610,6 +633,7 @@ export class InteractiveMode {
610
633
  terminal,
611
634
  onRightClickPaste: this.onRightClickPaste,
612
635
  fullscreenCopyOnSelect: this.settingsManager.getFullscreenCopyOnSelect(),
636
+ fullscreenWheelScrollLines: this.settingsManager.getFullscreenWheelScrollLines(),
613
637
  });
614
638
  nextUi.setClearOnShrink(clearOnShrink);
615
639
  nextUi.onDebug = onDebug;
@@ -639,7 +663,7 @@ export class InteractiveMode {
639
663
  this.registerSignalHandlers();
640
664
  // Load changelog (only show new entries, skip for resumed sessions)
641
665
  this.changelogMarkdown = this.getChangelogForDisplay();
642
- if (this.session.scopedModels.length > 0 && (this.options.verbose || !this.settingsManager.getQuietStartup())) {
666
+ if (this.session.scopedModels.length > 0 && this.shouldShowStartupDetails()) {
643
667
  const modelList = this.session.scopedModels
644
668
  .map((sm) => {
645
669
  const thinkingStr = sm.thinkingLevel ? `:${sm.thinkingLevel}` : "";
@@ -685,13 +709,26 @@ export class InteractiveMode {
685
709
  // Start the UI before initializing extensions so session_start handlers can use interactive dialogs
686
710
  this.ui.start();
687
711
  this.isInitialized = true;
688
- await this.themeController.applyFromSettings();
712
+ this.themeController.applyFromSettings();
713
+ // The header and startup notices bake theme colors into their text, so build them once the terminal
714
+ // reported its colors. This ends at the terminal's DA1 reply, or after 100 ms if it answers nothing.
715
+ await this.themeController.waitForTerminalColors();
689
716
  // Add header with keybindings from config (unless silenced)
690
- if (this.options.verbose || !this.settingsManager.getQuietStartup()) {
691
- const logo = theme.bold(theme.fg("accent", APP_NAME)) + theme.fg("dim", ` v${this.version}`);
717
+ if (this.shouldShowStartupHeader()) {
718
+ const showDetails = this.shouldShowStartupDetails();
719
+ // Built on demand so the header follows theme changes. The logo's first line carries the version,
720
+ // its second line the first line of key hints. Terminals that cannot render the logo get a
721
+ // "Pi vX" line instead, with the key hints below it.
722
+ const showLogo = supportsPiLogo();
723
+ const withLogo = (hints) => {
724
+ if (!showLogo)
725
+ return `${piWordmark()} ${theme.fg("dim", `v${this.version}`)}\n${hints}`;
726
+ const [top, bottom] = piLogoLines();
727
+ return `${top} ${theme.fg("dim", `v${this.version}`)}\n${bottom} ${hints}`;
728
+ };
692
729
  // Build startup instructions using keybinding hint helpers
693
730
  const hint = (keybinding, description) => keyHint(keybinding, description);
694
- const expandedInstructions = [
731
+ const expandedInstructions = () => [
695
732
  hint("app.interrupt", "to interrupt"),
696
733
  hint("app.clear", "to clear"),
697
734
  rawKeyHint(`${keyText("app.clear")} twice`, "to exit"),
@@ -709,19 +746,22 @@ export class InteractiveMode {
709
746
  rawKeyHint("!!", "to run bash (no context)"),
710
747
  hint("app.message.followUp", "to queue follow-up"),
711
748
  hint("app.message.dequeue", "to edit all queued messages"),
712
- hint("app.clipboard.pasteImage", "to paste image (with text fallback)"),
749
+ hint("app.clipboard.pasteImage", "to paste files on macOS, images, or text"),
713
750
  rawKeyHint("drop files", "to attach"),
714
751
  ].join("\n");
715
- const compactInstructions = [
752
+ const compactInstructions = () => [
716
753
  hint("app.interrupt", "interrupt"),
717
754
  rawKeyHint(`${keyText("app.clear")}/${keyText("app.exit")}`, "clear/exit"),
718
755
  rawKeyHint("/", "commands"),
719
756
  rawKeyHint("!", "bash"),
720
757
  hint("app.tools.expand", "more"),
721
758
  ].join(theme.fg("muted", " · "));
722
- const compactOnboarding = theme.fg("dim", `Press ${keyText("app.tools.expand")} to show full startup help and loaded resources.`);
723
- const onboarding = theme.fg("dim", `Pi can explain its own features and look up its docs. Ask it how to use or extend Pi.`);
724
- this.builtInHeader = new ExpandableText(() => `${logo}\n${compactInstructions}\n${compactOnboarding}\n\n${onboarding}`, () => `${logo}\n${expandedInstructions}\n\n${onboarding}`, this.getStartupExpansionState(), 1, 0);
759
+ const compactOnboarding = () => theme.fg("dim", `Press ${keyText("app.tools.expand")} to show full startup help${showDetails ? " and loaded resources" : ""}.`);
760
+ const onboarding = () => theme.fg("dim", `Pi can explain its own features and look up its docs. Ask it how to use or extend Pi.`);
761
+ const header = new BuiltInHeader(() => `${withLogo(compactInstructions())}\n${compactOnboarding()}\n\n${onboarding()}`, () => `${withLogo(expandedInstructions())}\n\n${onboarding()}`, this.getStartupExpansionState(), 1, 0);
762
+ if (showLogo)
763
+ header.onLogoClick = (column, row) => playPiLogoAnimation(this.renderer, column, row);
764
+ this.builtInHeader = header;
725
765
  // Setup UI layout
726
766
  this.headerContainer.addChild(new Spacer(1));
727
767
  this.headerContainer.addChild(this.builtInHeader);
@@ -1020,6 +1060,14 @@ export class InteractiveMode {
1020
1060
  getStartupExpansionState() {
1021
1061
  return this.options.verbose || this.toolOutputExpanded;
1022
1062
  }
1063
+ /** Startup header (logo, version, key hints). Hidden only by quietStartup: true. */
1064
+ shouldShowStartupHeader() {
1065
+ return this.options.verbose === true || this.settingsManager.getQuietStartup() !== true;
1066
+ }
1067
+ /** Startup details (model scope, loaded resources). Hidden by quietStartup: true or "header". */
1068
+ shouldShowStartupDetails() {
1069
+ return this.options.verbose === true || this.settingsManager.getQuietStartup() === false;
1070
+ }
1023
1071
  /**
1024
1072
  * Get a short path relative to the package root for display.
1025
1073
  */
@@ -1281,7 +1329,7 @@ export class InteractiveMode {
1281
1329
  showLoadedResources(options) {
1282
1330
  // Resource rendering is idempotent; chat clears no longer clear this separate container.
1283
1331
  this.loadedResourcesContainer.clear();
1284
- const showListing = options?.force || this.options.verbose || !this.settingsManager.getQuietStartup();
1332
+ const showListing = options?.force || this.shouldShowStartupDetails();
1285
1333
  const showDiagnostics = showListing || options?.showDiagnosticsWhenQuiet === true;
1286
1334
  if (!showListing && !showDiagnostics) {
1287
1335
  return;
@@ -1294,8 +1342,9 @@ export class InteractiveMode {
1294
1342
  }
1295
1343
  return theme.fg("dim", ` ${labels.join(", ")}`);
1296
1344
  };
1345
+ // Bodies are built on demand so the listing follows theme changes.
1297
1346
  const addLoadedSection = (name, collapsedBody, expandedBody = collapsedBody, color = "mdHeading") => {
1298
- const section = new ExpandableText(() => `${sectionHeader(name, color)}\n${collapsedBody}`, () => `${sectionHeader(name, color)}\n${expandedBody}`, this.getStartupExpansionState(), 0, 0);
1347
+ const section = new ExpandableText(() => `${sectionHeader(name, color)}\n${collapsedBody()}`, () => `${sectionHeader(name, color)}\n${expandedBody()}`, this.getStartupExpansionState(), 0, 0);
1299
1348
  this.loadedResourcesContainer.addChild(section);
1300
1349
  this.loadedResourcesContainer.addChild(new Spacer(1));
1301
1350
  };
@@ -1340,27 +1389,25 @@ export class InteractiveMode {
1340
1389
  ];
1341
1390
  if (contextFiles.length > 0) {
1342
1391
  this.loadedResourcesContainer.addChild(new Spacer(1));
1343
- const contextList = contextFiles
1344
- .map((f) => theme.fg("dim", ` ${this.formatDisplayPath(f.path)}`))
1345
- .join("\n");
1346
- const contextCompactList = formatCompactList(contextFiles.map((contextFile) => this.formatContextPath(contextFile.path)), { sort: false });
1392
+ const contextList = () => contextFiles.map((f) => theme.fg("dim", ` ${this.formatDisplayPath(f.path)}`)).join("\n");
1393
+ const contextCompactList = () => formatCompactList(contextFiles.map((contextFile) => this.formatContextPath(contextFile.path)), { sort: false });
1347
1394
  addLoadedSection("Context", contextCompactList, contextList);
1348
1395
  }
1349
1396
  const skills = skillsResult.skills;
1350
1397
  if (skills.length > 0) {
1351
1398
  const groups = this.buildScopeGroups(skills.map((skill) => ({ path: skill.filePath, sourceInfo: skill.sourceInfo })));
1352
- const skillList = this.formatScopeGroups(groups, {
1399
+ const skillList = () => this.formatScopeGroups(groups, {
1353
1400
  formatPath: (item) => this.formatDisplayPath(item.path),
1354
1401
  formatPackagePath: (item) => this.getShortPath(item.path, item.sourceInfo),
1355
1402
  });
1356
- const skillCompactList = formatCompactList(skills.map((skill) => skill.name));
1403
+ const skillCompactList = () => formatCompactList(skills.map((skill) => skill.name));
1357
1404
  addLoadedSection("Skills", skillCompactList, skillList);
1358
1405
  }
1359
1406
  const templates = this.session.promptTemplates;
1360
1407
  if (templates.length > 0) {
1361
1408
  const groups = this.buildScopeGroups(templates.map((template) => ({ path: template.filePath, sourceInfo: template.sourceInfo })));
1362
1409
  const templateByPath = new Map(templates.map((t) => [t.filePath, t]));
1363
- const templateList = this.formatScopeGroups(groups, {
1410
+ const templateList = () => this.formatScopeGroups(groups, {
1364
1411
  formatPath: (item) => {
1365
1412
  const template = templateByPath.get(item.path);
1366
1413
  return template ? `/${template.name}` : this.formatDisplayPath(item.path);
@@ -1370,53 +1417,40 @@ export class InteractiveMode {
1370
1417
  return template ? `/${template.name}` : this.formatDisplayPath(item.path);
1371
1418
  },
1372
1419
  });
1373
- const promptCompactList = formatCompactList(templates.map((template) => `/${template.name}`));
1420
+ const promptCompactList = () => formatCompactList(templates.map((template) => `/${template.name}`));
1374
1421
  addLoadedSection("Prompts", promptCompactList, templateList);
1375
1422
  }
1376
1423
  if (extensions.length > 0) {
1377
1424
  const groups = this.buildScopeGroups(extensions);
1378
- const extList = this.formatScopeGroups(groups, {
1425
+ const extList = () => this.formatScopeGroups(groups, {
1379
1426
  formatPath: (item) => this.formatExtensionDisplayPath(item.path),
1380
1427
  formatPackagePath: (item) => this.formatExtensionDisplayPath(this.getShortPath(item.path, item.sourceInfo)),
1381
1428
  });
1382
- const extensionCompactList = formatCompactList(this.getCompactExtensionLabels(extensions));
1429
+ const extensionLabels = this.getCompactExtensionLabels(extensions);
1430
+ const extensionCompactList = () => formatCompactList(extensionLabels);
1383
1431
  addLoadedSection("Extensions", extensionCompactList, extList, "mdHeading");
1384
1432
  }
1385
- // Show loaded themes (excluding built-in)
1386
- const loadedThemes = themesResult.themes;
1387
- const customThemes = loadedThemes.filter((t) => t.sourcePath);
1388
- if (customThemes.length > 0) {
1389
- const groups = this.buildScopeGroups(customThemes.map((loadedTheme) => ({
1390
- path: loadedTheme.sourcePath,
1391
- sourceInfo: loadedTheme.sourceInfo,
1392
- })));
1393
- const themeList = this.formatScopeGroups(groups, {
1394
- formatPath: (item) => this.formatDisplayPath(item.path),
1395
- formatPackagePath: (item) => this.getShortPath(item.path, item.sourceInfo),
1396
- });
1397
- const themeCompactList = formatCompactList(customThemes.map((loadedTheme) => loadedTheme.name ?? this.getCompactPathLabel(loadedTheme.sourcePath, loadedTheme.sourceInfo)));
1398
- addLoadedSection("Themes", themeCompactList, themeList);
1399
- }
1400
1433
  }
1401
1434
  if (showDiagnostics) {
1402
1435
  const skillDiagnostics = skillsResult.diagnostics;
1403
1436
  if (skillDiagnostics.length > 0) {
1404
- const warningLines = this.formatDiagnostics(skillDiagnostics, sourceInfos);
1405
- this.loadedResourcesContainer.addChild(new Text(`${theme.fg("warning", "[Skill conflicts]")}\n${warningLines}`, 0, 0));
1437
+ const warningLines = () => this.formatDiagnostics(skillDiagnostics, sourceInfos);
1438
+ this.loadedResourcesContainer.addChild(new ThemedText(() => `${theme.fg("warning", "[Skill conflicts]")}\n${warningLines()}`, 0, 0));
1406
1439
  this.loadedResourcesContainer.addChild(new Spacer(1));
1407
1440
  }
1408
1441
  const promptDiagnostics = promptsResult.diagnostics;
1409
1442
  if (promptDiagnostics.length > 0) {
1410
- const warningLines = this.formatDiagnostics(promptDiagnostics, sourceInfos);
1411
- this.loadedResourcesContainer.addChild(new Text(`${theme.fg("warning", "[Prompt conflicts]")}\n${warningLines}`, 0, 0));
1443
+ const warningLines = () => this.formatDiagnostics(promptDiagnostics, sourceInfos);
1444
+ this.loadedResourcesContainer.addChild(new ThemedText(() => `${theme.fg("warning", "[Prompt conflicts]")}\n${warningLines()}`, 0, 0));
1412
1445
  this.loadedResourcesContainer.addChild(new Spacer(1));
1413
1446
  }
1414
1447
  const extensionDiagnostics = [];
1415
- const extensionErrors = this.session.resourceLoader.getExtensions().errors;
1416
- if (extensionErrors.length > 0) {
1417
- for (const error of extensionErrors) {
1418
- extensionDiagnostics.push({ type: "error", message: error.error, path: error.path });
1419
- }
1448
+ const extensionsResult = this.session.resourceLoader.getExtensions();
1449
+ for (const error of extensionsResult.errors) {
1450
+ extensionDiagnostics.push({ type: "error", message: error.error, path: error.path });
1451
+ }
1452
+ for (const warning of extensionsResult.warnings ?? []) {
1453
+ extensionDiagnostics.push({ type: "warning", message: warning.warning, path: warning.path });
1420
1454
  }
1421
1455
  const commandDiagnostics = this.session.extensionRunner.getCommandDiagnostics();
1422
1456
  extensionDiagnostics.push(...commandDiagnostics);
@@ -1424,14 +1458,14 @@ export class InteractiveMode {
1424
1458
  const shortcutDiagnostics = this.session.extensionRunner.getShortcutDiagnostics();
1425
1459
  extensionDiagnostics.push(...shortcutDiagnostics);
1426
1460
  if (extensionDiagnostics.length > 0) {
1427
- const warningLines = this.formatDiagnostics(extensionDiagnostics, sourceInfos);
1428
- this.loadedResourcesContainer.addChild(new Text(`${theme.fg("warning", "[Extension issues]")}\n${warningLines}`, 0, 0));
1461
+ const warningLines = () => this.formatDiagnostics(extensionDiagnostics, sourceInfos);
1462
+ this.loadedResourcesContainer.addChild(new ThemedText(() => `${theme.fg("warning", "[Extension issues]")}\n${warningLines()}`, 0, 0));
1429
1463
  this.loadedResourcesContainer.addChild(new Spacer(1));
1430
1464
  }
1431
1465
  const themeDiagnostics = themesResult.diagnostics;
1432
1466
  if (themeDiagnostics.length > 0) {
1433
- const warningLines = this.formatDiagnostics(themeDiagnostics, sourceInfos);
1434
- this.loadedResourcesContainer.addChild(new Text(`${theme.fg("warning", "[Theme conflicts]")}\n${warningLines}`, 0, 0));
1467
+ const warningLines = () => this.formatDiagnostics(themeDiagnostics, sourceInfos);
1468
+ this.loadedResourcesContainer.addChild(new ThemedText(() => `${theme.fg("warning", "[Theme conflicts]")}\n${warningLines()}`, 0, 0));
1435
1469
  this.loadedResourcesContainer.addChild(new Spacer(1));
1436
1470
  }
1437
1471
  }
@@ -1523,6 +1557,7 @@ export class InteractiveMode {
1523
1557
  this.applyFullscreenScrollbarSetting();
1524
1558
  if (this.renderer instanceof TuiAltScreen) {
1525
1559
  this.renderer.setCopyOnSelect(this.settingsManager.getFullscreenCopyOnSelect());
1560
+ this.renderer.setWheelScrollLines(this.settingsManager.getFullscreenWheelScrollLines());
1526
1561
  }
1527
1562
  this.footer.setSession(this.session);
1528
1563
  this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled);
@@ -1569,10 +1604,11 @@ export class InteractiveMode {
1569
1604
  this.showError(`${prefix}: ${message}`);
1570
1605
  const extensionHint = this.getCrashExtensionHint(error);
1571
1606
  if (extensionHint) {
1572
- this.chatContainer.addChild(new Text(theme.fg("warning", extensionHint), this.outputPad, 0));
1607
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("warning", extensionHint), this.outputPad, 0));
1573
1608
  }
1574
1609
  if (this.recordCrash("fatal_error", error)) {
1575
- this.chatContainer.addChild(new Text(theme.fg("muted", this.crashReportInstructions()), this.outputPad, 0));
1610
+ const instructions = this.crashReportInstructions();
1611
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("muted", instructions), this.outputPad, 0));
1576
1612
  }
1577
1613
  stopThemeWatcher();
1578
1614
  this.stop("transcript");
@@ -1608,7 +1644,7 @@ export class InteractiveMode {
1608
1644
  if (this.bugReportHintShown)
1609
1645
  return;
1610
1646
  this.bugReportHintShown = true;
1611
- this.chatContainer.addChild(new Text(theme.fg("muted", `If this looks like a ${APP_NAME} bug, /bug sends a report to the developers.`), this.outputPad, 0));
1647
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("muted", `If this looks like a ${APP_NAME} bug, /bug sends a report to the developers.`), this.outputPad, 0));
1612
1648
  this.ui.requestRender();
1613
1649
  }
1614
1650
  maybeSuggestBugReport(message) {
@@ -1805,7 +1841,7 @@ export class InteractiveMode {
1805
1841
  container.addChild(new Text(line, 1, 0));
1806
1842
  }
1807
1843
  if (content.length > InteractiveMode.MAX_WIDGET_LINES) {
1808
- container.addChild(new Text(theme.fg("muted", "... (widget truncated)"), 1, 0));
1844
+ container.addChild(new ThemedText(() => theme.fg("muted", "... (widget truncated)"), 1, 0));
1809
1845
  }
1810
1846
  component = container;
1811
1847
  }
@@ -2318,17 +2354,14 @@ export class InteractiveMode {
2318
2354
  */
2319
2355
  showExtensionError(extensionPath, error, stack) {
2320
2356
  const errorMsg = `Extension "${extensionPath}" error: ${error}`;
2321
- const errorText = new Text(theme.fg("error", errorMsg), 1, 0);
2357
+ const errorText = new ThemedText(() => theme.fg("error", errorMsg), 1, 0);
2322
2358
  this.chatContainer.addChild(errorText);
2323
2359
  if (stack) {
2324
2360
  // Show stack trace in dim color, indented
2325
- const stackLines = stack
2326
- .split("\n")
2327
- .slice(1) // Skip first line (duplicates error message)
2328
- .map((line) => theme.fg("dim", ` ${line.trim()}`))
2329
- .join("\n");
2330
- if (stackLines) {
2331
- this.chatContainer.addChild(new Text(stackLines, 1, 0));
2361
+ const stackLines = stack.split("\n").slice(1); // Skip first line (duplicates error message)
2362
+ if (stackLines.length > 0) {
2363
+ const renderStack = () => stackLines.map((line) => theme.fg("dim", ` ${line.trim()}`)).join("\n");
2364
+ this.chatContainer.addChild(new ThemedText(renderStack, 1, 0));
2332
2365
  }
2333
2366
  }
2334
2367
  this.ui.requestRender();
@@ -2398,8 +2431,8 @@ export class InteractiveMode {
2398
2431
  this.updateEditorBorderColor();
2399
2432
  }
2400
2433
  };
2401
- // Handle clipboard paste (triggered on Ctrl+V). Images are attached by path;
2402
- // otherwise, paste plain text from the system clipboard.
2434
+ // Handle clipboard paste (triggered on Ctrl+V). Copied files use their original paths,
2435
+ // images are attached via temporary files, and plain text is the final fallback.
2403
2436
  this.defaultEditor.onPasteImage = () => {
2404
2437
  void this.handleClipboardPaste();
2405
2438
  };
@@ -2422,6 +2455,22 @@ export class InteractiveMode {
2422
2455
  }
2423
2456
  async handleClipboardPaste() {
2424
2457
  try {
2458
+ const filePaths = await readClipboardFilePaths();
2459
+ if (filePaths) {
2460
+ if (filePaths.some((filePath) => /\p{Cc}/u.test(filePath))) {
2461
+ throw new Error("Clipboard file path contains control characters");
2462
+ }
2463
+ const paths = this.isBashMode ? filePaths.map(quoteIfNeeded).join(" ") : filePaths.join("\n");
2464
+ const cursor = this.editor.getCursor?.();
2465
+ const currentLine = cursor ? (this.editor.getText().split("\n")[cursor.line] ?? "") : "";
2466
+ const characterBeforeCursor = cursor && cursor.col > 0 ? currentLine[cursor.col - 1] : "";
2467
+ const characterAfterCursor = cursor ? currentLine[cursor.col] : "";
2468
+ const leadingSpace = characterBeforeCursor && !/\s/.test(characterBeforeCursor) ? " " : "";
2469
+ const trailingSpace = characterAfterCursor && !/\s/.test(characterAfterCursor) ? " " : "";
2470
+ this.editor.insertTextAtCursor?.(`${leadingSpace}${paths}${trailingSpace}`);
2471
+ this.ui.requestRender();
2472
+ return;
2473
+ }
2425
2474
  const image = await readClipboardImage();
2426
2475
  if (image) {
2427
2476
  const tmpDir = os.tmpdir();
@@ -2439,8 +2488,8 @@ export class InteractiveMode {
2439
2488
  this.ui.requestRender();
2440
2489
  }
2441
2490
  }
2442
- catch {
2443
- // Silently ignore clipboard errors (may not have permission, etc.)
2491
+ catch (error) {
2492
+ this.showError(`Failed to paste from clipboard: ${error instanceof Error ? error.message : String(error)}`);
2444
2493
  }
2445
2494
  }
2446
2495
  handleStartupSubmit(text) {
@@ -2821,6 +2870,9 @@ export class InteractiveMode {
2821
2870
  // The bash execution callback handles TUI output rendering.
2822
2871
  break;
2823
2872
  case "tool_execution_start": {
2873
+ // Nested calls (from codemode scripts) are shown inside their parent's row.
2874
+ if (event.parentToolCallId)
2875
+ break;
2824
2876
  let component = this.pendingTools.get(event.toolCallId);
2825
2877
  if (!component) {
2826
2878
  component = new ToolExecutionComponent(event.toolName, event.toolCallId, event.args, {
@@ -2922,7 +2974,8 @@ export class InteractiveMode {
2922
2974
  }
2923
2975
  else {
2924
2976
  this.chatContainer.addChild(new Spacer(1));
2925
- this.chatContainer.addChild(new Text(theme.fg("error", event.errorMessage), 1, 0));
2977
+ const errorMessage = event.errorMessage;
2978
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("error", errorMessage), 1, 0));
2926
2979
  }
2927
2980
  }
2928
2981
  void this.flushCompactionQueue({ willRetry: event.willRetry });
@@ -2994,7 +3047,7 @@ export class InteractiveMode {
2994
3047
  }
2995
3048
  const message = status.type === "warning" ? `Warning: ${status.message}` : status.message;
2996
3049
  const color = status.type === "warning" ? "warning" : "dim";
2997
- this.chatContainer.addChild(new Text(theme.fg(color, message), 1, 0));
3050
+ this.chatContainer.addChild(new ThemedText(() => theme.fg(color, message), 1, 0));
2998
3051
  this.lastStatusSpacer = undefined;
2999
3052
  this.lastStatusText = undefined;
3000
3053
  this.ui.requestRender();
@@ -3010,12 +3063,14 @@ export class InteractiveMode {
3010
3063
  const last = children.length > 0 ? children[children.length - 1] : undefined;
3011
3064
  const secondLast = children.length > 1 ? children[children.length - 2] : undefined;
3012
3065
  if (last && secondLast && last === this.lastStatusText && secondLast === this.lastStatusSpacer) {
3013
- this.lastStatusText.setText(theme.fg("dim", message));
3066
+ this.lastStatusMessage = message;
3067
+ this.lastStatusText.invalidate();
3014
3068
  this.ui.requestRender();
3015
3069
  return;
3016
3070
  }
3017
3071
  const spacer = new Spacer(1);
3018
- const text = new Text(theme.fg("dim", message), 1, 0);
3072
+ this.lastStatusMessage = message;
3073
+ const text = new ThemedText(() => theme.fg("dim", this.lastStatusMessage), 1, 0);
3019
3074
  this.chatContainer.addChild(spacer);
3020
3075
  this.chatContainer.addChild(text);
3021
3076
  this.lastStatusSpacer = spacer;
@@ -3224,7 +3279,8 @@ export class InteractiveMode {
3224
3279
  if (!this.settingsManager.getShowCacheMissNotices())
3225
3280
  return;
3226
3281
  this.chatContainer.addChild(new Spacer(1));
3227
- this.chatContainer.addChild(new Text(theme.fg("dim", formatCacheWarmingUsage(entry)), 1, 0));
3282
+ const usage = formatCacheWarmingUsage(entry);
3283
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("dim", usage), 1, 0));
3228
3284
  }
3229
3285
  /**
3230
3286
  * Render billing usage for a compaction or branch summary. The notice is derived
@@ -3238,7 +3294,7 @@ export class InteractiveMode {
3238
3294
  const cost = usage.cost.total >= 0.01 ? ` (~$${usage.cost.total.toFixed(2)})` : "";
3239
3295
  const label = notice.kind === "compaction" ? "Compaction" : "Branch summary";
3240
3296
  this.chatContainer.addChild(new Spacer(1));
3241
- this.chatContainer.addChild(new Text(theme.fg("warning", `${label}: ${formatTokens(tokens)} tokens billed${cost}`), 1, 0));
3297
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("warning", `${label}: ${formatTokens(tokens)} tokens billed${cost}`), 1, 0));
3242
3298
  }
3243
3299
  static countDroppedThinkingBlocks(message) {
3244
3300
  let count = 0;
@@ -3275,7 +3331,7 @@ export class InteractiveMode {
3275
3331
  return;
3276
3332
  const noun = droppedCount === 1 ? "thinking block" : "thinking blocks";
3277
3333
  this.chatContainer.addChild(new Spacer(1));
3278
- this.chatContainer.addChild(new Text(theme.fg("warning", `Anthropic dropped ${droppedCount} ${noun} (details in session)`), 1, 0));
3334
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("warning", `Anthropic dropped ${droppedCount} ${noun} (details in session)`), 1, 0));
3279
3335
  }
3280
3336
  /**
3281
3337
  * Show a transcript notice when a completed assistant message paid for a
@@ -3302,9 +3358,8 @@ export class InteractiveMode {
3302
3358
  else if (miss.idleMs >= CACHE_TTL_MS) {
3303
3359
  label = `Cache miss after ${Math.round(miss.idleMs / 60_000)}m idle`;
3304
3360
  }
3305
- const text = theme.fg("warning", `${label}: ${reBilled}`);
3306
3361
  this.chatContainer.addChild(new Spacer(1));
3307
- this.chatContainer.addChild(new Text(text, 1, 0));
3362
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("warning", `${label}: ${reBilled}`), 1, 0));
3308
3363
  }
3309
3364
  renderInitialMessages() {
3310
3365
  const entries = this.sessionManager.buildContextEntries();
@@ -3328,7 +3383,7 @@ export class InteractiveMode {
3328
3383
  if (this.chatContainer.children.length > 0) {
3329
3384
  this.chatContainer.addChild(new Spacer(1));
3330
3385
  }
3331
- this.chatContainer.addChild(new Text(theme.fg("warning", `This project is not trusted. Project ${CONFIG_DIR_NAME} resources and packages are ignored. Use /trust to save a trust decision, then restart pi.`), 1, 0));
3386
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("warning", `This project is not trusted. Project ${CONFIG_DIR_NAME} resources and packages are ignored. Use /trust to save a trust decision, then restart pi.`), 1, 0));
3332
3387
  }
3333
3388
  async getUserInput() {
3334
3389
  const queuedInput = this.pendingUserInputs.shift();
@@ -3675,26 +3730,28 @@ export class InteractiveMode {
3675
3730
  }
3676
3731
  showError(errorMessage) {
3677
3732
  this.chatContainer.addChild(new Spacer(1));
3678
- this.chatContainer.addChild(new Text(theme.fg("error", `Error: ${errorMessage}`), this.outputPad, 0));
3733
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("error", `Error: ${errorMessage}`), this.outputPad, 0));
3679
3734
  this.ui.requestRender();
3680
3735
  }
3681
3736
  showWarning(warningMessage) {
3682
3737
  this.chatContainer.addChild(new Spacer(1));
3683
- this.chatContainer.addChild(new Text(theme.fg("warning", `Warning: ${warningMessage}`), 1, 0));
3738
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("warning", `Warning: ${warningMessage}`), 1, 0));
3684
3739
  this.ui.requestRender();
3685
3740
  }
3686
3741
  showNewVersionNotification(release) {
3687
- const action = theme.fg("accent", `${APP_NAME} update`);
3688
- const updateInstruction = theme.fg("muted", `New version ${release.version} is available. Run `) + action;
3742
+ const updateInstruction = () => theme.fg("muted", `New version ${release.version} is available. Run `) +
3743
+ theme.fg("accent", `${APP_NAME} update`);
3689
3744
  const changelogUrl = "https://pi.dev/changelog";
3690
- const changelogLink = getCapabilities().hyperlinks
3691
- ? hyperlink(theme.fg("accent", changelogUrl), changelogUrl)
3692
- : theme.fg("accent", changelogUrl);
3693
- const changelogLine = theme.fg("muted", "Changelog: ") + changelogLink;
3745
+ const changelogLine = () => {
3746
+ const changelogLink = getCapabilities().hyperlinks
3747
+ ? hyperlink(theme.fg("accent", changelogUrl), changelogUrl)
3748
+ : theme.fg("accent", changelogUrl);
3749
+ return theme.fg("muted", "Changelog: ") + changelogLink;
3750
+ };
3694
3751
  const note = release.note?.trim();
3695
3752
  this.chatContainer.addChild(new Spacer(1));
3696
3753
  this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
3697
- this.chatContainer.addChild(new Text(`${theme.bold(theme.fg("warning", "Update Available"))}\n${updateInstruction}`, 1, 0));
3754
+ this.chatContainer.addChild(new ThemedText(() => `${theme.bold(theme.fg("warning", "Update Available"))}\n${updateInstruction()}`, 1, 0));
3698
3755
  if (note) {
3699
3756
  this.chatContainer.addChild(new Spacer(1));
3700
3757
  this.chatContainer.addChild(new Markdown(note, 1, 0, this.getMarkdownThemeWithSettings(), {
@@ -3702,17 +3759,17 @@ export class InteractiveMode {
3702
3759
  }));
3703
3760
  this.chatContainer.addChild(new Spacer(1));
3704
3761
  }
3705
- this.chatContainer.addChild(new Text(changelogLine, 1, 0));
3762
+ this.chatContainer.addChild(new ThemedText(changelogLine, 1, 0));
3706
3763
  this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
3707
3764
  this.ui.requestRender();
3708
3765
  }
3709
3766
  showPackageUpdateNotification(packages) {
3710
- const action = theme.fg("accent", `${APP_NAME} update --extensions`);
3711
- const updateInstruction = theme.fg("muted", "Package updates are available. Run ") + action;
3767
+ const updateInstruction = () => theme.fg("muted", "Package updates are available. Run ") +
3768
+ theme.fg("accent", `${APP_NAME} update --extensions`);
3712
3769
  const packageLines = packages.map((pkg) => `- ${pkg}`).join("\n");
3713
3770
  this.chatContainer.addChild(new Spacer(1));
3714
3771
  this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
3715
- this.chatContainer.addChild(new Text(`${theme.bold(theme.fg("warning", "Package Updates Available"))}\n${updateInstruction}\n${theme.fg("muted", "Packages:")}\n${packageLines}`, 1, 0));
3772
+ this.chatContainer.addChild(new ThemedText(() => `${theme.bold(theme.fg("warning", "Package Updates Available"))}\n${updateInstruction()}\n${theme.fg("muted", "Packages:")}\n${packageLines}`, 1, 0));
3716
3773
  this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
3717
3774
  this.ui.requestRender();
3718
3775
  }
@@ -3942,7 +3999,7 @@ export class InteractiveMode {
3942
3999
  thinkingLevel: this.settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL,
3943
4000
  availableThinkingLevels: [...THINKING_LEVEL_OPTIONS],
3944
4001
  modelThinkingLevels: this.settingsManager.getAllModelThinkingLevels(),
3945
- currentTheme: this.themeController.getThemeSelection() || "dark",
4002
+ currentTheme: this.themeController.getThemeSelection() || SYSTEM_THEME_NAME,
3946
4003
  terminalTheme: this.themeController.getTerminalTheme(),
3947
4004
  availableThemes: getAvailableThemes(),
3948
4005
  hideThinkingBlock: this.hideThinkingBlock,
@@ -3964,6 +4021,7 @@ export class InteractiveMode {
3964
4021
  fullscreenExitOutput: this.settingsManager.getFullscreenExitOutput(),
3965
4022
  fullscreenScrollbar: this.settingsManager.getFullscreenScrollbar(),
3966
4023
  fullscreenCopyOnSelect: this.settingsManager.getFullscreenCopyOnSelect(),
4024
+ fullscreenWheelScrollLines: this.settingsManager.getFullscreenWheelScrollLines(),
3967
4025
  warnings: this.settingsManager.getWarnings(),
3968
4026
  }, {
3969
4027
  onAutoCompactChange: (enabled) => {
@@ -4038,7 +4096,7 @@ export class InteractiveMode {
4038
4096
  },
4039
4097
  onThemeChange: (themeSetting) => {
4040
4098
  this.settingsManager.setTheme(themeSetting);
4041
- void this.themeController.setThemeSetting(themeSetting);
4099
+ this.themeController.setThemeSetting(themeSetting);
4042
4100
  },
4043
4101
  onThemePreview: (themeName) => this.themeController.preview(themeName),
4044
4102
  onHideThinkingBlockChange: (hidden) => {
@@ -4061,8 +4119,8 @@ export class InteractiveMode {
4061
4119
  onEnableInstallTelemetryChange: (enabled) => {
4062
4120
  this.settingsManager.setEnableInstallTelemetry(enabled);
4063
4121
  },
4064
- onQuietStartupChange: (enabled) => {
4065
- this.settingsManager.setQuietStartup(enabled);
4122
+ onQuietStartupChange: (quiet) => {
4123
+ this.settingsManager.setQuietStartup(quiet);
4066
4124
  },
4067
4125
  onDefaultProjectTrustChange: (defaultProjectTrust) => {
4068
4126
  this.settingsManager.setDefaultProjectTrust(defaultProjectTrust);
@@ -4143,6 +4201,11 @@ export class InteractiveMode {
4143
4201
  if (this.renderer instanceof TuiAltScreen)
4144
4202
  this.renderer.setCopyOnSelect(enabled);
4145
4203
  },
4204
+ onFullscreenWheelScrollLinesChange: (lines) => {
4205
+ this.settingsManager.setFullscreenWheelScrollLines(lines);
4206
+ if (this.renderer instanceof TuiAltScreen)
4207
+ this.renderer.setWheelScrollLines(lines);
4208
+ },
4146
4209
  onWarningsChange: (warnings) => {
4147
4210
  this.settingsManager.setWarnings(warnings);
4148
4211
  },
@@ -4709,6 +4772,7 @@ export class InteractiveMode {
4709
4772
  source: authStatus.label ?? authStatus.source,
4710
4773
  }
4711
4774
  : undefined;
4775
+ const subscription = provider.auth.oauth?.isSubscription === true;
4712
4776
  if ((!authType || authType === "oauth") && provider.auth.oauth) {
4713
4777
  options.push({
4714
4778
  id: provider.id,
@@ -4716,6 +4780,7 @@ export class InteractiveMode {
4716
4780
  authType: "oauth",
4717
4781
  method: provider.auth.oauth,
4718
4782
  status,
4783
+ subscription,
4719
4784
  });
4720
4785
  }
4721
4786
  if ((!authType || authType === "api_key") && provider.auth.apiKey) {
@@ -4725,6 +4790,7 @@ export class InteractiveMode {
4725
4790
  authType: "api_key",
4726
4791
  method: provider.auth.apiKey,
4727
4792
  status,
4793
+ subscription,
4728
4794
  });
4729
4795
  }
4730
4796
  }
@@ -4732,12 +4798,16 @@ export class InteractiveMode {
4732
4798
  }
4733
4799
  async getLogoutProviderOptions() {
4734
4800
  return (await this.session.modelRuntime.listCredentials({ signal: AbortSignal.timeout(15_000) }))
4735
- .map(({ providerId, type }) => ({
4736
- id: providerId,
4737
- name: this.session.modelRuntime.getProvider(providerId)?.name ?? providerId,
4738
- authType: type,
4739
- status: { type, source: "stored credential" },
4740
- }))
4801
+ .map(({ providerId, type }) => {
4802
+ const provider = this.session.modelRuntime.getProvider(providerId);
4803
+ return {
4804
+ id: providerId,
4805
+ name: provider?.name ?? providerId,
4806
+ authType: type,
4807
+ status: { type, source: "stored credential" },
4808
+ subscription: provider?.auth.oauth?.isSubscription === true,
4809
+ };
4810
+ })
4741
4811
  .sort((a, b) => a.name.localeCompare(b.name));
4742
4812
  }
4743
4813
  findLoginProviderOptions(providerRef) {
@@ -4767,18 +4837,25 @@ export class InteractiveMode {
4767
4837
  }
4768
4838
  this.showLoginProviderSelector(undefined, providerRef);
4769
4839
  }
4770
- async startProviderLogin(providerOption) {
4840
+ /** `onBack` reopens the selector the login was started from when the user cancels it. */
4841
+ async startProviderLogin(providerOption, onBack) {
4771
4842
  if (providerOption.authType === "oauth") {
4772
- await this.showLoginDialog(providerOption.id, providerOption.name);
4843
+ await this.showLoginDialog(providerOption.id, providerOption.name, onBack);
4773
4844
  }
4774
4845
  else if (providerOption.method?.login) {
4775
- await this.showApiKeyLoginDialog(providerOption.id, providerOption.name);
4846
+ await this.showApiKeyLoginDialog(providerOption.id, providerOption.name, onBack);
4776
4847
  }
4777
4848
  else {
4778
- this.showAmbientAuthDialog(providerOption);
4849
+ this.showAmbientAuthDialog(providerOption, onBack);
4779
4850
  }
4780
4851
  }
4781
4852
  showLoginAuthTypeSelector(providerOptions) {
4853
+ // The top-level selector offers Radius directly, as its last option.
4854
+ const radiusOption = providerOptions
4855
+ ? undefined
4856
+ : this.getLoginProviderOptions("oauth").find((provider) => provider.id === RADIUS_PROVIDER_ID);
4857
+ const radiusText = radiusOption ? `Sign in with ${radiusOption.name}` : undefined;
4858
+ const radiusLabel = radiusOption ? `${radiusText}${formatAuthSelectorProviderStatus(radiusOption)}` : undefined;
4782
4859
  const oauthProvider = providerOptions?.find((provider) => provider.authType === "oauth");
4783
4860
  const oauthLoginLabel = oauthProvider?.method && "loginLabel" in oauthProvider.method ? oauthProvider.method.loginLabel : undefined;
4784
4861
  const subscriptionLabel = oauthLoginLabel ?? "Sign in with an account";
@@ -4793,6 +4870,8 @@ export class InteractiveMode {
4793
4870
  if (availableAuthTypes.has("api_key")) {
4794
4871
  options.push(apiKeyLabel);
4795
4872
  }
4873
+ if (radiusLabel)
4874
+ options.push(radiusLabel);
4796
4875
  if (options.length === 0) {
4797
4876
  this.showStatus("No login methods available.");
4798
4877
  return;
@@ -4808,29 +4887,37 @@ export class InteractiveMode {
4808
4887
  ? `Select authentication method for ${providerOptions[0].name}:`
4809
4888
  : "Select authentication method:";
4810
4889
  this.showSelector((done) => {
4811
- const selector = new ExtensionSelectorComponent(title, options, (option) => {
4890
+ const onSelect = (option) => {
4812
4891
  done();
4892
+ if (radiusOption && option === radiusLabel) {
4893
+ void this.startProviderLogin(radiusOption, () => this.showLoginAuthTypeSelector());
4894
+ return;
4895
+ }
4813
4896
  const authType = option === subscriptionLabel ? "oauth" : "api_key";
4814
4897
  if (providerOptions) {
4815
4898
  const providerOption = providerOptions.find((provider) => provider.authType === authType);
4816
4899
  if (providerOption) {
4817
- void this.startProviderLogin(providerOption);
4900
+ void this.startProviderLogin(providerOption, () => this.showLoginAuthTypeSelector(providerOptions));
4818
4901
  }
4819
4902
  return;
4820
4903
  }
4821
4904
  this.showLoginProviderSelector(authType);
4822
- }, () => {
4905
+ };
4906
+ const onCancel = () => {
4823
4907
  done();
4824
4908
  this.ui.requestRender();
4825
- });
4826
- return { component: selector, focus: selector };
4909
+ };
4910
+ const selector = radiusLabel && radiusText
4911
+ ? createLoginMenuSelector(this.ui, title, options, { label: radiusLabel, text: radiusText }, onSelect, onCancel)
4912
+ : new ExtensionSelectorComponent(title, options, onSelect, onCancel);
4913
+ return { component: selector, focus: selector, dispose: () => selector.dispose() };
4827
4914
  });
4828
4915
  }
4829
4916
  showLoginProviderSelector(authType, initialSearchInput) {
4830
4917
  const providerOptions = this.getLoginProviderOptions(authType);
4831
4918
  if (providerOptions.length === 0) {
4832
4919
  const message = authType === "oauth"
4833
- ? "No subscription providers available."
4920
+ ? "No account providers available."
4834
4921
  : authType === "api_key"
4835
4922
  ? "No API key providers available."
4836
4923
  : "No login providers available.";
@@ -4844,7 +4931,7 @@ export class InteractiveMode {
4844
4931
  if (!providerOption) {
4845
4932
  return;
4846
4933
  }
4847
- await this.startProviderLogin(providerOption);
4934
+ await this.startProviderLogin(providerOption, () => this.showLoginProviderSelector(authType, initialSearchInput));
4848
4935
  }, () => {
4849
4936
  done();
4850
4937
  if (authType) {
@@ -4998,21 +5085,24 @@ export class InteractiveMode {
4998
5085
  })
4999
5086
  .finally(() => clearTimeout(timeout));
5000
5087
  }
5001
- showAmbientAuthDialog(providerOption) {
5088
+ showAmbientAuthDialog(providerOption, onBack) {
5002
5089
  const restoreEditor = () => {
5003
5090
  this.editorContainer.clear();
5004
5091
  this.editorContainer.addChild(this.editor);
5005
5092
  this.ui.setFocus(this.editor);
5006
5093
  this.ui.requestRender();
5007
5094
  };
5008
- const dialog = new LoginDialogComponent(this.ui, providerOption.id, () => restoreEditor(), providerOption.name, `${providerOption.name} setup`);
5095
+ const dialog = new LoginDialogComponent(this.ui, providerOption.id, () => {
5096
+ restoreEditor();
5097
+ onBack?.();
5098
+ }, providerOption.name, `${providerOption.name} setup`);
5009
5099
  dialog.showInfo(`${providerOption.method?.name ?? "Authentication"} is configured outside ${APP_NAME}.`, [], true);
5010
5100
  this.editorContainer.clear();
5011
5101
  this.editorContainer.addChild(dialog);
5012
5102
  this.ui.setFocus(dialog);
5013
5103
  this.ui.requestRender();
5014
5104
  }
5015
- async showApiKeyLoginDialog(providerId, providerName) {
5105
+ async showApiKeyLoginDialog(providerId, providerName, onBack) {
5016
5106
  const previousModel = this.session.model;
5017
5107
  const dialog = new LoginDialogComponent(this.ui, providerId, (_success, _message) => {
5018
5108
  // Completion handled below
@@ -5045,12 +5135,15 @@ export class InteractiveMode {
5045
5135
  if (error instanceof CredentialSynchronizationError) {
5046
5136
  this.showError(`Saved API key for ${providerName}, but local model state could not be synchronized: ${errorMsg}`);
5047
5137
  }
5048
- else if (errorMsg !== "Login cancelled") {
5138
+ else if (errorMsg === "Login cancelled") {
5139
+ onBack?.();
5140
+ }
5141
+ else {
5049
5142
  this.showError(`Failed to save API key for ${providerName}: ${errorMsg}`);
5050
5143
  }
5051
5144
  }
5052
5145
  }
5053
- showAuthSelect(dialog, prompt) {
5146
+ showAuthSelect(dialog, prompt, providerId) {
5054
5147
  return new Promise((resolve, reject) => {
5055
5148
  const restoreDialog = () => {
5056
5149
  this.editorContainer.clear();
@@ -5069,17 +5162,17 @@ export class InteractiveMode {
5069
5162
  }, () => {
5070
5163
  restoreDialog();
5071
5164
  reject(new Error("Login cancelled"));
5072
- });
5165
+ }, { description: providerId === RADIUS_PROVIDER_ID ? RADIUS_LOGIN_INTRO : undefined });
5073
5166
  this.editorContainer.clear();
5074
5167
  this.editorContainer.addChild(selector);
5075
5168
  this.ui.setFocus(selector);
5076
5169
  this.ui.requestRender();
5077
5170
  });
5078
5171
  }
5079
- async showAuthPrompt(dialog, prompt) {
5172
+ async showAuthPrompt(dialog, prompt, providerId) {
5080
5173
  let response;
5081
5174
  if (prompt.type === "select") {
5082
- response = this.showAuthSelect(dialog, prompt);
5175
+ response = this.showAuthSelect(dialog, prompt, providerId);
5083
5176
  }
5084
5177
  else if (prompt.type === "manual_code") {
5085
5178
  response = dialog.showManualInput(prompt.message);
@@ -5123,11 +5216,11 @@ export class InteractiveMode {
5123
5216
  async loginProvider(dialog, providerId, method) {
5124
5217
  await this.session.modelRuntime.login(providerId, method, {
5125
5218
  signal: dialog.signal,
5126
- prompt: (prompt) => this.showAuthPrompt(dialog, prompt),
5219
+ prompt: (prompt) => this.showAuthPrompt(dialog, prompt, providerId),
5127
5220
  notify: (event) => this.notifyAuthDialog(dialog, event),
5128
- });
5221
+ }, { getDeviceId: () => this.settingsManager.getOrCreateDeviceId() });
5129
5222
  }
5130
- async showLoginDialog(providerId, providerName) {
5223
+ async showLoginDialog(providerId, providerName, onBack) {
5131
5224
  const previousModel = this.session.model;
5132
5225
  const dialog = new LoginDialogComponent(this.ui, providerId, (_success, _message) => { }, providerName);
5133
5226
  this.editorContainer.clear();
@@ -5144,6 +5237,8 @@ export class InteractiveMode {
5144
5237
  await this.loginProvider(dialog, providerId, "oauth");
5145
5238
  restoreEditor();
5146
5239
  await this.completeProviderAuthentication(providerId, providerName, "oauth", previousModel);
5240
+ if (providerId === RADIUS_PROVIDER_ID)
5241
+ this.offerRadiusMcpServer(providerId, providerName);
5147
5242
  }
5148
5243
  catch (error) {
5149
5244
  restoreEditor();
@@ -5151,11 +5246,58 @@ export class InteractiveMode {
5151
5246
  if (error instanceof CredentialSynchronizationError) {
5152
5247
  this.showError(`Logged in to ${providerName}, but local model state could not be synchronized: ${errorMsg}`);
5153
5248
  }
5154
- else if (errorMsg !== "Login cancelled") {
5249
+ else if (errorMsg === "Login cancelled") {
5250
+ onBack?.();
5251
+ }
5252
+ else {
5155
5253
  this.showError(`Failed to login to ${providerName}: ${errorMsg}`);
5156
5254
  }
5157
5255
  }
5158
5256
  }
5257
+ /**
5258
+ * Offer to point the Radius MCP server in the global mcp.json at the Radius login, adding the server
5259
+ * when missing. Nothing is asked when a global server already uses this login.
5260
+ */
5261
+ offerRadiusMcpServer(providerId, providerName) {
5262
+ const mcpPath = path.join(getAgentDir(), "mcp.json");
5263
+ const normalizeUrl = (url) => url.replace(/\/+$/u, "");
5264
+ const { servers } = loadMcpConfig({
5265
+ agentDir: getAgentDir(),
5266
+ cwd: this.sessionManager.getCwd(),
5267
+ projectTrusted: false,
5268
+ });
5269
+ const existing = servers.find((server) => "url" in server.config && normalizeUrl(server.config.url) === normalizeUrl(RADIUS_MCP_URL));
5270
+ if (existing && "url" in existing.config && existing.config.auth?.provider === providerId)
5271
+ return;
5272
+ let name = existing?.name ?? "radius";
5273
+ if (!existing && servers.some((server) => server.name === name))
5274
+ name = "radius-mcp";
5275
+ const config = existing && "url" in existing.config
5276
+ ? { ...existing.config, auth: { provider: providerId } }
5277
+ : { url: RADIUS_MCP_URL, auth: { provider: providerId } };
5278
+ // `auth` replaces the MCP OAuth sign-in.
5279
+ delete config.oauth;
5280
+ this.showSelector((done) => {
5281
+ const selector = new ExtensionSelectorComponent(`Configure ${providerName} MCP in ${mcpPath}?`, ["Yes", "No"], (option) => {
5282
+ done();
5283
+ if (option !== "Yes")
5284
+ return;
5285
+ try {
5286
+ addMcpServerConfig(mcpPath, name, config);
5287
+ }
5288
+ catch (error) {
5289
+ this.showError(`Could not update ${mcpPath}: ${error instanceof Error ? error.message : String(error)}`);
5290
+ return;
5291
+ }
5292
+ // The MCP extension reads mcp.json when the session starts.
5293
+ void this.handleReloadCommand();
5294
+ }, () => {
5295
+ done();
5296
+ this.ui.requestRender();
5297
+ });
5298
+ return { component: selector, focus: selector };
5299
+ });
5300
+ }
5159
5301
  // =========================================================================
5160
5302
  // Command handlers
5161
5303
  // =========================================================================
@@ -5173,7 +5315,7 @@ export class InteractiveMode {
5173
5315
  const borderColor = (s) => theme.fg("border", s);
5174
5316
  reloadBox.addChild(new DynamicBorder(borderColor));
5175
5317
  reloadBox.addChild(new Spacer(1));
5176
- reloadBox.addChild(new Text(theme.fg("muted", "Reloading keybindings, extensions, skills, prompts, themes, and context files..."), 1, 0));
5318
+ reloadBox.addChild(new ThemedText(() => theme.fg("muted", "Reloading keybindings, extensions, skills, prompts, themes, and context files..."), 1, 0));
5177
5319
  reloadBox.addChild(new Spacer(1));
5178
5320
  reloadBox.addChild(new DynamicBorder(borderColor));
5179
5321
  const previousEditor = this.editor;
@@ -5209,7 +5351,7 @@ export class InteractiveMode {
5209
5351
  }
5210
5352
  setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
5211
5353
  this.applyRuntimeSettings();
5212
- await this.themeController.applyFromSettings();
5354
+ this.themeController.applyFromSettings();
5213
5355
  this.setupAutocompleteProvider();
5214
5356
  const runner = this.session.extensionRunner;
5215
5357
  this.setupExtensionShortcuts(runner);
@@ -5373,7 +5515,7 @@ export class InteractiveMode {
5373
5515
  const currentName = this.sessionManager.getSessionName();
5374
5516
  if (currentName) {
5375
5517
  this.chatContainer.addChild(new Spacer(1));
5376
- this.chatContainer.addChild(new Text(theme.fg("dim", `Session name: ${currentName}`), 1, 0));
5518
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("dim", `Session name: ${currentName}`), 1, 0));
5377
5519
  }
5378
5520
  else {
5379
5521
  this.showWarning("Usage: /name <name>");
@@ -5387,7 +5529,8 @@ export class InteractiveMode {
5387
5529
  this.showWarning(`Session name was normalized from ${JSON.stringify(name)} to ${JSON.stringify(sessionName)}`);
5388
5530
  }
5389
5531
  this.chatContainer.addChild(new Spacer(1));
5390
- this.chatContainer.addChild(new Text(theme.fg("dim", `Session name set: ${sessionName ?? name}`), 1, 0));
5532
+ const displayName = sessionName ?? name;
5533
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("dim", `Session name set: ${displayName}`), 1, 0));
5391
5534
  this.ui.requestRender();
5392
5535
  }
5393
5536
  handleSessionCommand() {
@@ -5399,61 +5542,69 @@ export class InteractiveMode {
5399
5542
  // resolves to a concrete responseModel). Usage without model attribution is
5400
5543
  // grouped separately so the breakdown reconciles with the session total.
5401
5544
  const usageBreakdown = getUsageCostBreakdown(entries);
5402
- let info = `${theme.bold("Session Info")}\n\n`;
5403
- if (sessionName) {
5404
- info += `${theme.fg("dim", "Name:")} ${sessionName}\n`;
5405
- }
5406
- info += `${theme.fg("dim", "File:")} ${stats.sessionFile ?? "In-memory"}\n`;
5407
- info += `${theme.fg("dim", "ID:")} ${stats.sessionId}\n\n`;
5408
- info += `${theme.bold("Messages")}\n`;
5409
- info += `${theme.fg("dim", "Total:")} ${stats.totalMessages}\n`;
5410
- info += `${theme.fg("dim", "User:")} ${stats.userMessages}\n`;
5411
- info += `${theme.fg("dim", "Assistant:")} ${stats.assistantMessages}\n`;
5412
- info += `${theme.fg("dim", "Tools:")} ${stats.toolCalls} calls, ${stats.toolResults} results\n\n`;
5413
- info += `${theme.bold("Tokens")}\n`;
5414
- // "Input" is the full prompt volume. With cache activity, split it into
5415
- // cached (served from cache) vs uncached (everything else) - the only
5416
- // provider-independent split. Cache writes, where reported, are a detail
5417
- // of the uncached portion.
5418
- const { input, cacheRead, cacheWrite } = stats.tokens;
5419
- const promptTokens = input + cacheRead + cacheWrite;
5420
- info += `${theme.fg("dim", "Input:")} ${promptTokens.toLocaleString()}\n`;
5421
- if (promptTokens > 0 && (cacheRead > 0 || cacheWrite > 0)) {
5422
- const hitRate = theme.fg("dim", `(${((cacheRead / promptTokens) * 100).toFixed(1)}%)`);
5423
- info += ` ${theme.fg("dim", "Cached:")} ${cacheRead.toLocaleString()} ${hitRate}\n`;
5424
- const written = cacheWrite > 0 ? ` ${theme.fg("dim", `(${cacheWrite.toLocaleString()} written to cache)`)}` : "";
5425
- info += ` ${theme.fg("dim", "Uncached:")} ${(input + cacheWrite).toLocaleString()}${written}\n`;
5426
- }
5427
- info += `${theme.fg("dim", "Output:")} ${stats.tokens.output.toLocaleString()}\n`;
5428
- info += `${theme.fg("dim", "Total:")} ${stats.tokens.total.toLocaleString()}\n`;
5545
+ // Snapshot the stats; the text is built on demand so it follows theme changes.
5429
5546
  const cacheWarmingStatus = this.session.cacheWarmingStatus;
5430
- info += `\n${theme.bold("Cache Warming")}\n`;
5431
- info += `${theme.fg("dim", "Mode:")} ${this.settingsManager.getCacheWarmingMode()}\n`;
5432
- info += `${theme.fg("dim", "Status:")} ${cacheWarmingStatus ? formatCacheWarmingStatus(cacheWarmingStatus) : "Inactive (cache warming unavailable)"}\n`;
5433
- const decision = cacheWarmingStatus?.decision;
5434
- if (decision?.economicsAvailable) {
5435
- info += `${theme.fg("dim", "Cache miss penalty:")} $${decision.missCost.toFixed(3)}\n`;
5436
- info += `${theme.fg("dim", "Refresh cost:")} $${decision.warmCost.toFixed(3)}\n`;
5437
- }
5438
- if (stats.cost > 0 || cacheWaste.missedTokens > 0) {
5439
- info += `\n${theme.bold("Cost")}\n`;
5440
- info += `${theme.fg("dim", "Total:")} $${stats.cost.toFixed(3)}`;
5441
- if (usageBreakdown.length > 1) {
5442
- for (const entry of usageBreakdown) {
5443
- info += `\n ${theme.fg("dim", `${entry.key}:`)} $${entry.cost.toFixed(3)} ${theme.fg("dim", `(${formatTokens(entry.tokens)} tokens)`)}`;
5547
+ const cacheWarmingMode = this.settingsManager.getCacheWarmingMode();
5548
+ const model = this.session.model;
5549
+ const selectedModelKey = `${model?.provider}/${model?.id}`;
5550
+ const renderInfo = () => {
5551
+ let info = `${theme.bold("Session Info")}\n\n`;
5552
+ if (sessionName) {
5553
+ info += `${theme.fg("dim", "Name:")} ${sessionName}\n`;
5554
+ }
5555
+ info += `${theme.fg("dim", "File:")} ${stats.sessionFile ?? "In-memory"}\n`;
5556
+ info += `${theme.fg("dim", "ID:")} ${stats.sessionId}\n\n`;
5557
+ info += `${theme.bold("Messages")}\n`;
5558
+ info += `${theme.fg("dim", "Total:")} ${stats.totalMessages}\n`;
5559
+ info += `${theme.fg("dim", "User:")} ${stats.userMessages}\n`;
5560
+ info += `${theme.fg("dim", "Assistant:")} ${stats.assistantMessages}\n`;
5561
+ info += `${theme.fg("dim", "Tools:")} ${stats.toolCalls} calls, ${stats.toolResults} results\n\n`;
5562
+ info += `${theme.bold("Tokens")}\n`;
5563
+ // "Input" is the full prompt volume. With cache activity, split it into
5564
+ // cached (served from cache) vs uncached (everything else) - the only
5565
+ // provider-independent split. Cache writes, where reported, are a detail
5566
+ // of the uncached portion.
5567
+ const { input, cacheRead, cacheWrite } = stats.tokens;
5568
+ const promptTokens = input + cacheRead + cacheWrite;
5569
+ info += `${theme.fg("dim", "Input:")} ${promptTokens.toLocaleString()}\n`;
5570
+ if (promptTokens > 0 && (cacheRead > 0 || cacheWrite > 0)) {
5571
+ const hitRate = theme.fg("dim", `(${((cacheRead / promptTokens) * 100).toFixed(1)}%)`);
5572
+ info += ` ${theme.fg("dim", "Cached:")} ${cacheRead.toLocaleString()} ${hitRate}\n`;
5573
+ const written = cacheWrite > 0 ? ` ${theme.fg("dim", `(${cacheWrite.toLocaleString()} written to cache)`)}` : "";
5574
+ info += ` ${theme.fg("dim", "Uncached:")} ${(input + cacheWrite).toLocaleString()}${written}\n`;
5575
+ }
5576
+ info += `${theme.fg("dim", "Output:")} ${stats.tokens.output.toLocaleString()}\n`;
5577
+ info += `${theme.fg("dim", "Total:")} ${stats.tokens.total.toLocaleString()}\n`;
5578
+ info += `\n${theme.bold("Cache Warming")}\n`;
5579
+ info += `${theme.fg("dim", "Mode:")} ${cacheWarmingMode}\n`;
5580
+ info += `${theme.fg("dim", "Status:")} ${cacheWarmingStatus ? formatCacheWarmingStatus(cacheWarmingStatus) : "Inactive (cache warming unavailable)"}\n`;
5581
+ const decision = cacheWarmingStatus?.decision;
5582
+ if (decision?.economicsAvailable) {
5583
+ info += `${theme.fg("dim", "Cache miss penalty:")} $${decision.missCost.toFixed(3)}\n`;
5584
+ info += `${theme.fg("dim", "Refresh cost:")} $${decision.warmCost.toFixed(3)}\n`;
5585
+ }
5586
+ if (stats.cost > 0 || cacheWaste.missedTokens > 0) {
5587
+ info += `\n${theme.bold("Cost")}\n`;
5588
+ info += `${theme.fg("dim", "Total:")} $${stats.cost.toFixed(3)}`;
5589
+ // A single entry repeats the total, unless it names a model other than the selected one.
5590
+ if (usageBreakdown.length > 1 || usageBreakdown[0]?.key !== selectedModelKey) {
5591
+ for (const entry of usageBreakdown) {
5592
+ info += `\n ${theme.fg("dim", `${entry.key}:`)} $${entry.cost.toFixed(3)} ${theme.fg("dim", `(${formatTokens(entry.tokens)} tokens)`)}`;
5593
+ }
5594
+ }
5595
+ if (cacheWaste.missedTokens > 0) {
5596
+ const missLabel = cacheWaste.missCount === 1 ? "1 miss" : `${cacheWaste.missCount} misses`;
5597
+ const detail = `${cacheWaste.missedTokens.toLocaleString()} tokens, ${missLabel}`;
5598
+ info +=
5599
+ cacheWaste.missedCost >= 0.0001
5600
+ ? `\n${theme.fg("dim", "Cache Re-billed:")} $${cacheWaste.missedCost.toFixed(3)} ${theme.fg("dim", `(${detail})`)}`
5601
+ : `\n${theme.fg("dim", "Cache Re-billed:")} ${detail}`;
5444
5602
  }
5445
5603
  }
5446
- if (cacheWaste.missedTokens > 0) {
5447
- const missLabel = cacheWaste.missCount === 1 ? "1 miss" : `${cacheWaste.missCount} misses`;
5448
- const detail = `${cacheWaste.missedTokens.toLocaleString()} tokens, ${missLabel}`;
5449
- info +=
5450
- cacheWaste.missedCost >= 0.0001
5451
- ? `\n${theme.fg("dim", "Cache Re-billed:")} $${cacheWaste.missedCost.toFixed(3)} ${theme.fg("dim", `(${detail})`)}`
5452
- : `\n${theme.fg("dim", "Cache Re-billed:")} ${detail}`;
5453
- }
5454
- }
5604
+ return info;
5605
+ };
5455
5606
  this.chatContainer.addChild(new Spacer(1));
5456
- this.chatContainer.addChild(new Text(info, 1, 0));
5607
+ this.chatContainer.addChild(new ThemedText(renderInfo, 1, 0));
5457
5608
  this.ui.requestRender();
5458
5609
  }
5459
5610
  handleChangelogCommand() {
@@ -5467,7 +5618,7 @@ export class InteractiveMode {
5467
5618
  : "No changelog entries found.";
5468
5619
  this.chatContainer.addChild(new Spacer(1));
5469
5620
  this.chatContainer.addChild(new DynamicBorder());
5470
- this.chatContainer.addChild(new Text(theme.bold(theme.fg("accent", "What's New")), 1, 0));
5621
+ this.chatContainer.addChild(new ThemedText(() => theme.bold(theme.fg("accent", "What's New")), 1, 0));
5471
5622
  this.chatContainer.addChild(new Spacer(1));
5472
5623
  this.chatContainer.addChild(new Markdown(changelogMarkdown, 1, 1, this.getMarkdownThemeWithSettings()));
5473
5624
  this.chatContainer.addChild(new DynamicBorder());
@@ -5568,7 +5719,7 @@ export class InteractiveMode {
5568
5719
  | \`${copyMessage}\` | Copy selection or last assistant message |
5569
5720
  | \`${followUp}\` | Queue follow-up message |
5570
5721
  | \`${dequeue}\` | Restore queued messages |
5571
- | \`${pasteImage}\` | Paste image or text from clipboard |
5722
+ | \`${pasteImage}\` | Paste files on macOS, images, or text from clipboard |
5572
5723
  | \`/\` | Slash commands |
5573
5724
  | \`!\` | Run bash command |
5574
5725
  | \`!!\` | Run bash command (excluded from context) |
@@ -5590,7 +5741,7 @@ export class InteractiveMode {
5590
5741
  }
5591
5742
  this.chatContainer.addChild(new Spacer(1));
5592
5743
  this.chatContainer.addChild(new DynamicBorder());
5593
- this.chatContainer.addChild(new Text(theme.bold(theme.fg("accent", "Keyboard Shortcuts")), 1, 0));
5744
+ this.chatContainer.addChild(new ThemedText(() => theme.bold(theme.fg("accent", "Keyboard Shortcuts")), 1, 0));
5594
5745
  this.chatContainer.addChild(new Spacer(1));
5595
5746
  this.chatContainer.addChild(new Markdown(hotkeys.trim(), 1, 1, this.getMarkdownThemeWithSettings()));
5596
5747
  this.chatContainer.addChild(new DynamicBorder());
@@ -5604,7 +5755,7 @@ export class InteractiveMode {
5604
5755
  return;
5605
5756
  }
5606
5757
  this.chatContainer.addChild(new Spacer(1));
5607
- this.chatContainer.addChild(new Text(`${theme.fg("accent", "✓ New session started")}`, 1, 1));
5758
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("accent", "✓ New session started"), 1, 1));
5608
5759
  this.ui.requestRender();
5609
5760
  }
5610
5761
  catch (error) {
@@ -5635,7 +5786,7 @@ export class InteractiveMode {
5635
5786
  fs.mkdirSync(path.dirname(debugLogPath), { recursive: true });
5636
5787
  fs.writeFileSync(debugLogPath, debugData);
5637
5788
  this.chatContainer.addChild(new Spacer(1));
5638
- this.chatContainer.addChild(new Text(`${theme.fg("accent", "✓ Debug log written")}\n${theme.fg("muted", debugLogPath)}`, 1, 1));
5789
+ this.chatContainer.addChild(new ThemedText(() => `${theme.fg("accent", "✓ Debug log written")}\n${theme.fg("muted", debugLogPath)}`, 1, 1));
5639
5790
  this.ui.requestRender();
5640
5791
  }
5641
5792
  handleArminSaysHi() {