@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
@@ -9,7 +9,7 @@ import {
9
9
  File,
10
10
  Eye,
11
11
  } from 'lucide-react'
12
- import { openArtifactInMintBrowser } from '../../utils/artifactBrowser'
12
+ import { openArtifactInBrowser } from '../../utils/artifactBrowser'
13
13
  import { runtimePlatform } from '../../platform'
14
14
  import { renderFormattedMessage } from '../../utils/markdown'
15
15
  import { ChatCodeBlock } from '../chat/ChatCodeBlock'
@@ -25,6 +25,7 @@ import {
25
25
  detectArtifactType,
26
26
  getFileLanguage,
27
27
  } from '../../utils/artifacts'
28
+ import { setWorkspaceDragData } from '../../utils/workspaceDrag'
28
29
 
29
30
  export type { ArtifactFile, ArtifactType, ViewportMode }
30
31
  export { detectArtifactType, getFileLanguage }
@@ -75,6 +76,8 @@ export function ArtifactPreviewPanel({ artifact, onClose, workspacePath }: Props
75
76
  const [viewport, setViewport] = useState<ViewportMode>('desktop')
76
77
  const [content, setContent] = useState<string>(artifact?.content || '')
77
78
  const [imageUrl, setImageUrl] = useState(artifact?.url || '')
79
+ const [mediaUrl, setMediaUrl] = useState<string>(artifact?.url || '')
80
+ const [mediaByteLength, setMediaByteLength] = useState<number | undefined>(artifact?.byteLength)
78
81
  const [loading, setLoading] = useState<boolean>(false)
79
82
  const [error, setError] = useState<string | null>(null)
80
83
  const [openingBrowser, setOpeningBrowser] = useState(false)
@@ -144,9 +147,28 @@ export function ArtifactPreviewPanel({ artifact, onClose, workspacePath }: Props
144
147
  return
145
148
  }
146
149
  // Served previews load directly. Text is only needed when their Code tab is selected.
147
- if (mediaPreview || artifactType === 'file' || artifactType === 'image' || (artifact?.url && activeTab === 'preview')) {
150
+ if (mediaPreview) {
151
+ if (artifact?.url) {
152
+ setMediaUrl(artifact.url)
153
+ setLoading(false)
154
+ return
155
+ }
156
+ setLoading(true)
157
+ try {
158
+ const media = await runtimePlatform.readWorkspaceMedia(filePath, sourceWorkspace)
159
+ if (requestRevision.current === revision) {
160
+ setMediaUrl(media.url)
161
+ setMediaByteLength(media.byteLength)
162
+ }
163
+ } catch (reason) {
164
+ if (requestRevision.current === revision) setError(reason instanceof Error ? reason.message : String(reason))
165
+ } finally {
166
+ if (requestRevision.current === revision) setLoading(false)
167
+ }
168
+ return
169
+ }
170
+ if (artifactType === 'file' || artifactType === 'image' || (artifact?.url && activeTab === 'preview')) {
148
171
  setLoading(false)
149
- if (mediaPreview && !artifact?.url) setError('No media preview source is available')
150
172
  if (artifactType === 'image' && !artifact?.url) setError('No image preview URL is available')
151
173
  return
152
174
  }
@@ -168,6 +190,8 @@ export function ArtifactPreviewPanel({ artifact, onClose, workspacePath }: Props
168
190
  setBrowserError(null)
169
191
  setContent(artifact?.content ?? '')
170
192
  setImageUrl(artifact?.url ?? '')
193
+ setMediaUrl(artifact?.url ?? '')
194
+ setMediaByteLength(artifact?.byteLength)
171
195
  setImageDimensions(null)
172
196
  setError(null)
173
197
  }, [artifact, artifactType])
@@ -199,7 +223,7 @@ export function ArtifactPreviewPanel({ artifact, onClose, workspacePath }: Props
199
223
  setOpeningBrowser(true)
200
224
  setBrowserError(null)
201
225
  try {
202
- await openArtifactInMintBrowser(artifact, sourceWorkspace)
226
+ await openArtifactInBrowser(artifact, sourceWorkspace)
203
227
  } catch (reason: unknown) {
204
228
  if (currentArtifact.current === artifact) {
205
229
  setBrowserError(reason instanceof Error ? reason.message : String(reason))
@@ -242,7 +266,25 @@ export function ArtifactPreviewPanel({ artifact, onClose, workspacePath }: Props
242
266
  flexShrink: 0,
243
267
  }}
244
268
  >
245
- <div style={{ display: 'flex', alignItems: 'center', gap: '8px', minWidth: 0 }}>
269
+ <div
270
+ className="artifact-preview-header-drag"
271
+ draggable={Boolean(filePath)}
272
+ onDragStart={filePath ? (event) => {
273
+ setWorkspaceDragData(event.dataTransfer, {
274
+ path: filePath,
275
+ root: sourceWorkspace,
276
+ url: imageUrl || artifact?.url,
277
+ })
278
+ } : undefined}
279
+ style={{
280
+ display: 'flex',
281
+ alignItems: 'center',
282
+ gap: '8px',
283
+ minWidth: 0,
284
+ cursor: filePath ? 'grab' : undefined,
285
+ }}
286
+ title={filePath ? `${filePath} (Drag to chat)` : undefined}
287
+ >
246
288
  <span
247
289
  style={{
248
290
  display: 'inline-flex',
@@ -508,9 +550,9 @@ export function ArtifactPreviewPanel({ artifact, onClose, workspacePath }: Props
508
550
  type="button"
509
551
  onClick={() => { void handleOpenInMintBrowser() }}
510
552
  disabled={openingBrowser}
511
- aria-label="Open in Mint Browser (Mint Auto)"
553
+ aria-label="Open preview"
512
554
  aria-busy={openingBrowser}
513
- title={openingBrowser ? 'Opening Mint Browser…' : 'Open in Mint Browser (Mint Auto)'}
555
+ title={openingBrowser ? 'Opening preview…' : 'Open preview'}
514
556
  style={{
515
557
  background: 'none',
516
558
  border: 'none',
@@ -529,6 +571,68 @@ export function ArtifactPreviewPanel({ artifact, onClose, workspacePath }: Props
529
571
  </svg>
530
572
  </button>}
531
573
 
574
+ {(artifact?.url || mediaUrl || content) && (
575
+ <button
576
+ type="button"
577
+ onClick={() => {
578
+ const downloadUrl = artifact?.url || mediaUrl || (content ? `data:text/plain;charset=utf-8,${encodeURIComponent(content)}` : '')
579
+ if (!downloadUrl) return
580
+ const a = document.createElement('a')
581
+ a.href = downloadUrl
582
+ a.download = fileName || 'download'
583
+ document.body.appendChild(a)
584
+ a.click()
585
+ document.body.removeChild(a)
586
+ }}
587
+ title={`Download ${fileName}`}
588
+ aria-label={`Download ${fileName}`}
589
+ style={{
590
+ background: 'none',
591
+ border: 'none',
592
+ color: 'var(--text-muted)',
593
+ padding: '5px',
594
+ borderRadius: 'var(--radius-xs, 4px)',
595
+ cursor: 'pointer',
596
+ display: 'inline-flex',
597
+ alignItems: 'center',
598
+ }}
599
+ >
600
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
601
+ <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
602
+ <polyline points="7 10 12 15 17 10" />
603
+ <line x1="12" y1="15" x2="12" y2="3" />
604
+ </svg>
605
+ </button>
606
+ )}
607
+
608
+ {(artifact?.url || mediaUrl) && (
609
+ <button
610
+ type="button"
611
+ onClick={() => {
612
+ const target = artifact?.url || mediaUrl
613
+ if (target) window.open(target, '_blank', 'noopener,noreferrer')
614
+ }}
615
+ title="Open in new window"
616
+ aria-label="Open in new window"
617
+ style={{
618
+ background: 'none',
619
+ border: 'none',
620
+ color: 'var(--text-muted)',
621
+ padding: '5px',
622
+ borderRadius: 'var(--radius-xs, 4px)',
623
+ cursor: 'pointer',
624
+ display: 'inline-flex',
625
+ alignItems: 'center',
626
+ }}
627
+ >
628
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
629
+ <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
630
+ <polyline points="15 3 21 3 21 9" />
631
+ <line x1="10" y1="14" x2="21" y2="3" />
632
+ </svg>
633
+ </button>
634
+ )}
635
+
532
636
  <button
533
637
  type="button"
534
638
  onClick={onClose}
@@ -554,7 +658,7 @@ export function ArtifactPreviewPanel({ artifact, onClose, workspacePath }: Props
554
658
 
555
659
  {browserError && (
556
660
  <div role="alert" style={{ padding: '8px 14px', fontSize: '0.8rem', color: 'var(--status-error, #f87171)', flexShrink: 0 }}>
557
- Could not open Mint Browser: {browserError}
661
+ Could not open preview: {browserError}
558
662
  </div>
559
663
  )}
560
664
 
@@ -594,10 +698,10 @@ export function ArtifactPreviewPanel({ artifact, onClose, workspacePath }: Props
594
698
  </div>
595
699
  ) : artifactType === 'file' ? (
596
700
  <WorkspaceFileInfo key={`${sourceWorkspace}:${filePath}`} path={filePath} root={sourceWorkspace} />
597
- ) : artifactType === 'pdf' && artifact.url ? (
598
- <Suspense fallback={<p role="status">Loading PDF viewer…</p>}><WorkspacePdfPreview key={artifact.url} url={artifact.url} path={filePath} root={sourceWorkspace} byteLength={artifact.byteLength} range={artifact.range} /></Suspense>
599
- ) : (artifactType === 'audio' || artifactType === 'video') && artifact.url ? (
600
- <WorkspaceMediaPreview key={artifact.url} kind={artifactType} url={artifact.url} path={filePath} root={sourceWorkspace} mimeType={artifact.mimeType} />
701
+ ) : artifactType === 'pdf' && (artifact.url || mediaUrl) ? (
702
+ <Suspense fallback={<p role="status">Loading PDF viewer…</p>}><WorkspacePdfPreview key={artifact.url || mediaUrl} url={artifact.url || mediaUrl} path={filePath} root={sourceWorkspace} byteLength={artifact.byteLength || mediaByteLength} range={artifact.range} /></Suspense>
703
+ ) : (artifactType === 'audio' || artifactType === 'video') && (artifact.url || mediaUrl) ? (
704
+ <WorkspaceMediaPreview key={artifact.url || mediaUrl} kind={artifactType} url={artifact.url || mediaUrl} path={filePath} root={sourceWorkspace} mimeType={artifact.mimeType} />
601
705
  ) : activeTab === 'code' ? (
602
706
  <div style={{ width: '100%', height: '100%', overflow: 'auto', padding: '12px' }}>
603
707
  <ChatCodeBlock code={content} language={language} />
@@ -643,9 +747,17 @@ export function ArtifactPreviewPanel({ artifact, onClose, workspacePath }: Props
643
747
  })
644
748
  }
645
749
  }}
750
+ draggable
751
+ onDragStart={(event) => {
752
+ setWorkspaceDragData(event.dataTransfer, {
753
+ path: filePath,
754
+ root: sourceWorkspace,
755
+ url: imageUrl || artifact?.url,
756
+ })
757
+ }}
646
758
  src={imageUrl || artifact.url}
647
759
  alt={fileName}
648
- style={{ width: '100%', height: '100%', objectFit: 'contain' }}
760
+ style={{ width: '100%', height: '100%', objectFit: 'contain', cursor: 'grab' }}
649
761
  onLoad={(e) => {
650
762
  const img = e.currentTarget
651
763
  if (img.naturalWidth && img.naturalHeight) {
@@ -0,0 +1,50 @@
1
+ import React from 'react'
2
+ import { renderToStaticMarkup } from 'react-dom/server'
3
+ import { describe, expect, it } from 'vitest'
4
+ import CodeReviewPage from './CodeReviewPage'
5
+ import type { FileChange } from '../../types'
6
+
7
+ describe('CodeReviewPage', () => {
8
+ const sampleChanges: FileChange[] = [
9
+ {
10
+ path: 'src/generate_harness_pdf.py',
11
+ created: false,
12
+ additions: 10,
13
+ deletions: 2,
14
+ hunks: [
15
+ {
16
+ oldStart: 1,
17
+ oldLines: 1,
18
+ newStart: 1,
19
+ newLines: 2,
20
+ oldText: 'print("hello")',
21
+ newText: 'print("hello")\nprint("world")',
22
+ },
23
+ ],
24
+ },
25
+ ]
26
+
27
+ it('renders tree items with draggable attributes and drag tooltip for chat input', () => {
28
+ const html = renderToStaticMarkup(
29
+ <CodeReviewPage
30
+ changes={sampleChanges}
31
+ workspacePath="/home/user/project"
32
+ />
33
+ )
34
+
35
+ // Tree file button is draggable
36
+ expect(html).toContain('class="code-review-tree-file')
37
+ expect(html).toMatch(/class="code-review-tree-file[^"]*"[^>]*draggable="true"/)
38
+ expect(html).toContain('title="src/generate_harness_pdf.py (Drag to chat)"')
39
+
40
+ // Tree folder button is draggable
41
+ expect(html).toContain('class="code-review-tree-folder-btn"')
42
+ expect(html).toMatch(/class="code-review-tree-folder-btn"[^>]*draggable="true"/)
43
+ expect(html).toContain('title="src (Drag to chat)"')
44
+
45
+ // Diff view file bar path is draggable
46
+ expect(html).toContain('class="code-review-file-bar-path"')
47
+ expect(html).toMatch(/class="code-review-file-bar-path"[^>]*draggable="true"/)
48
+ expect(html).toContain('title="src/generate_harness_pdf.py (Drag to chat)"')
49
+ })
50
+ })
@@ -13,6 +13,8 @@ import {
13
13
  folderIcon,
14
14
  documentIcon,
15
15
  } from '../../utils/fileIcons'
16
+ import { tokenizeLine } from '../../utils/syntaxHighlight'
17
+ import { setWorkspaceDragData } from '../../utils/workspaceDrag'
16
18
  import '../../css/code-review.css'
17
19
 
18
20
  export function undoDescription(entry: WorkspaceHistoryEntry) {
@@ -368,6 +370,16 @@ export default function CodeReviewPage({
368
370
  style={{ paddingLeft: `${depth * 14 + 10}px` }}
369
371
  onClick={() => toggleFolder(node.path)}
370
372
  aria-expanded={!isCollapsed}
373
+ draggable="true"
374
+ onDragStart={(event) => {
375
+ event.stopPropagation()
376
+ setWorkspaceDragData(event.dataTransfer, {
377
+ path: node.path,
378
+ root: workspacePath,
379
+ kind: 'directory',
380
+ })
381
+ }}
382
+ title={`${node.path} (Drag to chat)`}
371
383
  >
372
384
  <span className="code-review-chevron">{isCollapsed ? '›' : '⌄'}</span>
373
385
  <span className="code-review-tree-icon material-icon folder" aria-hidden="true">
@@ -389,6 +401,7 @@ export default function CodeReviewPage({
389
401
  const ext = getExtension(node.name)
390
402
  const fileIconSrc = materialFileIcon(node.name, ext) || documentIcon
391
403
  const isCreated = Boolean(node.change?.created)
404
+ const targetPath = node.change?.path || node.path
392
405
 
393
406
  return (
394
407
  <button
@@ -397,7 +410,16 @@ export default function CodeReviewPage({
397
410
  className={`code-review-tree-file${isSelected ? ' is-selected' : ''}`}
398
411
  style={{ paddingLeft: `${depth * 14 + 12}px` }}
399
412
  onClick={() => setSelectedPath(node.path)}
400
- title={node.path}
413
+ title={`${node.path} (Drag to chat)`}
414
+ draggable="true"
415
+ onDragStart={(event) => {
416
+ event.stopPropagation()
417
+ setWorkspaceDragData(event.dataTransfer, {
418
+ path: targetPath,
419
+ root: workspacePath,
420
+ kind: 'file',
421
+ })
422
+ }}
401
423
  >
402
424
  <span className="code-review-tree-icon material-icon file" aria-hidden="true">
403
425
  {fileIconSrc && <img src={fileIconSrc} alt="" draggable={false} />}
@@ -591,7 +613,19 @@ export default function CodeReviewPage({
591
613
  <span className={`code-review-file-bar-status ${selectedChange.created ? 'is-created' : 'is-modified'}`}>
592
614
  {selectedChange.created ? 'A' : 'M'}
593
615
  </span>
594
- <span className="code-review-file-bar-path" title={selectedChange.path}>
616
+ <span
617
+ className="code-review-file-bar-path"
618
+ title={`${selectedChange.path} (Drag to chat)`}
619
+ draggable="true"
620
+ onDragStart={(event) => {
621
+ event.stopPropagation()
622
+ setWorkspaceDragData(event.dataTransfer, {
623
+ path: selectedChange.path,
624
+ root: workspacePath,
625
+ kind: 'file',
626
+ })
627
+ }}
628
+ >
595
629
  {selectedChange.path}
596
630
  </span>
597
631
  <button type="button" className="review-undo-button" disabled={!canUndoFile || history.busy} title={canUndoFile ? selectedFileHistory?.label : selectedFileHistory ? 'Undo newer workspace actions first in File history.' : 'No saved undo action for this file.'} onClick={() => selectedFileHistory && requestUndo(selectedFileHistory)}>Undo edit…</button>
@@ -602,25 +636,52 @@ export default function CodeReviewPage({
602
636
  <div className="code-review-code-container">
603
637
  {selectedChange.hunks && selectedChange.hunks.length > 0 ? (
604
638
  selectedChange.hunks.map((hunk, hunkIdx) => {
639
+ const fileExt = getExtension(selectedChange.path)
605
640
  const oldLines = diffLines(hunk.oldText)
606
641
  const newLines = diffLines(hunk.newText)
607
642
  let lineCounter = 1
608
643
  return (
609
644
  <div className="code-review-hunk-block" key={`${selectedChange.path}-hunk-${hunkIdx}`}>
610
- {oldLines.map((line, idx) => (
611
- <div className="code-review-line is-del" key={`del-${idx}`}>
612
- <span className="code-review-gutter">{lineCounter++}</span>
613
- <span className="code-review-sign">−</span>
614
- <code className="code-review-code-text">{line || ' '}</code>
615
- </div>
616
- ))}
617
- {newLines.map((line, idx) => (
618
- <div className="code-review-line is-add" key={`add-${idx}`}>
619
- <span className="code-review-gutter">{lineCounter++}</span>
620
- <span className="code-review-sign">+</span>
621
- <code className="code-review-code-text">{line || ' '}</code>
622
- </div>
623
- ))}
645
+ {oldLines.map((line, idx) => {
646
+ const tokens = tokenizeLine(line, fileExt)
647
+ return (
648
+ <div className="code-review-line is-del" key={`del-${idx}`}>
649
+ <span className="code-review-gutter">{lineCounter++}</span>
650
+ <span className="code-review-sign">−</span>
651
+ <code className="code-review-code-text">
652
+ {tokens.length === 0 ? (
653
+ ' '
654
+ ) : (
655
+ tokens.map((tok, tIdx) => (
656
+ <span key={tIdx} className={tok.type}>
657
+ {tok.text}
658
+ </span>
659
+ ))
660
+ )}
661
+ </code>
662
+ </div>
663
+ )
664
+ })}
665
+ {newLines.map((line, idx) => {
666
+ const tokens = tokenizeLine(line, fileExt)
667
+ return (
668
+ <div className="code-review-line is-add" key={`add-${idx}`}>
669
+ <span className="code-review-gutter">{lineCounter++}</span>
670
+ <span className="code-review-sign">+</span>
671
+ <code className="code-review-code-text">
672
+ {tokens.length === 0 ? (
673
+ ' '
674
+ ) : (
675
+ tokens.map((tok, tIdx) => (
676
+ <span key={tIdx} className={tok.type}>
677
+ {tok.text}
678
+ </span>
679
+ ))
680
+ )}
681
+ </code>
682
+ </div>
683
+ )
684
+ })}
624
685
  </div>
625
686
  )
626
687
  })
@@ -11,6 +11,56 @@ interface GitBranchSelectorProps {
11
11
  onBranchChanged?: () => void
12
12
  }
13
13
 
14
+ function BranchIcon({ className = '', width = 14, height = 14 }: { className?: string; width?: number; height?: number }) {
15
+ return (
16
+ <svg className={className} width={width} height={height} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
17
+ <line x1="6" y1="3" x2="6" y2="15" />
18
+ <circle cx="18" cy="6" r="3" />
19
+ <circle cx="6" cy="18" r="3" />
20
+ <path d="M18 9a9 9 0 0 1-9 9" />
21
+ </svg>
22
+ )
23
+ }
24
+
25
+ function RemoteGlobeIcon({ className = '', width = 14, height = 14 }: { className?: string; width?: number; height?: number }) {
26
+ return (
27
+ <svg className={className} width={width} height={height} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
28
+ <circle cx="12" cy="12" r="10" />
29
+ <path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20" />
30
+ <path d="M2 12h20" />
31
+ </svg>
32
+ )
33
+ }
34
+
35
+ function PlusIcon({ className = '', width = 14, height = 14 }: { className?: string; width?: number; height?: number }) {
36
+ return (
37
+ <svg className={className} width={width} height={height} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
38
+ <line x1="12" y1="5" x2="12" y2="19" />
39
+ <line x1="5" y1="12" x2="19" y2="12" />
40
+ </svg>
41
+ )
42
+ }
43
+
44
+ function GitGraphIcon({ className = '', width = 14, height = 14 }: { className?: string; width?: number; height?: number }) {
45
+ return (
46
+ <svg className={className} width={width} height={height} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
47
+ <circle cx="5" cy="6" r="3" />
48
+ <circle cx="5" cy="18" r="3" />
49
+ <line x1="5" y1="9" x2="5" y2="15" />
50
+ <circle cx="19" cy="9" r="3" />
51
+ <path d="M5 9c0 4 4 6 8 6h3" />
52
+ </svg>
53
+ )
54
+ }
55
+
56
+ function ChevronBackIcon({ className = '', width = 14, height = 14 }: { className?: string; width?: number; height?: number }) {
57
+ return (
58
+ <svg className={className} width={width} height={height} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
59
+ <polyline points="15 18 9 12 15 6" />
60
+ </svg>
61
+ )
62
+ }
63
+
14
64
  function errorMessage(reason: unknown): string {
15
65
  if (reason instanceof Error) return reason.message
16
66
  if (typeof reason === 'string') return reason
@@ -139,6 +189,7 @@ export default function GitBranchSelector({ workspacePath, disabled = false, onB
139
189
  title={`${error} Select to retry.`}
140
190
  aria-label="Git branch unavailable. Retry"
141
191
  >
192
+ <BranchIcon className="git-branch-icon" width={14} height={14} />
142
193
  <span className="git-branch-name">Git unavailable</span>
143
194
  </button>
144
195
  </div>
@@ -289,16 +340,11 @@ export default function GitBranchSelector({ workspacePath, disabled = false, onB
289
340
  aria-controls="workspace-branch-menu"
290
341
  title={`${branchLabel}${info.isDirty ? ' — uncommitted changes' : ''}`}
291
342
  >
292
- <svg className="git-branch-icon" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
293
- <circle cx="6" cy="5" r="2" />
294
- <circle cx="18" cy="6" r="2" />
295
- <circle cx="6" cy="19" r="2" />
296
- <path d="M6 7v10M8 7c2 4 8 1 8-1" />
297
- </svg>
343
+ <BranchIcon className="git-branch-icon" width={14} height={14} />
298
344
  <span className="git-branch-name">{switchingBranch || branchLabel}</span>
299
345
  {info.isDirty && <span className="git-branch-dirty" aria-label="Uncommitted changes" />}
300
- <svg className="git-branch-chevron" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
301
- <path d="m6 9 6 6 6-6" />
346
+ <svg className="git-branch-chevron" width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
347
+ <polyline points="6 9 12 15 18 9" />
302
348
  </svg>
303
349
  </button>
304
350
 
@@ -313,9 +359,9 @@ export default function GitBranchSelector({ workspacePath, disabled = false, onB
313
359
  {menuView === 'branches' && (
314
360
  <>
315
361
  <label className="git-branch-search">
316
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" aria-hidden="true">
317
- <circle cx="11" cy="11" r="7" />
318
- <path d="m20 20-4-4" />
362
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
363
+ <circle cx="11" cy="11" r="8" />
364
+ <path d="m21 21-4.3-4.3" />
319
365
  </svg>
320
366
  <input
321
367
  autoFocus
@@ -339,12 +385,16 @@ export default function GitBranchSelector({ workspacePath, disabled = false, onB
339
385
  disabled={Boolean(switchingBranch)}
340
386
  onClick={() => handleSwitch(branch)}
341
387
  >
342
- <span className="git-branch-option-icon" aria-hidden="true">⑂</span>
388
+ <span className="git-branch-option-icon" aria-hidden="true">
389
+ <BranchIcon width={14} height={14} />
390
+ </span>
343
391
  <span>{branch}</span>
344
392
  {selected && (
345
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
346
- <path d="m5 12 4 4L19 6" />
347
- </svg>
393
+ <span className="git-branch-option-check" aria-hidden="true">
394
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
395
+ <polyline points="20 6 9 17 4 12" />
396
+ </svg>
397
+ </span>
348
398
  )}
349
399
  </button>
350
400
  )
@@ -365,7 +415,9 @@ export default function GitBranchSelector({ workspacePath, disabled = false, onB
365
415
  onClick={() => handleRemoteCheckout(remoteBranch)}
366
416
  title={`Create a local tracking branch from ${remoteBranch}`}
367
417
  >
368
- <span className="git-branch-option-icon" aria-hidden="true">⇄</span>
418
+ <span className="git-branch-option-icon" aria-hidden="true">
419
+ <RemoteGlobeIcon width={14} height={14} />
420
+ </span>
369
421
  <span>{remoteBranch}</span>
370
422
  <span className="git-branch-track-label">Track</span>
371
423
  </button>
@@ -378,12 +430,12 @@ export default function GitBranchSelector({ workspacePath, disabled = false, onB
378
430
  )}
379
431
  <div className="git-branch-actions">
380
432
  <button type="button" onClick={() => { setMenuView('create'); setError('') }}>
381
- <span aria-hidden="true">+</span>
382
- Create branch
433
+ <PlusIcon width={14} height={14} />
434
+ <span>Create branch</span>
383
435
  </button>
384
436
  <button type="button" onClick={openGraph}>
385
- <span aria-hidden="true">⑂</span>
386
- Git graph
437
+ <GitGraphIcon width={14} height={14} />
438
+ <span>Git graph</span>
387
439
  </button>
388
440
  </div>
389
441
  </>
@@ -392,7 +444,9 @@ export default function GitBranchSelector({ workspacePath, disabled = false, onB
392
444
  {menuView === 'create' && (
393
445
  <form className="git-branch-create" onSubmit={handleCreateBranch}>
394
446
  <div className="git-branch-view-header">
395
- <button type="button" onClick={() => { setMenuView('branches'); setError('') }} aria-label="Back to branches">←</button>
447
+ <button type="button" onClick={() => { setMenuView('branches'); setError('') }} aria-label="Back to branches">
448
+ <ChevronBackIcon width={14} height={14} />
449
+ </button>
396
450
  <strong>Create branch</strong>
397
451
  </div>
398
452
  <label htmlFor="new-git-branch-name">Branch name</label>
@@ -415,7 +469,9 @@ export default function GitBranchSelector({ workspacePath, disabled = false, onB
415
469
  {menuView === 'graph' && (
416
470
  <div className="git-graph-view">
417
471
  <div className="git-branch-view-header">
418
- <button type="button" onClick={() => { setMenuView('branches'); setError('') }} aria-label="Back to branches">←</button>
472
+ <button type="button" onClick={() => { setMenuView('branches'); setError('') }} aria-label="Back to branches">
473
+ <ChevronBackIcon width={14} height={14} />
474
+ </button>
419
475
  <strong>Git graph</strong>
420
476
  <button type="button" className="git-graph-refresh" onClick={loadGraph} disabled={graphLoading}>Refresh</button>
421
477
  </div>
@@ -65,4 +65,17 @@ describe('Tools launcher', () => {
65
65
  expect(html).toContain('All open tabs (3)')
66
66
  expect(html).toContain('tool-surface-tabs-badge">3</span>')
67
67
  })
68
+
69
+ it('marks artifact preview tabs as draggable to allow dragging to chat', () => {
70
+ const previewProps = {
71
+ ...props,
72
+ surfaces: [
73
+ { id: 'pdf-1', kind: 'preview' as const, title: 'Harness_Presentation.pdf', artifact: { path: 'Harness_Presentation.pdf' } },
74
+ { id: 'term-1', kind: 'terminal' as const, title: 'Terminal' },
75
+ ],
76
+ activeSurfaceId: 'pdf-1',
77
+ }
78
+ const html = renderToStaticMarkup(<ToolSurfacePage {...previewProps} />)
79
+ expect(html).toMatch(/class="tool-surface-tab[^"]*"[^>]*draggable="true"/)
80
+ })
68
81
  })