apex-code 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (573) hide show
  1. package/CHANGELOG.md +280 -6
  2. package/README.md +624 -0
  3. package/dist/bun/cli.d.ts +3 -1
  4. package/dist/bun/cli.d.ts.map +1 -1
  5. package/dist/bun/cli.js +3 -9
  6. package/dist/bun/cli.js.map +1 -1
  7. package/dist/bun/runtime-setup.d.ts +2 -0
  8. package/dist/bun/runtime-setup.d.ts.map +1 -0
  9. package/dist/bun/runtime-setup.js +9 -0
  10. package/dist/bun/runtime-setup.js.map +1 -0
  11. package/dist/bun/sandbox-env-setup.d.ts +2 -0
  12. package/dist/bun/sandbox-env-setup.d.ts.map +1 -0
  13. package/dist/bun/sandbox-env-setup.js +4 -0
  14. package/dist/bun/sandbox-env-setup.js.map +1 -0
  15. package/dist/cli/args.d.ts.map +1 -1
  16. package/dist/cli/args.js +16 -5
  17. package/dist/cli/args.js.map +1 -1
  18. package/dist/cli/config-selector.d.ts.map +1 -1
  19. package/dist/cli/config-selector.js +2 -1
  20. package/dist/cli/config-selector.js.map +1 -1
  21. package/dist/cli/file-processor.d.ts +1 -1
  22. package/dist/cli/file-processor.d.ts.map +1 -1
  23. package/dist/cli/file-processor.js.map +1 -1
  24. package/dist/cli/session-picker.d.ts +1 -1
  25. package/dist/cli/session-picker.d.ts.map +1 -1
  26. package/dist/cli/session-picker.js.map +1 -1
  27. package/dist/cli/setup.d.ts +2 -0
  28. package/dist/cli/setup.d.ts.map +1 -0
  29. package/dist/cli/setup.js +13 -0
  30. package/dist/cli/setup.js.map +1 -0
  31. package/dist/config.d.ts +1 -0
  32. package/dist/config.d.ts.map +1 -1
  33. package/dist/config.js +1 -0
  34. package/dist/config.js.map +1 -1
  35. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  36. package/dist/core/agent-session-runtime.js +16 -8
  37. package/dist/core/agent-session-runtime.js.map +1 -1
  38. package/dist/core/agent-session.d.ts +85 -15
  39. package/dist/core/agent-session.d.ts.map +1 -1
  40. package/dist/core/agent-session.js +685 -266
  41. package/dist/core/agent-session.js.map +1 -1
  42. package/dist/core/auth-storage.d.ts +4 -0
  43. package/dist/core/auth-storage.d.ts.map +1 -1
  44. package/dist/core/auth-storage.js +55 -0
  45. package/dist/core/auth-storage.js.map +1 -1
  46. package/dist/core/bug-report.d.ts +176 -0
  47. package/dist/core/bug-report.d.ts.map +1 -0
  48. package/dist/core/bug-report.js +291 -0
  49. package/dist/core/bug-report.js.map +1 -0
  50. package/dist/core/cache-stats.d.ts.map +1 -1
  51. package/dist/core/cache-stats.js +12 -1
  52. package/dist/core/cache-stats.js.map +1 -1
  53. package/dist/core/cache-warmer.d.ts +103 -0
  54. package/dist/core/cache-warmer.d.ts.map +1 -0
  55. package/dist/core/cache-warmer.js +356 -0
  56. package/dist/core/cache-warmer.js.map +1 -0
  57. package/dist/core/compaction/branch-summarization.d.ts +1 -1
  58. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  59. package/dist/core/compaction/branch-summarization.js +4 -3
  60. package/dist/core/compaction/branch-summarization.js.map +1 -1
  61. package/dist/core/compaction/compaction.d.ts +5 -3
  62. package/dist/core/compaction/compaction.d.ts.map +1 -1
  63. package/dist/core/compaction/compaction.js +163 -66
  64. package/dist/core/compaction/compaction.js.map +1 -1
  65. package/dist/core/context/pipeline.d.ts +8 -8
  66. package/dist/core/context/pipeline.d.ts.map +1 -1
  67. package/dist/core/context/pipeline.js +21 -12
  68. package/dist/core/context/pipeline.js.map +1 -1
  69. package/dist/core/crash-log.d.ts +27 -0
  70. package/dist/core/crash-log.d.ts.map +1 -0
  71. package/dist/core/crash-log.js +139 -0
  72. package/dist/core/crash-log.js.map +1 -0
  73. package/dist/core/export-html/template.js +6 -1
  74. package/dist/core/extensions/index.d.ts +1 -1
  75. package/dist/core/extensions/index.d.ts.map +1 -1
  76. package/dist/core/extensions/index.js.map +1 -1
  77. package/dist/core/extensions/jiti-loader.d.ts +2 -0
  78. package/dist/core/extensions/jiti-loader.d.ts.map +1 -0
  79. package/dist/core/extensions/jiti-loader.js +4 -0
  80. package/dist/core/extensions/jiti-loader.js.map +1 -0
  81. package/dist/core/extensions/jiti-static-loader.d.ts +2 -0
  82. package/dist/core/extensions/jiti-static-loader.d.ts.map +1 -0
  83. package/dist/core/extensions/jiti-static-loader.js +4 -0
  84. package/dist/core/extensions/jiti-static-loader.js.map +1 -0
  85. package/dist/core/extensions/loader.d.ts.map +1 -1
  86. package/dist/core/extensions/loader.js +40 -59
  87. package/dist/core/extensions/loader.js.map +1 -1
  88. package/dist/core/extensions/runner.d.ts +24 -8
  89. package/dist/core/extensions/runner.d.ts.map +1 -1
  90. package/dist/core/extensions/runner.js +195 -72
  91. package/dist/core/extensions/runner.js.map +1 -1
  92. package/dist/core/extensions/types.d.ts +142 -55
  93. package/dist/core/extensions/types.d.ts.map +1 -1
  94. package/dist/core/extensions/types.js.map +1 -1
  95. package/dist/core/extensions/virtual-modules.d.ts +3 -0
  96. package/dist/core/extensions/virtual-modules.d.ts.map +1 -0
  97. package/dist/core/extensions/virtual-modules.js +41 -0
  98. package/dist/core/extensions/virtual-modules.js.map +1 -0
  99. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  100. package/dist/core/extensions/wrapper.js +1 -20
  101. package/dist/core/extensions/wrapper.js.map +1 -1
  102. package/dist/core/http-dispatcher.d.ts.map +1 -1
  103. package/dist/core/http-dispatcher.js +2 -0
  104. package/dist/core/http-dispatcher.js.map +1 -1
  105. package/dist/core/index.d.ts +2 -1
  106. package/dist/core/index.d.ts.map +1 -1
  107. package/dist/core/index.js.map +1 -1
  108. package/dist/core/keybindings.d.ts +6 -1
  109. package/dist/core/keybindings.d.ts.map +1 -1
  110. package/dist/core/keybindings.js +5 -1
  111. package/dist/core/keybindings.js.map +1 -1
  112. package/dist/core/messages.d.ts +1 -1
  113. package/dist/core/messages.d.ts.map +1 -1
  114. package/dist/core/messages.js +1 -0
  115. package/dist/core/messages.js.map +1 -1
  116. package/dist/core/model-config.d.ts +168 -20
  117. package/dist/core/model-config.d.ts.map +1 -1
  118. package/dist/core/model-config.js +44 -18
  119. package/dist/core/model-config.js.map +1 -1
  120. package/dist/core/model-registry.d.ts +5 -1
  121. package/dist/core/model-registry.d.ts.map +1 -1
  122. package/dist/core/model-registry.js +8 -0
  123. package/dist/core/model-registry.js.map +1 -1
  124. package/dist/core/model-resolver.d.ts.map +1 -1
  125. package/dist/core/model-resolver.js +4 -3
  126. package/dist/core/model-resolver.js.map +1 -1
  127. package/dist/core/model-runtime.d.ts +1 -0
  128. package/dist/core/model-runtime.d.ts.map +1 -1
  129. package/dist/core/model-runtime.js +12 -6
  130. package/dist/core/model-runtime.js.map +1 -1
  131. package/dist/core/permissions/store.d.ts.map +1 -1
  132. package/dist/core/permissions/store.js +11 -8
  133. package/dist/core/permissions/store.js.map +1 -1
  134. package/dist/core/prompt-templates.d.ts +6 -1
  135. package/dist/core/prompt-templates.d.ts.map +1 -1
  136. package/dist/core/prompt-templates.js +61 -35
  137. package/dist/core/prompt-templates.js.map +1 -1
  138. package/dist/core/provider-composer.d.ts +4 -2
  139. package/dist/core/provider-composer.d.ts.map +1 -1
  140. package/dist/core/provider-composer.js +29 -2
  141. package/dist/core/provider-composer.js.map +1 -1
  142. package/dist/core/radius.d.ts +3 -0
  143. package/dist/core/radius.d.ts.map +1 -1
  144. package/dist/core/radius.js +6 -0
  145. package/dist/core/radius.js.map +1 -1
  146. package/dist/core/resource-loader.d.ts.map +1 -1
  147. package/dist/core/resource-loader.js +6 -2
  148. package/dist/core/resource-loader.js.map +1 -1
  149. package/dist/core/sdk.d.ts.map +1 -1
  150. package/dist/core/sdk.js +63 -42
  151. package/dist/core/sdk.js.map +1 -1
  152. package/dist/core/session-export.d.ts +6 -2
  153. package/dist/core/session-export.d.ts.map +1 -1
  154. package/dist/core/session-export.js +14 -13
  155. package/dist/core/session-export.js.map +1 -1
  156. package/dist/core/session-manager.d.ts +66 -15
  157. package/dist/core/session-manager.d.ts.map +1 -1
  158. package/dist/core/session-manager.js +295 -115
  159. package/dist/core/session-manager.js.map +1 -1
  160. package/dist/core/settings-manager.d.ts +27 -4
  161. package/dist/core/settings-manager.d.ts.map +1 -1
  162. package/dist/core/settings-manager.js +56 -8
  163. package/dist/core/settings-manager.js.map +1 -1
  164. package/dist/core/skills.d.ts +1 -1
  165. package/dist/core/skills.d.ts.map +1 -1
  166. package/dist/core/skills.js +5 -4
  167. package/dist/core/skills.js.map +1 -1
  168. package/dist/core/slash-commands.d.ts.map +1 -1
  169. package/dist/core/slash-commands.js +1 -0
  170. package/dist/core/slash-commands.js.map +1 -1
  171. package/dist/core/system-prompt.d.ts +49 -6
  172. package/dist/core/system-prompt.d.ts.map +1 -1
  173. package/dist/core/system-prompt.js +140 -79
  174. package/dist/core/system-prompt.js.map +1 -1
  175. package/dist/core/tools/bash.d.ts +9 -15
  176. package/dist/core/tools/bash.d.ts.map +1 -1
  177. package/dist/core/tools/bash.js +20 -137
  178. package/dist/core/tools/bash.js.map +1 -1
  179. package/dist/core/tools/delegate.d.ts.map +1 -1
  180. package/dist/core/tools/delegate.js +2 -2
  181. package/dist/core/tools/delegate.js.map +1 -1
  182. package/dist/core/tools/edit.d.ts +1 -12
  183. package/dist/core/tools/edit.d.ts.map +1 -1
  184. package/dist/core/tools/edit.js +6 -204
  185. package/dist/core/tools/edit.js.map +1 -1
  186. package/dist/core/tools/find.d.ts.map +1 -1
  187. package/dist/core/tools/find.js +4 -55
  188. package/dist/core/tools/find.js.map +1 -1
  189. package/dist/core/tools/grep.d.ts.map +1 -1
  190. package/dist/core/tools/grep.js +4 -60
  191. package/dist/core/tools/grep.js.map +1 -1
  192. package/dist/core/tools/ls.d.ts.map +1 -1
  193. package/dist/core/tools/ls.js +4 -49
  194. package/dist/core/tools/ls.js.map +1 -1
  195. package/dist/core/tools/read.d.ts +4 -1
  196. package/dist/core/tools/read.d.ts.map +1 -1
  197. package/dist/core/tools/read.js +10 -122
  198. package/dist/core/tools/read.js.map +1 -1
  199. package/dist/core/tools/renderers/bash.d.ts +18 -0
  200. package/dist/core/tools/renderers/bash.d.ts.map +1 -0
  201. package/dist/core/tools/renderers/bash.js +126 -0
  202. package/dist/core/tools/renderers/bash.js.map +1 -0
  203. package/dist/core/tools/renderers/edit.d.ts +23 -0
  204. package/dist/core/tools/renderers/edit.d.ts.map +1 -0
  205. package/dist/core/tools/renderers/edit.js +207 -0
  206. package/dist/core/tools/renderers/edit.js.map +1 -0
  207. package/dist/core/tools/renderers/find.d.ts +10 -0
  208. package/dist/core/tools/renderers/find.d.ts.map +1 -0
  209. package/dist/core/tools/renderers/find.js +64 -0
  210. package/dist/core/tools/renderers/find.js.map +1 -0
  211. package/dist/core/tools/renderers/grep.d.ts +10 -0
  212. package/dist/core/tools/renderers/grep.d.ts.map +1 -0
  213. package/dist/core/tools/renderers/grep.js +69 -0
  214. package/dist/core/tools/renderers/grep.js.map +1 -0
  215. package/dist/core/tools/renderers/index.d.ts +34 -0
  216. package/dist/core/tools/renderers/index.d.ts.map +1 -0
  217. package/dist/core/tools/renderers/index.js +47 -0
  218. package/dist/core/tools/renderers/index.js.map +1 -0
  219. package/dist/core/tools/renderers/ls.d.ts +10 -0
  220. package/dist/core/tools/renderers/ls.d.ts.map +1 -0
  221. package/dist/core/tools/renderers/ls.js +58 -0
  222. package/dist/core/tools/renderers/ls.js.map +1 -0
  223. package/dist/core/tools/renderers/read.d.ts +11 -0
  224. package/dist/core/tools/renderers/read.d.ts.map +1 -0
  225. package/dist/core/tools/renderers/read.js +132 -0
  226. package/dist/core/tools/renderers/read.js.map +1 -0
  227. package/dist/core/tools/renderers/write.d.ts +10 -0
  228. package/dist/core/tools/renderers/write.d.ts.map +1 -0
  229. package/dist/core/tools/renderers/write.js +152 -0
  230. package/dist/core/tools/renderers/write.js.map +1 -0
  231. package/dist/core/tools/write.d.ts.map +1 -1
  232. package/dist/core/tools/write.js +6 -147
  233. package/dist/core/tools/write.js.map +1 -1
  234. package/dist/core/usage-totals.d.ts +1 -1
  235. package/dist/core/usage-totals.d.ts.map +1 -1
  236. package/dist/core/usage-totals.js +5 -1
  237. package/dist/core/usage-totals.js.map +1 -1
  238. package/dist/extensions/llama/client.d.ts +2 -0
  239. package/dist/extensions/llama/client.d.ts.map +1 -1
  240. package/dist/extensions/llama/client.js +7 -3
  241. package/dist/extensions/llama/client.js.map +1 -1
  242. package/dist/extensions/llama/provider.d.ts.map +1 -1
  243. package/dist/extensions/llama/provider.js +20 -5
  244. package/dist/extensions/llama/provider.js.map +1 -1
  245. package/dist/extensions/llama/ui.d.ts.map +1 -1
  246. package/dist/extensions/llama/ui.js +3 -2
  247. package/dist/extensions/llama/ui.js.map +1 -1
  248. package/dist/index.d.ts +5 -4
  249. package/dist/index.d.ts.map +1 -1
  250. package/dist/index.js +1 -1
  251. package/dist/index.js.map +1 -1
  252. package/dist/main.d.ts.map +1 -1
  253. package/dist/main.js +21 -13
  254. package/dist/main.js.map +1 -1
  255. package/dist/modes/interactive/bug-report.d.ts +16 -0
  256. package/dist/modes/interactive/bug-report.d.ts.map +1 -0
  257. package/dist/modes/interactive/bug-report.js +167 -0
  258. package/dist/modes/interactive/bug-report.js.map +1 -0
  259. package/dist/modes/interactive/chat-viewport.d.ts +20 -0
  260. package/dist/modes/interactive/chat-viewport.d.ts.map +1 -0
  261. package/dist/modes/interactive/chat-viewport.js +28 -0
  262. package/dist/modes/interactive/chat-viewport.js.map +1 -0
  263. package/dist/modes/interactive/components/assistant-message.d.ts +7 -0
  264. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  265. package/dist/modes/interactive/components/assistant-message.js +63 -27
  266. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  267. package/dist/modes/interactive/components/autocomplete-source.d.ts +8 -0
  268. package/dist/modes/interactive/components/autocomplete-source.d.ts.map +1 -0
  269. package/dist/modes/interactive/components/autocomplete-source.js +23 -0
  270. package/dist/modes/interactive/components/autocomplete-source.js.map +1 -0
  271. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  272. package/dist/modes/interactive/components/bash-execution.js +6 -4
  273. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  274. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  275. package/dist/modes/interactive/components/bordered-loader.js +1 -1
  276. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  277. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  278. package/dist/modes/interactive/components/branch-summary-message.js +12 -5
  279. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  280. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  281. package/dist/modes/interactive/components/compaction-summary-message.js +12 -5
  282. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  283. package/dist/modes/interactive/components/composer-dock.d.ts +12 -0
  284. package/dist/modes/interactive/components/composer-dock.d.ts.map +1 -0
  285. package/dist/modes/interactive/components/composer-dock.js +24 -0
  286. package/dist/modes/interactive/components/composer-dock.js.map +1 -0
  287. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  288. package/dist/modes/interactive/components/config-selector.js +11 -9
  289. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  290. package/dist/modes/interactive/components/custom-editor.d.ts +12 -0
  291. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  292. package/dist/modes/interactive/components/custom-editor.js +38 -0
  293. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  294. package/dist/modes/interactive/components/error-summary.d.ts +11 -0
  295. package/dist/modes/interactive/components/error-summary.d.ts.map +1 -0
  296. package/dist/modes/interactive/components/error-summary.js +31 -0
  297. package/dist/modes/interactive/components/error-summary.js.map +1 -0
  298. package/dist/modes/interactive/components/extension-editor.d.ts +4 -1
  299. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  300. package/dist/modes/interactive/components/extension-editor.js +15 -10
  301. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  302. package/dist/modes/interactive/components/extension-input.d.ts +2 -0
  303. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  304. package/dist/modes/interactive/components/extension-input.js +15 -5
  305. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  306. package/dist/modes/interactive/components/extension-selector.d.ts +2 -0
  307. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  308. package/dist/modes/interactive/components/extension-selector.js +15 -10
  309. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  310. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
  311. package/dist/modes/interactive/components/first-time-setup.js +6 -6
  312. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  313. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  314. package/dist/modes/interactive/components/footer.js +12 -4
  315. package/dist/modes/interactive/components/footer.js.map +1 -1
  316. package/dist/modes/interactive/components/index.d.ts +1 -1
  317. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  318. package/dist/modes/interactive/components/index.js.map +1 -1
  319. package/dist/modes/interactive/components/keybinding-hints.d.ts +21 -0
  320. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  321. package/dist/modes/interactive/components/keybinding-hints.js +34 -0
  322. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  323. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  324. package/dist/modes/interactive/components/login-dialog.js +27 -23
  325. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  326. package/dist/modes/interactive/components/model-selector.d.ts +1 -1
  327. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  328. package/dist/modes/interactive/components/model-selector.js +16 -20
  329. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  330. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  331. package/dist/modes/interactive/components/oauth-selector.js +7 -6
  332. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  333. package/dist/modes/interactive/components/permission-preview.d.ts.map +1 -1
  334. package/dist/modes/interactive/components/permission-preview.js +3 -3
  335. package/dist/modes/interactive/components/permission-preview.js.map +1 -1
  336. package/dist/modes/interactive/components/prompt-input.d.ts +12 -0
  337. package/dist/modes/interactive/components/prompt-input.d.ts.map +1 -0
  338. package/dist/modes/interactive/components/prompt-input.js +18 -0
  339. package/dist/modes/interactive/components/prompt-input.js.map +1 -0
  340. package/dist/modes/interactive/components/scoped-models-selector.d.ts +1 -1
  341. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  342. package/dist/modes/interactive/components/scoped-models-selector.js +17 -18
  343. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  344. package/dist/modes/interactive/components/session-selector.d.ts +5 -5
  345. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  346. package/dist/modes/interactive/components/session-selector.js +100 -67
  347. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  348. package/dist/modes/interactive/components/settings-selector.d.ts +5 -1
  349. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  350. package/dist/modes/interactive/components/settings-selector.js +74 -16
  351. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  352. package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -1
  353. package/dist/modes/interactive/components/settings-submenu.js +8 -6
  354. package/dist/modes/interactive/components/settings-submenu.js.map +1 -1
  355. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  356. package/dist/modes/interactive/components/skill-invocation-message.js +11 -4
  357. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  358. package/dist/modes/interactive/components/status-indicator.d.ts +3 -1
  359. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  360. package/dist/modes/interactive/components/status-indicator.js +10 -3
  361. package/dist/modes/interactive/components/status-indicator.js.map +1 -1
  362. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  363. package/dist/modes/interactive/components/thinking-selector.js +14 -9
  364. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  365. package/dist/modes/interactive/components/tool-execution.d.ts +28 -16
  366. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  367. package/dist/modes/interactive/components/tool-execution.js +73 -80
  368. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  369. package/dist/modes/interactive/components/tool-panel.d.ts.map +1 -1
  370. package/dist/modes/interactive/components/tool-panel.js +7 -2
  371. package/dist/modes/interactive/components/tool-panel.js.map +1 -1
  372. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  373. package/dist/modes/interactive/components/tree-selector.js +18 -5
  374. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  375. package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -1
  376. package/dist/modes/interactive/components/trust-selector.js +12 -12
  377. package/dist/modes/interactive/components/trust-selector.js.map +1 -1
  378. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  379. package/dist/modes/interactive/components/user-message-selector.js +2 -2
  380. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  381. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  382. package/dist/modes/interactive/components/user-message.js +6 -3
  383. package/dist/modes/interactive/components/user-message.js.map +1 -1
  384. package/dist/modes/interactive/interactive-mode.d.ts +50 -31
  385. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  386. package/dist/modes/interactive/interactive-mode.js +494 -229
  387. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  388. package/dist/modes/interactive/theme/dark.json +2 -1
  389. package/dist/modes/interactive/theme/light.json +2 -1
  390. package/dist/modes/interactive/theme/theme-controller.d.ts +1 -0
  391. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  392. package/dist/modes/interactive/theme/theme-controller.js +5 -0
  393. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  394. package/dist/modes/interactive/theme/theme-json.d.ts +84 -0
  395. package/dist/modes/interactive/theme/theme-json.d.ts.map +1 -0
  396. package/dist/modes/interactive/theme/theme-json.js +130 -0
  397. package/dist/modes/interactive/theme/theme-json.js.map +1 -0
  398. package/dist/modes/interactive/theme/theme-schema.json +6 -2
  399. package/dist/modes/interactive/theme/theme.d.ts +14 -5
  400. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  401. package/dist/modes/interactive/theme/theme.js +18 -119
  402. package/dist/modes/interactive/theme/theme.js.map +1 -1
  403. package/dist/modes/interactive/tui-renderer.d.ts +21 -0
  404. package/dist/modes/interactive/tui-renderer.d.ts.map +1 -0
  405. package/dist/modes/interactive/tui-renderer.js +66 -0
  406. package/dist/modes/interactive/tui-renderer.js.map +1 -0
  407. package/dist/modes/print-mode.d.ts.map +1 -1
  408. package/dist/modes/print-mode.js +49 -23
  409. package/dist/modes/print-mode.js.map +1 -1
  410. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  411. package/dist/modes/rpc/rpc-mode.js +2 -2
  412. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  413. package/dist/testing/replay/recorded-provider.d.ts +2 -2
  414. package/dist/testing/replay/recorded-provider.d.ts.map +1 -1
  415. package/dist/testing/replay/recorded-provider.js +2 -5
  416. package/dist/testing/replay/recorded-provider.js.map +1 -1
  417. package/dist/testing/replay/runner.d.ts.map +1 -1
  418. package/dist/testing/replay/runner.js +0 -1
  419. package/dist/testing/replay/runner.js.map +1 -1
  420. package/dist/utils/clipboard-command.d.ts +7 -0
  421. package/dist/utils/clipboard-command.d.ts.map +1 -0
  422. package/dist/utils/clipboard-command.js +45 -0
  423. package/dist/utils/clipboard-command.js.map +1 -0
  424. package/dist/utils/clipboard-image.d.ts.map +1 -1
  425. package/dist/utils/clipboard-image.js +53 -81
  426. package/dist/utils/clipboard-image.js.map +1 -1
  427. package/dist/utils/clipboard.d.ts.map +1 -1
  428. package/dist/utils/clipboard.js +111 -121
  429. package/dist/utils/clipboard.js.map +1 -1
  430. package/dist/utils/exif-orientation.d.ts.map +1 -1
  431. package/dist/utils/exif-orientation.js +2 -3
  432. package/dist/utils/exif-orientation.js.map +1 -1
  433. package/dist/utils/mime.d.ts.map +1 -1
  434. package/dist/utils/mime.js +1 -1
  435. package/dist/utils/mime.js.map +1 -1
  436. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  437. package/dist/utils/syntax-highlight.js +21 -21
  438. package/dist/utils/syntax-highlight.js.map +1 -1
  439. package/dist/utils/tool-result-images.d.ts +3 -1
  440. package/dist/utils/tool-result-images.d.ts.map +1 -1
  441. package/dist/utils/tool-result-images.js +4 -1
  442. package/dist/utils/tool-result-images.js.map +1 -1
  443. package/dist/utils/tools-manager.d.ts.map +1 -1
  444. package/dist/utils/tools-manager.js +11 -2
  445. package/dist/utils/tools-manager.js.map +1 -1
  446. package/dist/utils/wsl.d.ts +3 -0
  447. package/dist/utils/wsl.d.ts.map +1 -0
  448. package/dist/utils/wsl.js +15 -0
  449. package/dist/utils/wsl.js.map +1 -0
  450. package/dist/utils/zip.d.ts +7 -0
  451. package/dist/utils/zip.d.ts.map +1 -0
  452. package/dist/utils/zip.js +60 -0
  453. package/dist/utils/zip.js.map +1 -0
  454. package/docs/cli-integration.md +107 -0
  455. package/docs/cli.md +269 -0
  456. package/docs/compaction.md +73 -24
  457. package/docs/configuration.md +45 -0
  458. package/docs/containerization.md +22 -21
  459. package/docs/custom-provider.md +21 -12
  460. package/docs/development.md +19 -0
  461. package/docs/docs.json +139 -95
  462. package/docs/extensions.md +243 -371
  463. package/docs/how-pi-works.md +49 -0
  464. package/docs/images/interactive-mode.png +0 -0
  465. package/docs/index.md +3 -3
  466. package/docs/json.md +43 -3
  467. package/docs/keybindings.md +57 -54
  468. package/docs/llama-cpp.md +2 -2
  469. package/docs/message-types.md +261 -0
  470. package/docs/models.md +103 -49
  471. package/docs/packages.md +49 -47
  472. package/docs/prompt-templates.md +29 -56
  473. package/docs/providers.md +91 -139
  474. package/docs/quickstart.md +42 -14
  475. package/docs/rpc-commands.md +854 -0
  476. package/docs/rpc-extension-ui.md +200 -0
  477. package/docs/rpc.md +121 -223
  478. package/docs/sdk.md +99 -124
  479. package/docs/security.md +7 -7
  480. package/docs/session-format.md +85 -82
  481. package/docs/sessions.md +41 -57
  482. package/docs/settings.md +95 -88
  483. package/docs/shell-aliases.md +68 -3
  484. package/docs/skills.md +62 -49
  485. package/docs/slash-commands.md +60 -0
  486. package/docs/terminal-setup.md +86 -55
  487. package/docs/termux.md +65 -75
  488. package/docs/themes.md +64 -86
  489. package/docs/tmux.md +29 -7
  490. package/docs/tui.md +67 -122
  491. package/docs/usage.md +31 -42
  492. package/docs/windows.md +41 -13
  493. package/examples/README.md +16 -2
  494. package/examples/extensions/README.md +0 -1
  495. package/examples/extensions/custom-provider-anthropic/index.ts +18 -12
  496. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  497. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  498. package/examples/extensions/custom-provider-gitlab-duo/index.ts +2 -2
  499. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  500. package/examples/extensions/dynamic-resources/dynamic.json +2 -0
  501. package/examples/extensions/gondolin/package-lock.json +2 -2
  502. package/examples/extensions/gondolin/package.json +1 -1
  503. package/examples/extensions/prompt-customizer.ts +19 -67
  504. package/examples/extensions/sandbox/package-lock.json +2 -2
  505. package/examples/extensions/sandbox/package.json +1 -1
  506. package/examples/extensions/with-deps/package-lock.json +2 -2
  507. package/examples/extensions/with-deps/package.json +1 -1
  508. package/examples/plugins/pi-example-plugin/README.md +38 -0
  509. package/examples/plugins/pi-example-plugin/package.json +10 -0
  510. package/examples/plugins/pi-example-plugin/src/contract.ts +13 -0
  511. package/examples/plugins/pi-example-plugin/src/session.ts +24 -0
  512. package/examples/plugins/pi-example-plugin/src/tui.ts +31 -0
  513. package/examples/rpc-client.ts +35 -0
  514. package/examples/rpc-extension-ui.ts +25 -5
  515. package/examples/sdk/README.md +1 -1
  516. package/npm-shrinkwrap.json +861 -513
  517. package/package.json +27 -18
  518. package/dist/bun/register-bedrock.d.ts +0 -2
  519. package/dist/bun/register-bedrock.d.ts.map +0 -1
  520. package/dist/bun/register-bedrock.js +0 -4
  521. package/dist/bun/register-bedrock.js.map +0 -1
  522. package/dist/cli/experimental/auth.d.ts +0 -16
  523. package/dist/cli/experimental/auth.d.ts.map +0 -1
  524. package/dist/cli/experimental/auth.js +0 -13
  525. package/dist/cli/experimental/auth.js.map +0 -1
  526. package/dist/cli/experimental/cli.d.ts +0 -6
  527. package/dist/cli/experimental/cli.d.ts.map +0 -1
  528. package/dist/cli/experimental/cli.js +0 -5
  529. package/dist/cli/experimental/cli.js.map +0 -1
  530. package/dist/cli/experimental/command-options.d.ts +0 -17
  531. package/dist/cli/experimental/command-options.d.ts.map +0 -1
  532. package/dist/cli/experimental/command-options.js +0 -35
  533. package/dist/cli/experimental/command-options.js.map +0 -1
  534. package/dist/cli/experimental/command.d.ts +0 -63
  535. package/dist/cli/experimental/command.d.ts.map +0 -1
  536. package/dist/cli/experimental/command.js +0 -130
  537. package/dist/cli/experimental/command.js.map +0 -1
  538. package/dist/cli/experimental/commands/client.d.ts +0 -13
  539. package/dist/cli/experimental/commands/client.d.ts.map +0 -1
  540. package/dist/cli/experimental/commands/client.js +0 -25
  541. package/dist/cli/experimental/commands/client.js.map +0 -1
  542. package/dist/cli/experimental/commands/pi.d.ts +0 -15
  543. package/dist/cli/experimental/commands/pi.d.ts.map +0 -1
  544. package/dist/cli/experimental/commands/pi.js +0 -28
  545. package/dist/cli/experimental/commands/pi.js.map +0 -1
  546. package/dist/cli/experimental/commands/server.d.ts +0 -13
  547. package/dist/cli/experimental/commands/server.d.ts.map +0 -1
  548. package/dist/cli/experimental/commands/server.js +0 -25
  549. package/dist/cli/experimental/commands/server.js.map +0 -1
  550. package/dist/cli/experimental/transport-address.d.ts +0 -10
  551. package/dist/cli/experimental/transport-address.d.ts.map +0 -1
  552. package/dist/cli/experimental/transport-address.js +0 -38
  553. package/dist/cli/experimental/transport-address.js.map +0 -1
  554. package/dist/client/index.d.ts +0 -3
  555. package/dist/client/index.d.ts.map +0 -1
  556. package/dist/client/index.js +0 -3
  557. package/dist/client/index.js.map +0 -1
  558. package/dist/client/remote-session.d.ts +0 -53
  559. package/dist/client/remote-session.d.ts.map +0 -1
  560. package/dist/client/remote-session.js +0 -340
  561. package/dist/client/remote-session.js.map +0 -1
  562. package/dist/client/transcript.d.ts +0 -12
  563. package/dist/client/transcript.d.ts.map +0 -1
  564. package/dist/client/transcript.js +0 -98
  565. package/dist/client/transcript.js.map +0 -1
  566. package/dist/modes/interactive/components/message-spine.d.ts +0 -14
  567. package/dist/modes/interactive/components/message-spine.d.ts.map +0 -1
  568. package/dist/modes/interactive/components/message-spine.js +0 -19
  569. package/dist/modes/interactive/components/message-spine.js.map +0 -1
  570. package/dist/utils/clipboard-native.d.ts +0 -11
  571. package/dist/utils/clipboard-native.d.ts.map +0 -1
  572. package/dist/utils/clipboard-native.js +0 -20
  573. package/dist/utils/clipboard-native.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"skill-invocation-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/skill-invocation-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAsB,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAEjF,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEhD;;;;GAIG;AACH,MAAM,OAAO,+BAAgC,SAAQ,GAAG;IAC/C,QAAQ,GAAG,KAAK,CAAC;IACjB,UAAU,CAAmB;IAC7B,aAAa,CAAgB;IAErC,YAAY,UAA4B,EAAE,aAAa,GAAkB,gBAAgB,EAAE,EAAE;QAC5F,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,CAAC;QACnD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,aAAa,EAAE,CAAC;IAAA,CACrB;IAED,WAAW,CAAC,QAAiB,EAAQ;QACpC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,aAAa,EAAE,CAAC;IAAA,CACrB;IAEQ,UAAU,GAAS;QAC3B,KAAK,CAAC,UAAU,EAAE,CAAC;QACnB,IAAI,CAAC,aAAa,EAAE,CAAC;IAAA,CACrB;IAEO,aAAa,GAAS;QAC7B,IAAI,CAAC,KAAK,EAAE,CAAC;QAEb,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,qDAAqD;YACrD,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,oBAAoB,EAAE,wBAAwB,CAAC,CAAC;YACvE,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACrC,MAAM,MAAM,GAAG,KAAK,IAAI,CAAC,UAAU,CAAC,IAAI,QAAQ,CAAC;YACjD,IAAI,CAAC,QAAQ,CACZ,IAAI,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE;gBACxE,KAAK,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,IAAI,CAAC;aAC5D,CAAC,CACF,CAAC;QACH,CAAC;aAAM,CAAC;YACP,yDAAyD;YACzD,MAAM,IAAI,GACT,KAAK,CAAC,EAAE,CAAC,oBAAoB,EAAE,yBAAyB,CAAC;gBACzD,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;gBACnD,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,OAAO,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC;YAChE,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACrC,CAAC;IAAA,CACD;CACD","sourcesContent":["import { Box, Markdown, type MarkdownTheme, Text } from \"@earendil-works/pi-tui\";\nimport type { ParsedSkillBlock } from \"../../../core/agent-session.ts\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport { keyText } from \"./keybinding-hints.ts\";\n\n/**\n * Component that renders a skill invocation message with collapsed/expanded state.\n * Uses same background color as custom messages for visual consistency.\n * Only renders the skill block itself - user message is rendered separately.\n */\nexport class SkillInvocationMessageComponent extends Box {\n\tprivate expanded = false;\n\tprivate skillBlock: ParsedSkillBlock;\n\tprivate markdownTheme: MarkdownTheme;\n\n\tconstructor(skillBlock: ParsedSkillBlock, markdownTheme: MarkdownTheme = getMarkdownTheme()) {\n\t\tsuper(1, 1, (t) => theme.bg(\"customMessageBg\", t));\n\t\tthis.skillBlock = skillBlock;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tthis.clear();\n\n\t\tif (this.expanded) {\n\t\t\t// Expanded: label + skill name header + full content\n\t\t\tconst label = theme.fg(\"customMessageLabel\", `\\x1b[1m[skill]\\x1b[22m`);\n\t\t\tthis.addChild(new Text(label, 0, 0));\n\t\t\tconst header = `**${this.skillBlock.name}**\\n\\n`;\n\t\t\tthis.addChild(\n\t\t\t\tnew Markdown(header + this.skillBlock.content, 0, 0, this.markdownTheme, {\n\t\t\t\t\tcolor: (text: string) => theme.fg(\"customMessageText\", text),\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\t// Collapsed: single line - [skill] name (hint to expand)\n\t\t\tconst line =\n\t\t\t\ttheme.fg(\"customMessageLabel\", `\\x1b[1m[skill]\\x1b[22m `) +\n\t\t\t\ttheme.fg(\"customMessageText\", this.skillBlock.name) +\n\t\t\t\ttheme.fg(\"dim\", ` (${keyText(\"app.tools.expand\")} to expand)`);\n\t\t\tthis.addChild(new Text(line, 0, 0));\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"skill-invocation-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/skill-invocation-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAsB,WAAW,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAEzG,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEhD;;;;GAIG;AACH,MAAM,OAAO,+BAAgC,SAAQ,GAAG;IAC/C,QAAQ,GAAG,KAAK,CAAC;IACjB,UAAU,CAAmB;IAC7B,aAAa,CAAgB;IAErC,YAAY,UAA4B,EAAE,aAAa,GAAkB,gBAAgB,EAAE,EAAE;QAC5F,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,CAAC;QACnD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,aAAa,EAAE,CAAC;IAAA,CACrB;IAED,WAAW,CAAC,QAAiB,EAAQ;QACpC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,aAAa,EAAE,CAAC;IAAA,CACrB;IAEQ,UAAU,GAAS;QAC3B,KAAK,CAAC,UAAU,EAAE,CAAC;QACnB,IAAI,CAAC,aAAa,EAAE,CAAC;IAAA,CACrB;IAEO,aAAa,GAAS;QAC7B,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,IAAI,SAAS,EAAE,CAAC;QAEhC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,qDAAqD;YACrD,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,oBAAoB,EAAE,wBAAwB,CAAC,CAAC;YACvE,OAAO,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACxC,MAAM,MAAM,GAAG,KAAK,IAAI,CAAC,UAAU,CAAC,IAAI,QAAQ,CAAC;YACjD,OAAO,CAAC,QAAQ,CACf,IAAI,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE;gBACxE,KAAK,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,IAAI,CAAC;aAC5D,CAAC,CACF,CAAC;QACH,CAAC;aAAM,CAAC;YACP,yDAAyD;YACzD,MAAM,IAAI,GACT,KAAK,CAAC,EAAE,CAAC,oBAAoB,EAAE,yBAAyB,CAAC;gBACzD,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;gBACnD,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,OAAO,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC;YAChE,OAAO,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACxC,CAAC;QAED,IAAI,CAAC,QAAQ,CACZ,IAAI,WAAW,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC;YACnC,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM;gBAAE,OAAO,SAAS,CAAC;YACxE,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAAA,CACzB,CAAC,CACF,CAAC;IAAA,CACF;CACD","sourcesContent":["import { Box, Container, Markdown, type MarkdownTheme, MouseRegion, Text } from \"@earendil-works/pi-tui\";\nimport type { ParsedSkillBlock } from \"../../../core/agent-session.ts\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport { keyText } from \"./keybinding-hints.ts\";\n\n/**\n * Component that renders a skill invocation message with collapsed/expanded state.\n * Uses same background color as custom messages for visual consistency.\n * Only renders the skill block itself - user message is rendered separately.\n */\nexport class SkillInvocationMessageComponent extends Box {\n\tprivate expanded = false;\n\tprivate skillBlock: ParsedSkillBlock;\n\tprivate markdownTheme: MarkdownTheme;\n\n\tconstructor(skillBlock: ParsedSkillBlock, markdownTheme: MarkdownTheme = getMarkdownTheme()) {\n\t\tsuper(1, 1, (t) => theme.bg(\"customMessageBg\", t));\n\t\tthis.skillBlock = skillBlock;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tthis.clear();\n\t\tconst content = new Container();\n\n\t\tif (this.expanded) {\n\t\t\t// Expanded: label + skill name header + full content\n\t\t\tconst label = theme.fg(\"customMessageLabel\", `\\x1b[1m[skill]\\x1b[22m`);\n\t\t\tcontent.addChild(new Text(label, 0, 0));\n\t\t\tconst header = `**${this.skillBlock.name}**\\n\\n`;\n\t\t\tcontent.addChild(\n\t\t\t\tnew Markdown(header + this.skillBlock.content, 0, 0, this.markdownTheme, {\n\t\t\t\t\tcolor: (text: string) => theme.fg(\"customMessageText\", text),\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\t// Collapsed: single line - [skill] name (hint to expand)\n\t\t\tconst line =\n\t\t\t\ttheme.fg(\"customMessageLabel\", `\\x1b[1m[skill]\\x1b[22m `) +\n\t\t\t\ttheme.fg(\"customMessageText\", this.skillBlock.name) +\n\t\t\t\ttheme.fg(\"dim\", ` (${keyText(\"app.tools.expand\")} to expand)`);\n\t\t\tcontent.addChild(new Text(line, 0, 0));\n\t\t}\n\n\t\tthis.addChild(\n\t\t\tnew MouseRegion(content, (event) => {\n\t\t\t\tif (event.type !== \"click\" || event.button !== \"left\") return undefined;\n\t\t\t\tthis.setExpanded(!this.expanded);\n\t\t\t\treturn { handled: true };\n\t\t\t}),\n\t\t);\n\t}\n}\n"]}
@@ -4,10 +4,12 @@ export type StatusIndicatorKind = "working" | "retry" | "compaction" | "branchSu
4
4
  export declare class StatusIndicator extends Loader {
5
5
  readonly kind: StatusIndicatorKind;
6
6
  constructor(kind: StatusIndicatorKind, ui: TUI, spinnerColorFn: (str: string) => string, messageColorFn: (str: string) => string, message: string, indicator?: WorkingIndicatorOptions);
7
+ renderInBorder(width: number): string;
8
+ renderSpinnerInBorder(width: number): string;
7
9
  dispose(): void;
8
10
  }
9
11
  export declare class WorkingStatusIndicator extends StatusIndicator {
10
- constructor(ui: TUI, message: string, indicator?: WorkingIndicatorOptions);
12
+ constructor(ui: TUI, message: string, indicator?: WorkingIndicatorOptions, colorFn?: (text: string) => string);
11
13
  }
12
14
  export declare class RetryStatusIndicator extends StatusIndicator {
13
15
  private countdown;
@@ -1 +1 @@
1
- {"version":3,"file":"status-indicator.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/status-indicator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,EAAE,KAAK,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAKjF,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,OAAO,GAAG,YAAY,GAAG,eAAe,CAAC;AAEvF,qBAAa,eAAgB,SAAQ,MAAM;IAC1C,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IAEnC,YACC,IAAI,EAAE,mBAAmB,EACzB,EAAE,EAAE,GAAG,EACP,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,EACvC,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,EACvC,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,uBAAuB,EAInC;IAED,OAAO,IAAI,IAAI,CAEd;CACD;AAED,qBAAa,sBAAuB,SAAQ,eAAe;IAC1D,YAAY,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,uBAAuB,EASxE;CACD;AAED,qBAAa,oBAAqB,SAAQ,eAAe;IACxD,OAAO,CAAC,SAAS,CAA6B;IAE9C,YAAY,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAoBzE;IAEQ,OAAO,IAAI,IAAI,CAIvB;CACD;AAED,MAAM,MAAM,sBAAsB,GAAG,QAAQ,GAAG,WAAW,GAAG,UAAU,CAAC;AAEzE,qBAAa,yBAA0B,SAAQ,eAAe;IAC7D,YAAY,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,sBAAsB,EAalD;CACD;AAED,qBAAa,4BAA6B,SAAQ,eAAe;IAChE,YAAY,EAAE,EAAE,GAAG,EAQlB;CACD;AAED,qBAAa,UAAW,YAAW,SAAS;IAC3C,UAAU,IAAI,IAAI,CAEjB;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAG9B;CACD","sourcesContent":["import { type Component, Loader, type TUI } from \"@earendil-works/pi-tui\";\nimport type { WorkingIndicatorOptions } from \"../../../core/extensions/index.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { CountdownTimer } from \"./countdown-timer.ts\";\nimport { keyText } from \"./keybinding-hints.ts\";\n\nexport type StatusIndicatorKind = \"working\" | \"retry\" | \"compaction\" | \"branchSummary\";\n\nexport class StatusIndicator extends Loader {\n\treadonly kind: StatusIndicatorKind;\n\n\tconstructor(\n\t\tkind: StatusIndicatorKind,\n\t\tui: TUI,\n\t\tspinnerColorFn: (str: string) => string,\n\t\tmessageColorFn: (str: string) => string,\n\t\tmessage: string,\n\t\tindicator?: WorkingIndicatorOptions,\n\t) {\n\t\tsuper(ui, spinnerColorFn, messageColorFn, message, indicator);\n\t\tthis.kind = kind;\n\t}\n\n\tdispose(): void {\n\t\tthis.stop();\n\t}\n}\n\nexport class WorkingStatusIndicator extends StatusIndicator {\n\tconstructor(ui: TUI, message: string, indicator?: WorkingIndicatorOptions) {\n\t\tsuper(\n\t\t\t\"working\",\n\t\t\tui,\n\t\t\t(spinner) => theme.fg(\"accent\", spinner),\n\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\tmessage,\n\t\t\tindicator,\n\t\t);\n\t}\n}\n\nexport class RetryStatusIndicator extends StatusIndicator {\n\tprivate countdown: CountdownTimer | undefined;\n\n\tconstructor(ui: TUI, attempt: number, maxAttempts: number, delayMs: number) {\n\t\tconst retryMessage = (seconds: number) =>\n\t\t\t`Retrying (${attempt}/${maxAttempts}) in ${seconds}s... (${keyText(\"app.interrupt\")} to cancel)`;\n\t\tsuper(\n\t\t\t\"retry\",\n\t\t\tui,\n\t\t\t(spinner) => theme.fg(\"warning\", spinner),\n\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\tretryMessage(Math.ceil(delayMs / 1000)),\n\t\t);\n\t\tthis.countdown = new CountdownTimer(\n\t\t\tdelayMs,\n\t\t\tui,\n\t\t\t(seconds) => {\n\t\t\t\tthis.setMessage(retryMessage(seconds));\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tthis.countdown = undefined;\n\t\t\t},\n\t\t);\n\t}\n\n\toverride dispose(): void {\n\t\tthis.countdown?.dispose();\n\t\tthis.countdown = undefined;\n\t\tsuper.dispose();\n\t}\n}\n\nexport type CompactionStatusReason = \"manual\" | \"threshold\" | \"overflow\";\n\nexport class CompactionStatusIndicator extends StatusIndicator {\n\tconstructor(ui: TUI, reason: CompactionStatusReason) {\n\t\tconst cancelHint = `(${keyText(\"app.interrupt\")} to cancel)`;\n\t\tconst label =\n\t\t\treason === \"manual\"\n\t\t\t\t? `Compacting context... ${cancelHint}`\n\t\t\t\t: `${reason === \"overflow\" ? \"Context overflow detected, \" : \"\"}Auto-compacting... ${cancelHint}`;\n\t\tsuper(\n\t\t\t\"compaction\",\n\t\t\tui,\n\t\t\t(spinner) => theme.fg(\"accent\", spinner),\n\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\tlabel,\n\t\t);\n\t}\n}\n\nexport class BranchSummaryStatusIndicator extends StatusIndicator {\n\tconstructor(ui: TUI) {\n\t\tsuper(\n\t\t\t\"branchSummary\",\n\t\t\tui,\n\t\t\t(spinner) => theme.fg(\"accent\", spinner),\n\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\t`Summarizing branch... (${keyText(\"app.interrupt\")} to cancel)`,\n\t\t);\n\t}\n}\n\nexport class IdleStatus implements Component {\n\tinvalidate(): void {\n\t\t// No cached state to invalidate.\n\t}\n\n\trender(width: number): string[] {\n\t\tconst emptyLine = \" \".repeat(width);\n\t\treturn [emptyLine, emptyLine];\n\t}\n}\n"]}
1
+ {"version":3,"file":"status-indicator.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/status-indicator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,EAAE,KAAK,GAAG,EAAmB,MAAM,wBAAwB,CAAC;AAC3F,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAKjF,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,OAAO,GAAG,YAAY,GAAG,eAAe,CAAC;AAEvF,qBAAa,eAAgB,SAAQ,MAAM;IAC1C,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IAEnC,YACC,IAAI,EAAE,mBAAmB,EACzB,EAAE,EAAE,GAAG,EACP,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,EACvC,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,EACvC,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,uBAAuB,EAInC;IAED,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGpC;IAED,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE3C;IAED,OAAO,IAAI,IAAI,CAEd;CACD;AAED,qBAAa,sBAAuB,SAAQ,eAAe;IAC1D,YAAY,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,uBAAuB,EAAE,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EAS5G;CACD;AAED,qBAAa,oBAAqB,SAAQ,eAAe;IACxD,OAAO,CAAC,SAAS,CAA6B;IAE9C,YAAY,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAoBzE;IAEQ,OAAO,IAAI,IAAI,CAIvB;CACD;AAED,MAAM,MAAM,sBAAsB,GAAG,QAAQ,GAAG,WAAW,GAAG,UAAU,CAAC;AAEzE,qBAAa,yBAA0B,SAAQ,eAAe;IAC7D,YAAY,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,sBAAsB,EAalD;CACD;AAED,qBAAa,4BAA6B,SAAQ,eAAe;IAChE,YAAY,EAAE,EAAE,GAAG,EAQlB;CACD;AAED,qBAAa,UAAW,YAAW,SAAS;IAC3C,UAAU,IAAI,IAAI,CAEjB;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAG9B;CACD","sourcesContent":["import { type Component, Loader, type TUI, truncateToWidth } from \"@earendil-works/pi-tui\";\nimport type { WorkingIndicatorOptions } from \"../../../core/extensions/index.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { CountdownTimer } from \"./countdown-timer.ts\";\nimport { keyText } from \"./keybinding-hints.ts\";\n\nexport type StatusIndicatorKind = \"working\" | \"retry\" | \"compaction\" | \"branchSummary\";\n\nexport class StatusIndicator extends Loader {\n\treadonly kind: StatusIndicatorKind;\n\n\tconstructor(\n\t\tkind: StatusIndicatorKind,\n\t\tui: TUI,\n\t\tspinnerColorFn: (str: string) => string,\n\t\tmessageColorFn: (str: string) => string,\n\t\tmessage: string,\n\t\tindicator?: WorkingIndicatorOptions,\n\t) {\n\t\tsuper(ui, spinnerColorFn, messageColorFn, message, indicator);\n\t\tthis.kind = kind;\n\t}\n\n\trenderInBorder(width: number): string {\n\t\tconst line = super.render(width + 2)[1] ?? \"\";\n\t\treturn truncateToWidth(line.startsWith(\" \") ? line.slice(1).trimEnd() : line.trimEnd(), width, \"\");\n\t}\n\n\trenderSpinnerInBorder(width: number): string {\n\t\treturn truncateToWidth(this.getRenderedIndicator(), width, \"\");\n\t}\n\n\tdispose(): void {\n\t\tthis.stop();\n\t}\n}\n\nexport class WorkingStatusIndicator extends StatusIndicator {\n\tconstructor(ui: TUI, message: string, indicator?: WorkingIndicatorOptions, colorFn?: (text: string) => string) {\n\t\tsuper(\n\t\t\t\"working\",\n\t\t\tui,\n\t\t\tcolorFn ?? ((text) => theme.fg(\"accent\", text)),\n\t\t\tcolorFn ?? ((text) => theme.fg(\"muted\", text)),\n\t\t\tmessage,\n\t\t\tindicator,\n\t\t);\n\t}\n}\n\nexport class RetryStatusIndicator extends StatusIndicator {\n\tprivate countdown: CountdownTimer | undefined;\n\n\tconstructor(ui: TUI, attempt: number, maxAttempts: number, delayMs: number) {\n\t\tconst retryMessage = (seconds: number) =>\n\t\t\t`Retrying (${attempt}/${maxAttempts}) in ${seconds}s... (${keyText(\"app.interrupt\")} to cancel)`;\n\t\tsuper(\n\t\t\t\"retry\",\n\t\t\tui,\n\t\t\t(spinner) => theme.fg(\"warning\", spinner),\n\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\tretryMessage(Math.ceil(delayMs / 1000)),\n\t\t);\n\t\tthis.countdown = new CountdownTimer(\n\t\t\tdelayMs,\n\t\t\tui,\n\t\t\t(seconds) => {\n\t\t\t\tthis.setMessage(retryMessage(seconds));\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tthis.countdown = undefined;\n\t\t\t},\n\t\t);\n\t}\n\n\toverride dispose(): void {\n\t\tthis.countdown?.dispose();\n\t\tthis.countdown = undefined;\n\t\tsuper.dispose();\n\t}\n}\n\nexport type CompactionStatusReason = \"manual\" | \"threshold\" | \"overflow\";\n\nexport class CompactionStatusIndicator extends StatusIndicator {\n\tconstructor(ui: TUI, reason: CompactionStatusReason) {\n\t\tconst cancelHint = `(${keyText(\"app.interrupt\")} to cancel)`;\n\t\tconst label =\n\t\t\treason === \"manual\"\n\t\t\t\t? `Compacting context... ${cancelHint}`\n\t\t\t\t: `${reason === \"overflow\" ? \"Context overflow detected, \" : \"\"}Auto-compacting... ${cancelHint}`;\n\t\tsuper(\n\t\t\t\"compaction\",\n\t\t\tui,\n\t\t\t(spinner) => theme.fg(\"accent\", spinner),\n\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\tlabel,\n\t\t);\n\t}\n}\n\nexport class BranchSummaryStatusIndicator extends StatusIndicator {\n\tconstructor(ui: TUI) {\n\t\tsuper(\n\t\t\t\"branchSummary\",\n\t\t\tui,\n\t\t\t(spinner) => theme.fg(\"accent\", spinner),\n\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\t`Summarizing branch... (${keyText(\"app.interrupt\")} to cancel)`,\n\t\t);\n\t}\n}\n\nexport class IdleStatus implements Component {\n\tinvalidate(): void {\n\t\t// No cached state to invalidate.\n\t}\n\n\trender(width: number): string[] {\n\t\tconst emptyLine = \" \".repeat(width);\n\t\treturn [emptyLine, emptyLine];\n\t}\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { Loader } from "@earendil-works/pi-tui";
1
+ import { Loader, truncateToWidth } from "@earendil-works/pi-tui";
2
2
  import { theme } from "../theme/theme.js";
3
3
  import { CountdownTimer } from "./countdown-timer.js";
4
4
  import { keyText } from "./keybinding-hints.js";
@@ -8,13 +8,20 @@ export class StatusIndicator extends Loader {
8
8
  super(ui, spinnerColorFn, messageColorFn, message, indicator);
9
9
  this.kind = kind;
10
10
  }
11
+ renderInBorder(width) {
12
+ const line = super.render(width + 2)[1] ?? "";
13
+ return truncateToWidth(line.startsWith(" ") ? line.slice(1).trimEnd() : line.trimEnd(), width, "");
14
+ }
15
+ renderSpinnerInBorder(width) {
16
+ return truncateToWidth(this.getRenderedIndicator(), width, "");
17
+ }
11
18
  dispose() {
12
19
  this.stop();
13
20
  }
14
21
  }
15
22
  export class WorkingStatusIndicator extends StatusIndicator {
16
- constructor(ui, message, indicator) {
17
- super("working", ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), message, indicator);
23
+ constructor(ui, message, indicator, colorFn) {
24
+ super("working", ui, colorFn ?? ((text) => theme.fg("accent", text)), colorFn ?? ((text) => theme.fg("muted", text)), message, indicator);
18
25
  }
19
26
  }
20
27
  export class RetryStatusIndicator extends StatusIndicator {
@@ -1 +1 @@
1
- {"version":3,"file":"status-indicator.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/status-indicator.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Component, Loader, type TUI } from \"@earendil-works/pi-tui\";\nimport type { WorkingIndicatorOptions } from \"../../../core/extensions/index.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { CountdownTimer } from \"./countdown-timer.ts\";\nimport { keyText } from \"./keybinding-hints.ts\";\n\nexport type StatusIndicatorKind = \"working\" | \"retry\" | \"compaction\" | \"branchSummary\";\n\nexport class StatusIndicator extends Loader {\n\treadonly kind: StatusIndicatorKind;\n\n\tconstructor(\n\t\tkind: StatusIndicatorKind,\n\t\tui: TUI,\n\t\tspinnerColorFn: (str: string) => string,\n\t\tmessageColorFn: (str: string) => string,\n\t\tmessage: string,\n\t\tindicator?: WorkingIndicatorOptions,\n\t) {\n\t\tsuper(ui, spinnerColorFn, messageColorFn, message, indicator);\n\t\tthis.kind = kind;\n\t}\n\n\tdispose(): void {\n\t\tthis.stop();\n\t}\n}\n\nexport class WorkingStatusIndicator extends StatusIndicator {\n\tconstructor(ui: TUI, message: string, indicator?: WorkingIndicatorOptions) {\n\t\tsuper(\n\t\t\t\"working\",\n\t\t\tui,\n\t\t\t(spinner) => theme.fg(\"accent\", spinner),\n\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\tmessage,\n\t\t\tindicator,\n\t\t);\n\t}\n}\n\nexport class RetryStatusIndicator extends StatusIndicator {\n\tprivate countdown: CountdownTimer | undefined;\n\n\tconstructor(ui: TUI, attempt: number, maxAttempts: number, delayMs: number) {\n\t\tconst retryMessage = (seconds: number) =>\n\t\t\t`Retrying (${attempt}/${maxAttempts}) in ${seconds}s... (${keyText(\"app.interrupt\")} to cancel)`;\n\t\tsuper(\n\t\t\t\"retry\",\n\t\t\tui,\n\t\t\t(spinner) => theme.fg(\"warning\", spinner),\n\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\tretryMessage(Math.ceil(delayMs / 1000)),\n\t\t);\n\t\tthis.countdown = new CountdownTimer(\n\t\t\tdelayMs,\n\t\t\tui,\n\t\t\t(seconds) => {\n\t\t\t\tthis.setMessage(retryMessage(seconds));\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tthis.countdown = undefined;\n\t\t\t},\n\t\t);\n\t}\n\n\toverride dispose(): void {\n\t\tthis.countdown?.dispose();\n\t\tthis.countdown = undefined;\n\t\tsuper.dispose();\n\t}\n}\n\nexport type CompactionStatusReason = \"manual\" | \"threshold\" | \"overflow\";\n\nexport class CompactionStatusIndicator extends StatusIndicator {\n\tconstructor(ui: TUI, reason: CompactionStatusReason) {\n\t\tconst cancelHint = `(${keyText(\"app.interrupt\")} to cancel)`;\n\t\tconst label =\n\t\t\treason === \"manual\"\n\t\t\t\t? `Compacting context... ${cancelHint}`\n\t\t\t\t: `${reason === \"overflow\" ? \"Context overflow detected, \" : \"\"}Auto-compacting... ${cancelHint}`;\n\t\tsuper(\n\t\t\t\"compaction\",\n\t\t\tui,\n\t\t\t(spinner) => theme.fg(\"accent\", spinner),\n\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\tlabel,\n\t\t);\n\t}\n}\n\nexport class BranchSummaryStatusIndicator extends StatusIndicator {\n\tconstructor(ui: TUI) {\n\t\tsuper(\n\t\t\t\"branchSummary\",\n\t\t\tui,\n\t\t\t(spinner) => theme.fg(\"accent\", spinner),\n\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\t`Summarizing branch... (${keyText(\"app.interrupt\")} to cancel)`,\n\t\t);\n\t}\n}\n\nexport class IdleStatus implements Component {\n\tinvalidate(): void {\n\t\t// No cached state to invalidate.\n\t}\n\n\trender(width: number): string[] {\n\t\tconst emptyLine = \" \".repeat(width);\n\t\treturn [emptyLine, emptyLine];\n\t}\n}\n"]}
1
+ {"version":3,"file":"status-indicator.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/status-indicator.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Component, Loader, type TUI, truncateToWidth } from \"@earendil-works/pi-tui\";\nimport type { WorkingIndicatorOptions } from \"../../../core/extensions/index.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { CountdownTimer } from \"./countdown-timer.ts\";\nimport { keyText } from \"./keybinding-hints.ts\";\n\nexport type StatusIndicatorKind = \"working\" | \"retry\" | \"compaction\" | \"branchSummary\";\n\nexport class StatusIndicator extends Loader {\n\treadonly kind: StatusIndicatorKind;\n\n\tconstructor(\n\t\tkind: StatusIndicatorKind,\n\t\tui: TUI,\n\t\tspinnerColorFn: (str: string) => string,\n\t\tmessageColorFn: (str: string) => string,\n\t\tmessage: string,\n\t\tindicator?: WorkingIndicatorOptions,\n\t) {\n\t\tsuper(ui, spinnerColorFn, messageColorFn, message, indicator);\n\t\tthis.kind = kind;\n\t}\n\n\trenderInBorder(width: number): string {\n\t\tconst line = super.render(width + 2)[1] ?? \"\";\n\t\treturn truncateToWidth(line.startsWith(\" \") ? line.slice(1).trimEnd() : line.trimEnd(), width, \"\");\n\t}\n\n\trenderSpinnerInBorder(width: number): string {\n\t\treturn truncateToWidth(this.getRenderedIndicator(), width, \"\");\n\t}\n\n\tdispose(): void {\n\t\tthis.stop();\n\t}\n}\n\nexport class WorkingStatusIndicator extends StatusIndicator {\n\tconstructor(ui: TUI, message: string, indicator?: WorkingIndicatorOptions, colorFn?: (text: string) => string) {\n\t\tsuper(\n\t\t\t\"working\",\n\t\t\tui,\n\t\t\tcolorFn ?? ((text) => theme.fg(\"accent\", text)),\n\t\t\tcolorFn ?? ((text) => theme.fg(\"muted\", text)),\n\t\t\tmessage,\n\t\t\tindicator,\n\t\t);\n\t}\n}\n\nexport class RetryStatusIndicator extends StatusIndicator {\n\tprivate countdown: CountdownTimer | undefined;\n\n\tconstructor(ui: TUI, attempt: number, maxAttempts: number, delayMs: number) {\n\t\tconst retryMessage = (seconds: number) =>\n\t\t\t`Retrying (${attempt}/${maxAttempts}) in ${seconds}s... (${keyText(\"app.interrupt\")} to cancel)`;\n\t\tsuper(\n\t\t\t\"retry\",\n\t\t\tui,\n\t\t\t(spinner) => theme.fg(\"warning\", spinner),\n\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\tretryMessage(Math.ceil(delayMs / 1000)),\n\t\t);\n\t\tthis.countdown = new CountdownTimer(\n\t\t\tdelayMs,\n\t\t\tui,\n\t\t\t(seconds) => {\n\t\t\t\tthis.setMessage(retryMessage(seconds));\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tthis.countdown = undefined;\n\t\t\t},\n\t\t);\n\t}\n\n\toverride dispose(): void {\n\t\tthis.countdown?.dispose();\n\t\tthis.countdown = undefined;\n\t\tsuper.dispose();\n\t}\n}\n\nexport type CompactionStatusReason = \"manual\" | \"threshold\" | \"overflow\";\n\nexport class CompactionStatusIndicator extends StatusIndicator {\n\tconstructor(ui: TUI, reason: CompactionStatusReason) {\n\t\tconst cancelHint = `(${keyText(\"app.interrupt\")} to cancel)`;\n\t\tconst label =\n\t\t\treason === \"manual\"\n\t\t\t\t? `Compacting context... ${cancelHint}`\n\t\t\t\t: `${reason === \"overflow\" ? \"Context overflow detected, \" : \"\"}Auto-compacting... ${cancelHint}`;\n\t\tsuper(\n\t\t\t\"compaction\",\n\t\t\tui,\n\t\t\t(spinner) => theme.fg(\"accent\", spinner),\n\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\tlabel,\n\t\t);\n\t}\n}\n\nexport class BranchSummaryStatusIndicator extends StatusIndicator {\n\tconstructor(ui: TUI) {\n\t\tsuper(\n\t\t\t\"branchSummary\",\n\t\t\tui,\n\t\t\t(spinner) => theme.fg(\"accent\", spinner),\n\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\t`Summarizing branch... (${keyText(\"app.interrupt\")} to cancel)`,\n\t\t);\n\t}\n}\n\nexport class IdleStatus implements Component {\n\tinvalidate(): void {\n\t\t// No cached state to invalidate.\n\t}\n\n\trender(width: number): string[] {\n\t\tconst emptyLine = \" \".repeat(width);\n\t\treturn [emptyLine, emptyLine];\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"thinking-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/thinking-selector.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,SAAS,EACT,KAAK,SAAS,EAMd,UAAU,EAIV,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAoB1D;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,SAAU,YAAW,SAAS;IAC5E,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,oBAAoB,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,iBAAiB,CAAC,CAAiC;IAC3D,OAAO,CAAC,QAAQ,CAAS;IAEzB,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;IAED,YACC,YAAY,EAAE,aAAa,EAC3B,eAAe,EAAE,aAAa,EAAE,EAChC,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,EACxC,QAAQ,EAAE,MAAM,IAAI,EACpB,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,EAClD,oBAAoB,CAAC,EAAE,aAAa,EAoCpC;IAED,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,WAAW;IAUnB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAoBjC;IAED,aAAa,IAAI,UAAU,CAE1B;CACD","sourcesContent":["import {\n\tContainer,\n\ttype Focusable,\n\tfuzzyFilter,\n\tgetKeybindings,\n\tInput,\n\tmatchesKey,\n\ttype SelectItem,\n\tSelectList,\n\ttype SelectListLayoutOptions,\n\tSpacer,\n\tText,\n} from \"@earendil-works/pi-tui\";\nimport type { ThinkingLevel } from \"apex-code-agent-core\";\nimport { getSelectListTheme, theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyDisplayText } from \"./keybinding-hints.ts\";\n\nconst THINKING_SELECT_LIST_LAYOUT: SelectListLayoutOptions = {\n\tminPrimaryColumnWidth: 12,\n\tmaxPrimaryColumnWidth: 32,\n};\n\nconst LEVEL_DESCRIPTIONS: Record<ThinkingLevel, string> = {\n\toff: \"No reasoning\",\n\tminimal: \"Very brief reasoning (~1k tokens)\",\n\tlow: \"Light reasoning (~2k tokens)\",\n\tmedium: \"Moderate reasoning (~8k tokens)\",\n\thigh: \"Deep reasoning (~16k tokens)\",\n\txhigh: \"Extra-high reasoning (~32k tokens)\",\n\tmax: \"Maximum reasoning\",\n};\n\n/**\n * Component that renders a thinking level selector with borders\n */\nexport class ThinkingSelectorComponent extends Container implements Focusable {\n\tprivate searchInput: Input;\n\tprivate selectList: SelectList;\n\tprivate selectListChildIndex: number;\n\tprivate allItems: SelectItem[];\n\tprivate onSelect: (level: ThinkingLevel) => void;\n\tprivate onCancel: () => void;\n\tprivate onSelectAsDefault?: (level: ThinkingLevel) => void;\n\tprivate _focused = false;\n\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\n\tconstructor(\n\t\tcurrentLevel: ThinkingLevel,\n\t\tavailableLevels: ThinkingLevel[],\n\t\tonSelect: (level: ThinkingLevel) => void,\n\t\tonCancel: () => void,\n\t\tonSelectAsDefault?: (level: ThinkingLevel) => void,\n\t\tdefaultThinkingLevel?: ThinkingLevel,\n\t) {\n\t\tsuper();\n\t\tthis.onSelect = onSelect;\n\t\tthis.onCancel = onCancel;\n\t\tthis.onSelectAsDefault = onSelectAsDefault;\n\n\t\tthis.allItems = availableLevels.map((level) => ({\n\t\t\tvalue: level,\n\t\t\tlabel: level,\n\t\t\tdescription:\n\t\t\t\tlevel === defaultThinkingLevel ? `${LEVEL_DESCRIPTIONS[level]} · default` : LEVEL_DESCRIPTIONS[level],\n\t\t}));\n\n\t\t// Add top border\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(\"Thinking Level\", 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(`${keyDisplayText(\"app.thinking.cycle\")} cycles thinking levels in-session`, 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.searchInput = new Input();\n\t\tthis.searchInput.onSubmit = () => this.selectList.handleInput(\"\\r\");\n\t\tthis.addChild(this.searchInput);\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Create selector\n\t\tthis.selectList = this.buildSelectList(this.allItems, currentLevel);\n\t\tthis.selectListChildIndex = this.children.length;\n\t\tthis.addChild(this.selectList);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(theme.fg(\"dim\", \" Enter to select · Ctrl+S to set as default · Esc to cancel\"), 0, 0));\n\n\t\t// Add bottom border\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\tprivate buildSelectList(items: SelectItem[], preselect?: ThinkingLevel): SelectList {\n\t\tconst list = new SelectList(items, Math.max(1, items.length), getSelectListTheme(), THINKING_SELECT_LIST_LAYOUT);\n\t\tconst currentIndex = items.findIndex((item) => item.value === preselect);\n\t\tif (currentIndex !== -1) {\n\t\t\tlist.setSelectedIndex(currentIndex);\n\t\t}\n\t\tlist.onSelect = (item) => this.onSelect(item.value as ThinkingLevel);\n\t\tlist.onCancel = () => this.onCancel();\n\t\treturn list;\n\t}\n\n\tprivate applyFilter(query: string): void {\n\t\tconst filtered = query\n\t\t\t? fuzzyFilter(this.allItems, query, (item) => `${item.label} ${item.description ?? \"\"}`)\n\t\t\t: this.allItems;\n\t\tconst selectedValue = this.selectList.getSelectedItem()?.value as ThinkingLevel | undefined;\n\t\tconst newList = this.buildSelectList(filtered, selectedValue);\n\t\tthis.children[this.selectListChildIndex] = newList;\n\t\tthis.selectList = newList;\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tif (matchesKey(keyData, \"ctrl+s\") && this.onSelectAsDefault) {\n\t\t\tconst item = this.selectList.getSelectedItem();\n\t\t\tif (item) this.onSelectAsDefault(item.value as ThinkingLevel);\n\t\t\treturn;\n\t\t}\n\n\t\tconst kb = getKeybindings();\n\t\tconst isNav =\n\t\t\tkb.matches(keyData, \"tui.select.up\") ||\n\t\t\tkb.matches(keyData, \"tui.select.down\") ||\n\t\t\tkb.matches(keyData, \"tui.select.confirm\") ||\n\t\t\tkb.matches(keyData, \"tui.select.cancel\");\n\t\tif (isNav) {\n\t\t\tthis.selectList.handleInput(keyData);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applyFilter(this.searchInput.getValue());\n\t}\n\n\tgetSelectList(): SelectList {\n\t\treturn this.selectList;\n\t}\n}\n"]}
1
+ {"version":3,"file":"thinking-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/thinking-selector.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,SAAS,EACT,KAAK,SAAS,EAKd,UAAU,EAIV,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAqB1D;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,SAAU,YAAW,SAAS;IAC5E,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,oBAAoB,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,iBAAiB,CAAC,CAAiC;IAC3D,OAAO,CAAC,QAAQ,CAAS;IAEzB,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;IAED,YACC,YAAY,EAAE,aAAa,EAC3B,eAAe,EAAE,aAAa,EAAE,EAChC,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,EACxC,QAAQ,EAAE,MAAM,IAAI,EACpB,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,EAClD,oBAAoB,CAAC,EAAE,aAAa,EA8CpC;IAED,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,WAAW;IAUnB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAoBjC;IAED,aAAa,IAAI,UAAU,CAE1B;CACD","sourcesContent":["import {\n\tContainer,\n\ttype Focusable,\n\tfuzzyFilter,\n\tgetKeybindings,\n\ttype Input,\n\ttype SelectItem,\n\tSelectList,\n\ttype SelectListLayoutOptions,\n\tSpacer,\n\tText,\n} from \"@earendil-works/pi-tui\";\nimport type { ThinkingLevel } from \"apex-code-agent-core\";\nimport { getSelectListTheme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { hintRow, keyDisplayText } from \"./keybinding-hints.ts\";\nimport { PromptInput } from \"./prompt-input.ts\";\n\nconst THINKING_SELECT_LIST_LAYOUT: SelectListLayoutOptions = {\n\tminPrimaryColumnWidth: 12,\n\tmaxPrimaryColumnWidth: 32,\n};\n\nconst LEVEL_DESCRIPTIONS: Record<ThinkingLevel, string> = {\n\toff: \"No reasoning\",\n\tminimal: \"Very brief reasoning (~1k tokens)\",\n\tlow: \"Light reasoning (~2k tokens)\",\n\tmedium: \"Moderate reasoning (~8k tokens)\",\n\thigh: \"Deep reasoning (~16k tokens)\",\n\txhigh: \"Extra-high reasoning (~32k tokens)\",\n\tmax: \"Maximum reasoning\",\n};\n\n/**\n * Component that renders a thinking level selector with borders\n */\nexport class ThinkingSelectorComponent extends Container implements Focusable {\n\tprivate searchInput: Input;\n\tprivate selectList: SelectList;\n\tprivate selectListChildIndex: number;\n\tprivate allItems: SelectItem[];\n\tprivate onSelect: (level: ThinkingLevel) => void;\n\tprivate onCancel: () => void;\n\tprivate onSelectAsDefault?: (level: ThinkingLevel) => void;\n\tprivate _focused = false;\n\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\n\tconstructor(\n\t\tcurrentLevel: ThinkingLevel,\n\t\tavailableLevels: ThinkingLevel[],\n\t\tonSelect: (level: ThinkingLevel) => void,\n\t\tonCancel: () => void,\n\t\tonSelectAsDefault?: (level: ThinkingLevel) => void,\n\t\tdefaultThinkingLevel?: ThinkingLevel,\n\t) {\n\t\tsuper();\n\t\tthis.onSelect = onSelect;\n\t\tthis.onCancel = onCancel;\n\t\tthis.onSelectAsDefault = onSelectAsDefault;\n\n\t\tthis.allItems = availableLevels.map((level) => ({\n\t\t\tvalue: level,\n\t\t\tlabel: `${level === currentLevel ? \"✓ \" : \" \"}${level}`,\n\t\t\tdescription:\n\t\t\t\tlevel === defaultThinkingLevel ? `${LEVEL_DESCRIPTIONS[level]} · default` : LEVEL_DESCRIPTIONS[level],\n\t\t}));\n\n\t\t// Add top border\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(\"Thinking Level\", 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(`${keyDisplayText(\"app.thinking.cycle\")} cycles thinking levels in-session`, 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.searchInput = new PromptInput();\n\t\tthis.searchInput.onSubmit = () => this.selectList.handleInput(\"\\r\");\n\t\tthis.addChild(this.searchInput);\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Create selector\n\t\tthis.selectList = this.buildSelectList(this.allItems, currentLevel);\n\t\tthis.selectListChildIndex = this.children.length;\n\t\tthis.addChild(this.selectList);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\thintRow([\n\t\t\t\t\t[\"tui.select.confirm\", \"select\"],\n\t\t\t\t\t[\"app.thinking.save\", \"set as default\"],\n\t\t\t\t\t[\"tui.select.cancel\", \"close\"],\n\t\t\t\t]),\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\n\t\t// Add bottom border\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\tprivate buildSelectList(items: SelectItem[], preselect?: ThinkingLevel): SelectList {\n\t\tconst list = new SelectList(items, Math.max(1, items.length), getSelectListTheme(), THINKING_SELECT_LIST_LAYOUT);\n\t\tconst currentIndex = items.findIndex((item) => item.value === preselect);\n\t\tif (currentIndex !== -1) {\n\t\t\tlist.setSelectedIndex(currentIndex);\n\t\t}\n\t\tlist.onSelect = (item) => this.onSelect(item.value as ThinkingLevel);\n\t\tlist.onCancel = () => this.onCancel();\n\t\treturn list;\n\t}\n\n\tprivate applyFilter(query: string): void {\n\t\tconst filtered = query\n\t\t\t? fuzzyFilter(this.allItems, query, (item) => `${item.value} ${item.description ?? \"\"}`)\n\t\t\t: this.allItems;\n\t\tconst selectedValue = this.selectList.getSelectedItem()?.value as ThinkingLevel | undefined;\n\t\tconst newList = this.buildSelectList(filtered, selectedValue);\n\t\tthis.children[this.selectListChildIndex] = newList;\n\t\tthis.selectList = newList;\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"app.thinking.save\") && this.onSelectAsDefault) {\n\t\t\tconst item = this.selectList.getSelectedItem();\n\t\t\tif (item) this.onSelectAsDefault(item.value as ThinkingLevel);\n\t\t\treturn;\n\t\t}\n\n\t\tconst isNav =\n\t\t\tkb.matches(keyData, \"tui.select.up\") ||\n\t\t\tkb.matches(keyData, \"tui.select.down\") ||\n\t\t\tkb.matches(keyData, \"tui.select.confirm\") ||\n\t\t\tkb.matches(keyData, \"tui.select.cancel\");\n\t\tif (isNav) {\n\t\t\tthis.selectList.handleInput(keyData);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applyFilter(this.searchInput.getValue());\n\t}\n\n\tgetSelectList(): SelectList {\n\t\treturn this.selectList;\n\t}\n}\n"]}
@@ -1,7 +1,8 @@
1
- import { Container, fuzzyFilter, getKeybindings, Input, matchesKey, SelectList, Spacer, Text, } from "@earendil-works/pi-tui";
2
- import { getSelectListTheme, theme } from "../theme/theme.js";
1
+ import { Container, fuzzyFilter, getKeybindings, SelectList, Spacer, Text, } from "@earendil-works/pi-tui";
2
+ import { getSelectListTheme } from "../theme/theme.js";
3
3
  import { DynamicBorder } from "./dynamic-border.js";
4
- import { keyDisplayText } from "./keybinding-hints.js";
4
+ import { hintRow, keyDisplayText } from "./keybinding-hints.js";
5
+ import { PromptInput } from "./prompt-input.js";
5
6
  const THINKING_SELECT_LIST_LAYOUT = {
6
7
  minPrimaryColumnWidth: 12,
7
8
  maxPrimaryColumnWidth: 32,
@@ -41,7 +42,7 @@ export class ThinkingSelectorComponent extends Container {
41
42
  this.onSelectAsDefault = onSelectAsDefault;
42
43
  this.allItems = availableLevels.map((level) => ({
43
44
  value: level,
44
- label: level,
45
+ label: `${level === currentLevel ? "✓ " : " "}${level}`,
45
46
  description: level === defaultThinkingLevel ? `${LEVEL_DESCRIPTIONS[level]} · default` : LEVEL_DESCRIPTIONS[level],
46
47
  }));
47
48
  // Add top border
@@ -51,7 +52,7 @@ export class ThinkingSelectorComponent extends Container {
51
52
  this.addChild(new Spacer(1));
52
53
  this.addChild(new Text(`${keyDisplayText("app.thinking.cycle")} cycles thinking levels in-session`, 0, 0));
53
54
  this.addChild(new Spacer(1));
54
- this.searchInput = new Input();
55
+ this.searchInput = new PromptInput();
55
56
  this.searchInput.onSubmit = () => this.selectList.handleInput("\r");
56
57
  this.addChild(this.searchInput);
57
58
  this.addChild(new Spacer(1));
@@ -60,7 +61,11 @@ export class ThinkingSelectorComponent extends Container {
60
61
  this.selectListChildIndex = this.children.length;
61
62
  this.addChild(this.selectList);
62
63
  this.addChild(new Spacer(1));
63
- this.addChild(new Text(theme.fg("dim", " Enter to select · Ctrl+S to set as default · Esc to cancel"), 0, 0));
64
+ this.addChild(new Text(hintRow([
65
+ ["tui.select.confirm", "select"],
66
+ ["app.thinking.save", "set as default"],
67
+ ["tui.select.cancel", "close"],
68
+ ]), 0, 0));
64
69
  // Add bottom border
65
70
  this.addChild(new DynamicBorder());
66
71
  }
@@ -76,7 +81,7 @@ export class ThinkingSelectorComponent extends Container {
76
81
  }
77
82
  applyFilter(query) {
78
83
  const filtered = query
79
- ? fuzzyFilter(this.allItems, query, (item) => `${item.label} ${item.description ?? ""}`)
84
+ ? fuzzyFilter(this.allItems, query, (item) => `${item.value} ${item.description ?? ""}`)
80
85
  : this.allItems;
81
86
  const selectedValue = this.selectList.getSelectedItem()?.value;
82
87
  const newList = this.buildSelectList(filtered, selectedValue);
@@ -84,13 +89,13 @@ export class ThinkingSelectorComponent extends Container {
84
89
  this.selectList = newList;
85
90
  }
86
91
  handleInput(keyData) {
87
- if (matchesKey(keyData, "ctrl+s") && this.onSelectAsDefault) {
92
+ const kb = getKeybindings();
93
+ if (kb.matches(keyData, "app.thinking.save") && this.onSelectAsDefault) {
88
94
  const item = this.selectList.getSelectedItem();
89
95
  if (item)
90
96
  this.onSelectAsDefault(item.value);
91
97
  return;
92
98
  }
93
- const kb = getKeybindings();
94
99
  const isNav = kb.matches(keyData, "tui.select.up") ||
95
100
  kb.matches(keyData, "tui.select.down") ||
96
101
  kb.matches(keyData, "tui.select.confirm") ||
@@ -1 +1 @@
1
- {"version":3,"file":"thinking-selector.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/thinking-selector.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tContainer,\n\ttype Focusable,\n\tfuzzyFilter,\n\tgetKeybindings,\n\tInput,\n\tmatchesKey,\n\ttype SelectItem,\n\tSelectList,\n\ttype SelectListLayoutOptions,\n\tSpacer,\n\tText,\n} from \"@earendil-works/pi-tui\";\nimport type { ThinkingLevel } from \"apex-code-agent-core\";\nimport { getSelectListTheme, theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyDisplayText } from \"./keybinding-hints.ts\";\n\nconst THINKING_SELECT_LIST_LAYOUT: SelectListLayoutOptions = {\n\tminPrimaryColumnWidth: 12,\n\tmaxPrimaryColumnWidth: 32,\n};\n\nconst LEVEL_DESCRIPTIONS: Record<ThinkingLevel, string> = {\n\toff: \"No reasoning\",\n\tminimal: \"Very brief reasoning (~1k tokens)\",\n\tlow: \"Light reasoning (~2k tokens)\",\n\tmedium: \"Moderate reasoning (~8k tokens)\",\n\thigh: \"Deep reasoning (~16k tokens)\",\n\txhigh: \"Extra-high reasoning (~32k tokens)\",\n\tmax: \"Maximum reasoning\",\n};\n\n/**\n * Component that renders a thinking level selector with borders\n */\nexport class ThinkingSelectorComponent extends Container implements Focusable {\n\tprivate searchInput: Input;\n\tprivate selectList: SelectList;\n\tprivate selectListChildIndex: number;\n\tprivate allItems: SelectItem[];\n\tprivate onSelect: (level: ThinkingLevel) => void;\n\tprivate onCancel: () => void;\n\tprivate onSelectAsDefault?: (level: ThinkingLevel) => void;\n\tprivate _focused = false;\n\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\n\tconstructor(\n\t\tcurrentLevel: ThinkingLevel,\n\t\tavailableLevels: ThinkingLevel[],\n\t\tonSelect: (level: ThinkingLevel) => void,\n\t\tonCancel: () => void,\n\t\tonSelectAsDefault?: (level: ThinkingLevel) => void,\n\t\tdefaultThinkingLevel?: ThinkingLevel,\n\t) {\n\t\tsuper();\n\t\tthis.onSelect = onSelect;\n\t\tthis.onCancel = onCancel;\n\t\tthis.onSelectAsDefault = onSelectAsDefault;\n\n\t\tthis.allItems = availableLevels.map((level) => ({\n\t\t\tvalue: level,\n\t\t\tlabel: level,\n\t\t\tdescription:\n\t\t\t\tlevel === defaultThinkingLevel ? `${LEVEL_DESCRIPTIONS[level]} · default` : LEVEL_DESCRIPTIONS[level],\n\t\t}));\n\n\t\t// Add top border\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(\"Thinking Level\", 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(`${keyDisplayText(\"app.thinking.cycle\")} cycles thinking levels in-session`, 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.searchInput = new Input();\n\t\tthis.searchInput.onSubmit = () => this.selectList.handleInput(\"\\r\");\n\t\tthis.addChild(this.searchInput);\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Create selector\n\t\tthis.selectList = this.buildSelectList(this.allItems, currentLevel);\n\t\tthis.selectListChildIndex = this.children.length;\n\t\tthis.addChild(this.selectList);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(theme.fg(\"dim\", \" Enter to select · Ctrl+S to set as default · Esc to cancel\"), 0, 0));\n\n\t\t// Add bottom border\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\tprivate buildSelectList(items: SelectItem[], preselect?: ThinkingLevel): SelectList {\n\t\tconst list = new SelectList(items, Math.max(1, items.length), getSelectListTheme(), THINKING_SELECT_LIST_LAYOUT);\n\t\tconst currentIndex = items.findIndex((item) => item.value === preselect);\n\t\tif (currentIndex !== -1) {\n\t\t\tlist.setSelectedIndex(currentIndex);\n\t\t}\n\t\tlist.onSelect = (item) => this.onSelect(item.value as ThinkingLevel);\n\t\tlist.onCancel = () => this.onCancel();\n\t\treturn list;\n\t}\n\n\tprivate applyFilter(query: string): void {\n\t\tconst filtered = query\n\t\t\t? fuzzyFilter(this.allItems, query, (item) => `${item.label} ${item.description ?? \"\"}`)\n\t\t\t: this.allItems;\n\t\tconst selectedValue = this.selectList.getSelectedItem()?.value as ThinkingLevel | undefined;\n\t\tconst newList = this.buildSelectList(filtered, selectedValue);\n\t\tthis.children[this.selectListChildIndex] = newList;\n\t\tthis.selectList = newList;\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tif (matchesKey(keyData, \"ctrl+s\") && this.onSelectAsDefault) {\n\t\t\tconst item = this.selectList.getSelectedItem();\n\t\t\tif (item) this.onSelectAsDefault(item.value as ThinkingLevel);\n\t\t\treturn;\n\t\t}\n\n\t\tconst kb = getKeybindings();\n\t\tconst isNav =\n\t\t\tkb.matches(keyData, \"tui.select.up\") ||\n\t\t\tkb.matches(keyData, \"tui.select.down\") ||\n\t\t\tkb.matches(keyData, \"tui.select.confirm\") ||\n\t\t\tkb.matches(keyData, \"tui.select.cancel\");\n\t\tif (isNav) {\n\t\t\tthis.selectList.handleInput(keyData);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applyFilter(this.searchInput.getValue());\n\t}\n\n\tgetSelectList(): SelectList {\n\t\treturn this.selectList;\n\t}\n}\n"]}
1
+ {"version":3,"file":"thinking-selector.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/thinking-selector.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tContainer,\n\ttype Focusable,\n\tfuzzyFilter,\n\tgetKeybindings,\n\ttype Input,\n\ttype SelectItem,\n\tSelectList,\n\ttype SelectListLayoutOptions,\n\tSpacer,\n\tText,\n} from \"@earendil-works/pi-tui\";\nimport type { ThinkingLevel } from \"apex-code-agent-core\";\nimport { getSelectListTheme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { hintRow, keyDisplayText } from \"./keybinding-hints.ts\";\nimport { PromptInput } from \"./prompt-input.ts\";\n\nconst THINKING_SELECT_LIST_LAYOUT: SelectListLayoutOptions = {\n\tminPrimaryColumnWidth: 12,\n\tmaxPrimaryColumnWidth: 32,\n};\n\nconst LEVEL_DESCRIPTIONS: Record<ThinkingLevel, string> = {\n\toff: \"No reasoning\",\n\tminimal: \"Very brief reasoning (~1k tokens)\",\n\tlow: \"Light reasoning (~2k tokens)\",\n\tmedium: \"Moderate reasoning (~8k tokens)\",\n\thigh: \"Deep reasoning (~16k tokens)\",\n\txhigh: \"Extra-high reasoning (~32k tokens)\",\n\tmax: \"Maximum reasoning\",\n};\n\n/**\n * Component that renders a thinking level selector with borders\n */\nexport class ThinkingSelectorComponent extends Container implements Focusable {\n\tprivate searchInput: Input;\n\tprivate selectList: SelectList;\n\tprivate selectListChildIndex: number;\n\tprivate allItems: SelectItem[];\n\tprivate onSelect: (level: ThinkingLevel) => void;\n\tprivate onCancel: () => void;\n\tprivate onSelectAsDefault?: (level: ThinkingLevel) => void;\n\tprivate _focused = false;\n\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\n\tconstructor(\n\t\tcurrentLevel: ThinkingLevel,\n\t\tavailableLevels: ThinkingLevel[],\n\t\tonSelect: (level: ThinkingLevel) => void,\n\t\tonCancel: () => void,\n\t\tonSelectAsDefault?: (level: ThinkingLevel) => void,\n\t\tdefaultThinkingLevel?: ThinkingLevel,\n\t) {\n\t\tsuper();\n\t\tthis.onSelect = onSelect;\n\t\tthis.onCancel = onCancel;\n\t\tthis.onSelectAsDefault = onSelectAsDefault;\n\n\t\tthis.allItems = availableLevels.map((level) => ({\n\t\t\tvalue: level,\n\t\t\tlabel: `${level === currentLevel ? \"✓ \" : \" \"}${level}`,\n\t\t\tdescription:\n\t\t\t\tlevel === defaultThinkingLevel ? `${LEVEL_DESCRIPTIONS[level]} · default` : LEVEL_DESCRIPTIONS[level],\n\t\t}));\n\n\t\t// Add top border\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(\"Thinking Level\", 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(`${keyDisplayText(\"app.thinking.cycle\")} cycles thinking levels in-session`, 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.searchInput = new PromptInput();\n\t\tthis.searchInput.onSubmit = () => this.selectList.handleInput(\"\\r\");\n\t\tthis.addChild(this.searchInput);\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Create selector\n\t\tthis.selectList = this.buildSelectList(this.allItems, currentLevel);\n\t\tthis.selectListChildIndex = this.children.length;\n\t\tthis.addChild(this.selectList);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\thintRow([\n\t\t\t\t\t[\"tui.select.confirm\", \"select\"],\n\t\t\t\t\t[\"app.thinking.save\", \"set as default\"],\n\t\t\t\t\t[\"tui.select.cancel\", \"close\"],\n\t\t\t\t]),\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\n\t\t// Add bottom border\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\tprivate buildSelectList(items: SelectItem[], preselect?: ThinkingLevel): SelectList {\n\t\tconst list = new SelectList(items, Math.max(1, items.length), getSelectListTheme(), THINKING_SELECT_LIST_LAYOUT);\n\t\tconst currentIndex = items.findIndex((item) => item.value === preselect);\n\t\tif (currentIndex !== -1) {\n\t\t\tlist.setSelectedIndex(currentIndex);\n\t\t}\n\t\tlist.onSelect = (item) => this.onSelect(item.value as ThinkingLevel);\n\t\tlist.onCancel = () => this.onCancel();\n\t\treturn list;\n\t}\n\n\tprivate applyFilter(query: string): void {\n\t\tconst filtered = query\n\t\t\t? fuzzyFilter(this.allItems, query, (item) => `${item.value} ${item.description ?? \"\"}`)\n\t\t\t: this.allItems;\n\t\tconst selectedValue = this.selectList.getSelectedItem()?.value as ThinkingLevel | undefined;\n\t\tconst newList = this.buildSelectList(filtered, selectedValue);\n\t\tthis.children[this.selectListChildIndex] = newList;\n\t\tthis.selectList = newList;\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"app.thinking.save\") && this.onSelectAsDefault) {\n\t\t\tconst item = this.selectList.getSelectedItem();\n\t\t\tif (item) this.onSelectAsDefault(item.value as ThinkingLevel);\n\t\t\treturn;\n\t\t}\n\n\t\tconst isNav =\n\t\t\tkb.matches(keyData, \"tui.select.up\") ||\n\t\t\tkb.matches(keyData, \"tui.select.down\") ||\n\t\t\tkb.matches(keyData, \"tui.select.confirm\") ||\n\t\t\tkb.matches(keyData, \"tui.select.cancel\");\n\t\tif (isNav) {\n\t\t\tthis.selectList.handleInput(keyData);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applyFilter(this.searchInput.getValue());\n\t}\n\n\tgetSelectList(): SelectList {\n\t\treturn this.selectList;\n\t}\n}\n"]}
@@ -1,15 +1,30 @@
1
- import { Container, type TUI } from "@earendil-works/pi-tui";
2
- import type { ToolDefinition } from "../../../core/extensions/types.ts";
3
- import type { ApexToolDefinition } from "../../../core/tools/contract.ts";
1
+ import { type Component, Container, type TUI, type TuiMouseEvent } from "@earendil-works/pi-tui";
2
+ import type { AgentToolResult } from "apex-code-agent-core";
3
+ import type { ToolDefinition, ToolRenderContext, ToolRenderResultOptions } from "../../../core/extensions/types.ts";
4
+ import type { Theme } from "../theme/theme.ts";
5
+ /**
6
+ * What this component needs from a tool: how to draw it. It neither executes tools nor reads their
7
+ * parameter schemas, so a definition and a bare renderer pair are equally acceptable.
8
+ *
9
+ * The renderer parameters are `any` on purpose: a `ToolDefinition` types them from its schema, and
10
+ * narrowing them here would make those definitions unassignable.
11
+ */
12
+ export interface ToolRenderers {
13
+ renderShell?: "default" | "self";
14
+ renderCall?: (args: any, theme: Theme, context: ToolRenderContext<any, any>) => Component;
15
+ renderResult?: (result: AgentToolResult<any>, options: ToolRenderResultOptions, theme: Theme, context: ToolRenderContext<any, any>) => Component;
16
+ }
4
17
  import { type ToolSymbolPreset } from "./tool-panel.ts";
5
18
  export interface ToolExecutionOptions {
6
19
  showImages?: boolean;
7
20
  imageWidthCells?: number;
8
21
  symbolPreset?: ToolSymbolPreset;
9
22
  }
23
+ /** The phrase every expand affordance ends with, here and in each tool's own renderer. */
10
24
  export declare class ToolExecutionComponent extends Container {
11
25
  private contentBox;
12
26
  private contentText;
27
+ private contentTextRegion;
13
28
  private selfRenderContainer;
14
29
  private callRendererComponent?;
15
30
  private resultRendererComponent?;
@@ -25,7 +40,6 @@ export declare class ToolExecutionComponent extends Container {
25
40
  private imageWidthCells;
26
41
  private isPartial;
27
42
  private toolDefinition?;
28
- private builtInToolDefinition?;
29
43
  private ui;
30
44
  private cwd;
31
45
  private executionStarted;
@@ -35,12 +49,11 @@ export declare class ToolExecutionComponent extends Container {
35
49
  private argsComplete;
36
50
  private symbolPreset;
37
51
  private displayVersion;
38
- private fallbackHidNothing;
39
52
  private cachedRender?;
40
53
  private result?;
41
54
  private convertedImages;
42
55
  private hideComponent;
43
- constructor(toolName: string, toolCallId: string, args: any, options: ToolExecutionOptions | undefined, toolDefinition: ToolDefinition<any, any> | ApexToolDefinition<any, any> | undefined, ui: TUI, cwd: string);
56
+ constructor(toolName: string, toolCallId: string, args: any, options: ToolExecutionOptions | undefined, toolDefinition: ToolRenderers | ToolDefinition<any, any, any> | undefined, ui: TUI, cwd: string);
44
57
  private getCallRenderer;
45
58
  private getResultRenderer;
46
59
  private hasRendererDefinition;
@@ -48,6 +61,7 @@ export declare class ToolExecutionComponent extends Container {
48
61
  private getRenderContext;
49
62
  private createCallFallback;
50
63
  private createResultFallback;
64
+ private createResultRegion;
51
65
  updateArgs(args: any): void;
52
66
  markExecutionStarted(): void;
53
67
  setArgsComplete(): void;
@@ -74,16 +88,6 @@ export declare class ToolExecutionComponent extends Container {
74
88
  private getDurationMs;
75
89
  private renderWithStatus;
76
90
  private renderCollapsedError;
77
- /**
78
- * The affordance for a renderer that hides its body and says nothing itself.
79
- *
80
- * Every truncating renderer prints its own counted hint (`read.ts:196`,
81
- * `bash.ts:479`, `grep.ts:116`, `find.ts:111`, `ls.ts:90`, `write.ts:194`, and
82
- * the fallback below), which says more than this one does. Adding a second was
83
- * telling the reader less, twice. `read` is the case that still needs this: it
84
- * returns an empty body while collapsed and announces nothing.
85
- */
86
- private renderDisclosureHint;
87
91
  render(width: number): string[];
88
92
  /**
89
93
  * Cache key for the composed lines. Every state change funnels through
@@ -95,6 +99,14 @@ export declare class ToolExecutionComponent extends Container {
95
99
  */
96
100
  private renderCacheKey;
97
101
  private compose;
102
+ /**
103
+ * A left click on the panel toggles the result, as upstream's per-region
104
+ * handlers do. Apex composes the panel itself (lifecycle header, spine,
105
+ * padding, the separator row it inserts), so rendered rows do not line up
106
+ * with the children's rows and the inherited child-by-child dispatch would
107
+ * resolve the wrong region. Row 0 is the leading spacer and is inert.
108
+ */
109
+ handleMouse(event: TuiMouseEvent): ReturnType<Container["handleMouse"]>;
98
110
  private updateDisplay;
99
111
  private getTextOutput;
100
112
  private formatToolExecution;
@@ -1 +1 @@
1
- {"version":3,"file":"tool-execution.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-execution.ts"],"names":[],"mappings":"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","sourcesContent":["import { Box, type Component, Container, getCapabilities, Image, Spacer, Text, type TUI } from \"@earendil-works/pi-tui\";\nimport type { ToolDefinition, ToolRenderContext } from \"../../../core/extensions/types.ts\";\nimport type { ApexToolDefinition } from \"../../../core/tools/contract.ts\";\nimport { createAllToolDefinitions, type ToolName } from \"../../../core/tools/index.ts\";\nimport { getTextOutput as getRenderedTextOutput } from \"../../../core/tools/render-utils.ts\";\nimport { convertToPng } from \"../../../utils/image-convert.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { keyHint } from \"./keybinding-hints.ts\";\nimport {\n\ttype ToolLifecycle,\n\tToolPanelComponent,\n\tToolStatusLineComponent,\n\ttype ToolSymbolPreset,\n} from \"./tool-panel.ts\";\n\nconst COLLAPSED_ERROR_VISUAL_LINE_LIMIT = 3;\n\nconst FALLBACK_PREVIEW_LINES = 10;\n\nexport interface ToolExecutionOptions {\n\tshowImages?: boolean;\n\timageWidthCells?: number;\n\tsymbolPreset?: ToolSymbolPreset;\n}\n\n/** The phrase every expand affordance ends with, here and in each tool's own renderer. */\nconst EXPAND_HINT_LABEL = \"to expand\";\n\nexport class ToolExecutionComponent extends Container {\n\tprivate contentBox: Box;\n\tprivate contentText: Text;\n\tprivate selfRenderContainer: Container;\n\tprivate callRendererComponent?: Component;\n\tprivate resultRendererComponent?: Component;\n\tprivate rendererState: any = {};\n\tprivate imageComponents: Image[] = [];\n\tprivate imageSpacers: Spacer[] = [];\n\tprivate toolName: string;\n\tprivate toolCallId: string;\n\tprivate args: any;\n\tprivate expanded = false;\n\tprivate editDiffsExpanded = true;\n\tprivate showImages: boolean;\n\tprivate imageWidthCells: number;\n\tprivate isPartial = true;\n\tprivate toolDefinition?: ToolDefinition<any, any> | ApexToolDefinition<any, any>;\n\tprivate builtInToolDefinition?: ToolDefinition<any, any> | ApexToolDefinition<any, any>;\n\tprivate ui: TUI;\n\tprivate cwd: string;\n\tprivate executionStarted = false;\n\tprivate executionStartedAt?: number;\n\tprivate executionEndedAt?: number;\n\tprivate elapsedTimer?: ReturnType<typeof setInterval>;\n\tprivate argsComplete = false;\n\tprivate symbolPreset: ToolSymbolPreset;\n\t// Composed-line cache. Recomposing the panel (ANSI-aware truncation, width\n\t// measurement, background paint per content line) on every frame made\n\t// per-frame cost grow with the number of tools on screen; see\n\t// test/tool-execution-render-cache.test.ts.\n\tprivate displayVersion = 0;\n\tprivate fallbackHidNothing = false;\n\tprivate cachedRender?: { key: string; width: number; lines: string[] };\n\tprivate result?: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tisError: boolean;\n\t\tdetails?: any;\n\t};\n\tprivate convertedImages: Map<number, { data: string; mimeType: string }> = new Map();\n\tprivate hideComponent = false;\n\n\tconstructor(\n\t\ttoolName: string,\n\t\ttoolCallId: string,\n\t\targs: any,\n\t\toptions: ToolExecutionOptions = {},\n\t\ttoolDefinition: ToolDefinition<any, any> | ApexToolDefinition<any, any> | undefined,\n\t\tui: TUI,\n\t\tcwd: string,\n\t) {\n\t\tsuper();\n\t\tthis.toolName = toolName;\n\t\tthis.toolCallId = toolCallId;\n\t\tthis.args = args;\n\t\tthis.toolDefinition = toolDefinition;\n\t\tthis.builtInToolDefinition = createAllToolDefinitions(cwd)[toolName as ToolName];\n\t\tthis.showImages = options.showImages ?? true;\n\t\tthis.imageWidthCells = options.imageWidthCells ?? 60;\n\t\tthis.symbolPreset = options.symbolPreset ?? \"unicode\";\n\t\tthis.ui = ui;\n\t\tthis.cwd = cwd;\n\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Always create all shell variants. contentBox is used for default renderer-based composition.\n\t\t// selfRenderContainer is used when the tool renders its own framing.\n\t\t// contentText is reserved for generic fallback rendering when no tool definition exists.\n\t\tthis.contentBox = new Box(0, 0);\n\t\tthis.contentText = new Text(\"\", 0, 0);\n\t\tthis.selfRenderContainer = new Container();\n\n\t\tif (this.hasRendererDefinition()) {\n\t\t\tthis.addChild(this.getRenderShell() === \"self\" ? this.selfRenderContainer : this.contentBox);\n\t\t} else {\n\t\t\tthis.addChild(this.contentText);\n\t\t}\n\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate getCallRenderer(): ToolDefinition<any, any>[\"renderCall\"] | undefined {\n\t\tif (!this.builtInToolDefinition) {\n\t\t\treturn this.toolDefinition?.renderCall;\n\t\t}\n\t\tif (!this.toolDefinition) {\n\t\t\treturn this.builtInToolDefinition.renderCall;\n\t\t}\n\t\treturn this.toolDefinition.renderCall ?? this.builtInToolDefinition.renderCall;\n\t}\n\n\tprivate getResultRenderer(): ToolDefinition<any, any>[\"renderResult\"] | undefined {\n\t\tif (!this.builtInToolDefinition) {\n\t\t\treturn this.toolDefinition?.renderResult;\n\t\t}\n\t\tif (!this.toolDefinition) {\n\t\t\treturn this.builtInToolDefinition.renderResult;\n\t\t}\n\t\treturn this.toolDefinition.renderResult ?? this.builtInToolDefinition.renderResult;\n\t}\n\n\tprivate hasRendererDefinition(): boolean {\n\t\treturn this.builtInToolDefinition !== undefined || this.toolDefinition !== undefined;\n\t}\n\n\tprivate getRenderShell(): \"default\" | \"self\" {\n\t\tif (!this.builtInToolDefinition) {\n\t\t\treturn this.toolDefinition?.renderShell ?? \"default\";\n\t\t}\n\t\tif (!this.toolDefinition) {\n\t\t\treturn this.builtInToolDefinition.renderShell ?? \"default\";\n\t\t}\n\t\treturn this.toolDefinition.renderShell ?? this.builtInToolDefinition.renderShell ?? \"default\";\n\t}\n\n\tprivate getRenderContext(lastComponent: Component | undefined): ToolRenderContext {\n\t\treturn {\n\t\t\targs: this.args,\n\t\t\ttoolCallId: this.toolCallId,\n\t\t\tinvalidate: () => {\n\t\t\t\tthis.invalidate();\n\t\t\t\tthis.ui.requestRender();\n\t\t\t},\n\t\t\tlastComponent,\n\t\t\tstate: this.rendererState,\n\t\t\tcwd: this.cwd,\n\t\t\texecutionStarted: this.executionStarted,\n\t\t\targsComplete: this.argsComplete,\n\t\t\tisPartial: this.isPartial,\n\t\t\texpanded: this.expanded,\n\t\t\teditDiffsExpanded: this.editDiffsExpanded,\n\t\t\tshowImages: this.showImages,\n\t\t\tisError: this.result?.isError ?? false,\n\t\t};\n\t}\n\n\tprivate createCallFallback(): Component {\n\t\treturn new Text(theme.fg(\"toolTitle\", theme.bold(this.toolName)), 0, 0);\n\t}\n\n\tprivate createResultFallback(): Component | undefined {\n\t\tconst output = this.getTextOutput();\n\t\tif (!output) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst displayLines = this.expanded ? lines : lines.slice(0, FALLBACK_PREVIEW_LINES);\n\t\tconst remaining = lines.length - displayLines.length;\n\t\t// The one path that composes the body itself, so the one path that can say\n\t\t// for certain that expanding would reveal nothing.\n\t\tthis.fallbackHidNothing = remaining === 0;\n\t\tlet text = displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", EXPAND_HINT_LABEL)}${theme.fg(\"muted\", \")\")}`;\n\t\t}\n\t\treturn new Text(text, 0, 0);\n\t}\n\n\tupdateArgs(args: any): void {\n\t\tthis.args = args;\n\t\tthis.updateDisplay();\n\t}\n\n\tmarkExecutionStarted(): void {\n\t\tthis.executionStarted = true;\n\t\tthis.executionStartedAt ??= Date.now();\n\t\tthis.startElapsedTimer();\n\t\tthis.updateDisplay();\n\t\tthis.ui.requestRender();\n\t}\n\n\tsetArgsComplete(): void {\n\t\tthis.argsComplete = true;\n\t\tthis.updateDisplay();\n\t\tthis.ui.requestRender();\n\t}\n\n\tupdateResult(\n\t\tresult: {\n\t\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\t\tdetails?: any;\n\t\t\tisError: boolean;\n\t\t},\n\t\tisPartial = false,\n\t): void {\n\t\tthis.result = result;\n\t\tthis.isPartial = isPartial;\n\t\tif (!isPartial) {\n\t\t\tthis.executionEndedAt ??= Date.now();\n\t\t\tthis.stopElapsedTimer();\n\t\t}\n\t\tthis.updateDisplay();\n\t\tthis.maybeConvertImagesForKitty();\n\t}\n\n\tdispose(): void {\n\t\tthis.stopElapsedTimer();\n\t\tthis.cachedRender = undefined;\n\t}\n\n\tprivate startElapsedTimer(): void {\n\t\tif (this.elapsedTimer) return;\n\t\tthis.elapsedTimer = setInterval(() => this.ui.requestRender(), 1000);\n\t}\n\n\tprivate stopElapsedTimer(): void {\n\t\tif (!this.elapsedTimer) return;\n\t\tclearInterval(this.elapsedTimer);\n\t\tthis.elapsedTimer = undefined;\n\t}\n\n\tprivate maybeConvertImagesForKitty(): void {\n\t\tconst caps = getCapabilities();\n\t\tif (caps.images !== \"kitty\") return;\n\t\tif (!this.result) return;\n\n\t\tconst imageBlocks = this.result.content.filter((c) => c.type === \"image\");\n\t\tfor (let i = 0; i < imageBlocks.length; i++) {\n\t\t\tconst img = imageBlocks[i];\n\t\t\tif (!img.data || !img.mimeType) continue;\n\t\t\tif (img.mimeType === \"image/png\") continue;\n\t\t\tif (this.convertedImages.has(i)) continue;\n\n\t\t\tconst index = i;\n\t\t\tconvertToPng(img.data, img.mimeType).then((converted) => {\n\t\t\t\tif (converted) {\n\t\t\t\t\tthis.convertedImages.set(index, converted);\n\t\t\t\t\tthis.updateDisplay();\n\t\t\t\t\tthis.ui.requestRender();\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tsetEditDiffsExpanded(expanded: boolean): void {\n\t\tif (this.editDiffsExpanded === expanded) return;\n\t\tthis.editDiffsExpanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetShowImages(show: boolean): void {\n\t\tthis.showImages = show;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetImageWidthCells(width: number): void {\n\t\tthis.imageWidthCells = Math.max(1, Math.floor(width));\n\t\tthis.updateDisplay();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate getLifecycle(): ToolLifecycle {\n\t\tif (this.result && !this.isPartial) return this.result.isError ? \"error\" : \"done\";\n\t\treturn this.executionStarted ? \"running\" : \"queued\";\n\t}\n\n\tprivate getDurationMs(): number | undefined {\n\t\tif (this.executionStartedAt === undefined) return undefined;\n\t\treturn (this.executionEndedAt ?? Date.now()) - this.executionStartedAt;\n\t}\n\n\tprivate renderWithStatus(component: Component, width: number): string[] {\n\t\tconst options = {\n\t\t\tlifecycle: this.getLifecycle(),\n\t\t\tsymbolPreset: this.symbolPreset,\n\t\t\tdurationMs: this.getDurationMs(),\n\t\t};\n\t\tif (this.hasRendererDefinition() && this.getRenderShell() === \"self\") {\n\t\t\treturn new ToolStatusLineComponent(component, options).render(width);\n\t\t}\n\t\treturn new ToolPanelComponent(component, options).render(width);\n\t}\n\n\tprivate renderCollapsedError(contentLines: string[], width: number): string[] {\n\t\tconst errorText = this.getTextOutput();\n\t\tif (!errorText || contentLines.length === 0) return contentLines;\n\n\t\tconst errorLines = new Text(theme.fg(\"toolOutput\", errorText), 0, 0).render(width);\n\t\tconst previewLines = errorLines.slice(0, COLLAPSED_ERROR_VISUAL_LINE_LIMIT);\n\t\tconst omittedLines = errorLines.length - previewLines.length;\n\t\tif (omittedLines === 0) return [...contentLines.slice(0, 1), ...previewLines];\n\n\t\tconst omission =\n\t\t\ttheme.fg(\"muted\", `${omittedLines} more lines omitted, `) + keyHint(\"app.tools.expand\", EXPAND_HINT_LABEL);\n\t\treturn [...contentLines.slice(0, 1), ...previewLines, omission];\n\t}\n\n\t/**\n\t * The affordance for a renderer that hides its body and says nothing itself.\n\t *\n\t * Every truncating renderer prints its own counted hint (`read.ts:196`,\n\t * `bash.ts:479`, `grep.ts:116`, `find.ts:111`, `ls.ts:90`, `write.ts:194`, and\n\t * the fallback below), which says more than this one does. Adding a second was\n\t * telling the reader less, twice. `read` is the case that still needs this: it\n\t * returns an empty body while collapsed and announces nothing.\n\t */\n\tprivate renderDisclosureHint(width: number, contentLines: string[]): string[] {\n\t\tif (this.expanded || !this.result || this.isPartial || width <= 0) return [];\n\t\tif (this.fallbackHidNothing) return [];\n\t\t// Matching the shared phrase rather than the key text, because the key text is\n\t\t// empty until keybindings are installed and an unbound session would otherwise\n\t\t// get the duplicate back.\n\t\tif (contentLines.some((line) => line.includes(EXPAND_HINT_LABEL))) return [];\n\t\treturn new Text(keyHint(\"app.tools.expand\", EXPAND_HINT_LABEL), 0, 0).render(width);\n\t}\n\n\toverride render(width: number): string[] {\n\t\tif (this.hideComponent || width <= 0) return [];\n\t\tconst key = this.renderCacheKey();\n\t\tconst cached = this.cachedRender;\n\t\tif (cached && cached.key === key && cached.width === width) return cached.lines;\n\t\tconst lines = this.compose(width);\n\t\tthis.cachedRender = { key, width, lines };\n\t\treturn lines;\n\t}\n\n\t/**\n\t * Cache key for the composed lines. Every state change funnels through\n\t * updateDisplay(), which bumps displayVersion; the elapsed readout is the\n\t * one input that advances without a state change, so it is bucketed at\n\t * 250 ms while running (matching the 1 s elapsed timer's cadence closely\n\t * enough that the readout never looks stale, while bounding recomposition\n\t * to at most four per second for the one running tool).\n\t */\n\tprivate renderCacheKey(): string {\n\t\tconst lifecycle = this.getLifecycle();\n\t\tconst durationMs = this.getDurationMs();\n\t\tconst durationKey = lifecycle === \"running\" ? Math.floor((durationMs ?? 0) / 250) : (durationMs ?? -1);\n\t\treturn `${this.displayVersion}:${lifecycle}:${durationKey}`;\n\t}\n\n\tprivate compose(width: number): string[] {\n\t\tconst shell = this.hasRendererDefinition()\n\t\t\t? this.getRenderShell() === \"self\"\n\t\t\t\t? this.selfRenderContainer\n\t\t\t\t: this.contentBox\n\t\t\t: this.contentText;\n\t\tconst selfRendered = this.hasRendererDefinition() && this.getRenderShell() === \"self\";\n\t\tconst panelContent: Component = selfRendered\n\t\t\t? shell\n\t\t\t: {\n\t\t\t\t\trender: (innerWidth: number) => {\n\t\t\t\t\t\tconst contentLines = shell.render(innerWidth);\n\t\t\t\t\t\tconst visibleLines =\n\t\t\t\t\t\t\tthis.result?.isError && !this.isPartial && !this.expanded\n\t\t\t\t\t\t\t\t? this.renderCollapsedError(contentLines, innerWidth)\n\t\t\t\t\t\t\t\t: contentLines;\n\t\t\t\t\t\treturn [...visibleLines, ...this.renderDisclosureHint(innerWidth, visibleLines)];\n\t\t\t\t\t},\n\t\t\t\t\tinvalidate: () => shell.invalidate?.(),\n\t\t\t\t};\n\t\tconst visibleContentLines = this.renderWithStatus(panelContent, width);\n\t\tif (visibleContentLines.length === 0 && this.imageComponents.length === 0) return [];\n\n\t\tconst lines: string[] = [];\n\t\tif (visibleContentLines.length > 0) {\n\t\t\tlines.push(\"\");\n\t\t\tlines.push(...visibleContentLines);\n\t\t\tif (selfRendered) lines.push(...this.renderDisclosureHint(width, visibleContentLines));\n\t\t}\n\t\tfor (let i = 0; i < this.imageComponents.length; i++) {\n\t\t\tconst spacer = this.imageSpacers[i];\n\t\t\tif (spacer) lines.push(...spacer.render(width));\n\t\t\tconst imageComponent = this.imageComponents[i];\n\t\t\tif (imageComponent) lines.push(...imageComponent.render(width));\n\t\t}\n\t\treturn lines;\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tthis.displayVersion += 1;\n\t\tthis.fallbackHidNothing = false;\n\t\tlet hasContent = false;\n\t\tthis.hideComponent = false;\n\t\tif (this.hasRendererDefinition()) {\n\t\t\tconst renderContainer = this.getRenderShell() === \"self\" ? this.selfRenderContainer : this.contentBox;\n\t\t\trenderContainer.clear();\n\n\t\t\tconst callRenderer = this.getCallRenderer();\n\t\t\tif (!callRenderer) {\n\t\t\t\trenderContainer.addChild(this.createCallFallback());\n\t\t\t\thasContent = true;\n\t\t\t} else {\n\t\t\t\ttry {\n\t\t\t\t\tconst component = callRenderer(this.args, theme, this.getRenderContext(this.callRendererComponent));\n\t\t\t\t\tthis.callRendererComponent = component;\n\t\t\t\t\trenderContainer.addChild(component);\n\t\t\t\t\thasContent = true;\n\t\t\t\t} catch {\n\t\t\t\t\tthis.callRendererComponent = undefined;\n\t\t\t\t\trenderContainer.addChild(this.createCallFallback());\n\t\t\t\t\thasContent = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst resultRenderer = this.getResultRenderer();\n\t\t\t\tif (!resultRenderer) {\n\t\t\t\t\tconst component = this.createResultFallback();\n\t\t\t\t\tif (component) {\n\t\t\t\t\t\trenderContainer.addChild(component);\n\t\t\t\t\t\thasContent = true;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst component = resultRenderer(\n\t\t\t\t\t\t\t{ content: this.result.content as any, details: this.result.details },\n\t\t\t\t\t\t\t{ expanded: this.expanded, isPartial: this.isPartial },\n\t\t\t\t\t\t\ttheme,\n\t\t\t\t\t\t\tthis.getRenderContext(this.resultRendererComponent),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tthis.resultRendererComponent = component;\n\t\t\t\t\t\trenderContainer.addChild(component);\n\t\t\t\t\t\thasContent = true;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tthis.resultRendererComponent = undefined;\n\t\t\t\t\t\tconst component = this.createResultFallback();\n\t\t\t\t\t\tif (component) {\n\t\t\t\t\t\t\trenderContainer.addChild(component);\n\t\t\t\t\t\t\thasContent = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthis.contentText.setText(this.formatToolExecution());\n\t\t\thasContent = true;\n\t\t}\n\n\t\tfor (const img of this.imageComponents) {\n\t\t\tthis.removeChild(img);\n\t\t}\n\t\tthis.imageComponents = [];\n\t\tfor (const spacer of this.imageSpacers) {\n\t\t\tthis.removeChild(spacer);\n\t\t}\n\t\tthis.imageSpacers = [];\n\n\t\tif (this.result) {\n\t\t\tconst imageBlocks = this.result.content.filter((c) => c.type === \"image\");\n\t\t\tconst caps = getCapabilities();\n\t\t\tfor (let i = 0; i < imageBlocks.length; i++) {\n\t\t\t\tconst img = imageBlocks[i];\n\t\t\t\tif (caps.images && this.showImages && img.data && img.mimeType) {\n\t\t\t\t\tconst converted = this.convertedImages.get(i);\n\t\t\t\t\tconst imageData = converted?.data ?? img.data;\n\t\t\t\t\tconst imageMimeType = converted?.mimeType ?? img.mimeType;\n\t\t\t\t\tif (caps.images === \"kitty\" && imageMimeType !== \"image/png\") continue;\n\n\t\t\t\t\tconst spacer = new Spacer(1);\n\t\t\t\t\tthis.addChild(spacer);\n\t\t\t\t\tthis.imageSpacers.push(spacer);\n\t\t\t\t\tconst imageComponent = new Image(\n\t\t\t\t\t\timageData,\n\t\t\t\t\t\timageMimeType,\n\t\t\t\t\t\t{ fallbackColor: (s: string) => theme.fg(\"toolOutput\", s) },\n\t\t\t\t\t\t{ maxWidthCells: this.imageWidthCells },\n\t\t\t\t\t);\n\t\t\t\t\tthis.imageComponents.push(imageComponent);\n\t\t\t\t\tthis.addChild(imageComponent);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (this.hasRendererDefinition() && !hasContent && this.imageComponents.length === 0) {\n\t\t\tthis.hideComponent = true;\n\t\t}\n\t}\n\n\tprivate getTextOutput(): string {\n\t\treturn getRenderedTextOutput(this.result, this.showImages);\n\t}\n\n\tprivate formatToolExecution(): string {\n\t\tlet text = theme.fg(\"toolTitle\", theme.bold(this.toolName));\n\t\tconst content = JSON.stringify(this.args, null, 2);\n\t\tif (content) {\n\t\t\ttext += `\\n\\n${content}`;\n\t\t}\n\t\tconst output = this.getTextOutput();\n\t\tif (output) {\n\t\t\ttext += `\\n${output}`;\n\t\t}\n\t\treturn text;\n\t}\n}\n"]}
1
+ {"version":3,"file":"tool-execution.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-execution.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tBox,\n\ttype Component,\n\tContainer,\n\tgetCapabilities,\n\tImage,\n\tMouseRegion,\n\tSpacer,\n\tText,\n\ttype TUI,\n\ttype TuiMouseEvent,\n} from \"@earendil-works/pi-tui\";\nimport type { AgentToolResult } from \"apex-code-agent-core\";\nimport type { ToolDefinition, ToolRenderContext, ToolRenderResultOptions } from \"../../../core/extensions/types.ts\";\nimport type { Theme } from \"../theme/theme.ts\";\n\n/**\n * What this component needs from a tool: how to draw it. It neither executes tools nor reads their\n * parameter schemas, so a definition and a bare renderer pair are equally acceptable.\n *\n * The renderer parameters are `any` on purpose: a `ToolDefinition` types them from its schema, and\n * narrowing them here would make those definitions unassignable.\n */\nexport interface ToolRenderers {\n\trenderShell?: \"default\" | \"self\";\n\trenderCall?: (args: any, theme: Theme, context: ToolRenderContext<any, any>) => Component;\n\trenderResult?: (\n\t\tresult: AgentToolResult<any>,\n\t\toptions: ToolRenderResultOptions,\n\t\ttheme: Theme,\n\t\tcontext: ToolRenderContext<any, any>,\n\t) => Component;\n}\n\nimport { getTextOutput as getRenderedTextOutput } from \"../../../core/tools/render-utils.ts\";\nimport { convertToPng } from \"../../../utils/image-convert.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { formatHiddenLines, previewLineCount } from \"./keybinding-hints.ts\";\nimport {\n\ttype ToolLifecycle,\n\tToolPanelComponent,\n\tToolStatusLineComponent,\n\ttype ToolSymbolPreset,\n} from \"./tool-panel.ts\";\n\nconst COLLAPSED_ERROR_VISUAL_LINE_LIMIT = 3;\n\nconst FALLBACK_PREVIEW_LINES = 10;\n\nexport interface ToolExecutionOptions {\n\tshowImages?: boolean;\n\timageWidthCells?: number;\n\tsymbolPreset?: ToolSymbolPreset;\n}\n\n/** The phrase every expand affordance ends with, here and in each tool's own renderer. */\n\nexport class ToolExecutionComponent extends Container {\n\tprivate contentBox: Box;\n\tprivate contentText: Text;\n\tprivate contentTextRegion: MouseRegion;\n\tprivate selfRenderContainer: Container;\n\tprivate callRendererComponent?: Component;\n\tprivate resultRendererComponent?: Component;\n\tprivate rendererState: any = {};\n\tprivate imageComponents: Image[] = [];\n\tprivate imageSpacers: Spacer[] = [];\n\tprivate toolName: string;\n\tprivate toolCallId: string;\n\tprivate args: any;\n\tprivate expanded = false;\n\tprivate editDiffsExpanded = true;\n\tprivate showImages: boolean;\n\tprivate imageWidthCells: number;\n\tprivate isPartial = true;\n\tprivate toolDefinition?: ToolRenderers;\n\tprivate ui: TUI;\n\tprivate cwd: string;\n\tprivate executionStarted = false;\n\tprivate executionStartedAt?: number;\n\tprivate executionEndedAt?: number;\n\tprivate elapsedTimer?: ReturnType<typeof setInterval>;\n\tprivate argsComplete = false;\n\tprivate symbolPreset: ToolSymbolPreset;\n\t// Composed-line cache. Recomposing the panel (ANSI-aware truncation, width\n\t// measurement, background paint per content line) on every frame made\n\t// per-frame cost grow with the number of tools on screen; see\n\t// test/tool-execution-render-cache.test.ts.\n\tprivate displayVersion = 0;\n\tprivate cachedRender?: { key: string; width: number; lines: string[] };\n\tprivate result?: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tisError: boolean;\n\t\tdetails?: any;\n\t};\n\tprivate convertedImages: Map<\n\t\tnumber,\n\t\t{ sourceData: string; sourceMimeType: string; data: string; mimeType: string }\n\t> = new Map();\n\tprivate hideComponent = false;\n\n\tconstructor(\n\t\ttoolName: string,\n\t\ttoolCallId: string,\n\t\targs: any,\n\t\toptions: ToolExecutionOptions = {},\n\t\ttoolDefinition: ToolRenderers | ToolDefinition<any, any, any> | undefined,\n\t\tui: TUI,\n\t\tcwd: string,\n\t) {\n\t\tsuper();\n\t\tthis.toolName = toolName;\n\t\tthis.toolCallId = toolCallId;\n\t\tthis.args = args;\n\t\tthis.toolDefinition = toolDefinition;\n\t\tthis.showImages = options.showImages ?? true;\n\t\tthis.imageWidthCells = options.imageWidthCells ?? 60;\n\t\tthis.symbolPreset = options.symbolPreset ?? \"unicode\";\n\t\tthis.ui = ui;\n\t\tthis.cwd = cwd;\n\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Always create all shell variants. contentBox is used for default renderer-based composition.\n\t\t// selfRenderContainer is used when the tool renders its own framing.\n\t\t// contentText is reserved for generic fallback rendering when no tool definition exists.\n\t\tthis.contentBox = new Box(0, 0);\n\t\tthis.contentText = new Text(\"\", 0, 0);\n\t\tthis.contentTextRegion = this.createResultRegion(this.contentText);\n\t\tthis.selfRenderContainer = new Container();\n\n\t\tif (this.hasRendererDefinition()) {\n\t\t\tthis.addChild(this.getRenderShell() === \"self\" ? this.selfRenderContainer : this.contentBox);\n\t\t} else {\n\t\t\tthis.addChild(this.contentTextRegion);\n\t\t}\n\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate getCallRenderer(): ToolDefinition<any, any>[\"renderCall\"] | undefined {\n\t\treturn this.toolDefinition?.renderCall;\n\t}\n\n\tprivate getResultRenderer(): ToolDefinition<any, any>[\"renderResult\"] | undefined {\n\t\treturn this.toolDefinition?.renderResult;\n\t}\n\n\tprivate hasRendererDefinition(): boolean {\n\t\treturn this.toolDefinition !== undefined;\n\t}\n\n\tprivate getRenderShell(): \"default\" | \"self\" {\n\t\treturn this.toolDefinition?.renderShell ?? \"default\";\n\t}\n\n\tprivate getRenderContext(lastComponent: Component | undefined): ToolRenderContext {\n\t\treturn {\n\t\t\targs: this.args,\n\t\t\ttoolCallId: this.toolCallId,\n\t\t\tinvalidate: () => {\n\t\t\t\tthis.invalidate();\n\t\t\t\tthis.ui.requestRender();\n\t\t\t},\n\t\t\tlastComponent,\n\t\t\tstate: this.rendererState,\n\t\t\tcwd: this.cwd,\n\t\t\texecutionStarted: this.executionStarted,\n\t\t\targsComplete: this.argsComplete,\n\t\t\tisPartial: this.isPartial,\n\t\t\texpanded: this.expanded,\n\t\t\teditDiffsExpanded: this.editDiffsExpanded,\n\t\t\tshowImages: this.showImages,\n\t\t\tisError: this.result?.isError ?? false,\n\t\t};\n\t}\n\n\tprivate createCallFallback(): Component {\n\t\treturn new Text(theme.fg(\"toolTitle\", theme.bold(this.toolName)), 0, 0);\n\t}\n\n\tprivate createResultFallback(): Component | undefined {\n\t\tconst output = this.getTextOutput();\n\t\tif (!output) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst displayLines = this.expanded\n\t\t\t? lines\n\t\t\t: lines.slice(0, previewLineCount(lines.length, FALLBACK_PREVIEW_LINES));\n\t\tconst remaining = lines.length - displayLines.length;\n\t\tlet text = displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n\t\tif (remaining > 0) text += `\\n${formatHiddenLines(remaining, \"more\")}`;\n\t\treturn new Text(text, 0, 0);\n\t}\n\n\tprivate createResultRegion(component: Component): MouseRegion {\n\t\treturn new MouseRegion(component, (event) => {\n\t\t\tif (!this.result || event.type !== \"click\" || event.button !== \"left\") return undefined;\n\t\t\tthis.setExpanded(!this.expanded);\n\t\t\treturn { handled: true };\n\t\t});\n\t}\n\n\tupdateArgs(args: any): void {\n\t\tthis.args = args;\n\t\tthis.updateDisplay();\n\t}\n\n\tmarkExecutionStarted(): void {\n\t\tthis.executionStarted = true;\n\t\tthis.executionStartedAt ??= Date.now();\n\t\tthis.startElapsedTimer();\n\t\tthis.updateDisplay();\n\t\tthis.ui.requestRender();\n\t}\n\n\tsetArgsComplete(): void {\n\t\tthis.argsComplete = true;\n\t\tthis.updateDisplay();\n\t\tthis.ui.requestRender();\n\t}\n\n\tupdateResult(\n\t\tresult: {\n\t\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\t\tdetails?: any;\n\t\t\tisError: boolean;\n\t\t},\n\t\tisPartial = false,\n\t): void {\n\t\tthis.result = result;\n\t\tthis.isPartial = isPartial;\n\t\tif (!isPartial) {\n\t\t\tthis.executionEndedAt ??= Date.now();\n\t\t\tthis.stopElapsedTimer();\n\t\t}\n\t\tthis.updateDisplay();\n\t\tthis.maybeConvertImagesForKitty();\n\t}\n\n\tdispose(): void {\n\t\tthis.stopElapsedTimer();\n\t\tthis.cachedRender = undefined;\n\t}\n\n\tprivate startElapsedTimer(): void {\n\t\tif (this.elapsedTimer) return;\n\t\tthis.elapsedTimer = setInterval(() => this.ui.requestRender(), 1000);\n\t}\n\n\tprivate stopElapsedTimer(): void {\n\t\tif (!this.elapsedTimer) return;\n\t\tclearInterval(this.elapsedTimer);\n\t\tthis.elapsedTimer = undefined;\n\t}\n\n\tprivate maybeConvertImagesForKitty(): void {\n\t\tconst caps = getCapabilities();\n\t\tif (caps.images !== \"kitty\") return;\n\t\tif (!this.result) return;\n\n\t\tconst imageBlocks = this.result.content.filter((c) => c.type === \"image\");\n\t\tfor (let i = 0; i < imageBlocks.length; i++) {\n\t\t\tconst img = imageBlocks[i];\n\t\t\tif (!img.data || !img.mimeType) continue;\n\t\t\tconst sourceData = img.data;\n\t\t\tconst sourceMimeType = img.mimeType;\n\t\t\tif (sourceMimeType === \"image/png\") continue;\n\t\t\tconst cached = this.convertedImages.get(i);\n\t\t\tif (cached?.sourceData === sourceData && cached.sourceMimeType === sourceMimeType) continue;\n\n\t\t\tconst index = i;\n\t\t\tconvertToPng(sourceData, sourceMimeType).then((converted) => {\n\t\t\t\tconst currentImage = this.result?.content.filter((content) => content.type === \"image\")[index];\n\t\t\t\tif (!converted || currentImage?.data !== sourceData || currentImage.mimeType !== sourceMimeType) return;\n\t\t\t\tthis.convertedImages.set(index, {\n\t\t\t\t\tsourceData,\n\t\t\t\t\tsourceMimeType,\n\t\t\t\t\t...converted,\n\t\t\t\t});\n\t\t\t\tthis.updateDisplay();\n\t\t\t\tthis.ui.requestRender();\n\t\t\t});\n\t\t}\n\t}\n\n\tsetEditDiffsExpanded(expanded: boolean): void {\n\t\tif (this.editDiffsExpanded === expanded) return;\n\t\tthis.editDiffsExpanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetShowImages(show: boolean): void {\n\t\tthis.showImages = show;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetImageWidthCells(width: number): void {\n\t\tthis.imageWidthCells = Math.max(1, Math.floor(width));\n\t\tthis.updateDisplay();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate getLifecycle(): ToolLifecycle {\n\t\tif (this.result && !this.isPartial) return this.result.isError ? \"error\" : \"done\";\n\t\treturn this.executionStarted ? \"running\" : \"queued\";\n\t}\n\n\tprivate getDurationMs(): number | undefined {\n\t\tif (this.executionStartedAt === undefined) return undefined;\n\t\treturn (this.executionEndedAt ?? Date.now()) - this.executionStartedAt;\n\t}\n\n\tprivate renderWithStatus(component: Component, width: number): string[] {\n\t\tconst options = {\n\t\t\tlifecycle: this.getLifecycle(),\n\t\t\tsymbolPreset: this.symbolPreset,\n\t\t\tdurationMs: this.getDurationMs(),\n\t\t};\n\t\tif (this.hasRendererDefinition() && this.getRenderShell() === \"self\") {\n\t\t\treturn new ToolStatusLineComponent(component, options).render(width);\n\t\t}\n\t\treturn new ToolPanelComponent(component, options).render(width);\n\t}\n\n\tprivate renderCollapsedError(contentLines: string[], width: number): string[] {\n\t\tconst errorText = this.getTextOutput();\n\t\tif (!errorText || contentLines.length === 0) return contentLines;\n\n\t\tconst errorLines = new Text(theme.fg(\"toolOutput\", errorText), 0, 0).render(width);\n\t\tconst previewLines = errorLines.slice(0, previewLineCount(errorLines.length, COLLAPSED_ERROR_VISUAL_LINE_LIMIT));\n\t\tconst omittedLines = errorLines.length - previewLines.length;\n\t\tif (omittedLines === 0) return [...contentLines.slice(0, 1), ...previewLines];\n\n\t\treturn [...contentLines.slice(0, 1), ...previewLines, formatHiddenLines(omittedLines, \"more\")];\n\t}\n\n\toverride render(width: number): string[] {\n\t\tif (this.hideComponent || width <= 0) return [];\n\t\tconst key = this.renderCacheKey();\n\t\tconst cached = this.cachedRender;\n\t\tif (cached && cached.key === key && cached.width === width) return cached.lines;\n\t\tconst lines = this.compose(width);\n\t\tthis.cachedRender = { key, width, lines };\n\t\treturn lines;\n\t}\n\n\t/**\n\t * Cache key for the composed lines. Every state change funnels through\n\t * updateDisplay(), which bumps displayVersion; the elapsed readout is the\n\t * one input that advances without a state change, so it is bucketed at\n\t * 250 ms while running (matching the 1 s elapsed timer's cadence closely\n\t * enough that the readout never looks stale, while bounding recomposition\n\t * to at most four per second for the one running tool).\n\t */\n\tprivate renderCacheKey(): string {\n\t\tconst lifecycle = this.getLifecycle();\n\t\tconst durationMs = this.getDurationMs();\n\t\tconst durationKey = lifecycle === \"running\" ? Math.floor((durationMs ?? 0) / 250) : (durationMs ?? -1);\n\t\treturn `${this.displayVersion}:${lifecycle}:${durationKey}`;\n\t}\n\n\tprivate compose(width: number): string[] {\n\t\tconst shell = this.hasRendererDefinition()\n\t\t\t? this.getRenderShell() === \"self\"\n\t\t\t\t? this.selfRenderContainer\n\t\t\t\t: this.contentBox\n\t\t\t: this.contentText;\n\t\tconst selfRendered = this.hasRendererDefinition() && this.getRenderShell() === \"self\";\n\t\tconst panelContent: Component = selfRendered\n\t\t\t? shell\n\t\t\t: {\n\t\t\t\t\trender: (innerWidth: number) => {\n\t\t\t\t\t\tconst contentLines = shell.render(innerWidth);\n\t\t\t\t\t\tconst visibleLines =\n\t\t\t\t\t\t\tthis.result?.isError && !this.isPartial && !this.expanded\n\t\t\t\t\t\t\t\t? this.renderCollapsedError(contentLines, innerWidth)\n\t\t\t\t\t\t\t\t: contentLines;\n\t\t\t\t\t\treturn visibleLines;\n\t\t\t\t\t},\n\t\t\t\t\tinvalidate: () => shell.invalidate?.(),\n\t\t\t\t};\n\t\tconst visibleContentLines = this.renderWithStatus(panelContent, width);\n\t\tif (visibleContentLines.length === 0 && this.imageComponents.length === 0) return [];\n\n\t\tconst lines: string[] = [];\n\t\tif (visibleContentLines.length > 0) {\n\t\t\tlines.push(\"\");\n\t\t\tlines.push(...visibleContentLines);\n\t\t}\n\t\tfor (let i = 0; i < this.imageComponents.length; i++) {\n\t\t\tconst spacer = this.imageSpacers[i];\n\t\t\tif (spacer) lines.push(...spacer.render(width));\n\t\t\tconst imageComponent = this.imageComponents[i];\n\t\t\tif (imageComponent) lines.push(...imageComponent.render(width));\n\t\t}\n\t\treturn lines;\n\t}\n\n\t/**\n\t * A left click on the panel toggles the result, as upstream's per-region\n\t * handlers do. Apex composes the panel itself (lifecycle header, spine,\n\t * padding, the separator row it inserts), so rendered rows do not line up\n\t * with the children's rows and the inherited child-by-child dispatch would\n\t * resolve the wrong region. Row 0 is the leading spacer and is inert.\n\t */\n\toverride handleMouse(event: TuiMouseEvent): ReturnType<Container[\"handleMouse\"]> {\n\t\tif (this.hideComponent || event.y <= 0 || event.y >= event.height) return undefined;\n\t\tif (!this.result || event.type !== \"click\" || event.button !== \"left\") return undefined;\n\t\tthis.setExpanded(!this.expanded);\n\t\treturn {\n\t\t\thandled: true,\n\t\t\ttarget: {\n\t\t\t\tcomponent: this,\n\t\t\t\toriginX: event.screenX - event.x,\n\t\t\t\toriginY: event.screenY - event.y,\n\t\t\t\twidth: event.width,\n\t\t\t\theight: event.height,\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tthis.displayVersion += 1;\n\t\tlet hasContent = false;\n\t\tthis.hideComponent = false;\n\t\tif (this.hasRendererDefinition()) {\n\t\t\tconst renderContainer = this.getRenderShell() === \"self\" ? this.selfRenderContainer : this.contentBox;\n\t\t\trenderContainer.clear();\n\n\t\t\tconst callRenderer = this.getCallRenderer();\n\t\t\tif (!callRenderer) {\n\t\t\t\trenderContainer.addChild(this.createResultRegion(this.createCallFallback()));\n\t\t\t\thasContent = true;\n\t\t\t} else {\n\t\t\t\ttry {\n\t\t\t\t\tconst component = callRenderer(this.args, theme, this.getRenderContext(this.callRendererComponent));\n\t\t\t\t\tthis.callRendererComponent = component;\n\t\t\t\t\trenderContainer.addChild(this.createResultRegion(component));\n\t\t\t\t\thasContent = true;\n\t\t\t\t} catch {\n\t\t\t\t\tthis.callRendererComponent = undefined;\n\t\t\t\t\trenderContainer.addChild(this.createResultRegion(this.createCallFallback()));\n\t\t\t\t\thasContent = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst resultRenderer = this.getResultRenderer();\n\t\t\t\tif (!resultRenderer) {\n\t\t\t\t\tconst component = this.createResultFallback();\n\t\t\t\t\tif (component) {\n\t\t\t\t\t\trenderContainer.addChild(this.createResultRegion(component));\n\t\t\t\t\t\thasContent = true;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst component = resultRenderer(\n\t\t\t\t\t\t\t{ content: this.result.content as any, details: this.result.details },\n\t\t\t\t\t\t\t{ expanded: this.expanded, isPartial: this.isPartial },\n\t\t\t\t\t\t\ttheme,\n\t\t\t\t\t\t\tthis.getRenderContext(this.resultRendererComponent),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tthis.resultRendererComponent = component;\n\t\t\t\t\t\trenderContainer.addChild(this.createResultRegion(component));\n\t\t\t\t\t\thasContent = true;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tthis.resultRendererComponent = undefined;\n\t\t\t\t\t\tconst component = this.createResultFallback();\n\t\t\t\t\t\tif (component) {\n\t\t\t\t\t\t\trenderContainer.addChild(this.createResultRegion(component));\n\t\t\t\t\t\t\thasContent = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthis.contentText.setText(this.formatToolExecution());\n\t\t\thasContent = true;\n\t\t}\n\n\t\tfor (const img of this.imageComponents) {\n\t\t\tthis.removeChild(img);\n\t\t}\n\t\tthis.imageComponents = [];\n\t\tfor (const spacer of this.imageSpacers) {\n\t\t\tthis.removeChild(spacer);\n\t\t}\n\t\tthis.imageSpacers = [];\n\n\t\tif (this.result) {\n\t\t\tconst imageBlocks = this.result.content.filter((c) => c.type === \"image\");\n\t\t\tconst caps = getCapabilities();\n\t\t\tfor (let i = 0; i < imageBlocks.length; i++) {\n\t\t\t\tconst img = imageBlocks[i];\n\t\t\t\tif (caps.images && this.showImages && img.data && img.mimeType) {\n\t\t\t\t\tconst cached = this.convertedImages.get(i);\n\t\t\t\t\tconst converted =\n\t\t\t\t\t\tcached?.sourceData === img.data && cached.sourceMimeType === img.mimeType ? cached : undefined;\n\t\t\t\t\tconst imageData = converted?.data ?? img.data;\n\t\t\t\t\tconst imageMimeType = converted?.mimeType ?? img.mimeType;\n\t\t\t\t\tif (caps.images === \"kitty\" && imageMimeType !== \"image/png\") continue;\n\n\t\t\t\t\tconst spacer = new Spacer(1);\n\t\t\t\t\tthis.addChild(spacer);\n\t\t\t\t\tthis.imageSpacers.push(spacer);\n\t\t\t\t\tconst imageComponent = new Image(\n\t\t\t\t\t\timageData,\n\t\t\t\t\t\timageMimeType,\n\t\t\t\t\t\t{ fallbackColor: (s: string) => theme.fg(\"toolOutput\", s) },\n\t\t\t\t\t\t{ maxWidthCells: this.imageWidthCells },\n\t\t\t\t\t);\n\t\t\t\t\tthis.imageComponents.push(imageComponent);\n\t\t\t\t\tthis.addChild(imageComponent);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (this.hasRendererDefinition() && !hasContent && this.imageComponents.length === 0) {\n\t\t\tthis.hideComponent = true;\n\t\t}\n\t}\n\n\tprivate getTextOutput(): string {\n\t\treturn getRenderedTextOutput(this.result, this.showImages);\n\t}\n\n\tprivate formatToolExecution(): string {\n\t\tlet text = theme.fg(\"toolTitle\", theme.bold(this.toolName));\n\t\tconst content = JSON.stringify(this.args, null, 2);\n\t\tif (content) {\n\t\t\ttext += `\\n\\n${content}`;\n\t\t}\n\t\tconst output = this.getTextOutput();\n\t\tif (output) {\n\t\t\ttext += `\\n${output}`;\n\t\t}\n\t\treturn text;\n\t}\n}\n"]}