@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
@@ -222,37 +222,9 @@ pub(super) fn print_table_block(table_lines: &[String], is_first: &mut bool) {
222
222
  }
223
223
  }
224
224
 
225
- pub(super) fn should_show_verification(verification: &str) -> bool {
226
- let normalized = verification.trim().to_ascii_lowercase();
227
- if normalized.is_empty() {
228
- return false;
229
- }
230
- if normalized.starts_with("information retrieved from web search")
231
- || normalized.starts_with("successfully ran background command")
232
- || normalized.starts_with("opened ")
233
- || normalized.contains("background command to open")
234
- || normalized.contains("web search results")
235
- {
236
- return false;
237
- }
238
- !matches!(
239
- normalized.as_str(),
240
- "not run"
241
- | "not run."
242
- | "no checks run"
243
- | "no checks run."
244
- | "no technical task requested"
245
- | "no technical task requested."
246
- | "no technical task requested, just a greeting."
247
- | "not required"
248
- | "not required."
249
- | "none"
250
- | "n/a"
251
- )
252
- }
253
-
254
225
  #[derive(Debug, Default)]
255
226
  pub(super) struct LiveStatus {
227
+ pub(super) tui: Option<crate::interactive::TuiHandle>,
256
228
  pub(super) thinking: Option<String>,
257
229
  /// Context-window usage (0-100) as of the last completed step —
258
230
  /// mirrored here (not just built into `thinking`'s label text) so the
@@ -305,6 +277,9 @@ pub(super) struct LiveStatus {
305
277
  pub(super) committed_activities: usize,
306
278
  pub(super) committed_tasks: usize,
307
279
  pub(super) spinner_tick: usize,
280
+ /// When the currently running tool began executing — used to animate an
281
+ /// inline spinner and elapsed timer directly on the active tool line.
282
+ pub(super) active_tool_started: Option<Instant>,
308
283
  /// Sources collected from web_search ToolEnd results (title, url)
309
284
  pub(super) web_sources: Vec<(String, String)>,
310
285
  pub(super) inline_tui: InlineTui,
@@ -562,13 +537,6 @@ pub(super) fn strip_ansi_escapes(s: &str) -> String {
562
537
  result
563
538
  }
564
539
 
565
- pub(super) fn is_thai_combining(c: char) -> bool {
566
- matches!(c,
567
- '\u{0e31}' | '\u{0e34}'..='\u{0e37}' | '\u{0e38}'..='\u{0e39}' |
568
- '\u{0e47}'..='\u{0e4e}'
569
- )
570
- }
571
-
572
540
  pub(super) fn apply_wave_effect(text: &str, tick: usize) -> String {
573
541
  let (label, metadata) = if let Some(idx) = text.rfind(" • Esc to interrupt)") {
574
542
  if let Some(open_paren_idx) = text[..idx].rfind('(') {
@@ -606,33 +574,10 @@ pub(super) fn apply_wave_effect(text: &str, tick: usize) -> String {
606
574
  let x = (i as f32 * 0.4) - phase;
607
575
  let t = (x.sin() + 1.0) / 2.0; // Oscillates in [0.0, 1.0]
608
576
 
609
- // Stop colors: Dim Gray (70, 70, 70) -> Mint Green (105, 230, 166) -> Cyan (78, 201, 216)
610
- let (r, g, b) = if t < 0.3 {
611
- let local_t = t / 0.3;
612
- let r = 70.0 + (105.0 - 70.0) * local_t;
613
- let g = 70.0 + (230.0 - 70.0) * local_t;
614
- let b = 70.0 + (166.0 - 70.0) * local_t;
615
- (r, g, b)
616
- } else if t < 0.7 {
617
- let local_t = (t - 0.3) / 0.4;
618
- let r = 105.0 + (78.0 - 105.0) * local_t;
619
- let g = 230.0 + (201.0 - 230.0) * local_t;
620
- let b = 166.0 + (216.0 - 166.0) * local_t;
621
- (r, g, b)
622
- } else {
623
- let local_t = (t - 0.7) / 0.3;
624
- let r = 78.0 + (70.0 - 78.0) * local_t;
625
- let g = 201.0 + (70.0 - 201.0) * local_t;
626
- let b = 216.0 + (70.0 - 216.0) * local_t;
627
- (r, g, b)
628
- };
629
-
577
+ let emphasis = if t > 0.72 { BOLD } else { "" };
630
578
  animated_label.push_str(&format!(
631
- "\x1b[1m\x1b[38;2;{};{};{}m{}\x1b[0m",
632
- r.round() as u8,
633
- g.round() as u8,
634
- b.round() as u8,
635
- c
579
+ "{emphasis}{}{c}{RESET}",
580
+ crate::terminal_theme::ANSI_ACCENT
636
581
  ));
637
582
  }
638
583
 
@@ -715,7 +660,10 @@ pub(super) fn compose_queue_box(
715
660
  (lines, cursor_x, cursor_y)
716
661
  }
717
662
 
718
- pub(super) fn render_live_status(status: &mut LiveStatus) {
663
+ /// Renders the live viewport and reports whether a terminal was available to
664
+ /// draw it. Callers use the result to fall back to plain output when Mint is
665
+ /// run without an interactive terminal.
666
+ pub(super) fn render_live_status(status: &mut LiveStatus) -> bool {
719
667
  let mut lines = Vec::new();
720
668
  let explored_start = status.committed_explored.min(status.explored.len());
721
669
  let activities_start = status.committed_activities.min(status.activities.len());
@@ -735,6 +683,12 @@ pub(super) fn render_live_status(status: &mut LiveStatus) {
735
683
  &status.explored[explored_start..],
736
684
  true,
737
685
  tick,
686
+ status.active_tool_started,
687
+ // The full-screen TUI shows only the last eight live rows. A shell
688
+ // output preview can otherwise push the activity header and command
689
+ // labels out of view while the model is composing its next answer.
690
+ // Keep the preview in `status.tasks` for the committed transcript.
691
+ status.tui.is_none(),
738
692
  ));
739
693
  // Built here (not inline below) so both destinations for it — the old
740
694
  // trailing-line spot in `lines`, and the queue box's own pinned row —
@@ -831,18 +785,23 @@ pub(super) fn render_live_status(status: &mut LiveStatus) {
831
785
  }
832
786
  }
833
787
 
788
+ if let Some(tui) = &status.tui {
789
+ tui.set_status(lines.iter().map(|line| strip_ansi_escapes(line)).collect());
790
+ return true;
791
+ }
792
+
834
793
  if lines.is_empty() && box_lines.is_empty() {
835
794
  status.inline_tui.teardown();
836
- return;
795
+ return false;
837
796
  }
838
797
 
839
798
  let Ok(terminal) = status.inline_tui.ensure() else {
840
- return;
799
+ return false;
841
800
  };
842
801
  // `draw()` itself only queries the cursor position on the rare path
843
802
  // where it detects the terminal window was actually resized since the
844
803
  // last frame — bracket it too, defensively, for that case.
845
- let _ = with_raw_mode_for_cursor_query(|| {
804
+ with_raw_mode_for_cursor_query(|| {
846
805
  terminal.draw(|frame| {
847
806
  let area = frame.area();
848
807
  // The box (the "Ask anything..." input) claims its own rows
@@ -856,7 +815,7 @@ pub(super) fn render_live_status(status: &mut LiveStatus) {
856
815
  let box_height = (box_lines.len() as u16).min(area.height);
857
816
  let available_for_status = area.height.saturating_sub(box_height);
858
817
 
859
- let mut status_line_count: u16 = 0;
818
+ let mut status_height: u16 = 0;
860
819
  let mut status_paragraph = None;
861
820
  if !lines.is_empty()
862
821
  && let Ok(status_text) = lines.join("\n").into_text()
@@ -874,17 +833,18 @@ pub(super) fn render_live_status(status: &mut LiveStatus) {
874
833
  // bottom of the frame. (`Paragraph::line_count` would do this
875
834
  // exactly, but it's gated behind an unstable ratatui feature.)
876
835
  let wrap_width = area.width.max(1);
877
- status_line_count = status_text
836
+ let status_line_count: u16 = status_text
878
837
  .lines
879
838
  .iter()
880
839
  .map(|line| (line.width().max(1) as u16).div_ceil(wrap_width))
881
840
  .sum();
841
+ status_height = status_line_count.min(available_for_status);
882
842
  status_paragraph = Some(
883
843
  ratatui::widgets::Paragraph::new(status_text)
884
- .wrap(ratatui::widgets::Wrap { trim: false }),
844
+ .wrap(ratatui::widgets::Wrap { trim: false })
845
+ .scroll((status_line_count.saturating_sub(status_height), 0)),
885
846
  );
886
847
  }
887
- let status_height = status_line_count.min(available_for_status);
888
848
  let status_area = ratatui::layout::Rect {
889
849
  height: status_height,
890
850
  ..area
@@ -909,13 +869,24 @@ pub(super) fn render_live_status(status: &mut LiveStatus) {
909
869
  ));
910
870
  }
911
871
  })
912
- });
872
+ })
873
+ .is_ok()
913
874
  }
914
875
 
915
876
  /// Freezes any in-flight activity into scrollback. Returns whether it
916
877
  /// actually committed anything — callers that print their own leading blank
917
878
  /// line right after (e.g. the final answer) use this to skip it when this
918
879
  /// already ended on one, instead of stacking two.
880
+ pub(super) fn commit_activity_snapshot_if_idle(
881
+ status: &mut LiveStatus,
882
+ active_tools: usize,
883
+ ) -> bool {
884
+ if active_tools > 0 {
885
+ return false;
886
+ }
887
+ commit_activity_snapshot(status)
888
+ }
889
+
919
890
  pub(super) fn commit_activity_snapshot(status: &mut LiveStatus) -> bool {
920
891
  let explored_start = status.committed_explored.min(status.explored.len());
921
892
  let activities_start = status.committed_activities.min(status.activities.len());
@@ -927,16 +898,16 @@ pub(super) fn commit_activity_snapshot(status: &mut LiveStatus) -> bool {
927
898
  &status.explored[explored_start..],
928
899
  false,
929
900
  0,
901
+ None,
902
+ true,
930
903
  );
931
904
  if lines.is_empty() {
932
905
  return false;
933
906
  }
934
907
 
935
908
  let (tw, _) = markdown::terminal_size_or_default();
936
- let width = tw as usize;
937
- lines.push(String::new());
938
- lines.push(format!("{DIM}{}{RESET}", "─".repeat(width)));
939
- lines.push(String::new());
909
+ let width = (tw as usize).saturating_sub(8).max(40);
910
+ lines.push(format!("{DIM} {}{RESET}", "─".repeat(width)));
940
911
  insert_permanent_lines(status, &lines);
941
912
 
942
913
  status.committed_explored = status.explored.len();
@@ -945,19 +916,153 @@ pub(super) fn commit_activity_snapshot(status: &mut LiveStatus) -> bool {
945
916
  true
946
917
  }
947
918
 
948
- pub(super) fn print_timeline_note(status: &mut LiveStatus, thought: &str) {
919
+ #[cfg(test)]
920
+ mod concurrent_activity_tests {
921
+ use super::*;
922
+
923
+ #[test]
924
+ fn unrelated_thought_keeps_in_flight_shell_activity_live() {
925
+ let mut status = LiveStatus::default();
926
+ status.tasks.push(TaskEntry {
927
+ label: "[run_shell] Running command: `sleep 1`...".to_owned(),
928
+ output: Vec::new(),
929
+ });
930
+
931
+ assert!(!commit_activity_snapshot_if_idle(&mut status, 1));
932
+ assert_eq!(status.committed_tasks, 0);
933
+ let live_lines = activity_block_lines(
934
+ &status.tasks[status.committed_tasks..],
935
+ &[],
936
+ &[],
937
+ true,
938
+ 0,
939
+ Some(Instant::now()),
940
+ true,
941
+ );
942
+ assert!(
943
+ live_lines
944
+ .iter()
945
+ .any(|line| line.contains("Running 1 shell command"))
946
+ );
947
+ assert!(live_lines.iter().any(|line| line.contains("sleep 1")));
948
+ }
949
+ }
950
+
951
+ #[cfg(test)]
952
+ mod compact_tui_status_tests {
953
+ use super::*;
954
+
955
+ #[test]
956
+ fn completed_shell_output_does_not_push_command_labels_out_of_live_view() {
957
+ let tasks = vec![
958
+ TaskEntry {
959
+ label: "[run_shell] Running command: `time sleep 10`...".into(),
960
+ output: Vec::new(),
961
+ },
962
+ TaskEntry {
963
+ label: "Finished command: `time sleep 10`".into(),
964
+ output: vec![
965
+ "stdout:".into(),
966
+ "stderr:".into(),
967
+ "real 0m10.002s".into(),
968
+ "user 0m0.002s".into(),
969
+ "sys 0m0.002s".into(),
970
+ ],
971
+ },
972
+ ];
973
+ let mut lines = activity_block_lines(&tasks, &[], &[], true, 0, None, false);
974
+ lines.push(" Herding...".into());
975
+ let visible = &lines[lines.len().saturating_sub(8)..];
976
+ assert!(
977
+ visible
978
+ .iter()
979
+ .any(|line| line.contains("Running 1 shell command"))
980
+ );
981
+ assert!(visible.iter().any(|line| line.contains("[run_shell]")));
982
+ assert!(visible.iter().any(|line| line.contains("Finished command")));
983
+ assert!(!visible.iter().any(|line| line.contains("real 0m10.002s")));
984
+ let committed = activity_block_lines(&tasks, &[], &[], false, 0, None, true);
985
+ assert!(committed.iter().any(|line| line.contains("real 0m10.002s")));
986
+ }
987
+ }
988
+
989
+ pub(super) fn is_internal_cot(text: &str) -> bool {
990
+ mint_core::orchestration::is_internal_cot(text)
991
+ }
992
+
993
+ pub(super) fn print_timeline_note(
994
+ status: &mut LiveStatus,
995
+ thought: &str,
996
+ elapsed: Duration,
997
+ stream_id: Option<&str>,
998
+ ) {
949
999
  let thought = thought.trim();
950
1000
  if thought.is_empty() {
951
1001
  return;
952
1002
  }
953
- let (tw, _) = markdown::terminal_size_or_default();
954
- let width = tw as usize;
955
- let options = textwrap::Options::new(width)
956
- .initial_indent(" • ")
957
- .subsequent_indent(" ")
958
- .break_words(true);
959
- let wrapped = textwrap::fill(thought, &options);
960
- insert_permanent_lines(status, &[wrapped]);
1003
+ let elapsed_str = crate::interactive::format_thought_elapsed(elapsed);
1004
+ crate::interactive::finish_thought(stream_id, thought, &elapsed_str);
1005
+
1006
+ if is_internal_cot(thought) {
1007
+ let summary = format!(
1008
+ "{muted} • Thought for {elapsed_str}{reset} {muted}(Ctrl+T to view){reset}",
1009
+ muted = crate::terminal_theme::ANSI_MUTED,
1010
+ reset = crate::terminal_theme::ANSI_RESET
1011
+ );
1012
+ insert_permanent_lines(status, &[summary]);
1013
+ } else {
1014
+ let clean_note = thought
1015
+ .strip_prefix("•")
1016
+ .or_else(|| thought.strip_prefix("-"))
1017
+ .unwrap_or(thought)
1018
+ .trim();
1019
+ let clean_note = strip_intermediate_greeting(clean_note);
1020
+ let (tw, _) = markdown::terminal_size_or_default();
1021
+ let width = (tw as usize).saturating_sub(2).max(20);
1022
+ let options = textwrap::Options::new(width)
1023
+ .initial_indent(" ")
1024
+ .subsequent_indent(" ")
1025
+ .break_words(true);
1026
+ let wrapped = textwrap::fill(clean_note, &options);
1027
+ let formatted = format!("{WHITE}{wrapped}{RESET}");
1028
+ insert_permanent_lines(status, &[formatted]);
1029
+ }
1030
+ }
1031
+
1032
+ fn strip_intermediate_greeting(text: &str) -> &str {
1033
+ let mut s = text.trim();
1034
+ for prefix in &[
1035
+ "สวัสดีค่ะ",
1036
+ "สวัสดีครับ",
1037
+ "หวัดดีค่ะ",
1038
+ "หวัดดีครับ",
1039
+ "สวัสดี",
1040
+ "Hello",
1041
+ "Hi",
1042
+ "Hey",
1043
+ ] {
1044
+ if let Some(rest) = s.strip_prefix(prefix) {
1045
+ s = rest.trim_start();
1046
+ break;
1047
+ }
1048
+ }
1049
+ if let Some(rest) = s.strip_prefix("พี่") {
1050
+ if let Some(space_idx) = rest.find(' ') {
1051
+ s = rest[space_idx..].trim_start();
1052
+ }
1053
+ } else if let Some(rest) = s.strip_prefix("คุณ") {
1054
+ if let Some(space_idx) = rest.find(' ') {
1055
+ s = rest[space_idx..].trim_start();
1056
+ }
1057
+ }
1058
+ for emoji in &["🌿", "🍃", "✨", "🌱"] {
1059
+ if let Some(rest) = s.strip_prefix(emoji) {
1060
+ s = rest.trim_start();
1061
+ }
1062
+ }
1063
+ let trimmed =
1064
+ s.trim_start_matches(|c: char| c == ',' || c == '-' || c == '—' || c == ' ' || c == '•');
1065
+ if trimmed.is_empty() { text } else { trimmed }
961
1066
  }
962
1067
 
963
1068
  /// Inserts already ANSI-formatted `lines` as permanent content above the
@@ -979,6 +1084,10 @@ pub(super) fn print_timeline_note(status: &mut LiveStatus, thought: &str) {
979
1084
  /// Falls back to plain `println!` if no inline terminal is currently live
980
1085
  /// (e.g. committing before anything has rendered yet this turn).
981
1086
  pub(super) fn insert_permanent_lines(status: &mut LiveStatus, lines: &[String]) {
1087
+ if let Some(tui) = &status.tui {
1088
+ tui.push_notice(lines.join("\n"));
1089
+ return;
1090
+ }
982
1091
  let Some(terminal) = status.inline_tui.terminal.as_mut() else {
983
1092
  // Defensive, same reasoning as `approve_cb`/`on_chunk`: this is a
984
1093
  // plain `println!`, so it needs cooked mode regardless of whether
@@ -991,39 +1100,31 @@ pub(super) fn insert_permanent_lines(status: &mut LiveStatus, lines: &[String])
991
1100
  return;
992
1101
  };
993
1102
 
994
- let (tw, _) = markdown::terminal_size_or_default();
995
- let width = tw as usize;
996
- let mut height: u16 = 0;
997
- for line in lines {
998
- let stripped = strip_ansi_escapes(line);
999
- let line_len = stripped.chars().filter(|&c| !is_thai_combining(c)).count();
1000
- let physical_lines = if width > 0 {
1001
- line_len.div_ceil(width)
1002
- } else {
1003
- 1
1004
- }
1005
- .max(1);
1006
- height = height.saturating_add(physical_lines as u16);
1007
- }
1008
-
1009
1103
  let Ok(text) = lines.join("\n").into_text() else {
1010
1104
  return;
1011
1105
  };
1106
+ let (width, _) = markdown::terminal_size_or_default();
1107
+ let height = wrapped_text_height(&text, width);
1012
1108
  let _ = terminal.insert_before(height, |buf| {
1013
1109
  use ratatui::widgets::Widget as _;
1014
- // `height` above is computed assuming lines longer than the
1015
- // terminal width wrap onto extra rows; without `.wrap(...)` here
1016
- // the `Paragraph` instead clips each source line to a single row,
1017
- // so a long committed line (e.g. a full shell command) reserved
1018
- // more rows than it painted — leaving stray blank rows behind in
1019
- // the scrollback. Wrapping keeps what's actually drawn in sync
1020
- // with what was reserved.
1110
+ // Measure and render with the same Paragraph/Wrap implementation.
1111
+ // Counting Rust chars here under-reserved rows for wide Unicode,
1112
+ // emoji, ANSI-styled spans, and word-boundary wrapping, clipping the
1113
+ // tail of otherwise complete assistant responses in scrollback.
1021
1114
  ratatui::widgets::Paragraph::new(text)
1022
1115
  .wrap(ratatui::widgets::Wrap { trim: false })
1023
1116
  .render(buf.area, buf);
1024
1117
  });
1025
1118
  }
1026
1119
 
1120
+ fn wrapped_text_height(text: &ratatui::text::Text<'_>, width: u16) -> u16 {
1121
+ ratatui::widgets::Paragraph::new(text.clone())
1122
+ .wrap(ratatui::widgets::Wrap { trim: false })
1123
+ .line_count(width)
1124
+ .max(1)
1125
+ .min(u16::MAX as usize) as u16
1126
+ }
1127
+
1027
1128
  /// Tears down the shared inline `ratatui` terminal (if one is currently
1028
1129
  /// live), so whatever prints next — an approval card, a committed activity
1029
1130
  /// snapshot, the final AI answer — starts from a clean, un-managed cursor
@@ -1033,6 +1134,10 @@ pub(super) fn insert_permanent_lines(status: &mut LiveStatus, lines: &[String])
1033
1134
  /// `render_live_status` call reconstructs it fresh, re-querying the
1034
1135
  /// terminal for where the cursor actually is now.
1035
1136
  pub(super) fn clear_live_status(status: &mut LiveStatus) {
1137
+ if let Some(tui) = &status.tui {
1138
+ tui.clear_status();
1139
+ return;
1140
+ }
1036
1141
  if status.inline_tui.terminal.is_none() {
1037
1142
  clear_working_status();
1038
1143
  return;
@@ -1092,7 +1197,46 @@ pub(super) fn activity_summary_line(
1092
1197
  let web_count = activities.len();
1093
1198
  let shell_count = tasks
1094
1199
  .iter()
1095
- .filter(|t| t.label.starts_with("[run_shell]"))
1200
+ .filter(|t| {
1201
+ t.label.starts_with("[run_shell]")
1202
+ || t.label.starts_with("[shell_output]")
1203
+ || t.label.starts_with("[kill_shell]")
1204
+ })
1205
+ .count();
1206
+ let edit_count = tasks
1207
+ .iter()
1208
+ .filter(|t| {
1209
+ t.label.starts_with("[write_file]")
1210
+ || t.label.starts_with("[apply_patch]")
1211
+ || t.label.starts_with("[note_write]")
1212
+ })
1213
+ .count();
1214
+ let git_count = tasks
1215
+ .iter()
1216
+ .filter(|t| t.label.starts_with("[git_"))
1217
+ .count();
1218
+ let subagent_count = tasks
1219
+ .iter()
1220
+ .filter(|t| {
1221
+ t.label.contains("[dispatch_subagent]")
1222
+ || t.label.contains("Subagent dispatched")
1223
+ || t.label.contains("subagent")
1224
+ })
1225
+ .count();
1226
+ let other_count = tasks
1227
+ .iter()
1228
+ .filter(|t| {
1229
+ !t.label.starts_with("[run_shell]")
1230
+ && !t.label.starts_with("[shell_output]")
1231
+ && !t.label.starts_with("[kill_shell]")
1232
+ && !t.label.starts_with("[write_file]")
1233
+ && !t.label.starts_with("[apply_patch]")
1234
+ && !t.label.starts_with("[note_write]")
1235
+ && !t.label.starts_with("[git_")
1236
+ && !t.label.contains("[dispatch_subagent]")
1237
+ && !t.label.contains("Subagent dispatched")
1238
+ && !t.label.contains("subagent")
1239
+ })
1096
1240
  .count();
1097
1241
 
1098
1242
  let mut parts: Vec<String> = Vec::new();
@@ -1108,6 +1252,12 @@ pub(super) fn activity_summary_line(
1108
1252
  if file_count == 1 { "" } else { "s" }
1109
1253
  ));
1110
1254
  }
1255
+ if edit_count > 0 {
1256
+ parts.push(format!(
1257
+ "editing {edit_count} file{}",
1258
+ if edit_count == 1 { "" } else { "s" }
1259
+ ));
1260
+ }
1111
1261
  if dir_count > 0 {
1112
1262
  parts.push(format!(
1113
1263
  "listing {dir_count} director{}",
@@ -1132,8 +1282,33 @@ pub(super) fn activity_summary_line(
1132
1282
  if shell_count == 1 { "" } else { "s" }
1133
1283
  ));
1134
1284
  }
1285
+ if git_count > 0 {
1286
+ parts.push(format!(
1287
+ "checking repository {git_count} time{}",
1288
+ if git_count == 1 { "" } else { "s" }
1289
+ ));
1290
+ }
1291
+ if subagent_count > 0 {
1292
+ parts.push(format!(
1293
+ "dispatching {subagent_count} subagent{}",
1294
+ if subagent_count == 1 { "" } else { "s" }
1295
+ ));
1296
+ }
1297
+ if other_count > 0 {
1298
+ parts.push(format!(
1299
+ "running {other_count} tool{}",
1300
+ if other_count == 1 { "" } else { "s" }
1301
+ ));
1302
+ }
1135
1303
 
1136
1304
  if parts.is_empty() {
1305
+ let total = tasks.len() + activities.len() + explored.len();
1306
+ if total > 0 {
1307
+ return Some(format!(
1308
+ "Running {total} tool{}…",
1309
+ if total == 1 { "" } else { "s" }
1310
+ ));
1311
+ }
1137
1312
  return None;
1138
1313
  }
1139
1314
  let sentence = parts.join(", ");
@@ -1154,20 +1329,68 @@ pub(super) fn activity_block_lines(
1154
1329
  explored: &[ExploredAction],
1155
1330
  animate: bool,
1156
1331
  tick: usize,
1332
+ active_tool_started: Option<Instant>,
1333
+ // Whether to render stored command-output preview lines.
1334
+ include_output: bool,
1157
1335
  ) -> Vec<String> {
1158
1336
  if tasks.is_empty() && activities.is_empty() && explored.is_empty() {
1159
1337
  return Vec::new();
1160
1338
  }
1161
1339
  let char_str = bullet_char(animate, tick);
1162
- let header_text =
1163
- activity_summary_line(tasks, activities, explored).unwrap_or_else(|| "activity".into());
1340
+ let header_text = activity_summary_line(tasks, activities, explored)
1341
+ .unwrap_or_else(|| "Running tools…".into());
1164
1342
  let mut lines = vec![format!(" {BLUE}{char_str}{RESET} {header_text}")];
1165
- lines.extend(tasks_lines(tasks));
1166
- lines.extend(activities_lines(activities));
1167
- lines.extend(explored_lines(explored));
1343
+
1344
+ // Collect all items with their output lines
1345
+ let mut all_items: Vec<(String, Vec<String>)> = Vec::new();
1346
+ for task in tasks.iter().take(24) {
1347
+ all_items.push((task.label.clone(), task.output.clone()));
1348
+ }
1349
+ for act in activities.iter().take(24) {
1350
+ all_items.push((act.clone(), Vec::new()));
1351
+ }
1352
+ let grouped = grouped_explored_actions(explored);
1353
+ for action in grouped.into_iter().take(24) {
1354
+ all_items.push((action, Vec::new()));
1355
+ }
1356
+
1357
+ let total_items = all_items.len();
1358
+ const SPINNER_FRAMES: &[&str] = &["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
1359
+ let spinner = SPINNER_FRAMES[tick % SPINNER_FRAMES.len()];
1360
+
1361
+ for (idx, (label, output)) in all_items.into_iter().enumerate() {
1362
+ let is_active = animate && active_tool_started.is_some() && idx == total_items - 1;
1363
+ let prefix = if idx == 0 {
1364
+ format!("{DIM} └{RESET}")
1365
+ } else {
1366
+ " ".to_string()
1367
+ };
1368
+
1369
+ if is_active {
1370
+ let elapsed_secs = active_tool_started.unwrap().elapsed().as_secs_f64();
1371
+ let timer_suffix = format!(" ({:.1}s)", elapsed_secs);
1372
+ lines.push(format!(
1373
+ "{prefix} {CYAN}{spinner}{RESET} {WHITE}{label}{RESET}{DIM}{timer_suffix}{RESET}"
1374
+ ));
1375
+ } else {
1376
+ lines.push(format!("{prefix} {MINT}✓{RESET} {WHITE}{label}{RESET}"));
1377
+ }
1378
+
1379
+ if include_output {
1380
+ for out_line in &output {
1381
+ lines.push(format!("{DIM} │ {}{RESET}", out_line));
1382
+ }
1383
+ }
1384
+ }
1385
+
1386
+ let raw_total = tasks.len() + activities.len() + explored.len();
1387
+ if raw_total > 24 {
1388
+ lines.push(format!("{DIM} ... {} more{RESET}", raw_total - 24));
1389
+ }
1168
1390
  lines
1169
1391
  }
1170
1392
 
1393
+ #[allow(dead_code)]
1171
1394
  pub(super) fn explored_lines(actions: &[ExploredAction]) -> Vec<String> {
1172
1395
  if actions.is_empty() {
1173
1396
  return Vec::new();
@@ -1178,8 +1401,12 @@ pub(super) fn explored_lines(actions: &[ExploredAction]) -> Vec<String> {
1178
1401
  .take(24)
1179
1402
  .enumerate()
1180
1403
  .map(|(index, action)| {
1181
- let prefix = if index == 0 { " └" } else { " " };
1182
- format!("{DIM}{prefix} {action}{RESET}")
1404
+ if index == 0 {
1405
+ // └ connector in DIM, tool text in WHITE (plain white)
1406
+ format!("{DIM} └{RESET} {WHITE}{action}{RESET}")
1407
+ } else {
1408
+ format!(" {WHITE}{action}{RESET}")
1409
+ }
1183
1410
  })
1184
1411
  .collect();
1185
1412
  if grouped.len() > 24 {
@@ -1325,6 +1552,7 @@ pub(super) fn truncate_line(line: &str, max_chars: usize) -> String {
1325
1552
  format!("{head}…")
1326
1553
  }
1327
1554
 
1555
+ #[allow(dead_code)]
1328
1556
  pub(super) fn activities_lines(activities: &[String]) -> Vec<String> {
1329
1557
  if activities.is_empty() {
1330
1558
  return Vec::new();
@@ -1334,8 +1562,12 @@ pub(super) fn activities_lines(activities: &[String]) -> Vec<String> {
1334
1562
  .take(24)
1335
1563
  .enumerate()
1336
1564
  .map(|(index, act)| {
1337
- let prefix = if index == 0 { " └" } else { " " };
1338
- format!("{DIM}{prefix} {act}{RESET}")
1565
+ if index == 0 {
1566
+ // └ connector in DIM, activity text in WHITE (plain white)
1567
+ format!("{DIM} └{RESET} {WHITE}{act}{RESET}")
1568
+ } else {
1569
+ format!(" {WHITE}{act}{RESET}")
1570
+ }
1339
1571
  })
1340
1572
  .collect();
1341
1573
  if activities.len() > 24 {
@@ -1396,14 +1628,19 @@ pub(super) fn plan_lines(steps: &[String], animate: bool, tick: usize) -> Vec<St
1396
1628
  lines
1397
1629
  }
1398
1630
 
1631
+ #[allow(dead_code)]
1399
1632
  pub(super) fn tasks_lines(tasks: &[TaskEntry]) -> Vec<String> {
1400
1633
  if tasks.is_empty() {
1401
1634
  return Vec::new();
1402
1635
  }
1403
1636
  let mut lines = Vec::new();
1404
1637
  for (index, task) in tasks.iter().take(24).enumerate() {
1405
- let prefix = if index == 0 { " └" } else { " " };
1406
- lines.push(format!("{DIM}{prefix} {}{RESET}", task.label));
1638
+ if index == 0 {
1639
+ // └ connector in DIM, task label in WHITE (plain white)
1640
+ lines.push(format!("{DIM} └{RESET} {WHITE}{}{RESET}", task.label));
1641
+ } else {
1642
+ lines.push(format!(" {WHITE}{}{RESET}", task.label));
1643
+ }
1407
1644
  for out_line in &task.output {
1408
1645
  lines.push(format!("{DIM} │ {}{RESET}", out_line));
1409
1646
  }
@@ -1452,6 +1689,18 @@ mod format_token_count_tests {
1452
1689
  }
1453
1690
  }
1454
1691
 
1692
+ #[cfg(test)]
1693
+ mod scrollback_layout_tests {
1694
+ use super::*;
1695
+
1696
+ #[test]
1697
+ fn scrollback_height_accounts_for_wide_unicode() {
1698
+ let text = ratatui::text::Text::raw("🙂🙂🙂");
1699
+
1700
+ assert_eq!(wrapped_text_height(&text, 4), 2);
1701
+ }
1702
+ }
1703
+
1455
1704
  #[cfg(test)]
1456
1705
  mod project_tokens_tests {
1457
1706
  use super::*;