@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
@@ -2,7 +2,7 @@ use std::io::{self, Write};
2
2
  use std::path::Path;
3
3
  use std::sync::{
4
4
  Arc, Mutex,
5
- atomic::{AtomicBool, Ordering},
5
+ atomic::{AtomicBool, AtomicUsize, Ordering},
6
6
  };
7
7
  use std::time::{Duration, Instant};
8
8
 
@@ -27,19 +27,21 @@ mod markdown_render;
27
27
  use approval_prompts::*;
28
28
  use diff_render::*;
29
29
  pub(crate) use live_status::*;
30
- use markdown_render::*;
31
-
32
- const RESET: &str = "\x1b[0m";
33
- const MINT: &str = "\x1b[32m";
34
- const GREEN: &str = "\x1b[32m";
35
- const RED: &str = "\x1b[31m";
36
- const BLUE: &str = "\x1b[38;2;78;201;216m";
37
- const CYAN: &str = "\x1b[38;2;56;189;248m";
38
- const DIM: &str = "\x1b[90m";
39
- const BRIGHT: &str = "\x1b[1;97m";
40
- const BOLD: &str = "\x1b[1m";
41
- const BG_ADD: &str = "\x1b[48;2;20;53;32m\x1b[38;2;166;226;46m";
42
- const BG_DEL: &str = "\x1b[48;2;61;23;23m\x1b[38;2;255;121;121m";
30
+ pub(crate) use markdown_render::*;
31
+
32
+ const RESET: &str = crate::terminal_theme::ANSI_RESET;
33
+ const MINT: &str = crate::terminal_theme::ANSI_ACCENT;
34
+ const GREEN: &str = crate::terminal_theme::ANSI_ACCENT;
35
+ const RED: &str = crate::terminal_theme::ANSI_ERROR;
36
+ const YELLOW: &str = crate::terminal_theme::ANSI_WARNING;
37
+ const BLUE: &str = crate::terminal_theme::ANSI_BLUE;
38
+ const CYAN: &str = crate::terminal_theme::ANSI_BLUE;
39
+ const DIM: &str = crate::terminal_theme::ANSI_MUTED;
40
+ const BRIGHT: &str = crate::terminal_theme::ANSI_BRIGHT_TEXT;
41
+ const WHITE: &str = crate::terminal_theme::ANSI_TEXT;
42
+ const BOLD: &str = crate::terminal_theme::ANSI_BOLD;
43
+ const BG_ADD: &str = crate::terminal_theme::ANSI_ADD;
44
+ const BG_DEL: &str = crate::terminal_theme::ANSI_DELETE;
43
45
 
44
46
  #[derive(Debug, Clone, Default)]
45
47
  pub struct AgentOptions {
@@ -58,6 +60,11 @@ pub struct AgentOptions {
58
60
  /// configured MCP server — set by an `@servername` mention in the typed
59
61
  /// query, mirroring the GUI composer's `@` mention picker.
60
62
  pub pinned_mcp_server: Option<String>,
63
+ /// Chat ID / session ID for this turn. Defaults to `CHAT_CLI_ID` if omitted.
64
+ pub chat_id: Option<String>,
65
+ /// Full-screen UI event sink. When present, agent output never writes
66
+ /// directly to stdout and stdin remains owned by the TUI controller.
67
+ pub tui: Option<crate::interactive::TuiHandle>,
61
68
  }
62
69
 
63
70
  pub async fn run_code_agent(task: &str, root: &Path, config: &MintConfig) -> Result<AgentResult> {
@@ -327,6 +334,187 @@ fn save_plan_file(root: &Path, plan: &str) -> io::Result<std::path::PathBuf> {
327
334
  Ok(path)
328
335
  }
329
336
 
337
+ fn tui_persistable_approval(
338
+ tui: &crate::interactive::TuiHandle,
339
+ tool: &str,
340
+ subject: &str,
341
+ title: &str,
342
+ body: String,
343
+ root: &Path,
344
+ permission_rules: &mut Vec<PermissionRule>,
345
+ ) -> ApprovalOutcome {
346
+ if let Some(decision) = permission_decision_for(permission_rules, tool, subject, root) {
347
+ return match decision {
348
+ PermissionDecision::Allow => ApprovalOutcome::Approved,
349
+ PermissionDecision::Deny => ApprovalOutcome::Denied,
350
+ };
351
+ }
352
+ match tui.choose(
353
+ title,
354
+ body,
355
+ vec![
356
+ "Yes".into(),
357
+ "Yes, allow for this session".into(),
358
+ "No".into(),
359
+ ],
360
+ ) {
361
+ Some(0) => ApprovalOutcome::Approved,
362
+ Some(1) => {
363
+ permission_rules.push(PermissionRule {
364
+ tool: tool.to_owned(),
365
+ pattern: subject.to_owned(),
366
+ decision: PermissionDecision::Allow,
367
+ project_root: None,
368
+ });
369
+ ApprovalOutcome::Approved
370
+ }
371
+ _ => ApprovalOutcome::Denied,
372
+ }
373
+ }
374
+
375
+ fn tui_approval(
376
+ tui: &crate::interactive::TuiHandle,
377
+ approval: &AgentApproval,
378
+ root: &Path,
379
+ permission_rules: &mut Vec<PermissionRule>,
380
+ ) -> Result<ApprovalOutcome, String> {
381
+ let yes_no = |title: &str, body: String| match tui.choose(
382
+ title,
383
+ body,
384
+ vec!["Approve".into(), "Deny".into()],
385
+ ) {
386
+ Some(0) => ApprovalOutcome::Approved,
387
+ _ => ApprovalOutcome::Denied,
388
+ };
389
+ Ok(match approval {
390
+ AgentApproval::WriteFile { path, diff, .. } => tui_persistable_approval(
391
+ tui,
392
+ "write_file",
393
+ path,
394
+ "Create file",
395
+ format!("Path: {path}\n\n{diff}"),
396
+ root,
397
+ permission_rules,
398
+ ),
399
+ AgentApproval::ApplyPatch { path, diff, .. } => tui_persistable_approval(
400
+ tui,
401
+ "apply_patch",
402
+ path,
403
+ "Update file",
404
+ format!("Path: {path}\n\n{diff}"),
405
+ root,
406
+ permission_rules,
407
+ ),
408
+ AgentApproval::RunShell {
409
+ command,
410
+ mode,
411
+ background,
412
+ } => tui_persistable_approval(
413
+ tui,
414
+ "run_shell",
415
+ command,
416
+ "Local shell command",
417
+ format!(
418
+ "Command: {command}\nMode: {mode}\nBackground: {}",
419
+ if *background { "yes" } else { "no" }
420
+ ),
421
+ root,
422
+ permission_rules,
423
+ ),
424
+ AgentApproval::NoteWrite { path, .. } => tui_persistable_approval(
425
+ tui,
426
+ "note_write",
427
+ path,
428
+ "Create note",
429
+ format!("Path: {path}"),
430
+ root,
431
+ permission_rules,
432
+ ),
433
+ AgentApproval::RunPlugin { name, instruction } => {
434
+ let subject = format!("{name}: {instruction}");
435
+ tui_persistable_approval(
436
+ tui,
437
+ "run_plugin",
438
+ &subject,
439
+ "Run plugin",
440
+ format!("Plugin: {name}\n\n{instruction}"),
441
+ root,
442
+ permission_rules,
443
+ )
444
+ }
445
+ AgentApproval::McpTool {
446
+ server,
447
+ tool,
448
+ arguments,
449
+ } => {
450
+ let body = format!("Server: {server}\nTool: {tool}\nArguments: {arguments}");
451
+ if tui.choose(
452
+ "MCP tool call",
453
+ body,
454
+ vec![format!("Allow all tools on {server}"), "No".into()],
455
+ ) == Some(0)
456
+ {
457
+ ApprovalOutcome::Intercepted(mint_core::MCP_ALLOW_ALL_SENTINEL.to_owned())
458
+ } else {
459
+ ApprovalOutcome::Denied
460
+ }
461
+ }
462
+ AgentApproval::UserApproval { title, prompt } => yes_no(title, prompt.to_owned()),
463
+ AgentApproval::EnterPlanMode { reason } => yes_no("Enter plan mode?", reason.to_owned()),
464
+ AgentApproval::ExitPlanMode { plan } => {
465
+ let outcome = yes_no("Review plan", plan.to_owned());
466
+ if outcome == ApprovalOutcome::Approved {
467
+ match save_plan_file(root, plan) {
468
+ Ok(path) => tui.push_notice(format!("Plan saved to {}", path.display())),
469
+ Err(error) => tui.push_notice(format!("Could not save plan: {error}")),
470
+ }
471
+ }
472
+ outcome
473
+ }
474
+ AgentApproval::AskUser {
475
+ question,
476
+ options,
477
+ header,
478
+ multi_select,
479
+ } => {
480
+ let title = header.as_deref().unwrap_or("Mint needs your input");
481
+ if options.is_empty() {
482
+ tui.prompt_text(title, question)
483
+ .map(ApprovalOutcome::Intercepted)
484
+ .unwrap_or(ApprovalOutcome::Denied)
485
+ } else {
486
+ let labels = options
487
+ .iter()
488
+ .map(|option| match &option.description {
489
+ Some(description) => format!("{} — {description}", option.label),
490
+ None => option.label.clone(),
491
+ })
492
+ .collect::<Vec<_>>();
493
+ if *multi_select {
494
+ let selected = tui.choose_many(title, question, labels);
495
+ let answer = selected
496
+ .into_iter()
497
+ .filter_map(|index| options.get(index))
498
+ .map(|option| option.label.as_str())
499
+ .collect::<Vec<_>>()
500
+ .join(", ");
501
+ if answer.is_empty() {
502
+ ApprovalOutcome::Denied
503
+ } else {
504
+ ApprovalOutcome::Intercepted(answer)
505
+ }
506
+ } else {
507
+ let choice = tui.choose(title, question, labels);
508
+ choice
509
+ .and_then(|choice| options.get(choice))
510
+ .map(|option| ApprovalOutcome::Intercepted(option.label.clone()))
511
+ .unwrap_or(ApprovalOutcome::Denied)
512
+ }
513
+ }
514
+ }
515
+ })
516
+ }
517
+
330
518
  pub async fn run_code_agent_with_options(
331
519
  task: &str,
332
520
  root: &Path,
@@ -338,19 +526,23 @@ pub async fn run_code_agent_with_options(
338
526
  draft_out: Arc<Mutex<Option<String>>>,
339
527
  ) -> Result<AgentResult> {
340
528
  let started_at = Instant::now();
529
+ crate::interactive::clear_last_thought();
341
530
  let thinking_verb = random_thinking_verb();
342
531
  let approval_active = Arc::new(AtomicBool::new(false));
343
532
  let agent_done = Arc::new(AtomicBool::new(false));
344
- // True between a tool starting and finishing — tells the periodic timer
533
+ // Number of tools between start and finish — tells the periodic timer
345
534
  // below not to overwrite the live status with "Thinking (Xs)…" text
346
- // while a tool (e.g. a shell command) is actually the thing in flight,
347
- // without stopping it from still re-rendering (so the bullets keep
348
- // pulsing) while that's happening.
349
- let tool_running = Arc::new(AtomicBool::new(false));
535
+ // while any tool (e.g. a shell command) is still in flight. A count is
536
+ // needed because parallel tools may finish at different times.
537
+ let tool_running = Arc::new(AtomicUsize::new(0));
350
538
  let live_status = Arc::new(Mutex::new(LiveStatus::default()));
351
539
  {
352
540
  use crossterm::tty::IsTty;
541
+ if let Ok(mut status) = live_status.lock() {
542
+ status.tui = options.tui.clone();
543
+ }
353
544
  if options.queueing
545
+ && options.tui.is_none()
354
546
  && !options.fast_mode
355
547
  && io::stdout().is_tty()
356
548
  && io::stdin().is_tty()
@@ -372,6 +564,11 @@ pub async fn run_code_agent_with_options(
372
564
 
373
565
  let approve_cb = |approval: &AgentApproval| -> Result<ApprovalOutcome, String> {
374
566
  approve_approval_active.store(true, Ordering::Relaxed);
567
+ if let Some(tui) = &options.tui {
568
+ let result = tui_approval(tui, approval, root, &mut permission_rules);
569
+ approve_approval_active.store(false, Ordering::Relaxed);
570
+ return result;
571
+ }
375
572
  // Synchronous, not polled: `wait_for_escape_interrupt` holds raw
376
573
  // mode continuously while the queueing box is live (see its docs),
377
574
  // and only reacts to `approval_active` on its next ~15ms tick. Every
@@ -600,7 +797,7 @@ pub async fn run_code_agent_with_options(
600
797
  if timer_agent_done.load(Ordering::Relaxed) {
601
798
  break;
602
799
  }
603
- if !timer_tool_running.load(Ordering::Relaxed) {
800
+ if timer_tool_running.load(Ordering::Relaxed) == 0 {
604
801
  status.thinking = Some(
605
802
  if let Some((attempt, max_attempts)) = status.waiting_for_network {
606
803
  waiting_for_network_label(attempt, max_attempts)
@@ -648,6 +845,7 @@ pub async fn run_code_agent_with_options(
648
845
  } => {
649
846
  if !options.fast_mode
650
847
  && !progress_approval_active.load(Ordering::Relaxed)
848
+ && progress_tool_running.load(Ordering::Relaxed) == 0
651
849
  && let Ok(mut status) = progress_live_status.lock()
652
850
  {
653
851
  status.context_pct = context_pct;
@@ -655,6 +853,7 @@ pub async fn run_code_agent_with_options(
655
853
  status.input_tokens = input_tokens;
656
854
  status.generated_tokens = generated_tokens;
657
855
  status.estimated_tokens = estimated_tokens;
856
+ status.active_tool_started = None;
658
857
  // Re-derive the animation rate from this real data point
659
858
  // every time one arrives (cumulative generated tokens /
660
859
  // elapsed turn time so far) — see
@@ -695,6 +894,7 @@ pub async fn run_code_agent_with_options(
695
894
  } => {
696
895
  if !options.fast_mode
697
896
  && !progress_approval_active.load(Ordering::Relaxed)
897
+ && progress_tool_running.load(Ordering::Relaxed) == 0
698
898
  && let Ok(mut status) = progress_live_status.lock()
699
899
  {
700
900
  status.waiting_for_network = Some((attempt, max_attempts));
@@ -707,8 +907,49 @@ pub async fn run_code_agent_with_options(
707
907
  && !progress_approval_active.load(Ordering::Relaxed)
708
908
  && let Ok(mut status) = progress_live_status.lock()
709
909
  {
710
- commit_activity_snapshot(&mut status);
711
- print_timeline_note(&mut status, &thought);
910
+ commit_activity_snapshot_if_idle(
911
+ &mut status,
912
+ progress_tool_running.load(Ordering::Relaxed),
913
+ );
914
+ let elapsed = started_at.elapsed();
915
+ print_timeline_note(&mut status, &thought, elapsed, None);
916
+ status.thinking = None;
917
+ status.waiting_for_network = None;
918
+ render_live_status(&mut status);
919
+ }
920
+ }
921
+ AgentProgress::ThinkingDelta {
922
+ id,
923
+ delta,
924
+ elapsed_ms,
925
+ } => {
926
+ if !options.fast_mode {
927
+ let elapsed = Duration::from_millis(elapsed_ms);
928
+ let elapsed_str = crate::interactive::format_thought_elapsed(elapsed);
929
+ crate::interactive::append_thought_delta(&id, &delta, &elapsed_str);
930
+ }
931
+ }
932
+ AgentProgress::ExtendedThinking {
933
+ id,
934
+ thought,
935
+ elapsed_ms,
936
+ } => {
937
+ if !options.fast_mode
938
+ && !progress_approval_active.load(Ordering::Relaxed)
939
+ && let Ok(mut status) = progress_live_status.lock()
940
+ {
941
+ commit_activity_snapshot_if_idle(
942
+ &mut status,
943
+ progress_tool_running.load(Ordering::Relaxed),
944
+ );
945
+ let elapsed = elapsed_ms
946
+ .map(Duration::from_millis)
947
+ .unwrap_or_else(|| started_at.elapsed());
948
+ // Extended thinking gets the same timeline-note treatment
949
+ // as regular Thought — `print_timeline_note` already
950
+ // distinguishes internal CoT (long) from short notes via
951
+ // `is_internal_cot` and renders accordingly.
952
+ print_timeline_note(&mut status, &thought, elapsed, id.as_deref());
712
953
  status.thinking = None;
713
954
  status.waiting_for_network = None;
714
955
  render_live_status(&mut status);
@@ -719,8 +960,13 @@ pub async fn run_code_agent_with_options(
719
960
  input,
720
961
  subagent,
721
962
  } => {
722
- progress_tool_running.store(true, Ordering::Relaxed);
723
- if !options.fast_mode && !progress_approval_active.load(Ordering::Relaxed) {
963
+ progress_tool_running.fetch_add(1, Ordering::Relaxed);
964
+ if !options.fast_mode
965
+ && (options.tui.is_some() || !progress_approval_active.load(Ordering::Relaxed))
966
+ {
967
+ if let Ok(mut status) = progress_live_status.lock() {
968
+ status.active_tool_started = Some(std::time::Instant::now());
969
+ }
724
970
  if let Some(subagent_name) = subagent {
725
971
  // A tool call happening *inside* a running subagent's own
726
972
  // nested loop (tagged by `dispatch_one_subagent`) — render
@@ -794,8 +1040,20 @@ pub async fn run_code_agent_with_options(
794
1040
  result,
795
1041
  subagent,
796
1042
  } => {
797
- progress_tool_running.store(false, Ordering::Relaxed);
798
- if !options.fast_mode && !progress_approval_active.load(Ordering::Relaxed) {
1043
+ let remaining = progress_tool_running
1044
+ .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |running| {
1045
+ Some(running.saturating_sub(1))
1046
+ })
1047
+ .unwrap_or(0)
1048
+ .saturating_sub(1);
1049
+ if !options.fast_mode
1050
+ && (options.tui.is_some() || !progress_approval_active.load(Ordering::Relaxed))
1051
+ {
1052
+ if remaining == 0
1053
+ && let Ok(mut status) = progress_live_status.lock()
1054
+ {
1055
+ status.active_tool_started = None;
1056
+ }
799
1057
  if subagent.is_some() {
800
1058
  // Nested call inside a subagent finished — the ToolStart
801
1059
  // line already shown covers it; only the command-output
@@ -890,7 +1148,12 @@ pub async fn run_code_agent_with_options(
890
1148
  if let Ok(mut status) = progress_live_status.lock() {
891
1149
  status.thinking = None;
892
1150
  status.waiting_for_network = None;
893
- let mut card = format!("\x1b[1;36m┌─ Plan: {} \x1b[0m\n", plan.objective);
1151
+ let mut card = format!(
1152
+ "{}┌─ Plan: {} {}\n",
1153
+ crate::terminal_theme::ANSI_ACCENT_BOLD,
1154
+ plan.objective,
1155
+ crate::terminal_theme::ANSI_RESET
1156
+ );
894
1157
  for task in &plan.tasks {
895
1158
  let mark = match task.status.as_str() {
896
1159
  "completed" => "\x1b[32m[✓]\x1b[0m",
@@ -900,7 +1163,11 @@ pub async fn run_code_agent_with_options(
900
1163
  };
901
1164
  card.push_str(&format!("│ {} {}\n", mark, task.title));
902
1165
  }
903
- card.push_str("\x1b[1;36m└────────────────────────────────────────\x1b[0m");
1166
+ card.push_str(&format!(
1167
+ "{}└────────────────────────────────────────{}",
1168
+ crate::terminal_theme::ANSI_ACCENT_BOLD,
1169
+ crate::terminal_theme::ANSI_RESET
1170
+ ));
904
1171
  status.tasks.push(card.into());
905
1172
  render_live_status(&mut status);
906
1173
  }
@@ -909,174 +1176,76 @@ pub async fn run_code_agent_with_options(
909
1176
  if let Ok(mut status) = progress_live_status.lock() {
910
1177
  status.thinking = None;
911
1178
  status.waiting_for_network = None;
912
- let outcome_str = match summary.outcome.as_str() {
913
- "SUCCESS" => "\x1b[32m✓ Success\x1b[0m",
914
- "FAILED" => "\x1b[31m✗ Failure\x1b[0m",
915
- "ROLLED_BACK" => "\x1b[33m↺ Rolled Back\x1b[0m",
916
- _ => &summary.outcome,
917
- };
918
- let tokens_k = if summary.total_tokens >= 1000 {
919
- format!("{:.1}k", summary.total_tokens as f64 / 1000.0)
920
- } else {
921
- summary.total_tokens.to_string()
922
- };
923
- let created_count = summary.files_created.len();
924
- let modified_count = summary.files_changed.len().saturating_sub(created_count);
925
- let files_str = if created_count > 0 && modified_count > 0 {
926
- format!("{} created, {} modified", created_count, modified_count)
927
- } else if created_count > 0 {
928
- format!("{} created", created_count)
1179
+ commit_activity_snapshot(&mut status);
1180
+
1181
+ let failed_tools: Vec<_> = summary
1182
+ .tool_timeline
1183
+ .iter()
1184
+ .filter(|record| !record.success)
1185
+ .collect();
1186
+ let outcome = if !failed_tools.is_empty() {
1187
+ format!(
1188
+ "{YELLOW}⚠ Completed with {} failure{}{RESET}",
1189
+ failed_tools.len(),
1190
+ if failed_tools.len() == 1 { "" } else { "s" }
1191
+ )
1192
+ } else if summary.outcome == "ROLLED_BACK" {
1193
+ format!("{YELLOW}↺ Rolled back{RESET}")
1194
+ } else if summary.outcome == "FAILED" {
1195
+ format!("{RED}✗ Failed{RESET}")
929
1196
  } else {
930
- format!("{} modified", summary.files_changed.len())
1197
+ format!("{GREEN}✓ Completed{RESET}")
931
1198
  };
932
- let mut card = format!(
933
- "\x1b[1;36m┌─ Agent Run #{} ────────────────────────────\x1b[0m\n\
934
- │ Status: {}\n\
935
- │ Duration: {:.1}s\n\
936
- │ Tokens: {}\n\
937
- │ Tools: {} calls ({} retries)\n\
938
- │ Files: {}\n",
939
- summary.run_id,
940
- outcome_str,
1199
+ let file_count = summary.files_changed.len();
1200
+ let mut lines = vec![format!(
1201
+ " {outcome} {DIM}in {:.1}s · {} tool{} · {} file{} changed{RESET}",
941
1202
  summary.duration_secs,
942
- tokens_k,
943
1203
  summary.tool_calls_count,
944
- summary.retries_count,
945
- files_str,
946
- );
947
- if !summary.tool_timeline.is_empty() {
948
- card.push_str("│\n│ Tool calls timeline:\n");
949
- for rec in &summary.tool_timeline {
950
- let status_icon = if !rec.success {
951
- "\x1b[31m✗\x1b[0m"
952
- } else if rec.retried {
953
- "\x1b[33m↺\x1b[0m"
954
- } else {
955
- "\x1b[32m✓\x1b[0m"
956
- };
957
- let note = if !rec.success {
958
- " (failed)"
959
- } else if rec.retried {
960
- " (self-corrected)"
961
- } else {
962
- ""
963
- };
964
- let target_desc = if rec.target.is_empty() {
965
- String::new()
966
- } else {
967
- format!(" [{}]", rec.target)
968
- };
969
- card.push_str(&format!(
970
- "│ {:02}s {} {}{}{}\n",
971
- rec.step, status_icon, rec.action, target_desc, note
972
- ));
1204
+ if summary.tool_calls_count == 1 {
1205
+ ""
1206
+ } else {
1207
+ "s"
1208
+ },
1209
+ file_count,
1210
+ if file_count == 1 { "" } else { "s" },
1211
+ )];
1212
+
1213
+ if file_count > 0 {
1214
+ let mut names: Vec<String> = summary
1215
+ .files_changed
1216
+ .iter()
1217
+ .take(6)
1218
+ .map(|path| display_tool_target(path))
1219
+ .collect();
1220
+ if file_count > names.len() {
1221
+ names.push(format!("+{} more", file_count - names.len()));
973
1222
  }
1223
+ lines.push(format!(" {DIM}└ {}{RESET}", names.join(", ")));
974
1224
  }
975
- card.push_str("\x1b[1;36m└────────────────────────────────────────\x1b[0m");
976
- status.tasks.push(card.into());
977
- render_live_status(&mut status);
1225
+ for record in failed_tools.into_iter().take(3) {
1226
+ let target = if record.target.is_empty() {
1227
+ record.action.clone()
1228
+ } else {
1229
+ format!("{} [{}]", record.action, truncate_line(&record.target, 72))
1230
+ };
1231
+ lines.push(format!(" {RED}└ {target} failed{RESET}"));
1232
+ }
1233
+ insert_permanent_lines(&mut status, &lines);
978
1234
  }
979
1235
  }
980
1236
  }
981
1237
  };
982
1238
 
983
- let chunk_live_status = Arc::clone(&live_status);
984
- let chunk_agent_done = Arc::clone(&agent_done);
985
- let on_chunk = |summary: String| {
986
- // Flip this *before* touching anything else — `agent_loop` still has
987
- // async work left (memory writes, etc.) after calling `on_chunk`, so
988
- // the real "done" store below (after `agent_loop.await`) fires too
989
- // late: the periodic status ticker keeps polling every 150ms in the
990
- // meantime and, seeing `agent_done` still false, unconditionally
991
- // resurrects `status.thinking` and re-renders — reconstructing a
992
- // fresh inline TUI viewport mid-print if that lands while the plain
993
- // `print!`s below are still spooling out a long answer (e.g. a big
994
- // markdown table), corrupting the terminal. Setting it here closes
995
- // that window instead of only the (much narrower) one the
996
- // `accepting_input` flag below covers.
997
- chunk_agent_done.store(true, Ordering::Relaxed);
998
- let mut committed_activity = false;
999
- if !options.fast_mode
1000
- && let Ok(mut status) = chunk_live_status.lock()
1001
- {
1002
- status.thinking = None;
1003
- status.waiting_for_network = None;
1004
- // Stop accepting keystrokes for the queueing box before it's torn
1005
- // down below — otherwise a keypress landing between this
1006
- // `clear_live_status` and the final answer's plain `println!`
1007
- // would resurrect the box (via `render_live_status`'s lazy
1008
- // `InlineTui::ensure`) at whatever the cursor's current position
1009
- // happens to be, underneath the answer that just printed.
1010
- status.accepting_input = false;
1011
- committed_activity = commit_activity_snapshot(&mut status);
1012
- clear_live_status(&mut status);
1013
- }
1014
- // Same reasoning as `approve_cb`: drop raw mode synchronously,
1015
- // right here, rather than leaving `wait_for_escape_interrupt` to
1016
- // notice `accepting_input` went false on its next tick — the prints
1017
- // below need cooked mode's `\n` → `\r\n` translation immediately.
1018
- let _ = crossterm::terminal::disable_raw_mode();
1019
- let formatted_summary = format_markdown_bold(&sanitize_latex(&summary));
1020
- // `commit_activity_snapshot` above already ended on a blank line when
1021
- // it committed anything (e.g. a tool-use activity block) — printing
1022
- // this leading "\n" unconditionally on top of that stacked two blank
1023
- // lines before every answer that followed tool use.
1024
- if committed_activity {
1025
- print!(" {MINT}Mint:{RESET} ");
1026
- } else {
1027
- print!("\n {MINT}Mint:{RESET} ");
1028
- }
1029
- avatar_bridge.on_talking(true);
1030
- render_live_summary(&formatted_summary);
1031
- avatar_bridge.on_talking(false);
1032
-
1033
- // Print web search sources if any were collected (grouped by domain)
1034
- if let Ok(mut status) = chunk_live_status.lock()
1035
- && !status.web_sources.is_empty()
1036
- {
1037
- println!();
1038
- println!(" {DIM}Sources:{RESET}");
1039
-
1040
- let mut domain_groups: Vec<(String, Vec<(String, String)>)> = Vec::new();
1041
- for (title, url) in status.web_sources.drain(..) {
1042
- let domain = extract_domain(&url);
1043
- if let Some(group) = domain_groups.iter_mut().find(|(d, _)| d == &domain) {
1044
- group.1.push((title, url));
1045
- } else {
1046
- domain_groups.push((domain, vec![(title, url)]));
1047
- }
1048
- }
1049
-
1050
- for (i, (domain, items)) in domain_groups.iter().enumerate() {
1051
- let (first_title, first_url) = &items[0];
1052
- let extra_count = items.len() - 1;
1053
- if extra_count > 0 {
1054
- println!(
1055
- " {DIM}{}.{RESET} {BLUE}{}{RESET} {DIM}({}){RESET} {CYAN}[+{} extra]{RESET}",
1056
- i + 1,
1057
- first_title,
1058
- domain,
1059
- extra_count
1060
- );
1061
- } else {
1062
- println!(
1063
- " {DIM}{}.{RESET} {BLUE}{}{RESET} {DIM}({}){RESET}",
1064
- i + 1,
1065
- first_title,
1066
- domain
1067
- );
1068
- }
1069
- println!(" {DIM}{}{RESET}", first_url);
1070
- }
1071
- }
1072
-
1073
- println!();
1074
- };
1239
+ // Providers may still stream internally, but the CLI deliberately waits
1240
+ // for AgentResult.summary so it can render one complete Markdown document.
1241
+ let on_chunk = |_summary: String| {};
1075
1242
 
1076
1243
  let user_name = MemoryStore::open_default()
1077
1244
  .ok()
1078
1245
  .and_then(|memory| memory.get_profile("name").ok().flatten());
1079
1246
 
1247
+ let target_chat_id = options.chat_id.as_deref().unwrap_or(CHAT_CLI_ID);
1248
+
1080
1249
  let agent_loop = orchestrate_agent_loop(
1081
1250
  config,
1082
1251
  task,
@@ -1084,7 +1253,7 @@ pub async fn run_code_agent_with_options(
1084
1253
  image_data_uri,
1085
1254
  None,
1086
1255
  video_data_uri,
1087
- Some(CHAT_CLI_ID),
1256
+ Some(target_chat_id),
1088
1257
  None,
1089
1258
  user_name.as_deref(),
1090
1259
  options.pinned_mcp_server.as_deref(),
@@ -1111,51 +1280,53 @@ pub async fn run_code_agent_with_options(
1111
1280
  status.thinking = None;
1112
1281
  status.waiting_for_network = None;
1113
1282
  status.accepting_input = false;
1283
+ commit_activity_snapshot(&mut status);
1114
1284
  if let Ok(mut out) = queued_out.lock() {
1115
- *out = status.queued.clone();
1285
+ *out = options
1286
+ .tui
1287
+ .as_ref()
1288
+ .map(|tui| tui.take_queued())
1289
+ .unwrap_or_else(|| status.queued.clone());
1116
1290
  }
1117
1291
  if let Ok(mut out) = draft_out.lock() {
1118
- *out = if status.draft.is_empty() {
1119
- None
1120
- } else {
1121
- Some(status.draft.iter().collect())
1122
- };
1123
- }
1124
- if res.is_err() {
1125
- commit_activity_snapshot(&mut status);
1292
+ *out = options
1293
+ .tui
1294
+ .as_ref()
1295
+ .and_then(|tui| tui.draft())
1296
+ .or_else(|| (!status.draft.is_empty()).then(|| status.draft.iter().collect()));
1126
1297
  }
1127
1298
  clear_live_status(&mut status);
1128
1299
  }
1129
- let res = res.map_err(|e| anyhow!("{}", e))?;
1130
-
1131
- if should_show_verification(&res.verification) {
1132
- println!(" Verification: {}", res.verification);
1300
+ let mut res = res.map_err(|e| anyhow!("{}", e))?;
1301
+ if let Ok(status) = live_status.lock() {
1302
+ if res.input_tokens == 0 && status.input_tokens > 0 {
1303
+ res.input_tokens = status.input_tokens;
1304
+ }
1305
+ if res.generated_tokens == 0 && status.generated_tokens > 0 {
1306
+ res.generated_tokens = status.generated_tokens;
1307
+ }
1133
1308
  }
1134
- let badge_plain = if let Some(fb_provider) = &res.fallback {
1309
+
1310
+ let badge_plain = if let Some(orig_provider) = &res.fallback {
1311
+ let reason_suffix = if let Some(reason) = &res.fallback_reason {
1312
+ format!(" ({reason})")
1313
+ } else {
1314
+ String::new()
1315
+ };
1135
1316
  format!(
1136
- "{} • {} → fallback: {} • {}",
1137
- config.ai_provider,
1138
- crate::active_model(&config.ai_provider, config),
1139
- fb_provider,
1317
+ "{} • {}{} → fallback: {} • {}",
1318
+ orig_provider,
1319
+ crate::active_model(orig_provider, config),
1320
+ reason_suffix,
1321
+ res.provider,
1140
1322
  res.model
1141
1323
  )
1142
1324
  } else {
1143
1325
  format!("{} • {}", res.provider, res.model)
1144
1326
  };
1145
1327
 
1146
- // "─ Worked for {elapsed} • {provider} • {model}" as one *labeled*
1147
- // divider — filled out with more "─" to the same width the box's own
1148
- // two divider lines use — rather than the provider/model badge and the
1149
- // elapsed-time label as two separate short lines followed by a third,
1150
- // unlabeled full-width divider directly under them. The three used to
1151
- // look like unrelated elements stacked on top of each other; folding
1152
- // both labels into one rule reads as a single line doing all three
1153
- // jobs, matching the box below it.
1154
1328
  let (tw, _) = markdown::terminal_size_or_default();
1155
- let width = tw as usize;
1156
- // `↑` context stays dim with the rest of the footer; `↓` generated drops
1157
- // out of DIM for its segment so the "what the model actually produced"
1158
- // number reads a touch stronger than the divider around it.
1329
+ let width = (tw as usize).saturating_sub(6).max(40);
1159
1330
  let tokens_suffix = if res.input_tokens > 0 || res.generated_tokens > 0 {
1160
1331
  format!(
1161
1332
  " • ↑ {} · {RESET}↓ {}{DIM}",
@@ -1169,11 +1340,77 @@ pub async fn run_code_agent_with_options(
1169
1340
  "─ Worked for {}{tokens_suffix} • {badge_plain}",
1170
1341
  format_elapsed(started_at.elapsed())
1171
1342
  );
1172
- // Count only visible columns for the fill — `tokens_suffix` carries ANSI
1173
- // codes that don't occupy screen width.
1174
1343
  let label_width = strip_ansi_escapes(&label).chars().count();
1175
- let fill_len = width.saturating_sub(2).saturating_sub(label_width + 1);
1176
- println!(" {DIM}{label} {}{RESET}", "─".repeat(fill_len));
1344
+ let fill_len = width.saturating_sub(label_width + 1);
1345
+ let worked_line = format!("{DIM}{label} {}{RESET}", "─".repeat(fill_len));
1346
+
1347
+ if let Some(tui) = &options.tui {
1348
+ tui.push_assistant(res.summary.clone());
1349
+ if let Ok(mut status) = live_status.lock()
1350
+ && !status.web_sources.is_empty()
1351
+ {
1352
+ let sources = status
1353
+ .web_sources
1354
+ .drain(..)
1355
+ .enumerate()
1356
+ .map(|(index, (title, url))| format!("{}. {title}\n {url}", index + 1))
1357
+ .collect::<Vec<_>>()
1358
+ .join("\n");
1359
+ tui.push_notice(format!("Sources:\n{sources}"));
1360
+ }
1361
+ tui.push_notice(worked_line);
1362
+ avatar_bridge.on_talking(false);
1363
+ return Ok(res);
1364
+ }
1365
+
1366
+ let formatted_summary = format_markdown_bold(&sanitize_latex(&res.summary));
1367
+ print!("\n {MINT}Mint:{RESET} ");
1368
+ avatar_bridge.on_talking(true);
1369
+ render_live_summary(&formatted_summary);
1370
+ avatar_bridge.on_talking(false);
1371
+ println!();
1372
+
1373
+ // Print web search sources once after the streamed answer is complete.
1374
+ if let Ok(mut status) = live_status.lock()
1375
+ && !status.web_sources.is_empty()
1376
+ {
1377
+ println!(" {DIM}Sources:{RESET}");
1378
+
1379
+ let mut domain_groups: Vec<(String, Vec<(String, String)>)> = Vec::new();
1380
+ for (title, url) in status.web_sources.drain(..) {
1381
+ let domain = extract_domain(&url);
1382
+ if let Some(group) = domain_groups.iter_mut().find(|(d, _)| d == &domain) {
1383
+ group.1.push((title, url));
1384
+ } else {
1385
+ domain_groups.push((domain, vec![(title, url)]));
1386
+ }
1387
+ }
1388
+
1389
+ for (i, (domain, items)) in domain_groups.iter().enumerate() {
1390
+ let (first_title, first_url) = &items[0];
1391
+ let extra_count = items.len() - 1;
1392
+ if extra_count > 0 {
1393
+ println!(
1394
+ " {DIM}{}.{RESET} {BLUE}{}{RESET} {DIM}({}){RESET} {CYAN}[+{} extra]{RESET}",
1395
+ i + 1,
1396
+ first_title,
1397
+ domain,
1398
+ extra_count
1399
+ );
1400
+ } else {
1401
+ println!(
1402
+ " {DIM}{}.{RESET} {BLUE}{}{RESET} {DIM}({}){RESET}",
1403
+ i + 1,
1404
+ first_title,
1405
+ domain
1406
+ );
1407
+ }
1408
+ println!(" {DIM}{}{RESET}", first_url);
1409
+ }
1410
+ println!();
1411
+ }
1412
+
1413
+ println!(" {worked_line}");
1177
1414
 
1178
1415
  Ok(res)
1179
1416
  }