@astralyn/pi 0.87.6 → 0.99.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (698) hide show
  1. package/CHANGELOG.md +30 -6
  2. package/README.md +3 -3
  3. package/dist/bun/runtime-setup.js +4 -1
  4. package/dist/bun/runtime-setup.js.map +1 -1
  5. package/dist/bundle/chunks/anthropic-messages-KIXY7EDT.js +6 -0
  6. package/dist/bundle/chunks/anthropic.js +2 -2
  7. package/dist/bundle/chunks/azure-openai-responses-RPBERDXD.js +2 -0
  8. package/dist/bundle/chunks/bedrock-converse-stream.js +8 -8
  9. package/dist/bundle/chunks/{chunk-LPQCB2VJ.js → chunk-A576H74Y.js} +2 -2
  10. package/dist/bundle/chunks/{chunk-NW5FIDD7.js → chunk-ABVRAYXT.js} +3 -3
  11. package/dist/bundle/chunks/{chunk-I5IVW2WS.js → chunk-CLLDCO64.js} +1 -1
  12. package/dist/bundle/chunks/chunk-DEWXBB6W.js +2 -0
  13. package/dist/bundle/chunks/chunk-G4RY3GN7.js +11 -0
  14. package/dist/bundle/chunks/chunk-GCKVOFWP.js +2 -0
  15. package/dist/bundle/chunks/chunk-MPDALHNJ.js +2 -0
  16. package/dist/bundle/chunks/chunk-OO6DJ3CL.js +31 -0
  17. package/dist/bundle/chunks/{chunk-4W4Q2H6W.js → chunk-VW2P3X6P.js} +905 -278
  18. package/dist/bundle/chunks/chunk-VWCWZD6E.js +2 -0
  19. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-ZYSAFXXL.js +2 -0
  20. package/dist/bundle/chunks/codemode-worker.js +295 -0
  21. package/dist/bundle/chunks/github-copilot.js +1 -1
  22. package/dist/bundle/chunks/google-generative-ai-SDNQVVXA.js +2 -0
  23. package/dist/bundle/chunks/google-vertex-LZXOLBIO.js +2 -0
  24. package/dist/bundle/chunks/llama-cpp-classify-7IYGGPND.js +22 -0
  25. package/dist/bundle/chunks/meta.js +2 -0
  26. package/dist/bundle/chunks/mistral-conversations-VYKPSSAM.js +5 -0
  27. package/dist/bundle/chunks/openai-chatgpt.js +75 -0
  28. package/dist/bundle/chunks/openai-codex-responses-HZ4VUDXD.js +10 -0
  29. package/dist/bundle/chunks/openai-codex.js +2 -2
  30. package/dist/bundle/chunks/openai-completions-SKDGF6OE.js +7 -0
  31. package/dist/bundle/chunks/openai-responses-FPML4SSG.js +3 -0
  32. package/dist/bundle/chunks/{openrouter-images-6XDE2CEW.js → openrouter-images-5524IQHX.js} +1 -1
  33. package/dist/bundle/chunks/openrouter.js +2 -2
  34. package/dist/bundle/chunks/{pi-messages-MQMPIPNC.js → pi-messages-HZZ7GEEW.js} +2 -2
  35. package/dist/bundle/chunks/radius.js +2 -2
  36. package/dist/bundle/chunks/typesafe-system-one-Z2CDLKEY.js +2 -0
  37. package/dist/bundle/chunks/virtual-modules-TQRORWJQ.js +2 -0
  38. package/dist/bundle/cli.js +1 -1
  39. package/dist/bundle/index.js +1 -1
  40. package/dist/bundle/rpc-entry.js +1 -1
  41. package/dist/cli/args.d.ts.map +1 -1
  42. package/dist/cli/args.js +4 -3
  43. package/dist/cli/args.js.map +1 -1
  44. package/dist/cli/startup-ui.d.ts.map +1 -1
  45. package/dist/cli/startup-ui.js +38 -30
  46. package/dist/cli/startup-ui.js.map +1 -1
  47. package/dist/config.d.ts +18 -4
  48. package/dist/config.d.ts.map +1 -1
  49. package/dist/config.js +30 -4
  50. package/dist/config.js.map +1 -1
  51. package/dist/core/agent-session-runtime.d.ts +1 -1
  52. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  53. package/dist/core/agent-session-runtime.js +13 -13
  54. package/dist/core/agent-session-runtime.js.map +1 -1
  55. package/dist/core/agent-session-services.d.ts +2 -2
  56. package/dist/core/agent-session-services.d.ts.map +1 -1
  57. package/dist/core/agent-session-services.js +14 -1
  58. package/dist/core/agent-session-services.js.map +1 -1
  59. package/dist/core/agent-session.d.ts +100 -35
  60. package/dist/core/agent-session.d.ts.map +1 -1
  61. package/dist/core/agent-session.js +456 -194
  62. package/dist/core/agent-session.js.map +1 -1
  63. package/dist/core/bug-report.js +1 -1
  64. package/dist/core/bug-report.js.map +1 -1
  65. package/dist/core/compaction/compaction.d.ts.map +1 -1
  66. package/dist/core/compaction/compaction.js +1 -22
  67. package/dist/core/compaction/compaction.js.map +1 -1
  68. package/dist/core/compaction/utils.d.ts +2 -1
  69. package/dist/core/compaction/utils.d.ts.map +1 -1
  70. package/dist/core/compaction/utils.js +25 -18
  71. package/dist/core/compaction/utils.js.map +1 -1
  72. package/dist/core/crash-log.d.ts.map +1 -1
  73. package/dist/core/crash-log.js +2 -1
  74. package/dist/core/crash-log.js.map +1 -1
  75. package/dist/core/export-html/template.css +10 -0
  76. package/dist/core/export-html/template.js +66 -17
  77. package/dist/core/extensions/distribution-api.d.ts +1 -1
  78. package/dist/core/extensions/distribution-api.d.ts.map +1 -1
  79. package/dist/core/extensions/distribution-api.js.map +1 -1
  80. package/dist/core/extensions/index.d.ts +2 -2
  81. package/dist/core/extensions/index.d.ts.map +1 -1
  82. package/dist/core/extensions/index.js.map +1 -1
  83. package/dist/core/extensions/loader.d.ts.map +1 -1
  84. package/dist/core/extensions/loader.js +55 -5
  85. package/dist/core/extensions/loader.js.map +1 -1
  86. package/dist/core/extensions/runner.d.ts +22 -3
  87. package/dist/core/extensions/runner.d.ts.map +1 -1
  88. package/dist/core/extensions/runner.js +124 -8
  89. package/dist/core/extensions/runner.js.map +1 -1
  90. package/dist/core/extensions/types.d.ts +305 -25
  91. package/dist/core/extensions/types.d.ts.map +1 -1
  92. package/dist/core/extensions/types.js.map +1 -1
  93. package/dist/core/extensions/wrapper.d.ts +2 -2
  94. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  95. package/dist/core/extensions/wrapper.js +3 -3
  96. package/dist/core/extensions/wrapper.js.map +1 -1
  97. package/dist/core/keybindings.d.ts +30 -5
  98. package/dist/core/keybindings.d.ts.map +1 -1
  99. package/dist/core/keybindings.js +7 -1
  100. package/dist/core/keybindings.js.map +1 -1
  101. package/dist/core/mcp-servers.d.ts +98 -0
  102. package/dist/core/mcp-servers.d.ts.map +1 -0
  103. package/dist/core/mcp-servers.js +158 -0
  104. package/dist/core/mcp-servers.js.map +1 -0
  105. package/dist/core/model-registry.d.ts +13 -1
  106. package/dist/core/model-registry.d.ts.map +1 -1
  107. package/dist/core/model-registry.js +25 -0
  108. package/dist/core/model-registry.js.map +1 -1
  109. package/dist/core/model-resolver.d.ts +2 -2
  110. package/dist/core/model-resolver.d.ts.map +1 -1
  111. package/dist/core/model-resolver.js +5 -5
  112. package/dist/core/model-resolver.js.map +1 -1
  113. package/dist/core/model-runtime.d.ts +41 -3
  114. package/dist/core/model-runtime.d.ts.map +1 -1
  115. package/dist/core/model-runtime.js +167 -17
  116. package/dist/core/model-runtime.js.map +1 -1
  117. package/dist/core/nested-tool-calls.d.ts +102 -0
  118. package/dist/core/nested-tool-calls.d.ts.map +1 -0
  119. package/dist/core/nested-tool-calls.js +177 -0
  120. package/dist/core/nested-tool-calls.js.map +1 -0
  121. package/dist/core/package-manager.d.ts +4 -0
  122. package/dist/core/package-manager.d.ts.map +1 -1
  123. package/dist/core/package-manager.js +58 -12
  124. package/dist/core/package-manager.js.map +1 -1
  125. package/dist/core/provider-composer.d.ts +40 -21
  126. package/dist/core/provider-composer.d.ts.map +1 -1
  127. package/dist/core/provider-composer.js +92 -40
  128. package/dist/core/provider-composer.js.map +1 -1
  129. package/dist/core/remote-catalog-provider.d.ts +8 -1
  130. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  131. package/dist/core/remote-catalog-provider.js +18 -3
  132. package/dist/core/remote-catalog-provider.js.map +1 -1
  133. package/dist/core/resource-loader.d.ts +7 -1
  134. package/dist/core/resource-loader.d.ts.map +1 -1
  135. package/dist/core/resource-loader.js +160 -35
  136. package/dist/core/resource-loader.js.map +1 -1
  137. package/dist/core/sdk.d.ts +3 -3
  138. package/dist/core/sdk.d.ts.map +1 -1
  139. package/dist/core/sdk.js +25 -7
  140. package/dist/core/sdk.js.map +1 -1
  141. package/dist/core/session-manager.d.ts +9 -0
  142. package/dist/core/session-manager.d.ts.map +1 -1
  143. package/dist/core/session-manager.js +22 -22
  144. package/dist/core/session-manager.js.map +1 -1
  145. package/dist/core/settings-manager.d.ts +36 -1
  146. package/dist/core/settings-manager.d.ts.map +1 -1
  147. package/dist/core/settings-manager.js +108 -2
  148. package/dist/core/settings-manager.js.map +1 -1
  149. package/dist/core/slash-commands.d.ts.map +1 -1
  150. package/dist/core/slash-commands.js +1 -0
  151. package/dist/core/slash-commands.js.map +1 -1
  152. package/dist/core/source-info.d.ts +8 -0
  153. package/dist/core/source-info.d.ts.map +1 -1
  154. package/dist/core/source-info.js +16 -0
  155. package/dist/core/source-info.js.map +1 -1
  156. package/dist/core/system-prompt.js +1 -1
  157. package/dist/core/system-prompt.js.map +1 -1
  158. package/dist/core/tasks/delivery.d.ts +40 -0
  159. package/dist/core/tasks/delivery.d.ts.map +1 -0
  160. package/dist/core/tasks/delivery.js +157 -0
  161. package/dist/core/tasks/delivery.js.map +1 -0
  162. package/dist/core/tasks/history.d.ts +4 -0
  163. package/dist/core/tasks/history.d.ts.map +1 -0
  164. package/dist/core/{background → tasks}/history.js +24 -48
  165. package/dist/core/tasks/history.js.map +1 -0
  166. package/dist/core/{background → tasks}/output.d.ts +4 -4
  167. package/dist/core/tasks/output.d.ts.map +1 -0
  168. package/dist/core/{background → tasks}/output.js +11 -11
  169. package/dist/core/tasks/output.js.map +1 -0
  170. package/dist/core/tasks/presentation.d.ts +9 -0
  171. package/dist/core/tasks/presentation.d.ts.map +1 -0
  172. package/dist/core/{background → tasks}/presentation.js +53 -51
  173. package/dist/core/tasks/presentation.js.map +1 -0
  174. package/dist/core/{background/service.d.ts → tasks/runtime.d.ts} +22 -23
  175. package/dist/core/tasks/runtime.d.ts.map +1 -0
  176. package/dist/core/{background/service.js → tasks/runtime.js} +154 -198
  177. package/dist/core/tasks/runtime.js.map +1 -0
  178. package/dist/core/tasks/session.d.ts +49 -0
  179. package/dist/core/tasks/session.d.ts.map +1 -0
  180. package/dist/core/tasks/session.js +129 -0
  181. package/dist/core/tasks/session.js.map +1 -0
  182. package/dist/core/tasks/store.d.ts +32 -0
  183. package/dist/core/tasks/store.d.ts.map +1 -0
  184. package/dist/core/tasks/store.js +135 -0
  185. package/dist/core/tasks/store.js.map +1 -0
  186. package/dist/core/{background → tasks}/types.d.ts +80 -62
  187. package/dist/core/tasks/types.d.ts.map +1 -0
  188. package/dist/core/{background → tasks}/types.js +9 -9
  189. package/dist/core/tasks/types.js.map +1 -0
  190. package/dist/core/tasks/view-data.d.ts +8 -0
  191. package/dist/core/tasks/view-data.d.ts.map +1 -0
  192. package/dist/core/tasks/view-data.js +61 -0
  193. package/dist/core/tasks/view-data.js.map +1 -0
  194. package/dist/core/tasks/view.d.ts +30 -0
  195. package/dist/core/tasks/view.d.ts.map +1 -0
  196. package/dist/core/tasks/view.js +50 -0
  197. package/dist/core/tasks/view.js.map +1 -0
  198. package/dist/core/tools/bash.d.ts +8 -93
  199. package/dist/core/tools/bash.d.ts.map +1 -1
  200. package/dist/core/tools/bash.js +8 -240
  201. package/dist/core/tools/bash.js.map +1 -1
  202. package/dist/core/tools/grep.d.ts +2 -0
  203. package/dist/core/tools/grep.d.ts.map +1 -1
  204. package/dist/core/tools/grep.js +2 -0
  205. package/dist/core/tools/grep.js.map +1 -1
  206. package/dist/core/tools/index.d.ts +2 -1
  207. package/dist/core/tools/index.d.ts.map +1 -1
  208. package/dist/core/tools/index.js +9 -0
  209. package/dist/core/tools/index.js.map +1 -1
  210. package/dist/core/tools/output-accumulator.d.ts +11 -0
  211. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  212. package/dist/core/tools/output-accumulator.js +36 -0
  213. package/dist/core/tools/output-accumulator.js.map +1 -1
  214. package/dist/core/tools/powershell.d.ts +6 -2
  215. package/dist/core/tools/powershell.d.ts.map +1 -1
  216. package/dist/core/tools/powershell.js +1 -1
  217. package/dist/core/tools/powershell.js.map +1 -1
  218. package/dist/core/tools/render-utils.d.ts +6 -0
  219. package/dist/core/tools/render-utils.d.ts.map +1 -1
  220. package/dist/core/tools/render-utils.js +26 -0
  221. package/dist/core/tools/render-utils.js.map +1 -1
  222. package/dist/core/tools/renderers/bash.d.ts +1 -1
  223. package/dist/core/tools/renderers/bash.d.ts.map +1 -1
  224. package/dist/core/tools/renderers/bash.js +9 -10
  225. package/dist/core/tools/renderers/bash.js.map +1 -1
  226. package/dist/core/tools/renderers/index.d.ts.map +1 -1
  227. package/dist/core/tools/renderers/index.js +5 -7
  228. package/dist/core/tools/renderers/index.js.map +1 -1
  229. package/dist/core/tools/renderers/read.d.ts.map +1 -1
  230. package/dist/core/tools/renderers/read.js +3 -2
  231. package/dist/core/tools/renderers/read.js.map +1 -1
  232. package/dist/core/tools/renderers/shell-task.d.ts +4 -0
  233. package/dist/core/tools/renderers/shell-task.d.ts.map +1 -0
  234. package/dist/core/tools/renderers/shell-task.js +35 -0
  235. package/dist/core/tools/renderers/shell-task.js.map +1 -0
  236. package/dist/core/tools/shell-execution.d.ts +4 -5
  237. package/dist/core/tools/shell-execution.d.ts.map +1 -1
  238. package/dist/core/tools/shell-execution.js +19 -3
  239. package/dist/core/tools/shell-execution.js.map +1 -1
  240. package/dist/core/tools/shell-tool.d.ts +93 -0
  241. package/dist/core/tools/shell-tool.d.ts.map +1 -0
  242. package/dist/core/tools/shell-tool.js +251 -0
  243. package/dist/core/tools/shell-tool.js.map +1 -0
  244. package/dist/core/tools/tasks/actions.d.ts +12 -0
  245. package/dist/core/tools/tasks/actions.d.ts.map +1 -0
  246. package/dist/{extensions/background → core/tools/tasks}/actions.js +20 -19
  247. package/dist/core/tools/tasks/actions.js.map +1 -0
  248. package/dist/{extensions/background → core/tools/tasks}/constants.d.ts +10 -10
  249. package/dist/core/tools/tasks/constants.d.ts.map +1 -0
  250. package/dist/{extensions/background → core/tools/tasks}/constants.js +10 -10
  251. package/dist/core/tools/tasks/constants.js.map +1 -0
  252. package/dist/{extensions/background → core/tools/tasks}/schema.d.ts +6 -6
  253. package/dist/core/tools/tasks/schema.d.ts.map +1 -0
  254. package/dist/{extensions/background → core/tools/tasks}/schema.js +17 -17
  255. package/dist/core/tools/tasks/schema.js.map +1 -0
  256. package/dist/{extensions/background → core/tools/tasks}/types.d.ts +15 -17
  257. package/dist/core/tools/tasks/types.d.ts.map +1 -0
  258. package/dist/core/tools/tasks/types.js.map +1 -0
  259. package/dist/core/tools/tasks.d.ts +14 -0
  260. package/dist/core/tools/tasks.d.ts.map +1 -0
  261. package/dist/core/tools/tasks.js +40 -0
  262. package/dist/core/tools/tasks.js.map +1 -0
  263. package/dist/core/tools/tool-definition-wrapper.d.ts +4 -3
  264. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  265. package/dist/core/tools/tool-definition-wrapper.js +4 -2
  266. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  267. package/dist/core/tools/truncate.d.ts +14 -0
  268. package/dist/core/tools/truncate.d.ts.map +1 -1
  269. package/dist/core/tools/truncate.js +29 -0
  270. package/dist/core/tools/truncate.js.map +1 -1
  271. package/dist/core/trust-manager.d.ts.map +1 -1
  272. package/dist/core/trust-manager.js +1 -0
  273. package/dist/core/trust-manager.js.map +1 -1
  274. package/dist/core/usage-totals.d.ts +5 -3
  275. package/dist/core/usage-totals.d.ts.map +1 -1
  276. package/dist/core/usage-totals.js +27 -4
  277. package/dist/core/usage-totals.js.map +1 -1
  278. package/dist/core/virtual-models.d.ts +115 -0
  279. package/dist/core/virtual-models.d.ts.map +1 -0
  280. package/dist/core/virtual-models.js +117 -0
  281. package/dist/core/virtual-models.js.map +1 -0
  282. package/dist/extensions/codemode/execute.d.ts +16 -0
  283. package/dist/extensions/codemode/execute.d.ts.map +1 -0
  284. package/dist/extensions/codemode/execute.js +390 -0
  285. package/dist/extensions/codemode/execute.js.map +1 -0
  286. package/dist/extensions/codemode/execute.lazy.d.ts +3 -0
  287. package/dist/extensions/codemode/execute.lazy.d.ts.map +1 -0
  288. package/dist/extensions/codemode/execute.lazy.js +3 -0
  289. package/dist/extensions/codemode/execute.lazy.js.map +1 -0
  290. package/dist/extensions/codemode/index.d.ts +21 -0
  291. package/dist/extensions/codemode/index.d.ts.map +1 -0
  292. package/dist/extensions/codemode/index.js +36 -0
  293. package/dist/extensions/codemode/index.js.map +1 -0
  294. package/dist/extensions/codemode/renderer.d.ts +12 -0
  295. package/dist/extensions/codemode/renderer.d.ts.map +1 -0
  296. package/dist/extensions/codemode/renderer.js +119 -0
  297. package/dist/extensions/codemode/renderer.js.map +1 -0
  298. package/dist/extensions/codemode/search.d.ts +33 -0
  299. package/dist/extensions/codemode/search.d.ts.map +1 -0
  300. package/dist/extensions/codemode/search.js +117 -0
  301. package/dist/extensions/codemode/search.js.map +1 -0
  302. package/dist/extensions/codemode/tool.d.ts +122 -0
  303. package/dist/extensions/codemode/tool.d.ts.map +1 -0
  304. package/dist/extensions/codemode/tool.js +324 -0
  305. package/dist/extensions/codemode/tool.js.map +1 -0
  306. package/dist/extensions/codemode/worker.d.ts +7 -0
  307. package/dist/extensions/codemode/worker.d.ts.map +1 -0
  308. package/dist/extensions/codemode/worker.js +7 -0
  309. package/dist/extensions/codemode/worker.js.map +1 -0
  310. package/dist/extensions/deepwiki/schema.d.ts +1 -1
  311. package/dist/extensions/index.d.ts.map +1 -1
  312. package/dist/extensions/index.js +14 -12
  313. package/dist/extensions/index.js.map +1 -1
  314. package/dist/extensions/llama/provider.d.ts +1 -1
  315. package/dist/extensions/llama/provider.d.ts.map +1 -1
  316. package/dist/extensions/llama/provider.js +65 -13
  317. package/dist/extensions/llama/provider.js.map +1 -1
  318. package/dist/extensions/mcp/cli.d.ts +21 -0
  319. package/dist/extensions/mcp/cli.d.ts.map +1 -0
  320. package/dist/extensions/mcp/cli.js +485 -0
  321. package/dist/extensions/mcp/cli.js.map +1 -0
  322. package/dist/extensions/mcp/cli.lazy.d.ts +3 -0
  323. package/dist/extensions/mcp/cli.lazy.d.ts.map +1 -0
  324. package/dist/extensions/mcp/cli.lazy.js +3 -0
  325. package/dist/extensions/mcp/cli.lazy.js.map +1 -0
  326. package/dist/extensions/mcp/config.d.ts +70 -0
  327. package/dist/extensions/mcp/config.d.ts.map +1 -0
  328. package/dist/extensions/mcp/config.js +146 -0
  329. package/dist/extensions/mcp/config.js.map +1 -0
  330. package/dist/extensions/mcp/index.d.ts +52 -0
  331. package/dist/extensions/mcp/index.d.ts.map +1 -0
  332. package/dist/extensions/mcp/index.js +904 -0
  333. package/dist/extensions/mcp/index.js.map +1 -0
  334. package/dist/extensions/mcp/log.d.ts +16 -0
  335. package/dist/extensions/mcp/log.d.ts.map +1 -0
  336. package/dist/extensions/mcp/log.js +64 -0
  337. package/dist/extensions/mcp/log.js.map +1 -0
  338. package/dist/extensions/mcp/oauth.d.ts +94 -0
  339. package/dist/extensions/mcp/oauth.d.ts.map +1 -0
  340. package/dist/extensions/mcp/oauth.js +330 -0
  341. package/dist/extensions/mcp/oauth.js.map +1 -0
  342. package/dist/extensions/mcp/resources.d.ts +43 -0
  343. package/dist/extensions/mcp/resources.d.ts.map +1 -0
  344. package/dist/extensions/mcp/resources.js +262 -0
  345. package/dist/extensions/mcp/resources.js.map +1 -0
  346. package/dist/extensions/mcp/runtime.d.ts +96 -0
  347. package/dist/extensions/mcp/runtime.d.ts.map +1 -0
  348. package/dist/extensions/mcp/runtime.js +372 -0
  349. package/dist/extensions/mcp/runtime.js.map +1 -0
  350. package/dist/extensions/mcp/runtime.lazy.d.ts +3 -0
  351. package/dist/extensions/mcp/runtime.lazy.d.ts.map +1 -0
  352. package/dist/extensions/mcp/runtime.lazy.js +3 -0
  353. package/dist/extensions/mcp/runtime.lazy.js.map +1 -0
  354. package/dist/extensions/mcp/tools.d.ts +83 -0
  355. package/dist/extensions/mcp/tools.d.ts.map +1 -0
  356. package/dist/extensions/mcp/tools.js +233 -0
  357. package/dist/extensions/mcp/tools.js.map +1 -0
  358. package/dist/extensions/mcp/ui.d.ts +60 -0
  359. package/dist/extensions/mcp/ui.d.ts.map +1 -0
  360. package/dist/extensions/mcp/ui.js +166 -0
  361. package/dist/extensions/mcp/ui.js.map +1 -0
  362. package/dist/extensions/statusline/index.js +2 -2
  363. package/dist/extensions/statusline/index.js.map +1 -1
  364. package/dist/extensions/tool-search/index.d.ts +12 -0
  365. package/dist/extensions/tool-search/index.d.ts.map +1 -0
  366. package/dist/extensions/tool-search/index.js +20 -0
  367. package/dist/extensions/tool-search/index.js.map +1 -0
  368. package/dist/extensions/tool-search/tool.d.ts +72 -0
  369. package/dist/extensions/tool-search/tool.d.ts.map +1 -0
  370. package/dist/extensions/tool-search/tool.js +208 -0
  371. package/dist/extensions/tool-search/tool.js.map +1 -0
  372. package/dist/index.d.ts +13 -4
  373. package/dist/index.d.ts.map +1 -1
  374. package/dist/index.js +7 -1
  375. package/dist/index.js.map +1 -1
  376. package/dist/main.d.ts.map +1 -1
  377. package/dist/main.js +10 -0
  378. package/dist/main.js.map +1 -1
  379. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  380. package/dist/modes/interactive/components/config-selector.js +13 -3
  381. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  382. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  383. package/dist/modes/interactive/components/custom-message.js +3 -1
  384. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  385. package/dist/modes/interactive/components/first-time-setup.d.ts +4 -4
  386. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
  387. package/dist/modes/interactive/components/first-time-setup.js +8 -2
  388. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  389. package/dist/modes/interactive/components/footer.d.ts +7 -0
  390. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  391. package/dist/modes/interactive/components/footer.js +42 -3
  392. package/dist/modes/interactive/components/footer.js.map +1 -1
  393. package/dist/modes/interactive/components/pi-logo.d.ts +12 -0
  394. package/dist/modes/interactive/components/pi-logo.d.ts.map +1 -0
  395. package/dist/modes/interactive/components/pi-logo.js +25 -0
  396. package/dist/modes/interactive/components/pi-logo.js.map +1 -0
  397. package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  398. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  399. package/dist/modes/interactive/components/settings-selector.js +28 -6
  400. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  401. package/dist/modes/interactive/components/status-marker.d.ts +2 -2
  402. package/dist/modes/interactive/components/status-marker.js +2 -2
  403. package/dist/modes/interactive/components/status-marker.js.map +1 -1
  404. package/dist/modes/interactive/components/themed-text.d.ts +17 -0
  405. package/dist/modes/interactive/components/themed-text.d.ts.map +1 -0
  406. package/dist/modes/interactive/components/themed-text.js +28 -0
  407. package/dist/modes/interactive/components/themed-text.js.map +1 -0
  408. package/dist/modes/interactive/interactive-mode.d.ts +2 -4
  409. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  410. package/dist/modes/interactive/interactive-mode.js +214 -163
  411. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  412. package/dist/modes/interactive/tasks/completion-render.d.ts +8 -0
  413. package/dist/modes/interactive/tasks/completion-render.d.ts.map +1 -0
  414. package/dist/{extensions/background → modes/interactive/tasks}/completion-render.js +31 -27
  415. package/dist/modes/interactive/tasks/completion-render.js.map +1 -0
  416. package/dist/modes/interactive/tasks/fallback-view.d.ts +4 -0
  417. package/dist/modes/interactive/tasks/fallback-view.d.ts.map +1 -0
  418. package/dist/modes/interactive/tasks/fallback-view.js +27 -0
  419. package/dist/modes/interactive/tasks/fallback-view.js.map +1 -0
  420. package/dist/modes/interactive/tasks/index.d.ts +12 -0
  421. package/dist/modes/interactive/tasks/index.d.ts.map +1 -0
  422. package/dist/modes/interactive/tasks/index.js +97 -0
  423. package/dist/modes/interactive/tasks/index.js.map +1 -0
  424. package/dist/modes/interactive/tasks/manager.d.ts +67 -0
  425. package/dist/modes/interactive/tasks/manager.d.ts.map +1 -0
  426. package/dist/modes/interactive/tasks/manager.js +380 -0
  427. package/dist/modes/interactive/tasks/manager.js.map +1 -0
  428. package/dist/{extensions/background → modes/interactive/tasks}/render.d.ts +13 -13
  429. package/dist/modes/interactive/tasks/render.d.ts.map +1 -0
  430. package/dist/{extensions/background → modes/interactive/tasks}/render.js +18 -18
  431. package/dist/modes/interactive/tasks/render.js.map +1 -0
  432. package/dist/{extensions/background → modes/interactive/tasks}/task-view.d.ts +7 -7
  433. package/dist/modes/interactive/tasks/task-view.d.ts.map +1 -0
  434. package/dist/{extensions/background → modes/interactive/tasks}/task-view.js +4 -4
  435. package/dist/modes/interactive/tasks/task-view.js.map +1 -0
  436. package/dist/{extensions/background → modes/interactive/tasks}/text.d.ts +1 -1
  437. package/dist/modes/interactive/tasks/text.d.ts.map +1 -0
  438. package/dist/{extensions/background → modes/interactive/tasks}/text.js +1 -1
  439. package/dist/modes/interactive/tasks/text.js.map +1 -0
  440. package/dist/modes/interactive/tasks/viewport.d.ts +15 -0
  441. package/dist/modes/interactive/tasks/viewport.d.ts.map +1 -0
  442. package/dist/modes/interactive/tasks/viewport.js +49 -0
  443. package/dist/modes/interactive/tasks/viewport.js.map +1 -0
  444. package/dist/modes/interactive/theme/dark.json +59 -72
  445. package/dist/modes/interactive/theme/light.json +57 -69
  446. package/dist/modes/interactive/theme/system-theme.d.ts +54 -0
  447. package/dist/modes/interactive/theme/system-theme.d.ts.map +1 -0
  448. package/dist/modes/interactive/theme/system-theme.js +535 -0
  449. package/dist/modes/interactive/theme/system-theme.js.map +1 -0
  450. package/dist/modes/interactive/theme/theme-controller.d.ts +46 -6
  451. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  452. package/dist/modes/interactive/theme/theme-controller.js +125 -47
  453. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  454. package/dist/modes/interactive/theme/theme-json.d.ts +1 -0
  455. package/dist/modes/interactive/theme/theme-json.d.ts.map +1 -1
  456. package/dist/modes/interactive/theme/theme-json.js +3 -1
  457. package/dist/modes/interactive/theme/theme-json.js.map +1 -1
  458. package/dist/modes/interactive/theme/theme-schema.json +7 -2
  459. package/dist/modes/interactive/theme/theme.d.ts +70 -39
  460. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  461. package/dist/modes/interactive/theme/theme.js +247 -313
  462. package/dist/modes/interactive/theme/theme.js.map +1 -1
  463. package/dist/modes/interactive/tool-view/fallback.d.ts +1 -1
  464. package/dist/modes/interactive/tool-view/fallback.d.ts.map +1 -1
  465. package/dist/modes/interactive/tool-view/fallback.js +4 -1
  466. package/dist/modes/interactive/tool-view/fallback.js.map +1 -1
  467. package/dist/modes/interactive/tool-view/tool-execution.js +2 -2
  468. package/dist/modes/interactive/tool-view/tool-execution.js.map +1 -1
  469. package/dist/modes/interactive/tui-renderer.d.ts +2 -1
  470. package/dist/modes/interactive/tui-renderer.d.ts.map +1 -1
  471. package/dist/modes/interactive/tui-renderer.js +1 -0
  472. package/dist/modes/interactive/tui-renderer.js.map +1 -1
  473. package/dist/modes/rpc/rpc-client.d.ts +6 -6
  474. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  475. package/dist/modes/rpc/rpc-client.js +12 -8
  476. package/dist/modes/rpc/rpc-client.js.map +1 -1
  477. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  478. package/dist/modes/rpc/rpc-mode.js +7 -9
  479. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  480. package/dist/modes/rpc/rpc-types.d.ts +10 -1
  481. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  482. package/dist/modes/rpc/rpc-types.js.map +1 -1
  483. package/dist/package-manager-cli.d.ts.map +1 -1
  484. package/dist/package-manager-cli.js +6 -2
  485. package/dist/package-manager-cli.js.map +1 -1
  486. package/dist/utils/clipboard-image.d.ts.map +1 -1
  487. package/dist/utils/clipboard-image.js +14 -17
  488. package/dist/utils/clipboard-image.js.map +1 -1
  489. package/dist/utils/clipboard.d.ts +2 -0
  490. package/dist/utils/clipboard.d.ts.map +1 -1
  491. package/dist/utils/clipboard.js +5 -0
  492. package/dist/utils/clipboard.js.map +1 -1
  493. package/dist/utils/paths.d.ts +3 -3
  494. package/dist/utils/paths.d.ts.map +1 -1
  495. package/dist/utils/paths.js +5 -4
  496. package/dist/utils/paths.js.map +1 -1
  497. package/dist/utils/shell.d.ts +1 -3
  498. package/dist/utils/shell.d.ts.map +1 -1
  499. package/dist/utils/shell.js +3 -30
  500. package/dist/utils/shell.js.map +1 -1
  501. package/docs/bundled/README.md +22 -8
  502. package/docs/bundled/extensions/statusline.md +2 -2
  503. package/docs/bundled/tasks.md +141 -0
  504. package/docs/bundled/tool-presentation.md +1 -1
  505. package/docs/custom-provider.md +44 -0
  506. package/docs/docs.json +10 -6
  507. package/docs/extensions.md +89 -86
  508. package/docs/index.md +2 -1
  509. package/docs/keybindings.md +8 -7
  510. package/docs/llama-cpp.md +12 -1
  511. package/docs/mcp.md +188 -0
  512. package/docs/models.md +35 -0
  513. package/docs/packages.md +4 -0
  514. package/docs/providers.md +6 -0
  515. package/docs/rpc.md +5 -3
  516. package/docs/sdk.md +26 -16
  517. package/docs/security.md +4 -0
  518. package/docs/session-format.md +18 -11
  519. package/docs/settings.md +26 -2
  520. package/docs/themes.md +27 -5
  521. package/docs/tui.md +20 -0
  522. package/docs/usage.md +61 -3
  523. package/docs/virtual-models.md +114 -0
  524. package/docs/windows.md +2 -0
  525. package/examples/README.md +1 -1
  526. package/examples/extensions/README.md +2 -0
  527. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  528. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  529. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  530. package/examples/extensions/custom-provider-gitlab-duo/test.ts +4 -4
  531. package/examples/extensions/debug-provider.ts +90 -0
  532. package/examples/extensions/gondolin/package-lock.json +2 -2
  533. package/examples/extensions/gondolin/package.json +1 -1
  534. package/examples/extensions/jev-router.ts +113 -0
  535. package/examples/extensions/sandbox/package-lock.json +2 -2
  536. package/examples/extensions/sandbox/package.json +1 -1
  537. package/examples/extensions/with-deps/package-lock.json +2 -2
  538. package/examples/extensions/with-deps/package.json +1 -1
  539. package/examples/rpc-client.ts +1 -1
  540. package/examples/rpc-extension-ui.ts +1 -1
  541. package/examples/sdk/14-codemode-mcp.ts +61 -0
  542. package/examples/sdk/README.md +1 -0
  543. package/npm-shrinkwrap.json +409 -423
  544. package/package.json +13 -10
  545. package/dist/bundle/chunks/anthropic-messages-XWFTZP2N.js +0 -6
  546. package/dist/bundle/chunks/azure-openai-responses-HS35BQV6.js +0 -2
  547. package/dist/bundle/chunks/chunk-2IO5GDBS.js +0 -11
  548. package/dist/bundle/chunks/chunk-EDBLK2JQ.js +0 -2
  549. package/dist/bundle/chunks/chunk-IORR2FW4.js +0 -2
  550. package/dist/bundle/chunks/chunk-NUHFSC37.js +0 -25
  551. package/dist/bundle/chunks/google-generative-ai-NOVAJBFC.js +0 -2
  552. package/dist/bundle/chunks/google-vertex-4VHCZJV5.js +0 -2
  553. package/dist/bundle/chunks/mistral-conversations-WC6A2WCJ.js +0 -5
  554. package/dist/bundle/chunks/openai-codex-responses-XCDG75W2.js +0 -10
  555. package/dist/bundle/chunks/openai-completions-SHS3CAEL.js +0 -7
  556. package/dist/bundle/chunks/openai-responses-UT6XFKC7.js +0 -2
  557. package/dist/bundle/chunks/virtual-modules-KUEIEAZN.js +0 -2
  558. package/dist/core/background/history.d.ts +0 -4
  559. package/dist/core/background/history.d.ts.map +0 -1
  560. package/dist/core/background/history.js.map +0 -1
  561. package/dist/core/background/output.d.ts.map +0 -1
  562. package/dist/core/background/output.js.map +0 -1
  563. package/dist/core/background/presentation.d.ts +0 -9
  564. package/dist/core/background/presentation.d.ts.map +0 -1
  565. package/dist/core/background/presentation.js.map +0 -1
  566. package/dist/core/background/service.d.ts.map +0 -1
  567. package/dist/core/background/service.js.map +0 -1
  568. package/dist/core/background/session.d.ts +0 -67
  569. package/dist/core/background/session.d.ts.map +0 -1
  570. package/dist/core/background/session.js +0 -248
  571. package/dist/core/background/session.js.map +0 -1
  572. package/dist/core/background/types.d.ts.map +0 -1
  573. package/dist/core/background/types.js.map +0 -1
  574. package/dist/extensions/background/actions.d.ts +0 -11
  575. package/dist/extensions/background/actions.d.ts.map +0 -1
  576. package/dist/extensions/background/actions.js.map +0 -1
  577. package/dist/extensions/background/completion-render.d.ts +0 -8
  578. package/dist/extensions/background/completion-render.d.ts.map +0 -1
  579. package/dist/extensions/background/completion-render.js.map +0 -1
  580. package/dist/extensions/background/constants.d.ts.map +0 -1
  581. package/dist/extensions/background/constants.js.map +0 -1
  582. package/dist/extensions/background/index.d.ts +0 -7
  583. package/dist/extensions/background/index.d.ts.map +0 -1
  584. package/dist/extensions/background/index.js +0 -135
  585. package/dist/extensions/background/index.js.map +0 -1
  586. package/dist/extensions/background/keybindings.d.ts +0 -10
  587. package/dist/extensions/background/keybindings.d.ts.map +0 -1
  588. package/dist/extensions/background/keybindings.js +0 -14
  589. package/dist/extensions/background/keybindings.js.map +0 -1
  590. package/dist/extensions/background/manager.d.ts +0 -80
  591. package/dist/extensions/background/manager.d.ts.map +0 -1
  592. package/dist/extensions/background/manager.js +0 -673
  593. package/dist/extensions/background/manager.js.map +0 -1
  594. package/dist/extensions/background/render.d.ts.map +0 -1
  595. package/dist/extensions/background/render.js.map +0 -1
  596. package/dist/extensions/background/schema.d.ts.map +0 -1
  597. package/dist/extensions/background/schema.js.map +0 -1
  598. package/dist/extensions/background/task-view.d.ts.map +0 -1
  599. package/dist/extensions/background/task-view.js.map +0 -1
  600. package/dist/extensions/background/text.d.ts.map +0 -1
  601. package/dist/extensions/background/text.js.map +0 -1
  602. package/dist/extensions/background/types.d.ts.map +0 -1
  603. package/dist/extensions/background/types.js.map +0 -1
  604. package/dist/extensions/subagent/activity.d.ts +0 -34
  605. package/dist/extensions/subagent/activity.d.ts.map +0 -1
  606. package/dist/extensions/subagent/activity.js +0 -192
  607. package/dist/extensions/subagent/activity.js.map +0 -1
  608. package/dist/extensions/subagent/agents-command.d.ts +0 -4
  609. package/dist/extensions/subagent/agents-command.d.ts.map +0 -1
  610. package/dist/extensions/subagent/agents-command.js +0 -230
  611. package/dist/extensions/subagent/agents-command.js.map +0 -1
  612. package/dist/extensions/subagent/agents.d.ts +0 -6
  613. package/dist/extensions/subagent/agents.d.ts.map +0 -1
  614. package/dist/extensions/subagent/agents.js +0 -53
  615. package/dist/extensions/subagent/agents.js.map +0 -1
  616. package/dist/extensions/subagent/budget.d.ts +0 -15
  617. package/dist/extensions/subagent/budget.d.ts.map +0 -1
  618. package/dist/extensions/subagent/budget.js +0 -123
  619. package/dist/extensions/subagent/budget.js.map +0 -1
  620. package/dist/extensions/subagent/cancellation.d.ts +0 -29
  621. package/dist/extensions/subagent/cancellation.d.ts.map +0 -1
  622. package/dist/extensions/subagent/cancellation.js +0 -91
  623. package/dist/extensions/subagent/cancellation.js.map +0 -1
  624. package/dist/extensions/subagent/constants.d.ts +0 -25
  625. package/dist/extensions/subagent/constants.d.ts.map +0 -1
  626. package/dist/extensions/subagent/constants.js +0 -50
  627. package/dist/extensions/subagent/constants.js.map +0 -1
  628. package/dist/extensions/subagent/index.d.ts +0 -3
  629. package/dist/extensions/subagent/index.d.ts.map +0 -1
  630. package/dist/extensions/subagent/index.js +0 -151
  631. package/dist/extensions/subagent/index.js.map +0 -1
  632. package/dist/extensions/subagent/model-selection.d.ts +0 -16
  633. package/dist/extensions/subagent/model-selection.d.ts.map +0 -1
  634. package/dist/extensions/subagent/model-selection.js +0 -51
  635. package/dist/extensions/subagent/model-selection.js.map +0 -1
  636. package/dist/extensions/subagent/render.d.ts +0 -24
  637. package/dist/extensions/subagent/render.d.ts.map +0 -1
  638. package/dist/extensions/subagent/render.js +0 -336
  639. package/dist/extensions/subagent/render.js.map +0 -1
  640. package/dist/extensions/subagent/resolve.d.ts +0 -31
  641. package/dist/extensions/subagent/resolve.d.ts.map +0 -1
  642. package/dist/extensions/subagent/resolve.js +0 -111
  643. package/dist/extensions/subagent/resolve.js.map +0 -1
  644. package/dist/extensions/subagent/runner.d.ts +0 -35
  645. package/dist/extensions/subagent/runner.d.ts.map +0 -1
  646. package/dist/extensions/subagent/runner.js +0 -255
  647. package/dist/extensions/subagent/runner.js.map +0 -1
  648. package/dist/extensions/subagent/schema.d.ts +0 -28
  649. package/dist/extensions/subagent/schema.d.ts.map +0 -1
  650. package/dist/extensions/subagent/schema.js +0 -58
  651. package/dist/extensions/subagent/schema.js.map +0 -1
  652. package/dist/extensions/subagent/sdk-runner.d.ts +0 -33
  653. package/dist/extensions/subagent/sdk-runner.d.ts.map +0 -1
  654. package/dist/extensions/subagent/sdk-runner.js +0 -331
  655. package/dist/extensions/subagent/sdk-runner.js.map +0 -1
  656. package/dist/extensions/subagent/settings.d.ts +0 -8
  657. package/dist/extensions/subagent/settings.d.ts.map +0 -1
  658. package/dist/extensions/subagent/settings.js +0 -206
  659. package/dist/extensions/subagent/settings.js.map +0 -1
  660. package/dist/extensions/subagent/state.d.ts +0 -102
  661. package/dist/extensions/subagent/state.d.ts.map +0 -1
  662. package/dist/extensions/subagent/state.js +0 -383
  663. package/dist/extensions/subagent/state.js.map +0 -1
  664. package/dist/extensions/subagent/text.d.ts +0 -6
  665. package/dist/extensions/subagent/text.d.ts.map +0 -1
  666. package/dist/extensions/subagent/text.js +0 -66
  667. package/dist/extensions/subagent/text.js.map +0 -1
  668. package/dist/extensions/subagent/types.d.ts +0 -91
  669. package/dist/extensions/subagent/types.d.ts.map +0 -1
  670. package/dist/extensions/subagent/types.js +0 -2
  671. package/dist/extensions/subagent/types.js.map +0 -1
  672. package/dist/extensions/subagent/ui/agents-dialog.d.ts +0 -4
  673. package/dist/extensions/subagent/ui/agents-dialog.d.ts.map +0 -1
  674. package/dist/extensions/subagent/ui/agents-dialog.js +0 -84
  675. package/dist/extensions/subagent/ui/agents-dialog.js.map +0 -1
  676. package/dist/extensions/subagent/ui/choice-menu.d.ts +0 -39
  677. package/dist/extensions/subagent/ui/choice-menu.d.ts.map +0 -1
  678. package/dist/extensions/subagent/ui/choice-menu.js +0 -93
  679. package/dist/extensions/subagent/ui/choice-menu.js.map +0 -1
  680. package/dist/extensions/subagent/ui/choices.d.ts +0 -36
  681. package/dist/extensions/subagent/ui/choices.d.ts.map +0 -1
  682. package/dist/extensions/subagent/ui/choices.js +0 -54
  683. package/dist/extensions/subagent/ui/choices.js.map +0 -1
  684. package/dist/extensions/subagent/ui/model-list.d.ts +0 -66
  685. package/dist/extensions/subagent/ui/model-list.d.ts.map +0 -1
  686. package/dist/extensions/subagent/ui/model-list.js +0 -235
  687. package/dist/extensions/subagent/ui/model-list.js.map +0 -1
  688. package/dist/extensions/subagent/ui/model-picker.d.ts +0 -47
  689. package/dist/extensions/subagent/ui/model-picker.d.ts.map +0 -1
  690. package/dist/extensions/subagent/ui/model-picker.js +0 -143
  691. package/dist/extensions/subagent/ui/model-picker.js.map +0 -1
  692. package/dist/extensions/subagent/ui/profile-settings-menu.d.ts +0 -41
  693. package/dist/extensions/subagent/ui/profile-settings-menu.d.ts.map +0 -1
  694. package/dist/extensions/subagent/ui/profile-settings-menu.js +0 -98
  695. package/dist/extensions/subagent/ui/profile-settings-menu.js.map +0 -1
  696. package/docs/bundled/extensions/background.md +0 -132
  697. package/docs/bundled/extensions/subagent.md +0 -148
  698. /package/dist/{extensions/background → core/tools/tasks}/types.js +0 -0
@@ -1,3 +1,4 @@
1
+ import { bindTasksUI } from "./tasks/index.js";
1
2
  /**
2
3
  * Interactive mode for the coding agent.
3
4
  * Handles TUI rendering and user interaction, delegating business logic to AgentSession.
@@ -33,7 +34,7 @@ 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";
35
36
  import { getChangelogPath, getNewEntries, normalizeChangelogLinks, parseChangelog } from "../../utils/changelog.js";
36
- import { copyToClipboard, readClipboardText } from "../../utils/clipboard.js";
37
+ import { copyToClipboard, readClipboardFilePaths, readClipboardText } from "../../utils/clipboard.js";
37
38
  import { extensionForImageMimeType, readClipboardImage } from "../../utils/clipboard-image.js";
38
39
  import { parseGitUrl } from "../../utils/git.js";
39
40
  import { getCwdRelativePath } from "../../utils/paths.js";
@@ -64,11 +65,13 @@ import { LoginDialogComponent } from "./components/login-dialog.js";
64
65
  import { createMermaidMarkdownTransformer } from "./components/mermaid.js";
65
66
  import { ModelSelectorComponent } from "./components/model-selector.js";
66
67
  import { formatAuthSelectorProviderType, OAuthSelectorComponent, } from "./components/oauth-selector.js";
68
+ import { piLogoLines } from "./components/pi-logo.js";
67
69
  import { ScopedModelsSelectorComponent } from "./components/scoped-models-selector.js";
68
70
  import { SessionSelectorComponent } from "./components/session-selector.js";
69
71
  import { SettingsSelectorComponent } from "./components/settings-selector.js";
70
72
  import { SkillInvocationMessageComponent } from "./components/skill-invocation-message.js";
71
73
  import { BranchSummaryStatusIndicator, CompactionStatusIndicator, IdleStatus, RetryStatusIndicator, WorkingStatusIndicator, } from "./components/status-indicator.js";
74
+ import { ThemedText } from "./components/themed-text.js";
72
75
  import { ThinkingSelectorComponent } from "./components/thinking-selector.js";
73
76
  import { TreeSelectorComponent } from "./components/tree-selector.js";
74
77
  import { TrustSelectorComponent } from "./components/trust-selector.js";
@@ -79,7 +82,7 @@ import { editInExternalEditor } from "./external-editor.js";
79
82
  import { refreshModelCatalogs } from "./model-catalog-refresh.js";
80
83
  import { getModelSearchText } from "./model-search.js";
81
84
  import { shareSession } from "./session-share.js";
82
- import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMarkdownTheme, getThemeByName, onThemeChange, setRegisteredThemes, stopThemeWatcher, Theme, theme, } from "./theme/theme.js";
85
+ import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMarkdownTheme, getThemeByName, onThemeChange, SYSTEM_THEME_NAME, setRegisteredThemes, stopThemeWatcher, Theme, theme, } from "./theme/theme.js";
83
86
  import { InteractiveThemeController } from "./theme/theme-controller.js";
84
87
  import { disposeChatRows, PendingToolMap, ToolChatContainer } from "./tool-view/chat.js";
85
88
  import { ToolExecutionComponent } from "./tool-view/tool-execution.js";
@@ -94,14 +97,15 @@ function isWorkingStatusEditor(editor) {
94
97
  function isExpandable(obj) {
95
98
  return typeof obj === "object" && obj !== null && "setExpanded" in obj && typeof obj.setExpanded === "function";
96
99
  }
97
- class ExpandableText extends Text {
100
+ class ExpandableText extends ThemedText {
98
101
  constructor(getCollapsedText, getExpandedText, expanded = false, paddingX = 0, paddingY = 0) {
99
- super(expanded ? getExpandedText() : getCollapsedText(), paddingX, paddingY);
100
- this.getCollapsedText = getCollapsedText;
101
- this.getExpandedText = getExpandedText;
102
+ const state = { expanded };
103
+ super(() => (state.expanded ? getExpandedText() : getCollapsedText()), paddingX, paddingY);
104
+ this.state = state;
102
105
  }
103
106
  setExpanded(expanded) {
104
- this.setText(expanded ? this.getExpandedText() : this.getCollapsedText());
107
+ this.state.expanded = expanded;
108
+ this.invalidate();
105
109
  }
106
110
  }
107
111
  function isCustomSessionEntry(item) {
@@ -244,6 +248,7 @@ export class InteractiveMode {
244
248
  // Status line tracking (for mutating immediately-sequential status updates)
245
249
  this.lastStatusSpacer = undefined;
246
250
  this.lastStatusText = undefined;
251
+ this.lastStatusMessage = "";
247
252
  this.managedToolStatusStarted = false;
248
253
  // Streaming message tracking
249
254
  this.streamingComponent = undefined;
@@ -316,11 +321,12 @@ export class InteractiveMode {
316
321
  this.options = { ...options, tuiMode };
317
322
  this.autoTrustOnReloadCwd = options.autoTrustOnReloadCwd;
318
323
  this.runtimeHost.setBeforeSessionInvalidate(() => {
324
+ this.tasksUI?.dispose();
319
325
  this.resetExtensionUI();
320
326
  });
321
327
  this.runtimeHost.setRebindSession(async () => {
322
328
  await this.rebindCurrentSession({ renderBeforeBind: true });
323
- await this.themeController.applyFromSettings();
329
+ this.themeController.applyFromSettings();
324
330
  });
325
331
  this.version = VERSION;
326
332
  this.renderer = createInteractiveTui({
@@ -330,6 +336,7 @@ export class InteractiveMode {
330
336
  terminal: options.terminal,
331
337
  onRightClickPaste: this.onRightClickPaste,
332
338
  fullscreenCopyOnSelect: this.settingsManager.getFullscreenCopyOnSelect(),
339
+ fullscreenWheelScrollLines: this.settingsManager.getFullscreenWheelScrollLines(),
333
340
  });
334
341
  this.ui = createInteractiveTuiReference(() => this.renderer);
335
342
  this.ui.setClearOnShrink(this.settingsManager.getClearOnShrink());
@@ -374,7 +381,8 @@ export class InteractiveMode {
374
381
  });
375
382
  }
376
383
  getAutocompleteSourceTag(sourceInfo) {
377
- if (!sourceInfo) {
384
+ // Built-in extension commands are untagged, like built-in commands.
385
+ if (!sourceInfo || sourceInfo.source === "builtin") {
378
386
  return undefined;
379
387
  }
380
388
  const scopePrefix = sourceInfo.scope === "user" ? "u" : sourceInfo.scope === "project" ? "p" : "t";
@@ -527,7 +535,7 @@ export class InteractiveMode {
527
535
  this.chatContainer.addChild(new Text(condensedText, 1, 0));
528
536
  }
529
537
  else {
530
- this.chatContainer.addChild(new Text(theme.bold(theme.fg("accent", "What's New")), 1, 0));
538
+ this.chatContainer.addChild(new ThemedText(() => theme.bold(theme.fg("accent", "What's New")), 1, 0));
531
539
  this.chatContainer.addChild(new Spacer(1));
532
540
  this.chatContainer.addChild(new Markdown(this.changelogMarkdown.trim(), 1, 0, this.getMarkdownThemeWithSettings()));
533
541
  this.chatContainer.addChild(new Spacer(1));
@@ -579,6 +587,7 @@ export class InteractiveMode {
579
587
  terminal,
580
588
  onRightClickPaste: this.onRightClickPaste,
581
589
  fullscreenCopyOnSelect: this.settingsManager.getFullscreenCopyOnSelect(),
590
+ fullscreenWheelScrollLines: this.settingsManager.getFullscreenWheelScrollLines(),
582
591
  });
583
592
  nextUi.setClearOnShrink(clearOnShrink);
584
593
  nextUi.onDebug = onDebug;
@@ -654,13 +663,21 @@ export class InteractiveMode {
654
663
  // Start the UI before initializing extensions so session_start handlers can use interactive dialogs
655
664
  this.ui.start();
656
665
  this.isInitialized = true;
657
- await this.themeController.applyFromSettings();
666
+ this.themeController.applyFromSettings();
667
+ // The header and startup notices bake theme colors into their text, so build them once the terminal
668
+ // reported its colors. This ends at the terminal's DA1 reply, or after 100 ms if it answers nothing.
669
+ await this.themeController.waitForTerminalColors();
658
670
  // Add header with keybindings from config (unless silenced)
659
671
  if (this.options.verbose || !this.settingsManager.getQuietStartup()) {
660
- const logo = theme.bold(theme.fg("accent", APP_NAME)) + theme.fg("dim", ` v${this.version}`);
672
+ // Built on demand so the header follows theme changes. The logo's first line carries the version,
673
+ // its second line the first line of key hints.
674
+ const withLogo = (hints) => {
675
+ const [top, bottom] = piLogoLines();
676
+ return `${top} ${theme.fg("dim", `v${this.version}`)}\n${bottom} ${hints}`;
677
+ };
661
678
  // Build startup instructions using keybinding hint helpers
662
679
  const hint = (keybinding, description) => keyHint(keybinding, description);
663
- const expandedInstructions = [
680
+ const expandedInstructions = () => [
664
681
  hint("app.interrupt", "to interrupt"),
665
682
  hint("app.clear", "to clear"),
666
683
  rawKeyHint(`${keyText("app.clear")} twice`, "to exit"),
@@ -678,19 +695,19 @@ export class InteractiveMode {
678
695
  rawKeyHint("!!", "to run bash (no context)"),
679
696
  hint("app.message.followUp", "to queue follow-up"),
680
697
  hint("app.message.dequeue", "to edit all queued messages"),
681
- hint("app.clipboard.pasteImage", "to paste image (with text fallback)"),
698
+ hint("app.clipboard.pasteImage", "to paste files on macOS, images, or text"),
682
699
  rawKeyHint("drop files", "to attach"),
683
700
  ].join("\n");
684
- const compactInstructions = [
701
+ const compactInstructions = () => [
685
702
  hint("app.interrupt", "interrupt"),
686
703
  rawKeyHint(`${keyText("app.clear")}/${keyText("app.exit")}`, "clear/exit"),
687
704
  rawKeyHint("/", "commands"),
688
705
  rawKeyHint("!", "bash"),
689
706
  hint("app.tools.expand", "more"),
690
707
  ].join(theme.fg("muted", " · "));
691
- const compactOnboarding = theme.fg("dim", `Press ${keyText("app.tools.expand")} to show full startup help and loaded resources.`);
692
- const onboarding = theme.fg("dim", `Pi can explain its own features and look up its docs. Ask it how to use or extend Pi.`);
693
- this.builtInHeader = new ExpandableText(() => `${logo}\n${compactInstructions}\n${compactOnboarding}\n\n${onboarding}`, () => `${logo}\n${expandedInstructions}\n\n${onboarding}`, this.getStartupExpansionState(), 1, 0);
708
+ const compactOnboarding = () => theme.fg("dim", `Press ${keyText("app.tools.expand")} to show full startup help and loaded resources.`);
709
+ const onboarding = () => theme.fg("dim", `Pi can explain its own features and look up its docs. Ask it how to use or extend Pi.`);
710
+ this.builtInHeader = new ExpandableText(() => `${withLogo(compactInstructions())}\n${compactOnboarding()}\n\n${onboarding()}`, () => `${withLogo(expandedInstructions())}\n\n${onboarding()}`, this.getStartupExpansionState(), 1, 0);
694
711
  // Setup UI layout
695
712
  this.headerContainer.addChild(new Spacer(1));
696
713
  this.headerContainer.addChild(this.builtInHeader);
@@ -1265,8 +1282,9 @@ export class InteractiveMode {
1265
1282
  }
1266
1283
  return theme.fg("dim", ` ${labels.join(", ")}`);
1267
1284
  };
1285
+ // Bodies are built on demand so the listing follows theme changes.
1268
1286
  const addLoadedSection = (name, collapsedBody, expandedBody = collapsedBody, color = "mdHeading") => {
1269
- const section = new ExpandableText(() => `${sectionHeader(name, color)}\n${collapsedBody}`, () => `${sectionHeader(name, color)}\n${expandedBody}`, this.getStartupExpansionState(), 0, 0);
1287
+ const section = new ExpandableText(() => `${sectionHeader(name, color)}\n${collapsedBody()}`, () => `${sectionHeader(name, color)}\n${expandedBody()}`, this.getStartupExpansionState(), 0, 0);
1270
1288
  this.loadedResourcesContainer.addChild(section);
1271
1289
  this.loadedResourcesContainer.addChild(new Spacer(1));
1272
1290
  };
@@ -1311,27 +1329,25 @@ export class InteractiveMode {
1311
1329
  ];
1312
1330
  if (contextFiles.length > 0) {
1313
1331
  this.loadedResourcesContainer.addChild(new Spacer(1));
1314
- const contextList = contextFiles
1315
- .map((f) => theme.fg("dim", ` ${this.formatDisplayPath(f.path)}`))
1316
- .join("\n");
1317
- const contextCompactList = formatCompactList(contextFiles.map((contextFile) => this.formatContextPath(contextFile.path)), { sort: false });
1332
+ const contextList = () => contextFiles.map((f) => theme.fg("dim", ` ${this.formatDisplayPath(f.path)}`)).join("\n");
1333
+ const contextCompactList = () => formatCompactList(contextFiles.map((contextFile) => this.formatContextPath(contextFile.path)), { sort: false });
1318
1334
  addLoadedSection("Context", contextCompactList, contextList);
1319
1335
  }
1320
1336
  const skills = skillsResult.skills;
1321
1337
  if (skills.length > 0) {
1322
1338
  const groups = this.buildScopeGroups(skills.map((skill) => ({ path: skill.filePath, sourceInfo: skill.sourceInfo })));
1323
- const skillList = this.formatScopeGroups(groups, {
1339
+ const skillList = () => this.formatScopeGroups(groups, {
1324
1340
  formatPath: (item) => this.formatDisplayPath(item.path),
1325
1341
  formatPackagePath: (item) => this.getShortPath(item.path, item.sourceInfo),
1326
1342
  });
1327
- const skillCompactList = formatCompactList(skills.map((skill) => skill.name));
1343
+ const skillCompactList = () => formatCompactList(skills.map((skill) => skill.name));
1328
1344
  addLoadedSection("Skills", skillCompactList, skillList);
1329
1345
  }
1330
1346
  const templates = this.session.promptTemplates;
1331
1347
  if (templates.length > 0) {
1332
1348
  const groups = this.buildScopeGroups(templates.map((template) => ({ path: template.filePath, sourceInfo: template.sourceInfo })));
1333
1349
  const templateByPath = new Map(templates.map((t) => [t.filePath, t]));
1334
- const templateList = this.formatScopeGroups(groups, {
1350
+ const templateList = () => this.formatScopeGroups(groups, {
1335
1351
  formatPath: (item) => {
1336
1352
  const template = templateByPath.get(item.path);
1337
1353
  return template ? `/${template.name}` : this.formatDisplayPath(item.path);
@@ -1341,53 +1357,40 @@ export class InteractiveMode {
1341
1357
  return template ? `/${template.name}` : this.formatDisplayPath(item.path);
1342
1358
  },
1343
1359
  });
1344
- const promptCompactList = formatCompactList(templates.map((template) => `/${template.name}`));
1360
+ const promptCompactList = () => formatCompactList(templates.map((template) => `/${template.name}`));
1345
1361
  addLoadedSection("Prompts", promptCompactList, templateList);
1346
1362
  }
1347
1363
  if (extensions.length > 0) {
1348
1364
  const groups = this.buildScopeGroups(extensions);
1349
- const extList = this.formatScopeGroups(groups, {
1365
+ const extList = () => this.formatScopeGroups(groups, {
1350
1366
  formatPath: (item) => this.formatExtensionDisplayPath(item.path),
1351
1367
  formatPackagePath: (item) => this.formatExtensionDisplayPath(this.getShortPath(item.path, item.sourceInfo)),
1352
1368
  });
1353
- const extensionCompactList = formatCompactList(this.getCompactExtensionLabels(extensions));
1369
+ const extensionLabels = this.getCompactExtensionLabels(extensions);
1370
+ const extensionCompactList = () => formatCompactList(extensionLabels);
1354
1371
  addLoadedSection("Extensions", extensionCompactList, extList, "mdHeading");
1355
1372
  }
1356
- // Show loaded themes (excluding built-in)
1357
- const loadedThemes = themesResult.themes;
1358
- const customThemes = loadedThemes.filter((t) => t.sourcePath);
1359
- if (customThemes.length > 0) {
1360
- const groups = this.buildScopeGroups(customThemes.map((loadedTheme) => ({
1361
- path: loadedTheme.sourcePath,
1362
- sourceInfo: loadedTheme.sourceInfo,
1363
- })));
1364
- const themeList = this.formatScopeGroups(groups, {
1365
- formatPath: (item) => this.formatDisplayPath(item.path),
1366
- formatPackagePath: (item) => this.getShortPath(item.path, item.sourceInfo),
1367
- });
1368
- const themeCompactList = formatCompactList(customThemes.map((loadedTheme) => loadedTheme.name ?? this.getCompactPathLabel(loadedTheme.sourcePath, loadedTheme.sourceInfo)));
1369
- addLoadedSection("Themes", themeCompactList, themeList);
1370
- }
1371
1373
  }
1372
1374
  if (showDiagnostics) {
1373
1375
  const skillDiagnostics = skillsResult.diagnostics;
1374
1376
  if (skillDiagnostics.length > 0) {
1375
- const warningLines = this.formatDiagnostics(skillDiagnostics, sourceInfos);
1376
- this.loadedResourcesContainer.addChild(new Text(`${theme.fg("warning", "[Skill conflicts]")}\n${warningLines}`, 0, 0));
1377
+ const warningLines = () => this.formatDiagnostics(skillDiagnostics, sourceInfos);
1378
+ this.loadedResourcesContainer.addChild(new ThemedText(() => `${theme.fg("warning", "[Skill conflicts]")}\n${warningLines()}`, 0, 0));
1377
1379
  this.loadedResourcesContainer.addChild(new Spacer(1));
1378
1380
  }
1379
1381
  const promptDiagnostics = promptsResult.diagnostics;
1380
1382
  if (promptDiagnostics.length > 0) {
1381
- const warningLines = this.formatDiagnostics(promptDiagnostics, sourceInfos);
1382
- this.loadedResourcesContainer.addChild(new Text(`${theme.fg("warning", "[Prompt conflicts]")}\n${warningLines}`, 0, 0));
1383
+ const warningLines = () => this.formatDiagnostics(promptDiagnostics, sourceInfos);
1384
+ this.loadedResourcesContainer.addChild(new ThemedText(() => `${theme.fg("warning", "[Prompt conflicts]")}\n${warningLines()}`, 0, 0));
1383
1385
  this.loadedResourcesContainer.addChild(new Spacer(1));
1384
1386
  }
1385
1387
  const extensionDiagnostics = [];
1386
- const extensionErrors = this.session.resourceLoader.getExtensions().errors;
1387
- if (extensionErrors.length > 0) {
1388
- for (const error of extensionErrors) {
1389
- extensionDiagnostics.push({ type: "error", message: error.error, path: error.path });
1390
- }
1388
+ const extensionsResult = this.session.resourceLoader.getExtensions();
1389
+ for (const error of extensionsResult.errors) {
1390
+ extensionDiagnostics.push({ type: "error", message: error.error, path: error.path });
1391
+ }
1392
+ for (const warning of extensionsResult.warnings ?? []) {
1393
+ extensionDiagnostics.push({ type: "warning", message: warning.warning, path: warning.path });
1391
1394
  }
1392
1395
  const commandDiagnostics = this.session.extensionRunner.getCommandDiagnostics();
1393
1396
  extensionDiagnostics.push(...commandDiagnostics);
@@ -1395,14 +1398,14 @@ export class InteractiveMode {
1395
1398
  const shortcutDiagnostics = this.session.extensionRunner.getShortcutDiagnostics();
1396
1399
  extensionDiagnostics.push(...shortcutDiagnostics);
1397
1400
  if (extensionDiagnostics.length > 0) {
1398
- const warningLines = this.formatDiagnostics(extensionDiagnostics, sourceInfos);
1399
- this.loadedResourcesContainer.addChild(new Text(`${theme.fg("warning", "[Extension issues]")}\n${warningLines}`, 0, 0));
1401
+ const warningLines = () => this.formatDiagnostics(extensionDiagnostics, sourceInfos);
1402
+ this.loadedResourcesContainer.addChild(new ThemedText(() => `${theme.fg("warning", "[Extension issues]")}\n${warningLines()}`, 0, 0));
1400
1403
  this.loadedResourcesContainer.addChild(new Spacer(1));
1401
1404
  }
1402
1405
  const themeDiagnostics = themesResult.diagnostics;
1403
1406
  if (themeDiagnostics.length > 0) {
1404
- const warningLines = this.formatDiagnostics(themeDiagnostics, sourceInfos);
1405
- this.loadedResourcesContainer.addChild(new Text(`${theme.fg("warning", "[Theme conflicts]")}\n${warningLines}`, 0, 0));
1407
+ const warningLines = () => this.formatDiagnostics(themeDiagnostics, sourceInfos);
1408
+ this.loadedResourcesContainer.addChild(new ThemedText(() => `${theme.fg("warning", "[Theme conflicts]")}\n${warningLines()}`, 0, 0));
1406
1409
  this.loadedResourcesContainer.addChild(new Spacer(1));
1407
1410
  }
1408
1411
  }
@@ -1411,11 +1414,12 @@ export class InteractiveMode {
1411
1414
  * Initialize the extension system with TUI-based UI context.
1412
1415
  */
1413
1416
  async bindCurrentSessionExtensions() {
1417
+ this.tasksUI?.dispose();
1414
1418
  const uiContext = this.createExtensionUIContext();
1415
1419
  await this.session.bindExtensions({
1416
1420
  uiContext,
1417
1421
  mode: "tui",
1418
- backgroundEnabled: true,
1422
+ tasksEnabled: true,
1419
1423
  abortHandler: () => {
1420
1424
  this.restoreQueuedMessagesToEditor({ abort: true });
1421
1425
  },
@@ -1479,6 +1483,7 @@ export class InteractiveMode {
1479
1483
  this.showExtensionError(error.extensionPath, error.error, error.stack);
1480
1484
  },
1481
1485
  });
1486
+ this.tasksUI = bindTasksUI({ tasks: this.session.tasks, ui: uiContext });
1482
1487
  setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
1483
1488
  this.setupAutocompleteProvider();
1484
1489
  const extensionRunner = this.session.extensionRunner;
@@ -1495,6 +1500,7 @@ export class InteractiveMode {
1495
1500
  this.applyFullscreenScrollbarSetting();
1496
1501
  if (this.renderer instanceof TuiAltScreen) {
1497
1502
  this.renderer.setCopyOnSelect(this.settingsManager.getFullscreenCopyOnSelect());
1503
+ this.renderer.setWheelScrollLines(this.settingsManager.getFullscreenWheelScrollLines());
1498
1504
  }
1499
1505
  this.footer.setSession(this.session);
1500
1506
  this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled);
@@ -1541,10 +1547,11 @@ export class InteractiveMode {
1541
1547
  this.showError(`${prefix}: ${message}`);
1542
1548
  const extensionHint = this.getCrashExtensionHint(error);
1543
1549
  if (extensionHint) {
1544
- this.chatContainer.addChild(new Text(theme.fg("warning", extensionHint), this.outputPad, 0));
1550
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("warning", extensionHint), this.outputPad, 0));
1545
1551
  }
1546
1552
  if (this.recordCrash("fatal_error", error)) {
1547
- this.chatContainer.addChild(new Text(theme.fg("muted", this.crashReportInstructions()), this.outputPad, 0));
1553
+ const instructions = this.crashReportInstructions();
1554
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("muted", instructions), this.outputPad, 0));
1548
1555
  }
1549
1556
  stopThemeWatcher();
1550
1557
  this.stop("transcript");
@@ -1580,7 +1587,7 @@ export class InteractiveMode {
1580
1587
  if (this.bugReportHintShown)
1581
1588
  return;
1582
1589
  this.bugReportHintShown = true;
1583
- 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));
1590
+ 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));
1584
1591
  this.ui.requestRender();
1585
1592
  }
1586
1593
  maybeSuggestBugReport(message) {
@@ -1741,7 +1748,7 @@ export class InteractiveMode {
1741
1748
  container.addChild(new Text(line, 1, 0));
1742
1749
  }
1743
1750
  if (content.length > InteractiveMode.MAX_WIDGET_LINES) {
1744
- container.addChild(new Text(theme.fg("muted", "... (widget truncated)"), 1, 0));
1751
+ container.addChild(new ThemedText(() => theme.fg("muted", "... (widget truncated)"), 1, 0));
1745
1752
  }
1746
1753
  component = container;
1747
1754
  }
@@ -2263,17 +2270,14 @@ export class InteractiveMode {
2263
2270
  */
2264
2271
  showExtensionError(extensionPath, error, stack) {
2265
2272
  const errorMsg = `Extension "${extensionPath}" error: ${error}`;
2266
- const errorText = new Text(theme.fg("error", errorMsg), 1, 0);
2273
+ const errorText = new ThemedText(() => theme.fg("error", errorMsg), 1, 0);
2267
2274
  this.chatContainer.addChild(errorText);
2268
2275
  if (stack) {
2269
2276
  // Show stack trace in dim color, indented
2270
- const stackLines = stack
2271
- .split("\n")
2272
- .slice(1) // Skip first line (duplicates error message)
2273
- .map((line) => theme.fg("dim", ` ${line.trim()}`))
2274
- .join("\n");
2275
- if (stackLines) {
2276
- this.chatContainer.addChild(new Text(stackLines, 1, 0));
2277
+ const stackLines = stack.split("\n").slice(1); // Skip first line (duplicates error message)
2278
+ if (stackLines.length > 0) {
2279
+ const renderStack = () => stackLines.map((line) => theme.fg("dim", ` ${line.trim()}`)).join("\n");
2280
+ this.chatContainer.addChild(new ThemedText(renderStack, 1, 0));
2277
2281
  }
2278
2282
  }
2279
2283
  this.ui.requestRender();
@@ -2343,8 +2347,8 @@ export class InteractiveMode {
2343
2347
  this.updateEditorBorderColor();
2344
2348
  }
2345
2349
  };
2346
- // Handle clipboard paste (triggered on Ctrl+V). Images are attached by path;
2347
- // otherwise, paste plain text from the system clipboard.
2350
+ // Handle clipboard paste (triggered on Ctrl+V). Copied files use their original paths,
2351
+ // images are attached via temporary files, and plain text is the final fallback.
2348
2352
  this.defaultEditor.onPasteImage = () => {
2349
2353
  void this.handleClipboardPaste();
2350
2354
  };
@@ -2367,6 +2371,22 @@ export class InteractiveMode {
2367
2371
  }
2368
2372
  async handleClipboardPaste() {
2369
2373
  try {
2374
+ const filePaths = await readClipboardFilePaths();
2375
+ if (filePaths) {
2376
+ if (filePaths.some((filePath) => /\p{Cc}/u.test(filePath))) {
2377
+ throw new Error("Clipboard file path contains control characters");
2378
+ }
2379
+ const paths = this.isBashMode ? filePaths.map(quoteIfNeeded).join(" ") : filePaths.join("\n");
2380
+ const cursor = this.editor.getCursor?.();
2381
+ const currentLine = cursor ? (this.editor.getText().split("\n")[cursor.line] ?? "") : "";
2382
+ const characterBeforeCursor = cursor && cursor.col > 0 ? currentLine[cursor.col - 1] : "";
2383
+ const characterAfterCursor = cursor ? currentLine[cursor.col] : "";
2384
+ const leadingSpace = characterBeforeCursor && !/\s/.test(characterBeforeCursor) ? " " : "";
2385
+ const trailingSpace = characterAfterCursor && !/\s/.test(characterAfterCursor) ? " " : "";
2386
+ this.editor.insertTextAtCursor?.(`${leadingSpace}${paths}${trailingSpace}`);
2387
+ this.ui.requestRender();
2388
+ return;
2389
+ }
2370
2390
  const image = await readClipboardImage();
2371
2391
  if (image) {
2372
2392
  const tmpDir = os.tmpdir();
@@ -2384,8 +2404,8 @@ export class InteractiveMode {
2384
2404
  this.ui.requestRender();
2385
2405
  }
2386
2406
  }
2387
- catch {
2388
- // Silently ignore clipboard errors (may not have permission, etc.)
2407
+ catch (error) {
2408
+ this.showError(`Failed to paste from clipboard: ${error instanceof Error ? error.message : String(error)}`);
2389
2409
  }
2390
2410
  }
2391
2411
  handleStartupSubmit(text) {
@@ -2400,6 +2420,11 @@ export class InteractiveMode {
2400
2420
  if (this.editorHost.intercept(text, "steer"))
2401
2421
  return;
2402
2422
  // Handle commands
2423
+ if (text === "/tasks") {
2424
+ this.editor.setText("");
2425
+ await this.tasksUI?.open();
2426
+ return;
2427
+ }
2403
2428
  if (text === "/settings") {
2404
2429
  this.showSettingsSelector();
2405
2430
  this.editor.setText("");
@@ -2768,6 +2793,9 @@ export class InteractiveMode {
2768
2793
  // The bash execution callback handles TUI output rendering.
2769
2794
  break;
2770
2795
  case "tool_execution_start": {
2796
+ // Nested calls (from codemode scripts) are shown inside their parent's row.
2797
+ if (event.parentToolCallId)
2798
+ break;
2771
2799
  let component = this.pendingTools.get(event.toolCallId);
2772
2800
  if (!component) {
2773
2801
  component = new ToolExecutionComponent(event.toolName, event.toolCallId, event.args, {
@@ -2869,7 +2897,8 @@ export class InteractiveMode {
2869
2897
  }
2870
2898
  else {
2871
2899
  this.chatContainer.addChild(new Spacer(1));
2872
- this.chatContainer.addChild(new Text(theme.fg("error", event.errorMessage), 1, 0));
2900
+ const errorMessage = event.errorMessage;
2901
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("error", errorMessage), 1, 0));
2873
2902
  }
2874
2903
  }
2875
2904
  void this.flushCompactionQueue({ willRetry: event.willRetry });
@@ -2941,7 +2970,7 @@ export class InteractiveMode {
2941
2970
  }
2942
2971
  const message = status.type === "warning" ? `Warning: ${status.message}` : status.message;
2943
2972
  const color = status.type === "warning" ? "warning" : "dim";
2944
- this.chatContainer.addChild(new Text(theme.fg(color, message), 1, 0));
2973
+ this.chatContainer.addChild(new ThemedText(() => theme.fg(color, message), 1, 0));
2945
2974
  this.lastStatusSpacer = undefined;
2946
2975
  this.lastStatusText = undefined;
2947
2976
  this.ui.requestRender();
@@ -2957,12 +2986,14 @@ export class InteractiveMode {
2957
2986
  const last = children.length > 0 ? children[children.length - 1] : undefined;
2958
2987
  const secondLast = children.length > 1 ? children[children.length - 2] : undefined;
2959
2988
  if (last && secondLast && last === this.lastStatusText && secondLast === this.lastStatusSpacer) {
2960
- this.lastStatusText.setText(theme.fg("dim", message));
2989
+ this.lastStatusMessage = message;
2990
+ this.lastStatusText.invalidate();
2961
2991
  this.ui.requestRender();
2962
2992
  return;
2963
2993
  }
2964
2994
  const spacer = new Spacer(1);
2965
- const text = new Text(theme.fg("dim", message), 1, 0);
2995
+ this.lastStatusMessage = message;
2996
+ const text = new ThemedText(() => theme.fg("dim", this.lastStatusMessage), 1, 0);
2966
2997
  this.chatContainer.addChild(spacer);
2967
2998
  this.chatContainer.addChild(text);
2968
2999
  this.lastStatusSpacer = spacer;
@@ -3171,7 +3202,8 @@ export class InteractiveMode {
3171
3202
  if (!this.settingsManager.getShowCacheMissNotices())
3172
3203
  return;
3173
3204
  this.chatContainer.addChild(new Spacer(1));
3174
- this.chatContainer.addChild(new Text(theme.fg("dim", formatCacheWarmingUsage(entry)), 1, 0));
3205
+ const usage = formatCacheWarmingUsage(entry);
3206
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("dim", usage), 1, 0));
3175
3207
  }
3176
3208
  /**
3177
3209
  * Render billing usage for a compaction or branch summary. The notice is derived
@@ -3185,7 +3217,7 @@ export class InteractiveMode {
3185
3217
  const cost = usage.cost.total >= 0.01 ? ` (~$${usage.cost.total.toFixed(2)})` : "";
3186
3218
  const label = notice.kind === "compaction" ? "Compaction" : "Branch summary";
3187
3219
  this.chatContainer.addChild(new Spacer(1));
3188
- this.chatContainer.addChild(new Text(theme.fg("warning", `${label}: ${formatTokens(tokens)} tokens billed${cost}`), 1, 0));
3220
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("warning", `${label}: ${formatTokens(tokens)} tokens billed${cost}`), 1, 0));
3189
3221
  }
3190
3222
  static countDroppedThinkingBlocks(message) {
3191
3223
  let count = 0;
@@ -3222,7 +3254,7 @@ export class InteractiveMode {
3222
3254
  return;
3223
3255
  const noun = droppedCount === 1 ? "thinking block" : "thinking blocks";
3224
3256
  this.chatContainer.addChild(new Spacer(1));
3225
- this.chatContainer.addChild(new Text(theme.fg("warning", `Anthropic dropped ${droppedCount} ${noun} (details in session)`), 1, 0));
3257
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("warning", `Anthropic dropped ${droppedCount} ${noun} (details in session)`), 1, 0));
3226
3258
  }
3227
3259
  /**
3228
3260
  * Show a transcript notice when a completed assistant message paid for a
@@ -3249,9 +3281,8 @@ export class InteractiveMode {
3249
3281
  else if (miss.idleMs >= CACHE_TTL_MS) {
3250
3282
  label = `Cache miss after ${Math.round(miss.idleMs / 60_000)}m idle`;
3251
3283
  }
3252
- const text = theme.fg("warning", `${label}: ${reBilled}`);
3253
3284
  this.chatContainer.addChild(new Spacer(1));
3254
- this.chatContainer.addChild(new Text(text, 1, 0));
3285
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("warning", `${label}: ${reBilled}`), 1, 0));
3255
3286
  }
3256
3287
  renderInitialMessages() {
3257
3288
  const entries = this.sessionManager.buildContextEntries();
@@ -3275,7 +3306,7 @@ export class InteractiveMode {
3275
3306
  if (this.chatContainer.children.length > 0) {
3276
3307
  this.chatContainer.addChild(new Spacer(1));
3277
3308
  }
3278
- 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));
3309
+ 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));
3279
3310
  }
3280
3311
  async getUserInput() {
3281
3312
  const queuedInput = this.pendingUserInputs.shift();
@@ -3314,7 +3345,8 @@ export class InteractiveMode {
3314
3345
  if (this.isShuttingDown)
3315
3346
  return;
3316
3347
  this.isShuttingDown = true;
3317
- this.session.background.close();
3348
+ this.tasksUI?.dispose();
3349
+ this.session.tasks.close();
3318
3350
  // Keep signal handlers registered until terminal cleanup has completed.
3319
3351
  // `signal-exit` checks the listener list during the same SIGTERM/SIGHUP
3320
3352
  // dispatch and re-sends the signal if only its own listeners remain.
@@ -3619,28 +3651,30 @@ export class InteractiveMode {
3619
3651
  }
3620
3652
  showError(errorMessage) {
3621
3653
  this.chatContainer.addChild(new Spacer(1));
3622
- this.chatContainer.addChild(new Text(theme.fg("error", `Error: ${errorMessage}`), this.outputPad, 0));
3654
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("error", `Error: ${errorMessage}`), this.outputPad, 0));
3623
3655
  this.ui.requestRender();
3624
3656
  }
3625
3657
  showWarning(warningMessage) {
3626
3658
  this.chatContainer.addChild(new Spacer(1));
3627
- this.chatContainer.addChild(new Text(theme.fg("warning", `Warning: ${warningMessage}`), 1, 0));
3659
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("warning", `Warning: ${warningMessage}`), 1, 0));
3628
3660
  this.ui.requestRender();
3629
3661
  }
3630
3662
  showNewVersionNotification(release) {
3631
- const action = theme.fg("accent", `${APP_NAME} update`);
3632
- const updateInstruction = theme.fg("muted", `New version ${release.version} is available. Run `) + action;
3663
+ const updateInstruction = () => theme.fg("muted", `New version ${release.version} is available. Run `) +
3664
+ theme.fg("accent", `${APP_NAME} update`);
3633
3665
  const changelogUrl = "https://pi.dev/changelog";
3634
- const changelogLink = getCapabilities().hyperlinks
3635
- ? hyperlink(theme.fg("accent", changelogUrl), changelogUrl)
3636
- : theme.fg("accent", changelogUrl);
3637
- const changelogLine = UPDATE_CHANGELOG_HINT
3638
- ? theme.fg("muted", UPDATE_CHANGELOG_HINT)
3639
- : theme.fg("muted", "Changelog: ") + changelogLink;
3666
+ const changelogLine = () => {
3667
+ const changelogLink = getCapabilities().hyperlinks
3668
+ ? hyperlink(theme.fg("accent", changelogUrl), changelogUrl)
3669
+ : theme.fg("accent", changelogUrl);
3670
+ return UPDATE_CHANGELOG_HINT
3671
+ ? theme.fg("muted", UPDATE_CHANGELOG_HINT)
3672
+ : theme.fg("muted", "Changelog: ") + changelogLink;
3673
+ };
3640
3674
  const note = release.note?.trim();
3641
3675
  this.chatContainer.addChild(new Spacer(1));
3642
3676
  this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
3643
- this.chatContainer.addChild(new Text(`${theme.bold(theme.fg("warning", "Update Available"))}\n${updateInstruction}`, 1, 0));
3677
+ this.chatContainer.addChild(new ThemedText(() => `${theme.bold(theme.fg("warning", "Update Available"))}\n${updateInstruction()}`, 1, 0));
3644
3678
  if (note) {
3645
3679
  this.chatContainer.addChild(new Spacer(1));
3646
3680
  this.chatContainer.addChild(new Markdown(note, 1, 0, this.getMarkdownThemeWithSettings(), {
@@ -3648,17 +3682,17 @@ export class InteractiveMode {
3648
3682
  }));
3649
3683
  this.chatContainer.addChild(new Spacer(1));
3650
3684
  }
3651
- this.chatContainer.addChild(new Text(changelogLine, 1, 0));
3685
+ this.chatContainer.addChild(new ThemedText(changelogLine, 1, 0));
3652
3686
  this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
3653
3687
  this.ui.requestRender();
3654
3688
  }
3655
3689
  showPackageUpdateNotification(packages) {
3656
- const action = theme.fg("accent", `${APP_NAME} update --extensions`);
3657
- const updateInstruction = theme.fg("muted", "Package updates are available. Run ") + action;
3690
+ const updateInstruction = () => theme.fg("muted", "Package updates are available. Run ") +
3691
+ theme.fg("accent", `${APP_NAME} update --extensions`);
3658
3692
  const packageLines = packages.map((pkg) => `- ${pkg}`).join("\n");
3659
3693
  this.chatContainer.addChild(new Spacer(1));
3660
3694
  this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
3661
- this.chatContainer.addChild(new Text(`${theme.bold(theme.fg("warning", "Package Updates Available"))}\n${updateInstruction}\n${theme.fg("muted", "Packages:")}\n${packageLines}`, 1, 0));
3695
+ this.chatContainer.addChild(new ThemedText(() => `${theme.bold(theme.fg("warning", "Package Updates Available"))}\n${updateInstruction()}\n${theme.fg("muted", "Packages:")}\n${packageLines}`, 1, 0));
3662
3696
  this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
3663
3697
  this.ui.requestRender();
3664
3698
  }
@@ -3895,7 +3929,7 @@ export class InteractiveMode {
3895
3929
  thinkingLevel: this.settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL,
3896
3930
  availableThinkingLevels: [...THINKING_LEVEL_OPTIONS],
3897
3931
  modelThinkingLevels: this.settingsManager.getAllModelThinkingLevels(),
3898
- currentTheme: this.themeController.getThemeSelection() || "dark",
3932
+ currentTheme: this.themeController.getThemeSelection() || SYSTEM_THEME_NAME,
3899
3933
  terminalTheme: this.themeController.getTerminalTheme(),
3900
3934
  availableThemes: getAvailableThemes(),
3901
3935
  hideThinkingBlock: this.hideThinkingBlock,
@@ -3917,6 +3951,7 @@ export class InteractiveMode {
3917
3951
  fullscreenExitOutput: this.settingsManager.getFullscreenExitOutput(),
3918
3952
  fullscreenScrollbar: this.settingsManager.getFullscreenScrollbar(),
3919
3953
  fullscreenCopyOnSelect: this.settingsManager.getFullscreenCopyOnSelect(),
3954
+ fullscreenWheelScrollLines: this.settingsManager.getFullscreenWheelScrollLines(),
3920
3955
  warnings: this.settingsManager.getWarnings(),
3921
3956
  }, {
3922
3957
  onAutoCompactChange: (enabled) => {
@@ -3991,7 +4026,7 @@ export class InteractiveMode {
3991
4026
  },
3992
4027
  onThemeChange: (themeSetting) => {
3993
4028
  this.settingsManager.setTheme(themeSetting);
3994
- void this.themeController.setThemeSetting(themeSetting);
4029
+ this.themeController.setThemeSetting(themeSetting);
3995
4030
  },
3996
4031
  onThemePreview: (themeName) => this.themeController.preview(themeName),
3997
4032
  onHideThinkingBlockChange: (hidden) => {
@@ -4096,6 +4131,11 @@ export class InteractiveMode {
4096
4131
  if (this.renderer instanceof TuiAltScreen)
4097
4132
  this.renderer.setCopyOnSelect(enabled);
4098
4133
  },
4134
+ onFullscreenWheelScrollLinesChange: (lines) => {
4135
+ this.settingsManager.setFullscreenWheelScrollLines(lines);
4136
+ if (this.renderer instanceof TuiAltScreen)
4137
+ this.renderer.setWheelScrollLines(lines);
4138
+ },
4099
4139
  onWarningsChange: (warnings) => {
4100
4140
  this.settingsManager.setWarnings(warnings);
4101
4141
  },
@@ -5078,7 +5118,7 @@ export class InteractiveMode {
5078
5118
  signal: dialog.signal,
5079
5119
  prompt: (prompt) => this.showAuthPrompt(dialog, prompt),
5080
5120
  notify: (event) => this.notifyAuthDialog(dialog, event),
5081
- });
5121
+ }, { getDeviceId: () => this.settingsManager.getOrCreateDeviceId() });
5082
5122
  }
5083
5123
  async showLoginDialog(providerId, providerName) {
5084
5124
  const previousModel = this.session.model;
@@ -5126,7 +5166,7 @@ export class InteractiveMode {
5126
5166
  const borderColor = (s) => theme.fg("border", s);
5127
5167
  reloadBox.addChild(new DynamicBorder(borderColor));
5128
5168
  reloadBox.addChild(new Spacer(1));
5129
- reloadBox.addChild(new Text(theme.fg("muted", "Reloading keybindings, extensions, skills, prompts, themes, and context files..."), 1, 0));
5169
+ reloadBox.addChild(new ThemedText(() => theme.fg("muted", "Reloading keybindings, extensions, skills, prompts, themes, and context files..."), 1, 0));
5130
5170
  reloadBox.addChild(new Spacer(1));
5131
5171
  reloadBox.addChild(new DynamicBorder(borderColor));
5132
5172
  const previousEditor = this.editor;
@@ -5153,7 +5193,9 @@ export class InteractiveMode {
5153
5193
  chatRestoredBeforeSessionStart = true;
5154
5194
  };
5155
5195
  try {
5196
+ this.tasksUI?.dispose();
5156
5197
  await this.session.reload({ beforeSessionStart: restoreChatBeforeSessionStart });
5198
+ this.tasksUI = bindTasksUI({ tasks: this.session.tasks, ui: this.createExtensionUIContext() });
5157
5199
  restoreChatBeforeSessionStart();
5158
5200
  this.keybindings.reload();
5159
5201
  const activeHeader = this.customHeader ?? this.builtInHeader;
@@ -5162,7 +5204,7 @@ export class InteractiveMode {
5162
5204
  }
5163
5205
  setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
5164
5206
  this.applyRuntimeSettings();
5165
- await this.themeController.applyFromSettings();
5207
+ this.themeController.applyFromSettings();
5166
5208
  this.setupAutocompleteProvider();
5167
5209
  const runner = this.session.extensionRunner;
5168
5210
  this.setupExtensionShortcuts(runner);
@@ -5326,7 +5368,7 @@ export class InteractiveMode {
5326
5368
  const currentName = this.sessionManager.getSessionName();
5327
5369
  if (currentName) {
5328
5370
  this.chatContainer.addChild(new Spacer(1));
5329
- this.chatContainer.addChild(new Text(theme.fg("dim", `Session name: ${currentName}`), 1, 0));
5371
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("dim", `Session name: ${currentName}`), 1, 0));
5330
5372
  }
5331
5373
  else {
5332
5374
  this.showWarning("Usage: /name <name>");
@@ -5340,7 +5382,8 @@ export class InteractiveMode {
5340
5382
  this.showWarning(`Session name was normalized from ${JSON.stringify(name)} to ${JSON.stringify(sessionName)}`);
5341
5383
  }
5342
5384
  this.chatContainer.addChild(new Spacer(1));
5343
- this.chatContainer.addChild(new Text(theme.fg("dim", `Session name set: ${sessionName ?? name}`), 1, 0));
5385
+ const displayName = sessionName ?? name;
5386
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("dim", `Session name set: ${displayName}`), 1, 0));
5344
5387
  this.ui.requestRender();
5345
5388
  }
5346
5389
  handleSessionCommand() {
@@ -5352,61 +5395,69 @@ export class InteractiveMode {
5352
5395
  // resolves to a concrete responseModel). Usage without model attribution is
5353
5396
  // grouped separately so the breakdown reconciles with the session total.
5354
5397
  const usageBreakdown = getUsageCostBreakdown(entries);
5355
- let info = `${theme.bold("Session Info")}\n\n`;
5356
- if (sessionName) {
5357
- info += `${theme.fg("dim", "Name:")} ${sessionName}\n`;
5358
- }
5359
- info += `${theme.fg("dim", "File:")} ${stats.sessionFile ?? "In-memory"}\n`;
5360
- info += `${theme.fg("dim", "ID:")} ${stats.sessionId}\n\n`;
5361
- info += `${theme.bold("Messages")}\n`;
5362
- info += `${theme.fg("dim", "Total:")} ${stats.totalMessages}\n`;
5363
- info += `${theme.fg("dim", "User:")} ${stats.userMessages}\n`;
5364
- info += `${theme.fg("dim", "Assistant:")} ${stats.assistantMessages}\n`;
5365
- info += `${theme.fg("dim", "Tools:")} ${stats.toolCalls} calls, ${stats.toolResults} results\n\n`;
5366
- info += `${theme.bold("Tokens")}\n`;
5367
- // "Input" is the full prompt volume. With cache activity, split it into
5368
- // cached (served from cache) vs uncached (everything else) - the only
5369
- // provider-independent split. Cache writes, where reported, are a detail
5370
- // of the uncached portion.
5371
- const { input, cacheRead, cacheWrite } = stats.tokens;
5372
- const promptTokens = input + cacheRead + cacheWrite;
5373
- info += `${theme.fg("dim", "Input:")} ${promptTokens.toLocaleString()}\n`;
5374
- if (promptTokens > 0 && (cacheRead > 0 || cacheWrite > 0)) {
5375
- const hitRate = theme.fg("dim", `(${((cacheRead / promptTokens) * 100).toFixed(1)}%)`);
5376
- info += ` ${theme.fg("dim", "Cached:")} ${cacheRead.toLocaleString()} ${hitRate}\n`;
5377
- const written = cacheWrite > 0 ? ` ${theme.fg("dim", `(${cacheWrite.toLocaleString()} written to cache)`)}` : "";
5378
- info += ` ${theme.fg("dim", "Uncached:")} ${(input + cacheWrite).toLocaleString()}${written}\n`;
5379
- }
5380
- info += `${theme.fg("dim", "Output:")} ${stats.tokens.output.toLocaleString()}\n`;
5381
- info += `${theme.fg("dim", "Total:")} ${stats.tokens.total.toLocaleString()}\n`;
5398
+ // Snapshot the stats; the text is built on demand so it follows theme changes.
5382
5399
  const cacheWarmingStatus = this.session.cacheWarmingStatus;
5383
- info += `\n${theme.bold("Cache Warming")}\n`;
5384
- info += `${theme.fg("dim", "Mode:")} ${this.settingsManager.getCacheWarmingMode()}\n`;
5385
- info += `${theme.fg("dim", "Status:")} ${cacheWarmingStatus ? formatCacheWarmingStatus(cacheWarmingStatus) : "Inactive (cache warming unavailable)"}\n`;
5386
- const decision = cacheWarmingStatus?.decision;
5387
- if (decision?.economicsAvailable) {
5388
- info += `${theme.fg("dim", "Cache miss penalty:")} $${decision.missCost.toFixed(3)}\n`;
5389
- info += `${theme.fg("dim", "Refresh cost:")} $${decision.warmCost.toFixed(3)}\n`;
5390
- }
5391
- if (stats.cost > 0 || cacheWaste.missedTokens > 0) {
5392
- info += `\n${theme.bold("Cost")}\n`;
5393
- info += `${theme.fg("dim", "Total:")} $${stats.cost.toFixed(3)}`;
5394
- if (usageBreakdown.length > 1) {
5395
- for (const entry of usageBreakdown) {
5396
- info += `\n ${theme.fg("dim", `${entry.key}:`)} $${entry.cost.toFixed(3)} ${theme.fg("dim", `(${formatTokens(entry.tokens)} tokens)`)}`;
5400
+ const cacheWarmingMode = this.settingsManager.getCacheWarmingMode();
5401
+ const model = this.session.model;
5402
+ const selectedModelKey = `${model?.provider}/${model?.id}`;
5403
+ const renderInfo = () => {
5404
+ let info = `${theme.bold("Session Info")}\n\n`;
5405
+ if (sessionName) {
5406
+ info += `${theme.fg("dim", "Name:")} ${sessionName}\n`;
5407
+ }
5408
+ info += `${theme.fg("dim", "File:")} ${stats.sessionFile ?? "In-memory"}\n`;
5409
+ info += `${theme.fg("dim", "ID:")} ${stats.sessionId}\n\n`;
5410
+ info += `${theme.bold("Messages")}\n`;
5411
+ info += `${theme.fg("dim", "Total:")} ${stats.totalMessages}\n`;
5412
+ info += `${theme.fg("dim", "User:")} ${stats.userMessages}\n`;
5413
+ info += `${theme.fg("dim", "Assistant:")} ${stats.assistantMessages}\n`;
5414
+ info += `${theme.fg("dim", "Tools:")} ${stats.toolCalls} calls, ${stats.toolResults} results\n\n`;
5415
+ info += `${theme.bold("Tokens")}\n`;
5416
+ // "Input" is the full prompt volume. With cache activity, split it into
5417
+ // cached (served from cache) vs uncached (everything else) - the only
5418
+ // provider-independent split. Cache writes, where reported, are a detail
5419
+ // of the uncached portion.
5420
+ const { input, cacheRead, cacheWrite } = stats.tokens;
5421
+ const promptTokens = input + cacheRead + cacheWrite;
5422
+ info += `${theme.fg("dim", "Input:")} ${promptTokens.toLocaleString()}\n`;
5423
+ if (promptTokens > 0 && (cacheRead > 0 || cacheWrite > 0)) {
5424
+ const hitRate = theme.fg("dim", `(${((cacheRead / promptTokens) * 100).toFixed(1)}%)`);
5425
+ info += ` ${theme.fg("dim", "Cached:")} ${cacheRead.toLocaleString()} ${hitRate}\n`;
5426
+ const written = cacheWrite > 0 ? ` ${theme.fg("dim", `(${cacheWrite.toLocaleString()} written to cache)`)}` : "";
5427
+ info += ` ${theme.fg("dim", "Uncached:")} ${(input + cacheWrite).toLocaleString()}${written}\n`;
5428
+ }
5429
+ info += `${theme.fg("dim", "Output:")} ${stats.tokens.output.toLocaleString()}\n`;
5430
+ info += `${theme.fg("dim", "Total:")} ${stats.tokens.total.toLocaleString()}\n`;
5431
+ info += `\n${theme.bold("Cache Warming")}\n`;
5432
+ info += `${theme.fg("dim", "Mode:")} ${cacheWarmingMode}\n`;
5433
+ info += `${theme.fg("dim", "Status:")} ${cacheWarmingStatus ? formatCacheWarmingStatus(cacheWarmingStatus) : "Inactive (cache warming unavailable)"}\n`;
5434
+ const decision = cacheWarmingStatus?.decision;
5435
+ if (decision?.economicsAvailable) {
5436
+ info += `${theme.fg("dim", "Cache miss penalty:")} $${decision.missCost.toFixed(3)}\n`;
5437
+ info += `${theme.fg("dim", "Refresh cost:")} $${decision.warmCost.toFixed(3)}\n`;
5438
+ }
5439
+ if (stats.cost > 0 || cacheWaste.missedTokens > 0) {
5440
+ info += `\n${theme.bold("Cost")}\n`;
5441
+ info += `${theme.fg("dim", "Total:")} $${stats.cost.toFixed(3)}`;
5442
+ // A single entry repeats the total, unless it names a model other than the selected one.
5443
+ if (usageBreakdown.length > 1 || usageBreakdown[0]?.key !== selectedModelKey) {
5444
+ for (const entry of usageBreakdown) {
5445
+ info += `\n ${theme.fg("dim", `${entry.key}:`)} $${entry.cost.toFixed(3)} ${theme.fg("dim", `(${formatTokens(entry.tokens)} tokens)`)}`;
5446
+ }
5447
+ }
5448
+ if (cacheWaste.missedTokens > 0) {
5449
+ const missLabel = cacheWaste.missCount === 1 ? "1 miss" : `${cacheWaste.missCount} misses`;
5450
+ const detail = `${cacheWaste.missedTokens.toLocaleString()} tokens, ${missLabel}`;
5451
+ info +=
5452
+ cacheWaste.missedCost >= 0.0001
5453
+ ? `\n${theme.fg("dim", "Cache Re-billed:")} $${cacheWaste.missedCost.toFixed(3)} ${theme.fg("dim", `(${detail})`)}`
5454
+ : `\n${theme.fg("dim", "Cache Re-billed:")} ${detail}`;
5397
5455
  }
5398
5456
  }
5399
- if (cacheWaste.missedTokens > 0) {
5400
- const missLabel = cacheWaste.missCount === 1 ? "1 miss" : `${cacheWaste.missCount} misses`;
5401
- const detail = `${cacheWaste.missedTokens.toLocaleString()} tokens, ${missLabel}`;
5402
- info +=
5403
- cacheWaste.missedCost >= 0.0001
5404
- ? `\n${theme.fg("dim", "Cache Re-billed:")} $${cacheWaste.missedCost.toFixed(3)} ${theme.fg("dim", `(${detail})`)}`
5405
- : `\n${theme.fg("dim", "Cache Re-billed:")} ${detail}`;
5406
- }
5407
- }
5457
+ return info;
5458
+ };
5408
5459
  this.chatContainer.addChild(new Spacer(1));
5409
- this.chatContainer.addChild(new Text(info, 1, 0));
5460
+ this.chatContainer.addChild(new ThemedText(renderInfo, 1, 0));
5410
5461
  this.ui.requestRender();
5411
5462
  }
5412
5463
  handleChangelogCommand() {
@@ -5420,7 +5471,7 @@ export class InteractiveMode {
5420
5471
  : "No changelog entries found.";
5421
5472
  this.chatContainer.addChild(new Spacer(1));
5422
5473
  this.chatContainer.addChild(new DynamicBorder());
5423
- this.chatContainer.addChild(new Text(theme.bold(theme.fg("accent", "What's New")), 1, 0));
5474
+ this.chatContainer.addChild(new ThemedText(() => theme.bold(theme.fg("accent", "What's New")), 1, 0));
5424
5475
  this.chatContainer.addChild(new Spacer(1));
5425
5476
  this.chatContainer.addChild(new Markdown(changelogMarkdown, 1, 1, this.getMarkdownThemeWithSettings()));
5426
5477
  this.chatContainer.addChild(new DynamicBorder());
@@ -5521,7 +5572,7 @@ export class InteractiveMode {
5521
5572
  | \`${copyMessage}\` | Copy selection or last assistant message |
5522
5573
  | \`${followUp}\` | Queue follow-up message |
5523
5574
  | \`${dequeue}\` | Restore queued messages |
5524
- | \`${pasteImage}\` | Paste image or text from clipboard |
5575
+ | \`${pasteImage}\` | Paste files on macOS, images, or text from clipboard |
5525
5576
  | \`/\` | Slash commands |
5526
5577
  | \`!\` | Run bash command |
5527
5578
  | \`!!\` | Run bash command (excluded from context) |
@@ -5543,7 +5594,7 @@ export class InteractiveMode {
5543
5594
  }
5544
5595
  this.chatContainer.addChild(new Spacer(1));
5545
5596
  this.chatContainer.addChild(new DynamicBorder());
5546
- this.chatContainer.addChild(new Text(theme.bold(theme.fg("accent", "Keyboard Shortcuts")), 1, 0));
5597
+ this.chatContainer.addChild(new ThemedText(() => theme.bold(theme.fg("accent", "Keyboard Shortcuts")), 1, 0));
5547
5598
  this.chatContainer.addChild(new Spacer(1));
5548
5599
  this.chatContainer.addChild(new Markdown(hotkeys.trim(), 1, 1, this.getMarkdownThemeWithSettings()));
5549
5600
  this.chatContainer.addChild(new DynamicBorder());
@@ -5557,7 +5608,7 @@ export class InteractiveMode {
5557
5608
  return;
5558
5609
  }
5559
5610
  this.chatContainer.addChild(new Spacer(1));
5560
- this.chatContainer.addChild(new Text(`${theme.fg("accent", "✓ New session started")}`, 1, 1));
5611
+ this.chatContainer.addChild(new ThemedText(() => theme.fg("accent", "✓ New session started"), 1, 1));
5561
5612
  this.ui.requestRender();
5562
5613
  }
5563
5614
  catch (error) {
@@ -5588,7 +5639,7 @@ export class InteractiveMode {
5588
5639
  fs.mkdirSync(path.dirname(debugLogPath), { recursive: true });
5589
5640
  fs.writeFileSync(debugLogPath, debugData);
5590
5641
  this.chatContainer.addChild(new Spacer(1));
5591
- this.chatContainer.addChild(new Text(`${theme.fg("accent", "✓ Debug log written")}\n${theme.fg("muted", debugLogPath)}`, 1, 1));
5642
+ this.chatContainer.addChild(new ThemedText(() => `${theme.fg("accent", "✓ Debug log written")}\n${theme.fg("muted", debugLogPath)}`, 1, 1));
5592
5643
  this.ui.requestRender();
5593
5644
  }
5594
5645
  handleArminSaysHi() {