@pheem49/mint 1.14.0 → 1.15.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 (585) hide show
  1. package/CLAUDE.md +1 -1
  2. package/Cargo.lock +291 -11
  3. package/Cargo.toml +1 -1
  4. package/README.md +71 -9
  5. package/ROADMAP.md +30 -0
  6. package/Release_Note.md +579 -465
  7. package/crates/mint-cli/Cargo.toml +3 -1
  8. package/crates/mint-cli/src/agent/approval_prompts.rs +16 -3
  9. package/crates/mint-cli/src/agent/live_status.rs +367 -118
  10. package/crates/mint-cli/src/agent/markdown_render.rs +601 -61
  11. package/crates/mint-cli/src/agent.rs +452 -215
  12. package/crates/mint-cli/src/commands/agent.rs +16 -21
  13. package/crates/mint-cli/src/commands/eval.rs +9 -5
  14. package/crates/mint-cli/src/commands/git.rs +204 -0
  15. package/crates/mint-cli/src/commands/integrations.rs +28 -0
  16. package/crates/mint-cli/src/commands/knowledge.rs +1 -0
  17. package/crates/mint-cli/src/commands/mod.rs +37 -2
  18. package/crates/mint-cli/src/commands/tailnet_web.rs +235 -0
  19. package/crates/mint-cli/src/image.rs +26 -3
  20. package/crates/mint-cli/src/interactive/chat_tui.rs +4742 -0
  21. package/crates/mint-cli/src/interactive/command_ui.rs +477 -0
  22. package/crates/mint-cli/src/interactive/format.rs +8 -0
  23. package/crates/mint-cli/src/interactive/input_box.rs +38 -2
  24. package/crates/mint-cli/src/interactive/picker.rs +180 -37
  25. package/crates/mint-cli/src/interactive/resume_picker.rs +686 -0
  26. package/crates/mint-cli/src/interactive/slash_commands.rs +868 -450
  27. package/crates/mint-cli/src/interactive/thought_viewer.rs +286 -0
  28. package/crates/mint-cli/src/interactive.rs +400 -136
  29. package/crates/mint-cli/src/main.rs +84 -23
  30. package/crates/mint-cli/src/markdown.rs +12 -5
  31. package/crates/mint-cli/src/onboard.rs +32 -30
  32. package/crates/mint-cli/src/plugins_cli.rs +8 -5
  33. package/crates/mint-cli/src/setup.rs +10 -8
  34. package/crates/mint-cli/src/terminal_theme.rs +187 -0
  35. package/crates/mint-cli/src/updater.rs +56 -21
  36. package/crates/mint-core/src/agent/agent_loop.rs +1 -0
  37. package/crates/mint-core/src/agent/chat.rs +843 -177
  38. package/crates/mint-core/src/agent/code_tools.rs +83 -2
  39. package/crates/mint-core/src/agent/memory.rs +658 -20
  40. package/crates/mint-core/src/agent/skills.rs +1 -1
  41. package/crates/mint-core/src/api_server/routes/chat.rs +31 -5
  42. package/crates/mint-core/src/api_server/routes/linked_folders.rs +118 -3
  43. package/crates/mint-core/src/api_server/routes/misc.rs +10 -14
  44. package/crates/mint-core/src/api_server/routes/sessions.rs +44 -0
  45. package/crates/mint-core/src/api_server.rs +22 -3
  46. package/crates/mint-core/src/avatar_bridge.rs +2 -0
  47. package/crates/mint-core/src/browser/cdp.rs +74 -83
  48. package/crates/mint-core/src/browser/evidence.rs +260 -0
  49. package/crates/mint-core/src/browser/input.rs +1 -1
  50. package/crates/mint-core/src/browser/interact.rs +98 -124
  51. package/crates/mint-core/src/browser/lifecycle.rs +75 -4
  52. package/crates/mint-core/src/browser/mod.rs +16 -2
  53. package/crates/mint-core/src/browser/navigate.rs +27 -19
  54. package/crates/mint-core/src/browser/observe.js +40 -0
  55. package/crates/mint-core/src/browser/session.rs +1558 -0
  56. package/crates/mint-core/src/git/branches.rs +348 -0
  57. package/crates/mint-core/src/git/checkpoint.rs +40 -0
  58. package/crates/mint-core/src/git/diff.rs +206 -0
  59. package/crates/mint-core/src/git/mod.rs +10 -2
  60. package/crates/mint-core/src/integrations/channels.rs +1 -0
  61. package/crates/mint-core/src/lib.rs +22 -14
  62. package/crates/mint-core/src/live_sync.rs +28 -9
  63. package/crates/mint-core/src/media/auto_shorts.rs +1 -0
  64. package/crates/mint-core/src/media/gemini_live.rs +12 -1
  65. package/crates/mint-core/src/media/mic_transcribe.rs +1 -0
  66. package/crates/mint-core/src/media/subtitle.rs +1 -0
  67. package/crates/mint-core/src/orchestration/context_render.rs +1 -0
  68. package/crates/mint-core/src/orchestration/memory_skill.rs +6 -1
  69. package/crates/mint-core/src/orchestration/mod.rs +1024 -271
  70. package/crates/mint-core/src/orchestration/tools/browser.rs +16 -139
  71. package/crates/mint-core/src/orchestration/tools/misc.rs +2 -1
  72. package/crates/mint-core/src/orchestration/tools/web.rs +1 -1
  73. package/crates/mint-core/src/prompts/agent.rs +58 -29
  74. package/crates/mint-core/src/prompts/chat.rs +1 -1
  75. package/crates/mint-core/src/prompts/persona.rs +1 -1
  76. package/crates/mint-core/src/prompts/tool_catalog.rs +93 -25
  77. package/crates/mint-core/src/search/linked_folders/index.rs +732 -0
  78. package/crates/mint-core/src/search/linked_folders.rs +391 -130
  79. package/crates/mint-core/src/slash/mod.rs +470 -22
  80. package/crates/mint-core/src/slash/model_fetcher.rs +12 -3
  81. package/crates/mint-core/src/slash/models.rs +66 -10
  82. package/crates/mint-core/src/system/config.rs +230 -0
  83. package/crates/mint-core/src/system/workspace.rs +228 -0
  84. package/crates/mint-core/src/system.rs +1 -0
  85. package/crates/mint-core/tests/memory_persistence.rs +39 -0
  86. package/mint-presentation-demo.mp4 +0 -0
  87. package/out/web/assets/CliSessionsView-BxUVWEEL.js +1 -0
  88. package/out/web/assets/CliSessionsView-CBDTXuQv.css +1 -0
  89. package/out/web/assets/CodeReviewPage-DkMgfcos.css +1 -0
  90. package/out/web/assets/CodeReviewPage-jKlmLJwT.js +3 -0
  91. package/out/web/assets/CommandPalette-DnwPA5hy.js +1 -0
  92. package/out/web/assets/ImageStudioPanel-BR1XFwhR.js +1 -0
  93. package/out/web/assets/ImageStudioPanel-D0lnhQV5.css +1 -0
  94. package/out/web/assets/LinkedFoldersView-bi-CWQ-I.js +1 -0
  95. package/out/web/assets/McpRegistryPicker-D5tEFnyq.js +1 -0
  96. package/out/web/assets/McpServersView-BGG1dhFM.js +1 -0
  97. package/out/web/assets/MintDashboard-BIglDEWX.js +20 -0
  98. package/out/web/assets/MintDashboard-DSMywSgs.css +1 -0
  99. package/out/web/assets/ModelPanel-CbJ1PFoZ.js +1 -0
  100. package/out/web/assets/PicturesLibrary-CQP0fLP1.css +1 -0
  101. package/out/web/assets/PicturesLibrary-DoYN7T1p.js +1 -0
  102. package/out/web/assets/PluginsView-CU1HWXGk.js +1 -0
  103. package/out/web/assets/ScheduledTasksView-Bnl36y2N.js +1 -0
  104. package/out/web/assets/SettingsWindow-DhWLAn9T.css +1 -0
  105. package/out/web/assets/SettingsWindow-Dw8L01pw.js +2 -0
  106. package/out/web/assets/SkillsView-cnl8aY5p.js +2 -0
  107. package/out/web/assets/ToolSurfacePage-CgsQw6l5.css +1 -0
  108. package/out/web/assets/ToolSurfacePage-Cz2VJAPZ.js +37 -0
  109. package/out/web/assets/VeoStudioPanel-D4JnERWR.js +4 -0
  110. package/out/web/assets/VeoStudioPanel-DOj7_WR3.css +1 -0
  111. package/out/web/assets/WorkspacePanel-CbJ1PFoZ.js +1 -0
  112. package/out/web/assets/{abnfDiagram-VCTEODGH-DAOBA7ZG.js → abnfDiagram-VCTEODGH-ByMyfanq.js} +1 -1
  113. package/out/web/assets/{architecture-7GRP2DOG-CgSwQOPQ.js → architecture-7GRP2DOG-CLq2kEOB.js} +1 -1
  114. package/out/web/assets/{architectureDiagram-5GKGNRK7-CYp3yupP.js → architectureDiagram-5GKGNRK7-6PoVSmNG.js} +1 -1
  115. package/out/web/assets/{blockDiagram-NRAW4CY4-CyWybDWr.js → blockDiagram-NRAW4CY4-cKw9mAKi.js} +1 -1
  116. package/out/web/assets/{c4Diagram-UCG6FXSJ-BvY3U709.js → c4Diagram-UCG6FXSJ-Cqy8N5Ge.js} +1 -1
  117. package/out/web/assets/{chunk-75Z2AOVW-TLXCoZYv.js → chunk-75Z2AOVW-3qybijF5.js} +1 -1
  118. package/out/web/assets/chunk-CKBBP62Z-cIrXq6jN.js +2 -0
  119. package/out/web/assets/{chunk-CLGD4ZFX-xjsKtNS7.js → chunk-CLGD4ZFX-CndDQkww.js} +1 -1
  120. package/out/web/assets/chunk-DSNCTWBM-Cc4NxvgD.js +2 -0
  121. package/out/web/assets/chunk-DU6HZSFF-drzh6GsU.js +128 -0
  122. package/out/web/assets/{chunk-F27PBJKO-BFpgF55A.js → chunk-F27PBJKO-FiY35l4v.js} +1 -1
  123. package/out/web/assets/{chunk-G27WJ6UU-DfF7qW-C.js → chunk-G27WJ6UU-Bjt9Il4A.js} +1 -1
  124. package/out/web/assets/{chunk-GMAD6QVW-C-558kh_.js → chunk-GMAD6QVW-Bppi3Ctd.js} +1 -1
  125. package/out/web/assets/{chunk-JQ64N6SF-wJmeGKAw.js → chunk-JQ64N6SF-DGg5kcEV.js} +1 -1
  126. package/out/web/assets/{chunk-LCL6LL3I-C1wHD8Ie.js → chunk-LCL6LL3I-CCYcjd7p.js} +1 -1
  127. package/out/web/assets/{chunk-OBVCFTLP-BsRTPBqs.js → chunk-OBVCFTLP-DJeNil5M.js} +1 -1
  128. package/out/web/assets/{chunk-P2QGCYS3-HZIiM7Ni.js → chunk-P2QGCYS3-lRzkRjBB.js} +1 -1
  129. package/out/web/assets/{chunk-POPQ4Y6H-Dk9wvVb0.js → chunk-POPQ4Y6H-DouASMBW.js} +1 -1
  130. package/out/web/assets/{chunk-PWAF6VOD-BmjYLNbq.js → chunk-PWAF6VOD-DMmD1vVf.js} +1 -1
  131. package/out/web/assets/{chunk-R7TYR2AO-CaHIf-lK.js → chunk-R7TYR2AO-CYLA5UC5.js} +1 -1
  132. package/out/web/assets/{chunk-RHFEMEQ7-_T561hOU.js → chunk-RHFEMEQ7-BiXwEcUT.js} +1 -1
  133. package/out/web/assets/{chunk-SVP7TREG-CM-GGYoY.js → chunk-SVP7TREG-BV-zPslF.js} +1 -1
  134. package/out/web/assets/{chunk-TEH6E4GO-K2A8Vg2C.js → chunk-TEH6E4GO-B2RGEohZ.js} +1 -1
  135. package/out/web/assets/classDiagram-DTDB5LWJ-Dq0smRWk.js +1 -0
  136. package/out/web/assets/classDiagram-v2-JRS7N3AN-Dq0smRWk.js +1 -0
  137. package/out/web/assets/config-C-ZFtipU.css +1 -0
  138. package/out/web/assets/config-eEDngJXO.js +1 -0
  139. package/out/web/assets/core-hQ2VA9Ti.js +1 -0
  140. package/out/web/assets/{cynefin-OW5HDTMX-ClzaB6cc.js → cynefin-OW5HDTMX-Cas4csHM.js} +1 -1
  141. package/out/web/assets/{cynefinDiagram-5FMLGOSQ-D_JzZBzf.js → cynefinDiagram-5FMLGOSQ-Bbpj66Y3.js} +1 -1
  142. package/out/web/assets/{dagre-3AP2YEHR-BDuUeMHj.js → dagre-3AP2YEHR-B0-2RDEd.js} +1 -1
  143. package/out/web/assets/{diagram-S7CK7UJ4-DgtcfE8P.js → diagram-S7CK7UJ4-BdzEjUyH.js} +1 -1
  144. package/out/web/assets/{diagram-UQ7AKVKN-DTLoEYti.js → diagram-UQ7AKVKN-CJDwyPxF.js} +1 -1
  145. package/out/web/assets/{diagram-VSXAHHWV-ChGl9pXz.js → diagram-VSXAHHWV-BxaG1r_B.js} +1 -1
  146. package/out/web/assets/{diagram-VX7I27RA-Be8DWz0S.js → diagram-VX7I27RA-BMmUqm8f.js} +1 -1
  147. package/out/web/assets/{diagram-Z3DM3KII-BMXjRTOF.js → diagram-Z3DM3KII-CFtd03eE.js} +1 -1
  148. package/out/web/assets/dist-js-Bf2bhoku.js +1 -0
  149. package/out/web/assets/{ebnfDiagram-PWID7BFC-8Q9pl1CJ.js → ebnfDiagram-PWID7BFC-DwAen1hO.js} +1 -1
  150. package/out/web/assets/{erDiagram-SSCWMZ5O-DjH8Lnkn.js → erDiagram-SSCWMZ5O-BCZSHACj.js} +1 -1
  151. package/out/web/assets/event-ChBVpRy0.js +1 -0
  152. package/out/web/assets/{eventmodeling-NTZA5JFV-BKUH_DOp.js → eventmodeling-NTZA5JFV-XHStE4E_.js} +1 -1
  153. package/out/web/assets/fira-code-latin-600-normal-BmSSHshu.woff +0 -0
  154. package/out/web/assets/fira-code-latin-600-normal-CvYZpPHg.woff2 +0 -0
  155. package/out/web/assets/fira-code-symbols2-600-normal-Dvq6IQE5.woff +0 -0
  156. package/out/web/assets/flowDiagram-A5DVABFB-BLg7nEcd.js +1 -0
  157. package/out/web/assets/{ganttDiagram-EL5Y4UJY-D7fZKJNM.js → ganttDiagram-EL5Y4UJY-BAEu1Cql.js} +1 -1
  158. package/out/web/assets/{gitGraph-4MIJSDKK-BypWaaBU.js → gitGraph-4MIJSDKK-r32Vyper.js} +1 -1
  159. package/out/web/assets/{gitGraphDiagram-WWUBYQGX-DWiw_3bq.js → gitGraphDiagram-WWUBYQGX-z9o9qt6V.js} +1 -1
  160. package/out/web/assets/index-Btsf4L8M.css +1 -0
  161. package/out/web/assets/index-D8D9MeRA.js +11 -0
  162. package/out/web/assets/{info-A6RAGUB7-KkAUxT4j.js → info-A6RAGUB7-BvLaC2cw.js} +1 -1
  163. package/out/web/assets/{infoDiagram-RXCK75RN-BNb6E48y.js → infoDiagram-RXCK75RN-Be6WAXXw.js} +1 -1
  164. package/out/web/assets/{ishikawaDiagram-5VMMS53U-Caa-JoAK.js → ishikawaDiagram-5VMMS53U-DZjoHJHC.js} +1 -1
  165. package/out/web/assets/{journeyDiagram-EYS64GPL-DOrmFGz6.js → journeyDiagram-EYS64GPL-CtVkjkGm.js} +1 -1
  166. package/out/web/assets/{kanban-definition-3QL26DDD-BOWCYcK0.js → kanban-definition-3QL26DDD-CW5FMv1w.js} +1 -1
  167. package/out/web/assets/lucide-react-Ip3L6Jtn.js +1 -0
  168. package/out/web/assets/markdown-BSeeUbJH.js +38 -0
  169. package/out/web/assets/{mermaid-parser.core-BQqjCkS_.js → mermaid-parser.core-aUgCqsZ5.js} +3 -3
  170. package/out/web/assets/mermaid.core-D57sEiSL.js +11 -0
  171. package/out/web/assets/{mindmap-definition-FBJOCRG2-jTceWpr0.js → mindmap-definition-FBJOCRG2-DAmSpM3a.js} +1 -1
  172. package/out/web/assets/modelManager-tMVmJVAW.js +2 -0
  173. package/out/web/assets/oauthManager-9jxicDWJ.js +1 -0
  174. package/out/web/assets/{packet-AYTQ26CC-CJ5RXgol.js → packet-AYTQ26CC-DJ27iIoJ.js} +1 -1
  175. package/out/web/assets/{pegDiagram-XKGWAZYB-y8wMtd0y.js → pegDiagram-XKGWAZYB-Bj3ii-gS.js} +1 -1
  176. package/out/web/assets/{pie-WAS4IAKB-72fTBbl4.js → pie-WAS4IAKB-DG5mCUbc.js} +1 -1
  177. package/out/web/assets/{pieDiagram-E7YTZNPT-e0O02qWq.js → pieDiagram-E7YTZNPT-BrJLPnDA.js} +1 -1
  178. package/out/web/assets/prompt-latin-700-normal-BfbftDSq.woff +0 -0
  179. package/out/web/assets/prompt-latin-700-normal-I2gc831J.woff2 +0 -0
  180. package/out/web/assets/prompt-thai-700-normal-Cb5ilR-c.woff +0 -0
  181. package/out/web/assets/prompt-thai-700-normal-Cg4aQ0Nn.woff2 +0 -0
  182. package/out/web/assets/{quadrantDiagram-AXDQQJYC-C9phYLom.js → quadrantDiagram-AXDQQJYC-3x_TmF3j.js} +1 -1
  183. package/out/web/assets/{radar-RG4KPBEZ-BAU2hzUT.js → radar-RG4KPBEZ-CrXaTTuV.js} +1 -1
  184. package/out/web/assets/{railroad-74A4TZTK-B0bCAVHC.js → railroad-74A4TZTK-BpqMH9BE.js} +1 -1
  185. package/out/web/assets/{railroad-abnf-HS5TGJTU-WhxO7ndE.js → railroad-abnf-HS5TGJTU-DHI0uLlV.js} +1 -1
  186. package/out/web/assets/{railroad-ebnf-LZEXJU2U-BkA0m7-F.js → railroad-ebnf-LZEXJU2U-CQCb316y.js} +1 -1
  187. package/out/web/assets/{railroad-peg-WCYAUIDC-BsVpHIaj.js → railroad-peg-WCYAUIDC-Ph1giKkH.js} +1 -1
  188. package/out/web/assets/{railroadDiagram-O6MQD6OU-CyOLN65Q.js → railroadDiagram-O6MQD6OU-BRq6wIxx.js} +1 -1
  189. package/out/web/assets/{requirementDiagram-EFPCY7ZU-DQXJ7Dud.js → requirementDiagram-EFPCY7ZU-DIJj6G1g.js} +1 -1
  190. package/out/web/assets/{sankeyDiagram-P5KCCOFB-B2XLyIIc.js → sankeyDiagram-P5KCCOFB-DZajSryq.js} +1 -1
  191. package/out/web/assets/{sequenceDiagram-WJ2MYXX4-DGQY4wwm.js → sequenceDiagram-WJ2MYXX4-DxJCWyZS.js} +1 -1
  192. package/out/web/assets/{stateDiagram-HBIQ2CUA-DHZpDwNy.js → stateDiagram-HBIQ2CUA-k6voi8Vf.js} +1 -1
  193. package/out/web/assets/stateDiagram-v2-4QOOHH4V-DeEc0lGZ.js +1 -0
  194. package/out/web/assets/studio-B1mk40wD.js +1 -0
  195. package/out/web/assets/{swimlanes-XN3QIQJK-Bn_jcZz-.js → swimlanes-XN3QIQJK-igYhTjXB.js} +1 -1
  196. package/out/web/assets/swimlanesDiagram-VK2B7HYN-DpVik9v7.js +8 -0
  197. package/out/web/assets/{timeline-definition-24CTP7MA-CdTERuJZ.js → timeline-definition-24CTP7MA-Dke2p93p.js} +1 -1
  198. package/out/web/assets/{treeView-Q6P3EWNA-TKBKQG6R.js → treeView-Q6P3EWNA-hNELnXUs.js} +1 -1
  199. package/out/web/assets/{treemap-WGGIJYW6-BP7gQoiC.js → treemap-WGGIJYW6-D2B6wDsx.js} +1 -1
  200. package/out/web/assets/{vennDiagram-4TSXK5OY-BHUmxDuK.js → vennDiagram-4TSXK5OY-CDkW7rUP.js} +1 -1
  201. package/out/web/assets/{wardley-WFR3VGLG-9bct5AAN.js → wardley-WFR3VGLG-BECdXETi.js} +1 -1
  202. package/out/web/assets/{wardleyDiagram-VM6X3IG4-BfJwDDso.js → wardleyDiagram-VM6X3IG4-B5BycpQ4.js} +1 -1
  203. package/out/web/assets/window-5qYXKoW7.js +1 -0
  204. package/out/web/assets/{xychartDiagram-S5SC5T6Z-Dqd9Mvpo.js → xychartDiagram-S5SC5T6Z-CtJS3b--.js} +1 -1
  205. package/out/web/index-web.html +3 -4
  206. package/out/web/index.html +3 -4
  207. package/package.json +17 -6
  208. package/skills-lock.json +36 -0
  209. package/slash-commands.json +9 -0
  210. package/src/renderer/index-web.html +1 -0
  211. package/src/renderer/index.html +1 -0
  212. package/src/renderer/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  213. package/src/renderer/shared/agentProgress.ts +168 -3
  214. package/src/renderer/shared/components/AgentActivityDrawer.tsx +6 -6
  215. package/src/renderer/shared/components/AgentActivityTable.tsx +192 -132
  216. package/src/renderer/shared/components/ArtifactPreviewPanel.tsx +4 -4
  217. package/src/renderer/shared/components/AuthGate.tsx +4 -9
  218. package/src/renderer/shared/components/CalculationCard.tsx +41 -15
  219. package/src/renderer/shared/components/ChatMessageItem.tsx +20 -21
  220. package/src/renderer/shared/components/ChatPanel.tsx +432 -193
  221. package/src/renderer/shared/components/ChunkErrorBoundary.tsx +198 -49
  222. package/src/renderer/shared/components/CliSessionsView.tsx +495 -0
  223. package/src/renderer/shared/components/CodeReviewPage.tsx +565 -0
  224. package/src/renderer/shared/components/CommandPalette.tsx +8 -8
  225. package/src/renderer/shared/components/DashboardSidebar.tsx +862 -125
  226. package/src/renderer/shared/components/DesktopTitlebar.tsx +345 -0
  227. package/src/renderer/shared/components/DiffReviewModal.tsx +3 -3
  228. package/src/renderer/shared/components/GitBranchSelector.tsx +442 -0
  229. package/src/renderer/shared/components/ImageGenCard.tsx +31 -12
  230. package/src/renderer/shared/components/ImageSearchCard.tsx +59 -38
  231. package/src/renderer/shared/components/ImageStudioPanel.tsx +40 -41
  232. package/src/renderer/shared/components/InlineThoughtNote.tsx +27 -0
  233. package/src/renderer/shared/components/LinkedFoldersView.tsx +365 -46
  234. package/src/renderer/shared/components/McpRegistryPicker.tsx +1 -1
  235. package/src/renderer/shared/components/McpServersView.tsx +24 -22
  236. package/src/renderer/shared/components/MermaidCard.tsx +14 -8
  237. package/src/renderer/shared/components/MintDashboard.tsx +1141 -508
  238. package/src/renderer/shared/components/ModelSelectorPopover.tsx +535 -214
  239. package/src/renderer/shared/components/PlanChecklistWidget.tsx +1 -1
  240. package/src/renderer/shared/components/PluginsView.tsx +1 -1
  241. package/src/renderer/shared/components/RewindModal.tsx +6 -6
  242. package/src/renderer/shared/components/RunSummaryDashboard.tsx +3 -3
  243. package/src/renderer/shared/components/ScheduledTasksView.tsx +4 -4
  244. package/src/renderer/shared/components/ScreenCaptureDialog.css +221 -0
  245. package/src/renderer/shared/components/ScreenCaptureDialog.tsx +199 -0
  246. package/src/renderer/shared/components/Settings/AgentsTab.tsx +34 -39
  247. package/src/renderer/shared/components/Settings/AudioTab.tsx +8 -8
  248. package/src/renderer/shared/components/Settings/AutomationTab.tsx +8 -58
  249. package/src/renderer/shared/components/Settings/AvatarCropModal.tsx +368 -0
  250. package/src/renderer/shared/components/Settings/GeneralTab.tsx +335 -81
  251. package/src/renderer/shared/components/Settings/MemoryTab.tsx +3 -3
  252. package/src/renderer/shared/components/Settings/PluginsTab.tsx +20 -12
  253. package/src/renderer/shared/components/Settings/ProfileTab.tsx +29 -5
  254. package/src/renderer/shared/components/Settings/SearchableModelCombobox.tsx +411 -0
  255. package/src/renderer/shared/components/Settings/ThemeTab.tsx +401 -158
  256. package/src/renderer/shared/components/SkillsView.tsx +41 -16
  257. package/src/renderer/shared/components/SlashSuggestions.tsx +3 -2
  258. package/src/renderer/shared/components/SourcesBlock.tsx +44 -32
  259. package/src/renderer/shared/components/StockCard.tsx +58 -24
  260. package/src/renderer/shared/components/SubagentDagView.tsx +4 -4
  261. package/src/renderer/shared/components/TerminalDock.tsx +241 -0
  262. package/src/renderer/shared/components/ThinkingBlock.tsx +14 -8
  263. package/src/renderer/shared/components/ToolSurfacePage.tsx +520 -0
  264. package/src/renderer/shared/components/UiFeatureCard.tsx +267 -0
  265. package/src/renderer/shared/components/UiGridCard.tsx +188 -0
  266. package/src/renderer/shared/components/UiMockupWidget.tsx +149 -0
  267. package/src/renderer/shared/components/VeoStudioPanel.tsx +13 -29
  268. package/src/renderer/shared/components/WeatherCard.tsx +3 -3
  269. package/src/renderer/shared/components/WorkspaceContextPopover.tsx +133 -0
  270. package/src/renderer/shared/components/WorkspaceSelector.tsx +149 -0
  271. package/src/renderer/shared/constants/config.ts +28 -3
  272. package/src/renderer/shared/constants/models.ts +189 -2
  273. package/src/renderer/shared/conversation/coordinator.test.ts +27 -0
  274. package/src/renderer/shared/conversation/coordinator.ts +82 -0
  275. package/src/renderer/shared/conversation/syncView.test.ts +46 -0
  276. package/src/renderer/shared/conversation/syncView.ts +43 -0
  277. package/src/renderer/shared/conversation/useConversationCoordinator.ts +106 -0
  278. package/src/renderer/shared/css/agent-observability.css +35 -3
  279. package/src/renderer/shared/css/auth-gate.css +2 -2
  280. package/src/renderer/shared/css/chat-ui-cards.css +495 -0
  281. package/src/renderer/shared/css/code-review.css +823 -0
  282. package/src/renderer/shared/css/code-sessions.css +452 -0
  283. package/src/renderer/shared/css/file-changes.css +132 -0
  284. package/src/renderer/shared/css/image-studio.css +16 -16
  285. package/src/renderer/shared/css/management-views.css +277 -27
  286. package/src/renderer/shared/css/model-selector.css +442 -42
  287. package/src/renderer/shared/css/settings/agents.css +1 -1
  288. package/src/renderer/shared/css/settings/automation.css +13 -13
  289. package/src/renderer/shared/css/settings/general.css +526 -5
  290. package/src/renderer/shared/css/settings/plugins.css +5 -5
  291. package/src/renderer/shared/css/settings/profile.css +331 -1
  292. package/src/renderer/shared/css/settings/theme.css +651 -3
  293. package/src/renderer/shared/css/veo-studio.css +16 -15
  294. package/src/renderer/shared/fonts.ts +19 -37
  295. package/src/renderer/shared/platform.test.ts +34 -0
  296. package/src/renderer/shared/platform.ts +173 -6
  297. package/src/renderer/shared/theme/themeManager.ts +144 -0
  298. package/src/renderer/shared/theme/themes.ts +116 -0
  299. package/src/renderer/shared/theme/tokens.css +318 -0
  300. package/src/renderer/shared/types.ts +82 -1
  301. package/src/renderer/shared/utils/agentActivity.ts +126 -5
  302. package/src/renderer/shared/utils/cardJson.test.ts +35 -0
  303. package/src/renderer/shared/utils/cardJson.ts +30 -0
  304. package/src/renderer/shared/utils/fileIcons.ts +1 -1
  305. package/src/renderer/shared/utils/markdown.tsx +329 -80
  306. package/src/renderer/shared/utils/markdown.webImages.test.tsx +40 -0
  307. package/src/renderer/shared/utils/providers.ts +8 -3
  308. package/src/renderer/shared/utils/screenCapture.ts +43 -0
  309. package/src/renderer/shared/utils/slashCommandProcessor.ts +4 -1
  310. package/src/renderer/shared/utils/ui.ts +4 -64
  311. package/src/renderer/src/App.tsx +7 -0
  312. package/src/renderer/src/components/BrowserShell.tsx +108 -0
  313. package/src/renderer/src/components/BrowserSuggestionsPopup.tsx +91 -0
  314. package/src/renderer/src/components/Live2DStage.tsx +32 -9
  315. package/src/renderer/src/components/MintDashboard.tsx +4 -2
  316. package/src/renderer/src/components/ModelPanel.tsx +2 -1
  317. package/src/renderer/src/components/PicturesLibrary.tsx +3 -2
  318. package/src/renderer/src/components/ScreenPicker.css +190 -0
  319. package/src/renderer/src/components/ScreenPicker.tsx +185 -540
  320. package/src/renderer/src/components/SettingsWindow.tsx +40 -2
  321. package/src/renderer/src/components/SpotlightWindow.tsx +1 -0
  322. package/src/renderer/src/components/WidgetWindow.tsx +27 -3
  323. package/src/renderer/src/components/WorkspacePanel.tsx +61 -43
  324. package/src/renderer/src/components/browser-shell.css +185 -0
  325. package/src/renderer/src/components/browser-suggestions-popup.css +55 -0
  326. package/src/renderer/src/components/liveTranslateFrames.test.ts +23 -0
  327. package/src/renderer/src/components/liveTranslateFrames.ts +34 -0
  328. package/src/renderer/src/css/app-shell.css +394 -113
  329. package/src/renderer/src/css/chat.css +1926 -380
  330. package/src/renderer/src/css/dashboard.css +11 -0
  331. package/src/renderer/src/css/desktop-tools.css +730 -0
  332. package/src/renderer/src/css/misc.css +19 -22
  333. package/src/renderer/src/css/model.css +49 -48
  334. package/src/renderer/src/css/pictures.css +144 -136
  335. package/src/renderer/src/css/settings/base.css +357 -123
  336. package/src/renderer/src/css/sidebar-workspace.css +930 -291
  337. package/src/renderer/src/css/spotlight.css +15 -26
  338. package/src/renderer/src/css/tool-surfaces.css +728 -0
  339. package/src/renderer/src/css/widget.css +35 -7
  340. package/src/renderer/src/env.d.ts +3 -0
  341. package/src/renderer/src/hooks/useProviderModels.ts +2 -9
  342. package/src/renderer/src/index.css +53 -46
  343. package/src/renderer/src/main.tsx +11 -0
  344. package/src/renderer/src/tauri.ts +201 -30
  345. package/src/renderer/src-web/App.tsx +40 -0
  346. package/src/renderer/src-web/components/MintDashboard.tsx +4 -2
  347. package/src/renderer/src-web/components/PicturesLibrary.tsx +3 -2
  348. package/src/renderer/src-web/components/PullToRefresh.tsx +107 -0
  349. package/src/renderer/src-web/components/SettingsWindow.tsx +28 -2
  350. package/src/renderer/src-web/css/app-shell.css +174 -96
  351. package/src/renderer/src-web/css/chat.css +1519 -316
  352. package/src/renderer/src-web/css/dashboard.css +11 -0
  353. package/src/renderer/src-web/css/misc.css +17 -17
  354. package/src/renderer/src-web/css/mobile.css +678 -0
  355. package/src/renderer/src-web/css/model.css +46 -46
  356. package/src/renderer/src-web/css/pictures.css +81 -34
  357. package/src/renderer/src-web/css/pull-to-refresh.css +54 -0
  358. package/src/renderer/src-web/css/settings/base.css +316 -100
  359. package/src/renderer/src-web/css/settings/mobile.css +320 -0
  360. package/src/renderer/src-web/css/sidebar-workspace.css +545 -100
  361. package/src/renderer/src-web/css/spotlight.css +9 -26
  362. package/src/renderer/src-web/css/widget.css +0 -5
  363. package/src/renderer/src-web/env.d.ts +3 -0
  364. package/src/renderer/src-web/hooks/useProviderModels.ts +2 -9
  365. package/src/renderer/src-web/index.css +53 -96
  366. package/src/renderer/src-web/main.tsx +11 -0
  367. package/src/renderer/src-web/tauri.ts +200 -30
  368. package/vite.config.web.ts +1 -0
  369. package/out/web/assets/MintDashboard-DWSqucgb.js +0 -57
  370. package/out/web/assets/SettingsWindow-DFM2aj5B.js +0 -2
  371. package/out/web/assets/chunk-CKBBP62Z-nr1uKPj9.js +0 -2
  372. package/out/web/assets/chunk-DSNCTWBM-Dtj8Rqsd.js +0 -2
  373. package/out/web/assets/chunk-DU6HZSFF-2tv5K1wT.js +0 -128
  374. package/out/web/assets/classDiagram-DTDB5LWJ-BdSFArgw.js +0 -1
  375. package/out/web/assets/classDiagram-v2-JRS7N3AN-BdSFArgw.js +0 -1
  376. package/out/web/assets/core-DImejIUG.js +0 -1
  377. package/out/web/assets/dist-js-BxuKEVWM.js +0 -1
  378. package/out/web/assets/event-BNl8Zahw.js +0 -1
  379. package/out/web/assets/fira-code-cyrillic-400-normal-UC0NFL4U.woff2 +0 -0
  380. package/out/web/assets/fira-code-cyrillic-400-normal-dc1q3VD7.woff +0 -0
  381. package/out/web/assets/fira-code-cyrillic-500-normal-Bu7VCL72.woff +0 -0
  382. package/out/web/assets/fira-code-cyrillic-500-normal-CX35h3Mg.woff2 +0 -0
  383. package/out/web/assets/fira-code-cyrillic-ext-400-normal-Buh61xzB.woff +0 -0
  384. package/out/web/assets/fira-code-cyrillic-ext-400-normal-txZ9Fk_1.woff2 +0 -0
  385. package/out/web/assets/fira-code-cyrillic-ext-500-normal-CYRspHgm.woff2 +0 -0
  386. package/out/web/assets/fira-code-cyrillic-ext-500-normal-CwtLmSFD.woff +0 -0
  387. package/out/web/assets/fira-code-greek-400-normal-B2Gh_Y8s.woff2 +0 -0
  388. package/out/web/assets/fira-code-greek-400-normal-DobhaxvF.woff +0 -0
  389. package/out/web/assets/fira-code-greek-500-normal-CVO0IRNt.woff2 +0 -0
  390. package/out/web/assets/fira-code-greek-500-normal-DEXIWiey.woff +0 -0
  391. package/out/web/assets/fira-code-greek-ext-400-normal-DR7mBgIM.woff2 +0 -0
  392. package/out/web/assets/fira-code-greek-ext-400-normal-DSPUheWg.woff +0 -0
  393. package/out/web/assets/fira-code-greek-ext-500-normal-BO3iq16n.woff2 +0 -0
  394. package/out/web/assets/fira-code-greek-ext-500-normal-CMiNLXER.woff +0 -0
  395. package/out/web/assets/fira-code-latin-ext-400-normal-DG73JjOf.woff +0 -0
  396. package/out/web/assets/fira-code-latin-ext-400-normal-KSMg0QLl.woff2 +0 -0
  397. package/out/web/assets/fira-code-latin-ext-500-normal-CaANqXjI.woff +0 -0
  398. package/out/web/assets/fira-code-latin-ext-500-normal-Crd9e_oI.woff2 +0 -0
  399. package/out/web/assets/flowDiagram-A5DVABFB-BpnHUSU7.js +0 -1
  400. package/out/web/assets/index-CVRg270z.css +0 -1
  401. package/out/web/assets/index-DxZQr9yD.js +0 -10
  402. package/out/web/assets/inter-cyrillic-400-normal-HOLc17fK.woff +0 -0
  403. package/out/web/assets/inter-cyrillic-400-normal-obahsSVq.woff2 +0 -0
  404. package/out/web/assets/inter-cyrillic-500-normal-BasfLYem.woff2 +0 -0
  405. package/out/web/assets/inter-cyrillic-500-normal-CxZf_p3X.woff +0 -0
  406. package/out/web/assets/inter-cyrillic-600-normal-4D_pXhcN.woff +0 -0
  407. package/out/web/assets/inter-cyrillic-600-normal-CWCymEST.woff2 +0 -0
  408. package/out/web/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2 +0 -0
  409. package/out/web/assets/inter-cyrillic-ext-400-normal-DQukG94-.woff +0 -0
  410. package/out/web/assets/inter-cyrillic-ext-500-normal-B0yAr1jD.woff2 +0 -0
  411. package/out/web/assets/inter-cyrillic-ext-500-normal-BmqWE9Dz.woff +0 -0
  412. package/out/web/assets/inter-cyrillic-ext-600-normal-Bcila6Z-.woff +0 -0
  413. package/out/web/assets/inter-cyrillic-ext-600-normal-Dfes3d0z.woff2 +0 -0
  414. package/out/web/assets/inter-greek-400-normal-B4URO6DV.woff2 +0 -0
  415. package/out/web/assets/inter-greek-400-normal-q2sYcFCs.woff +0 -0
  416. package/out/web/assets/inter-greek-500-normal-BIZE56-Y.woff2 +0 -0
  417. package/out/web/assets/inter-greek-500-normal-Xzm54t5V.woff +0 -0
  418. package/out/web/assets/inter-greek-600-normal-BZpKdvQh.woff +0 -0
  419. package/out/web/assets/inter-greek-600-normal-plRanbMR.woff2 +0 -0
  420. package/out/web/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2 +0 -0
  421. package/out/web/assets/inter-greek-ext-400-normal-KugGGMne.woff +0 -0
  422. package/out/web/assets/inter-greek-ext-500-normal-2j5mBUwD.woff +0 -0
  423. package/out/web/assets/inter-greek-ext-500-normal-C4iEst2y.woff2 +0 -0
  424. package/out/web/assets/inter-greek-ext-600-normal-B8X0CLgF.woff +0 -0
  425. package/out/web/assets/inter-greek-ext-600-normal-DRtmH8MT.woff2 +0 -0
  426. package/out/web/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
  427. package/out/web/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
  428. package/out/web/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
  429. package/out/web/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
  430. package/out/web/assets/inter-latin-600-normal-CiBQ2DWP.woff +0 -0
  431. package/out/web/assets/inter-latin-600-normal-LgqL8muc.woff2 +0 -0
  432. package/out/web/assets/inter-latin-ext-400-normal-77YHD8bZ.woff +0 -0
  433. package/out/web/assets/inter-latin-ext-400-normal-C1nco2VV.woff2 +0 -0
  434. package/out/web/assets/inter-latin-ext-500-normal-BxGbmqWO.woff +0 -0
  435. package/out/web/assets/inter-latin-ext-500-normal-CV4jyFjo.woff2 +0 -0
  436. package/out/web/assets/inter-latin-ext-600-normal-CIVaiw4L.woff +0 -0
  437. package/out/web/assets/inter-latin-ext-600-normal-D2bJ5OIk.woff2 +0 -0
  438. package/out/web/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff +0 -0
  439. package/out/web/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
  440. package/out/web/assets/inter-vietnamese-500-normal-DOriooB6.woff2 +0 -0
  441. package/out/web/assets/inter-vietnamese-500-normal-mJboJaSs.woff +0 -0
  442. package/out/web/assets/inter-vietnamese-600-normal-BuLX-rYi.woff +0 -0
  443. package/out/web/assets/inter-vietnamese-600-normal-Cc8MFFhd.woff2 +0 -0
  444. package/out/web/assets/kanit-latin-400-normal-BUlsQXH3.woff2 +0 -0
  445. package/out/web/assets/kanit-latin-400-normal-HVZWrfev.woff +0 -0
  446. package/out/web/assets/kanit-latin-500-normal-CX_4XcKi.woff2 +0 -0
  447. package/out/web/assets/kanit-latin-500-normal-qBha86O4.woff +0 -0
  448. package/out/web/assets/kanit-latin-600-normal-0lS78yAd.woff2 +0 -0
  449. package/out/web/assets/kanit-latin-600-normal-DlacpeTg.woff +0 -0
  450. package/out/web/assets/kanit-latin-ext-400-normal-B2xPf58u.woff2 +0 -0
  451. package/out/web/assets/kanit-latin-ext-400-normal-CHvNKHHD.woff +0 -0
  452. package/out/web/assets/kanit-latin-ext-500-normal-BFdWrG22.woff +0 -0
  453. package/out/web/assets/kanit-latin-ext-500-normal-EHs3suD6.woff2 +0 -0
  454. package/out/web/assets/kanit-latin-ext-600-normal-BBDzoLaj.woff +0 -0
  455. package/out/web/assets/kanit-latin-ext-600-normal-DAX3wtuq.woff2 +0 -0
  456. package/out/web/assets/kanit-thai-400-normal-D2nliXKa.woff +0 -0
  457. package/out/web/assets/kanit-thai-400-normal-D80Pglro.woff2 +0 -0
  458. package/out/web/assets/kanit-thai-500-normal-BB8gri04.woff2 +0 -0
  459. package/out/web/assets/kanit-thai-500-normal-Iy_w0a80.woff +0 -0
  460. package/out/web/assets/kanit-thai-600-normal-Bj6oiaDc.woff2 +0 -0
  461. package/out/web/assets/kanit-thai-600-normal-wbTlPO7I.woff +0 -0
  462. package/out/web/assets/kanit-vietnamese-400-normal-DRI8YWyb.woff2 +0 -0
  463. package/out/web/assets/kanit-vietnamese-400-normal-dow6Bnto.woff +0 -0
  464. package/out/web/assets/kanit-vietnamese-500-normal-BzTrpCM3.woff2 +0 -0
  465. package/out/web/assets/kanit-vietnamese-500-normal-T1ndT7MF.woff +0 -0
  466. package/out/web/assets/kanit-vietnamese-600-normal-Bi7fw3I4.woff2 +0 -0
  467. package/out/web/assets/kanit-vietnamese-600-normal-DXCRAa_8.woff +0 -0
  468. package/out/web/assets/mali-latin-400-normal-ByPcZ8Gx.woff +0 -0
  469. package/out/web/assets/mali-latin-400-normal-Cuc6Ykl8.woff2 +0 -0
  470. package/out/web/assets/mali-latin-500-normal-B01M-LP6.woff2 +0 -0
  471. package/out/web/assets/mali-latin-500-normal-Thgqw_9f.woff +0 -0
  472. package/out/web/assets/mali-latin-600-normal-B9TiUNpT.woff2 +0 -0
  473. package/out/web/assets/mali-latin-600-normal-CycpQCwU.woff +0 -0
  474. package/out/web/assets/mali-latin-ext-400-normal-DUVdJQO4.woff +0 -0
  475. package/out/web/assets/mali-latin-ext-400-normal-iCG1ALuJ.woff2 +0 -0
  476. package/out/web/assets/mali-latin-ext-500-normal-BfJE4UMZ.woff2 +0 -0
  477. package/out/web/assets/mali-latin-ext-500-normal-FoLEyOKS.woff +0 -0
  478. package/out/web/assets/mali-latin-ext-600-normal-BTvIfiCp.woff2 +0 -0
  479. package/out/web/assets/mali-latin-ext-600-normal-DAQcLVmD.woff +0 -0
  480. package/out/web/assets/mali-thai-400-normal-BO7A3bLZ.woff2 +0 -0
  481. package/out/web/assets/mali-thai-400-normal-CX9VrjTn.woff +0 -0
  482. package/out/web/assets/mali-thai-500-normal-Cph2qha9.woff +0 -0
  483. package/out/web/assets/mali-thai-500-normal-D89rMT77.woff2 +0 -0
  484. package/out/web/assets/mali-thai-600-normal-DPgXT6rZ.woff +0 -0
  485. package/out/web/assets/mali-thai-600-normal-DlTx3OsB.woff2 +0 -0
  486. package/out/web/assets/mali-vietnamese-400-normal-DUKxzXaz.woff2 +0 -0
  487. package/out/web/assets/mali-vietnamese-400-normal-gFDLvsOK.woff +0 -0
  488. package/out/web/assets/mali-vietnamese-500-normal--OY07q2c.woff +0 -0
  489. package/out/web/assets/mali-vietnamese-500-normal-KDrNRwfW.woff2 +0 -0
  490. package/out/web/assets/mali-vietnamese-600-normal-CtTMUU7T.woff +0 -0
  491. package/out/web/assets/mali-vietnamese-600-normal-DFlJr66u.woff2 +0 -0
  492. package/out/web/assets/mermaid.core-DYGGlqOf.js +0 -11
  493. package/out/web/assets/mitr-latin-400-normal-Cb18vPmZ.woff +0 -0
  494. package/out/web/assets/mitr-latin-400-normal-CwbkLQ4a.woff2 +0 -0
  495. package/out/web/assets/mitr-latin-500-normal-B4JOhzAi.woff +0 -0
  496. package/out/web/assets/mitr-latin-500-normal-BmClOow2.woff2 +0 -0
  497. package/out/web/assets/mitr-latin-ext-400-normal-B3CPG7Yo.woff2 +0 -0
  498. package/out/web/assets/mitr-latin-ext-400-normal-DTx65hiC.woff +0 -0
  499. package/out/web/assets/mitr-latin-ext-500-normal-B_Diajz1.woff2 +0 -0
  500. package/out/web/assets/mitr-latin-ext-500-normal-DYOsVaVT.woff +0 -0
  501. package/out/web/assets/mitr-thai-400-normal-CS4Do6aM.woff +0 -0
  502. package/out/web/assets/mitr-thai-400-normal-CXWaAdVj.woff2 +0 -0
  503. package/out/web/assets/mitr-thai-500-normal-CVdBrEVH.woff2 +0 -0
  504. package/out/web/assets/mitr-thai-500-normal-CW_B5D-i.woff +0 -0
  505. package/out/web/assets/mitr-vietnamese-400-normal-CPMGWyoC.woff2 +0 -0
  506. package/out/web/assets/mitr-vietnamese-400-normal-Z6XhIpdY.woff +0 -0
  507. package/out/web/assets/mitr-vietnamese-500-normal-CDrv0585.woff2 +0 -0
  508. package/out/web/assets/mitr-vietnamese-500-normal-CMQWyq-Z.woff +0 -0
  509. package/out/web/assets/noto-sans-thai-latin-400-normal-BaWBrqFP.woff2 +0 -0
  510. package/out/web/assets/noto-sans-thai-latin-400-normal-Dh_FJjOB.woff +0 -0
  511. package/out/web/assets/noto-sans-thai-latin-500-normal-BC04jsmm.woff +0 -0
  512. package/out/web/assets/noto-sans-thai-latin-500-normal-fyBKClF1.woff2 +0 -0
  513. package/out/web/assets/noto-sans-thai-latin-600-normal-CemcjnVR.woff2 +0 -0
  514. package/out/web/assets/noto-sans-thai-latin-600-normal-Dbc-dNO6.woff +0 -0
  515. package/out/web/assets/noto-sans-thai-latin-ext-400-normal-B-1H0YkH.woff +0 -0
  516. package/out/web/assets/noto-sans-thai-latin-ext-400-normal-nBP59pVw.woff2 +0 -0
  517. package/out/web/assets/noto-sans-thai-latin-ext-500-normal-B-ZWb8SZ.woff2 +0 -0
  518. package/out/web/assets/noto-sans-thai-latin-ext-500-normal-CrEHO7C8.woff +0 -0
  519. package/out/web/assets/noto-sans-thai-latin-ext-600-normal-PkMZo0xa.woff +0 -0
  520. package/out/web/assets/noto-sans-thai-latin-ext-600-normal-maHHBsez.woff2 +0 -0
  521. package/out/web/assets/noto-sans-thai-thai-400-normal-BEOmKAI1.woff2 +0 -0
  522. package/out/web/assets/noto-sans-thai-thai-400-normal-Dxb_unuU.woff +0 -0
  523. package/out/web/assets/noto-sans-thai-thai-500-normal-BOGXO2tw.woff +0 -0
  524. package/out/web/assets/noto-sans-thai-thai-500-normal-CU_X86GQ.woff2 +0 -0
  525. package/out/web/assets/noto-sans-thai-thai-600-normal-CmgB8_JK.woff +0 -0
  526. package/out/web/assets/noto-sans-thai-thai-600-normal-Cs73sVjl.woff2 +0 -0
  527. package/out/web/assets/oauthManager-DNiwM8Rn.js +0 -2
  528. package/out/web/assets/oauthManager-DuamS1Av.css +0 -1
  529. package/out/web/assets/outfit-latin-300-normal-AWLfuCom.woff +0 -0
  530. package/out/web/assets/outfit-latin-300-normal-CRYTwY6m.woff2 +0 -0
  531. package/out/web/assets/outfit-latin-400-normal-BGsTXAXT.woff2 +0 -0
  532. package/out/web/assets/outfit-latin-400-normal-DMwTpYkH.woff +0 -0
  533. package/out/web/assets/outfit-latin-500-normal-ClnHRwRh.woff +0 -0
  534. package/out/web/assets/outfit-latin-500-normal-DKnIMDSk.woff2 +0 -0
  535. package/out/web/assets/outfit-latin-600-normal-B7SfZ07L.woff2 +0 -0
  536. package/out/web/assets/outfit-latin-600-normal-BEfTtDA7.woff +0 -0
  537. package/out/web/assets/outfit-latin-ext-300-normal-BYS6Dpvq.woff2 +0 -0
  538. package/out/web/assets/outfit-latin-ext-300-normal-CMIMshEd.woff +0 -0
  539. package/out/web/assets/outfit-latin-ext-400-normal-5tcqmc2S.woff2 +0 -0
  540. package/out/web/assets/outfit-latin-ext-400-normal-DHm7mdGe.woff +0 -0
  541. package/out/web/assets/outfit-latin-ext-500-normal-DrCvqoFD.woff +0 -0
  542. package/out/web/assets/outfit-latin-ext-500-normal-zeox_O30.woff2 +0 -0
  543. package/out/web/assets/outfit-latin-ext-600-normal-B85nYjL1.woff2 +0 -0
  544. package/out/web/assets/outfit-latin-ext-600-normal-CWJcPgd7.woff +0 -0
  545. package/out/web/assets/preload-helper-D0uHx7FM.js +0 -1
  546. package/out/web/assets/prompt-latin-ext-400-normal-1pHbN9uy.woff +0 -0
  547. package/out/web/assets/prompt-latin-ext-400-normal-DdSafGZ9.woff2 +0 -0
  548. package/out/web/assets/prompt-latin-ext-500-normal--EZ1um7s.woff2 +0 -0
  549. package/out/web/assets/prompt-latin-ext-500-normal-D-lI1EVT.woff +0 -0
  550. package/out/web/assets/prompt-latin-ext-600-normal-C8b50x67.woff +0 -0
  551. package/out/web/assets/prompt-latin-ext-600-normal-Cg9L7iJU.woff2 +0 -0
  552. package/out/web/assets/prompt-vietnamese-400-normal-BCPzsgPT.woff2 +0 -0
  553. package/out/web/assets/prompt-vietnamese-400-normal-D4pLyeNK.woff +0 -0
  554. package/out/web/assets/prompt-vietnamese-500-normal-DmzxmPwa.woff2 +0 -0
  555. package/out/web/assets/prompt-vietnamese-500-normal-w_sS_j2F.woff +0 -0
  556. package/out/web/assets/prompt-vietnamese-600-normal-1dyohtNh.woff +0 -0
  557. package/out/web/assets/prompt-vietnamese-600-normal-7QWjJBsF.woff2 +0 -0
  558. package/out/web/assets/sarabun-latin-400-normal-DmguIS-7.woff +0 -0
  559. package/out/web/assets/sarabun-latin-400-normal-URPBxl-K.woff2 +0 -0
  560. package/out/web/assets/sarabun-latin-500-normal-BjUTcdxu.woff2 +0 -0
  561. package/out/web/assets/sarabun-latin-500-normal-CJexTAnl.woff +0 -0
  562. package/out/web/assets/sarabun-latin-600-normal-9FonlkKx.woff +0 -0
  563. package/out/web/assets/sarabun-latin-600-normal-DMD3TROr.woff2 +0 -0
  564. package/out/web/assets/sarabun-latin-ext-400-normal-BbP7GpLL.woff2 +0 -0
  565. package/out/web/assets/sarabun-latin-ext-400-normal-BsmTn0SS.woff +0 -0
  566. package/out/web/assets/sarabun-latin-ext-500-normal-Cot16Bd2.woff +0 -0
  567. package/out/web/assets/sarabun-latin-ext-500-normal-DE1LysqI.woff2 +0 -0
  568. package/out/web/assets/sarabun-latin-ext-600-normal-0tXu9x_i.woff +0 -0
  569. package/out/web/assets/sarabun-latin-ext-600-normal-BRxjKUQ6.woff2 +0 -0
  570. package/out/web/assets/sarabun-thai-400-normal-C2DaJlKK.woff2 +0 -0
  571. package/out/web/assets/sarabun-thai-400-normal-CH-UbWgg.woff +0 -0
  572. package/out/web/assets/sarabun-thai-500-normal-BVssjame.woff2 +0 -0
  573. package/out/web/assets/sarabun-thai-500-normal-C3iDLEzi.woff +0 -0
  574. package/out/web/assets/sarabun-thai-600-normal-3dIAQ-_s.woff2 +0 -0
  575. package/out/web/assets/sarabun-thai-600-normal-DWKeTe6a.woff +0 -0
  576. package/out/web/assets/sarabun-vietnamese-400-normal-DPfkSCMy.woff +0 -0
  577. package/out/web/assets/sarabun-vietnamese-400-normal-igdrzAGY.woff2 +0 -0
  578. package/out/web/assets/sarabun-vietnamese-500-normal-CpRVvGRU.woff +0 -0
  579. package/out/web/assets/sarabun-vietnamese-500-normal-Dpe7Br9m.woff2 +0 -0
  580. package/out/web/assets/sarabun-vietnamese-600-normal-BMbOgAW-.woff +0 -0
  581. package/out/web/assets/sarabun-vietnamese-600-normal-DkxrOlLB.woff2 +0 -0
  582. package/out/web/assets/stateDiagram-v2-4QOOHH4V-s6P9g2_b.js +0 -1
  583. package/out/web/assets/swimlanesDiagram-VK2B7HYN-CV9fOLrV.js +0 -8
  584. package/out/web/assets/tauri-CNrHQ2Gb.js +0 -3
  585. package/out/web/assets/window-DkIhgI7B.js +0 -1
@@ -1,5 +1,6 @@
1
1
  import { useEffect, useMemo, useRef, useState, useCallback, Fragment, type ChangeEvent, type ClipboardEvent, type DragEvent, type FormEvent, type KeyboardEvent, type RefObject } from 'react'
2
- import { hasAgentToolActivity, thoughtsFrom, parseFileChangesFromProgress } from '../agentProgress'
2
+ import { hasAgentToolActivity, thoughtsFrom, extendedThoughtsFrom, mergeFileChanges, parseFileChangesFromProgress } from '../agentProgress'
3
+ import { visibleInteractionsDuringRun } from '../conversation/syncView'
3
4
  import {
4
5
  GEMINI_MODELS,
5
6
  OPENAI_MODELS,
@@ -25,32 +26,61 @@ import ChatMessageItem from './ChatMessageItem'
25
26
  import { AgentActivityDrawer } from './AgentActivityDrawer'
26
27
  import { ArtifactPreviewPanel, type ArtifactFile } from './ArtifactPreviewPanel'
27
28
  import { RewindModal } from './RewindModal'
28
- import type { DiffHunk, FileChange, GitCheckpoint } from '../types'
29
+ import type { AgentProgress, ChatResponse, DiffHunk, FileChange, GitCheckpoint, RuntimeStatus } from '../types'
29
30
  import { numericSetting, shouldShowSessionDivider, formatSessionDividerLabel } from '../utils/ui'
30
31
  import { useVoiceInput } from '@/voiceInput'
31
32
  import { useGeminiLiveVoice } from '../utils/useGeminiLiveVoice'
32
33
  import GeminiLiveOverlay from './GeminiLiveOverlay'
33
34
  import { isSupportedDocument, SUPPORTED_DOCUMENT_ACCEPT } from '../utils/documentTypes'
34
35
  import ModelSelectorPopover from './ModelSelectorPopover'
36
+ import GitBranchSelector from './GitBranchSelector'
37
+ import WorkspaceSelector from './WorkspaceSelector'
38
+ import CodeReviewPage from './CodeReviewPage'
39
+ import type { ToolSurface } from './ToolSurfacePage'
35
40
 
36
- import {
37
- APP_ICON_PATH,
38
- type AgentProgress,
39
- type ChatResponse,
40
- type RuntimeStatus,
41
- getTtsUrls,
42
- startGeminiLiveSession,
43
- sendGeminiLiveAudioChunk,
44
- stopGeminiLiveSession,
45
- listGitCheckpoints,
46
- rollbackGitCheckpoint,
47
- undoGitCheckpoint,
48
- fetchProviderModels,
49
- } from '@/tauri'
41
+ import { catalogPlatform, conversationPlatform, runtimePlatform } from '../platform'
50
42
 
43
+ const STREAM_MARKDOWN_UPDATE_MS = 120
51
44
 
52
- interface ChatPanelProps {
45
+ function useThrottledValue<T>(value: T, intervalMs: number): T {
46
+ const [throttledValue, setThrottledValue] = useState(value)
47
+ const latestValueRef = useRef(value)
48
+ const lastUpdateRef = useRef(0)
49
+ const timerRef = useRef<ReturnType<typeof window.setTimeout> | null>(null)
50
+
51
+ useEffect(() => {
52
+ latestValueRef.current = value
53
+ if (Object.is(value, throttledValue)) return
54
+
55
+ const flush = () => {
56
+ timerRef.current = null
57
+ lastUpdateRef.current = Date.now()
58
+ setThrottledValue(latestValueRef.current)
59
+ }
60
+ const remaining = intervalMs - (Date.now() - lastUpdateRef.current)
61
+ if (remaining <= 0) flush()
62
+ else if (timerRef.current === null) timerRef.current = window.setTimeout(flush, remaining)
63
+ }, [value, throttledValue, intervalMs])
64
+
65
+ useEffect(() => () => {
66
+ if (timerRef.current !== null) window.clearTimeout(timerRef.current)
67
+ }, [])
68
+
69
+ return throttledValue
70
+ }
71
+
72
+ const {
73
+ getTtsUrls, startGeminiLiveSession, sendGeminiLiveAudioChunk, stopGeminiLiveSession,
74
+ listGitCheckpoints, rollbackGitCheckpoint, undoGitCheckpoint,
75
+ } = conversationPlatform
76
+ const { fetchProviderModels } = catalogPlatform
77
+
78
+
79
+ interface ChatPanelContract {
53
80
  interactions: any[]
81
+ sendingInteractionId?: number | null
82
+ hasOlder?: boolean
83
+ onLoadOlder?: () => Promise<void>
54
84
  sending: boolean
55
85
  sendingMessage: string
56
86
  sendingImageCount: number
@@ -66,13 +96,13 @@ interface ChatPanelProps {
66
96
  videoAttachments: Array<{ dataUri: string; name: string }>
67
97
  documentName: string
68
98
  pendingApproval: any | null
69
- smartContext: boolean
70
99
  agentMode: boolean
71
100
  /** Desktop only — plan-mode-approval UI isn't available on web. */
72
101
  planMode?: boolean
73
102
  status: RuntimeStatus | null
74
103
  /** Desktop only — web has no local workspace-folder concept to select from. */
75
104
  workspacePath?: string
105
+ chatId: string
76
106
  chatEnd: RefObject<HTMLDivElement | null>
77
107
  welcomeInteraction: any
78
108
  onSubmit: (event: FormEvent<HTMLFormElement>) => void
@@ -87,15 +117,17 @@ interface ChatPanelProps {
87
117
  onRemoveDocument: () => void
88
118
  onStartWebSearch: () => void
89
119
  onCaptureScreen: () => void
90
- onSetSmartContext: (enabled: boolean) => void
91
120
  onSetAgentMode: (enabled: boolean) => void
92
121
  /** Desktop only — see `planMode`. */
93
122
  onSetPlanMode?: (enabled: boolean) => void
94
123
  onSetProvider: (provider: string) => void
95
124
  /** Desktop only — see `workspacePath`. */
96
- onSelectWorkspace?: () => void
125
+ onSelectWorkspace?: (path?: string) => void
126
+ onWorkspaceChanged?: () => void
127
+ recentWorkspacePaths: string[]
97
128
  onApproval: (approved: boolean, autoApproveSession?: boolean, answer?: string) => void
98
129
  settingsConfig: any
130
+ onUpdateSettings?: (config: any) => void
99
131
  onSetModel: (model: string) => void
100
132
  onSelectModelAndProvider?: (provider: string, model: string) => void
101
133
  onCancelMessage: () => void
@@ -103,11 +135,40 @@ interface ChatPanelProps {
103
135
  onSetGeminiLiveVoice: (voice: string) => Promise<void>
104
136
  /** Web only — desktop's window has no mobile-width sidebar to toggle. */
105
137
  onToggleMobileSidebar?: () => void
138
+ isCliSession?: boolean
139
+ cliSessionId?: string
140
+ onBackToCode?: () => void
141
+ conversationTitle?: string
142
+ onOpenArtifact?: (artifact: ArtifactFile) => void
143
+ onOpenReview?: (review: Extract<ToolSurface, { kind: 'review' }>) => void
106
144
  }
107
145
 
146
+ export type ConversationViewModel = Pick<ChatPanelContract,
147
+ | 'interactions' | 'sending' | 'sendingMessage' | 'sendingImageCount' | 'sendingVideoCount'
148
+ | 'streamedReply' | 'streamedResponse' | 'agentProgress' | 'agentActivitySnapshots'
149
+ | 'thinkingExpanded' | 'message' | 'imageAttachments' | 'videoAttachments' | 'documentName'
150
+ | 'pendingApproval' | 'agentMode' | 'planMode' | 'status' | 'workspacePath' | 'chatId' | 'recentWorkspacePaths'
151
+ | 'chatEnd' | 'welcomeInteraction' | 'settingsConfig' | 'isCliSession' | 'cliSessionId'
152
+ | 'conversationTitle'
153
+ | 'hasOlder'
154
+ | 'sendingInteractionId'
155
+ >
156
+ export type ConversationActions = Omit<ChatPanelContract, keyof ConversationViewModel>
157
+
158
+ interface ChatPanelProps {
159
+ conversation: ConversationViewModel
160
+ actions: ConversationActions
161
+ }
108
162
 
109
163
  export default function ChatPanel({
164
+ conversation,
165
+ actions,
166
+ }: ChatPanelProps) {
167
+ const {
110
168
  interactions,
169
+ sendingInteractionId,
170
+ hasOlder,
171
+ onLoadOlder,
111
172
  sending,
112
173
  sendingMessage,
113
174
  sendingImageCount,
@@ -123,11 +184,12 @@ export default function ChatPanel({
123
184
  videoAttachments,
124
185
  documentName,
125
186
  pendingApproval,
126
- smartContext,
127
187
  agentMode,
128
188
  planMode,
129
189
  status,
130
190
  workspacePath,
191
+ chatId,
192
+ recentWorkspacePaths,
131
193
  chatEnd,
132
194
  welcomeInteraction,
133
195
  onSubmit,
@@ -142,21 +204,71 @@ export default function ChatPanel({
142
204
  onRemoveDocument,
143
205
  onStartWebSearch,
144
206
  onCaptureScreen,
145
- onSetSmartContext,
146
207
  onSetAgentMode,
147
208
  onSetPlanMode,
148
209
  onSetProvider,
149
210
  onSelectWorkspace,
211
+ onWorkspaceChanged,
150
212
  onApproval,
151
213
  settingsConfig,
214
+ onUpdateSettings,
152
215
  onSetModel,
153
216
  onSelectModelAndProvider,
154
217
  onCancelMessage,
155
218
  onClearMessages,
156
219
  onSetGeminiLiveVoice,
157
220
  onToggleMobileSidebar,
158
- }: ChatPanelProps) {
221
+ isCliSession,
222
+ cliSessionId,
223
+ onBackToCode,
224
+ conversationTitle,
225
+ onOpenArtifact,
226
+ onOpenReview,
227
+ } = { ...conversation, ...actions }
228
+ // The initiating surface already renders a live prompt/reply pair below.
229
+ // Hide its matching persisted turn until the local stream settles, while
230
+ // still showing turns submitted from other surfaces during that time.
231
+ const visibleInteractions = useMemo(
232
+ () => visibleInteractionsDuringRun(interactions, sending, sendingInteractionId),
233
+ [interactions, sending, sendingInteractionId],
234
+ )
159
235
  const agentActivities = activitiesFrom(agentProgress)
236
+ // Keep the composer summary tied to the active/latest agent run. This is cheap
237
+ // metadata, but memoizing it avoids parsing the activity stream while typing.
238
+ const composerChanges = useMemo(() => parseFileChangesFromProgress(agentProgress), [agentProgress])
239
+ const composerAdditions = useMemo(
240
+ () => composerChanges.reduce((sum, change) => sum + change.additions, 0),
241
+ [composerChanges],
242
+ )
243
+ const composerDeletions = useMemo(
244
+ () => composerChanges.reduce((sum, change) => sum + change.deletions, 0),
245
+ [composerChanges],
246
+ )
247
+ const composerChangeLabel = composerChanges.length === 1
248
+ ? '1 file changed'
249
+ : `${composerChanges.length} files changed`
250
+ const conversationChanges = useMemo(() => {
251
+ const historicalGroups = interactions.map((interaction) => {
252
+ const interactionId = String(interaction.id)
253
+ const progress = agentActivitySnapshots[interactionId] ?? interaction.agentActivity ?? []
254
+ return parseFileChangesFromProgress(progress)
255
+ })
256
+ const activeChanges = parseFileChangesFromProgress(agentProgress)
257
+ return mergeFileChanges([...historicalGroups, activeChanges])
258
+ }, [agentActivitySnapshots, agentProgress, interactions])
259
+
260
+ const projectName = useMemo(() => {
261
+ if (!workspacePath) return null
262
+ const clean = workspacePath.replace(/[\\/]+$/, '').trim()
263
+ if (!clean) return null
264
+ const parts = clean.split(/[\\/]/)
265
+ return parts[parts.length - 1] || clean
266
+ }, [workspacePath])
267
+
268
+ // Markdown parsing can be expensive for code, tables, and interactive cards.
269
+ // Limit it to a steady cadence instead of parsing on every stream chunk.
270
+ const throttledStreamedReply = useThrottledValue(streamedReply, STREAM_MARKDOWN_UPDATE_MS)
271
+ const liveWebSources = useMemo(() => parseWebSearchSources(agentProgress), [agentProgress])
160
272
  const activeFallbackNotice = fallbackNotice(streamedResponse)
161
273
  const lastThinkingProgress = [...agentProgress].reverse().find(p => p.type === 'Thinking')
162
274
  let activeAgentName: string | null = null
@@ -168,11 +280,23 @@ export default function ChatPanel({
168
280
  const [openActivityIds, setOpenActivityIds] = useState<Record<string, boolean>>({})
169
281
  const [openReviewIds, setOpenReviewIds] = useState<Record<string, boolean>>({})
170
282
  const [openFileDiffs, setOpenFileDiffs] = useState<Record<string, boolean>>({})
283
+ const [showAllFileChanges, setShowAllFileChanges] = useState<Record<string, boolean>>({})
284
+ const [reviewPage, setReviewPage] = useState<{ title: string; changes: FileChange[] } | null>(null)
171
285
  const [activeArtifact, setActiveArtifact] = useState<ArtifactFile | null>(null)
172
286
  const [toolMenuOpen, setToolMenuOpen] = useState(false)
173
287
  const [elapsedSeconds, setElapsedSeconds] = useState(0)
174
288
  const [dynamicOllamaModels, setDynamicOllamaModels] = useState<string[]>(OLLAMA_MODELS)
175
289
 
290
+ const openArtifact = (artifact: ArtifactFile) => {
291
+ if (onOpenArtifact) onOpenArtifact(artifact)
292
+ else setActiveArtifact(artifact)
293
+ }
294
+
295
+ const openReview = (title: string, changes: FileChange[]) => {
296
+ if (onOpenReview) onOpenReview({ id: `review:${Date.now()}`, kind: 'review', title: 'Review', reviewTitle: title, changes })
297
+ else setReviewPage({ title, changes })
298
+ }
299
+
176
300
  useEffect(() => {
177
301
  let cancelled = false
178
302
  const fetchOllamaModels = async () => {
@@ -239,7 +363,9 @@ export default function ChatPanel({
239
363
 
240
364
  const chatContainerRef = useRef<HTMLDivElement | null>(null)
241
365
  const [showScrollToBottom, setShowScrollToBottom] = useState(false)
366
+ const [loadingOlder, setLoadingOlder] = useState(false)
242
367
  const isNearBottomRef = useRef(true)
368
+ const scrollFrameRef = useRef<number | null>(null)
243
369
 
244
370
  const handleChatScroll = useCallback(() => {
245
371
  const el = chatContainerRef.current
@@ -250,6 +376,26 @@ export default function ChatPanel({
250
376
  isNearBottomRef.current = nearBottom
251
377
  }, [])
252
378
 
379
+ const scheduleScrollToLatest = useCallback(() => {
380
+ if (!isNearBottomRef.current || scrollFrameRef.current !== null) return
381
+ scrollFrameRef.current = window.requestAnimationFrame(() => {
382
+ scrollFrameRef.current = null
383
+ const element = chatContainerRef.current
384
+ if (element && isNearBottomRef.current) {
385
+ // Smooth scrolling on every token restarts animations and causes jank.
386
+ element.scrollTop = element.scrollHeight
387
+ }
388
+ })
389
+ }, [])
390
+
391
+ useEffect(() => {
392
+ scheduleScrollToLatest()
393
+ }, [interactions, sending, streamedReply, pendingApproval, agentProgress, scheduleScrollToLatest])
394
+
395
+ useEffect(() => () => {
396
+ if (scrollFrameRef.current !== null) window.cancelAnimationFrame(scrollFrameRef.current)
397
+ }, [])
398
+
253
399
  useEffect(() => {
254
400
  const el = chatContainerRef.current
255
401
  if (!el) return
@@ -560,6 +706,7 @@ export default function ChatPanel({
560
706
  const geminiLiveEnabled = settingsConfig?.voiceMode === 'geminiLive'
561
707
  const geminiLive = useGeminiLiveVoice({
562
708
  workspacePath,
709
+ chatId,
563
710
  startSession: startGeminiLiveSession,
564
711
  sendAudioChunk: sendGeminiLiveAudioChunk,
565
712
  stopSession: stopGeminiLiveSession
@@ -631,9 +778,6 @@ export default function ChatPanel({
631
778
  }
632
779
  }
633
780
  const activeModel = getActiveModel(activeProvider)
634
- const workspaceName = workspacePath
635
- ? workspacePath.split(/[\\/]/).filter(Boolean).pop() || workspacePath
636
- : 'Select Project'
637
781
  const textareaRef = useRef<HTMLTextAreaElement>(null)
638
782
  const slashRef = useRef<SlashSuggestionsHandle>(null)
639
783
 
@@ -993,9 +1137,11 @@ export default function ChatPanel({
993
1137
  }, [agentActivitySnapshots])
994
1138
 
995
1139
  const renderChangesList = (changes: ReturnType<typeof parseFileChangesFromProgress>, idPrefix: string) => {
1140
+ const showAll = Boolean(showAllFileChanges[idPrefix])
1141
+ const visibleChanges = showAll ? changes : changes.slice(0, 3)
996
1142
  return (
997
- <div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>
998
- {changes.map((change) => {
1143
+ <div className="file-changes-list" style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>
1144
+ {visibleChanges.map((change) => {
999
1145
  const fileKey = `${idPrefix}-${change.path}`
1000
1146
  const isDiffOpen = Boolean(openFileDiffs[fileKey])
1001
1147
  const fileName = change.path.split('/').pop() || change.path
@@ -1042,7 +1188,7 @@ export default function ChatPanel({
1042
1188
  change.created && change.hunks.length > 0
1043
1189
  ? change.hunks.map((h) => h.newText).filter(Boolean).join('\n')
1044
1190
  : undefined
1045
- setActiveArtifact({ path: change.path, content: fallbackContent })
1191
+ openArtifact({ path: change.path, content: fallbackContent })
1046
1192
  }}
1047
1193
  title="Open Live Preview Split View"
1048
1194
  >
@@ -1083,6 +1229,17 @@ export default function ChatPanel({
1083
1229
  </div>
1084
1230
  )
1085
1231
  })}
1232
+ {changes.length > 3 && (
1233
+ <button
1234
+ type="button"
1235
+ className="file-changes-show-more"
1236
+ aria-expanded={showAll}
1237
+ onClick={() => setShowAllFileChanges((current) => ({ ...current, [idPrefix]: !current[idPrefix] }))}
1238
+ >
1239
+ {showAll ? 'Show fewer files' : `Show ${changes.length - 3} more ${changes.length - 3 === 1 ? 'file' : 'files'}`}
1240
+ <span aria-hidden="true" className={showAll ? 'is-expanded' : ''}>⌄</span>
1241
+ </button>
1242
+ )}
1086
1243
  </div>
1087
1244
  )
1088
1245
  }
@@ -1097,7 +1254,7 @@ export default function ChatPanel({
1097
1254
  const totalDeletions = changes.reduce((sum, c) => sum + c.deletions, 0)
1098
1255
  const createdCount = changes.filter((c) => c.created).length
1099
1256
  const modifiedCount = changes.length - createdCount
1100
- const isOpen = Boolean(openReviewIds[interactionId])
1257
+ const isOpen = openReviewIds[interactionId] ?? true
1101
1258
 
1102
1259
  let summaryLabel = ''
1103
1260
  if (createdCount > 0 && modifiedCount === 0) {
@@ -1171,56 +1328,49 @@ export default function ChatPanel({
1171
1328
  }
1172
1329
 
1173
1330
  return (
1174
- <div className="file-changes-summary-container" style={{ marginBottom: '8px' }}>
1175
- <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '8px' }}>
1176
- <button
1177
- type="button"
1178
- className="agent-activity-toggle file-changes-toggle"
1179
- aria-expanded={isOpen}
1180
- onClick={() => setOpenReviewIds((current) => ({ ...current, [interactionId]: !current[interactionId] }))}
1181
- >
1182
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{ marginRight: '2px' }}>
1183
- <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
1184
- <polyline points="22 4 12 14.01 9 11.01" />
1185
- </svg>
1186
- <span>
1187
- {summaryLabel}
1188
- {createdCount > 0 && modifiedCount === 0 ? (
1189
- <span className="file-changes-count-add" style={{ marginLeft: '6px' }}>
1190
- (+{totalAdditions} {totalAdditions === 1 ? 'line' : 'lines'})
1331
+ <div className="file-changes-summary-container">
1332
+ <div className="agent-activity-card file-changes-card">
1333
+ <div className="file-changes-summary-row">
1334
+ <div className="file-changes-summary">
1335
+ <span className="file-changes-summary-icon" aria-hidden="true">⊞</span>
1336
+ <span className="file-changes-summary-copy">
1337
+ <span className="file-changes-summary-label">{summaryLabel}</span>
1338
+ <span className="file-changes-summary-counts">
1339
+ {totalAdditions > 0 && <span className="file-changes-count-add">+{totalAdditions}</span>}
1340
+ {totalDeletions > 0 && <span className="file-changes-count-del">-{totalDeletions}</span>}
1191
1341
  </span>
1192
- ) : (
1193
- <>
1194
- {totalAdditions > 0 && <span className="file-changes-count-add" style={{ marginLeft: '6px' }}>+{totalAdditions}</span>}
1195
- {totalDeletions > 0 && <span className="file-changes-count-del" style={{ marginLeft: '4px' }}>-{totalDeletions}</span>}
1196
- </>
1197
- )}
1198
- </span>
1199
- <span aria-hidden="true">{isOpen ? '^' : '>'}</span>
1200
- </button>
1201
-
1202
- <button
1203
- type="button"
1204
- className="file-changes-rewind-btn"
1205
- onClick={handleRewind}
1206
- title="Rewind workspace to before these file edits (Git Checkpoint)"
1207
- >
1208
- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
1209
- <polyline points="1 4 1 10 7 10" />
1210
- <path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10" />
1211
- </svg>
1212
- Rewind
1213
- </button>
1214
- </div>
1215
-
1216
- {isOpen && (
1217
- <div className="agent-activity-card file-changes-card">
1218
- {renderChangesList(changes, interactionId)}
1342
+ </span>
1343
+ </div>
1344
+ <div className="file-changes-summary-actions">
1345
+ <button
1346
+ type="button"
1347
+ className="file-changes-rewind-btn"
1348
+ onClick={handleRewind}
1349
+ title="Rewind workspace to before these file edits (Git Checkpoint)"
1350
+ >
1351
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1352
+ <polyline points="1 4 7 4 7 10" />
1353
+ <path d="M3 9a9 9 0 1 0 2.13-5.36L1 7" />
1354
+ </svg>
1355
+ Undo
1356
+ </button>
1357
+ <button
1358
+ type="button"
1359
+ className="file-changes-review-btn"
1360
+ title="Review changed code"
1361
+ onClick={() => {
1362
+ openReview('All conversation changes', conversationChanges)
1363
+ }}
1364
+ >
1365
+ Review
1366
+ </button>
1367
+ </div>
1219
1368
  </div>
1220
- )}
1369
+ {isOpen && <div className="file-changes-list-container">{renderChangesList(changes, interactionId)}</div>}
1370
+ </div>
1221
1371
  </div>
1222
1372
  )
1223
- }, [agentActivitySnapshots, openReviewIds, openFileDiffs, workspacePath])
1373
+ }, [agentActivitySnapshots, conversationChanges, openReviewIds, openFileDiffs, showAllFileChanges, workspacePath])
1224
1374
 
1225
1375
  const renderActiveFileChanges = () => {
1226
1376
  const changes = parseFileChangesFromProgress(agentProgress)
@@ -1230,49 +1380,45 @@ export default function ChatPanel({
1230
1380
  const totalDeletions = changes.reduce((sum, c) => sum + c.deletions, 0)
1231
1381
  const createdCount = changes.filter((c) => c.created).length
1232
1382
  const modifiedCount = changes.length - createdCount
1233
- const isOpen = Boolean(openReviewIds['active-run'])
1383
+ const isOpen = openReviewIds['active-run'] ?? true
1234
1384
 
1235
1385
  let summaryLabel = ''
1236
1386
  if (createdCount > 0 && modifiedCount === 0) {
1237
- summaryLabel = `${createdCount} ${createdCount === 1 ? 'file created' : 'files created'} in this run`
1387
+ summaryLabel = `${createdCount} ${createdCount === 1 ? 'file created' : 'files created'}`
1238
1388
  } else if (createdCount > 0 && modifiedCount > 0) {
1239
- summaryLabel = `${createdCount} created, ${modifiedCount} modified in this run`
1389
+ summaryLabel = `${createdCount} created, ${modifiedCount} modified`
1240
1390
  } else {
1241
- summaryLabel = `${changes.length} ${changes.length === 1 ? 'file changed' : 'files changed'} in this run`
1391
+ summaryLabel = `${changes.length} ${changes.length === 1 ? 'file changed' : 'files changed'}`
1242
1392
  }
1243
1393
 
1244
1394
  return (
1245
1395
  <div className="message ai-message agent-activity-message" style={{ marginTop: '4px', marginBottom: '8px' }}>
1246
1396
  <div className="agent-activity-card file-changes-card">
1247
- <button
1248
- type="button"
1249
- className="agent-activity-toggle file-changes-toggle"
1250
- aria-expanded={isOpen}
1251
- onClick={() => setOpenReviewIds((current) => ({ ...current, 'active-run': !current['active-run'] }))}
1252
- style={{ border: 0, background: 'transparent', padding: 0 }}
1253
- >
1254
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{ marginRight: '2px' }}>
1255
- <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
1256
- <polyline points="22 4 12 14.01 9 11.01" />
1257
- </svg>
1258
- <span>
1259
- {summaryLabel}
1260
- {createdCount > 0 && modifiedCount === 0 ? (
1261
- <span className="file-changes-count-add" style={{ marginLeft: '6px' }}>
1262
- (+{totalAdditions} {totalAdditions === 1 ? 'line' : 'lines'})
1397
+ <div className="file-changes-summary-row">
1398
+ <div className="file-changes-summary">
1399
+ <span className="file-changes-summary-icon" aria-hidden="true">✓</span>
1400
+ <span className="file-changes-summary-copy">
1401
+ <span className="file-changes-summary-label">{summaryLabel}</span>
1402
+ <span className="file-changes-summary-counts">
1403
+ {totalAdditions > 0 && <span className="file-changes-count-add">+{totalAdditions}</span>}
1404
+ {totalDeletions > 0 && <span className="file-changes-count-del">-{totalDeletions}</span>}
1263
1405
  </span>
1264
- ) : (
1265
- <>
1266
- {totalAdditions > 0 && <span className="file-changes-count-add" style={{ marginLeft: '6px' }}>+{totalAdditions}</span>}
1267
- {totalDeletions > 0 && <span className="file-changes-count-del" style={{ marginLeft: '4px' }}>-{totalDeletions}</span>}
1268
- </>
1269
- )}
1270
- </span>
1271
- <span aria-hidden="true">{isOpen ? '^' : '>'}</span>
1272
- </button>
1406
+ </span>
1407
+ </div>
1408
+ <button
1409
+ type="button"
1410
+ className="file-changes-review-btn"
1411
+ title="Review changed code"
1412
+ onClick={() => {
1413
+ openReview('All conversation changes', conversationChanges)
1414
+ }}
1415
+ >
1416
+ Review
1417
+ </button>
1418
+ </div>
1273
1419
 
1274
1420
  {isOpen && (
1275
- <div style={{ marginTop: '8px' }}>
1421
+ <div className="file-changes-list-container" style={{ marginTop: '8px' }}>
1276
1422
  {renderChangesList(changes, 'active')}
1277
1423
  </div>
1278
1424
  )}
@@ -1288,7 +1434,7 @@ export default function ChatPanel({
1288
1434
  onDragOver={handleDragOver}
1289
1435
  onDragLeave={handleDragLeave}
1290
1436
  onDrop={handleDrop}
1291
- style={activeArtifact ? { flex: '0 0 calc(100% - var(--preview-width, 50%))', width: 'calc(100% - var(--preview-width, 50%))', minWidth: '320px', maxWidth: 'none', margin: 0, position: 'relative' } : undefined}
1437
+ style={activeArtifact || reviewPage ? { flex: '0 0 calc(100% - var(--preview-width, 50%))', width: 'calc(100% - var(--preview-width, 50%))', minWidth: '320px', maxWidth: 'none', margin: 0, position: 'relative' } : undefined}
1292
1438
  >
1293
1439
  {isDragging && (
1294
1440
  <div
@@ -1317,7 +1463,7 @@ export default function ChatPanel({
1317
1463
  pointerEvents: 'auto',
1318
1464
  }}
1319
1465
  >
1320
- <div style={{ marginBottom: '16px', color: 'var(--accent)' }}>
1466
+ <div style={{ marginBottom: '16px', color: 'var(--interactive-fg)' }}>
1321
1467
  <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1322
1468
  <rect x="3" y="3" width="18" height="18" rx="2" ry="2" />
1323
1469
  <circle cx="8.5" cy="8.5" r="1.5" />
@@ -1334,9 +1480,9 @@ export default function ChatPanel({
1334
1480
  className="mobile-menu-btn"
1335
1481
  type="button"
1336
1482
  onClick={onToggleMobileSidebar}
1337
- aria-label="Toggle menu"
1483
+ aria-label="Open navigation menu"
1338
1484
  >
1339
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1485
+ <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
1340
1486
  <line x1="3" y1="12" x2="21" y2="12" />
1341
1487
  <line x1="3" y1="6" x2="21" y2="6" />
1342
1488
  <line x1="3" y1="18" x2="21" y2="18" />
@@ -1344,35 +1490,79 @@ export default function ChatPanel({
1344
1490
  </button>
1345
1491
  )}
1346
1492
  <div className="chat-header-title">
1347
- <img src={APP_ICON_PATH} alt="Logo" className="chat-header-logo" />
1348
- <span>Mint Agent</span>
1493
+ {isCliSession ? (
1494
+ <div className="chat-header-breadcrumb">
1495
+ {onBackToCode && (
1496
+ <button
1497
+ type="button"
1498
+ className="chat-header-back-btn"
1499
+ onClick={onBackToCode}
1500
+ title="Back to Code sessions Hub"
1501
+ >
1502
+ <svg
1503
+ width="12"
1504
+ height="12"
1505
+ viewBox="0 0 24 24"
1506
+ fill="none"
1507
+ stroke="currentColor"
1508
+ strokeWidth="2.5"
1509
+ strokeLinecap="round"
1510
+ strokeLinejoin="round"
1511
+ >
1512
+ <path d="M15 18l-6-6 6-6" />
1513
+ </svg>
1514
+ <span>Code</span>
1515
+ </button>
1516
+ )}
1517
+ <span className="chat-header-sep">/</span>
1518
+ <span className="chat-header-session-tag" title={cliSessionId || 'CLI Session'}>
1519
+ <span>
1520
+ {cliSessionId ? (cliSessionId === 'cli' ? 'cli' : `cli::${cliSessionId.replace(/^cli::/, '').slice(0, 7)}`) : 'cli'}
1521
+ </span>
1522
+ </span>
1523
+ </div>
1524
+ ) : (
1525
+ <div className="chat-header-brand-group">
1526
+ <img src={runtimePlatform.appIconPath()} alt="Logo" className="chat-header-logo" />
1527
+ <span
1528
+ className="chat-header-title-text"
1529
+ title={conversationTitle && conversationTitle.trim() && conversationTitle !== 'New chat' ? conversationTitle.trim() : 'Mint Agent'}
1530
+ >
1531
+ {conversationTitle && conversationTitle.trim() && conversationTitle !== 'New chat' ? conversationTitle.trim() : 'Mint Agent'}
1532
+ </span>
1533
+ {projectName && (
1534
+ <span className="chat-header-project-pill" title={`Project: ${workspacePath}`}>
1535
+ <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
1536
+ <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path>
1537
+ </svg>
1538
+ <span>{projectName}</span>
1539
+ </span>
1540
+ )}
1541
+ </div>
1542
+ )}
1349
1543
  </div>
1350
- <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
1544
+ <div className="chat-header-actions">
1351
1545
  {activeArtifact && (
1352
1546
  <button
1353
1547
  type="button"
1354
- className="chat-header-clear-btn"
1548
+ className="chat-header-pill-btn"
1355
1549
  title="Close Live Preview"
1356
1550
  onClick={() => setActiveArtifact(null)}
1357
- style={{
1358
- color: 'var(--accent)',
1359
- background: 'color-mix(in srgb, var(--accent) 12%, transparent)',
1360
- border: '1px solid color-mix(in srgb, var(--accent) 25%, transparent)',
1361
- padding: '2px 8px',
1362
- borderRadius: 'var(--radius-xs, 4px)',
1363
- fontSize: '0.74rem',
1364
- fontWeight: 600,
1365
- cursor: 'pointer',
1366
- display: 'inline-flex',
1367
- alignItems: 'center',
1368
- gap: '4px',
1369
- }}
1370
1551
  >
1371
- <span>Close Live Preview</span>
1552
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
1553
+ <line x1="18" y1="6" x2="6" y2="18"></line>
1554
+ <line x1="6" y1="6" x2="18" y2="18"></line>
1555
+ </svg>
1556
+ <span>Close preview</span>
1372
1557
  </button>
1373
1558
  )}
1374
- <button className="chat-header-clear-btn" title="Clear Messages" onClick={onClearMessages}>
1375
- <svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
1559
+ <button
1560
+ type="button"
1561
+ className="chat-header-action-btn"
1562
+ title="Clear conversation"
1563
+ onClick={onClearMessages}
1564
+ >
1565
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1376
1566
  <polyline points="3 6 5 6 21 6"></polyline>
1377
1567
  <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
1378
1568
  <line x1="10" y1="11" x2="10" y2="17"></line>
@@ -1382,9 +1572,28 @@ export default function ChatPanel({
1382
1572
  </div>
1383
1573
  </div>
1384
1574
  <div className="chat-container" ref={chatContainerRef} onScroll={handleChatScroll}>
1385
- {interactions.map((interaction, index) => (
1575
+ {hasOlder && onLoadOlder && (
1576
+ <button type="button" className="load-older-messages" disabled={loadingOlder}
1577
+ style={{ display: 'block', margin: '0 auto 20px', padding: '7px 14px', borderRadius: 8,
1578
+ border: '1px solid var(--border-color, #3a3a3a)', background: 'var(--surface, #252525)',
1579
+ color: 'var(--text-secondary, #c0c0c0)', cursor: loadingOlder ? 'default' : 'pointer' }}
1580
+ onClick={async () => {
1581
+ const container = chatContainerRef.current
1582
+ const previousHeight = container?.scrollHeight ?? 0
1583
+ setLoadingOlder(true)
1584
+ try {
1585
+ await onLoadOlder()
1586
+ window.requestAnimationFrame(() => {
1587
+ if (container) container.scrollTop += container.scrollHeight - previousHeight
1588
+ })
1589
+ } finally { setLoadingOlder(false) }
1590
+ }}>
1591
+ {loadingOlder ? 'Loading earlier messages…' : 'Load earlier messages'}
1592
+ </button>
1593
+ )}
1594
+ {visibleInteractions.map((interaction, index) => (
1386
1595
  <Fragment key={interaction.id}>
1387
- {index > 0 && shouldShowSessionDivider(interactions[index - 1].createdAt, interaction.createdAt) && (
1596
+ {index > 0 && shouldShowSessionDivider(visibleInteractions[index - 1].createdAt, interaction.createdAt) && (
1388
1597
  <div className="system-event-divider">
1389
1598
  <div className="system-event-line" />
1390
1599
  <div className="system-event-pill">
@@ -1432,23 +1641,29 @@ export default function ChatPanel({
1432
1641
  {renderActiveFileChanges()}
1433
1642
  <div className="message ai-message thinking-message">
1434
1643
  <div className="bubble-wrapper">
1435
- <ThinkingBlock
1436
- blockKey="live"
1437
- thoughts={thoughtsFrom(agentProgress)}
1438
- isLive={true}
1439
- expanded={thinkingExpanded.live ?? true}
1440
- onExpandedChange={onThinkingExpandedChange}
1441
- showEmptyHint={
1442
- agentMode
1443
- && hasAgentToolActivity(agentProgress)
1444
- && thoughtsFrom(agentProgress).length === 0
1445
- && !streamedReply
1446
- }
1447
- />
1644
+ {!agentMode && extendedThoughtsFrom(agentProgress).length > 0 && (
1645
+ <ThinkingBlock
1646
+ blockKey="live-extended"
1647
+ thoughts={extendedThoughtsFrom(agentProgress)}
1648
+ isLive={true}
1649
+ variant="extended"
1650
+ expanded={thinkingExpanded['live-extended'] ?? true}
1651
+ onExpandedChange={onThinkingExpandedChange}
1652
+ />
1653
+ )}
1654
+ {!agentMode && thoughtsFrom(agentProgress).length > 0 && extendedThoughtsFrom(agentProgress).length === 0 && (
1655
+ <ThinkingBlock
1656
+ blockKey="live"
1657
+ thoughts={thoughtsFrom(agentProgress)}
1658
+ isLive={true}
1659
+ expanded={thinkingExpanded.live ?? true}
1660
+ onExpandedChange={onThinkingExpandedChange}
1661
+ />
1662
+ )}
1448
1663
  <div className="message-bubble">
1449
1664
  <span>
1450
- {streamedReply ? (
1451
- renderFormattedMessage(streamedReply)
1665
+ {throttledStreamedReply ? (
1666
+ renderFormattedMessage(throttledStreamedReply, liveWebSources)
1452
1667
  ) : (
1453
1668
  <div style={{ display: 'flex', alignItems: 'center', gap: '8px', color: 'var(--text-soft, #94a3b8)' }}>
1454
1669
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" style={{ display: 'inline-block', flexShrink: 0 }}>
@@ -1483,23 +1698,23 @@ export default function ChatPanel({
1483
1698
  <span className="provider-chip-model">{streamedResponse.model}</span>
1484
1699
  </span>
1485
1700
  {activeFallbackNotice && <span className="provider-fallback-notice">{activeFallbackNotice}</span>}
1486
- {streamedReply && (
1701
+ {throttledStreamedReply && (
1487
1702
  <div className="message-action-buttons" style={{ display: 'flex', alignItems: 'center', gap: '4px', marginLeft: 'auto' }}>
1488
1703
  <button
1489
1704
  type="button"
1490
1705
  className={`msg-action-btn copy-btn ${copiedId === 'live' ? 'is-copied' : ''}`}
1491
- onClick={() => handleCopyMessage('live', streamedReply)}
1706
+ onClick={() => handleCopyMessage('live', throttledStreamedReply)}
1492
1707
  title={copiedId === 'live' ? 'คัดลอกแล้ว (Copied!)' : 'คัดลอกข้อความ (Copy message)'}
1493
1708
  >
1494
1709
  {renderCopyIcon(copiedId === 'live')}
1495
1710
  </button>
1496
1711
  <button
1497
1712
  type="button"
1498
- className={`msg-action-btn tts-btn ${speakingText === streamedReply ? 'is-speaking' : ''}`}
1499
- onClick={() => speak(streamedReply)}
1500
- title={speakingText === streamedReply ? 'Stop reading' : 'Read aloud'}
1713
+ className={`msg-action-btn tts-btn ${speakingText === throttledStreamedReply ? 'is-speaking' : ''}`}
1714
+ onClick={() => speak(throttledStreamedReply)}
1715
+ title={speakingText === throttledStreamedReply ? 'Stop reading' : 'Read aloud'}
1501
1716
  >
1502
- {renderSpeakerIcon(speakingText === streamedReply)}
1717
+ {renderSpeakerIcon(speakingText === throttledStreamedReply)}
1503
1718
  </button>
1504
1719
  </div>
1505
1720
  )}
@@ -1535,41 +1750,62 @@ export default function ChatPanel({
1535
1750
  </div>
1536
1751
 
1537
1752
  <div className={`input-area ${voiceMode ? 'voice-active' : ''}`}>
1538
- {isEmptyChat && <div className="empty-chat-prompt">Mint Agent is ready to work</div>}
1539
- {onSelectWorkspace && (
1540
- <button type="button" className="workspace-select-btn" onClick={onSelectWorkspace}>
1541
- <span aria-hidden="true" style={{ display: 'inline-flex', alignItems: 'center' }}>
1542
- <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round">
1543
- <path d="M3 6h7l2 2h9v10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z"></path>
1544
- </svg>
1753
+ {composerChanges.length > 0 && (
1754
+ <button
1755
+ type="button"
1756
+ className={`composer-change-status ${sending ? 'is-live' : ''}`}
1757
+ onClick={() => openReview(composerChangeLabel, composerChanges)}
1758
+ title="Review recent agent changes"
1759
+ >
1760
+ <span className="composer-change-status-copy">
1761
+ {sending && <span className="composer-change-status-spinner" aria-hidden="true" />}
1762
+ <span>{sending ? `Editing ${composerChanges.length} ${composerChanges.length === 1 ? 'file' : 'files'}…` : composerChangeLabel}</span>
1763
+ </span>
1764
+ <span className="composer-change-status-counts" aria-label={`${composerAdditions} additions and ${composerDeletions} deletions`}>
1765
+ {composerAdditions > 0 && <strong>+{composerAdditions}</strong>}
1766
+ {composerDeletions > 0 && <em>-{composerDeletions}</em>}
1545
1767
  </span>
1546
- <span>{workspaceName}</span>
1547
- <span aria-hidden="true">⌄</span>
1548
1768
  </button>
1549
1769
  )}
1550
- <div className="smart-context-bar">
1551
- <div className="smart-context-label" style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
1552
- <label className="toggle-switch">
1553
- <input type="checkbox" checked={smartContext} onChange={(event) => onSetSmartContext(event.target.checked)} />
1554
- <span className="slider round" />
1555
- </label>
1556
- <span>Smart Context (Auto-Screen)</span>
1770
+ {isEmptyChat && (
1771
+ <div className="empty-chat-prompt-wrap">
1772
+ <div className="empty-chat-prompt">Mint Agent is ready to work</div>
1773
+ {projectName && (
1774
+ <div className="empty-chat-project-badge">
1775
+ <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
1776
+ <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path>
1777
+ </svg>
1778
+ <span>Working in <strong>{projectName}</strong></span>
1779
+ </div>
1780
+ )}
1557
1781
  </div>
1558
- <div className="smart-context-label" style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
1559
- <label className="toggle-switch">
1782
+ )}
1783
+ {onSelectWorkspace && (
1784
+ <div className="project-context-row">
1785
+ <WorkspaceSelector
1786
+ currentPath={workspacePath || ''}
1787
+ recentPaths={recentWorkspacePaths}
1788
+ onSelectWorkspace={onSelectWorkspace}
1789
+ />
1790
+ {workspacePath && <GitBranchSelector workspacePath={workspacePath} disabled={sending} onBranchChanged={onWorkspaceChanged} />}
1791
+ </div>
1792
+ )}
1793
+ <div className="smart-context-bar">
1794
+ <label className={`smart-context-option ${agentMode ? 'is-active' : ''}`}>
1795
+ <span className="toggle-switch">
1560
1796
  <input type="checkbox" checked={agentMode} onChange={(event) => onSetAgentMode(event.target.checked)} />
1561
1797
  <span className="slider round" />
1562
- </label>
1563
- <span>Agent Mode</span>
1564
- </div>
1798
+ </span>
1799
+ <span className="smart-context-copy"><span className="smart-context-title">Agent mode</span></span>
1800
+ </label>
1565
1801
  {onSetPlanMode && (
1566
- <div className="smart-context-label" style={{ display: 'flex', alignItems: 'center', gap: '8px' }} title="Investigate read-only and require plan approval before editing files or running commands">
1567
- <label className="toggle-switch">
1802
+ <label className={`smart-context-option ${planMode ? 'is-active' : ''}`} title="Investigate read-only and require plan approval before editing files or running commands">
1803
+ <span className="toggle-switch">
1568
1804
  <input type="checkbox" checked={Boolean(planMode)} onChange={(event) => onSetPlanMode(event.target.checked)} />
1569
1805
  <span className="slider round" />
1570
- </label>
1571
- <span>Plan Mode</span>
1572
- </div>
1806
+ </span>
1807
+ <span className="smart-context-copy"><span className="smart-context-title">Plan mode</span></span>
1808
+ </label>
1573
1809
  )}
1574
1810
  </div>
1575
1811
  {voiceMode && (
@@ -1779,7 +2015,10 @@ export default function ChatPanel({
1779
2015
  <input id="video-file-input" type="file" accept="video/mp4,video/webm,video/quicktime,video/x-matroska" onChange={onSelectVideo} style={{ display: 'none' }} />
1780
2016
  <input id="document-file-input" type="file" accept={SUPPORTED_DOCUMENT_ACCEPT} onChange={onSelectDocument} style={{ display: 'none' }} />
1781
2017
  <button id="screen-capture-btn" type="button" onClick={onCaptureScreen} aria-label="Capture screen">
1782
- <span className="screen-capture-eye" aria-hidden="true" />
2018
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
2019
+ <rect x="2" y="3" width="20" height="15" rx="2" />
2020
+ <path d="M8 22h8M12 18v4M7 10h10M12 5v10" />
2021
+ </svg>
1783
2022
  </button>
1784
2023
  <ModelSelectorPopover
1785
2024
  activeProvider={status?.activeProvider ?? ''}
@@ -1795,6 +2034,7 @@ export default function ChatPanel({
1795
2034
  onSetModel(model)
1796
2035
  }
1797
2036
  }}
2037
+ onUpdateSettings={onUpdateSettings}
1798
2038
  />
1799
2039
  <button
1800
2040
  id="mic-btn"
@@ -1941,19 +2181,13 @@ export default function ChatPanel({
1941
2181
  return (
1942
2182
  <div
1943
2183
  ref={wrapperRef}
1944
- className={`chat-panel-split-wrapper ${activeArtifact ? 'has-preview' : 'no-preview'}`}
2184
+ className={`chat-panel-split-wrapper ${activeArtifact || reviewPage ? 'has-preview' : 'no-preview'}`}
1945
2185
  style={{
1946
- width: '100%',
1947
- height: '100%',
1948
- overflow: 'hidden',
1949
- position: 'relative',
1950
- gridColumn: '1 / -1',
1951
- zIndex: 1,
1952
2186
  '--preview-width': `${(splitRatio * 100).toFixed(2)}%`,
1953
2187
  } as React.CSSProperties}
1954
2188
  >
1955
2189
  {sectionContent}
1956
- {activeArtifact && (
2190
+ {(activeArtifact || reviewPage) && (
1957
2191
  <>
1958
2192
  <div
1959
2193
  className="preview-split-resizer"
@@ -1963,11 +2197,16 @@ export default function ChatPanel({
1963
2197
  >
1964
2198
  <div className="preview-split-resizer-grip" />
1965
2199
  </div>
1966
- <ArtifactPreviewPanel
1967
- artifact={activeArtifact}
1968
- onClose={() => setActiveArtifact(null)}
1969
- workspacePath={workspacePath}
1970
- />
2200
+ {reviewPage ? (
2201
+ <CodeReviewPage
2202
+ title={reviewPage.title}
2203
+ changes={reviewPage.changes}
2204
+ workspacePath={workspacePath}
2205
+ onBack={() => setReviewPage(null)}
2206
+ />
2207
+ ) : activeArtifact ? (
2208
+ <ArtifactPreviewPanel artifact={activeArtifact} onClose={() => setActiveArtifact(null)} workspacePath={workspacePath} />
2209
+ ) : null}
1971
2210
  </>
1972
2211
  )}
1973
2212
  {rewindModalState.isOpen && (