@pheem49/mint 1.17.0 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (421) hide show
  1. package/Cargo.lock +6 -6
  2. package/Cargo.toml +2 -2
  3. package/README.md +8 -2
  4. package/Release_Note.md +222 -71
  5. package/crates/mint-cli/src/agent/diff_render.rs +66 -44
  6. package/crates/mint-cli/src/agent/live_status.rs +21 -4
  7. package/crates/mint-cli/src/agent/markdown_render.rs +342 -5
  8. package/crates/mint-cli/src/agent.rs +25 -10
  9. package/crates/mint-cli/src/commands/agent.rs +4 -92
  10. package/crates/mint-cli/src/commands/browser.rs +2 -15
  11. package/crates/mint-cli/src/commands/integrations.rs +3 -3
  12. package/crates/mint-cli/src/commands/mod.rs +0 -3
  13. package/crates/mint-cli/src/commands/tailnet_web.rs +1 -0
  14. package/crates/mint-cli/src/interactive/chat_tui/dialog.rs +572 -0
  15. package/crates/mint-cli/src/interactive/chat_tui/mod.rs +1427 -0
  16. package/crates/mint-cli/src/interactive/chat_tui/render.rs +1524 -0
  17. package/crates/mint-cli/src/interactive/chat_tui/selection.rs +401 -0
  18. package/crates/mint-cli/src/interactive/chat_tui/state.rs +1833 -0
  19. package/crates/mint-cli/src/interactive/chat_tui/tests.rs +3414 -0
  20. package/crates/mint-cli/src/interactive/chat_tui/thought.rs +202 -0
  21. package/crates/mint-cli/src/interactive/chat_tui/transcript.rs +728 -0
  22. package/crates/mint-cli/src/interactive/chat_tui/watermark.rs +148 -0
  23. package/crates/mint-cli/src/interactive/command_ui.rs +53 -5
  24. package/crates/mint-cli/src/interactive/composer.rs +186 -0
  25. package/crates/mint-cli/src/interactive/format.rs +78 -3
  26. package/crates/mint-cli/src/interactive/input_box.rs +61 -1
  27. package/crates/mint-cli/src/interactive/resume_picker.rs +367 -25
  28. package/crates/mint-cli/src/interactive/slash_commands.rs +648 -371
  29. package/crates/mint-cli/src/interactive/tool_activity.rs +93 -20
  30. package/crates/mint-cli/src/interactive.rs +37 -0
  31. package/crates/mint-cli/src/main.rs +6 -3
  32. package/crates/mint-cli/src/markdown.rs +2 -37
  33. package/crates/mint-cli/src/onboard.rs +700 -282
  34. package/crates/mint-cli/src/setup.rs +1342 -624
  35. package/crates/mint-cli/src/terminal_theme.rs +159 -35
  36. package/crates/mint-cli/tests/library_intake.rs +1 -0
  37. package/crates/mint-core/src/agent/chat/anthropic.rs +318 -0
  38. package/crates/mint-core/src/agent/chat/custom.rs +149 -0
  39. package/crates/mint-core/src/agent/chat/gemini.rs +518 -0
  40. package/crates/mint-core/src/agent/chat/mod.rs +857 -0
  41. package/crates/mint-core/src/agent/chat/ollama.rs +321 -0
  42. package/crates/mint-core/src/agent/chat/openai.rs +582 -0
  43. package/crates/mint-core/src/agent/chat/streaming.rs +469 -0
  44. package/crates/mint-core/src/agent/chat/tests.rs +1479 -0
  45. package/crates/mint-core/src/agent/memory.rs +56 -2
  46. package/crates/mint-core/src/agent/tasks.rs +2 -2
  47. package/crates/mint-core/src/api_server/routes/chat.rs +24 -2
  48. package/crates/mint-core/src/api_server/routes/gemini_live.rs +14 -1
  49. package/crates/mint-core/src/api_server/routes/html_preview.rs +1 -8
  50. package/crates/mint-core/src/api_server/routes/sessions.rs +21 -0
  51. package/crates/mint-core/src/avatar_bridge.rs +0 -22
  52. package/crates/mint-core/src/browser/cdp.rs +10 -4
  53. package/crates/mint-core/src/browser/headless.rs +582 -0
  54. package/crates/mint-core/src/browser/input.rs +7 -62
  55. package/crates/mint-core/src/browser/interact.rs +0 -14
  56. package/crates/mint-core/src/browser/mod.rs +8 -29
  57. package/crates/mint-core/src/browser/navigate.rs +2 -36
  58. package/crates/mint-core/src/browser/runtime.rs +2 -4
  59. package/crates/mint-core/src/browser/session.rs +50 -466
  60. package/crates/mint-core/src/browser/workflow.rs +142 -32
  61. package/crates/mint-core/src/cron/store.rs +2 -2
  62. package/crates/mint-core/src/integrations/mcp.rs +6 -8
  63. package/crates/mint-core/src/lib.rs +0 -5
  64. package/crates/mint-core/src/media/gemini_live.rs +636 -86
  65. package/crates/mint-core/src/media/library/migration.rs +26 -0
  66. package/crates/mint-core/src/media/library/tests.rs +1 -1
  67. package/crates/mint-core/src/media/library/thumbnails.rs +8 -2
  68. package/crates/mint-core/src/media/pictures.rs +1 -1
  69. package/crates/mint-core/src/media/tool_images.rs +92 -1
  70. package/crates/mint-core/src/mods/manager.rs +101 -35
  71. package/crates/mint-core/src/orchestration/context_render.rs +441 -24
  72. package/crates/mint-core/src/orchestration/decision_parsing.rs +531 -16
  73. package/crates/mint-core/src/orchestration/full_skill_result_tests.rs +12 -0
  74. package/crates/mint-core/src/orchestration/loop_guard.rs +145 -0
  75. package/crates/mint-core/src/orchestration/mcp_outcome_tests.rs +864 -0
  76. package/crates/mint-core/src/orchestration/memory_skill.rs +88 -28
  77. package/crates/mint-core/src/orchestration/mod.rs +320 -4249
  78. package/crates/mint-core/src/orchestration/reliability.rs +67 -27
  79. package/crates/mint-core/src/orchestration/review_regressions.rs +5 -0
  80. package/crates/mint-core/src/orchestration/tests.rs +1665 -0
  81. package/crates/mint-core/src/orchestration/tools/dispatch.rs +967 -0
  82. package/crates/mint-core/src/orchestration/tools/files.rs +1 -0
  83. package/crates/mint-core/src/orchestration/tools/mod.rs +5 -1
  84. package/crates/mint-core/src/orchestration/tools/planning.rs +102 -42
  85. package/crates/mint-core/src/orchestration/tools/shell.rs +129 -58
  86. package/crates/mint-core/src/orchestration/truncation.rs +170 -13
  87. package/crates/mint-core/src/orchestration/types.rs +648 -0
  88. package/crates/mint-core/src/orchestration/verification.rs +0 -3
  89. package/crates/mint-core/src/orchestration/workspace_helpers.rs +24 -6
  90. package/crates/mint-core/src/prompts/agent.rs +52 -76
  91. package/crates/mint-core/src/prompts/tool_catalog.rs +8 -151
  92. package/crates/mint-core/src/search/files.rs +20 -0
  93. package/crates/mint-core/src/slash/mod.rs +228 -265
  94. package/crates/mint-core/src/slash/models.rs +6 -1
  95. package/crates/mint-core/src/system/bg_shell.rs +1 -0
  96. package/crates/mint-core/src/system/config.rs +176 -34
  97. package/crates/mint-mod-runtime/src/lib.rs +37 -23
  98. package/out/web/assets/ArtifactPreviewPanel-Cx6BVOOF.js +2 -0
  99. package/out/web/assets/CalculationCard-D2E74u5q.js +1 -0
  100. package/out/web/assets/CliSessionsView-ZbdtSjvK.css +1 -0
  101. package/out/web/assets/{CliSessionsView-MI8kXMAb.js → CliSessionsView-z5i6qGyb.js} +1 -1
  102. package/out/web/assets/CodeReviewPage-BK2bOScd.css +1 -0
  103. package/out/web/assets/CodeReviewPage-Dp6zHuHu.js +2 -0
  104. package/out/web/assets/{CommandPalette-BD8SlTE5.js → CommandPalette-DaKlzbKs.js} +1 -1
  105. package/out/web/assets/ImageGenCard-BMCJHP9O.js +1 -0
  106. package/out/web/assets/ImageSearchCard-Cld_SOUg.js +1 -0
  107. package/out/web/assets/{ImageStudioPanel-BP7N4rLr.js → ImageStudioPanel-B5N7TjeB.js} +1 -1
  108. package/out/web/assets/LibraryPage-CMB89rJ0.css +1 -0
  109. package/out/web/assets/LibraryPage-DbZEi4W_.js +2 -0
  110. package/out/web/assets/LinkedFoldersView-9B9DIPoZ.js +1 -0
  111. package/out/web/assets/{McpRegistryPicker-CoS83vtc.js → McpRegistryPicker-DnXPlzI7.js} +1 -1
  112. package/out/web/assets/McpServersView-CiNBNUl4.js +1 -0
  113. package/out/web/assets/MermaidCard-BBDNEXbY.js +2 -0
  114. package/out/web/assets/MintDashboard-C_UYPoNV.js +119 -0
  115. package/out/web/assets/MintDashboard-DTd8C_c8.css +1 -0
  116. package/out/web/assets/PlanCard-C2x5pajq.js +1 -0
  117. package/out/web/assets/{PluginsView-jBYmcKh4.js → PluginsView-DoTg9MVa.js} +1 -1
  118. package/out/web/assets/RewindModal-B5oowrR0.js +1 -0
  119. package/out/web/assets/{ScheduledTasksView-5uw9-V9H.js → ScheduledTasksView-BD5DVPkZ.js} +1 -1
  120. package/out/web/assets/{SelectField-DXBQtrUK.js → SelectField-Cy6CghrU.js} +1 -1
  121. package/out/web/assets/SettingsWindow-BYl_oCFh.js +4 -0
  122. package/out/web/assets/SettingsWindow-Ckcgnjt8.css +1 -0
  123. package/out/web/assets/{SkillsView-C-gp9J7m.js → SkillsView-CIeWwq5z.js} +1 -1
  124. package/out/web/assets/StockCard-DxUciKyp.js +1 -0
  125. package/out/web/assets/ToolSurfacePage-qBgs_VHq.css +1 -0
  126. package/out/web/assets/ToolSurfacePage-saVbVrkE.js +38 -0
  127. package/out/web/assets/{UiFeatureCard-6BwxTOCe.js → UiFeatureCard-CdY0hGWy.js} +1 -1
  128. package/out/web/assets/{UiGridCard-DvZcLNxb.js → UiGridCard-BBK3I5hC.js} +1 -1
  129. package/out/web/assets/UiMockupWidget-CpR9EDuc.js +1 -0
  130. package/out/web/assets/{VeoStudioPanel-DOj7_WR3.css → VeoStudioPanel-9kU9YLEN.css} +1 -1
  131. package/out/web/assets/{VeoStudioPanel-DfsOJKv0.js → VeoStudioPanel-Co6-wEWM.js} +2 -2
  132. package/out/web/assets/WeatherCard-Buzi7Vfu.js +1 -0
  133. package/out/web/assets/WorkspacePdfPreview-Bi8Zzyir.js +2 -0
  134. package/out/web/assets/{abnfDiagram-VCTEODGH-BOo3Ckng.js → abnfDiagram-VCTEODGH-CMfR95N2.js} +1 -1
  135. package/out/web/assets/{architecture-7GRP2DOG-ZOwheW3n.js → architecture-7GRP2DOG-DhAM4HyO.js} +1 -1
  136. package/out/web/assets/{architectureDiagram-5GKGNRK7-DC2FDzVd.js → architectureDiagram-5GKGNRK7-Yk3TUJ_F.js} +1 -1
  137. package/out/web/assets/{blockDiagram-I7D4REHJ-BrKFWdAH.js → blockDiagram-I7D4REHJ-X9fBgJik.js} +1 -1
  138. package/out/web/assets/{c4Diagram-7LVT6UL2-BHTHK1Yd.js → c4Diagram-7LVT6UL2-Bk9x7N-8.js} +1 -1
  139. package/out/web/assets/{chunk-4HAMMTFA-BYFkZwNj.js → chunk-4HAMMTFA-Dx5fk1_0.js} +1 -1
  140. package/out/web/assets/{chunk-75Z2AOVW-BSKfSKSA.js → chunk-75Z2AOVW-BszTQoM4.js} +1 -1
  141. package/out/web/assets/{chunk-DU6HZSFF-vIhsiW6n.js → chunk-DU6HZSFF-DK-As3rk.js} +1 -1
  142. package/out/web/assets/{chunk-F27PBJKO-BlYpW9xq.js → chunk-F27PBJKO-LmncZZIS.js} +1 -1
  143. package/out/web/assets/{chunk-GMAD6QVW-BIBz_Ug5.js → chunk-GMAD6QVW-DSQ_sDRJ.js} +1 -1
  144. package/out/web/assets/{chunk-GVQU2GXP-NPSHxeqC.js → chunk-GVQU2GXP-Cno3ulje.js} +1 -1
  145. package/out/web/assets/{chunk-IMKFNOWR-YlJK8_Fp.js → chunk-IMKFNOWR-bIzfY9Jc.js} +1 -1
  146. package/out/web/assets/{chunk-L3NEJ4N5-DMYi4-af.js → chunk-L3NEJ4N5-Dl6eOa0D.js} +1 -1
  147. package/out/web/assets/{chunk-OSK3NFVY-Begd3-jA.js → chunk-OSK3NFVY-BaUGJ-cM.js} +1 -1
  148. package/out/web/assets/{chunk-P2QGCYS3-D1I4xFHN.js → chunk-P2QGCYS3-_066ndhH.js} +1 -1
  149. package/out/web/assets/{chunk-POPQ4Y6H-CafZZzNE.js → chunk-POPQ4Y6H-YT1AKhTv.js} +1 -1
  150. package/out/web/assets/{chunk-PWAF6VOD-Dwh6_Lnt.js → chunk-PWAF6VOD-CrEgDsxh.js} +1 -1
  151. package/out/web/assets/{chunk-SHT3W25Y-B0XrCSEb.js → chunk-SHT3W25Y-_KwaRLOl.js} +1 -1
  152. package/out/web/assets/{chunk-SVP7TREG-CxLsddxC.js → chunk-SVP7TREG-BQ1qb32L.js} +1 -1
  153. package/out/web/assets/{chunk-TICWLB2K-y156QInb.js → chunk-TICWLB2K-BDyehCtg.js} +1 -1
  154. package/out/web/assets/classDiagram-ZZMXUADV-BoSpzRCJ.js +1 -0
  155. package/out/web/assets/classDiagram-v2-VYDZK3BY-BoSpzRCJ.js +1 -0
  156. package/out/web/assets/{config-DqXJXeZM.css → config-2suVFPZg.css} +1 -1
  157. package/out/web/assets/config-CkRCdkxn.js +2 -0
  158. package/out/web/assets/{cynefin-OW5HDTMX-SMVvrLf-.js → cynefin-OW5HDTMX-Dl_31aaN.js} +1 -1
  159. package/out/web/assets/{cynefinDiagram-5FMLGOSQ-rZznN24T.js → cynefinDiagram-5FMLGOSQ-Bpir8jha.js} +1 -1
  160. package/out/web/assets/{dagre-GXQ25YYZ-BOToydFu.js → dagre-GXQ25YYZ-D9xu3nsq.js} +1 -1
  161. package/out/web/assets/{diagram-S7CK7UJ4-TMVaGQEJ.js → diagram-S7CK7UJ4-DeveoEeB.js} +1 -1
  162. package/out/web/assets/{diagram-UQ7AKVKN-C2JK-GP2.js → diagram-UQ7AKVKN-p4xWRESV.js} +1 -1
  163. package/out/web/assets/{diagram-VSXAHHWV-Cw8VSi2K.js → diagram-VSXAHHWV-C7qz9NDF.js} +1 -1
  164. package/out/web/assets/{diagram-VX7I27RA-DXp4fKk9.js → diagram-VX7I27RA-DRiCa3Vd.js} +1 -1
  165. package/out/web/assets/{diagram-Z3DM3KII-CzSicYiW.js → diagram-Z3DM3KII-Bt7zduQX.js} +1 -1
  166. package/out/web/assets/{ebnfDiagram-PWID7BFC-Dqj-zqPu.js → ebnfDiagram-PWID7BFC-DV9WpwdR.js} +1 -1
  167. package/out/web/assets/{erDiagram-RLTQ6QDP-DZwFZAuD.js → erDiagram-RLTQ6QDP-BJ_nwG2m.js} +1 -1
  168. package/out/web/assets/{eventmodeling-NTZA5JFV-C0O-Lvgp.js → eventmodeling-NTZA5JFV-BTBMrfVa.js} +1 -1
  169. package/out/web/assets/flowDiagram-HODETNUW-Cdlq3cJL.js +1 -0
  170. package/out/web/assets/{ganttDiagram-EL5Y4UJY-Da4ULXTl.js → ganttDiagram-EL5Y4UJY-DQLdsXrC.js} +1 -1
  171. package/out/web/assets/{gitGraph-4MIJSDKK-B9wNFZIP.js → gitGraph-4MIJSDKK-CL1OEOQ_.js} +1 -1
  172. package/out/web/assets/{gitGraphDiagram-WWUBYQGX-RjrhB0MP.js → gitGraphDiagram-WWUBYQGX-8cSi42H7.js} +1 -1
  173. package/out/web/assets/index-BocxnrDG.js +168 -0
  174. package/out/web/assets/index-yeh_r55a.css +1 -0
  175. package/out/web/assets/{info-A6RAGUB7-B3dfCpeY.js → info-A6RAGUB7-C1zsX5sc.js} +1 -1
  176. package/out/web/assets/{infoDiagram-27XIBGKW-QVWkLVx7.js → infoDiagram-27XIBGKW-DsRYtIyI.js} +1 -1
  177. package/out/web/assets/{ishikawaDiagram-5VMMS53U-CLFNIRI9.js → ishikawaDiagram-5VMMS53U-B2crwIXj.js} +1 -1
  178. package/out/web/assets/{journeyDiagram-3NMN7TZE-fgOQadYF.js → journeyDiagram-3NMN7TZE-BTH-GyVR.js} +1 -1
  179. package/out/web/assets/{kanban-definition-UXKFOSKX-G3Q_9g9O.js → kanban-definition-UXKFOSKX-BeRfCnuA.js} +1 -1
  180. package/out/web/assets/{mermaid-parser.core-v3Jm7nco.js → mermaid-parser.core-BJwgCBBc.js} +3 -3
  181. package/out/web/assets/{mermaid.core-DTEjLUA1.js → mermaid.core-CsDDodN8.js} +4 -4
  182. package/out/web/assets/{mindmap-definition-YA3MSWOX-C_D42_fF.js → mindmap-definition-YA3MSWOX-B42efOQ1.js} +1 -1
  183. package/out/web/assets/{modelManager-BPLycQrN.js → modelManager-B3ZFMh8v.js} +2 -2
  184. package/out/web/assets/{oauthManager-BUK7ic7q.js → oauthManager-Ch5Du2fF.js} +1 -1
  185. package/out/web/assets/{packet-AYTQ26CC-B-R-SHlF.js → packet-AYTQ26CC-B6xUyE6r.js} +1 -1
  186. package/out/web/assets/{pegDiagram-XKGWAZYB-Da2q_giz.js → pegDiagram-XKGWAZYB-1LabVycL.js} +1 -1
  187. package/out/web/assets/{pie-WAS4IAKB-BC8F0N7-.js → pie-WAS4IAKB-DJwo-nf_.js} +1 -1
  188. package/out/web/assets/{pieDiagram-E7YTZNPT-Iy9REJNC.js → pieDiagram-E7YTZNPT-icmAqzy4.js} +1 -1
  189. package/out/web/assets/{quadrantDiagram-AXDQQJYC-ztsiYw7h.js → quadrantDiagram-AXDQQJYC-CZ-wEx41.js} +1 -1
  190. package/out/web/assets/{radar-RG4KPBEZ-B_1P8Z_z.js → radar-RG4KPBEZ-D7d-Xriw.js} +1 -1
  191. package/out/web/assets/{railroad-74A4TZTK-DuTqczSo.js → railroad-74A4TZTK-viuhdYbs.js} +1 -1
  192. package/out/web/assets/{railroad-abnf-HS5TGJTU-Df29WLmp.js → railroad-abnf-HS5TGJTU-DNXiCNea.js} +1 -1
  193. package/out/web/assets/{railroad-ebnf-LZEXJU2U-ePFMo-qp.js → railroad-ebnf-LZEXJU2U-nkSu1-0C.js} +1 -1
  194. package/out/web/assets/{railroad-peg-WCYAUIDC-DYXLW4_E.js → railroad-peg-WCYAUIDC-BhbMeQzz.js} +1 -1
  195. package/out/web/assets/{railroadDiagram-O6MQD6OU-LStnZf2S.js → railroadDiagram-O6MQD6OU-CLpG1jUX.js} +1 -1
  196. package/out/web/assets/{requirementDiagram-BXWQKSXE-DmzonMH-.js → requirementDiagram-BXWQKSXE-kRDrvWrc.js} +1 -1
  197. package/out/web/assets/{sankeyDiagram-P5KCCOFB-B8vjmUU1.js → sankeyDiagram-P5KCCOFB-DxAwmq4x.js} +1 -1
  198. package/out/web/assets/{sequenceDiagram-WJ2MYXX4-CTnplOAX.js → sequenceDiagram-WJ2MYXX4-aLgY-6Wz.js} +1 -1
  199. package/out/web/assets/{stateDiagram-D77RDMKH-BFrIaLdI.js → stateDiagram-D77RDMKH-D5QWfOhp.js} +1 -1
  200. package/out/web/assets/stateDiagram-v2-MP3YSRHH-D6OiZoAP.js +1 -0
  201. package/out/web/assets/{swimlanes-42K2YHIH-BXGngUNU.js → swimlanes-42K2YHIH-CRs5UyA-.js} +1 -1
  202. package/out/web/assets/swimlanesDiagram-VR7AAH4N-UgEXIsV0.js +8 -0
  203. package/out/web/assets/syntaxHighlight-C-wAGT84.js +3 -0
  204. package/out/web/assets/{timeline-definition-24CTP7MA-CegH7n43.js → timeline-definition-24CTP7MA-Denqd9qb.js} +1 -1
  205. package/out/web/assets/{treeView-Q6P3EWNA-DTpJv2Tw.js → treeView-Q6P3EWNA-0my3Z3s4.js} +1 -1
  206. package/out/web/assets/{treemap-WGGIJYW6-i8M9iJU6.js → treemap-WGGIJYW6-B_EjkLYq.js} +1 -1
  207. package/out/web/assets/{vennDiagram-4TSXK5OY-Dpzo1S8U.js → vennDiagram-4TSXK5OY-DxVg3Ewr.js} +1 -1
  208. package/out/web/assets/{wardley-WFR3VGLG-BrNsgtfw.js → wardley-WFR3VGLG-CGD-Tj4p.js} +1 -1
  209. package/out/web/assets/{wardleyDiagram-VM6X3IG4-lQ92LFE1.js → wardleyDiagram-VM6X3IG4-CmfS39Xm.js} +1 -1
  210. package/out/web/assets/{xychartDiagram-S5SC5T6Z-BaOaEoBd.js → xychartDiagram-S5SC5T6Z-BVM9bKis.js} +1 -1
  211. package/out/web/index-web.html +2 -2
  212. package/out/web/index.html +2 -2
  213. package/package.json +2 -2
  214. package/shared-modules/CODEOWNERS +3 -3
  215. package/shared-modules/SDL2/SDL2_mixer.json +27 -0
  216. package/shared-modules/appstream/README.md +13 -0
  217. package/shared-modules/appstream/appstream-compose.json +111 -0
  218. package/shared-modules/dbus-glib/dbus-glib.json +2 -2
  219. package/shared-modules/libportal/libportal.json +23 -0
  220. package/shared-modules/linux-audio/fluidsynth2-static.json +2 -2
  221. package/shared-modules/linux-audio/fluidsynth2.json +2 -2
  222. package/shared-modules/linux-audio/libinstpatch.json +2 -2
  223. package/shared-modules/linux-audio/liblo-static.json +3 -0
  224. package/shared-modules/luajit/luajit.json +2 -2
  225. package/shared-modules/squashfs-tools/squashfs-tools.json +0 -3
  226. package/slash-commands.json +7 -2
  227. package/src/renderer/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  228. package/src/renderer/shared/agentProgress.ts +51 -3
  229. package/src/renderer/shared/components/Settings/AutomationTab.tsx +2 -56
  230. package/src/renderer/shared/components/Settings/AvatarCropModal.tsx +15 -1
  231. package/src/renderer/shared/components/Settings/GeneralTab.tsx +25 -12
  232. package/src/renderer/shared/components/Settings/ThemeTab.test.tsx +45 -0
  233. package/src/renderer/shared/components/Settings/ThemeTab.tsx +106 -3
  234. package/src/renderer/shared/components/activity/AgentActivityDrawer.tsx +67 -17
  235. package/src/renderer/shared/components/activity/AgentActivityTable.tsx +376 -134
  236. package/src/renderer/shared/components/activity/AskUserActivityCard.test.tsx +122 -0
  237. package/src/renderer/shared/components/activity/AskUserActivityCard.tsx +70 -0
  238. package/src/renderer/shared/components/activity/McpToolResults.tsx +39 -2
  239. package/src/renderer/shared/components/activity/SubagentDagView.tsx +7 -7
  240. package/src/renderer/shared/components/activity/ViewedImages.tsx +41 -2
  241. package/src/renderer/shared/components/app/ChunkErrorBoundary.tsx +3 -3
  242. package/src/renderer/shared/components/app/CommandPalette.tsx +7 -7
  243. package/src/renderer/shared/components/app/DesktopTitlebar.tsx +2 -2
  244. package/src/renderer/shared/components/app/MintDashboard.tsx +27 -17
  245. package/src/renderer/shared/components/app/ModalErrorBoundary.tsx +3 -3
  246. package/src/renderer/shared/components/cards/CalculationCard.tsx +3 -3
  247. package/src/renderer/shared/components/cards/ImageGenCard.tsx +2 -2
  248. package/src/renderer/shared/components/cards/ImageSearchCard.tsx +2 -2
  249. package/src/renderer/shared/components/cards/MermaidCard.tsx +1 -1
  250. package/src/renderer/shared/components/cards/PlanCard.test.tsx +41 -0
  251. package/src/renderer/shared/components/cards/PlanCard.tsx +32 -0
  252. package/src/renderer/shared/components/cards/ReleaseNotesCard.test.tsx +29 -0
  253. package/src/renderer/shared/components/cards/ReleaseNotesCard.tsx +137 -0
  254. package/src/renderer/shared/components/cards/StockCard.tsx +7 -7
  255. package/src/renderer/shared/components/cards/ToolResultCards.tsx +11 -3
  256. package/src/renderer/shared/components/cards/UiMockupWidget.tsx +4 -4
  257. package/src/renderer/shared/components/cards/WeatherCard.tsx +5 -5
  258. package/src/renderer/shared/components/chat/ApprovalCard.test.tsx +11 -0
  259. package/src/renderer/shared/components/chat/ApprovalCard.tsx +21 -2
  260. package/src/renderer/shared/components/chat/ArtifactCards.test.tsx +69 -0
  261. package/src/renderer/shared/components/chat/ArtifactCards.tsx +238 -0
  262. package/src/renderer/shared/components/chat/AttachedDocumentCard.test.tsx +39 -0
  263. package/src/renderer/shared/components/chat/AttachedDocumentCard.tsx +220 -0
  264. package/src/renderer/shared/components/chat/ChatCodeBlock.test.tsx +33 -0
  265. package/src/renderer/shared/components/chat/ChatCodeBlock.tsx +15 -1
  266. package/src/renderer/shared/components/chat/ChatMessageItem.test.tsx +40 -2
  267. package/src/renderer/shared/components/chat/ChatMessageItem.tsx +180 -34
  268. package/src/renderer/shared/components/chat/ChatModeSelector.css +227 -0
  269. package/src/renderer/shared/components/chat/ChatModeSelector.test.tsx +45 -0
  270. package/src/renderer/shared/components/chat/ChatModeSelector.tsx +198 -0
  271. package/src/renderer/shared/components/chat/ChatPanel.test.tsx +22 -0
  272. package/src/renderer/shared/components/chat/ChatPanel.tsx +227 -53
  273. package/src/renderer/shared/components/chat/DiffReviewModal.tsx +6 -6
  274. package/src/renderer/shared/components/chat/GeminiLiveOverlay.test.tsx +142 -1
  275. package/src/renderer/shared/components/chat/GeminiLiveOverlay.tsx +45 -3
  276. package/src/renderer/shared/components/chat/ModelSelectorPopover.tsx +42 -14
  277. package/src/renderer/shared/components/chat/RewindModal.tsx +10 -10
  278. package/src/renderer/shared/components/chat/SlashSuggestions.test.tsx +14 -0
  279. package/src/renderer/shared/components/chat/SourcesBlock.test.tsx +53 -0
  280. package/src/renderer/shared/components/chat/SourcesBlock.tsx +236 -90
  281. package/src/renderer/shared/components/chat/TurnFileChanges.test.tsx +45 -1
  282. package/src/renderer/shared/components/chat/TurnFileChanges.tsx +202 -169
  283. package/src/renderer/shared/components/extensions/CliSessionsView.tsx +5 -4
  284. package/src/renderer/shared/components/extensions/McpRegistryPicker.tsx +3 -3
  285. package/src/renderer/shared/components/studio/LibraryPage.tsx +48 -5
  286. package/src/renderer/shared/components/workspace/ArtifactPreviewPanel.tsx +125 -13
  287. package/src/renderer/shared/components/workspace/CodeReviewPage.test.tsx +50 -0
  288. package/src/renderer/shared/components/workspace/CodeReviewPage.tsx +77 -16
  289. package/src/renderer/shared/components/workspace/GitBranchSelector.tsx +78 -22
  290. package/src/renderer/shared/components/workspace/ToolSurfacePage.test.tsx +13 -0
  291. package/src/renderer/shared/components/workspace/ToolSurfacePage.tsx +48 -28
  292. package/src/renderer/shared/components/workspace/WorkspacePdfPreview.tsx +266 -47
  293. package/src/renderer/shared/components/workspace/WorkspacePreviewActions.test.tsx +18 -6
  294. package/src/renderer/shared/components/workspace/background-terminals.css +11 -11
  295. package/src/renderer/shared/constants/config.ts +1 -5
  296. package/src/renderer/shared/constants/models.test.ts +51 -0
  297. package/src/renderer/shared/constants/models.ts +139 -32
  298. package/src/renderer/shared/conversation/lifecycle.test.ts +91 -3
  299. package/src/renderer/shared/conversation/lifecycle.ts +104 -5
  300. package/src/renderer/shared/conversation/progressiveStream.test.ts +83 -0
  301. package/src/renderer/shared/conversation/progressiveStream.ts +219 -0
  302. package/src/renderer/shared/css/agent-observability.css +133 -0
  303. package/src/renderer/shared/css/chat-ui-cards.css +13 -13
  304. package/src/renderer/shared/css/code-review.css +63 -34
  305. package/src/renderer/shared/css/code-sessions.css +47 -18
  306. package/src/renderer/shared/css/collapsed-paste.css +1 -1
  307. package/src/renderer/shared/css/error-notice.css +1 -1
  308. package/src/renderer/shared/css/file-changes.css +165 -80
  309. package/src/renderer/shared/css/library.css +105 -10
  310. package/src/renderer/shared/css/management-views.css +1 -1
  311. package/src/renderer/shared/css/mcp-results.css +5 -5
  312. package/src/renderer/shared/css/model-selector.css +18 -18
  313. package/src/renderer/shared/css/mods.css +7 -7
  314. package/src/renderer/shared/css/notification-notice.css +2 -2
  315. package/src/renderer/shared/css/queued-messages.css +5 -5
  316. package/src/renderer/shared/css/settings/general.css +18 -13
  317. package/src/renderer/shared/css/settings/profile.css +5 -5
  318. package/src/renderer/shared/css/settings/theme.css +5 -5
  319. package/src/renderer/shared/css/slash-choice.css +2 -2
  320. package/src/renderer/shared/css/slash-suggestions.css +3 -3
  321. package/src/renderer/shared/css/sources-block.css +41 -2
  322. package/src/renderer/shared/css/tools-panel.css +2 -2
  323. package/src/renderer/shared/css/ui-tailwind.css +8 -0
  324. package/src/renderer/shared/css/veo-studio.css +2 -2
  325. package/src/renderer/shared/css/viewed-images.css +7 -7
  326. package/src/renderer/shared/platform.ts +2 -1
  327. package/src/renderer/shared/theme/themeManager.test.ts +17 -0
  328. package/src/renderer/shared/theme/themeManager.ts +21 -4
  329. package/src/renderer/shared/theme/themes.ts +54 -0
  330. package/src/renderer/shared/theme/tokens.css +6 -4
  331. package/src/renderer/shared/types.ts +1 -1
  332. package/src/renderer/shared/utils/agentActivity.test.ts +468 -2
  333. package/src/renderer/shared/utils/agentActivity.ts +602 -35
  334. package/src/renderer/shared/utils/artifactBrowser.test.ts +37 -32
  335. package/src/renderer/shared/utils/artifactBrowser.ts +17 -19
  336. package/src/renderer/shared/utils/attachedDocument.test.ts +73 -0
  337. package/src/renderer/shared/utils/attachedDocument.ts +49 -0
  338. package/src/renderer/shared/utils/fileIcons.test.ts +59 -0
  339. package/src/renderer/shared/utils/fileIcons.ts +149 -16
  340. package/src/renderer/shared/utils/markdown.tsx +72 -19
  341. package/src/renderer/shared/utils/markdown.webImages.test.tsx +16 -0
  342. package/src/renderer/shared/utils/mcpResults.test.tsx +29 -0
  343. package/src/renderer/shared/utils/slashCommandProcessor.ts +4 -1
  344. package/src/renderer/shared/utils/syntaxHighlight.test.tsx +11 -1
  345. package/src/renderer/shared/utils/syntaxHighlight.tsx +51 -3
  346. package/src/renderer/shared/utils/useGeminiLiveVoice.ts +324 -51
  347. package/src/renderer/shared/utils/workspaceDrag.test.ts +153 -0
  348. package/src/renderer/shared/utils/workspaceDrag.ts +142 -0
  349. package/src/renderer/shared/utils/workspaceMedia.ts +10 -2
  350. package/src/renderer/src/App.tsx +14 -8
  351. package/src/renderer/src/agentProgress.ts +1 -0
  352. package/src/renderer/src/components/ScreenPicker.css +1 -1
  353. package/src/renderer/src/components/WorkspacePanel.tsx +6 -5
  354. package/src/renderer/src/css/app-shell.css +4 -4
  355. package/src/renderer/src/css/chat.css +1261 -241
  356. package/src/renderer/src/css/desktop-tools.css +11 -11
  357. package/src/renderer/src/css/sidebar-workspace.css +2 -2
  358. package/src/renderer/src/css/tool-surfaces.css +12 -12
  359. package/src/renderer/src/index.css +38 -20
  360. package/src/renderer/src/tauri.ts +22 -2
  361. package/src/renderer/src-web/App.tsx +14 -0
  362. package/src/renderer/src-web/agentProgress.ts +1 -0
  363. package/src/renderer/src-web/css/app-shell.css +4 -4
  364. package/src/renderer/src-web/css/chat.css +1278 -190
  365. package/src/renderer/src-web/css/mobile.css +29 -13
  366. package/src/renderer/src-web/css/settings/mobile.css +2 -2
  367. package/src/renderer/src-web/css/sidebar-workspace.css +1 -1
  368. package/src/renderer/src-web/index.css +38 -20
  369. package/src/renderer/src-web/tauri.ts +22 -2
  370. package/src/renderer/tests/browserArtifacts.browser.tsx +1 -1
  371. package/src/renderer/tests/library.browser.tsx +3 -0
  372. package/src/renderer/tests/liveVoice.browser.html +1 -0
  373. package/src/renderer/tests/workspaceDrop.browser.tsx +1 -1
  374. package/src-tauri/src/app/lifecycle.rs +1 -14
  375. package/src-tauri/src/background/headless.rs +14 -8
  376. package/src-tauri/src/commands/conversation.rs +38 -0
  377. package/src-tauri/src/native/mod.rs +0 -1
  378. package/src-tauri/src/native/system.rs +4 -47
  379. package/crates/mint-cli/src/interactive/chat_tui.rs +0 -8855
  380. package/crates/mint-core/src/agent/chat.rs +0 -4394
  381. package/crates/mint-core/src/browser/lifecycle.rs +0 -291
  382. package/crates/mint-core/src/browser/logging.rs +0 -20
  383. package/crates/mint-core/src/orchestration/tools/browser.rs +0 -31
  384. package/out/web/assets/ArtifactPreviewPanel-S0dPfYFx.js +0 -2
  385. package/out/web/assets/CalculationCard-CRjP3E1j.js +0 -1
  386. package/out/web/assets/CliSessionsView-C3Br2v5Y.css +0 -1
  387. package/out/web/assets/CodeReviewPage-CUJceQme.css +0 -1
  388. package/out/web/assets/CodeReviewPage-VCUgPla_.js +0 -2
  389. package/out/web/assets/ImageGenCard-BCXxkVJX.js +0 -1
  390. package/out/web/assets/ImageSearchCard-N3yQOr8Z.js +0 -1
  391. package/out/web/assets/LibraryPage-DAxUTAg7.css +0 -1
  392. package/out/web/assets/LibraryPage-WlviRdR8.js +0 -2
  393. package/out/web/assets/LinkedFoldersView-CKRgroWK.js +0 -1
  394. package/out/web/assets/McpServersView-D3wHnuHg.js +0 -1
  395. package/out/web/assets/MermaidCard-NqrHdyJW.js +0 -2
  396. package/out/web/assets/MintDashboard-B2DJsDDO.css +0 -1
  397. package/out/web/assets/MintDashboard-COw_xol7.js +0 -63
  398. package/out/web/assets/RewindModal-DempuDod.js +0 -1
  399. package/out/web/assets/SettingsWindow-2YP3yj7s.js +0 -4
  400. package/out/web/assets/SettingsWindow-Dz8LQVgD.css +0 -1
  401. package/out/web/assets/StockCard-BDMCe7mx.js +0 -1
  402. package/out/web/assets/ToolSurfacePage-B0J_q0Jl.js +0 -38
  403. package/out/web/assets/ToolSurfacePage-CRIQ1owD.css +0 -1
  404. package/out/web/assets/UiMockupWidget-DD73QWg1.js +0 -1
  405. package/out/web/assets/WeatherCard-CPucIfq8.js +0 -1
  406. package/out/web/assets/WorkspacePdfPreview-Dx_lkjNu.js +0 -2
  407. package/out/web/assets/classDiagram-ZZMXUADV-BgJ5WtSp.js +0 -1
  408. package/out/web/assets/classDiagram-v2-VYDZK3BY-BgJ5WtSp.js +0 -1
  409. package/out/web/assets/config-CvIO5hkn.js +0 -2
  410. package/out/web/assets/flowDiagram-HODETNUW-uqCHJond.js +0 -1
  411. package/out/web/assets/index-BmpulIkg.js +0 -168
  412. package/out/web/assets/index-CkvBwhX_.css +0 -1
  413. package/out/web/assets/stateDiagram-v2-MP3YSRHH-uf3kdNW4.js +0 -1
  414. package/out/web/assets/swimlanesDiagram-VR7AAH4N-Y8q5bQce.js +0 -8
  415. package/shared-modules/libsecret/libsecret.json +0 -23
  416. package/shared-modules/libusb/libusb.json +0 -27
  417. package/shared-modules/lzo/lzo.json +0 -27
  418. package/src/renderer/src/components/BrowserShell.tsx +0 -108
  419. package/src/renderer/src/components/BrowserSuggestionsPopup.tsx +0 -91
  420. package/src/renderer/src/components/browser-shell.css +0 -185
  421. package/src-tauri/src/native/browser.rs +0 -252
@@ -0,0 +1,728 @@
1
+ //! Width-reactive transcript entries, paragraph layout, and user message highlighting.
2
+ use super::*;
3
+
4
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
5
+ pub(crate) enum TranscriptRole {
6
+ User,
7
+ Assistant,
8
+ Notice,
9
+ Command,
10
+ ReleaseNotes,
11
+ Plan,
12
+ #[allow(dead_code)]
13
+ System,
14
+ }
15
+ #[derive(Debug, Clone, PartialEq, Eq)]
16
+ pub(crate) struct TranscriptEntry {
17
+ pub role: TranscriptRole,
18
+ pub text: String,
19
+ pub rendered_lines: Vec<Line<'static>>,
20
+ pub plain_lines: Vec<String>,
21
+ pub rendered_width: u16,
22
+ }
23
+
24
+ impl TranscriptEntry {
25
+ pub fn new(role: TranscriptRole, text: impl Into<String>) -> Self {
26
+ let (default_width, _) = crate::markdown::terminal_size_or_default();
27
+ Self::new_with_width(role, text, default_width)
28
+ }
29
+
30
+ pub fn new_with_width(role: TranscriptRole, text: impl Into<String>, width: u16) -> Self {
31
+ let text = text.into();
32
+ let (rendered_lines, plain_lines) =
33
+ Self::render_content_with_width(role, &text, width as usize);
34
+ Self {
35
+ role,
36
+ text,
37
+ rendered_lines,
38
+ plain_lines,
39
+ rendered_width: width,
40
+ }
41
+ }
42
+
43
+ pub fn lines_for_width(&self, width: u16) -> std::borrow::Cow<'_, [Line<'static>]> {
44
+ if (self.role != TranscriptRole::Assistant
45
+ && self.role != TranscriptRole::ReleaseNotes
46
+ && self.role != TranscriptRole::Plan)
47
+ || width == 0
48
+ || width == self.rendered_width
49
+ || self.text.is_empty()
50
+ {
51
+ return std::borrow::Cow::Borrowed(&self.rendered_lines);
52
+ }
53
+ if self.role == TranscriptRole::ReleaseNotes || self.role == TranscriptRole::Plan {
54
+ let (rendered, _) =
55
+ Self::render_content_with_width(self.role, &self.text, width as usize);
56
+ return std::borrow::Cow::Owned(rendered);
57
+ }
58
+ let needs_width_reflow = self.text.contains('|')
59
+ || self.text.contains("```")
60
+ || self.text.contains("---")
61
+ || self.text.contains("***")
62
+ || self.text.contains("___")
63
+ || self.text.contains("ui-");
64
+ if !needs_width_reflow {
65
+ return std::borrow::Cow::Borrowed(&self.rendered_lines);
66
+ }
67
+ let (rendered, _) = Self::render_content_with_width(self.role, &self.text, width as usize);
68
+ std::borrow::Cow::Owned(rendered)
69
+ }
70
+
71
+ fn render_content_with_width(
72
+ role: TranscriptRole,
73
+ text: &str,
74
+ width: usize,
75
+ ) -> (Vec<Line<'static>>, Vec<String>) {
76
+ use ansi_to_tui::IntoText;
77
+ if text.is_empty() {
78
+ return (Vec::new(), Vec::new());
79
+ }
80
+ match role {
81
+ TranscriptRole::Assistant => {
82
+ let sanitized = crate::agent::sanitize_latex(text);
83
+ crate::agent::render_markdown_to_lines(&sanitized, width)
84
+ }
85
+ TranscriptRole::User => {
86
+ let normalized = normalize_prompt_newlines(text);
87
+ let rendered_lines = normalized
88
+ .as_str()
89
+ .into_text()
90
+ .map(|parsed| parsed.lines)
91
+ .unwrap_or_else(|_| {
92
+ normalized
93
+ .lines()
94
+ .map(|line| Line::raw(line.to_owned()))
95
+ .collect()
96
+ });
97
+ let plain_lines = rendered_lines
98
+ .iter()
99
+ .map(|line| {
100
+ line.spans
101
+ .iter()
102
+ .map(|span| span.content.as_ref())
103
+ .collect()
104
+ })
105
+ .collect();
106
+ (rendered_lines, plain_lines)
107
+ }
108
+ TranscriptRole::Notice | TranscriptRole::Command | TranscriptRole::System => {
109
+ let rendered_lines =
110
+ text.into_text()
111
+ .map(|parsed| parsed.lines)
112
+ .unwrap_or_else(|_| {
113
+ text.lines()
114
+ .map(|line| Line::raw(line.to_owned()))
115
+ .collect()
116
+ });
117
+ let plain_lines = rendered_lines
118
+ .iter()
119
+ .map(|line| {
120
+ line.spans
121
+ .iter()
122
+ .map(|span| span.content.as_ref())
123
+ .collect()
124
+ })
125
+ .collect();
126
+ (rendered_lines, plain_lines)
127
+ }
128
+ TranscriptRole::ReleaseNotes => render_release_notes_card_to_lines(text, width as u16),
129
+ TranscriptRole::Plan => render_plan_card_to_lines(text, width as u16),
130
+ }
131
+ }
132
+ }
133
+
134
+ pub(super) fn render_release_notes_card_to_lines(
135
+ text: &str,
136
+ width: u16,
137
+ ) -> (Vec<Line<'static>>, Vec<String>) {
138
+ use ratatui::widgets::Widget;
139
+
140
+ if text.is_empty() {
141
+ return (Vec::new(), Vec::new());
142
+ }
143
+
144
+ let mut version = String::new();
145
+ let mut sections_count = 0;
146
+ let mut inner_lines: Vec<Line<'static>> = Vec::new();
147
+ let mut plain_lines: Vec<String> = Vec::new();
148
+
149
+ let padding = if width >= 40 { 1u16 } else { 0u16 };
150
+ let card_width = width.saturating_sub(padding * 2 + 2).max(20);
151
+
152
+ for line in text.lines() {
153
+ let trimmed = line.trim();
154
+ if trimmed.is_empty() {
155
+ if !inner_lines.is_empty() {
156
+ inner_lines.push(Line::default());
157
+ plain_lines.push(String::new());
158
+ }
159
+ continue;
160
+ }
161
+
162
+ if trimmed.starts_with("# ") {
163
+ if let Some(pos) = trimmed.rfind('v') {
164
+ version = trimmed[pos..].trim().to_string();
165
+ }
166
+ continue;
167
+ }
168
+
169
+ if trimmed.starts_with("## ") {
170
+ sections_count += 1;
171
+ let section_title = trimmed[3..].trim();
172
+ if !inner_lines.is_empty() && !inner_lines.last().map_or(false, |l| l.spans.is_empty())
173
+ {
174
+ inner_lines.push(Line::default());
175
+ plain_lines.push(String::new());
176
+ }
177
+ inner_lines.push(Line::from(vec![
178
+ Span::raw(" "),
179
+ Span::styled(
180
+ "● ",
181
+ Style::default()
182
+ .fg(crate::terminal_theme::CARD_BORDER)
183
+ .add_modifier(Modifier::BOLD),
184
+ ),
185
+ Span::styled(
186
+ section_title.to_string(),
187
+ Style::default()
188
+ .fg(crate::terminal_theme::TEXT)
189
+ .add_modifier(Modifier::BOLD),
190
+ ),
191
+ ]));
192
+ plain_lines.push(format!("● {}", section_title));
193
+ continue;
194
+ }
195
+
196
+ let indent = line.len() - line.trim_start().len();
197
+ if trimmed.starts_with("- ") || trimmed.starts_with("* ") {
198
+ let bullet_content = trimmed[2..].trim();
199
+ let (prefix_indent, bullet_color) = if indent >= 2 {
200
+ (" • ", crate::terminal_theme::MUTED)
201
+ } else {
202
+ (" • ", crate::terminal_theme::ACCENT)
203
+ };
204
+
205
+ let spans = if bullet_content.starts_with("**") {
206
+ if let Some(end_bold) = bullet_content[2..].find("**") {
207
+ let title = &bullet_content[2..2 + end_bold];
208
+ let rest = &bullet_content[2 + end_bold + 2..];
209
+ vec![
210
+ Span::styled(prefix_indent, Style::default().fg(bullet_color)),
211
+ Span::styled(
212
+ title.to_string(),
213
+ Style::default()
214
+ .fg(crate::terminal_theme::TEXT)
215
+ .add_modifier(Modifier::BOLD),
216
+ ),
217
+ Span::styled(
218
+ rest.to_string(),
219
+ Style::default().fg(crate::terminal_theme::TEXT),
220
+ ),
221
+ ]
222
+ } else {
223
+ vec![
224
+ Span::styled(prefix_indent, Style::default().fg(bullet_color)),
225
+ Span::styled(
226
+ bullet_content.to_string(),
227
+ Style::default().fg(crate::terminal_theme::TEXT),
228
+ ),
229
+ ]
230
+ }
231
+ } else {
232
+ vec![
233
+ Span::styled(prefix_indent, Style::default().fg(bullet_color)),
234
+ Span::styled(
235
+ bullet_content.to_string(),
236
+ Style::default().fg(crate::terminal_theme::TEXT),
237
+ ),
238
+ ]
239
+ };
240
+ let plain_str = format!("{}{}", prefix_indent, bullet_content.replace("**", ""));
241
+ plain_lines.push(plain_str);
242
+ inner_lines.push(Line::from(spans));
243
+ continue;
244
+ }
245
+
246
+ inner_lines.push(Line::from(vec![
247
+ Span::raw(" "),
248
+ Span::raw(trimmed.to_string()),
249
+ ]));
250
+ plain_lines.push(trimmed.to_string());
251
+ }
252
+
253
+ if version.is_empty() {
254
+ version = format!("v{}", env!("CARGO_PKG_VERSION"));
255
+ }
256
+
257
+ plain_lines.insert(0, format!("Release Notes · {}", version));
258
+
259
+ let bg_color = crate::terminal_theme::CARD_BACKGROUND;
260
+ let bg_style = Style::default().bg(bg_color);
261
+
262
+ let title_line = Line::from(vec![
263
+ Span::raw(" "),
264
+ Span::styled(
265
+ "🚀 Release Notes ",
266
+ Style::default()
267
+ .fg(crate::terminal_theme::ACCENT)
268
+ .add_modifier(Modifier::BOLD),
269
+ ),
270
+ Span::styled(
271
+ format!("· {} ", version),
272
+ Style::default()
273
+ .fg(crate::terminal_theme::TEXT)
274
+ .add_modifier(Modifier::BOLD),
275
+ ),
276
+ ]);
277
+
278
+ let footer_line = Line::from(vec![
279
+ Span::raw(" "),
280
+ Span::styled(
281
+ format!("[ {} Highlights · Latest ]", sections_count),
282
+ Style::default().fg(crate::terminal_theme::MUTED),
283
+ ),
284
+ ]);
285
+
286
+ let mut card_lines = Vec::with_capacity(inner_lines.len() + 6);
287
+ card_lines.push(Line::default()); // top padding
288
+ card_lines.push(title_line);
289
+ card_lines.push(Line::default());
290
+ card_lines.extend(inner_lines);
291
+ card_lines.push(Line::default());
292
+ card_lines.push(footer_line);
293
+ card_lines.push(Line::default()); // bottom padding
294
+
295
+ let paragraph = Paragraph::new(card_lines)
296
+ .style(bg_style)
297
+ .wrap(Wrap { trim: false });
298
+ let card_height = paragraph
299
+ .line_count(card_width)
300
+ .max(1)
301
+ .min(u16::MAX as usize) as u16;
302
+
303
+ let area = Rect::new(0, 0, card_width, card_height);
304
+ let mut buffer = Buffer::empty(area);
305
+ for cell in &mut buffer.content {
306
+ cell.set_bg(bg_color);
307
+ }
308
+ let widget = paragraph.block(Block::default().style(bg_style));
309
+ widget.render(area, &mut buffer);
310
+
311
+ let rendered_lines: Vec<Line<'static>> = (0..card_height)
312
+ .map(|y| {
313
+ let mut spans = Vec::new();
314
+ if padding > 0 {
315
+ spans.push(Span::raw(" ".repeat(padding as usize)));
316
+ }
317
+ let mut x = 0;
318
+ while x < card_width {
319
+ let cell = &buffer[(x, y)];
320
+ let mut style = cell.style();
321
+ style.bg = Some(bg_color);
322
+ let sym = if cell.symbol() == " " {
323
+ "\u{00A0}"
324
+ } else {
325
+ cell.symbol()
326
+ };
327
+ spans.push(Span::styled(sym.to_owned(), style));
328
+ x += UnicodeWidthStr::width(cell.symbol()).max(1) as u16;
329
+ }
330
+ Line::from(spans)
331
+ })
332
+ .collect();
333
+
334
+ (rendered_lines, plain_lines)
335
+ }
336
+
337
+ pub(super) fn render_plan_card_to_lines(
338
+ text: &str,
339
+ width: u16,
340
+ ) -> (Vec<Line<'static>>, Vec<String>) {
341
+ use ratatui::widgets::Widget;
342
+
343
+ if text.is_empty() {
344
+ return (Vec::new(), Vec::new());
345
+ }
346
+
347
+ let mut title = String::new();
348
+ let mut inner_lines: Vec<Line<'static>> = Vec::new();
349
+ let mut plain_lines: Vec<String> = Vec::new();
350
+
351
+ let padding = if width >= 40 { 1u16 } else { 0u16 };
352
+ let card_width = width.saturating_sub(padding * 2 + 2).max(20);
353
+
354
+ let mut in_code_block = false;
355
+
356
+ for line in text.lines() {
357
+ let trimmed = line.trim();
358
+
359
+ if trimmed.starts_with("```") {
360
+ in_code_block = !in_code_block;
361
+ inner_lines.push(Line::from(vec![
362
+ Span::raw(" "),
363
+ Span::styled(
364
+ trimmed.to_string(),
365
+ Style::default().fg(crate::terminal_theme::MUTED),
366
+ ),
367
+ ]));
368
+ plain_lines.push(trimmed.to_string());
369
+ continue;
370
+ }
371
+
372
+ if in_code_block {
373
+ inner_lines.push(Line::from(vec![
374
+ Span::raw(" "),
375
+ Span::styled(
376
+ line.to_string(),
377
+ Style::default().fg(crate::terminal_theme::TEXT),
378
+ ),
379
+ ]));
380
+ plain_lines.push(format!(" {}", line));
381
+ continue;
382
+ }
383
+
384
+ if trimmed.is_empty() {
385
+ if !inner_lines.is_empty() && !inner_lines.last().map_or(false, |l| l.spans.is_empty())
386
+ {
387
+ inner_lines.push(Line::default());
388
+ plain_lines.push(String::new());
389
+ }
390
+ continue;
391
+ }
392
+
393
+ // Title at level 1: # Title
394
+ if trimmed.starts_with("# ") && title.is_empty() {
395
+ title = trimmed[2..].trim().to_string();
396
+ continue;
397
+ }
398
+
399
+ // Section header: ## or ### or # (if title already set)
400
+ if trimmed.starts_with("### ") || trimmed.starts_with("## ") || trimmed.starts_with("# ") {
401
+ let hash_count = trimmed.chars().take_while(|&c| c == '#').count();
402
+ let section_title = trimmed[hash_count..].trim();
403
+ if !inner_lines.is_empty() && !inner_lines.last().map_or(false, |l| l.spans.is_empty())
404
+ {
405
+ inner_lines.push(Line::default());
406
+ plain_lines.push(String::new());
407
+ }
408
+ inner_lines.push(Line::from(vec![
409
+ Span::raw(" "),
410
+ Span::styled(
411
+ "● ",
412
+ Style::default()
413
+ .fg(crate::terminal_theme::ACCENT)
414
+ .add_modifier(Modifier::BOLD),
415
+ ),
416
+ Span::styled(
417
+ section_title.to_string(),
418
+ Style::default()
419
+ .fg(crate::terminal_theme::TEXT)
420
+ .add_modifier(Modifier::BOLD),
421
+ ),
422
+ ]));
423
+ plain_lines.push(format!("● {}", section_title));
424
+ continue;
425
+ }
426
+
427
+ // Checklists: - [ ] or - [x] or * [ ] or * [x]
428
+ if (trimmed.starts_with("- [ ] ") || trimmed.starts_with("* [ ] "))
429
+ || (trimmed.starts_with("- [x] ")
430
+ || trimmed.starts_with("- [X] ")
431
+ || trimmed.starts_with("* [x] ")
432
+ || trimmed.starts_with("* [X] "))
433
+ {
434
+ let is_checked = trimmed.starts_with("- [x] ")
435
+ || trimmed.starts_with("- [X] ")
436
+ || trimmed.starts_with("* [x] ")
437
+ || trimmed.starts_with("* [X] ");
438
+ let item_text = trimmed[6..].trim();
439
+ let (status_icon, status_color) = if is_checked {
440
+ ("[✓] ", crate::terminal_theme::ACCENT)
441
+ } else {
442
+ ("[ ] ", crate::terminal_theme::SUBTLE)
443
+ };
444
+
445
+ let spans = vec![
446
+ Span::raw(" "),
447
+ Span::styled(
448
+ status_icon,
449
+ Style::default()
450
+ .fg(status_color)
451
+ .add_modifier(Modifier::BOLD),
452
+ ),
453
+ Span::styled(
454
+ item_text.to_string(),
455
+ Style::default().fg(crate::terminal_theme::TEXT),
456
+ ),
457
+ ];
458
+ plain_lines.push(format!(" {}{}", status_icon, item_text));
459
+ inner_lines.push(Line::from(spans));
460
+ continue;
461
+ }
462
+
463
+ let indent = line.len() - line.trim_start().len();
464
+
465
+ // Numbered list: e.g. "1. ", "2. ", "10. "
466
+ let is_numbered = if let Some(dot_idx) = trimmed.find(". ") {
467
+ !trimmed[..dot_idx].is_empty() && trimmed[..dot_idx].chars().all(|c| c.is_ascii_digit())
468
+ } else {
469
+ false
470
+ };
471
+
472
+ if is_numbered {
473
+ let dot_idx = trimmed.find(". ").unwrap();
474
+ let num_prefix = &trimmed[..=dot_idx]; // e.g. "1."
475
+ let item_text = trimmed[dot_idx + 2..].trim();
476
+ let prefix_indent = if indent >= 2 { " " } else { " " };
477
+
478
+ let spans = vec![
479
+ Span::styled(
480
+ format!("{}{}", prefix_indent, num_prefix),
481
+ Style::default()
482
+ .fg(crate::terminal_theme::ACCENT)
483
+ .add_modifier(Modifier::BOLD),
484
+ ),
485
+ Span::raw(" "),
486
+ Span::styled(
487
+ item_text.to_string(),
488
+ Style::default().fg(crate::terminal_theme::TEXT),
489
+ ),
490
+ ];
491
+ plain_lines.push(format!("{}{} {}", prefix_indent, num_prefix, item_text));
492
+ inner_lines.push(Line::from(spans));
493
+ continue;
494
+ }
495
+
496
+ // Bullet lists: - or *
497
+ if trimmed.starts_with("- ") || trimmed.starts_with("* ") {
498
+ let bullet_content = trimmed[2..].trim();
499
+ let (prefix_indent, bullet_color) = if indent >= 2 {
500
+ (" • ", crate::terminal_theme::MUTED)
501
+ } else {
502
+ (" • ", crate::terminal_theme::ACCENT)
503
+ };
504
+
505
+ let spans = if bullet_content.starts_with("**") {
506
+ if let Some(end_bold) = bullet_content[2..].find("**") {
507
+ let b_title = &bullet_content[2..2 + end_bold];
508
+ let rest = &bullet_content[2 + end_bold + 2..];
509
+ vec![
510
+ Span::styled(prefix_indent, Style::default().fg(bullet_color)),
511
+ Span::styled(
512
+ b_title.to_string(),
513
+ Style::default()
514
+ .fg(crate::terminal_theme::TEXT)
515
+ .add_modifier(Modifier::BOLD),
516
+ ),
517
+ Span::styled(
518
+ rest.to_string(),
519
+ Style::default().fg(crate::terminal_theme::TEXT),
520
+ ),
521
+ ]
522
+ } else {
523
+ vec![
524
+ Span::styled(prefix_indent, Style::default().fg(bullet_color)),
525
+ Span::styled(
526
+ bullet_content.to_string(),
527
+ Style::default().fg(crate::terminal_theme::TEXT),
528
+ ),
529
+ ]
530
+ }
531
+ } else {
532
+ vec![
533
+ Span::styled(prefix_indent, Style::default().fg(bullet_color)),
534
+ Span::styled(
535
+ bullet_content.to_string(),
536
+ Style::default().fg(crate::terminal_theme::TEXT),
537
+ ),
538
+ ]
539
+ };
540
+ let plain_str = format!("{}{}", prefix_indent, bullet_content.replace("**", ""));
541
+ plain_lines.push(plain_str);
542
+ inner_lines.push(Line::from(spans));
543
+ continue;
544
+ }
545
+
546
+ // Normal paragraph text
547
+ inner_lines.push(Line::from(vec![
548
+ Span::raw(" "),
549
+ Span::styled(
550
+ trimmed.to_string(),
551
+ Style::default().fg(crate::terminal_theme::TEXT),
552
+ ),
553
+ ]));
554
+ plain_lines.push(format!(" {}", trimmed));
555
+ }
556
+
557
+ let bg_color = crate::terminal_theme::CARD_BACKGROUND;
558
+ let bg_style = Style::default().bg(bg_color);
559
+
560
+ let title_line = Line::from(vec![
561
+ Span::raw(" "),
562
+ Span::styled(
563
+ "📋 Proposed Plan ",
564
+ Style::default()
565
+ .fg(crate::terminal_theme::ACCENT)
566
+ .add_modifier(Modifier::BOLD),
567
+ ),
568
+ Span::styled(
569
+ if title.is_empty() {
570
+ "· Plan Review".to_string()
571
+ } else {
572
+ format!("· {}", title)
573
+ },
574
+ Style::default()
575
+ .fg(crate::terminal_theme::TEXT)
576
+ .add_modifier(Modifier::BOLD),
577
+ ),
578
+ ]);
579
+
580
+ let footer_line = Line::from(vec![
581
+ Span::raw(" "),
582
+ Span::styled(
583
+ "[ Review plan above · Choose Approve to execute or Deny below ]",
584
+ Style::default().fg(crate::terminal_theme::MUTED),
585
+ ),
586
+ ]);
587
+
588
+ let mut card_lines = Vec::with_capacity(inner_lines.len() + 6);
589
+ card_lines.push(Line::default()); // top padding
590
+ card_lines.push(title_line);
591
+ card_lines.push(Line::default());
592
+ card_lines.extend(inner_lines);
593
+ card_lines.push(Line::default());
594
+ card_lines.push(footer_line);
595
+ card_lines.push(Line::default()); // bottom padding
596
+
597
+ let paragraph = Paragraph::new(card_lines)
598
+ .style(bg_style)
599
+ .wrap(Wrap { trim: false });
600
+ let card_height = paragraph
601
+ .line_count(card_width)
602
+ .max(1)
603
+ .min(u16::MAX as usize) as u16;
604
+
605
+ let area = Rect::new(0, 0, card_width, card_height);
606
+ let mut buffer = Buffer::empty(area);
607
+ for cell in &mut buffer.content {
608
+ cell.set_bg(bg_color);
609
+ }
610
+ let widget = paragraph.block(Block::default().style(bg_style));
611
+ widget.render(area, &mut buffer);
612
+
613
+ let rendered_lines: Vec<Line<'static>> = (0..card_height)
614
+ .map(|y| {
615
+ let mut spans = Vec::new();
616
+ if padding > 0 {
617
+ spans.push(Span::raw(" ".repeat(padding as usize)));
618
+ }
619
+ let mut x = 0;
620
+ while x < card_width {
621
+ let cell = &buffer[(x, y)];
622
+ let mut style = cell.style();
623
+ style.bg = Some(bg_color);
624
+ let sym = if cell.symbol() == " " {
625
+ "\u{00A0}"
626
+ } else {
627
+ cell.symbol()
628
+ };
629
+ spans.push(Span::styled(sym.to_owned(), style));
630
+ x += UnicodeWidthStr::width(cell.symbol()).max(1) as u16;
631
+ }
632
+ Line::from(spans)
633
+ })
634
+ .collect();
635
+
636
+ plain_lines.insert(
637
+ 0,
638
+ if title.is_empty() {
639
+ "Proposed Plan · Plan Review".to_string()
640
+ } else {
641
+ format!("Proposed Plan · {}", title)
642
+ },
643
+ );
644
+
645
+ (rendered_lines, plain_lines)
646
+ }
647
+
648
+ // Wrap first, then pad each visual row: a line background alone would leave
649
+ // the unused columns after short text unpainted in the transcript paragraph.
650
+ pub(super) fn highlighted_user_content(line: Line<'static>, width: u16) -> Vec<Line<'static>> {
651
+ use ratatui::widgets::Widget;
652
+
653
+ let padding = u16::from(width > 2);
654
+ let inner_width = width.saturating_sub(padding * 2).max(1);
655
+ let background = Style::default()
656
+ .fg(crate::terminal_theme::TEXT)
657
+ .bg(crate::terminal_theme::USER_MESSAGE_BACKGROUND);
658
+ let paragraph = Paragraph::new(line)
659
+ .style(background)
660
+ .wrap(Wrap { trim: false });
661
+ let height = paragraph
662
+ .line_count(inner_width)
663
+ .max(1)
664
+ .min(u16::MAX as usize) as u16;
665
+ let area = Rect::new(0, 0, inner_width, height);
666
+ let mut buffer = Buffer::empty(area);
667
+ paragraph.render(area, &mut buffer);
668
+ (0..height)
669
+ .map(|y| {
670
+ let mut spans = vec![Span::styled(" ".repeat(padding as usize), background)];
671
+ let mut x = 0;
672
+ while x < inner_width {
673
+ let cell = &buffer[(x, y)];
674
+ spans.push(Span::styled(cell.symbol().to_owned(), cell.style()));
675
+ x += UnicodeWidthStr::width(cell.symbol()).max(1) as u16;
676
+ }
677
+ spans.push(Span::styled(" ".repeat(padding as usize), background));
678
+ Line::from(spans)
679
+ })
680
+ .collect()
681
+ }
682
+
683
+ // Keep styled text and visual-row offsets, rather than cells for the whole history.
684
+ pub(super) struct TranscriptLayout {
685
+ pub(super) text: Text<'static>,
686
+ pub(super) row_starts: Vec<usize>,
687
+ pub(super) height: usize,
688
+ pub(super) width: u16,
689
+ }
690
+
691
+ impl TranscriptLayout {
692
+ pub(super) fn new(text: Text<'static>, width: u16) -> Self {
693
+ let mut height = 0;
694
+ let row_starts = text
695
+ .lines
696
+ .iter()
697
+ .map(|line| {
698
+ let start = height;
699
+ height += Paragraph::new(line.clone())
700
+ .wrap(Wrap { trim: false })
701
+ .line_count(width.max(1))
702
+ .max(1);
703
+ start
704
+ })
705
+ .collect();
706
+ Self {
707
+ text,
708
+ row_starts,
709
+ height,
710
+ width,
711
+ }
712
+ }
713
+ pub(super) fn paragraph_at(&self, row: usize) -> Paragraph<'static> {
714
+ let line = self
715
+ .row_starts
716
+ .partition_point(|start| *start <= row)
717
+ .saturating_sub(1);
718
+ let offset = row.saturating_sub(self.row_starts.get(line).copied().unwrap_or(0));
719
+ let text = Text {
720
+ lines: self.text.lines.get(line..).unwrap_or_default().to_vec(),
721
+ style: self.text.style,
722
+ alignment: self.text.alignment,
723
+ };
724
+ Paragraph::new(text)
725
+ .wrap(Wrap { trim: false })
726
+ .scroll((offset.min(u16::MAX as usize) as u16, 0))
727
+ }
728
+ }