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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bug-report.js","sourceRoot":"","sources":["../../../src/modes/interactive/bug-report.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAGlC,OAAO,EACN,4BAA4B,EAG5B,wBAAwB,EACxB,2BAA2B,EAC3B,wBAAwB,EACxB,qBAAqB,GACrB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAChF,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAoBzC,MAAM,UAAU,GACf,4TAA4T,CAAC;AAC9T,MAAM,eAAe,GACpB,yJAAyJ,CAAC;AAE3J,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAyB,EAAE,WAAoB,EAAiB;IAC/F,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAC7D,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,OAAO,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC;QAC3C,OAAO;IACR,CAAC;IACD,IAAI,OAA2B,CAAC;IAChC,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,UAAU,CACxB,OAAO,EACP,wBAAwB,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,IAAI,mBAAmB,KAAK,CAC/E,CAAC;QACF,IAAI,CAAC;YACJ,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,qBAAqB,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACtG,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACzB,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC/B,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO;gBAAE,OAAO,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC;;gBACjE,OAAO,CAAC,SAAS,CAAC,uCAAuC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACrF,OAAO;QACR,CAAC;QACD,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC/B,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YAC3B,OAAO,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC;YAC3C,OAAO;QACR,CAAC;IACF,CAAC;IAED,IAAI,MAAuB,CAAC;IAC5B,IAAI,CAAC;QACJ,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IACzD,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACzB,OAAO,CAAC,SAAS,CAAC,+BAA+B,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACxE,OAAO;IACR,CAAC;IAED,MAAM,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAAA,CACjC;AAED,KAAK,UAAU,gBAAgB,CAC9B,OAAyB,EACzB,WAA+B,EACS;IACxC,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,UAAU,iCAAiC,EAAE,WAAW,CAAC,CAAC;IAC/G,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACpC,MAAM,UAAU,GAAG,MAAM,MAAM,CAC9B,OAAO,EACP,iCAAiC,EACjC,CAAC,6BAA6B,EAAE,IAAI,CAAC,EACrC,eAAe,CACf,CAAC;IACF,IAAI,CAAC,UAAU;QAAE,OAAO,SAAS,CAAC;IAClC,MAAM,cAAc,GAAG,UAAU,KAAK,IAAI,CAAC;IAC3C,IAAI,cAAc,GAAG,KAAK,CAAC;IAC3B,IAAI,CAAC,cAAc,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC;QACpC,MAAM,OAAO,GAAG,MAAM,MAAM,CAC3B,OAAO,EACP,+BAA+B,KAAK,EAAE,IAAI,IAAI,mBAAmB,WAAW,EAC5E,CAAC,yBAAyB,EAAE,IAAI,CAAC,EACjC,6BAA6B,KAAK,EAAE,QAAQ,IAAI,eAAe,kHAAkH,CACjL,CAAC;QACF,IAAI,CAAC,OAAO;YAAE,OAAO,SAAS,CAAC;QAC/B,cAAc,GAAG,OAAO,KAAK,IAAI,CAAC;IACnC,CAAC;IACD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAChC,MAAM,YAAY,GAAG,MAAM,MAAM,CAChC,OAAO,EACP,YAAY,EACZ,CAAC,eAAe,EAAE,QAAQ,CAAC,EAC3B,gBAAgB,WAAW,IAAI,MAAM,iBAAiB,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,cAAc,cAAc,cAAc,CAAC,CAAC,CAAC,cAAc,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,IAAI,mBAAmB,EAAE,CAAC,CAAC,CAAC,MAAM,kFAAkF,CAC9R,CAAC;IACF,IAAI,YAAY,KAAK,eAAe;QAAE,OAAO,SAAS,CAAC;IACvD,OAAO;QACN,IAAI,EAAE,WAAW,IAAI,SAAS;QAC9B,cAAc;QACd,cAAc;KACd,CAAC;AAAA,CACF;AAED,SAAS,WAAW,CAAC,OAAqB,EAAE,OAAyB,EAAE,OAA2B,EAAmB;IACpH,MAAM,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC,aAAa,EAAE,CAAC;IAC1D,OAAO;QACN,QAAQ,EAAE,wBAAwB,CAAC;YAClC,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,GAAG,EAAE,OAAO,CAAC,cAAc,CAAC,MAAM,EAAE;YACpC,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,cAAc,EAAE,OAAO,KAAK,SAAS;YACrC,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM;YACrC,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,aAAa,EAAE,OAAO,CAAC,aAAa;YACpC,UAAU,EAAE,UAAU,CAAC,UAAU;YACjC,eAAe,EAAE,UAAU,CAAC,MAAM;YAClC,cAAc,EAAE,OAAO,CAAC,eAAe,CAAC,iBAAiB,EAAE;YAC3D,eAAe,EAAE,OAAO,CAAC,eAAe,CAAC,kBAAkB,EAAE;SAC7D,CAAC;QACF,WAAW,EAAE,2BAA2B,CAAC,OAAO,CAAC,cAAc,EAAE,YAAY,EAAE,CAAC;QAChF,OAAO;QACP,YAAY,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,sBAAsB,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,SAAS;KACjG,CAAC;AAAA,CACF;AAED,KAAK,UAAU,SAAS,CAAC,OAAyB,EAAE,MAAuB,EAAiB;IAC3F,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,wBAAwB,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3F,IAAI,CAAC;QACJ,MAAM,qBAAqB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAClD,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACzB,OAAO,CAAC,SAAS,CAAC,+BAA+B,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACxE,OAAO;IACR,CAAC;IACD,eAAe,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;IACjF,OAAO,CAAC,UAAU,CAAC,2BAA2B,WAAW,gBAAgB,MAAM,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;AAAA,CAC/F;AAED,SAAS,eAAe,CACvB,OAAqB,EACrB,MAAuB,EACvB,QAA8D,EACvD;IACP,OAAO,CAAC,cAAc,CAAC,iBAAiB,CAAC,4BAA4B,EAAE;QACtE,EAAE,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE;QACtB,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,SAAS;QACpC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI;QAC1B,eAAe,EAAE,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ;QACjD,eAAe,EAAE,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,eAAe;QACxD,GAAG,QAAQ;KACyB,CAAC,CAAC;IACvC,IAAI,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,aAAa,EAAE,CAAC;AAAA,CAC3D;AAED,SAAS,KAAK,CACb,OAAyB,EACzB,KAAa,EACb,WAAmB,EACnB,YAAqB,EACI;IACzB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;QAC/B,IAAI,SAAmC,CAAC;QACxC,MAAM,MAAM,GAAG,CAAC,KAAoB,EAAE,EAAE,CAAC;YACxC,aAAa,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;YAClC,OAAO,CAAC,KAAK,CAAC,CAAC;QAAA,CACf,CAAC;QACF,SAAS,GAAG,IAAI,wBAAwB,CACvC,OAAO,CAAC,EAAE,EACV,OAAO,CAAC,WAAW,EACnB,KAAK,EACL,YAAY,EACZ,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EACxB,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAClB,EAAE,WAAW,EAAE,EACf,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,wBAAwB,EAAE,CAC1D,CAAC;QACF,WAAW,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAAA,CAChC,CAAC,CAAC;AAAA,CACH;AAED,SAAS,MAAM,CACd,OAAyB,EACzB,KAAa,EACb,OAAiB,EACjB,WAAoB,EACU;IAC9B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;QAC/B,IAAI,SAAqC,CAAC;QAC1C,MAAM,MAAM,GAAG,CAAC,KAAc,EAAE,EAAE,CAAC;YAClC,aAAa,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;YAClC,OAAO,CAAC,KAAK,CAAC,CAAC;QAAA,CACf,CAAC;QACF,SAAS,GAAG,IAAI,0BAA0B,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,EAAE;YAClF,GAAG,EAAE,OAAO,CAAC,EAAE;YACf,WAAW;SACX,CAAC,CAAC;QACH,WAAW,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAAA,CAChC,CAAC,CAAC;AAAA,CACH;AAED,SAAS,UAAU,CAAC,OAAyB,EAAE,OAAe,EAAkB;IAC/E,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IAC9D,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC7B,OAAO,MAAM,CAAC;AAAA,CACd;AAED,SAAS,WAAW,CAAC,OAAyB,EAAE,SAAkB,EAAQ;IACzE,OAAO,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;IAChC,OAAO,CAAC,eAAe,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC5C,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,aAAa,EAAE,CAAC;AAAA,CAC3B;AAED,SAAS,aAAa,CAAC,OAAyB,EAAE,SAAkB,EAAQ;IAC3E,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC;IACtB,OAAO,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;IAChC,OAAO,CAAC,eAAe,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjD,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACpC,OAAO,CAAC,EAAE,CAAC,aAAa,EAAE,CAAC;AAAA,CAC3B;AAED,SAAS,YAAY,CAAC,KAAc,EAAU;IAC7C,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;AAAA,CAChE","sourcesContent":["import * as path from \"node:path\";\nimport type { Container, EditorComponent, TUI } from \"@earendil-works/pi-tui\";\nimport type { AgentSession } from \"../../core/agent-session.ts\";\nimport {\n\tBUG_REPORT_CUSTOM_ENTRY_TYPE,\n\ttype BugReportBundle,\n\ttype BugReportSessionEntryData,\n\tbugReportArchiveFileName,\n\tcollectBugReportDiagnostics,\n\tcollectBugReportMetadata,\n\twriteBugReportArchive,\n} from \"../../core/bug-report.ts\";\nimport { clearCrashLog, readCrashLog } from \"../../core/crash-log.ts\";\nimport type { KeybindingsManager } from \"../../core/keybindings.ts\";\nimport { serializeSessionBranch } from \"../../core/session-export.ts\";\nimport { BorderedLoader } from \"./components/bordered-loader.ts\";\nimport { ExtensionEditorComponent } from \"./components/extension-editor.ts\";\nimport { ExtensionSelectorComponent } from \"./components/extension-selector.ts\";\nimport { theme } from \"./theme/theme.ts\";\n\ninterface BugReportContext {\n\tsession: AgentSession;\n\tui: TUI;\n\teditorContainer: Container;\n\teditor: EditorComponent;\n\tkeybindings: KeybindingsManager;\n\tshowStatus: (message: string) => void;\n\tshowError: (message: string) => void;\n}\n\ninterface BugReportOptions {\n\thint?: string;\n\tincludeSession: boolean;\n\tincludeSummary: boolean;\n}\n\ntype Overlay = Container & { dispose?: () => void };\n\nconst DISCLAIMER =\n\t\"This report is exported as a zip file on this machine. This flow does not send it to Apex Code or any other service. It includes your Apex Code version, operating system, the current model and provider configuration (without API keys), loaded extensions, settings, and provider error diagnostics from this session.\";\nconst TRANSCRIPT_NOTE =\n\t\"The transcript contains your messages, model output, tool calls and their results, including file contents and command output read during this session.\";\n\n/** Run the `/bug` flow: consent, optional summary, then export a local archive. */\nexport async function reportBug(context: BugReportContext, initialHint?: string): Promise<void> {\n\tconst options = await promptForOptions(context, initialHint);\n\tif (!options) {\n\t\tcontext.showStatus(\"Bug report cancelled\");\n\t\treturn;\n\t}\n\tlet summary: string | undefined;\n\tif (options.includeSummary) {\n\t\tconst loader = showLoader(\n\t\t\tcontext,\n\t\t\t`Writing summary with ${context.session.model?.name ?? \"the current model\"}...`,\n\t\t);\n\t\ttry {\n\t\t\tsummary = await context.session.summarizeForBugReport({ hint: options.hint, signal: loader.signal });\n\t\t} catch (error: unknown) {\n\t\t\trestoreEditor(context, loader);\n\t\t\tif (loader.signal.aborted) context.showStatus(\"Bug report cancelled\");\n\t\t\telse context.showError(`Failed to write bug report summary: ${errorMessage(error)}`);\n\t\t\treturn;\n\t\t}\n\t\trestoreEditor(context, loader);\n\t\tif (loader.signal.aborted) {\n\t\t\tcontext.showStatus(\"Bug report cancelled\");\n\t\t\treturn;\n\t\t}\n\t}\n\n\tlet bundle: BugReportBundle;\n\ttry {\n\t\tbundle = buildBundle(context.session, options, summary);\n\t} catch (error: unknown) {\n\t\tcontext.showError(`Failed to build bug report: ${errorMessage(error)}`);\n\t\treturn;\n\t}\n\n\tawait exportZip(context, bundle);\n}\n\nasync function promptForOptions(\n\tcontext: BugReportContext,\n\tinitialHint: string | undefined,\n): Promise<BugReportOptions | undefined> {\n\tconst hint = await input(context, \"Report a bug\", `${DISCLAIMER}\\n\\nWhat went wrong? (optional)`, initialHint);\n\tif (hint === null) return undefined;\n\tconst transcript = await choose(\n\t\tcontext,\n\t\t\"Include the session transcript?\",\n\t\t[\"Yes, include the transcript\", \"No\"],\n\t\tTRANSCRIPT_NOTE,\n\t);\n\tif (!transcript) return undefined;\n\tconst includeSession = transcript !== \"No\";\n\tlet includeSummary = false;\n\tif (!includeSession) {\n\t\tconst model = context.session.model;\n\t\tconst summary = await choose(\n\t\t\tcontext,\n\t\t\t`Attach a summary written by ${model?.name ?? \"the current model\"} instead?`,\n\t\t\t[\"Yes, generate a summary\", \"No\"],\n\t\t\t`The transcript is sent to ${model?.provider ?? \"your provider\"} with your credentials and tokens. Only the generated summary is attached; the transcript stays on your machine.`,\n\t\t);\n\t\tif (!summary) return undefined;\n\t\tincludeSummary = summary !== \"No\";\n\t}\n\tconst description = hint.trim();\n\tconst exportChoice = await choose(\n\t\tcontext,\n\t\t\"Bug report\",\n\t\t[\"Export as Zip\", \"Cancel\"],\n\t\t`Description: ${description || \"none\"}\\nTranscript: ${includeSession ? \"included\" : \"not included\"}\\nSummary: ${includeSummary ? `written by ${context.session.model?.name ?? \"the current model\"}` : \"none\"}\\n\\nThe archive is saved to the current directory. This flow does not upload it.`,\n\t);\n\tif (exportChoice !== \"Export as Zip\") return undefined;\n\treturn {\n\t\thint: description || undefined,\n\t\tincludeSession,\n\t\tincludeSummary,\n\t};\n}\n\nfunction buildBundle(session: AgentSession, options: BugReportOptions, summary: string | undefined): BugReportBundle {\n\tconst extensions = session.resourceLoader.getExtensions();\n\treturn {\n\t\tmetadata: collectBugReportMetadata({\n\t\t\thint: options.hint,\n\t\t\tsessionId: session.sessionId,\n\t\t\tcwd: session.sessionManager.getCwd(),\n\t\t\tincludeSession: options.includeSession,\n\t\t\tincludeSummary: summary !== undefined,\n\t\t\tmessageCount: session.messages.length,\n\t\t\tmodel: session.model,\n\t\t\tmodelRuntime: session.modelRuntime,\n\t\t\tthinkingLevel: session.thinkingLevel,\n\t\t\textensions: extensions.extensions,\n\t\t\textensionErrors: extensions.errors,\n\t\t\tglobalSettings: session.settingsManager.getGlobalSettings(),\n\t\t\tprojectSettings: session.settingsManager.getProjectSettings(),\n\t\t}),\n\t\tdiagnostics: collectBugReportDiagnostics(session.sessionManager, readCrashLog()),\n\t\tsummary,\n\t\tsessionJsonl: options.includeSession ? serializeSessionBranch(session.sessionManager) : undefined,\n\t};\n}\n\nasync function exportZip(context: BugReportContext, bundle: BugReportBundle): Promise<void> {\n\tconst archivePath = path.join(process.cwd(), bugReportArchiveFileName(bundle.metadata.id));\n\ttry {\n\t\tawait writeBugReportArchive(bundle, archivePath);\n\t} catch (error: unknown) {\n\t\tcontext.showError(`Failed to write bug report: ${errorMessage(error)}`);\n\t\treturn;\n\t}\n\trecordInSession(context.session, bundle, { delivery: \"zip\", path: archivePath });\n\tcontext.showStatus(`Bug report exported to: ${archivePath}\\nReport ID: ${bundle.metadata.id}`);\n}\n\nfunction recordInSession(\n\tsession: AgentSession,\n\tbundle: BugReportBundle,\n\tdelivery: Pick<BugReportSessionEntryData, \"delivery\" | \"path\">,\n): void {\n\tsession.sessionManager.appendCustomEntry(BUG_REPORT_CUSTOM_ENTRY_TYPE, {\n\t\tid: bundle.metadata.id,\n\t\tcreatedAt: bundle.metadata.createdAt,\n\t\thint: bundle.metadata.hint,\n\t\tsessionIncluded: bundle.metadata.session.included,\n\t\tsummaryIncluded: bundle.metadata.session.summaryIncluded,\n\t\t...delivery,\n\t} satisfies BugReportSessionEntryData);\n\tif (bundle.diagnostics.crashes.length > 0) clearCrashLog();\n}\n\nfunction input(\n\tcontext: BugReportContext,\n\ttitle: string,\n\tdescription: string,\n\tinitialValue?: string,\n): Promise<string | null> {\n\treturn new Promise((resolve) => {\n\t\tlet component: ExtensionEditorComponent;\n\t\tconst finish = (value: string | null) => {\n\t\t\trestoreEditor(context, component);\n\t\t\tresolve(value);\n\t\t};\n\t\tcomponent = new ExtensionEditorComponent(\n\t\t\tcontext.ui,\n\t\t\tcontext.keybindings,\n\t\t\ttitle,\n\t\t\tinitialValue,\n\t\t\t(value) => finish(value),\n\t\t\t() => finish(null),\n\t\t\t{ description },\n\t\t\tcontext.session.settingsManager.getExternalEditorCommand(),\n\t\t);\n\t\tshowOverlay(context, component);\n\t});\n}\n\nfunction choose(\n\tcontext: BugReportContext,\n\ttitle: string,\n\toptions: string[],\n\tdescription?: string,\n): Promise<string | undefined> {\n\treturn new Promise((resolve) => {\n\t\tlet component: ExtensionSelectorComponent;\n\t\tconst finish = (value?: string) => {\n\t\t\trestoreEditor(context, component);\n\t\t\tresolve(value);\n\t\t};\n\t\tcomponent = new ExtensionSelectorComponent(title, options, finish, () => finish(), {\n\t\t\ttui: context.ui,\n\t\t\tdescription,\n\t\t});\n\t\tshowOverlay(context, component);\n\t});\n}\n\nfunction showLoader(context: BugReportContext, message: string): BorderedLoader {\n\tconst loader = new BorderedLoader(context.ui, theme, message);\n\tshowOverlay(context, loader);\n\treturn loader;\n}\n\nfunction showOverlay(context: BugReportContext, component: Overlay): void {\n\tcontext.editorContainer.clear();\n\tcontext.editorContainer.addChild(component);\n\tcontext.ui.setFocus(component);\n\tcontext.ui.requestRender();\n}\n\nfunction restoreEditor(context: BugReportContext, component: Overlay): void {\n\tcomponent.dispose?.();\n\tcontext.editorContainer.clear();\n\tcontext.editorContainer.addChild(context.editor);\n\tcontext.ui.setFocus(context.editor);\n\tcontext.ui.requestRender();\n}\n\nfunction errorMessage(error: unknown): string {\n\treturn error instanceof Error ? error.message : \"Unknown error\";\n}\n"]}
@@ -0,0 +1,20 @@
1
+ import { type Component, ScrollView, type ScrollViewScrollbar } from "@earendil-works/pi-tui";
2
+ export interface ChatViewportOptions {
3
+ readonly document: Component;
4
+ readonly pendingMessages: Component;
5
+ readonly status: Component;
6
+ readonly editor: Component;
7
+ readonly footer: Component;
8
+ readonly widgetsAbove?: Component;
9
+ readonly widgetsBelow?: Component;
10
+ readonly scrollbar?: ScrollViewScrollbar;
11
+ readonly scrollbarTrackStyle?: (text: string) => string;
12
+ readonly scrollbarThumbStyle?: (text: string) => string;
13
+ }
14
+ export interface ChatViewport {
15
+ readonly root: Component;
16
+ readonly transcript: ScrollView;
17
+ }
18
+ /** Shared fullscreen transcript and fixed input-dock layout. */
19
+ export declare function createChatViewport(options: ChatViewportOptions): ChatViewport;
20
+ //# sourceMappingURL=chat-viewport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-viewport.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/chat-viewport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,UAAU,EAAE,KAAK,mBAAmB,EAAU,MAAM,wBAAwB,CAAC;AAEtG,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,eAAe,EAAE,SAAS,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,CAAC;IAClC,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,CAAC;IAClC,QAAQ,CAAC,SAAS,CAAC,EAAE,mBAAmB,CAAC;IACzC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACxD,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACxD;AAED,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CAChC;AAED,gEAAgE;AAChE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAwB7E","sourcesContent":["import { type Component, ScrollView, type ScrollViewScrollbar, VStack } from \"@earendil-works/pi-tui\";\n\nexport interface ChatViewportOptions {\n\treadonly document: Component;\n\treadonly pendingMessages: Component;\n\treadonly status: Component;\n\treadonly editor: Component;\n\treadonly footer: Component;\n\treadonly widgetsAbove?: Component;\n\treadonly widgetsBelow?: Component;\n\treadonly scrollbar?: ScrollViewScrollbar;\n\treadonly scrollbarTrackStyle?: (text: string) => string;\n\treadonly scrollbarThumbStyle?: (text: string) => string;\n}\n\nexport interface ChatViewport {\n\treadonly root: Component;\n\treadonly transcript: ScrollView;\n}\n\n/** Shared fullscreen transcript and fixed input-dock layout. */\nexport function createChatViewport(options: ChatViewportOptions): ChatViewport {\n\tconst transcript = new ScrollView(options.document, {\n\t\tfollow: \"end\",\n\t\tprimary: true,\n\t\toverscroll: \"chain\",\n\t\tscrollbar: options.scrollbar ?? \"auto\",\n\t\t...(options.scrollbarTrackStyle === undefined ? {} : { scrollbarTrackStyle: options.scrollbarTrackStyle }),\n\t\t...(options.scrollbarThumbStyle === undefined ? {} : { scrollbarThumbStyle: options.scrollbarThumbStyle }),\n\t});\n\tconst dock = new VStack([\n\t\t{ component: options.pendingMessages, shrink: 1, minSize: 0 },\n\t\t{ component: options.status, shrink: 1, minSize: 0 },\n\t\t...(options.widgetsAbove === undefined ? [] : [{ component: options.widgetsAbove, shrink: 1, minSize: 0 }]),\n\t\t{ component: options.editor, shrink: 1, minSize: 3 },\n\t\t...(options.widgetsBelow === undefined ? [] : [{ component: options.widgetsBelow, shrink: 1, minSize: 0 }]),\n\t\t{ component: options.footer, shrink: 1, minSize: 0 },\n\t]);\n\treturn {\n\t\ttranscript,\n\t\troot: new VStack([\n\t\t\t{ component: transcript, basis: 0, grow: 1, shrink: 1, minSize: 1 },\n\t\t\t{ component: dock, basis: \"auto\", grow: 0, shrink: 1, minSize: 1 },\n\t\t]),\n\t};\n}\n"]}
@@ -0,0 +1,28 @@
1
+ import { ScrollView, VStack } from "@earendil-works/pi-tui";
2
+ /** Shared fullscreen transcript and fixed input-dock layout. */
3
+ export function createChatViewport(options) {
4
+ const transcript = new ScrollView(options.document, {
5
+ follow: "end",
6
+ primary: true,
7
+ overscroll: "chain",
8
+ scrollbar: options.scrollbar ?? "auto",
9
+ ...(options.scrollbarTrackStyle === undefined ? {} : { scrollbarTrackStyle: options.scrollbarTrackStyle }),
10
+ ...(options.scrollbarThumbStyle === undefined ? {} : { scrollbarThumbStyle: options.scrollbarThumbStyle }),
11
+ });
12
+ const dock = new VStack([
13
+ { component: options.pendingMessages, shrink: 1, minSize: 0 },
14
+ { component: options.status, shrink: 1, minSize: 0 },
15
+ ...(options.widgetsAbove === undefined ? [] : [{ component: options.widgetsAbove, shrink: 1, minSize: 0 }]),
16
+ { component: options.editor, shrink: 1, minSize: 3 },
17
+ ...(options.widgetsBelow === undefined ? [] : [{ component: options.widgetsBelow, shrink: 1, minSize: 0 }]),
18
+ { component: options.footer, shrink: 1, minSize: 0 },
19
+ ]);
20
+ return {
21
+ transcript,
22
+ root: new VStack([
23
+ { component: transcript, basis: 0, grow: 1, shrink: 1, minSize: 1 },
24
+ { component: dock, basis: "auto", grow: 0, shrink: 1, minSize: 1 },
25
+ ]),
26
+ };
27
+ }
28
+ //# sourceMappingURL=chat-viewport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-viewport.js","sourceRoot":"","sources":["../../../src/modes/interactive/chat-viewport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,UAAU,EAA4B,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAoBtG,gEAAgE;AAChE,MAAM,UAAU,kBAAkB,CAAC,OAA4B,EAAgB;IAC9E,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE;QACnD,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,IAAI;QACb,UAAU,EAAE,OAAO;QACnB,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,MAAM;QACtC,GAAG,CAAC,OAAO,CAAC,mBAAmB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,OAAO,CAAC,mBAAmB,EAAE,CAAC;QAC1G,GAAG,CAAC,OAAO,CAAC,mBAAmB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,OAAO,CAAC,mBAAmB,EAAE,CAAC;KAC1G,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC;QACvB,EAAE,SAAS,EAAE,OAAO,CAAC,eAAe,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;QAC7D,EAAE,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;QACpD,GAAG,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;QAC3G,EAAE,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;QACpD,GAAG,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;QAC3G,EAAE,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;KACpD,CAAC,CAAC;IACH,OAAO;QACN,UAAU;QACV,IAAI,EAAE,IAAI,MAAM,CAAC;YAChB,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;YACnE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;SAClE,CAAC;KACF,CAAC;AAAA,CACF","sourcesContent":["import { type Component, ScrollView, type ScrollViewScrollbar, VStack } from \"@earendil-works/pi-tui\";\n\nexport interface ChatViewportOptions {\n\treadonly document: Component;\n\treadonly pendingMessages: Component;\n\treadonly status: Component;\n\treadonly editor: Component;\n\treadonly footer: Component;\n\treadonly widgetsAbove?: Component;\n\treadonly widgetsBelow?: Component;\n\treadonly scrollbar?: ScrollViewScrollbar;\n\treadonly scrollbarTrackStyle?: (text: string) => string;\n\treadonly scrollbarThumbStyle?: (text: string) => string;\n}\n\nexport interface ChatViewport {\n\treadonly root: Component;\n\treadonly transcript: ScrollView;\n}\n\n/** Shared fullscreen transcript and fixed input-dock layout. */\nexport function createChatViewport(options: ChatViewportOptions): ChatViewport {\n\tconst transcript = new ScrollView(options.document, {\n\t\tfollow: \"end\",\n\t\tprimary: true,\n\t\toverscroll: \"chain\",\n\t\tscrollbar: options.scrollbar ?? \"auto\",\n\t\t...(options.scrollbarTrackStyle === undefined ? {} : { scrollbarTrackStyle: options.scrollbarTrackStyle }),\n\t\t...(options.scrollbarThumbStyle === undefined ? {} : { scrollbarThumbStyle: options.scrollbarThumbStyle }),\n\t});\n\tconst dock = new VStack([\n\t\t{ component: options.pendingMessages, shrink: 1, minSize: 0 },\n\t\t{ component: options.status, shrink: 1, minSize: 0 },\n\t\t...(options.widgetsAbove === undefined ? [] : [{ component: options.widgetsAbove, shrink: 1, minSize: 0 }]),\n\t\t{ component: options.editor, shrink: 1, minSize: 3 },\n\t\t...(options.widgetsBelow === undefined ? [] : [{ component: options.widgetsBelow, shrink: 1, minSize: 0 }]),\n\t\t{ component: options.footer, shrink: 1, minSize: 0 },\n\t]);\n\treturn {\n\t\ttranscript,\n\t\troot: new VStack([\n\t\t\t{ component: transcript, basis: 0, grow: 1, shrink: 1, minSize: 1 },\n\t\t\t{ component: dock, basis: \"auto\", grow: 0, shrink: 1, minSize: 1 },\n\t\t]),\n\t};\n}\n"]}
@@ -23,12 +23,16 @@ export declare class AssistantMessageComponent extends Container {
23
23
  private markdownTransformers;
24
24
  private lastMessage?;
25
25
  private hasToolCalls;
26
+ private expanded;
26
27
  private isStreaming;
27
28
  private forceFullRebuild;
28
29
  private sections;
30
+ private thinkingVisibilityOverrides;
29
31
  constructor(message?: AssistantMessage, hideThinkingBlock?: boolean, markdownTheme?: MarkdownTheme, hiddenThinkingLabel?: string, outputPad?: number, markdownTransformers?: readonly MarkdownTransformer[]);
30
32
  invalidate(): void;
31
33
  setHideThinkingBlock(hide: boolean): void;
34
+ /** Multi-line errors show only their summary until the transcript is fully expanded. */
35
+ setExpanded(expanded: boolean): void;
32
36
  setHiddenThinkingLabel(label: string): void;
33
37
  setOutputPad(padding: number): void;
34
38
  render(width: number): string[];
@@ -36,6 +40,7 @@ export declare class AssistantMessageComponent extends Container {
36
40
  private buildSectionSpecs;
37
41
  private appendContentSpecs;
38
42
  private appendStatusSpecs;
43
+ private errorLabel;
39
44
  /**
40
45
  * Push markdown sections for one content block. While streaming, the block
41
46
  * is split at render-independent boundaries so completed units keep their
@@ -49,6 +54,8 @@ export declare class AssistantMessageComponent extends Container {
49
54
  * still gets it: a non-streaming update always renders whole blocks.
50
55
  */
51
56
  private pushMarkdownSpecs;
57
+ private isThinkingRunHidden;
58
+ private createSection;
52
59
  private createComponent;
53
60
  }
54
61
  //# sourceMappingURL=assistant-message.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"assistant-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAY,KAAK,aAAa,EAAgB,MAAM,wBAAwB,CAAC;AAC/F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAkC7E;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAqC7D;AAcD;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,SAAS;IACvD,OAAO,CAAC,gBAAgB,CAAY;IACpC,OAAO,CAAC,iBAAiB,CAAU;IACnC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,oBAAoB,CAAiC;IAC7D,OAAO,CAAC,WAAW,CAAC,CAAmB;IACvC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,gBAAgB,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAiB;IAEjC,YACC,OAAO,CAAC,EAAE,gBAAgB,EAC1B,iBAAiB,UAAQ,EACzB,aAAa,GAAE,aAAkC,EACjD,mBAAmB,SAAgB,EACnC,SAAS,SAAI,EACb,oBAAoB,GAAE,SAAS,mBAAmB,EAAO,EAiBzD;IAEQ,UAAU,IAAI,IAAI,CAM1B;IAED,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAMxC;IAED,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAM1C;IAED,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAMlC;IAEQ,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAkBvC;IAED,aAAa,CAAC,OAAO,EAAE,gBAAgB,EAAE,WAAW,UAAmB,GAAG,IAAI,CA0C7E;IAED,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,kBAAkB;IAyD1B,OAAO,CAAC,iBAAiB;IAqBzB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,eAAe;CA0BvB","sourcesContent":["import type { AssistantMessage } from \"@earendil-works/pi-ai\";\nimport { Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { MarkdownTransformer } from \"../../../core/extensions/types.ts\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport { createMarkdownTransform } from \"./markdown-transform.ts\";\nimport { withAccentSpine } from \"./message-spine.ts\";\n\nconst OSC133_ZONE_START = \"\\x1b]133;A\\x07\";\nconst OSC133_ZONE_END = \"\\x1b]133;B\\x07\";\nconst OSC133_ZONE_FINAL = \"\\x1b]133;C\\x07\";\n\nconst FENCE_OPENER = /^(```|~~~)/;\nconst FENCE_CLOSER = /^(```|~~~)\\s*$/;\nconst LIST_MARKER = /^([-*+]\\s|\\d+[.)]\\s)/;\nconst QUOTE_MARKER = /^>\\s?/;\nconst INDENTED_CODE = /^(?:\\t| {4})/;\n\nfunction lastNonEmpty(lines: string[]): string | undefined {\n\tfor (let i = lines.length - 1; i >= 0; i--) {\n\t\tif (lines[i].trim() !== \"\") return lines[i];\n\t}\n\treturn undefined;\n}\n\nfunction shouldSplitBefore(next: string, current: string[]): boolean {\n\t// Indented lines can continue indented code blocks; never split there.\n\tif (INDENTED_CODE.test(next)) return false;\n\tconst previous = lastNonEmpty(current);\n\tif (previous && INDENTED_CODE.test(previous)) return false;\n\t// A loose list (\"item\\n\\nitem\") and a blockquote with a blank line render\n\t// as one construct; splitting them would change the output.\n\tif (LIST_MARKER.test(next) && previous && LIST_MARKER.test(previous)) return false;\n\tif (QUOTE_MARKER.test(next) && previous && QUOTE_MARKER.test(previous)) return false;\n\treturn true;\n}\n\n/**\n * Split streamed markdown into render units at boundaries that render\n * independently: closed column-0 code fences, and blank-line block\n * boundaries that cannot continue a preceding construct.\n *\n * The result is prefix-stable: appending text can only add units at the end,\n * never change earlier ones, which is what makes the units cacheable while\n * a message streams.\n */\nexport function splitStreamingMarkdown(text: string): string[] {\n\tif (!text) return [];\n\tconst lines = text.split(\"\\n\");\n\tconst units: string[] = [];\n\tlet current: string[] = [];\n\tlet inFence = false;\n\tconst flush = (): void => {\n\t\tif (current.length > 0) {\n\t\t\tunits.push(current.join(\"\\n\"));\n\t\t\tcurrent = [];\n\t\t}\n\t};\n\tfor (let i = 0; i < lines.length; i++) {\n\t\tconst line = lines[i];\n\t\tif (!inFence && FENCE_OPENER.test(line)) {\n\t\t\tinFence = true;\n\t\t\tcurrent.push(line);\n\t\t\tcontinue;\n\t\t}\n\t\tif (inFence) {\n\t\t\tcurrent.push(line);\n\t\t\tif (FENCE_CLOSER.test(line)) {\n\t\t\t\tflush();\n\t\t\t\tinFence = false;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tcurrent.push(line);\n\t\tif (line.trim() === \"\") {\n\t\t\tconst next = lines[i + 1];\n\t\t\tif (next !== undefined && next.trim() !== \"\" && shouldSplitBefore(next, current)) {\n\t\t\t\tflush();\n\t\t\t}\n\t\t}\n\t}\n\tflush();\n\treturn units;\n}\n\ntype SectionSpec =\n\t| { kind: \"spacer\" }\n\t| { kind: \"markdown-text\"; text: string }\n\t| { kind: \"markdown-thinking\"; text: string }\n\t| { kind: \"label\"; text: string };\n\ntype Section = { spec: SectionSpec; component: Container[\"children\"][number] };\n\nfunction specText(spec: SectionSpec): string | undefined {\n\treturn spec.kind === \"spacer\" ? undefined : spec.text;\n}\n\n/**\n * Component that renders a complete assistant message\n */\nexport class AssistantMessageComponent extends Container {\n\tprivate contentContainer: Container;\n\tprivate hideThinkingBlock: boolean;\n\tprivate markdownTheme: MarkdownTheme;\n\tprivate hiddenThinkingLabel: string;\n\tprivate outputPad: number;\n\tprivate markdownTransformers: readonly MarkdownTransformer[];\n\tprivate lastMessage?: AssistantMessage;\n\tprivate hasToolCalls = false;\n\tprivate isStreaming = false;\n\tprivate forceFullRebuild = true;\n\tprivate sections: Section[] = [];\n\n\tconstructor(\n\t\tmessage?: AssistantMessage,\n\t\thideThinkingBlock = false,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\thiddenThinkingLabel = \"Thinking...\",\n\t\toutputPad = 1,\n\t\tmarkdownTransformers: readonly MarkdownTransformer[] = [],\n\t) {\n\t\tsuper();\n\n\t\tthis.hideThinkingBlock = hideThinkingBlock;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.hiddenThinkingLabel = hiddenThinkingLabel;\n\t\tthis.outputPad = outputPad;\n\t\tthis.markdownTransformers = markdownTransformers;\n\n\t\t// Container for text/thinking content\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\tif (message) {\n\t\t\tthis.updateContent(message);\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tif (this.lastMessage) {\n\t\t\tthis.forceFullRebuild = true;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.hideThinkingBlock = hide;\n\t\tif (this.lastMessage) {\n\t\t\tthis.forceFullRebuild = true;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetHiddenThinkingLabel(label: string): void {\n\t\tthis.hiddenThinkingLabel = label;\n\t\tif (this.lastMessage) {\n\t\t\tthis.forceFullRebuild = true;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetOutputPad(padding: number): void {\n\t\tthis.outputPad = padding;\n\t\tif (this.lastMessage) {\n\t\t\tthis.forceFullRebuild = true;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\toverride render(width: number): string[] {\n\t\tconst lines = super.render(width);\n\t\tif (this.hasToolCalls || lines.length === 0) {\n\t\t\treturn lines;\n\t\t}\n\n\t\t// Keep conversational messages on one visual axis. Tool panels own\n\t\t// their lifecycle spine; assistant text uses the quieter accent rail.\n\t\tif (this.outputPad > 0) {\n\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\tif (lines[i].trim().length > 0) {\n\t\t\t\t\tlines[i] = withAccentSpine(lines[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tlines[0] = OSC133_ZONE_START + lines[0];\n\t\tlines[lines.length - 1] = OSC133_ZONE_END + OSC133_ZONE_FINAL + lines[lines.length - 1];\n\t\treturn lines;\n\t}\n\n\tupdateContent(message: AssistantMessage, isStreaming = this.isStreaming): void {\n\t\tthis.lastMessage = message;\n\t\t// The transform closures capture isStreaming, and non-streaming updates\n\t\t// render whole blocks rather than split units, so an isStreaming flip\n\t\t// rebuilds every section.\n\t\tconst rebuildAll = this.forceFullRebuild || isStreaming !== this.isStreaming;\n\t\tthis.isStreaming = isStreaming;\n\n\t\tconst specs = this.buildSectionSpecs(message);\n\t\tconst sections: Section[] = [];\n\t\tfor (let i = 0; i < specs.length; i++) {\n\t\t\tconst spec = specs[i];\n\t\t\tconst previous = rebuildAll ? undefined : this.sections[i];\n\t\t\tconst sameKind = previous !== undefined && previous.spec.kind === spec.kind;\n\t\t\tif (sameKind && (spec.kind === \"spacer\" || specText(previous.spec) === specText(spec))) {\n\t\t\t\tsections.push({ spec, component: previous.component });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (sameKind && spec.kind !== \"spacer\") {\n\t\t\t\t// Same slot, new content (the growing tail of a streamed\n\t\t\t\t// message): update in place so only this unit re-parses.\n\t\t\t\tconst component = previous.component as Text;\n\t\t\t\tcomponent.setText(specText(spec) ?? \"\");\n\t\t\t\tsections.push({ spec, component: previous.component });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tsections.push({ spec, component: this.createComponent(spec) });\n\t\t}\n\n\t\tthis.forceFullRebuild = false;\n\t\tthis.sections = sections;\n\n\t\tthis.contentContainer.clear();\n\t\tfor (const section of sections) {\n\t\t\tthis.contentContainer.addChild(section.component);\n\t\t}\n\n\t\t// Check if incomplete/failed - show after partial content.\n\t\t// For aborted/error tool calls, tool execution components show the error.\n\t\t// Length stops can happen before a tool call is complete, so surface them here too.\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tthis.hasToolCalls = hasToolCalls;\n\t}\n\n\tprivate buildSectionSpecs(message: AssistantMessage): SectionSpec[] {\n\t\tconst specs: SectionSpec[] = [];\n\t\tthis.appendContentSpecs(message, specs);\n\t\tthis.appendStatusSpecs(message, specs);\n\t\treturn specs;\n\t}\n\n\tprivate appendContentSpecs(message: AssistantMessage, specs: SectionSpec[]): void {\n\t\tconst hasVisibleContent = message.content.some(\n\t\t\t(c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()),\n\t\t);\n\n\t\tif (hasVisibleContent) {\n\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t}\n\n\t\t// Render content in order\n\t\tfor (let i = 0; i < message.content.length; i++) {\n\t\t\tconst content = message.content[i];\n\t\t\tif (content.type === \"text\" && content.text.trim()) {\n\t\t\t\t// Assistant text messages with no background - trim the text\n\t\t\t\t// Set paddingY=0 to avoid extra spacing before tool executions\n\t\t\t\tthis.pushMarkdownSpecs(specs, content.text.trim(), \"markdown-text\");\n\t\t\t} else if (content.type === \"thinking\") {\n\t\t\t\tconst thinkingBlocks: string[] = [];\n\t\t\t\tfor (; i < message.content.length; i++) {\n\t\t\t\t\tconst thinkingContent = message.content[i];\n\t\t\t\t\tif (thinkingContent.type !== \"thinking\") {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tconst thinking = thinkingContent.thinking.trim();\n\t\t\t\t\tif (thinking) {\n\t\t\t\t\t\tthinkingBlocks.push(thinking);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ti--;\n\n\t\t\t\tif (thinkingBlocks.length === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Add spacing only when another visible assistant content block follows.\n\t\t\t\t// This avoids a superfluous blank line before separately-rendered tool execution blocks.\n\t\t\t\tconst hasVisibleContentAfter = message.content\n\t\t\t\t\t.slice(i + 1)\n\t\t\t\t\t.some((c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()));\n\n\t\t\t\tif (this.hideThinkingBlock) {\n\t\t\t\t\t// Show one static label for each run of thinking blocks when hidden.\n\t\t\t\t\tspecs.push({\n\t\t\t\t\t\tkind: \"label\",\n\t\t\t\t\t\ttext: theme.italic(theme.fg(\"thinkingText\", this.hiddenThinkingLabel)),\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\t// Render each run of thinking blocks as one Markdown section.\n\t\t\t\t\tthis.pushMarkdownSpecs(specs, thinkingBlocks.join(\"\\n\\n\"), \"markdown-thinking\");\n\t\t\t\t}\n\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate appendStatusSpecs(message: AssistantMessage, specs: SectionSpec[]): void {\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tif (message.stopReason === \"length\") {\n\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t\tspecs.push({ kind: \"label\", text: theme.fg(\"error\", \"Response was truncated before completion.\") });\n\t\t} else if (!hasToolCalls) {\n\t\t\tif (message.stopReason === \"aborted\") {\n\t\t\t\tconst abortMessage =\n\t\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t\t\tspecs.push({ kind: \"label\", text: theme.fg(\"error\", abortMessage) });\n\t\t\t} else if (message.stopReason === \"error\") {\n\t\t\t\tconst errorMsg = message.errorMessage || \"Unknown error\";\n\t\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t\t\tspecs.push({ kind: \"label\", text: theme.fg(\"error\", `Error: ${errorMsg}`) });\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Push markdown sections for one content block. While streaming, the block\n\t * is split at render-independent boundaries so completed units keep their\n\t * rendered Markdown instances and only the active tail re-parses per\n\t * chunk; otherwise the block renders whole, byte-identical to the\n\t * pre-split behaviour.\n\t *\n\t * Transformers are assumed block-local (the built-in mermaid transformer\n\t * maps tokens and preserves the rest, so per-unit application is\n\t * equivalent). A transformer that genuinely needs whole-message context\n\t * still gets it: a non-streaming update always renders whole blocks.\n\t */\n\tprivate pushMarkdownSpecs(specs: SectionSpec[], text: string, kind: \"markdown-text\" | \"markdown-thinking\"): void {\n\t\tif (this.isStreaming) {\n\t\t\tfor (const unit of splitStreamingMarkdown(text)) {\n\t\t\t\tspecs.push({ kind, text: unit });\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tspecs.push({ kind, text });\n\t}\n\n\tprivate createComponent(spec: SectionSpec): Section[\"component\"] {\n\t\tswitch (spec.kind) {\n\t\t\tcase \"spacer\":\n\t\t\t\treturn new Spacer(1);\n\t\t\tcase \"label\":\n\t\t\t\treturn new Text(spec.text, this.outputPad, 0);\n\t\t\tcase \"markdown-text\":\n\t\t\t\treturn new Markdown(spec.text, this.outputPad, 0, this.markdownTheme, undefined, {\n\t\t\t\t\ttransform: createMarkdownTransform(\"assistant\", this.isStreaming, this.markdownTransformers),\n\t\t\t\t});\n\t\t\tcase \"markdown-thinking\":\n\t\t\t\treturn new Markdown(\n\t\t\t\t\tspec.text,\n\t\t\t\t\tthis.outputPad,\n\t\t\t\t\t0,\n\t\t\t\t\tthis.markdownTheme,\n\t\t\t\t\t{\n\t\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\t\titalic: true,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttransform: createMarkdownTransform(\"assistant-thinking\", this.isStreaming, this.markdownTransformers),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"assistant-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAY,KAAK,aAAa,EAA6B,MAAM,wBAAwB,CAAC;AAC5G,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAmC7E;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAqC7D;AA+BD;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,SAAS;IACvD,OAAO,CAAC,gBAAgB,CAAY;IACpC,OAAO,CAAC,iBAAiB,CAAU;IACnC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,oBAAoB,CAAiC;IAC7D,OAAO,CAAC,WAAW,CAAC,CAAmB;IACvC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,gBAAgB,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,2BAA2B,CAA8B;IAEjE,YACC,OAAO,CAAC,EAAE,gBAAgB,EAC1B,iBAAiB,UAAQ,EACzB,aAAa,GAAE,aAAkC,EACjD,mBAAmB,SAAgB,EACnC,SAAS,SAAI,EACb,oBAAoB,GAAE,SAAS,mBAAmB,EAAO,EAiBzD;IAEQ,UAAU,IAAI,IAAI,CAM1B;IAED,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAOxC;IAED,wFAAwF;IACxF,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAOnC;IAED,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAM1C;IAED,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAMlC;IAEQ,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CASvC;IAED,aAAa,CAAC,OAAO,EAAE,gBAAgB,EAAE,WAAW,UAAmB,GAAG,IAAI,CA2C7E;IAED,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,kBAAkB;IA8D1B,OAAO,CAAC,iBAAiB;IAqBzB,OAAO,CAAC,UAAU;IAKlB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,aAAa;IAarB,OAAO,CAAC,eAAe;CA2BvB","sourcesContent":["import type { AssistantMessage } from \"@earendil-works/pi-ai\";\nimport { Container, Markdown, type MarkdownTheme, MouseRegion, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { MarkdownTransformer } from \"../../../core/extensions/types.ts\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport { collapsedErrorLine, summarizeError } from \"./error-summary.ts\";\nimport { keyHint } from \"./keybinding-hints.ts\";\nimport { createMarkdownTransform } from \"./markdown-transform.ts\";\n\nconst OSC133_ZONE_START = \"\\x1b]133;A\\x07\";\nconst OSC133_ZONE_END = \"\\x1b]133;B\\x07\";\nconst OSC133_ZONE_FINAL = \"\\x1b]133;C\\x07\";\n\nconst FENCE_OPENER = /^(```|~~~)/;\nconst FENCE_CLOSER = /^(```|~~~)\\s*$/;\nconst LIST_MARKER = /^([-*+]\\s|\\d+[.)]\\s)/;\nconst QUOTE_MARKER = /^>\\s?/;\nconst INDENTED_CODE = /^(?:\\t| {4})/;\n\nfunction lastNonEmpty(lines: string[]): string | undefined {\n\tfor (let i = lines.length - 1; i >= 0; i--) {\n\t\tif (lines[i].trim() !== \"\") return lines[i];\n\t}\n\treturn undefined;\n}\n\nfunction shouldSplitBefore(next: string, current: string[]): boolean {\n\t// Indented lines can continue indented code blocks; never split there.\n\tif (INDENTED_CODE.test(next)) return false;\n\tconst previous = lastNonEmpty(current);\n\tif (previous && INDENTED_CODE.test(previous)) return false;\n\t// A loose list (\"item\\n\\nitem\") and a blockquote with a blank line render\n\t// as one construct; splitting them would change the output.\n\tif (LIST_MARKER.test(next) && previous && LIST_MARKER.test(previous)) return false;\n\tif (QUOTE_MARKER.test(next) && previous && QUOTE_MARKER.test(previous)) return false;\n\treturn true;\n}\n\n/**\n * Split streamed markdown into render units at boundaries that render\n * independently: closed column-0 code fences, and blank-line block\n * boundaries that cannot continue a preceding construct.\n *\n * The result is prefix-stable: appending text can only add units at the end,\n * never change earlier ones, which is what makes the units cacheable while\n * a message streams.\n */\nexport function splitStreamingMarkdown(text: string): string[] {\n\tif (!text) return [];\n\tconst lines = text.split(\"\\n\");\n\tconst units: string[] = [];\n\tlet current: string[] = [];\n\tlet inFence = false;\n\tconst flush = (): void => {\n\t\tif (current.length > 0) {\n\t\t\tunits.push(current.join(\"\\n\"));\n\t\t\tcurrent = [];\n\t\t}\n\t};\n\tfor (let i = 0; i < lines.length; i++) {\n\t\tconst line = lines[i];\n\t\tif (!inFence && FENCE_OPENER.test(line)) {\n\t\t\tinFence = true;\n\t\t\tcurrent.push(line);\n\t\t\tcontinue;\n\t\t}\n\t\tif (inFence) {\n\t\t\tcurrent.push(line);\n\t\t\tif (FENCE_CLOSER.test(line)) {\n\t\t\t\tflush();\n\t\t\t\tinFence = false;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tcurrent.push(line);\n\t\tif (line.trim() === \"\") {\n\t\t\tconst next = lines[i + 1];\n\t\t\tif (next !== undefined && next.trim() !== \"\" && shouldSplitBefore(next, current)) {\n\t\t\t\tflush();\n\t\t\t}\n\t\t}\n\t}\n\tflush();\n\treturn units;\n}\n\n/**\n * `run` numbers the message's thinking runs in order. It keys the per-run\n * visibility override that a click toggles, so two thinking sections are the\n * same slot only when they belong to the same run.\n */\ntype SectionSpec =\n\t| { kind: \"spacer\" }\n\t| { kind: \"markdown-text\"; text: string }\n\t| { kind: \"markdown-thinking\"; text: string; run: number }\n\t| { kind: \"thinking-label\"; text: string; run: number }\n\t| { kind: \"label\"; text: string };\n\ntype SectionComponent = Container[\"children\"][number];\n\n/**\n * `content` is the Text or Markdown whose text an in-place update replaces;\n * `component` is what the container holds, which for a thinking section is a\n * MouseRegion wrapping `content`.\n */\ntype Section = { spec: SectionSpec; component: SectionComponent; content: SectionComponent };\n\nfunction specText(spec: SectionSpec): string | undefined {\n\treturn spec.kind === \"spacer\" ? undefined : spec.text;\n}\n\nfunction specRun(spec: SectionSpec): number | undefined {\n\treturn spec.kind === \"markdown-thinking\" || spec.kind === \"thinking-label\" ? spec.run : undefined;\n}\n\n/**\n * Component that renders a complete assistant message\n */\nexport class AssistantMessageComponent extends Container {\n\tprivate contentContainer: Container;\n\tprivate hideThinkingBlock: boolean;\n\tprivate markdownTheme: MarkdownTheme;\n\tprivate hiddenThinkingLabel: string;\n\tprivate outputPad: number;\n\tprivate markdownTransformers: readonly MarkdownTransformer[];\n\tprivate lastMessage?: AssistantMessage;\n\tprivate hasToolCalls = false;\n\tprivate expanded = false;\n\tprivate isStreaming = false;\n\tprivate forceFullRebuild = true;\n\tprivate sections: Section[] = [];\n\tprivate thinkingVisibilityOverrides = new Map<number, boolean>();\n\n\tconstructor(\n\t\tmessage?: AssistantMessage,\n\t\thideThinkingBlock = false,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\thiddenThinkingLabel = \"Thinking...\",\n\t\toutputPad = 1,\n\t\tmarkdownTransformers: readonly MarkdownTransformer[] = [],\n\t) {\n\t\tsuper();\n\n\t\tthis.hideThinkingBlock = hideThinkingBlock;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.hiddenThinkingLabel = hiddenThinkingLabel;\n\t\tthis.outputPad = outputPad;\n\t\tthis.markdownTransformers = markdownTransformers;\n\n\t\t// Container for text/thinking content\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\tif (message) {\n\t\t\tthis.updateContent(message);\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tif (this.lastMessage) {\n\t\t\tthis.forceFullRebuild = true;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.hideThinkingBlock = hide;\n\t\tthis.thinkingVisibilityOverrides.clear();\n\t\tif (this.lastMessage) {\n\t\t\tthis.forceFullRebuild = true;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\t/** Multi-line errors show only their summary until the transcript is fully expanded. */\n\tsetExpanded(expanded: boolean): void {\n\t\tif (this.expanded === expanded) return;\n\t\tthis.expanded = expanded;\n\t\tif (this.lastMessage) {\n\t\t\tthis.forceFullRebuild = true;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetHiddenThinkingLabel(label: string): void {\n\t\tthis.hiddenThinkingLabel = label;\n\t\tif (this.lastMessage) {\n\t\t\tthis.forceFullRebuild = true;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetOutputPad(padding: number): void {\n\t\tthis.outputPad = padding;\n\t\tif (this.lastMessage) {\n\t\t\tthis.forceFullRebuild = true;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\toverride render(width: number): string[] {\n\t\tconst lines = super.render(width);\n\t\tif (this.hasToolCalls || lines.length === 0) {\n\t\t\treturn lines;\n\t\t}\n\n\t\tlines[0] = OSC133_ZONE_START + lines[0];\n\t\tlines[lines.length - 1] = OSC133_ZONE_END + OSC133_ZONE_FINAL + lines[lines.length - 1];\n\t\treturn lines;\n\t}\n\n\tupdateContent(message: AssistantMessage, isStreaming = this.isStreaming): void {\n\t\tthis.lastMessage = message;\n\t\t// The transform closures capture isStreaming, and non-streaming updates\n\t\t// render whole blocks rather than split units, so an isStreaming flip\n\t\t// rebuilds every section.\n\t\tconst rebuildAll = this.forceFullRebuild || isStreaming !== this.isStreaming;\n\t\tthis.isStreaming = isStreaming;\n\n\t\tconst specs = this.buildSectionSpecs(message);\n\t\tconst sections: Section[] = [];\n\t\tfor (let i = 0; i < specs.length; i++) {\n\t\t\tconst spec = specs[i];\n\t\t\tconst previous = rebuildAll ? undefined : this.sections[i];\n\t\t\tconst sameKind =\n\t\t\t\tprevious !== undefined && previous.spec.kind === spec.kind && specRun(previous.spec) === specRun(spec);\n\t\t\tif (sameKind && (spec.kind === \"spacer\" || specText(previous.spec) === specText(spec))) {\n\t\t\t\tsections.push({ ...previous, spec });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (sameKind && spec.kind !== \"spacer\") {\n\t\t\t\t// Same slot, new content (the growing tail of a streamed\n\t\t\t\t// message): update in place so only this unit re-parses.\n\t\t\t\tconst content = previous.content as Text;\n\t\t\t\tcontent.setText(specText(spec) ?? \"\");\n\t\t\t\tsections.push({ ...previous, spec });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tsections.push(this.createSection(spec));\n\t\t}\n\n\t\tthis.forceFullRebuild = false;\n\t\tthis.sections = sections;\n\n\t\tthis.contentContainer.clear();\n\t\tfor (const section of sections) {\n\t\t\tthis.contentContainer.addChild(section.component);\n\t\t}\n\n\t\t// Check if incomplete/failed - show after partial content.\n\t\t// For aborted/error tool calls, tool execution components show the error.\n\t\t// Length stops can happen before a tool call is complete, so surface them here too.\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tthis.hasToolCalls = hasToolCalls;\n\t}\n\n\tprivate buildSectionSpecs(message: AssistantMessage): SectionSpec[] {\n\t\tconst specs: SectionSpec[] = [];\n\t\tthis.appendContentSpecs(message, specs);\n\t\tthis.appendStatusSpecs(message, specs);\n\t\treturn specs;\n\t}\n\n\tprivate appendContentSpecs(message: AssistantMessage, specs: SectionSpec[]): void {\n\t\tconst hasVisibleContent = message.content.some(\n\t\t\t(c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()),\n\t\t);\n\n\t\tif (hasVisibleContent) {\n\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t}\n\n\t\t// Render content in order\n\t\tlet thinkingRunIndex = 0;\n\t\tfor (let i = 0; i < message.content.length; i++) {\n\t\t\tconst content = message.content[i];\n\t\t\tif (content.type === \"text\" && content.text.trim()) {\n\t\t\t\t// Assistant text messages with no background - trim the text\n\t\t\t\t// Set paddingY=0 to avoid extra spacing before tool executions\n\t\t\t\tthis.pushMarkdownSpecs(specs, content.text.trim(), { kind: \"markdown-text\" });\n\t\t\t} else if (content.type === \"thinking\") {\n\t\t\t\tconst thinkingBlocks: string[] = [];\n\t\t\t\tfor (; i < message.content.length; i++) {\n\t\t\t\t\tconst thinkingContent = message.content[i];\n\t\t\t\t\tif (thinkingContent.type !== \"thinking\") {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tconst thinking = thinkingContent.thinking.trim();\n\t\t\t\t\tif (thinking) {\n\t\t\t\t\t\tthinkingBlocks.push(thinking);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ti--;\n\n\t\t\t\tif (thinkingBlocks.length === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Add spacing only when another visible assistant content block follows.\n\t\t\t\t// This avoids a superfluous blank line before separately-rendered tool execution blocks.\n\t\t\t\tconst hasVisibleContentAfter = message.content\n\t\t\t\t\t.slice(i + 1)\n\t\t\t\t\t.some((c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()));\n\n\t\t\t\t// Each run can be expanded or collapsed on its own by clicking it; the\n\t\t\t\t// global hide setting is the default for runs nobody has clicked.\n\t\t\t\tconst run = thinkingRunIndex++;\n\t\t\t\tif (this.isThinkingRunHidden(run)) {\n\t\t\t\t\t// Show one static label for each run of thinking blocks when hidden.\n\t\t\t\t\tspecs.push({\n\t\t\t\t\t\tkind: \"thinking-label\",\n\t\t\t\t\t\ttext: `${theme.italic(theme.fg(\"thinkingText\", this.hiddenThinkingLabel))} ${keyHint(\"app.tools.expand\", \"to expand\")}`,\n\t\t\t\t\t\trun,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\t// Render each run of thinking blocks as one Markdown section.\n\t\t\t\t\tthis.pushMarkdownSpecs(specs, thinkingBlocks.join(\"\\n\\n\"), { kind: \"markdown-thinking\", run });\n\t\t\t\t}\n\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate appendStatusSpecs(message: AssistantMessage, specs: SectionSpec[]): void {\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tif (message.stopReason === \"length\") {\n\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t\tspecs.push({ kind: \"label\", text: theme.fg(\"error\", \"Response was truncated before completion.\") });\n\t\t} else if (!hasToolCalls) {\n\t\t\tif (message.stopReason === \"aborted\") {\n\t\t\t\tconst abortMessage =\n\t\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t\t\tspecs.push({ kind: \"label\", text: this.errorLabel(abortMessage) });\n\t\t\t} else if (message.stopReason === \"error\") {\n\t\t\t\tconst errorMsg = message.errorMessage || \"Unknown error\";\n\t\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t\t\tspecs.push({ kind: \"label\", text: this.errorLabel(`Error: ${errorMsg}`) });\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate errorLabel(text: string): string {\n\t\tconst summary = this.expanded ? undefined : summarizeError(text);\n\t\treturn summary === undefined ? theme.fg(\"error\", text) : collapsedErrorLine(theme.fg(\"error\", summary));\n\t}\n\n\t/**\n\t * Push markdown sections for one content block. While streaming, the block\n\t * is split at render-independent boundaries so completed units keep their\n\t * rendered Markdown instances and only the active tail re-parses per\n\t * chunk; otherwise the block renders whole, byte-identical to the\n\t * pre-split behaviour.\n\t *\n\t * Transformers are assumed block-local (the built-in mermaid transformer\n\t * maps tokens and preserves the rest, so per-unit application is\n\t * equivalent). A transformer that genuinely needs whole-message context\n\t * still gets it: a non-streaming update always renders whole blocks.\n\t */\n\tprivate pushMarkdownSpecs(\n\t\tspecs: SectionSpec[],\n\t\ttext: string,\n\t\tslot: { kind: \"markdown-text\" } | { kind: \"markdown-thinking\"; run: number },\n\t): void {\n\t\tif (this.isStreaming) {\n\t\t\tfor (const unit of splitStreamingMarkdown(text)) {\n\t\t\t\tspecs.push({ ...slot, text: unit });\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tspecs.push({ ...slot, text });\n\t}\n\n\tprivate isThinkingRunHidden(run: number): boolean {\n\t\treturn this.thinkingVisibilityOverrides.get(run) ?? this.hideThinkingBlock;\n\t}\n\n\tprivate createSection(spec: SectionSpec): Section {\n\t\tconst content = this.createComponent(spec);\n\t\tconst run = specRun(spec);\n\t\tif (run === undefined) return { spec, component: content, content };\n\t\tconst component = new MouseRegion(content, (event) => {\n\t\t\tif (event.type !== \"click\" || event.button !== \"left\") return undefined;\n\t\t\tthis.thinkingVisibilityOverrides.set(run, !this.isThinkingRunHidden(run));\n\t\t\tif (this.lastMessage) this.updateContent(this.lastMessage);\n\t\t\treturn { handled: true };\n\t\t});\n\t\treturn { spec, component, content };\n\t}\n\n\tprivate createComponent(spec: SectionSpec): SectionComponent {\n\t\tswitch (spec.kind) {\n\t\t\tcase \"spacer\":\n\t\t\t\treturn new Spacer(1);\n\t\t\tcase \"label\":\n\t\t\tcase \"thinking-label\":\n\t\t\t\treturn new Text(spec.text, this.outputPad, 0);\n\t\t\tcase \"markdown-text\":\n\t\t\t\treturn new Markdown(spec.text, this.outputPad, 0, this.markdownTheme, undefined, {\n\t\t\t\t\ttransform: createMarkdownTransform(\"assistant\", this.isStreaming, this.markdownTransformers),\n\t\t\t\t});\n\t\t\tcase \"markdown-thinking\":\n\t\t\t\treturn new Markdown(\n\t\t\t\t\tspec.text,\n\t\t\t\t\tthis.outputPad,\n\t\t\t\t\t0,\n\t\t\t\t\tthis.markdownTheme,\n\t\t\t\t\t{\n\t\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\t\titalic: true,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttransform: createMarkdownTransform(\"assistant-thinking\", this.isStreaming, this.markdownTransformers),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t}\n\t}\n}\n"]}
@@ -1,7 +1,8 @@
1
- import { Container, Markdown, Spacer, Text } from "@earendil-works/pi-tui";
1
+ import { Container, Markdown, MouseRegion, Spacer, Text } from "@earendil-works/pi-tui";
2
2
  import { getMarkdownTheme, theme } from "../theme/theme.js";
3
+ import { collapsedErrorLine, summarizeError } from "./error-summary.js";
4
+ import { keyHint } from "./keybinding-hints.js";
3
5
  import { createMarkdownTransform } from "./markdown-transform.js";
4
- import { withAccentSpine } from "./message-spine.js";
5
6
  const OSC133_ZONE_START = "\x1b]133;A\x07";
6
7
  const OSC133_ZONE_END = "\x1b]133;B\x07";
7
8
  const OSC133_ZONE_FINAL = "\x1b]133;C\x07";
@@ -83,6 +84,9 @@ export function splitStreamingMarkdown(text) {
83
84
  function specText(spec) {
84
85
  return spec.kind === "spacer" ? undefined : spec.text;
85
86
  }
87
+ function specRun(spec) {
88
+ return spec.kind === "markdown-thinking" || spec.kind === "thinking-label" ? spec.run : undefined;
89
+ }
86
90
  /**
87
91
  * Component that renders a complete assistant message
88
92
  */
@@ -95,9 +99,11 @@ export class AssistantMessageComponent extends Container {
95
99
  markdownTransformers;
96
100
  lastMessage;
97
101
  hasToolCalls = false;
102
+ expanded = false;
98
103
  isStreaming = false;
99
104
  forceFullRebuild = true;
100
105
  sections = [];
106
+ thinkingVisibilityOverrides = new Map();
101
107
  constructor(message, hideThinkingBlock = false, markdownTheme = getMarkdownTheme(), hiddenThinkingLabel = "Thinking...", outputPad = 1, markdownTransformers = []) {
102
108
  super();
103
109
  this.hideThinkingBlock = hideThinkingBlock;
@@ -121,6 +127,17 @@ export class AssistantMessageComponent extends Container {
121
127
  }
122
128
  setHideThinkingBlock(hide) {
123
129
  this.hideThinkingBlock = hide;
130
+ this.thinkingVisibilityOverrides.clear();
131
+ if (this.lastMessage) {
132
+ this.forceFullRebuild = true;
133
+ this.updateContent(this.lastMessage);
134
+ }
135
+ }
136
+ /** Multi-line errors show only their summary until the transcript is fully expanded. */
137
+ setExpanded(expanded) {
138
+ if (this.expanded === expanded)
139
+ return;
140
+ this.expanded = expanded;
124
141
  if (this.lastMessage) {
125
142
  this.forceFullRebuild = true;
126
143
  this.updateContent(this.lastMessage);
@@ -145,15 +162,6 @@ export class AssistantMessageComponent extends Container {
145
162
  if (this.hasToolCalls || lines.length === 0) {
146
163
  return lines;
147
164
  }
148
- // Keep conversational messages on one visual axis. Tool panels own
149
- // their lifecycle spine; assistant text uses the quieter accent rail.
150
- if (this.outputPad > 0) {
151
- for (let i = 0; i < lines.length; i++) {
152
- if (lines[i].trim().length > 0) {
153
- lines[i] = withAccentSpine(lines[i]);
154
- }
155
- }
156
- }
157
165
  lines[0] = OSC133_ZONE_START + lines[0];
158
166
  lines[lines.length - 1] = OSC133_ZONE_END + OSC133_ZONE_FINAL + lines[lines.length - 1];
159
167
  return lines;
@@ -170,20 +178,20 @@ export class AssistantMessageComponent extends Container {
170
178
  for (let i = 0; i < specs.length; i++) {
171
179
  const spec = specs[i];
172
180
  const previous = rebuildAll ? undefined : this.sections[i];
173
- const sameKind = previous !== undefined && previous.spec.kind === spec.kind;
181
+ const sameKind = previous !== undefined && previous.spec.kind === spec.kind && specRun(previous.spec) === specRun(spec);
174
182
  if (sameKind && (spec.kind === "spacer" || specText(previous.spec) === specText(spec))) {
175
- sections.push({ spec, component: previous.component });
183
+ sections.push({ ...previous, spec });
176
184
  continue;
177
185
  }
178
186
  if (sameKind && spec.kind !== "spacer") {
179
187
  // Same slot, new content (the growing tail of a streamed
180
188
  // message): update in place so only this unit re-parses.
181
- const component = previous.component;
182
- component.setText(specText(spec) ?? "");
183
- sections.push({ spec, component: previous.component });
189
+ const content = previous.content;
190
+ content.setText(specText(spec) ?? "");
191
+ sections.push({ ...previous, spec });
184
192
  continue;
185
193
  }
186
- sections.push({ spec, component: this.createComponent(spec) });
194
+ sections.push(this.createSection(spec));
187
195
  }
188
196
  this.forceFullRebuild = false;
189
197
  this.sections = sections;
@@ -209,12 +217,13 @@ export class AssistantMessageComponent extends Container {
209
217
  specs.push({ kind: "spacer" });
210
218
  }
211
219
  // Render content in order
220
+ let thinkingRunIndex = 0;
212
221
  for (let i = 0; i < message.content.length; i++) {
213
222
  const content = message.content[i];
214
223
  if (content.type === "text" && content.text.trim()) {
215
224
  // Assistant text messages with no background - trim the text
216
225
  // Set paddingY=0 to avoid extra spacing before tool executions
217
- this.pushMarkdownSpecs(specs, content.text.trim(), "markdown-text");
226
+ this.pushMarkdownSpecs(specs, content.text.trim(), { kind: "markdown-text" });
218
227
  }
219
228
  else if (content.type === "thinking") {
220
229
  const thinkingBlocks = [];
@@ -237,16 +246,20 @@ export class AssistantMessageComponent extends Container {
237
246
  const hasVisibleContentAfter = message.content
238
247
  .slice(i + 1)
239
248
  .some((c) => (c.type === "text" && c.text.trim()) || (c.type === "thinking" && c.thinking.trim()));
240
- if (this.hideThinkingBlock) {
249
+ // Each run can be expanded or collapsed on its own by clicking it; the
250
+ // global hide setting is the default for runs nobody has clicked.
251
+ const run = thinkingRunIndex++;
252
+ if (this.isThinkingRunHidden(run)) {
241
253
  // Show one static label for each run of thinking blocks when hidden.
242
254
  specs.push({
243
- kind: "label",
244
- text: theme.italic(theme.fg("thinkingText", this.hiddenThinkingLabel)),
255
+ kind: "thinking-label",
256
+ text: `${theme.italic(theme.fg("thinkingText", this.hiddenThinkingLabel))} ${keyHint("app.tools.expand", "to expand")}`,
257
+ run,
245
258
  });
246
259
  }
247
260
  else {
248
261
  // Render each run of thinking blocks as one Markdown section.
249
- this.pushMarkdownSpecs(specs, thinkingBlocks.join("\n\n"), "markdown-thinking");
262
+ this.pushMarkdownSpecs(specs, thinkingBlocks.join("\n\n"), { kind: "markdown-thinking", run });
250
263
  }
251
264
  if (hasVisibleContentAfter) {
252
265
  specs.push({ kind: "spacer" });
@@ -266,15 +279,19 @@ export class AssistantMessageComponent extends Container {
266
279
  ? message.errorMessage
267
280
  : "Operation aborted";
268
281
  specs.push({ kind: "spacer" });
269
- specs.push({ kind: "label", text: theme.fg("error", abortMessage) });
282
+ specs.push({ kind: "label", text: this.errorLabel(abortMessage) });
270
283
  }
271
284
  else if (message.stopReason === "error") {
272
285
  const errorMsg = message.errorMessage || "Unknown error";
273
286
  specs.push({ kind: "spacer" });
274
- specs.push({ kind: "label", text: theme.fg("error", `Error: ${errorMsg}`) });
287
+ specs.push({ kind: "label", text: this.errorLabel(`Error: ${errorMsg}`) });
275
288
  }
276
289
  }
277
290
  }
291
+ errorLabel(text) {
292
+ const summary = this.expanded ? undefined : summarizeError(text);
293
+ return summary === undefined ? theme.fg("error", text) : collapsedErrorLine(theme.fg("error", summary));
294
+ }
278
295
  /**
279
296
  * Push markdown sections for one content block. While streaming, the block
280
297
  * is split at render-independent boundaries so completed units keep their
@@ -287,20 +304,39 @@ export class AssistantMessageComponent extends Container {
287
304
  * equivalent). A transformer that genuinely needs whole-message context
288
305
  * still gets it: a non-streaming update always renders whole blocks.
289
306
  */
290
- pushMarkdownSpecs(specs, text, kind) {
307
+ pushMarkdownSpecs(specs, text, slot) {
291
308
  if (this.isStreaming) {
292
309
  for (const unit of splitStreamingMarkdown(text)) {
293
- specs.push({ kind, text: unit });
310
+ specs.push({ ...slot, text: unit });
294
311
  }
295
312
  return;
296
313
  }
297
- specs.push({ kind, text });
314
+ specs.push({ ...slot, text });
315
+ }
316
+ isThinkingRunHidden(run) {
317
+ return this.thinkingVisibilityOverrides.get(run) ?? this.hideThinkingBlock;
318
+ }
319
+ createSection(spec) {
320
+ const content = this.createComponent(spec);
321
+ const run = specRun(spec);
322
+ if (run === undefined)
323
+ return { spec, component: content, content };
324
+ const component = new MouseRegion(content, (event) => {
325
+ if (event.type !== "click" || event.button !== "left")
326
+ return undefined;
327
+ this.thinkingVisibilityOverrides.set(run, !this.isThinkingRunHidden(run));
328
+ if (this.lastMessage)
329
+ this.updateContent(this.lastMessage);
330
+ return { handled: true };
331
+ });
332
+ return { spec, component, content };
298
333
  }
299
334
  createComponent(spec) {
300
335
  switch (spec.kind) {
301
336
  case "spacer":
302
337
  return new Spacer(1);
303
338
  case "label":
339
+ case "thinking-label":
304
340
  return new Text(spec.text, this.outputPad, 0);
305
341
  case "markdown-text":
306
342
  return new Markdown(spec.text, this.outputPad, 0, this.markdownTheme, undefined, {
@@ -1 +1 @@
1
- {"version":3,"file":"assistant-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-message.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AssistantMessage } from \"@earendil-works/pi-ai\";\nimport { Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { MarkdownTransformer } from \"../../../core/extensions/types.ts\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport { createMarkdownTransform } from \"./markdown-transform.ts\";\nimport { withAccentSpine } from \"./message-spine.ts\";\n\nconst OSC133_ZONE_START = \"\\x1b]133;A\\x07\";\nconst OSC133_ZONE_END = \"\\x1b]133;B\\x07\";\nconst OSC133_ZONE_FINAL = \"\\x1b]133;C\\x07\";\n\nconst FENCE_OPENER = /^(```|~~~)/;\nconst FENCE_CLOSER = /^(```|~~~)\\s*$/;\nconst LIST_MARKER = /^([-*+]\\s|\\d+[.)]\\s)/;\nconst QUOTE_MARKER = /^>\\s?/;\nconst INDENTED_CODE = /^(?:\\t| {4})/;\n\nfunction lastNonEmpty(lines: string[]): string | undefined {\n\tfor (let i = lines.length - 1; i >= 0; i--) {\n\t\tif (lines[i].trim() !== \"\") return lines[i];\n\t}\n\treturn undefined;\n}\n\nfunction shouldSplitBefore(next: string, current: string[]): boolean {\n\t// Indented lines can continue indented code blocks; never split there.\n\tif (INDENTED_CODE.test(next)) return false;\n\tconst previous = lastNonEmpty(current);\n\tif (previous && INDENTED_CODE.test(previous)) return false;\n\t// A loose list (\"item\\n\\nitem\") and a blockquote with a blank line render\n\t// as one construct; splitting them would change the output.\n\tif (LIST_MARKER.test(next) && previous && LIST_MARKER.test(previous)) return false;\n\tif (QUOTE_MARKER.test(next) && previous && QUOTE_MARKER.test(previous)) return false;\n\treturn true;\n}\n\n/**\n * Split streamed markdown into render units at boundaries that render\n * independently: closed column-0 code fences, and blank-line block\n * boundaries that cannot continue a preceding construct.\n *\n * The result is prefix-stable: appending text can only add units at the end,\n * never change earlier ones, which is what makes the units cacheable while\n * a message streams.\n */\nexport function splitStreamingMarkdown(text: string): string[] {\n\tif (!text) return [];\n\tconst lines = text.split(\"\\n\");\n\tconst units: string[] = [];\n\tlet current: string[] = [];\n\tlet inFence = false;\n\tconst flush = (): void => {\n\t\tif (current.length > 0) {\n\t\t\tunits.push(current.join(\"\\n\"));\n\t\t\tcurrent = [];\n\t\t}\n\t};\n\tfor (let i = 0; i < lines.length; i++) {\n\t\tconst line = lines[i];\n\t\tif (!inFence && FENCE_OPENER.test(line)) {\n\t\t\tinFence = true;\n\t\t\tcurrent.push(line);\n\t\t\tcontinue;\n\t\t}\n\t\tif (inFence) {\n\t\t\tcurrent.push(line);\n\t\t\tif (FENCE_CLOSER.test(line)) {\n\t\t\t\tflush();\n\t\t\t\tinFence = false;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tcurrent.push(line);\n\t\tif (line.trim() === \"\") {\n\t\t\tconst next = lines[i + 1];\n\t\t\tif (next !== undefined && next.trim() !== \"\" && shouldSplitBefore(next, current)) {\n\t\t\t\tflush();\n\t\t\t}\n\t\t}\n\t}\n\tflush();\n\treturn units;\n}\n\ntype SectionSpec =\n\t| { kind: \"spacer\" }\n\t| { kind: \"markdown-text\"; text: string }\n\t| { kind: \"markdown-thinking\"; text: string }\n\t| { kind: \"label\"; text: string };\n\ntype Section = { spec: SectionSpec; component: Container[\"children\"][number] };\n\nfunction specText(spec: SectionSpec): string | undefined {\n\treturn spec.kind === \"spacer\" ? undefined : spec.text;\n}\n\n/**\n * Component that renders a complete assistant message\n */\nexport class AssistantMessageComponent extends Container {\n\tprivate contentContainer: Container;\n\tprivate hideThinkingBlock: boolean;\n\tprivate markdownTheme: MarkdownTheme;\n\tprivate hiddenThinkingLabel: string;\n\tprivate outputPad: number;\n\tprivate markdownTransformers: readonly MarkdownTransformer[];\n\tprivate lastMessage?: AssistantMessage;\n\tprivate hasToolCalls = false;\n\tprivate isStreaming = false;\n\tprivate forceFullRebuild = true;\n\tprivate sections: Section[] = [];\n\n\tconstructor(\n\t\tmessage?: AssistantMessage,\n\t\thideThinkingBlock = false,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\thiddenThinkingLabel = \"Thinking...\",\n\t\toutputPad = 1,\n\t\tmarkdownTransformers: readonly MarkdownTransformer[] = [],\n\t) {\n\t\tsuper();\n\n\t\tthis.hideThinkingBlock = hideThinkingBlock;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.hiddenThinkingLabel = hiddenThinkingLabel;\n\t\tthis.outputPad = outputPad;\n\t\tthis.markdownTransformers = markdownTransformers;\n\n\t\t// Container for text/thinking content\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\tif (message) {\n\t\t\tthis.updateContent(message);\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tif (this.lastMessage) {\n\t\t\tthis.forceFullRebuild = true;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.hideThinkingBlock = hide;\n\t\tif (this.lastMessage) {\n\t\t\tthis.forceFullRebuild = true;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetHiddenThinkingLabel(label: string): void {\n\t\tthis.hiddenThinkingLabel = label;\n\t\tif (this.lastMessage) {\n\t\t\tthis.forceFullRebuild = true;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetOutputPad(padding: number): void {\n\t\tthis.outputPad = padding;\n\t\tif (this.lastMessage) {\n\t\t\tthis.forceFullRebuild = true;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\toverride render(width: number): string[] {\n\t\tconst lines = super.render(width);\n\t\tif (this.hasToolCalls || lines.length === 0) {\n\t\t\treturn lines;\n\t\t}\n\n\t\t// Keep conversational messages on one visual axis. Tool panels own\n\t\t// their lifecycle spine; assistant text uses the quieter accent rail.\n\t\tif (this.outputPad > 0) {\n\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\tif (lines[i].trim().length > 0) {\n\t\t\t\t\tlines[i] = withAccentSpine(lines[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tlines[0] = OSC133_ZONE_START + lines[0];\n\t\tlines[lines.length - 1] = OSC133_ZONE_END + OSC133_ZONE_FINAL + lines[lines.length - 1];\n\t\treturn lines;\n\t}\n\n\tupdateContent(message: AssistantMessage, isStreaming = this.isStreaming): void {\n\t\tthis.lastMessage = message;\n\t\t// The transform closures capture isStreaming, and non-streaming updates\n\t\t// render whole blocks rather than split units, so an isStreaming flip\n\t\t// rebuilds every section.\n\t\tconst rebuildAll = this.forceFullRebuild || isStreaming !== this.isStreaming;\n\t\tthis.isStreaming = isStreaming;\n\n\t\tconst specs = this.buildSectionSpecs(message);\n\t\tconst sections: Section[] = [];\n\t\tfor (let i = 0; i < specs.length; i++) {\n\t\t\tconst spec = specs[i];\n\t\t\tconst previous = rebuildAll ? undefined : this.sections[i];\n\t\t\tconst sameKind = previous !== undefined && previous.spec.kind === spec.kind;\n\t\t\tif (sameKind && (spec.kind === \"spacer\" || specText(previous.spec) === specText(spec))) {\n\t\t\t\tsections.push({ spec, component: previous.component });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (sameKind && spec.kind !== \"spacer\") {\n\t\t\t\t// Same slot, new content (the growing tail of a streamed\n\t\t\t\t// message): update in place so only this unit re-parses.\n\t\t\t\tconst component = previous.component as Text;\n\t\t\t\tcomponent.setText(specText(spec) ?? \"\");\n\t\t\t\tsections.push({ spec, component: previous.component });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tsections.push({ spec, component: this.createComponent(spec) });\n\t\t}\n\n\t\tthis.forceFullRebuild = false;\n\t\tthis.sections = sections;\n\n\t\tthis.contentContainer.clear();\n\t\tfor (const section of sections) {\n\t\t\tthis.contentContainer.addChild(section.component);\n\t\t}\n\n\t\t// Check if incomplete/failed - show after partial content.\n\t\t// For aborted/error tool calls, tool execution components show the error.\n\t\t// Length stops can happen before a tool call is complete, so surface them here too.\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tthis.hasToolCalls = hasToolCalls;\n\t}\n\n\tprivate buildSectionSpecs(message: AssistantMessage): SectionSpec[] {\n\t\tconst specs: SectionSpec[] = [];\n\t\tthis.appendContentSpecs(message, specs);\n\t\tthis.appendStatusSpecs(message, specs);\n\t\treturn specs;\n\t}\n\n\tprivate appendContentSpecs(message: AssistantMessage, specs: SectionSpec[]): void {\n\t\tconst hasVisibleContent = message.content.some(\n\t\t\t(c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()),\n\t\t);\n\n\t\tif (hasVisibleContent) {\n\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t}\n\n\t\t// Render content in order\n\t\tfor (let i = 0; i < message.content.length; i++) {\n\t\t\tconst content = message.content[i];\n\t\t\tif (content.type === \"text\" && content.text.trim()) {\n\t\t\t\t// Assistant text messages with no background - trim the text\n\t\t\t\t// Set paddingY=0 to avoid extra spacing before tool executions\n\t\t\t\tthis.pushMarkdownSpecs(specs, content.text.trim(), \"markdown-text\");\n\t\t\t} else if (content.type === \"thinking\") {\n\t\t\t\tconst thinkingBlocks: string[] = [];\n\t\t\t\tfor (; i < message.content.length; i++) {\n\t\t\t\t\tconst thinkingContent = message.content[i];\n\t\t\t\t\tif (thinkingContent.type !== \"thinking\") {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tconst thinking = thinkingContent.thinking.trim();\n\t\t\t\t\tif (thinking) {\n\t\t\t\t\t\tthinkingBlocks.push(thinking);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ti--;\n\n\t\t\t\tif (thinkingBlocks.length === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Add spacing only when another visible assistant content block follows.\n\t\t\t\t// This avoids a superfluous blank line before separately-rendered tool execution blocks.\n\t\t\t\tconst hasVisibleContentAfter = message.content\n\t\t\t\t\t.slice(i + 1)\n\t\t\t\t\t.some((c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()));\n\n\t\t\t\tif (this.hideThinkingBlock) {\n\t\t\t\t\t// Show one static label for each run of thinking blocks when hidden.\n\t\t\t\t\tspecs.push({\n\t\t\t\t\t\tkind: \"label\",\n\t\t\t\t\t\ttext: theme.italic(theme.fg(\"thinkingText\", this.hiddenThinkingLabel)),\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\t// Render each run of thinking blocks as one Markdown section.\n\t\t\t\t\tthis.pushMarkdownSpecs(specs, thinkingBlocks.join(\"\\n\\n\"), \"markdown-thinking\");\n\t\t\t\t}\n\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate appendStatusSpecs(message: AssistantMessage, specs: SectionSpec[]): void {\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tif (message.stopReason === \"length\") {\n\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t\tspecs.push({ kind: \"label\", text: theme.fg(\"error\", \"Response was truncated before completion.\") });\n\t\t} else if (!hasToolCalls) {\n\t\t\tif (message.stopReason === \"aborted\") {\n\t\t\t\tconst abortMessage =\n\t\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t\t\tspecs.push({ kind: \"label\", text: theme.fg(\"error\", abortMessage) });\n\t\t\t} else if (message.stopReason === \"error\") {\n\t\t\t\tconst errorMsg = message.errorMessage || \"Unknown error\";\n\t\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t\t\tspecs.push({ kind: \"label\", text: theme.fg(\"error\", `Error: ${errorMsg}`) });\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Push markdown sections for one content block. While streaming, the block\n\t * is split at render-independent boundaries so completed units keep their\n\t * rendered Markdown instances and only the active tail re-parses per\n\t * chunk; otherwise the block renders whole, byte-identical to the\n\t * pre-split behaviour.\n\t *\n\t * Transformers are assumed block-local (the built-in mermaid transformer\n\t * maps tokens and preserves the rest, so per-unit application is\n\t * equivalent). A transformer that genuinely needs whole-message context\n\t * still gets it: a non-streaming update always renders whole blocks.\n\t */\n\tprivate pushMarkdownSpecs(specs: SectionSpec[], text: string, kind: \"markdown-text\" | \"markdown-thinking\"): void {\n\t\tif (this.isStreaming) {\n\t\t\tfor (const unit of splitStreamingMarkdown(text)) {\n\t\t\t\tspecs.push({ kind, text: unit });\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tspecs.push({ kind, text });\n\t}\n\n\tprivate createComponent(spec: SectionSpec): Section[\"component\"] {\n\t\tswitch (spec.kind) {\n\t\t\tcase \"spacer\":\n\t\t\t\treturn new Spacer(1);\n\t\t\tcase \"label\":\n\t\t\t\treturn new Text(spec.text, this.outputPad, 0);\n\t\t\tcase \"markdown-text\":\n\t\t\t\treturn new Markdown(spec.text, this.outputPad, 0, this.markdownTheme, undefined, {\n\t\t\t\t\ttransform: createMarkdownTransform(\"assistant\", this.isStreaming, this.markdownTransformers),\n\t\t\t\t});\n\t\t\tcase \"markdown-thinking\":\n\t\t\t\treturn new Markdown(\n\t\t\t\t\tspec.text,\n\t\t\t\t\tthis.outputPad,\n\t\t\t\t\t0,\n\t\t\t\t\tthis.markdownTheme,\n\t\t\t\t\t{\n\t\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\t\titalic: true,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttransform: createMarkdownTransform(\"assistant-thinking\", this.isStreaming, this.markdownTransformers),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"assistant-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-message.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AssistantMessage } from \"@earendil-works/pi-ai\";\nimport { Container, Markdown, type MarkdownTheme, MouseRegion, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { MarkdownTransformer } from \"../../../core/extensions/types.ts\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport { collapsedErrorLine, summarizeError } from \"./error-summary.ts\";\nimport { keyHint } from \"./keybinding-hints.ts\";\nimport { createMarkdownTransform } from \"./markdown-transform.ts\";\n\nconst OSC133_ZONE_START = \"\\x1b]133;A\\x07\";\nconst OSC133_ZONE_END = \"\\x1b]133;B\\x07\";\nconst OSC133_ZONE_FINAL = \"\\x1b]133;C\\x07\";\n\nconst FENCE_OPENER = /^(```|~~~)/;\nconst FENCE_CLOSER = /^(```|~~~)\\s*$/;\nconst LIST_MARKER = /^([-*+]\\s|\\d+[.)]\\s)/;\nconst QUOTE_MARKER = /^>\\s?/;\nconst INDENTED_CODE = /^(?:\\t| {4})/;\n\nfunction lastNonEmpty(lines: string[]): string | undefined {\n\tfor (let i = lines.length - 1; i >= 0; i--) {\n\t\tif (lines[i].trim() !== \"\") return lines[i];\n\t}\n\treturn undefined;\n}\n\nfunction shouldSplitBefore(next: string, current: string[]): boolean {\n\t// Indented lines can continue indented code blocks; never split there.\n\tif (INDENTED_CODE.test(next)) return false;\n\tconst previous = lastNonEmpty(current);\n\tif (previous && INDENTED_CODE.test(previous)) return false;\n\t// A loose list (\"item\\n\\nitem\") and a blockquote with a blank line render\n\t// as one construct; splitting them would change the output.\n\tif (LIST_MARKER.test(next) && previous && LIST_MARKER.test(previous)) return false;\n\tif (QUOTE_MARKER.test(next) && previous && QUOTE_MARKER.test(previous)) return false;\n\treturn true;\n}\n\n/**\n * Split streamed markdown into render units at boundaries that render\n * independently: closed column-0 code fences, and blank-line block\n * boundaries that cannot continue a preceding construct.\n *\n * The result is prefix-stable: appending text can only add units at the end,\n * never change earlier ones, which is what makes the units cacheable while\n * a message streams.\n */\nexport function splitStreamingMarkdown(text: string): string[] {\n\tif (!text) return [];\n\tconst lines = text.split(\"\\n\");\n\tconst units: string[] = [];\n\tlet current: string[] = [];\n\tlet inFence = false;\n\tconst flush = (): void => {\n\t\tif (current.length > 0) {\n\t\t\tunits.push(current.join(\"\\n\"));\n\t\t\tcurrent = [];\n\t\t}\n\t};\n\tfor (let i = 0; i < lines.length; i++) {\n\t\tconst line = lines[i];\n\t\tif (!inFence && FENCE_OPENER.test(line)) {\n\t\t\tinFence = true;\n\t\t\tcurrent.push(line);\n\t\t\tcontinue;\n\t\t}\n\t\tif (inFence) {\n\t\t\tcurrent.push(line);\n\t\t\tif (FENCE_CLOSER.test(line)) {\n\t\t\t\tflush();\n\t\t\t\tinFence = false;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tcurrent.push(line);\n\t\tif (line.trim() === \"\") {\n\t\t\tconst next = lines[i + 1];\n\t\t\tif (next !== undefined && next.trim() !== \"\" && shouldSplitBefore(next, current)) {\n\t\t\t\tflush();\n\t\t\t}\n\t\t}\n\t}\n\tflush();\n\treturn units;\n}\n\n/**\n * `run` numbers the message's thinking runs in order. It keys the per-run\n * visibility override that a click toggles, so two thinking sections are the\n * same slot only when they belong to the same run.\n */\ntype SectionSpec =\n\t| { kind: \"spacer\" }\n\t| { kind: \"markdown-text\"; text: string }\n\t| { kind: \"markdown-thinking\"; text: string; run: number }\n\t| { kind: \"thinking-label\"; text: string; run: number }\n\t| { kind: \"label\"; text: string };\n\ntype SectionComponent = Container[\"children\"][number];\n\n/**\n * `content` is the Text or Markdown whose text an in-place update replaces;\n * `component` is what the container holds, which for a thinking section is a\n * MouseRegion wrapping `content`.\n */\ntype Section = { spec: SectionSpec; component: SectionComponent; content: SectionComponent };\n\nfunction specText(spec: SectionSpec): string | undefined {\n\treturn spec.kind === \"spacer\" ? undefined : spec.text;\n}\n\nfunction specRun(spec: SectionSpec): number | undefined {\n\treturn spec.kind === \"markdown-thinking\" || spec.kind === \"thinking-label\" ? spec.run : undefined;\n}\n\n/**\n * Component that renders a complete assistant message\n */\nexport class AssistantMessageComponent extends Container {\n\tprivate contentContainer: Container;\n\tprivate hideThinkingBlock: boolean;\n\tprivate markdownTheme: MarkdownTheme;\n\tprivate hiddenThinkingLabel: string;\n\tprivate outputPad: number;\n\tprivate markdownTransformers: readonly MarkdownTransformer[];\n\tprivate lastMessage?: AssistantMessage;\n\tprivate hasToolCalls = false;\n\tprivate expanded = false;\n\tprivate isStreaming = false;\n\tprivate forceFullRebuild = true;\n\tprivate sections: Section[] = [];\n\tprivate thinkingVisibilityOverrides = new Map<number, boolean>();\n\n\tconstructor(\n\t\tmessage?: AssistantMessage,\n\t\thideThinkingBlock = false,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\thiddenThinkingLabel = \"Thinking...\",\n\t\toutputPad = 1,\n\t\tmarkdownTransformers: readonly MarkdownTransformer[] = [],\n\t) {\n\t\tsuper();\n\n\t\tthis.hideThinkingBlock = hideThinkingBlock;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.hiddenThinkingLabel = hiddenThinkingLabel;\n\t\tthis.outputPad = outputPad;\n\t\tthis.markdownTransformers = markdownTransformers;\n\n\t\t// Container for text/thinking content\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\tif (message) {\n\t\t\tthis.updateContent(message);\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tif (this.lastMessage) {\n\t\t\tthis.forceFullRebuild = true;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.hideThinkingBlock = hide;\n\t\tthis.thinkingVisibilityOverrides.clear();\n\t\tif (this.lastMessage) {\n\t\t\tthis.forceFullRebuild = true;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\t/** Multi-line errors show only their summary until the transcript is fully expanded. */\n\tsetExpanded(expanded: boolean): void {\n\t\tif (this.expanded === expanded) return;\n\t\tthis.expanded = expanded;\n\t\tif (this.lastMessage) {\n\t\t\tthis.forceFullRebuild = true;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetHiddenThinkingLabel(label: string): void {\n\t\tthis.hiddenThinkingLabel = label;\n\t\tif (this.lastMessage) {\n\t\t\tthis.forceFullRebuild = true;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetOutputPad(padding: number): void {\n\t\tthis.outputPad = padding;\n\t\tif (this.lastMessage) {\n\t\t\tthis.forceFullRebuild = true;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\toverride render(width: number): string[] {\n\t\tconst lines = super.render(width);\n\t\tif (this.hasToolCalls || lines.length === 0) {\n\t\t\treturn lines;\n\t\t}\n\n\t\tlines[0] = OSC133_ZONE_START + lines[0];\n\t\tlines[lines.length - 1] = OSC133_ZONE_END + OSC133_ZONE_FINAL + lines[lines.length - 1];\n\t\treturn lines;\n\t}\n\n\tupdateContent(message: AssistantMessage, isStreaming = this.isStreaming): void {\n\t\tthis.lastMessage = message;\n\t\t// The transform closures capture isStreaming, and non-streaming updates\n\t\t// render whole blocks rather than split units, so an isStreaming flip\n\t\t// rebuilds every section.\n\t\tconst rebuildAll = this.forceFullRebuild || isStreaming !== this.isStreaming;\n\t\tthis.isStreaming = isStreaming;\n\n\t\tconst specs = this.buildSectionSpecs(message);\n\t\tconst sections: Section[] = [];\n\t\tfor (let i = 0; i < specs.length; i++) {\n\t\t\tconst spec = specs[i];\n\t\t\tconst previous = rebuildAll ? undefined : this.sections[i];\n\t\t\tconst sameKind =\n\t\t\t\tprevious !== undefined && previous.spec.kind === spec.kind && specRun(previous.spec) === specRun(spec);\n\t\t\tif (sameKind && (spec.kind === \"spacer\" || specText(previous.spec) === specText(spec))) {\n\t\t\t\tsections.push({ ...previous, spec });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (sameKind && spec.kind !== \"spacer\") {\n\t\t\t\t// Same slot, new content (the growing tail of a streamed\n\t\t\t\t// message): update in place so only this unit re-parses.\n\t\t\t\tconst content = previous.content as Text;\n\t\t\t\tcontent.setText(specText(spec) ?? \"\");\n\t\t\t\tsections.push({ ...previous, spec });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tsections.push(this.createSection(spec));\n\t\t}\n\n\t\tthis.forceFullRebuild = false;\n\t\tthis.sections = sections;\n\n\t\tthis.contentContainer.clear();\n\t\tfor (const section of sections) {\n\t\t\tthis.contentContainer.addChild(section.component);\n\t\t}\n\n\t\t// Check if incomplete/failed - show after partial content.\n\t\t// For aborted/error tool calls, tool execution components show the error.\n\t\t// Length stops can happen before a tool call is complete, so surface them here too.\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tthis.hasToolCalls = hasToolCalls;\n\t}\n\n\tprivate buildSectionSpecs(message: AssistantMessage): SectionSpec[] {\n\t\tconst specs: SectionSpec[] = [];\n\t\tthis.appendContentSpecs(message, specs);\n\t\tthis.appendStatusSpecs(message, specs);\n\t\treturn specs;\n\t}\n\n\tprivate appendContentSpecs(message: AssistantMessage, specs: SectionSpec[]): void {\n\t\tconst hasVisibleContent = message.content.some(\n\t\t\t(c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()),\n\t\t);\n\n\t\tif (hasVisibleContent) {\n\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t}\n\n\t\t// Render content in order\n\t\tlet thinkingRunIndex = 0;\n\t\tfor (let i = 0; i < message.content.length; i++) {\n\t\t\tconst content = message.content[i];\n\t\t\tif (content.type === \"text\" && content.text.trim()) {\n\t\t\t\t// Assistant text messages with no background - trim the text\n\t\t\t\t// Set paddingY=0 to avoid extra spacing before tool executions\n\t\t\t\tthis.pushMarkdownSpecs(specs, content.text.trim(), { kind: \"markdown-text\" });\n\t\t\t} else if (content.type === \"thinking\") {\n\t\t\t\tconst thinkingBlocks: string[] = [];\n\t\t\t\tfor (; i < message.content.length; i++) {\n\t\t\t\t\tconst thinkingContent = message.content[i];\n\t\t\t\t\tif (thinkingContent.type !== \"thinking\") {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tconst thinking = thinkingContent.thinking.trim();\n\t\t\t\t\tif (thinking) {\n\t\t\t\t\t\tthinkingBlocks.push(thinking);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ti--;\n\n\t\t\t\tif (thinkingBlocks.length === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Add spacing only when another visible assistant content block follows.\n\t\t\t\t// This avoids a superfluous blank line before separately-rendered tool execution blocks.\n\t\t\t\tconst hasVisibleContentAfter = message.content\n\t\t\t\t\t.slice(i + 1)\n\t\t\t\t\t.some((c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()));\n\n\t\t\t\t// Each run can be expanded or collapsed on its own by clicking it; the\n\t\t\t\t// global hide setting is the default for runs nobody has clicked.\n\t\t\t\tconst run = thinkingRunIndex++;\n\t\t\t\tif (this.isThinkingRunHidden(run)) {\n\t\t\t\t\t// Show one static label for each run of thinking blocks when hidden.\n\t\t\t\t\tspecs.push({\n\t\t\t\t\t\tkind: \"thinking-label\",\n\t\t\t\t\t\ttext: `${theme.italic(theme.fg(\"thinkingText\", this.hiddenThinkingLabel))} ${keyHint(\"app.tools.expand\", \"to expand\")}`,\n\t\t\t\t\t\trun,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\t// Render each run of thinking blocks as one Markdown section.\n\t\t\t\t\tthis.pushMarkdownSpecs(specs, thinkingBlocks.join(\"\\n\\n\"), { kind: \"markdown-thinking\", run });\n\t\t\t\t}\n\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate appendStatusSpecs(message: AssistantMessage, specs: SectionSpec[]): void {\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tif (message.stopReason === \"length\") {\n\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t\tspecs.push({ kind: \"label\", text: theme.fg(\"error\", \"Response was truncated before completion.\") });\n\t\t} else if (!hasToolCalls) {\n\t\t\tif (message.stopReason === \"aborted\") {\n\t\t\t\tconst abortMessage =\n\t\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t\t\tspecs.push({ kind: \"label\", text: this.errorLabel(abortMessage) });\n\t\t\t} else if (message.stopReason === \"error\") {\n\t\t\t\tconst errorMsg = message.errorMessage || \"Unknown error\";\n\t\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t\t\tspecs.push({ kind: \"label\", text: this.errorLabel(`Error: ${errorMsg}`) });\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate errorLabel(text: string): string {\n\t\tconst summary = this.expanded ? undefined : summarizeError(text);\n\t\treturn summary === undefined ? theme.fg(\"error\", text) : collapsedErrorLine(theme.fg(\"error\", summary));\n\t}\n\n\t/**\n\t * Push markdown sections for one content block. While streaming, the block\n\t * is split at render-independent boundaries so completed units keep their\n\t * rendered Markdown instances and only the active tail re-parses per\n\t * chunk; otherwise the block renders whole, byte-identical to the\n\t * pre-split behaviour.\n\t *\n\t * Transformers are assumed block-local (the built-in mermaid transformer\n\t * maps tokens and preserves the rest, so per-unit application is\n\t * equivalent). A transformer that genuinely needs whole-message context\n\t * still gets it: a non-streaming update always renders whole blocks.\n\t */\n\tprivate pushMarkdownSpecs(\n\t\tspecs: SectionSpec[],\n\t\ttext: string,\n\t\tslot: { kind: \"markdown-text\" } | { kind: \"markdown-thinking\"; run: number },\n\t): void {\n\t\tif (this.isStreaming) {\n\t\t\tfor (const unit of splitStreamingMarkdown(text)) {\n\t\t\t\tspecs.push({ ...slot, text: unit });\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tspecs.push({ ...slot, text });\n\t}\n\n\tprivate isThinkingRunHidden(run: number): boolean {\n\t\treturn this.thinkingVisibilityOverrides.get(run) ?? this.hideThinkingBlock;\n\t}\n\n\tprivate createSection(spec: SectionSpec): Section {\n\t\tconst content = this.createComponent(spec);\n\t\tconst run = specRun(spec);\n\t\tif (run === undefined) return { spec, component: content, content };\n\t\tconst component = new MouseRegion(content, (event) => {\n\t\t\tif (event.type !== \"click\" || event.button !== \"left\") return undefined;\n\t\t\tthis.thinkingVisibilityOverrides.set(run, !this.isThinkingRunHidden(run));\n\t\t\tif (this.lastMessage) this.updateContent(this.lastMessage);\n\t\t\treturn { handled: true };\n\t\t});\n\t\treturn { spec, component, content };\n\t}\n\n\tprivate createComponent(spec: SectionSpec): SectionComponent {\n\t\tswitch (spec.kind) {\n\t\t\tcase \"spacer\":\n\t\t\t\treturn new Spacer(1);\n\t\t\tcase \"label\":\n\t\t\tcase \"thinking-label\":\n\t\t\t\treturn new Text(spec.text, this.outputPad, 0);\n\t\t\tcase \"markdown-text\":\n\t\t\t\treturn new Markdown(spec.text, this.outputPad, 0, this.markdownTheme, undefined, {\n\t\t\t\t\ttransform: createMarkdownTransform(\"assistant\", this.isStreaming, this.markdownTransformers),\n\t\t\t\t});\n\t\t\tcase \"markdown-thinking\":\n\t\t\t\treturn new Markdown(\n\t\t\t\t\tspec.text,\n\t\t\t\t\tthis.outputPad,\n\t\t\t\t\t0,\n\t\t\t\t\tthis.markdownTheme,\n\t\t\t\t\t{\n\t\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\t\titalic: true,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttransform: createMarkdownTransform(\"assistant-thinking\", this.isStreaming, this.markdownTransformers),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t}\n\t}\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import type { SourceInfo } from "../../../core/source-info.ts";
2
+ /**
3
+ * A palette description, led by the package it came from when there is one. A resource the
4
+ * user or the project wrote carries no tag: a scope letter told the reader nothing they
5
+ * could act on.
6
+ */
7
+ export declare function describeWithSource(description: string | undefined, sourceInfo?: SourceInfo): string | undefined;
8
+ //# sourceMappingURL=autocomplete-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autocomplete-source.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/autocomplete-source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAY/D;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,UAAU,CAAC,EAAE,UAAU,GAAG,MAAM,GAAG,SAAS,CAI/G","sourcesContent":["import type { SourceInfo } from \"../../../core/source-info.ts\";\nimport { parseGitUrl } from \"../../../utils/git.ts\";\n\n/** The package a palette entry came from, or nothing for one the user or the project wrote. */\nfunction packageSource(sourceInfo: SourceInfo | undefined): string | undefined {\n\tconst source = sourceInfo?.source.trim();\n\tif (!source) return undefined;\n\tif (source.startsWith(\"npm:\")) return source;\n\tconst git = parseGitUrl(source);\n\treturn git ? `git:${git.host}/${git.path}${git.ref ? `@${git.ref}` : \"\"}` : undefined;\n}\n\n/**\n * A palette description, led by the package it came from when there is one. A resource the\n * user or the project wrote carries no tag: a scope letter told the reader nothing they\n * could act on.\n */\nexport function describeWithSource(description: string | undefined, sourceInfo?: SourceInfo): string | undefined {\n\tconst source = packageSource(sourceInfo);\n\tif (!source) return description;\n\treturn description ? `[${source}] ${description}` : `[${source}]`;\n}\n"]}
@@ -0,0 +1,23 @@
1
+ import { parseGitUrl } from "../../../utils/git.js";
2
+ /** The package a palette entry came from, or nothing for one the user or the project wrote. */
3
+ function packageSource(sourceInfo) {
4
+ const source = sourceInfo?.source.trim();
5
+ if (!source)
6
+ return undefined;
7
+ if (source.startsWith("npm:"))
8
+ return source;
9
+ const git = parseGitUrl(source);
10
+ return git ? `git:${git.host}/${git.path}${git.ref ? `@${git.ref}` : ""}` : undefined;
11
+ }
12
+ /**
13
+ * A palette description, led by the package it came from when there is one. A resource the
14
+ * user or the project wrote carries no tag: a scope letter told the reader nothing they
15
+ * could act on.
16
+ */
17
+ export function describeWithSource(description, sourceInfo) {
18
+ const source = packageSource(sourceInfo);
19
+ if (!source)
20
+ return description;
21
+ return description ? `[${source}] ${description}` : `[${source}]`;
22
+ }
23
+ //# sourceMappingURL=autocomplete-source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autocomplete-source.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/autocomplete-source.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,+FAA+F;AAC/F,SAAS,aAAa,CAAC,UAAkC,EAAsB;IAC9E,MAAM,MAAM,GAAG,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;IACzC,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IAC7C,MAAM,GAAG,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IAChC,OAAO,GAAG,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAAA,CACtF;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,WAA+B,EAAE,UAAuB,EAAsB;IAChH,MAAM,MAAM,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;IACzC,IAAI,CAAC,MAAM;QAAE,OAAO,WAAW,CAAC;IAChC,OAAO,WAAW,CAAC,CAAC,CAAC,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,MAAM,GAAG,CAAC;AAAA,CAClE","sourcesContent":["import type { SourceInfo } from \"../../../core/source-info.ts\";\nimport { parseGitUrl } from \"../../../utils/git.ts\";\n\n/** The package a palette entry came from, or nothing for one the user or the project wrote. */\nfunction packageSource(sourceInfo: SourceInfo | undefined): string | undefined {\n\tconst source = sourceInfo?.source.trim();\n\tif (!source) return undefined;\n\tif (source.startsWith(\"npm:\")) return source;\n\tconst git = parseGitUrl(source);\n\treturn git ? `git:${git.host}/${git.path}${git.ref ? `@${git.ref}` : \"\"}` : undefined;\n}\n\n/**\n * A palette description, led by the package it came from when there is one. A resource the\n * user or the project wrote carries no tag: a scope letter told the reader nothing they\n * could act on.\n */\nexport function describeWithSource(description: string | undefined, sourceInfo?: SourceInfo): string | undefined {\n\tconst source = packageSource(sourceInfo);\n\tif (!source) return description;\n\treturn description ? `[${source}] ${description}` : `[${source}]`;\n}\n"]}