@pheem49/mint 1.16.0 → 1.17.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 (848) hide show
  1. package/Cargo.lock +6 -6
  2. package/Cargo.toml +1 -1
  3. package/README.md +1 -1
  4. package/Release_Note.md +71 -72
  5. package/apps/mint-companion/src-tauri/src/compact.rs +69 -0
  6. package/apps/mint-companion/src-tauri/src/main.rs +218 -11
  7. package/apps/mint-companion/vite.config.ts +2 -1
  8. package/crates/mint-cli/src/agent/live_status.rs +43 -2
  9. package/crates/mint-cli/src/agent.rs +178 -38
  10. package/crates/mint-cli/src/commands/agent.rs +225 -31
  11. package/crates/mint-cli/src/commands/browser.rs +127 -0
  12. package/crates/mint-cli/src/commands/config.rs +14 -1
  13. package/crates/mint-cli/src/commands/knowledge.rs +16 -2
  14. package/crates/mint-cli/src/commands/mod.rs +15 -1
  15. package/crates/mint-cli/src/commands/tailnet_web.rs +2 -7
  16. package/crates/mint-cli/src/companion_navigation.rs +268 -0
  17. package/crates/mint-cli/src/interactive/chat_tui.rs +1065 -63
  18. package/crates/mint-cli/src/interactive/command_ui.rs +39 -0
  19. package/crates/mint-cli/src/interactive/slash_commands.rs +114 -6
  20. package/crates/mint-cli/src/interactive/tool_activity.rs +375 -36
  21. package/crates/mint-cli/src/interactive.rs +37 -5
  22. package/crates/mint-cli/src/main.rs +23 -2
  23. package/crates/mint-cli/src/onboard.rs +3494 -1336
  24. package/crates/mint-cli/tests/mods_testing.rs +5 -1
  25. package/crates/mint-companion-protocol/src/lib.rs +113 -0
  26. package/crates/mint-core/src/agent/chat.rs +240 -1
  27. package/crates/mint-core/src/agent/memory.rs +73 -6
  28. package/crates/mint-core/src/agent/safety.rs +56 -4
  29. package/crates/mint-core/src/agent/skill_inventory.rs +3 -1
  30. package/crates/mint-core/src/agent/skills.rs +1 -0
  31. package/crates/mint-core/src/api_server/routes/auth.rs +1 -4
  32. package/crates/mint-core/src/api_server/routes/chat.rs +29 -15
  33. package/crates/mint-core/src/api_server/routes/misc.rs +116 -0
  34. package/crates/mint-core/src/api_server/routes/profile_oauth.rs +43 -26
  35. package/crates/mint-core/src/api_server/routes/sessions.rs +93 -76
  36. package/crates/mint-core/src/api_server/routes/skills_subagents.rs +11 -7
  37. package/crates/mint-core/src/api_server/routes/status_health.rs +18 -8
  38. package/crates/mint-core/src/api_server.rs +211 -65
  39. package/crates/mint-core/src/avatar_bridge.rs +5 -2
  40. package/crates/mint-core/src/browser/cdp.rs +82 -26
  41. package/crates/mint-core/src/browser/lifecycle.rs +143 -43
  42. package/crates/mint-core/src/browser/mod.rs +5 -4
  43. package/crates/mint-core/src/browser/navigate.rs +82 -9
  44. package/crates/mint-core/src/browser/runtime.rs +284 -0
  45. package/crates/mint-core/src/browser/session.rs +263 -7
  46. package/crates/mint-core/src/browser/workflow.rs +386 -0
  47. package/crates/mint-core/src/companion/navigation.rs +115 -0
  48. package/crates/mint-core/src/companion.rs +109 -1
  49. package/crates/mint-core/src/integrations/mcp_result.rs +45 -0
  50. package/crates/mint-core/src/lib.rs +10 -6
  51. package/crates/mint-core/src/media/image_proxy.rs +563 -0
  52. package/crates/mint-core/src/media/tool_images.rs +196 -0
  53. package/crates/mint-core/src/media/tts/playback.rs +609 -0
  54. package/crates/mint-core/src/media/tts.rs +1 -0
  55. package/crates/mint-core/src/media.rs +2 -0
  56. package/crates/mint-core/src/orchestration/context_render.rs +450 -33
  57. package/crates/mint-core/src/orchestration/decision_parsing.rs +5 -23
  58. package/crates/mint-core/src/orchestration/diagnostics.rs +307 -0
  59. package/crates/mint-core/src/orchestration/image_regressions.rs +379 -0
  60. package/crates/mint-core/src/orchestration/loop_guard.rs +334 -0
  61. package/crates/mint-core/src/orchestration/mod.rs +1104 -560
  62. package/crates/mint-core/src/orchestration/reliability.rs +541 -0
  63. package/crates/mint-core/src/orchestration/repeated_failures.rs +8 -0
  64. package/crates/mint-core/src/orchestration/review_regressions.rs +174 -28
  65. package/crates/mint-core/src/orchestration/tools/files.rs +31 -3
  66. package/crates/mint-core/src/orchestration/tools/plugins_mcp.rs +19 -4
  67. package/crates/mint-core/src/orchestration/tools/project.rs +1 -1
  68. package/crates/mint-core/src/orchestration/tools/shell.rs +29 -5
  69. package/crates/mint-core/src/orchestration/tools/web.rs +5 -1
  70. package/crates/mint-core/src/orchestration/trajectory_schema.rs +353 -0
  71. package/crates/mint-core/src/orchestration/truncation.rs +211 -0
  72. package/crates/mint-core/src/orchestration/verification.rs +36 -6
  73. package/crates/mint-core/src/orchestration/workspace_helpers.rs +54 -23
  74. package/crates/mint-core/src/prompts/agent.rs +31 -40
  75. package/crates/mint-core/src/prompts/tool_catalog.rs +134 -40
  76. package/crates/mint-core/src/search/web_search.rs +44 -3
  77. package/crates/mint-core/src/slash/mod.rs +464 -1
  78. package/crates/mint-core/src/swarm/batch.rs +643 -0
  79. package/crates/mint-core/src/swarm/dossier.rs +152 -0
  80. package/crates/mint-core/src/swarm/labels.rs +100 -0
  81. package/crates/mint-core/src/swarm/mod.rs +158 -0
  82. package/crates/mint-core/src/swarm/permissions.rs +167 -0
  83. package/crates/mint-core/src/system/auth.rs +156 -7
  84. package/crates/mint-core/src/system/bg_shell.rs +77 -9
  85. package/crates/mint-core/src/system/config.rs +92 -3
  86. package/crates/mint-core/src/system/mint_web.rs +33 -12
  87. package/crates/mint-core/src/system/shell.rs +179 -10
  88. package/crates/mint-core/src/system/workspace.rs +204 -0
  89. package/crates/mint-core/tests/background_retention.rs +1 -1
  90. package/crates/mint-core/tests/memory_persistence.rs +27 -0
  91. package/out/web/assets/ArtifactPreviewPanel-DAT_Y7i0.css +1 -0
  92. package/out/web/assets/ArtifactPreviewPanel-S0dPfYFx.js +2 -0
  93. package/out/web/assets/CalculationCard-CRjP3E1j.js +1 -0
  94. package/out/web/assets/{CliSessionsView-CtzUJpK_.css → CliSessionsView-C3Br2v5Y.css} +1 -1
  95. package/out/web/assets/CliSessionsView-MI8kXMAb.js +1 -0
  96. package/out/web/assets/CodeReviewPage-CUJceQme.css +1 -0
  97. package/out/web/assets/CodeReviewPage-VCUgPla_.js +2 -0
  98. package/out/web/assets/CommandPalette-BD8SlTE5.js +1 -0
  99. package/out/web/assets/ImageGenCard-BCXxkVJX.js +1 -0
  100. package/out/web/assets/ImageSearchCard-N3yQOr8Z.js +1 -0
  101. package/out/web/assets/ImageStudioPanel-BP7N4rLr.js +1 -0
  102. package/out/web/assets/LibraryPage-WlviRdR8.js +2 -0
  103. package/out/web/assets/LinkedFoldersView-CKRgroWK.js +1 -0
  104. package/out/web/assets/McpRegistryPicker-CoS83vtc.js +1 -0
  105. package/out/web/assets/McpServersView-D3wHnuHg.js +1 -0
  106. package/out/web/assets/MermaidCard-NqrHdyJW.js +2 -0
  107. package/out/web/assets/MintDashboard-B2DJsDDO.css +1 -0
  108. package/out/web/assets/MintDashboard-COw_xol7.js +63 -0
  109. package/out/web/assets/PluginsView-jBYmcKh4.js +1 -0
  110. package/out/web/assets/RewindModal-DempuDod.js +1 -0
  111. package/out/web/assets/ScheduledTasksView-5uw9-V9H.js +1 -0
  112. package/out/web/assets/SelectField-DXBQtrUK.js +1 -0
  113. package/out/web/assets/SelectField-lFEkkWCU.css +1 -0
  114. package/out/web/assets/SettingsWindow-2YP3yj7s.js +4 -0
  115. package/out/web/assets/SettingsWindow-Dz8LQVgD.css +1 -0
  116. package/out/web/assets/SkillsView-C-gp9J7m.js +2 -0
  117. package/out/web/assets/StockCard-BDMCe7mx.js +1 -0
  118. package/out/web/assets/ToolSurfacePage-B0J_q0Jl.js +38 -0
  119. package/out/web/assets/ToolSurfacePage-CRIQ1owD.css +1 -0
  120. package/out/web/assets/UiFeatureCard-6BwxTOCe.js +1 -0
  121. package/out/web/assets/UiGridCard-DvZcLNxb.js +1 -0
  122. package/out/web/assets/UiMockupWidget-DD73QWg1.js +1 -0
  123. package/out/web/assets/VeoStudioPanel-DfsOJKv0.js +4 -0
  124. package/out/web/assets/WeatherCard-CPucIfq8.js +1 -0
  125. package/out/web/assets/WorkspacePanel-BfHKkulU.js +1 -0
  126. package/out/web/assets/WorkspacePdfPreview-Dx_lkjNu.js +2 -0
  127. package/out/web/assets/abnfDiagram-VCTEODGH-BOo3Ckng.js +1 -0
  128. package/out/web/assets/architecture-7GRP2DOG-ZOwheW3n.js +1 -0
  129. package/out/web/assets/architectureDiagram-5GKGNRK7-DC2FDzVd.js +36 -0
  130. package/out/web/assets/{blockDiagram-NRAW4CY4-BrrqzHW5.js → blockDiagram-I7D4REHJ-BrKFWdAH.js} +4 -4
  131. package/out/web/assets/c4Diagram-7LVT6UL2-BHTHK1Yd.js +38 -0
  132. package/out/web/assets/chunk-2Q5K7J3B-D2JLPQzF.js +1 -0
  133. package/out/web/assets/{chunk-TEH6E4GO-G4Cdlyrt.js → chunk-4HAMMTFA-BYFkZwNj.js} +3 -3
  134. package/out/web/assets/{chunk-5VM5RSS4-BiPuE0io.js → chunk-5VM5RSS4-BZ2oBPYQ.js} +1 -1
  135. package/out/web/assets/chunk-75Z2AOVW-BSKfSKSA.js +2 -0
  136. package/out/web/assets/chunk-DU6HZSFF-vIhsiW6n.js +128 -0
  137. package/out/web/assets/chunk-F27PBJKO-BlYpW9xq.js +1 -0
  138. package/out/web/assets/chunk-FOHPRMQF-JXEeeJ9r.js +161 -0
  139. package/out/web/assets/{chunk-GMAD6QVW-BuhEcgHq.js → chunk-GMAD6QVW-BIBz_Ug5.js} +12 -12
  140. package/out/web/assets/chunk-GVQU2GXP-NPSHxeqC.js +1 -0
  141. package/out/web/assets/chunk-IMKFNOWR-YlJK8_Fp.js +231 -0
  142. package/out/web/assets/chunk-JWPE2WC7-BeEMUFDw.js +1 -0
  143. package/out/web/assets/chunk-L3NEJ4N5-DMYi4-af.js +1 -0
  144. package/out/web/assets/chunk-OSK3NFVY-Begd3-jA.js +10 -0
  145. package/out/web/assets/chunk-P2QGCYS3-D1I4xFHN.js +1 -0
  146. package/out/web/assets/chunk-POPQ4Y6H-CafZZzNE.js +1 -0
  147. package/out/web/assets/chunk-PWAF6VOD-Dwh6_Lnt.js +1 -0
  148. package/out/web/assets/chunk-SHT3W25Y-B0XrCSEb.js +168 -0
  149. package/out/web/assets/{chunk-SVP7TREG-Bu_yYb-V.js → chunk-SVP7TREG-CxLsddxC.js} +1 -1
  150. package/out/web/assets/{chunk-LCL6LL3I-BhXV9zyH.js → chunk-TICWLB2K-y156QInb.js} +4 -4
  151. package/out/web/assets/chunk-XXDRQBXY-B9YlhOkE.js +1 -0
  152. package/out/web/assets/chunk-Y2CYZVJY-BxCWjNVG.js +1 -0
  153. package/out/web/assets/classDiagram-ZZMXUADV-BgJ5WtSp.js +1 -0
  154. package/out/web/assets/classDiagram-v2-VYDZK3BY-BgJ5WtSp.js +1 -0
  155. package/out/web/assets/config-CvIO5hkn.js +2 -0
  156. package/out/web/assets/config-DqXJXeZM.css +1 -0
  157. package/out/web/assets/core-Mi3s5D4_.js +1 -0
  158. package/out/web/assets/cose-bilkent-JH36ORCC-qlna31ty.js +1 -0
  159. package/out/web/assets/cynefin-OW5HDTMX-SMVvrLf-.js +1 -0
  160. package/out/web/assets/cynefinDiagram-5FMLGOSQ-rZznN24T.js +62 -0
  161. package/out/web/assets/cytoscape.esm-DWtAUG0r.js +321 -0
  162. package/out/web/assets/dagre-CnWJJM5f.js +1 -0
  163. package/out/web/assets/dagre-GXQ25YYZ-BOToydFu.js +4 -0
  164. package/out/web/assets/diagram-S7CK7UJ4-TMVaGQEJ.js +30 -0
  165. package/out/web/assets/diagram-UQ7AKVKN-C2JK-GP2.js +41 -0
  166. package/out/web/assets/{diagram-VSXAHHWV-BJ86Ov2Y.js → diagram-VSXAHHWV-Cw8VSi2K.js} +1 -1
  167. package/out/web/assets/diagram-VX7I27RA-DXp4fKk9.js +24 -0
  168. package/out/web/assets/diagram-Z3DM3KII-CzSicYiW.js +24 -0
  169. package/out/web/assets/dist-9ISJ7r-g.js +1 -0
  170. package/out/web/assets/dist-js-BV3mI7uw.js +1 -0
  171. package/out/web/assets/ebnfDiagram-PWID7BFC-Dqj-zqPu.js +1 -0
  172. package/out/web/assets/{erDiagram-SSCWMZ5O-CzzmnZWT.js → erDiagram-RLTQ6QDP-DZwFZAuD.js} +3 -3
  173. package/out/web/assets/event-D7D-EBy9.js +1 -0
  174. package/out/web/assets/eventmodeling-NTZA5JFV-C0O-Lvgp.js +1 -0
  175. package/out/web/assets/flowDiagram-HODETNUW-uqCHJond.js +1 -0
  176. package/out/web/assets/ganttDiagram-EL5Y4UJY-Da4ULXTl.js +292 -0
  177. package/out/web/assets/gitGraph-4MIJSDKK-B9wNFZIP.js +1 -0
  178. package/out/web/assets/gitGraphDiagram-WWUBYQGX-RjrhB0MP.js +106 -0
  179. package/out/web/assets/graphlib-Bh9gHply.js +1 -0
  180. package/out/web/assets/index-BmpulIkg.js +168 -0
  181. package/out/web/assets/index-CkvBwhX_.css +1 -0
  182. package/out/web/assets/info-A6RAGUB7-B3dfCpeY.js +1 -0
  183. package/out/web/assets/infoDiagram-27XIBGKW-QVWkLVx7.js +2 -0
  184. package/out/web/assets/{ishikawaDiagram-5VMMS53U-s38yo28y.js → ishikawaDiagram-5VMMS53U-CLFNIRI9.js} +4 -4
  185. package/out/web/assets/journeyDiagram-3NMN7TZE-fgOQadYF.js +139 -0
  186. package/out/web/assets/jsx-runtime-DmUwWVTj.js +1 -0
  187. package/out/web/assets/{kanban-definition-3QL26DDD-DodjgySL.js → kanban-definition-UXKFOSKX-G3Q_9g9O.js} +6 -6
  188. package/out/web/assets/katex-MCdQaEAD.js +257 -0
  189. package/out/web/assets/mermaid-parser.core-v3Jm7nco.js +7 -0
  190. package/out/web/assets/mermaid.core-DTEjLUA1.js +44 -0
  191. package/out/web/assets/{mindmap-definition-FBJOCRG2-260WBDxZ.js → mindmap-definition-YA3MSWOX-C_D42_fF.js} +4 -4
  192. package/out/web/assets/modelManager-BPLycQrN.js +2 -0
  193. package/out/web/assets/oauthManager-BUK7ic7q.js +1 -0
  194. package/out/web/assets/packet-AYTQ26CC-B-R-SHlF.js +1 -0
  195. package/out/web/assets/pdf-Bcahc2yC.js +56 -0
  196. package/out/web/assets/pdf.worker.min-Dkey6ZUl.mjs +27 -0
  197. package/out/web/assets/pegDiagram-XKGWAZYB-Da2q_giz.js +1 -0
  198. package/out/web/assets/pie-WAS4IAKB-BC8F0N7-.js +1 -0
  199. package/out/web/assets/pieDiagram-E7YTZNPT-Iy9REJNC.js +39 -0
  200. package/out/web/assets/{quadrantDiagram-AXDQQJYC-B8D3gU5d.js → quadrantDiagram-AXDQQJYC-ztsiYw7h.js} +4 -4
  201. package/out/web/assets/radar-RG4KPBEZ-B_1P8Z_z.js +1 -0
  202. package/out/web/assets/railroad-74A4TZTK-DuTqczSo.js +1 -0
  203. package/out/web/assets/railroad-abnf-HS5TGJTU-Df29WLmp.js +1 -0
  204. package/out/web/assets/railroad-ebnf-LZEXJU2U-ePFMo-qp.js +1 -0
  205. package/out/web/assets/railroad-peg-WCYAUIDC-DYXLW4_E.js +1 -0
  206. package/out/web/assets/railroadDiagram-O6MQD6OU-LStnZf2S.js +1 -0
  207. package/out/web/assets/{requirementDiagram-EFPCY7ZU-D2X-Ewik.js → requirementDiagram-BXWQKSXE-DmzonMH-.js} +3 -3
  208. package/out/web/assets/rolldown-runtime-CNOWq4Kh.js +1 -0
  209. package/out/web/assets/rough.esm-CNnFptCR.js +1 -0
  210. package/out/web/assets/sankeyDiagram-P5KCCOFB-B8vjmUU1.js +40 -0
  211. package/out/web/assets/sequenceDiagram-WJ2MYXX4-CTnplOAX.js +162 -0
  212. package/out/web/assets/sizeCapture-INFHLROL-C8Q8DbV5.js +1 -0
  213. package/out/web/assets/src-CRDfRlHM.js +1 -0
  214. package/out/web/assets/stateDiagram-D77RDMKH-BFrIaLdI.js +1 -0
  215. package/out/web/assets/stateDiagram-v2-MP3YSRHH-uf3kdNW4.js +1 -0
  216. package/out/web/assets/studio-BBZQ_-QK.js +1 -0
  217. package/out/web/assets/swimlanes-42K2YHIH-BXGngUNU.js +1 -0
  218. package/out/web/assets/swimlanesDiagram-VR7AAH4N-Y8q5bQce.js +8 -0
  219. package/out/web/assets/timeline-definition-24CTP7MA-CegH7n43.js +120 -0
  220. package/out/web/assets/treeView-Q6P3EWNA-DTpJv2Tw.js +1 -0
  221. package/out/web/assets/treemap-WGGIJYW6-i8M9iJU6.js +1 -0
  222. package/out/web/assets/vennDiagram-4TSXK5OY-Dpzo1S8U.js +34 -0
  223. package/out/web/assets/wardley-WFR3VGLG-BrNsgtfw.js +1 -0
  224. package/out/web/assets/{wardleyDiagram-VM6X3IG4-DAdXELbQ.js → wardleyDiagram-VM6X3IG4-lQ92LFE1.js} +35 -35
  225. package/out/web/assets/window-CkUOP7t0.js +1 -0
  226. package/out/web/assets/workspaces-SYPrmbgC.js +1 -0
  227. package/out/web/assets/{xychartDiagram-S5SC5T6Z-IZIXf3Vo.js → xychartDiagram-S5SC5T6Z-BaOaEoBd.js} +4 -4
  228. package/out/web/index-web.html +4 -4
  229. package/out/web/index.html +4 -4
  230. package/out/web/pdfjs/cmaps/78-EUC-H.bcmap +0 -0
  231. package/out/web/pdfjs/cmaps/78-EUC-V.bcmap +0 -0
  232. package/out/web/pdfjs/cmaps/78-H.bcmap +0 -0
  233. package/out/web/pdfjs/cmaps/78-RKSJ-H.bcmap +0 -0
  234. package/out/web/pdfjs/cmaps/78-RKSJ-V.bcmap +0 -0
  235. package/out/web/pdfjs/cmaps/78-V.bcmap +0 -0
  236. package/out/web/pdfjs/cmaps/78ms-RKSJ-H.bcmap +0 -0
  237. package/out/web/pdfjs/cmaps/78ms-RKSJ-V.bcmap +0 -0
  238. package/out/web/pdfjs/cmaps/83pv-RKSJ-H.bcmap +0 -0
  239. package/out/web/pdfjs/cmaps/90ms-RKSJ-H.bcmap +0 -0
  240. package/out/web/pdfjs/cmaps/90ms-RKSJ-V.bcmap +0 -0
  241. package/out/web/pdfjs/cmaps/90msp-RKSJ-H.bcmap +0 -0
  242. package/out/web/pdfjs/cmaps/90msp-RKSJ-V.bcmap +0 -0
  243. package/out/web/pdfjs/cmaps/90pv-RKSJ-H.bcmap +0 -0
  244. package/out/web/pdfjs/cmaps/90pv-RKSJ-V.bcmap +0 -0
  245. package/out/web/pdfjs/cmaps/Add-H.bcmap +0 -0
  246. package/out/web/pdfjs/cmaps/Add-RKSJ-H.bcmap +0 -0
  247. package/out/web/pdfjs/cmaps/Add-RKSJ-V.bcmap +0 -0
  248. package/out/web/pdfjs/cmaps/Add-V.bcmap +0 -0
  249. package/out/web/pdfjs/cmaps/Adobe-CNS1-0.bcmap +0 -0
  250. package/out/web/pdfjs/cmaps/Adobe-CNS1-1.bcmap +0 -0
  251. package/out/web/pdfjs/cmaps/Adobe-CNS1-2.bcmap +0 -0
  252. package/out/web/pdfjs/cmaps/Adobe-CNS1-3.bcmap +0 -0
  253. package/out/web/pdfjs/cmaps/Adobe-CNS1-4.bcmap +0 -0
  254. package/out/web/pdfjs/cmaps/Adobe-CNS1-5.bcmap +0 -0
  255. package/out/web/pdfjs/cmaps/Adobe-CNS1-6.bcmap +0 -0
  256. package/out/web/pdfjs/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
  257. package/out/web/pdfjs/cmaps/Adobe-GB1-0.bcmap +0 -0
  258. package/out/web/pdfjs/cmaps/Adobe-GB1-1.bcmap +0 -0
  259. package/out/web/pdfjs/cmaps/Adobe-GB1-2.bcmap +0 -0
  260. package/out/web/pdfjs/cmaps/Adobe-GB1-3.bcmap +0 -0
  261. package/out/web/pdfjs/cmaps/Adobe-GB1-4.bcmap +0 -0
  262. package/out/web/pdfjs/cmaps/Adobe-GB1-5.bcmap +0 -0
  263. package/out/web/pdfjs/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
  264. package/out/web/pdfjs/cmaps/Adobe-Japan1-0.bcmap +0 -0
  265. package/out/web/pdfjs/cmaps/Adobe-Japan1-1.bcmap +0 -0
  266. package/out/web/pdfjs/cmaps/Adobe-Japan1-2.bcmap +0 -0
  267. package/out/web/pdfjs/cmaps/Adobe-Japan1-3.bcmap +0 -0
  268. package/out/web/pdfjs/cmaps/Adobe-Japan1-4.bcmap +0 -0
  269. package/out/web/pdfjs/cmaps/Adobe-Japan1-5.bcmap +0 -0
  270. package/out/web/pdfjs/cmaps/Adobe-Japan1-6.bcmap +0 -0
  271. package/out/web/pdfjs/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
  272. package/out/web/pdfjs/cmaps/Adobe-Korea1-0.bcmap +0 -0
  273. package/out/web/pdfjs/cmaps/Adobe-Korea1-1.bcmap +0 -0
  274. package/out/web/pdfjs/cmaps/Adobe-Korea1-2.bcmap +0 -0
  275. package/out/web/pdfjs/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
  276. package/out/web/pdfjs/cmaps/B5-H.bcmap +0 -0
  277. package/out/web/pdfjs/cmaps/B5-V.bcmap +0 -0
  278. package/out/web/pdfjs/cmaps/B5pc-H.bcmap +0 -0
  279. package/out/web/pdfjs/cmaps/B5pc-V.bcmap +0 -0
  280. package/out/web/pdfjs/cmaps/CNS-EUC-H.bcmap +0 -0
  281. package/out/web/pdfjs/cmaps/CNS-EUC-V.bcmap +0 -0
  282. package/out/web/pdfjs/cmaps/CNS1-H.bcmap +0 -0
  283. package/out/web/pdfjs/cmaps/CNS1-V.bcmap +0 -0
  284. package/out/web/pdfjs/cmaps/CNS2-H.bcmap +0 -0
  285. package/out/web/pdfjs/cmaps/CNS2-V.bcmap +3 -0
  286. package/out/web/pdfjs/cmaps/ETHK-B5-H.bcmap +0 -0
  287. package/out/web/pdfjs/cmaps/ETHK-B5-V.bcmap +0 -0
  288. package/out/web/pdfjs/cmaps/ETen-B5-H.bcmap +0 -0
  289. package/out/web/pdfjs/cmaps/ETen-B5-V.bcmap +0 -0
  290. package/out/web/pdfjs/cmaps/ETenms-B5-H.bcmap +3 -0
  291. package/out/web/pdfjs/cmaps/ETenms-B5-V.bcmap +0 -0
  292. package/out/web/pdfjs/cmaps/EUC-H.bcmap +0 -0
  293. package/out/web/pdfjs/cmaps/EUC-V.bcmap +0 -0
  294. package/out/web/pdfjs/cmaps/Ext-H.bcmap +0 -0
  295. package/out/web/pdfjs/cmaps/Ext-RKSJ-H.bcmap +0 -0
  296. package/out/web/pdfjs/cmaps/Ext-RKSJ-V.bcmap +0 -0
  297. package/out/web/pdfjs/cmaps/Ext-V.bcmap +0 -0
  298. package/out/web/pdfjs/cmaps/GB-EUC-H.bcmap +0 -0
  299. package/out/web/pdfjs/cmaps/GB-EUC-V.bcmap +0 -0
  300. package/out/web/pdfjs/cmaps/GB-H.bcmap +4 -0
  301. package/out/web/pdfjs/cmaps/GB-V.bcmap +0 -0
  302. package/out/web/pdfjs/cmaps/GBK-EUC-H.bcmap +0 -0
  303. package/out/web/pdfjs/cmaps/GBK-EUC-V.bcmap +0 -0
  304. package/out/web/pdfjs/cmaps/GBK2K-H.bcmap +0 -0
  305. package/out/web/pdfjs/cmaps/GBK2K-V.bcmap +0 -0
  306. package/out/web/pdfjs/cmaps/GBKp-EUC-H.bcmap +0 -0
  307. package/out/web/pdfjs/cmaps/GBKp-EUC-V.bcmap +0 -0
  308. package/out/web/pdfjs/cmaps/GBT-EUC-H.bcmap +0 -0
  309. package/out/web/pdfjs/cmaps/GBT-EUC-V.bcmap +0 -0
  310. package/out/web/pdfjs/cmaps/GBT-H.bcmap +0 -0
  311. package/out/web/pdfjs/cmaps/GBT-V.bcmap +0 -0
  312. package/out/web/pdfjs/cmaps/GBTpc-EUC-H.bcmap +0 -0
  313. package/out/web/pdfjs/cmaps/GBTpc-EUC-V.bcmap +0 -0
  314. package/out/web/pdfjs/cmaps/GBpc-EUC-H.bcmap +0 -0
  315. package/out/web/pdfjs/cmaps/GBpc-EUC-V.bcmap +0 -0
  316. package/out/web/pdfjs/cmaps/H.bcmap +0 -0
  317. package/out/web/pdfjs/cmaps/HKdla-B5-H.bcmap +0 -0
  318. package/out/web/pdfjs/cmaps/HKdla-B5-V.bcmap +0 -0
  319. package/out/web/pdfjs/cmaps/HKdlb-B5-H.bcmap +0 -0
  320. package/out/web/pdfjs/cmaps/HKdlb-B5-V.bcmap +0 -0
  321. package/out/web/pdfjs/cmaps/HKgccs-B5-H.bcmap +0 -0
  322. package/out/web/pdfjs/cmaps/HKgccs-B5-V.bcmap +0 -0
  323. package/out/web/pdfjs/cmaps/HKm314-B5-H.bcmap +0 -0
  324. package/out/web/pdfjs/cmaps/HKm314-B5-V.bcmap +0 -0
  325. package/out/web/pdfjs/cmaps/HKm471-B5-H.bcmap +0 -0
  326. package/out/web/pdfjs/cmaps/HKm471-B5-V.bcmap +0 -0
  327. package/out/web/pdfjs/cmaps/HKscs-B5-H.bcmap +0 -0
  328. package/out/web/pdfjs/cmaps/HKscs-B5-V.bcmap +0 -0
  329. package/out/web/pdfjs/cmaps/Hankaku.bcmap +0 -0
  330. package/out/web/pdfjs/cmaps/Hiragana.bcmap +0 -0
  331. package/out/web/pdfjs/cmaps/KSC-EUC-H.bcmap +0 -0
  332. package/out/web/pdfjs/cmaps/KSC-EUC-V.bcmap +0 -0
  333. package/out/web/pdfjs/cmaps/KSC-H.bcmap +0 -0
  334. package/out/web/pdfjs/cmaps/KSC-Johab-H.bcmap +0 -0
  335. package/out/web/pdfjs/cmaps/KSC-Johab-V.bcmap +0 -0
  336. package/out/web/pdfjs/cmaps/KSC-V.bcmap +0 -0
  337. package/out/web/pdfjs/cmaps/KSCms-UHC-H.bcmap +0 -0
  338. package/out/web/pdfjs/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
  339. package/out/web/pdfjs/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
  340. package/out/web/pdfjs/cmaps/KSCms-UHC-V.bcmap +0 -0
  341. package/out/web/pdfjs/cmaps/KSCpc-EUC-H.bcmap +0 -0
  342. package/out/web/pdfjs/cmaps/KSCpc-EUC-V.bcmap +0 -0
  343. package/out/web/pdfjs/cmaps/Katakana.bcmap +0 -0
  344. package/out/web/pdfjs/cmaps/LICENSE +36 -0
  345. package/out/web/pdfjs/cmaps/NWP-H.bcmap +0 -0
  346. package/out/web/pdfjs/cmaps/NWP-V.bcmap +0 -0
  347. package/out/web/pdfjs/cmaps/RKSJ-H.bcmap +0 -0
  348. package/out/web/pdfjs/cmaps/RKSJ-V.bcmap +0 -0
  349. package/out/web/pdfjs/cmaps/Roman.bcmap +0 -0
  350. package/out/web/pdfjs/cmaps/UniCNS-UCS2-H.bcmap +0 -0
  351. package/out/web/pdfjs/cmaps/UniCNS-UCS2-V.bcmap +0 -0
  352. package/out/web/pdfjs/cmaps/UniCNS-UTF16-H.bcmap +0 -0
  353. package/out/web/pdfjs/cmaps/UniCNS-UTF16-V.bcmap +0 -0
  354. package/out/web/pdfjs/cmaps/UniCNS-UTF32-H.bcmap +0 -0
  355. package/out/web/pdfjs/cmaps/UniCNS-UTF32-V.bcmap +0 -0
  356. package/out/web/pdfjs/cmaps/UniCNS-UTF8-H.bcmap +0 -0
  357. package/out/web/pdfjs/cmaps/UniCNS-UTF8-V.bcmap +0 -0
  358. package/out/web/pdfjs/cmaps/UniGB-UCS2-H.bcmap +0 -0
  359. package/out/web/pdfjs/cmaps/UniGB-UCS2-V.bcmap +0 -0
  360. package/out/web/pdfjs/cmaps/UniGB-UTF16-H.bcmap +0 -0
  361. package/out/web/pdfjs/cmaps/UniGB-UTF16-V.bcmap +0 -0
  362. package/out/web/pdfjs/cmaps/UniGB-UTF32-H.bcmap +0 -0
  363. package/out/web/pdfjs/cmaps/UniGB-UTF32-V.bcmap +0 -0
  364. package/out/web/pdfjs/cmaps/UniGB-UTF8-H.bcmap +0 -0
  365. package/out/web/pdfjs/cmaps/UniGB-UTF8-V.bcmap +0 -0
  366. package/out/web/pdfjs/cmaps/UniJIS-UCS2-H.bcmap +0 -0
  367. package/out/web/pdfjs/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
  368. package/out/web/pdfjs/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
  369. package/out/web/pdfjs/cmaps/UniJIS-UCS2-V.bcmap +0 -0
  370. package/out/web/pdfjs/cmaps/UniJIS-UTF16-H.bcmap +0 -0
  371. package/out/web/pdfjs/cmaps/UniJIS-UTF16-V.bcmap +0 -0
  372. package/out/web/pdfjs/cmaps/UniJIS-UTF32-H.bcmap +0 -0
  373. package/out/web/pdfjs/cmaps/UniJIS-UTF32-V.bcmap +0 -0
  374. package/out/web/pdfjs/cmaps/UniJIS-UTF8-H.bcmap +0 -0
  375. package/out/web/pdfjs/cmaps/UniJIS-UTF8-V.bcmap +0 -0
  376. package/out/web/pdfjs/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
  377. package/out/web/pdfjs/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
  378. package/out/web/pdfjs/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
  379. package/out/web/pdfjs/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
  380. package/out/web/pdfjs/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
  381. package/out/web/pdfjs/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
  382. package/out/web/pdfjs/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
  383. package/out/web/pdfjs/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
  384. package/out/web/pdfjs/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
  385. package/out/web/pdfjs/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
  386. package/out/web/pdfjs/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
  387. package/out/web/pdfjs/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
  388. package/out/web/pdfjs/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
  389. package/out/web/pdfjs/cmaps/UniKS-UCS2-H.bcmap +0 -0
  390. package/out/web/pdfjs/cmaps/UniKS-UCS2-V.bcmap +0 -0
  391. package/out/web/pdfjs/cmaps/UniKS-UTF16-H.bcmap +0 -0
  392. package/out/web/pdfjs/cmaps/UniKS-UTF16-V.bcmap +0 -0
  393. package/out/web/pdfjs/cmaps/UniKS-UTF32-H.bcmap +0 -0
  394. package/out/web/pdfjs/cmaps/UniKS-UTF32-V.bcmap +0 -0
  395. package/out/web/pdfjs/cmaps/UniKS-UTF8-H.bcmap +0 -0
  396. package/out/web/pdfjs/cmaps/UniKS-UTF8-V.bcmap +0 -0
  397. package/out/web/pdfjs/cmaps/V.bcmap +0 -0
  398. package/out/web/pdfjs/cmaps/WP-Symbol.bcmap +0 -0
  399. package/out/web/pdfjs/standard_fonts/FoxitDingbats.pfb +0 -0
  400. package/out/web/pdfjs/standard_fonts/FoxitFixed.pfb +0 -0
  401. package/out/web/pdfjs/standard_fonts/FoxitFixedBold.pfb +0 -0
  402. package/out/web/pdfjs/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
  403. package/out/web/pdfjs/standard_fonts/FoxitFixedItalic.pfb +0 -0
  404. package/out/web/pdfjs/standard_fonts/FoxitSerif.pfb +0 -0
  405. package/out/web/pdfjs/standard_fonts/FoxitSerifBold.pfb +0 -0
  406. package/out/web/pdfjs/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
  407. package/out/web/pdfjs/standard_fonts/FoxitSerifItalic.pfb +0 -0
  408. package/out/web/pdfjs/standard_fonts/FoxitSymbol.pfb +0 -0
  409. package/out/web/pdfjs/standard_fonts/LICENSE_FOXIT +27 -0
  410. package/out/web/pdfjs/standard_fonts/LICENSE_LIBERATION +363 -0
  411. package/out/web/pdfjs/standard_fonts/LiberationSans-Bold.ttf +0 -0
  412. package/out/web/pdfjs/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
  413. package/out/web/pdfjs/standard_fonts/LiberationSans-Italic.ttf +0 -0
  414. package/out/web/pdfjs/standard_fonts/LiberationSans-Regular.ttf +0 -0
  415. package/out/web/pdfjs/wasm/LICENSE_JBIG2 +196 -0
  416. package/out/web/pdfjs/wasm/LICENSE_OPENJPEG +39 -0
  417. package/out/web/pdfjs/wasm/LICENSE_PDFJS_JBIG2 +13 -0
  418. package/out/web/pdfjs/wasm/LICENSE_PDFJS_OPENJPEG +22 -0
  419. package/out/web/pdfjs/wasm/LICENSE_PDFJS_QCMS +19 -0
  420. package/out/web/pdfjs/wasm/LICENSE_QCMS +21 -0
  421. package/out/web/pdfjs/wasm/jbig2.wasm +0 -0
  422. package/out/web/pdfjs/wasm/jbig2_nowasm_fallback.js +15 -0
  423. package/out/web/pdfjs/wasm/openjpeg.wasm +0 -0
  424. package/out/web/pdfjs/wasm/openjpeg_nowasm_fallback.js +17 -0
  425. package/out/web/pdfjs/wasm/qcms_bg.wasm +0 -0
  426. package/out/web/pdfjs/wasm/quickjs-eval.js +16 -0
  427. package/out/web/pdfjs/wasm/quickjs-eval.wasm +0 -0
  428. package/package.json +6 -4
  429. package/slash-commands.json +8 -2
  430. package/src/bin/index.js +4 -1
  431. package/src/bin/pdfjs-assets.mjs +31 -0
  432. package/src/renderer/node_modules/.vite/vitest/CACHEDIR.TAG +3 -0
  433. package/src/renderer/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  434. package/src/renderer/shared/agentProgress.ts +11 -2
  435. package/src/renderer/shared/components/Settings/AgentsTab.tsx +70 -6
  436. package/src/renderer/shared/components/Settings/AudioTab.tsx +1 -1
  437. package/src/renderer/shared/components/Settings/AutomationTab.tsx +57 -0
  438. package/src/renderer/shared/components/Settings/AvatarCropModal.tsx +18 -12
  439. package/src/renderer/shared/components/Settings/CustomProviderLogoPicker.test.tsx +65 -0
  440. package/src/renderer/shared/components/Settings/CustomProviderLogoPicker.tsx +456 -0
  441. package/src/renderer/shared/components/Settings/GeneralTab.tsx +40 -82
  442. package/src/renderer/shared/components/Settings/PluginsTab.tsx +101 -24
  443. package/src/renderer/shared/components/Settings/ProfileTab.tsx +1 -1
  444. package/src/renderer/shared/components/Settings/SettingsWindow.tsx +796 -0
  445. package/src/renderer/shared/components/Settings/ThemeTab.tsx +13 -1
  446. package/src/renderer/shared/components/{AgentActivityDrawer.tsx → activity/AgentActivityDrawer.tsx} +77 -61
  447. package/src/renderer/shared/components/{AgentActivityTable.tsx → activity/AgentActivityTable.tsx} +46 -7
  448. package/src/renderer/shared/components/{McpToolResults.tsx → activity/McpToolResults.tsx} +32 -13
  449. package/src/renderer/shared/components/{PlanChecklistWidget.tsx → activity/PlanChecklistWidget.tsx} +2 -2
  450. package/src/renderer/shared/components/activity/RunSummaryDashboard.test.tsx +127 -0
  451. package/src/renderer/shared/components/activity/RunSummaryDashboard.tsx +222 -0
  452. package/src/renderer/shared/components/activity/SubagentDagView.test.ts +123 -0
  453. package/src/renderer/shared/components/{SubagentDagView.tsx → activity/SubagentDagView.tsx} +97 -43
  454. package/src/renderer/shared/components/activity/SubagentStatusStrip.test.tsx +82 -0
  455. package/src/renderer/shared/components/activity/SubagentStatusStrip.tsx +107 -0
  456. package/src/renderer/shared/components/activity/ViewedImages.tsx +140 -0
  457. package/src/renderer/shared/components/{AuthGate.tsx → app/AuthGate.tsx} +3 -3
  458. package/src/renderer/shared/components/{ChunkErrorBoundary.tsx → app/ChunkErrorBoundary.tsx} +10 -10
  459. package/src/renderer/shared/components/{CommandPalette.tsx → app/CommandPalette.tsx} +25 -25
  460. package/src/renderer/shared/components/{DashboardSidebar.tsx → app/DashboardSidebar.tsx} +7 -5
  461. package/src/renderer/shared/components/{DesktopTitlebar.tsx → app/DesktopTitlebar.tsx} +7 -24
  462. package/src/renderer/shared/components/{ErrorNotice.tsx → app/ErrorNotice.tsx} +1 -1
  463. package/src/renderer/shared/components/{MintDashboard.tsx → app/MintDashboard.tsx} +191 -212
  464. package/src/renderer/shared/components/{ModalErrorBoundary.tsx → app/ModalErrorBoundary.tsx} +5 -5
  465. package/src/renderer/shared/components/{CalculationCard.tsx → cards/CalculationCard.tsx} +13 -27
  466. package/src/renderer/shared/components/{ImageGenCard.tsx → cards/ImageGenCard.tsx} +9 -22
  467. package/src/renderer/shared/components/{ImageSearchCard.tsx → cards/ImageSearchCard.tsx} +9 -22
  468. package/src/renderer/shared/components/{MermaidCard.tsx → cards/MermaidCard.tsx} +37 -21
  469. package/src/renderer/shared/components/{StockCard.tsx → cards/StockCard.tsx} +15 -31
  470. package/src/renderer/shared/components/cards/ToolResultCards.tsx +86 -0
  471. package/src/renderer/shared/components/{UiFeatureCard.tsx → cards/UiFeatureCard.tsx} +6 -6
  472. package/src/renderer/shared/components/{UiGridCard.tsx → cards/UiGridCard.tsx} +3 -3
  473. package/src/renderer/shared/components/{WeatherCard.tsx → cards/WeatherCard.tsx} +1 -1
  474. package/src/renderer/shared/components/{ApprovalCard.test.tsx → chat/ApprovalCard.test.tsx} +1 -1
  475. package/src/renderer/shared/components/{ApprovalCard.tsx → chat/ApprovalCard.tsx} +5 -5
  476. package/src/renderer/shared/components/{ChatCodeBlock.tsx → chat/ChatCodeBlock.tsx} +1 -1
  477. package/src/renderer/shared/components/{ChatMessageItem.test.tsx → chat/ChatMessageItem.test.tsx} +92 -15
  478. package/src/renderer/shared/components/{ChatMessageItem.tsx → chat/ChatMessageItem.tsx} +73 -157
  479. package/src/renderer/shared/components/chat/ChatPanel.test.tsx +31 -0
  480. package/src/renderer/shared/components/{ChatPanel.tsx → chat/ChatPanel.tsx} +244 -493
  481. package/src/renderer/shared/components/{CollapsiblePasteInput.tsx → chat/CollapsiblePasteInput.tsx} +2 -2
  482. package/src/renderer/shared/components/{DiffReviewModal.tsx → chat/DiffReviewModal.tsx} +40 -40
  483. package/src/renderer/shared/components/{GeminiLiveOverlay.tsx → chat/GeminiLiveOverlay.tsx} +2 -2
  484. package/src/renderer/shared/components/{ModelSelectorPopover.tsx → chat/ModelSelectorPopover.tsx} +3 -3
  485. package/src/renderer/shared/components/chat/QueuedMessagesBanner.test.tsx +89 -0
  486. package/src/renderer/shared/components/chat/QueuedMessagesBanner.tsx +201 -0
  487. package/src/renderer/shared/components/{RewindModal.tsx → chat/RewindModal.tsx} +4 -4
  488. package/src/renderer/shared/components/{SlashChoicePanel.tsx → chat/SlashChoicePanel.tsx} +2 -2
  489. package/src/renderer/shared/components/{SlashSuggestions.tsx → chat/SlashSuggestions.tsx} +4 -4
  490. package/src/renderer/shared/components/{SourcesBlock.tsx → chat/SourcesBlock.tsx} +30 -37
  491. package/src/renderer/shared/components/{ThinkingBlock.tsx → chat/ThinkingBlock.tsx} +1 -1
  492. package/src/renderer/shared/components/chat/TurnFileChanges.test.tsx +86 -0
  493. package/src/renderer/shared/components/chat/TurnFileChanges.tsx +430 -0
  494. package/src/renderer/shared/components/{VoicePill.css → chat/VoicePill.css} +1 -1
  495. package/src/renderer/shared/components/{VoicePill.jsx → chat/VoicePill.jsx} +3 -2
  496. package/src/renderer/shared/components/{CliSessionsView.test.tsx → extensions/CliSessionsView.test.tsx} +2 -2
  497. package/src/renderer/shared/components/{CliSessionsView.tsx → extensions/CliSessionsView.tsx} +14 -12
  498. package/src/renderer/shared/components/{LinkedFoldersView.tsx → extensions/LinkedFoldersView.tsx} +3 -3
  499. package/src/renderer/shared/components/{McpRegistryPicker.tsx → extensions/McpRegistryPicker.tsx} +3 -3
  500. package/src/renderer/shared/components/{McpServersView.tsx → extensions/McpServersView.tsx} +105 -36
  501. package/src/renderer/shared/components/{McpToolAllowlist.tsx → extensions/McpToolAllowlist.tsx} +2 -2
  502. package/src/renderer/shared/components/{ModUi.test.tsx → extensions/ModUi.test.tsx} +9 -4
  503. package/src/renderer/shared/components/{ModsPanel.tsx → extensions/ModsPanel.tsx} +59 -7
  504. package/src/renderer/shared/components/{PluginsView.tsx → extensions/PluginsView.tsx} +6 -6
  505. package/src/renderer/shared/components/{ScheduledTasksView.tsx → extensions/ScheduledTasksView.tsx} +5 -5
  506. package/src/renderer/shared/components/extensions/SkillsView.test.tsx +31 -0
  507. package/src/renderer/shared/components/{SkillsView.tsx → extensions/SkillsView.tsx} +20 -4
  508. package/src/renderer/shared/components/{ImageStudioPanel.tsx → studio/ImageStudioPanel.tsx} +6 -6
  509. package/src/renderer/shared/components/{LibraryItemCard.tsx → studio/LibraryItemCard.tsx} +2 -2
  510. package/src/renderer/shared/components/{LibraryPage.tsx → studio/LibraryPage.tsx} +5 -5
  511. package/src/renderer/shared/components/{LibraryPreview.tsx → studio/LibraryPreview.tsx} +2 -2
  512. package/src/renderer/shared/components/{VeoStudioPanel.tsx → studio/VeoStudioPanel.tsx} +7 -7
  513. package/src/renderer/shared/components/{GlideSelect.css → ui/GlideSelect.css} +7 -6
  514. package/src/renderer/shared/components/ui/ProviderBrandIcon.test.tsx +67 -0
  515. package/src/renderer/shared/components/ui/ProviderBrandIcon.tsx +167 -0
  516. package/src/renderer/shared/components/ui/SelectField.tsx +506 -0
  517. package/src/renderer/shared/components/ui/error-recovery.css +10 -10
  518. package/src/renderer/shared/components/ui/error-recovery.tsx +1 -1
  519. package/src/renderer/shared/components/{ArtifactPreviewPanel.tsx → workspace/ArtifactPreviewPanel.tsx} +256 -112
  520. package/src/renderer/shared/components/workspace/BackgroundTerminals.test.tsx +63 -0
  521. package/src/renderer/shared/components/{BackgroundTerminals.tsx → workspace/BackgroundTerminals.tsx} +40 -9
  522. package/src/renderer/shared/components/{CodeReviewPage.tsx → workspace/CodeReviewPage.tsx} +47 -8
  523. package/src/renderer/shared/components/{GitBranchSelector.tsx → workspace/GitBranchSelector.tsx} +2 -2
  524. package/src/renderer/shared/components/workspace/SessionSources.tsx +113 -0
  525. package/src/renderer/shared/components/{TerminalDock.tsx → workspace/TerminalDock.tsx} +5 -2
  526. package/src/renderer/shared/components/workspace/ToolSurfacePage.test.tsx +68 -0
  527. package/src/renderer/shared/components/{ToolSurfacePage.tsx → workspace/ToolSurfacePage.tsx} +322 -71
  528. package/src/renderer/shared/components/{ToolsPanelToggle.tsx → workspace/ToolsPanelToggle.tsx} +1 -1
  529. package/src/renderer/shared/components/workspace/WorkspaceFileInfo.tsx +28 -0
  530. package/src/renderer/shared/components/workspace/WorkspaceMediaPreview.tsx +17 -0
  531. package/src/renderer/shared/components/{WorkspacePaneResizer.tsx → workspace/WorkspacePaneResizer.tsx} +1 -1
  532. package/src/renderer/shared/components/workspace/WorkspacePdfPreview.tsx +89 -0
  533. package/src/renderer/shared/components/{WorkspacePreviewActions.test.tsx → workspace/WorkspacePreviewActions.test.tsx} +48 -3
  534. package/src/renderer/shared/components/{WorkspacePreviewActions.tsx → workspace/WorkspacePreviewActions.tsx} +3 -3
  535. package/src/renderer/shared/components/{WorkspaceSelector.tsx → workspace/WorkspaceSelector.tsx} +99 -7
  536. package/src/renderer/shared/components/{workspace-selector.css → workspace/workspace-selector.css} +84 -2
  537. package/src/renderer/shared/constants/config.ts +7 -0
  538. package/src/renderer/shared/conversation/coordinator.test.ts +46 -0
  539. package/src/renderer/shared/conversation/coordinator.ts +50 -2
  540. package/src/renderer/shared/conversation/lifecycle.test.ts +163 -1
  541. package/src/renderer/shared/conversation/lifecycle.ts +164 -7
  542. package/src/renderer/shared/conversation/projectNavigation.test.ts +18 -0
  543. package/src/renderer/shared/conversation/projectNavigation.ts +11 -0
  544. package/src/renderer/shared/conversation/transport.test.ts +20 -0
  545. package/src/renderer/shared/conversation/transport.ts +51 -9
  546. package/src/renderer/shared/conversation/useConversationCoordinator.ts +42 -12
  547. package/src/renderer/shared/css/agent-observability.css +72 -11
  548. package/src/renderer/shared/css/chat-ui-cards.css +35 -35
  549. package/src/renderer/shared/css/code-review.css +86 -86
  550. package/src/renderer/shared/css/code-sessions.css +10 -10
  551. package/src/renderer/shared/css/file-changes.css +167 -5
  552. package/src/renderer/shared/css/management-views.css +78 -37
  553. package/src/renderer/shared/css/mcp-results.css +46 -3
  554. package/src/renderer/shared/css/queued-messages.css +221 -0
  555. package/src/renderer/shared/css/session-sources.css +12 -7
  556. package/src/renderer/shared/css/settings/agents.css +2 -2
  557. package/src/renderer/{src-web → shared}/css/settings/base.css +101 -107
  558. package/src/renderer/shared/css/settings/general.css +384 -92
  559. package/src/renderer/shared/css/settings/plugins.css +8 -8
  560. package/src/renderer/shared/css/settings/theme.css +44 -32
  561. package/src/renderer/shared/css/ui-tailwind.css +2 -2
  562. package/src/renderer/shared/css/viewed-images.css +89 -0
  563. package/src/renderer/shared/css/workspace-file-info.css +12 -0
  564. package/src/renderer/shared/css/workspace-media-preview.css +13 -0
  565. package/src/renderer/shared/env.d.ts +9 -0
  566. package/src/renderer/shared/platform.test.ts +143 -0
  567. package/src/renderer/shared/platform.ts +10 -4
  568. package/src/renderer/shared/speech/player.ts +160 -0
  569. package/src/renderer/shared/speech/types.ts +11 -0
  570. package/src/renderer/shared/theme/themeManager.test.ts +20 -0
  571. package/src/renderer/shared/theme/themeManager.ts +3 -1
  572. package/src/renderer/shared/theme/themes.ts +17 -4
  573. package/src/renderer/shared/theme/tokens.css +448 -51
  574. package/src/renderer/shared/types.ts +56 -1
  575. package/src/renderer/shared/utils/agentActivity.test.ts +165 -6
  576. package/src/renderer/shared/utils/agentActivity.ts +181 -31
  577. package/src/renderer/shared/utils/artifactBrowser.ts +1 -1
  578. package/src/renderer/shared/utils/artifacts.ts +55 -0
  579. package/src/renderer/shared/utils/contextCompaction.test.tsx +1 -1
  580. package/src/renderer/shared/utils/externalLinks.ts +91 -0
  581. package/src/renderer/shared/utils/lazyWithRetry.ts +13 -0
  582. package/src/renderer/shared/utils/markdown.tsx +169 -35
  583. package/src/renderer/shared/utils/markdown.webImages.test.tsx +124 -2
  584. package/src/renderer/shared/utils/mcpResults.test.tsx +24 -1
  585. package/src/renderer/shared/utils/pdfRange.ts +16 -0
  586. package/src/renderer/shared/utils/previewObjectUrls.ts +20 -0
  587. package/src/renderer/shared/utils/sessionSources.test.ts +41 -1
  588. package/src/renderer/shared/utils/sessionSources.ts +2 -0
  589. package/src/renderer/shared/utils/slashCommandProcessor.ts +4 -1
  590. package/src/renderer/shared/utils/speech.ts +18 -4
  591. package/src/renderer/shared/utils/useNativeVoiceInput.ts +19 -5
  592. package/src/renderer/shared/utils/useSessionSources.ts +4 -0
  593. package/src/renderer/shared/utils/viewedImages.test.ts +129 -0
  594. package/src/renderer/shared/utils/viewedImages.ts +81 -10
  595. package/src/renderer/shared/utils/workspaceDrag.ts +30 -0
  596. package/src/renderer/shared/utils/workspaceImage.ts +17 -0
  597. package/src/renderer/shared/utils/workspaceListPreferences.test.ts +64 -0
  598. package/src/renderer/shared/utils/workspaceListPreferences.ts +54 -0
  599. package/src/renderer/shared/utils/workspaceMedia.ts +41 -0
  600. package/src/renderer/shared/utils/workspacePreview.test.ts +147 -2
  601. package/src/renderer/shared/utils/workspacePreview.ts +34 -3
  602. package/src/renderer/shared/utils/workspaces.ts +3 -2
  603. package/src/renderer/src/App.tsx +6 -8
  604. package/src/renderer/src/components/ChatPanel.tsx +1 -1
  605. package/src/renderer/src/components/DashboardSidebar.tsx +2 -2
  606. package/src/renderer/src/components/ImageStudioPanel.tsx +1 -1
  607. package/src/renderer/src/components/LiveTranslateControls.tsx +1 -1
  608. package/src/renderer/src/components/MintDashboard.tsx +1 -1
  609. package/src/renderer/src/components/ProactiveGlow.tsx +1 -1
  610. package/src/renderer/src/components/ScreenPicker.tsx +1 -1
  611. package/src/renderer/src/components/SettingsWindow.tsx +6 -830
  612. package/src/renderer/src/components/SpotlightWindow.tsx +4 -32
  613. package/src/renderer/src/components/VeoStudioPanel.tsx +1 -1
  614. package/src/renderer/src/components/WorkspacePanel.tsx +45 -12
  615. package/src/renderer/src/components/browser-shell.css +26 -26
  616. package/src/renderer/src/components/browser-suggestions-popup.css +8 -8
  617. package/src/renderer/src/css/app-shell.css +22 -102
  618. package/src/renderer/src/css/chat.css +221 -34
  619. package/src/renderer/src/css/desktop-tools.css +6 -337
  620. package/src/renderer/src/css/sidebar-workspace.css +20 -0
  621. package/src/renderer/src/css/spotlight.css +2 -2
  622. package/src/renderer/src/css/tool-surfaces.css +328 -58
  623. package/src/renderer/src/css/widget.css +6 -5
  624. package/src/renderer/src/env.d.ts +13 -0
  625. package/src/renderer/src/index.css +15 -63
  626. package/src/renderer/src/tauri.ts +77 -11
  627. package/src/renderer/src/voiceInput.ts +3 -1
  628. package/src/renderer/src-web/App.tsx +6 -8
  629. package/src/renderer/src-web/components/ChatPanel.tsx +1 -1
  630. package/src/renderer/src-web/components/DashboardSidebar.tsx +2 -2
  631. package/src/renderer/src-web/components/ImageStudioPanel.tsx +1 -1
  632. package/src/renderer/src-web/components/MintDashboard.tsx +1 -1
  633. package/src/renderer/src-web/components/SettingsWindow.tsx +6 -851
  634. package/src/renderer/src-web/components/VeoStudioPanel.tsx +1 -1
  635. package/src/renderer/src-web/css/app-shell.css +16 -100
  636. package/src/renderer/src-web/css/chat.css +221 -34
  637. package/src/renderer/src-web/css/sidebar-workspace.css +20 -0
  638. package/src/renderer/src-web/env.d.ts +14 -0
  639. package/src/renderer/src-web/index.css +15 -63
  640. package/src/renderer/src-web/tauri.ts +71 -13
  641. package/src/renderer/tests/browserArtifacts.browser.html +1 -0
  642. package/src/renderer/tests/browserArtifacts.browser.tsx +68 -0
  643. package/src/renderer/tests/chatEscape.browser.html +1 -0
  644. package/src/renderer/tests/chatEscape.browser.tsx +25 -0
  645. package/src/renderer/tests/chatPerformance.browser.html +1 -1
  646. package/src/renderer/tests/collapsedPaste.browser.html +1 -1
  647. package/src/renderer/tests/composerMenus.browser.html +3 -3
  648. package/src/renderer/tests/contextCompaction.browser.html +1 -1
  649. package/src/renderer/tests/errorRecovery.browser.html +1 -1
  650. package/src/renderer/tests/fixtures/preview.webm +0 -0
  651. package/src/renderer/tests/glideSelect.browser.html +1 -2
  652. package/src/renderer/tests/glideSelect.preview.html +1 -1
  653. package/src/renderer/tests/library.browser.tsx +1 -1
  654. package/src/renderer/tests/liveOrb.browser.html +1 -1
  655. package/src/renderer/tests/mediaFixtures.ts +32 -0
  656. package/src/renderer/tests/modInput.browser.html +1 -1
  657. package/src/renderer/tests/sessionSources.browser.tsx +76 -15
  658. package/src/renderer/tests/toolsPanel.browser.tsx +5 -5
  659. package/src/renderer/tests/viewedImages.browser.tsx +3 -3
  660. package/src/renderer/tests/voiceDictation.browser.html +101 -0
  661. package/src/renderer/tests/voicePill.browser.html +3 -3
  662. package/src/renderer/tests/voicePill.preview.html +1 -1
  663. package/src/renderer/tests/webSources.browser.tsx +2 -98
  664. package/src/renderer/tests/workspaceDrop.browser.html +1 -0
  665. package/src/renderer/tests/workspaceDrop.browser.tsx +183 -0
  666. package/src/renderer/tests/workspaceExpansion.browser.html +1 -0
  667. package/src/renderer/tests/workspaceExpansion.browser.tsx +66 -0
  668. package/src/renderer/tests/workspaceRemoval.browser.html +66 -0
  669. package/src/renderer/tests/workspaceUndo.browser.html +10 -2
  670. package/src-tauri/src/app/lifecycle.rs +44 -1
  671. package/src-tauri/src/commands/conversation.rs +99 -73
  672. package/src-tauri/src/commands/integrations.rs +7 -1
  673. package/src-tauri/src/commands/media.rs +7 -0
  674. package/src-tauri/src/commands/workspace.rs +38 -0
  675. package/tsconfig.json +15 -1
  676. package/vite.config.ts +2 -1
  677. package/vite.config.web.ts +2 -0
  678. package/out/web/assets/CliSessionsView-D7hw0Mgj.js +0 -1
  679. package/out/web/assets/CodeReviewPage-C7bEOJfd.js +0 -4
  680. package/out/web/assets/CodeReviewPage-Dte9uLiL.css +0 -1
  681. package/out/web/assets/CommandPalette-0RrF-AOT.js +0 -1
  682. package/out/web/assets/ImageStudioPanel-CdxkAf_r.js +0 -1
  683. package/out/web/assets/LibraryPage--Qfisp6D.js +0 -2
  684. package/out/web/assets/LinkedFoldersView-2nfZbDgN.js +0 -1
  685. package/out/web/assets/McpRegistryPicker-h9uS8_wT.js +0 -1
  686. package/out/web/assets/McpServersView-slfQJzNB.js +0 -1
  687. package/out/web/assets/MintDashboard-BSR5XpXh.js +0 -25
  688. package/out/web/assets/MintDashboard-CWUcCGhd.css +0 -1
  689. package/out/web/assets/PluginsView-l7LSm503.js +0 -1
  690. package/out/web/assets/ScheduledTasksView-CttmLbq1.js +0 -1
  691. package/out/web/assets/SettingsWindow-BCMLYvEV.js +0 -4
  692. package/out/web/assets/SettingsWindow-DcMVmU9u.css +0 -1
  693. package/out/web/assets/SkillsView-rNs1qr_U.js +0 -2
  694. package/out/web/assets/ToolSurfacePage-B9DzEPWN.js +0 -37
  695. package/out/web/assets/ToolSurfacePage-CTfgggF2.css +0 -1
  696. package/out/web/assets/VeoStudioPanel-DiJs_Cg2.js +0 -4
  697. package/out/web/assets/WorkspacePanel-CbJ1PFoZ.js +0 -1
  698. package/out/web/assets/WorkspaceSelector-B2xIp04D.js +0 -1
  699. package/out/web/assets/WorkspaceSelector-Ca8uJOsS.css +0 -1
  700. package/out/web/assets/abnfDiagram-VCTEODGH-CD0CjoGl.js +0 -1
  701. package/out/web/assets/architecture-7GRP2DOG-RKV83OeZ.js +0 -1
  702. package/out/web/assets/architectureDiagram-5GKGNRK7-nN_HAFct.js +0 -36
  703. package/out/web/assets/c4Diagram-UCG6FXSJ-DTdV8_zE.js +0 -38
  704. package/out/web/assets/chunk-2Q5K7J3B-Dmqrq8Tp.js +0 -1
  705. package/out/web/assets/chunk-75Z2AOVW-_M0z5olV.js +0 -2
  706. package/out/web/assets/chunk-CKBBP62Z-BpQEgeHF.js +0 -2
  707. package/out/web/assets/chunk-CLGD4ZFX-D54yGvGS.js +0 -1
  708. package/out/web/assets/chunk-CacB07dV.js +0 -1
  709. package/out/web/assets/chunk-DSNCTWBM-C-gvT2ru.js +0 -2
  710. package/out/web/assets/chunk-DU6HZSFF-CnFngIhW.js +0 -128
  711. package/out/web/assets/chunk-F27PBJKO-BqtWrnEO.js +0 -1
  712. package/out/web/assets/chunk-FOHPRMQF-BaVC1uA7.js +0 -161
  713. package/out/web/assets/chunk-G27WJ6UU-Ckoq5mi2.js +0 -231
  714. package/out/web/assets/chunk-JQ64N6SF-CF8T7GiZ.js +0 -1
  715. package/out/web/assets/chunk-JWPE2WC7-BwtYOHqU.js +0 -1
  716. package/out/web/assets/chunk-LNGE3PJU-AdBoOWw2.js +0 -34
  717. package/out/web/assets/chunk-OBVCFTLP-CRIkunUB.js +0 -1
  718. package/out/web/assets/chunk-P2QGCYS3-UFEU6BxZ.js +0 -1
  719. package/out/web/assets/chunk-POPQ4Y6H-CQcrNbjr.js +0 -1
  720. package/out/web/assets/chunk-PWAF6VOD-Cc2uVDsG.js +0 -1
  721. package/out/web/assets/chunk-R7TYR2AO-DiCxzdAY.js +0 -10
  722. package/out/web/assets/chunk-RHFEMEQ7-b7hnPmrR.js +0 -168
  723. package/out/web/assets/chunk-XXDRQBXY-DnJkbUaw.js +0 -1
  724. package/out/web/assets/chunk-Y2CYZVJY-C9o-s6OY.js +0 -1
  725. package/out/web/assets/classDiagram-DTDB5LWJ-RnC2mYO4.js +0 -1
  726. package/out/web/assets/classDiagram-v2-JRS7N3AN-RnC2mYO4.js +0 -1
  727. package/out/web/assets/config-CnvCChUM.js +0 -2
  728. package/out/web/assets/config-DM6oIVO3.css +0 -1
  729. package/out/web/assets/core-DsKkQ7ig.js +0 -1
  730. package/out/web/assets/cose-bilkent-JH36ORCC--UN4aw5-.js +0 -1
  731. package/out/web/assets/cynefin-OW5HDTMX-CnzQfOGp.js +0 -1
  732. package/out/web/assets/cynefinDiagram-5FMLGOSQ-DVtQnfpm.js +0 -62
  733. package/out/web/assets/cytoscape.esm-Df1UN4Y1.js +0 -321
  734. package/out/web/assets/dagre-3AP2YEHR-DG76_k5_.js +0 -4
  735. package/out/web/assets/dagre-BWadQu2F.js +0 -1
  736. package/out/web/assets/diagram-S7CK7UJ4-CaouUoze.js +0 -30
  737. package/out/web/assets/diagram-UQ7AKVKN-B4bEc26B.js +0 -41
  738. package/out/web/assets/diagram-VX7I27RA-7hH5IPYf.js +0 -24
  739. package/out/web/assets/diagram-Z3DM3KII-CCM4clo8.js +0 -24
  740. package/out/web/assets/dist-BoTOASLF.js +0 -1
  741. package/out/web/assets/dist-js-BkYNznHX.js +0 -1
  742. package/out/web/assets/ebnfDiagram-PWID7BFC-Da7WAM3k.js +0 -1
  743. package/out/web/assets/event-Cdt7Byyj.js +0 -1
  744. package/out/web/assets/eventmodeling-NTZA5JFV-xcfsA0XD.js +0 -1
  745. package/out/web/assets/flowDiagram-A5DVABFB-JdtH1673.js +0 -1
  746. package/out/web/assets/ganttDiagram-EL5Y4UJY-B3ClFGmL.js +0 -292
  747. package/out/web/assets/gitGraph-4MIJSDKK-BZ_y_cDU.js +0 -1
  748. package/out/web/assets/gitGraphDiagram-WWUBYQGX-drhRSYm3.js +0 -106
  749. package/out/web/assets/graphlib-CTR5ZhLf.js +0 -1
  750. package/out/web/assets/index-BZ9xgmMP.css +0 -1
  751. package/out/web/assets/index-Ca8cCS4h.js +0 -168
  752. package/out/web/assets/info-A6RAGUB7-B7I3K0F1.js +0 -1
  753. package/out/web/assets/infoDiagram-RXCK75RN-deX_1MPh.js +0 -2
  754. package/out/web/assets/journeyDiagram-EYS64GPL-CZn2kB8b.js +0 -139
  755. package/out/web/assets/jsx-runtime-DN4NhQUK.js +0 -1
  756. package/out/web/assets/katex-O3jvqgnU.js +0 -257
  757. package/out/web/assets/markdown-CMhYIcWB.js +0 -39
  758. package/out/web/assets/mermaid-parser.core-Whu2rlJC.js +0 -7
  759. package/out/web/assets/mermaid.core-CKyPo8VH.js +0 -11
  760. package/out/web/assets/modelManager-CUaGWMWu.js +0 -2
  761. package/out/web/assets/oauthManager-DlNhXJr6.js +0 -1
  762. package/out/web/assets/packet-AYTQ26CC-CEeIRKRG.js +0 -1
  763. package/out/web/assets/pegDiagram-XKGWAZYB-BYadI-KO.js +0 -1
  764. package/out/web/assets/pie-WAS4IAKB-D8uf4dh5.js +0 -1
  765. package/out/web/assets/pieDiagram-E7YTZNPT-CjSDy4hO.js +0 -39
  766. package/out/web/assets/radar-RG4KPBEZ-DZJxnokY.js +0 -1
  767. package/out/web/assets/railroad-74A4TZTK-DBysUiUi.js +0 -1
  768. package/out/web/assets/railroad-abnf-HS5TGJTU-CHWxoJYg.js +0 -1
  769. package/out/web/assets/railroad-ebnf-LZEXJU2U-DDv7X6bY.js +0 -1
  770. package/out/web/assets/railroad-peg-WCYAUIDC-DpfcYYNJ.js +0 -1
  771. package/out/web/assets/railroadDiagram-O6MQD6OU-CYtyv0t3.js +0 -1
  772. package/out/web/assets/rough.esm-DFbTUy8a.js +0 -1
  773. package/out/web/assets/sankeyDiagram-P5KCCOFB-Bn2x6C4Y.js +0 -40
  774. package/out/web/assets/sequenceDiagram-WJ2MYXX4-BvFLKtPd.js +0 -162
  775. package/out/web/assets/sizeCapture-X5ZJPWSS-DKeOCaN2.js +0 -1
  776. package/out/web/assets/src-DnfeXQPr.js +0 -1
  777. package/out/web/assets/stateDiagram-HBIQ2CUA-Bx0GWeaY.js +0 -1
  778. package/out/web/assets/stateDiagram-v2-4QOOHH4V--hol1yg_.js +0 -1
  779. package/out/web/assets/studio-B1mk40wD.js +0 -1
  780. package/out/web/assets/swimlanes-XN3QIQJK-CCma0T7L.js +0 -1
  781. package/out/web/assets/swimlanesDiagram-VK2B7HYN-BkohoVsU.js +0 -8
  782. package/out/web/assets/timeline-definition-24CTP7MA-iCRhhJ7C.js +0 -120
  783. package/out/web/assets/treeView-Q6P3EWNA-DZ-y08qp.js +0 -1
  784. package/out/web/assets/treemap-WGGIJYW6-De0CxzMx.js +0 -1
  785. package/out/web/assets/vennDiagram-4TSXK5OY-w_7aZ6xe.js +0 -34
  786. package/out/web/assets/wardley-WFR3VGLG-DT0y0xJ4.js +0 -1
  787. package/out/web/assets/window-BJCVtyET.js +0 -1
  788. package/src/renderer/shared/components/ChatPanel.test.tsx +0 -21
  789. package/src/renderer/shared/components/FormattedMessage.tsx +0 -11
  790. package/src/renderer/shared/components/GlideSelect.d.ts +0 -31
  791. package/src/renderer/shared/components/GlideSelect.jsx +0 -266
  792. package/src/renderer/shared/components/InlineThoughtNote.tsx +0 -27
  793. package/src/renderer/shared/components/ModSessionControls.tsx +0 -8
  794. package/src/renderer/shared/components/ModUi.tsx +0 -26
  795. package/src/renderer/shared/components/ProgressActivity.tsx +0 -17
  796. package/src/renderer/shared/components/ReviewHistory.tsx +0 -42
  797. package/src/renderer/shared/components/RunSummaryDashboard.tsx +0 -143
  798. package/src/renderer/shared/components/SelectField.tsx +0 -38
  799. package/src/renderer/shared/components/SessionSources.tsx +0 -48
  800. package/src/renderer/shared/components/SessionSourcesPopover.tsx +0 -61
  801. package/src/renderer/shared/components/ToolSurfacePage.test.tsx +0 -32
  802. package/src/renderer/shared/components/ViewedImages.tsx +0 -36
  803. package/src/renderer/shared/components/WorkspaceContextPopover.tsx +0 -138
  804. package/src/renderer/shared/components/ui/demo.tsx +0 -26
  805. package/src/renderer/shared/css/session-sources-popover.css +0 -9
  806. package/src/renderer/src/components/CalculationCard.tsx +0 -3
  807. package/src/renderer/src/components/ImageGenCard.tsx +0 -2
  808. package/src/renderer/src/components/ImageSearchCard.tsx +0 -2
  809. package/src/renderer/src/components/MermaidCard.tsx +0 -1
  810. package/src/renderer/src/components/PicturesLibrary.tsx +0 -2
  811. package/src/renderer/src/components/Settings/AgentsTab.tsx +0 -4
  812. package/src/renderer/src/components/Settings/AudioTab.tsx +0 -3
  813. package/src/renderer/src/components/Settings/AutomationTab.tsx +0 -3
  814. package/src/renderer/src/components/Settings/GeneralTab.tsx +0 -3
  815. package/src/renderer/src/components/Settings/MemoryTab.tsx +0 -3
  816. package/src/renderer/src/components/Settings/PluginsTab.tsx +0 -3
  817. package/src/renderer/src/components/Settings/ProfileTab.tsx +0 -3
  818. package/src/renderer/src/components/Settings/ShortcutsTab.tsx +0 -3
  819. package/src/renderer/src/components/Settings/ThemeTab.tsx +0 -3
  820. package/src/renderer/src/components/StockCard.tsx +0 -3
  821. package/src/renderer/src/components/WeatherCard.tsx +0 -3
  822. package/src/renderer/src/css/pictures.css +0 -2
  823. package/src/renderer/src/css/settings/base.css +0 -1266
  824. package/src/renderer/src-web/components/PicturesLibrary.tsx +0 -2
  825. package/src/renderer/src-web/components/Settings/AgentsTab.tsx +0 -4
  826. package/src/renderer/src-web/components/Settings/AudioTab.tsx +0 -3
  827. package/src/renderer/src-web/components/Settings/AutomationTab.tsx +0 -3
  828. package/src/renderer/src-web/components/Settings/GeneralTab.tsx +0 -3
  829. package/src/renderer/src-web/components/Settings/MemoryTab.tsx +0 -3
  830. package/src/renderer/src-web/components/Settings/PluginsTab.tsx +0 -3
  831. package/src/renderer/src-web/components/Settings/ProfileTab.tsx +0 -3
  832. package/src/renderer/src-web/components/Settings/ShortcutsTab.tsx +0 -3
  833. package/src/renderer/src-web/components/Settings/ThemeTab.tsx +0 -3
  834. package/src/renderer/src-web/css/pictures.css +0 -2
  835. package/src/renderer/src-web/css/spotlight.css +0 -102
  836. package/src/renderer/src-web/css/widget.css +0 -213
  837. /package/src/renderer/shared/components/{UiMockupWidget.tsx → cards/UiMockupWidget.tsx} +0 -0
  838. /package/src/renderer/shared/components/{ContextCompactionStatus.tsx → chat/ContextCompactionStatus.tsx} +0 -0
  839. /package/src/renderer/shared/components/{GeminiLiveOverlay.css → chat/GeminiLiveOverlay.css} +0 -0
  840. /package/src/renderer/shared/components/{GeminiLiveOverlay.test.tsx → chat/GeminiLiveOverlay.test.tsx} +0 -0
  841. /package/src/renderer/shared/components/{SlashSuggestions.test.tsx → chat/SlashSuggestions.test.tsx} +0 -0
  842. /package/src/renderer/shared/components/{VirtualChatHistory.tsx → chat/VirtualChatHistory.tsx} +0 -0
  843. /package/src/renderer/shared/components/{VoicePill.d.ts → chat/VoicePill.d.ts} +0 -0
  844. /package/src/renderer/shared/components/{VoicePill.test.tsx → chat/VoicePill.test.tsx} +0 -0
  845. /package/src/renderer/shared/components/{ScreenCaptureDialog.css → studio/ScreenCaptureDialog.css} +0 -0
  846. /package/src/renderer/shared/components/{ScreenCaptureDialog.tsx → studio/ScreenCaptureDialog.tsx} +0 -0
  847. /package/src/renderer/shared/components/{SelectField.test.tsx → ui/SelectField.test.tsx} +0 -0
  848. /package/src/renderer/shared/components/{background-terminals.css → workspace/background-terminals.css} +0 -0
@@ -390,9 +390,77 @@ pub(crate) struct ThoughtModalState {
390
390
  pub scroll: usize,
391
391
  }
392
392
 
393
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
394
+ pub(crate) enum SwarmUiStatus {
395
+ Running,
396
+ Success,
397
+ Failed,
398
+ }
399
+
400
+ #[derive(Debug, Clone)]
401
+ pub(crate) struct SwarmAgentUiState {
402
+ pub label: String,
403
+ pub profile: String,
404
+ pub task: String,
405
+ pub current_action: Option<String>,
406
+ pub status: SwarmUiStatus,
407
+ pub started_at: std::time::Instant,
408
+ pub finished_elapsed_ms: Option<u64>,
409
+ pub summary_preview: Option<String>,
410
+ }
411
+
412
+ fn clip_text(text: &str, width: usize) -> String {
413
+ if UnicodeWidthStr::width(text) <= width {
414
+ return text.to_owned();
415
+ }
416
+ let mut used = 0;
417
+ let mut clipped = String::new();
418
+ for ch in text.chars() {
419
+ let next = unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0);
420
+ if used + next > width.saturating_sub(1) {
421
+ break;
422
+ }
423
+ used += next;
424
+ clipped.push(ch);
425
+ }
426
+ if width > 0 {
427
+ clipped.push('…');
428
+ }
429
+ clipped
430
+ }
431
+
432
+ fn format_subagent_tool_action(action: &str, input: &serde_json::Value) -> String {
433
+ for key in [
434
+ "description",
435
+ "command",
436
+ "cmd",
437
+ "path",
438
+ "query",
439
+ "pattern",
440
+ "url",
441
+ ] {
442
+ if let Some(val) = input.get(key).and_then(|v| v.as_str()) {
443
+ if let Some(line) = val.lines().find(|l| !l.trim().is_empty()) {
444
+ let trimmed = line.trim();
445
+ if trimmed.is_empty() || trimmed.eq_ignore_ascii_case("null") {
446
+ continue;
447
+ }
448
+ return match key {
449
+ "command" | "cmd" => format!("Running `{trimmed}`"),
450
+ "pattern" | "query" => format!("Searching for {trimmed}"),
451
+ "path" => format!("Reading {trimmed}"),
452
+ _ => trimmed.to_string(),
453
+ };
454
+ }
455
+ }
456
+ }
457
+ action.replace('_', " ")
458
+ }
459
+
393
460
  #[derive(Debug, Default)]
394
461
  pub(crate) struct ChatViewState {
395
462
  pub(crate) transcript: Vec<TranscriptEntry>,
463
+ pub(crate) swarm_agents: Vec<SwarmAgentUiState>,
396
464
  chat_id: String,
397
465
  mods: Vec<serde_json::Value>,
398
466
  mods_open: bool,
@@ -427,6 +495,8 @@ pub(crate) struct ChatViewState {
427
495
  tool_viewer: Option<usize>,
428
496
  watermark_frame: u8,
429
497
  watermark_animating: bool,
498
+ pub(crate) queued_count: usize,
499
+ pub(crate) queued_preview: Option<String>,
430
500
  pub(crate) theme: crate::terminal_theme::TuiTheme,
431
501
  }
432
502
 
@@ -1321,6 +1391,91 @@ impl TuiHandle {
1321
1391
  impl ChatViewState {
1322
1392
  fn record_tool_progress(&mut self, progress: &mint_core::AgentProgress) -> Option<usize> {
1323
1393
  use mint_core::AgentProgress;
1394
+ match progress {
1395
+ AgentProgress::SubagentStarted {
1396
+ subagent,
1397
+ profile,
1398
+ task,
1399
+ } => {
1400
+ if let Some(existing) = self.swarm_agents.iter_mut().find(|a| a.label == *subagent)
1401
+ {
1402
+ existing.profile = profile.clone();
1403
+ existing.task = task.clone();
1404
+ existing.status = SwarmUiStatus::Running;
1405
+ existing.started_at = std::time::Instant::now();
1406
+ } else {
1407
+ self.swarm_agents.push(SwarmAgentUiState {
1408
+ label: subagent.clone(),
1409
+ profile: profile.clone(),
1410
+ task: task.clone(),
1411
+ current_action: None,
1412
+ status: SwarmUiStatus::Running,
1413
+ started_at: std::time::Instant::now(),
1414
+ finished_elapsed_ms: None,
1415
+ summary_preview: None,
1416
+ });
1417
+ }
1418
+ return None;
1419
+ }
1420
+ AgentProgress::SubagentFinished {
1421
+ subagent,
1422
+ status,
1423
+ elapsed_ms,
1424
+ summary_preview,
1425
+ ..
1426
+ } => {
1427
+ let ui_status = if status == "failed" {
1428
+ SwarmUiStatus::Failed
1429
+ } else {
1430
+ SwarmUiStatus::Success
1431
+ };
1432
+ if let Some(existing) = self.swarm_agents.iter_mut().find(|a| a.label == *subagent)
1433
+ {
1434
+ existing.status = ui_status;
1435
+ existing.finished_elapsed_ms = Some(*elapsed_ms);
1436
+ if !summary_preview.is_empty() {
1437
+ existing.summary_preview = Some(summary_preview.clone());
1438
+ }
1439
+ } else {
1440
+ self.swarm_agents.push(SwarmAgentUiState {
1441
+ label: subagent.clone(),
1442
+ profile: String::new(),
1443
+ task: String::new(),
1444
+ current_action: None,
1445
+ status: ui_status,
1446
+ started_at: std::time::Instant::now(),
1447
+ finished_elapsed_ms: Some(*elapsed_ms),
1448
+ summary_preview: if summary_preview.is_empty() {
1449
+ None
1450
+ } else {
1451
+ Some(summary_preview.clone())
1452
+ },
1453
+ });
1454
+ }
1455
+ return None;
1456
+ }
1457
+ AgentProgress::ToolStart {
1458
+ subagent: Some(agent_label),
1459
+ action,
1460
+ input,
1461
+ ..
1462
+ } => {
1463
+ if let Some(agent) = self
1464
+ .swarm_agents
1465
+ .iter_mut()
1466
+ .find(|a| a.label == *agent_label)
1467
+ {
1468
+ agent.current_action = Some(format_subagent_tool_action(action, input));
1469
+ }
1470
+ return None;
1471
+ }
1472
+ AgentProgress::ToolEnd {
1473
+ subagent: Some(_), ..
1474
+ } => {
1475
+ return None;
1476
+ }
1477
+ _ => {}
1478
+ }
1324
1479
  let (call_id, action, input, subagent, end) = match progress {
1325
1480
  AgentProgress::ToolStart {
1326
1481
  call_id,
@@ -1485,7 +1640,8 @@ impl ChatViewState {
1485
1640
  if self.tools.is_empty() {
1486
1641
  self.set_notice("No tool activity recorded yet");
1487
1642
  } else {
1488
- self.tool_viewer = Some(self.tools.len() - 1);
1643
+ let target = self.preferred_tool_viewer_index();
1644
+ self.tool_viewer = Some(target);
1489
1645
  self.refresh_tool_viewer(true);
1490
1646
  }
1491
1647
  return true;
@@ -1493,22 +1649,55 @@ impl ChatViewState {
1493
1649
  false
1494
1650
  }
1495
1651
 
1652
+ fn preferred_tool_viewer_index(&self) -> usize {
1653
+ let has_recent_sources = self.transcript.iter().rev().take(6).any(|entry| {
1654
+ entry.text.starts_with("Sources:\n") || entry.text.contains("Ctrl+O view web_search")
1655
+ });
1656
+
1657
+ if has_recent_sources {
1658
+ if let Some(pos) = self
1659
+ .tools
1660
+ .iter()
1661
+ .rposition(|tool| tool.action == "web_search")
1662
+ {
1663
+ return pos;
1664
+ }
1665
+ }
1666
+ self.tools.len() - 1
1667
+ }
1668
+
1496
1669
  fn live_thought(&self) -> Option<&ThinkingSegment> {
1497
1670
  self.thoughts
1498
1671
  .last()
1499
1672
  .filter(|thought| thought.updated_at.is_some() && !thought.text.trim().is_empty())
1500
1673
  }
1501
1674
 
1675
+ fn thought_total_elapsed_label(&self) -> String {
1676
+ if self.thoughts.iter().all(|thought| thought.elapsed_known) {
1677
+ super::format_thought_elapsed(self.thoughts.iter().map(ThinkingSegment::elapsed).sum())
1678
+ } else {
1679
+ "time unavailable".into()
1680
+ }
1681
+ }
1682
+
1502
1683
  fn thought_record(&self) -> Option<ThoughtModalState> {
1503
- let latest = self.thoughts.last()?;
1684
+ self.thoughts.last()?;
1504
1685
  Some(ThoughtModalState {
1505
- elapsed_str: latest.elapsed_label(),
1686
+ elapsed_str: self.thought_total_elapsed_label(),
1506
1687
  lines: self
1507
1688
  .thoughts
1508
1689
  .iter()
1509
- .map(|thought| thought.text.as_str())
1690
+ .enumerate()
1691
+ .map(|(index, thought)| {
1692
+ format!(
1693
+ "── Thought {} · {} ──────────────────────────\n{}",
1694
+ index + 1,
1695
+ thought.elapsed_label(),
1696
+ thought.text
1697
+ )
1698
+ })
1510
1699
  .collect::<Vec<_>>()
1511
- .join("\n\n── Next Step ──────────────────────────\n")
1700
+ .join("\n\n")
1512
1701
  .lines()
1513
1702
  .map(str::to_owned)
1514
1703
  .collect(),
@@ -1863,9 +2052,14 @@ impl ChatViewState {
1863
2052
  }
1864
2053
  }
1865
2054
 
1866
- fn push_saved_activity(&mut self, activity: Option<&serde_json::Value>, turn_status: &str) {
2055
+ fn push_saved_activity(
2056
+ &mut self,
2057
+ activity: Option<&serde_json::Value>,
2058
+ turn_status: &str,
2059
+ ) -> Vec<(String, String)> {
2060
+ let mut sources = Vec::new();
1867
2061
  let Some(events) = activity.and_then(serde_json::Value::as_array) else {
1868
- return;
2062
+ return sources;
1869
2063
  };
1870
2064
  let first_tool = self.tools.len();
1871
2065
  for value in events {
@@ -1879,7 +2073,7 @@ impl ChatViewState {
1879
2073
  mint_core::AgentProgress::ToolStart { .. } => {
1880
2074
  self.record_tool_progress(&event);
1881
2075
  }
1882
- mint_core::AgentProgress::ToolEnd { .. } => {
2076
+ mint_core::AgentProgress::ToolEnd { action, result, .. } => {
1883
2077
  if let Some(index) = self.record_tool_progress(&event) {
1884
2078
  self.tools[index].elapsed = value["data"]["elapsed_ms"]
1885
2079
  .as_u64()
@@ -1887,6 +2081,16 @@ impl ChatViewState {
1887
2081
  .map(std::time::Duration::from_millis);
1888
2082
  self.refresh_tool_card(index);
1889
2083
  }
2084
+ if action == "web_search"
2085
+ && !result.starts_with("Web search error:")
2086
+ && result != "No web search results found."
2087
+ {
2088
+ sources.extend(crate::agent::parse_web_search_sources(result));
2089
+ }
2090
+ }
2091
+ mint_core::AgentProgress::SubagentStarted { .. }
2092
+ | mint_core::AgentProgress::SubagentFinished { .. } => {
2093
+ self.record_tool_progress(&event);
1890
2094
  }
1891
2095
  mint_core::AgentProgress::ExtendedThinking {
1892
2096
  id,
@@ -1923,9 +2127,12 @@ impl ChatViewState {
1923
2127
  _ => {}
1924
2128
  }
1925
2129
  }
1926
- if let Some(notes) = crate::agent::mcp_progress_notes(&event) {
1927
- for note in notes {
1928
- self.push_notice(note);
2130
+ // Suppress redundant ExecutionUpdate notices in TUI (handled by ToolActivity cards)
2131
+ if !matches!(event, mint_core::AgentProgress::ExecutionUpdate { .. }) {
2132
+ if let Some(notes) = crate::agent::mcp_progress_notes(&event) {
2133
+ for note in notes {
2134
+ self.push_notice(note);
2135
+ }
1929
2136
  }
1930
2137
  }
1931
2138
  }
@@ -1939,6 +2146,7 @@ impl ChatViewState {
1939
2146
  self.refresh_tool_card(index);
1940
2147
  }
1941
2148
  }
2149
+ sources
1942
2150
  }
1943
2151
 
1944
2152
  pub fn reload_transcript_with(
@@ -1970,11 +2178,22 @@ impl ChatViewState {
1970
2178
  for row in rows {
1971
2179
  self.transcript
1972
2180
  .push(TranscriptEntry::new(TranscriptRole::User, row.user_text));
1973
- self.push_saved_activity(row.agent_activity.as_ref(), &row.status);
2181
+ let sources = self.push_saved_activity(row.agent_activity.as_ref(), &row.status);
1974
2182
  match row.status.as_str() {
1975
- "completed" => self
1976
- .transcript
1977
- .push(TranscriptEntry::new(TranscriptRole::Assistant, row.ai_text)),
2183
+ "completed" => {
2184
+ self.transcript
2185
+ .push(TranscriptEntry::new(TranscriptRole::Assistant, row.ai_text));
2186
+ if !sources.is_empty() {
2187
+ let text = crate::agent::format_tui_web_sources(
2188
+ &sources,
2189
+ crate::agent::MAX_TUI_WEB_SOURCES,
2190
+ );
2191
+ if !text.is_empty() {
2192
+ self.transcript
2193
+ .push(TranscriptEntry::new(TranscriptRole::Notice, text));
2194
+ }
2195
+ }
2196
+ }
1978
2197
  "queued" => self.transcript.push(TranscriptEntry::new(
1979
2198
  TranscriptRole::Notice,
1980
2199
  "Queued for this session…",
@@ -2064,12 +2283,24 @@ impl ChatViewState {
2064
2283
  // Incoming new interaction from an external client (Web/Desktop)
2065
2284
  self.transcript
2066
2285
  .push(TranscriptEntry::new(TranscriptRole::User, &row.user_text));
2067
- self.push_saved_activity(row.agent_activity.as_ref(), &row.status);
2286
+ let sources = self.push_saved_activity(row.agent_activity.as_ref(), &row.status);
2068
2287
  match row.status.as_str() {
2069
- "completed" => self.transcript.push(TranscriptEntry::new(
2070
- TranscriptRole::Assistant,
2071
- &row.ai_text,
2072
- )),
2288
+ "completed" => {
2289
+ self.transcript.push(TranscriptEntry::new(
2290
+ TranscriptRole::Assistant,
2291
+ &row.ai_text,
2292
+ ));
2293
+ if !sources.is_empty() {
2294
+ let text = crate::agent::format_tui_web_sources(
2295
+ &sources,
2296
+ crate::agent::MAX_TUI_WEB_SOURCES,
2297
+ );
2298
+ if !text.is_empty() {
2299
+ self.transcript
2300
+ .push(TranscriptEntry::new(TranscriptRole::Notice, text));
2301
+ }
2302
+ }
2303
+ }
2073
2304
  "queued" => self.transcript.push(TranscriptEntry::new(
2074
2305
  TranscriptRole::Notice,
2075
2306
  "Queued for this session…",
@@ -2105,11 +2336,22 @@ impl ChatViewState {
2105
2336
  }
2106
2337
  }
2107
2338
  if append {
2108
- self.push_saved_activity(row.agent_activity.as_ref(), &row.status);
2339
+ let sources =
2340
+ self.push_saved_activity(row.agent_activity.as_ref(), &row.status);
2109
2341
  self.transcript.push(TranscriptEntry::new(
2110
2342
  TranscriptRole::Assistant,
2111
2343
  &row.ai_text,
2112
2344
  ));
2345
+ if !sources.is_empty() {
2346
+ let text = crate::agent::format_tui_web_sources(
2347
+ &sources,
2348
+ crate::agent::MAX_TUI_WEB_SOURCES,
2349
+ );
2350
+ if !text.is_empty() {
2351
+ self.transcript
2352
+ .push(TranscriptEntry::new(TranscriptRole::Notice, text));
2353
+ }
2354
+ }
2113
2355
  changed = true;
2114
2356
  }
2115
2357
  } else if row.status == "running" {
@@ -2149,6 +2391,7 @@ impl ChatViewState {
2149
2391
  self.transcript
2150
2392
  .push(TranscriptEntry::new(TranscriptRole::User, text));
2151
2393
  self.scroll_from_bottom = 0;
2394
+ self.swarm_agents.clear();
2152
2395
  }
2153
2396
  pub fn push_notice(&mut self, text: impl Into<String>) {
2154
2397
  self.transcript
@@ -2163,6 +2406,7 @@ impl ChatViewState {
2163
2406
  pub fn clear_transcript(&mut self) {
2164
2407
  self.transcript.clear();
2165
2408
  self.tools.clear();
2409
+ self.swarm_agents.clear();
2166
2410
  if self
2167
2411
  .dialog
2168
2412
  .as_ref()
@@ -2698,6 +2942,25 @@ impl ChatViewState {
2698
2942
  let composer_scroll = cursor_row
2699
2943
  .saturating_add(1)
2700
2944
  .saturating_sub(visible_composer_rows);
2945
+ let swarm_height = if self.swarm_agents.is_empty()
2946
+ || self.dialog.is_some()
2947
+ || self.thought_modal.is_some()
2948
+ {
2949
+ 0
2950
+ } else {
2951
+ let max_avail = main_area
2952
+ .height
2953
+ .saturating_sub(6 + 3 + status_height + suggestion_height + composer_height + 1);
2954
+ if max_avail == 0 {
2955
+ 0
2956
+ } else if main_area.height < 24 || max_avail < 3 {
2957
+ 1
2958
+ } else {
2959
+ let needed = (self.swarm_agents.len().min(5) as u16) + 2;
2960
+ needed.min(max_avail)
2961
+ }
2962
+ };
2963
+
2701
2964
  let rows = if dialog_height > 0 {
2702
2965
  let dialog_status_height =
2703
2966
  status_height.min(main_area.height.saturating_sub(6 + 1 + dialog_height));
@@ -2729,6 +2992,7 @@ impl ChatViewState {
2729
2992
  Constraint::Length(status_height),
2730
2993
  Constraint::Length(suggestion_height),
2731
2994
  Constraint::Length(composer_height),
2995
+ Constraint::Length(swarm_height),
2732
2996
  Constraint::Length(1),
2733
2997
  ])
2734
2998
  .split(main_area)
@@ -3054,18 +3318,58 @@ impl ChatViewState {
3054
3318
  let title_height = Paragraph::new(lines.clone())
3055
3319
  .wrap(Wrap { trim: false })
3056
3320
  .line_count(width);
3057
- let body = Paragraph::new(
3321
+ let command_line_count = if dialog.title == "Local shell command"
3322
+ && dialog.body.starts_with("Command: ")
3323
+ {
3324
+ dialog
3325
+ .body
3326
+ .rfind("\nMode: ")
3327
+ .map_or(0, |end| dialog.body[..end].lines().count())
3328
+ } else {
3329
+ 0
3330
+ };
3331
+ let detail_lines = self
3332
+ .tool_viewer
3333
+ .and_then(|index| self.tools.get(index))
3334
+ .map(|tool| {
3335
+ tool.detail_lines()
3336
+ .into_iter()
3337
+ .map(|mut line| {
3338
+ line.spans.insert(0, Span::raw(" "));
3339
+ line
3340
+ })
3341
+ .collect::<Vec<_>>()
3342
+ });
3343
+ let body = Paragraph::new(detail_lines.unwrap_or_else(|| {
3058
3344
  dialog
3059
3345
  .body
3060
3346
  .lines()
3061
- .map(|line| {
3347
+ .enumerate()
3348
+ .map(|(index, line)| {
3349
+ if index < command_line_count {
3350
+ let (label, command) = if index == 0 {
3351
+ (" Command: ", &line["Command: ".len()..])
3352
+ } else {
3353
+ (" ", line)
3354
+ };
3355
+ return Line::from(vec![
3356
+ Span::styled(
3357
+ label,
3358
+ Style::default().fg(crate::terminal_theme::TEXT),
3359
+ ),
3360
+ Span::styled(
3361
+ command,
3362
+ Style::default().fg(crate::terminal_theme::ACCENT),
3363
+ ),
3364
+ ]);
3365
+ }
3062
3366
  Line::styled(
3063
3367
  format!(" {line}"),
3064
3368
  Style::default().fg(crate::terminal_theme::TEXT),
3065
3369
  )
3066
3370
  })
3067
- .collect::<Vec<_>>(),
3068
- )
3371
+ .collect::<Vec<_>>()
3372
+ }))
3069
3373
  .wrap(Wrap { trim: false });
3070
3374
  let body_lines = if dialog.body.is_empty() {
3071
3375
  0
@@ -3073,7 +3377,7 @@ impl ChatViewState {
3073
3377
  body.line_count(width)
3074
3378
  };
3075
3379
  let hint = if self.tool_viewer.is_some() {
3076
- " PgUp/PgDn scroll · Tab next · Ctrl+Y copy all · Esc close"
3380
+ " Shift+Tab previous · Tab next (wraps)\n PgUp/PgDn scroll · Ctrl+Y copy all · Esc/Ctrl+O close"
3077
3381
  } else if dialog.update_prompt {
3078
3382
  " ↑/↓ navigate · 1-3 choose · Enter continue · Esc skip"
3079
3383
  } else if dialog.input.is_some() {
@@ -3107,7 +3411,8 @@ impl ChatViewState {
3107
3411
  let fixed_height = title_height + filter_height + 1 + option_height;
3108
3412
  let body_overflows =
3109
3413
  body_lines > inner_height.saturating_sub(fixed_height + normal_footer_height);
3110
- let hint = if body_overflows && dialog.input.is_none() {
3414
+ let hint = if body_overflows && dialog.input.is_none() && self.tool_viewer.is_none()
3415
+ {
3111
3416
  if dialog.checked.is_some() {
3112
3417
  " Space toggle · Enter confirm · Esc cancel"
3113
3418
  } else {
@@ -3341,10 +3646,9 @@ impl ChatViewState {
3341
3646
  if !body_overflows {
3342
3647
  lines.push(Line::raw(""));
3343
3648
  }
3344
- lines.push(Line::styled(
3345
- hint,
3346
- Style::default().fg(crate::terminal_theme::MUTED),
3347
- ));
3649
+ lines.extend(hint.lines().map(|line| {
3650
+ Line::styled(line, Style::default().fg(crate::terminal_theme::MUTED))
3651
+ }));
3348
3652
  if !body_overflows {
3349
3653
  lines.push(Line::raw(""));
3350
3654
  }
@@ -3386,16 +3690,18 @@ impl ChatViewState {
3386
3690
  } else if let Some(modal) = &self.thought_modal {
3387
3691
  let panel_area = rows[3];
3388
3692
  let content_width = (panel_area.width as usize).saturating_sub(4).max(20);
3389
- let mut wrapped_lines: Vec<String> = Vec::new();
3693
+ let mut wrapped_lines: Vec<(String, bool)> = Vec::new();
3390
3694
  for paragraph in &modal.lines {
3391
3695
  let p_trimmed = paragraph.trim_end();
3696
+ let separator = p_trimmed.starts_with("── Thought ")
3697
+ && p_trimmed.ends_with(" ──────────────────────────");
3392
3698
  if p_trimmed.is_empty() {
3393
- wrapped_lines.push(String::new());
3699
+ wrapped_lines.push((String::new(), false));
3394
3700
  } else {
3395
3701
  let options = textwrap::Options::new(content_width).break_words(true);
3396
3702
  let filled = textwrap::fill(p_trimmed, &options);
3397
3703
  for l in filled.lines() {
3398
- wrapped_lines.push(l.to_string());
3704
+ wrapped_lines.push((l.to_string(), separator));
3399
3705
  }
3400
3706
  }
3401
3707
  }
@@ -3404,41 +3710,56 @@ impl ChatViewState {
3404
3710
  let max_scroll = wrapped_lines.len().saturating_sub(inner_height);
3405
3711
  let scroll = modal.scroll.min(max_scroll);
3406
3712
 
3407
- let scroll_hint = if max_scroll > 0 {
3408
- format!(
3409
- " ↑/↓ scroll {}/{} · Esc / Ctrl+T to close ",
3713
+ let key_style = Style::default().fg(crate::terminal_theme::BLUE);
3714
+ let mut hint_spans = Vec::new();
3715
+ if max_scroll > 0 {
3716
+ hint_spans.push(Span::styled(" ↑/↓", key_style));
3717
+ hint_spans.push(Span::raw(format!(
3718
+ " scroll {}/{} ·",
3410
3719
  scroll + 1,
3411
3720
  max_scroll + 1
3412
- )
3413
- } else {
3414
- " Esc / Ctrl+T to close ".to_string()
3415
- };
3721
+ )));
3722
+ }
3723
+ hint_spans.extend([
3724
+ Span::styled(" Esc", key_style),
3725
+ Span::raw(" / "),
3726
+ Span::styled("Ctrl+T", key_style),
3727
+ Span::raw(" to close "),
3728
+ ]);
3729
+ let scroll_hint =
3730
+ Line::from(hint_spans).style(Style::default().fg(crate::terminal_theme::MUTED));
3416
3731
 
3417
3732
  let block = Block::default()
3418
3733
  .borders(Borders::TOP)
3419
3734
  .border_style(Style::default().fg(crate::terminal_theme::BLUE))
3420
3735
  .title(Span::styled(
3421
3736
  format!(
3422
- " Thought Process ({}) ",
3423
- self.live_thought()
3424
- .map(|thought| super::format_thought_elapsed(thought.elapsed()))
3425
- .unwrap_or_else(|| modal.elapsed_str.clone())
3737
+ " Thought Process · {} ",
3738
+ if self.thoughts.is_empty() {
3739
+ modal.elapsed_str.clone()
3740
+ } else {
3741
+ self.thought_total_elapsed_label()
3742
+ }
3426
3743
  ),
3427
3744
  Style::default()
3428
3745
  .fg(crate::terminal_theme::BLUE)
3429
3746
  .add_modifier(Modifier::BOLD),
3430
3747
  ))
3431
- .title_bottom(Span::styled(
3432
- scroll_hint,
3433
- Style::default().fg(crate::terminal_theme::MUTED),
3434
- ));
3748
+ .title_bottom(scroll_hint);
3435
3749
 
3436
3750
  let visible = &wrapped_lines[scroll..(scroll + inner_height).min(wrapped_lines.len())];
3437
3751
  let mut p_lines: Vec<Line> = Vec::with_capacity(inner_height);
3438
- for l in visible {
3752
+ for (l, separator) in visible {
3439
3753
  p_lines.push(Line::from(vec![
3440
3754
  Span::raw(" "),
3441
- Span::styled(l.clone(), Style::default().fg(crate::terminal_theme::TEXT)),
3755
+ Span::styled(
3756
+ l.clone(),
3757
+ Style::default().fg(if *separator {
3758
+ crate::terminal_theme::ACCENT
3759
+ } else {
3760
+ crate::terminal_theme::TEXT
3761
+ }),
3762
+ ),
3442
3763
  ]));
3443
3764
  }
3444
3765
  for _ in visible.len()..inner_height {
@@ -3534,6 +3855,32 @@ impl ChatViewState {
3534
3855
  if !self.collapsed_pastes.is_empty() || self.expanded_paste.is_some() {
3535
3856
  input_block = input_block.title_bottom(" F2: open/collapse paste ");
3536
3857
  }
3858
+ if self.queued_count > 0 {
3859
+ let preview = self
3860
+ .queued_preview
3861
+ .as_deref()
3862
+ .unwrap_or("")
3863
+ .chars()
3864
+ .take(30)
3865
+ .collect::<String>();
3866
+ let text = if preview.is_empty() {
3867
+ format!(" Queued ({}) · Ctrl+D drop ", self.queued_count)
3868
+ } else {
3869
+ format!(
3870
+ " Queued ({}): \"{}\" · Ctrl+D drop ",
3871
+ self.queued_count, preview
3872
+ )
3873
+ };
3874
+ input_block = input_block.title_bottom(
3875
+ Line::styled(
3876
+ text,
3877
+ Style::default()
3878
+ .fg(crate::terminal_theme::ACCENT)
3879
+ .add_modifier(Modifier::BOLD),
3880
+ )
3881
+ .alignment(ratatui::layout::Alignment::Left),
3882
+ );
3883
+ }
3537
3884
  // Rows already wrap at the content width. A second word-wrap
3538
3885
  // pass would change blank-row and cursor/scroll positions.
3539
3886
  frame.render_widget(
@@ -3543,6 +3890,209 @@ impl ChatViewState {
3543
3890
  rows[4],
3544
3891
  );
3545
3892
 
3893
+ if rows[5].height > 0 {
3894
+ if rows[5].height == 1 {
3895
+ let running_count = self
3896
+ .swarm_agents
3897
+ .iter()
3898
+ .filter(|a| a.status == SwarmUiStatus::Running)
3899
+ .count();
3900
+ const SPINNER_CHARS: &[char] =
3901
+ &['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
3902
+ let spinner = SPINNER_CHARS[tick % SPINNER_CHARS.len()];
3903
+ let line = if running_count > 0 {
3904
+ Line::from(vec![
3905
+ Span::styled(
3906
+ format!(" {spinner} "),
3907
+ Style::default()
3908
+ .fg(crate::terminal_theme::BLUE)
3909
+ .add_modifier(Modifier::BOLD),
3910
+ ),
3911
+ Span::styled(
3912
+ format!(
3913
+ "Running {running_count} subagent{} ({}/{} completed)",
3914
+ if running_count == 1 { "" } else { "s" },
3915
+ self.swarm_agents.len() - running_count,
3916
+ self.swarm_agents.len(),
3917
+ ),
3918
+ Style::default().fg(crate::terminal_theme::TEXT),
3919
+ ),
3920
+ ])
3921
+ } else {
3922
+ Line::from(vec![
3923
+ Span::styled(
3924
+ " ✓ ",
3925
+ Style::default()
3926
+ .fg(crate::terminal_theme::ACCENT)
3927
+ .add_modifier(Modifier::BOLD),
3928
+ ),
3929
+ Span::styled(
3930
+ format!("{} subagents finished", self.swarm_agents.len()),
3931
+ Style::default().fg(crate::terminal_theme::MUTED),
3932
+ ),
3933
+ ])
3934
+ };
3935
+ frame.render_widget(Paragraph::new(line), rows[5]);
3936
+ } else {
3937
+ let any_running = self
3938
+ .swarm_agents
3939
+ .iter()
3940
+ .any(|a| a.status == SwarmUiStatus::Running);
3941
+ let block = Block::default()
3942
+ .borders(Borders::ALL)
3943
+ .border_style(Style::default().fg(crate::terminal_theme::MUTED))
3944
+ .title(Span::styled(
3945
+ if any_running {
3946
+ " Running Subagents "
3947
+ } else {
3948
+ " Subagents "
3949
+ },
3950
+ Style::default()
3951
+ .fg(if any_running {
3952
+ crate::terminal_theme::BLUE
3953
+ } else {
3954
+ crate::terminal_theme::TEXT
3955
+ })
3956
+ .add_modifier(Modifier::BOLD),
3957
+ ));
3958
+
3959
+ const SPINNER_CHARS: &[char] =
3960
+ &['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
3961
+ let spinner = SPINNER_CHARS[tick % SPINNER_CHARS.len()];
3962
+ let inner_width = (rows[5].width as usize).saturating_sub(2);
3963
+ let max_items = (rows[5].height as usize).saturating_sub(2);
3964
+ let total_agents = self.swarm_agents.len();
3965
+ let has_overflow = total_agents > max_items;
3966
+ let take_count = if has_overflow {
3967
+ max_items.saturating_sub(1)
3968
+ } else {
3969
+ max_items.min(total_agents)
3970
+ };
3971
+
3972
+ let mut lines = Vec::new();
3973
+ for a in self.swarm_agents.iter().take(take_count) {
3974
+ let (icon_span, icon_width) = match a.status {
3975
+ SwarmUiStatus::Running => (
3976
+ Span::styled(
3977
+ format!(" {spinner} "),
3978
+ Style::default()
3979
+ .fg(crate::terminal_theme::BLUE)
3980
+ .add_modifier(Modifier::BOLD),
3981
+ ),
3982
+ 4,
3983
+ ),
3984
+ SwarmUiStatus::Success => (
3985
+ Span::styled(
3986
+ " ✓ ",
3987
+ Style::default()
3988
+ .fg(crate::terminal_theme::ACCENT)
3989
+ .add_modifier(Modifier::BOLD),
3990
+ ),
3991
+ 4,
3992
+ ),
3993
+ SwarmUiStatus::Failed => (
3994
+ Span::styled(
3995
+ " ✗ ",
3996
+ Style::default().fg(Color::Red).add_modifier(Modifier::BOLD),
3997
+ ),
3998
+ 4,
3999
+ ),
4000
+ };
4001
+
4002
+ let label_str = format!("[{}] ", a.label);
4003
+ let label_width = UnicodeWidthStr::width(label_str.as_str());
4004
+ let label_span = Span::styled(
4005
+ label_str,
4006
+ Style::default()
4007
+ .fg(crate::terminal_theme::ACCENT)
4008
+ .add_modifier(Modifier::BOLD),
4009
+ );
4010
+
4011
+ let suffix_str = match a.status {
4012
+ SwarmUiStatus::Running => {
4013
+ let secs = a.started_at.elapsed().as_secs();
4014
+ if secs < 60 {
4015
+ format!(" · {secs}s")
4016
+ } else {
4017
+ format!(" · {}m {}s", secs / 60, secs % 60)
4018
+ }
4019
+ }
4020
+ SwarmUiStatus::Success => {
4021
+ let ms = a.finished_elapsed_ms.unwrap_or(0);
4022
+ let secs = (ms / 1000).max(1);
4023
+ if secs < 60 {
4024
+ format!(" · done {secs}s")
4025
+ } else {
4026
+ format!(" · done {}m {}s", secs / 60, secs % 60)
4027
+ }
4028
+ }
4029
+ SwarmUiStatus::Failed => {
4030
+ let ms = a.finished_elapsed_ms.unwrap_or(0);
4031
+ let secs = (ms / 1000).max(1);
4032
+ if secs < 60 {
4033
+ format!(" · failed {secs}s")
4034
+ } else {
4035
+ format!(" · failed {}m {}s", secs / 60, secs % 60)
4036
+ }
4037
+ }
4038
+ };
4039
+ let suffix_width = UnicodeWidthStr::width(suffix_str.as_str());
4040
+
4041
+ let desc = if a.status == SwarmUiStatus::Success
4042
+ && a.summary_preview.as_deref().is_some_and(|p| !p.is_empty())
4043
+ {
4044
+ a.summary_preview.as_deref().unwrap()
4045
+ } else if let Some(act) = a
4046
+ .current_action
4047
+ .as_deref()
4048
+ .filter(|s| !s.is_empty() && !s.eq_ignore_ascii_case("null"))
4049
+ {
4050
+ act
4051
+ } else if !a.task.is_empty() && !a.task.eq_ignore_ascii_case("null") {
4052
+ &a.task
4053
+ } else {
4054
+ "Working on task..."
4055
+ };
4056
+
4057
+ let prefix_width = icon_width + label_width;
4058
+ let avail_for_desc =
4059
+ inner_width.saturating_sub(prefix_width + suffix_width + 1);
4060
+ let clipped_desc = clip_text(desc, avail_for_desc);
4061
+ let used_width = prefix_width
4062
+ + UnicodeWidthStr::width(clipped_desc.as_str())
4063
+ + suffix_width;
4064
+ let gap = inner_width.saturating_sub(used_width);
4065
+
4066
+ lines.push(Line::from(vec![
4067
+ icon_span,
4068
+ label_span,
4069
+ Span::styled(
4070
+ clipped_desc,
4071
+ Style::default().fg(crate::terminal_theme::TEXT),
4072
+ ),
4073
+ Span::raw(" ".repeat(gap)),
4074
+ Span::styled(
4075
+ suffix_str,
4076
+ Style::default().fg(crate::terminal_theme::MUTED),
4077
+ ),
4078
+ ]));
4079
+ }
4080
+
4081
+ if has_overflow {
4082
+ let overflow_count = total_agents - take_count;
4083
+ lines.push(Line::from(vec![
4084
+ Span::raw(" "),
4085
+ Span::styled(
4086
+ format!("+{overflow_count} more subagents..."),
4087
+ Style::default().fg(crate::terminal_theme::MUTED),
4088
+ ),
4089
+ ]));
4090
+ }
4091
+
4092
+ frame.render_widget(Paragraph::new(lines).block(block), rows[5]);
4093
+ }
4094
+ }
4095
+
3546
4096
  let mode_label = if self.plan_mode {
3547
4097
  " [Plan] "
3548
4098
  } else {
@@ -3555,7 +4105,7 @@ impl ChatViewState {
3555
4105
  + thinking_text.chars().count()
3556
4106
  + 1;
3557
4107
  let right_len = path_text.chars().count();
3558
- let available = rows[5].width as usize;
4108
+ let available = rows[6].width as usize;
3559
4109
  let gap = available.saturating_sub(left_len + right_len);
3560
4110
  let footer = if let Some(notice) = self.active_notice() {
3561
4111
  Line::styled(
@@ -3590,7 +4140,7 @@ impl ChatViewState {
3590
4140
  Span::styled(path_text, Style::default().fg(crate::terminal_theme::MUTED)),
3591
4141
  ])
3592
4142
  };
3593
- frame.render_widget(Paragraph::new(footer), rows[5]);
4143
+ frame.render_widget(Paragraph::new(footer), rows[6]);
3594
4144
 
3595
4145
  if !self.selection_mode {
3596
4146
  let row_start = self.cursor.saturating_sub(cursor_col);
@@ -3622,7 +4172,9 @@ impl ChatViewState {
3622
4172
  main_area.x,
3623
4173
  main_area.y + 6,
3624
4174
  main_area.width,
3625
- main_area.height.saturating_sub(6 + composer_height + 1),
4175
+ main_area
4176
+ .height
4177
+ .saturating_sub(6 + composer_height + swarm_height + 1),
3626
4178
  ));
3627
4179
  frame.render_widget(ratatui::widgets::Clear, area);
3628
4180
  let mut lines = crate::mods_ui::slot_lines(&self.mods, "side_panel");
@@ -5302,6 +5854,18 @@ impl ChatTui {
5302
5854
  }
5303
5855
  }
5304
5856
  }
5857
+ pub fn run_onboard_wizard(&mut self, config: &mut mint_core::MintConfig) -> Result<bool> {
5858
+ let mut wizard = crate::onboard::OnboardWizard::new(config.clone());
5859
+ let outcome = wizard.run_with_terminal(&mut self.terminal)?;
5860
+ match outcome {
5861
+ crate::onboard::OnboardOutcome::SavedAndLaunch
5862
+ | crate::onboard::OnboardOutcome::SavedAndExit => {
5863
+ *config = wizard.take_config();
5864
+ Ok(true)
5865
+ }
5866
+ crate::onboard::OnboardOutcome::Cancelled => Ok(false),
5867
+ }
5868
+ }
5305
5869
  pub async fn drive_agent<T: Send + 'static>(
5306
5870
  &mut self,
5307
5871
  handle: &TuiHandle,
@@ -5310,6 +5874,10 @@ impl ChatTui {
5310
5874
  use event::{KeyCode, KeyModifiers};
5311
5875
  loop {
5312
5876
  if let Ok(mut state) = handle.state.lock() {
5877
+ if let Ok(queued) = handle.queued.lock() {
5878
+ state.queued_count = queued.len();
5879
+ state.queued_preview = queued.last().cloned();
5880
+ }
5313
5881
  self.scroll_mouse_selection(&mut state);
5314
5882
  self.draw_state(&state)?;
5315
5883
  }
@@ -5317,6 +5885,8 @@ impl ChatTui {
5317
5885
  if let Ok(mut state) = handle.state.lock() {
5318
5886
  state.finish_live_thought();
5319
5887
  state.finish_running_tools();
5888
+ state.queued_count = 0;
5889
+ state.queued_preview = None;
5320
5890
  }
5321
5891
  return Ok(task.await?);
5322
5892
  }
@@ -5385,6 +5955,15 @@ impl ChatTui {
5385
5955
  continue;
5386
5956
  }
5387
5957
  match key.code {
5958
+ KeyCode::Char('d')
5959
+ if key.modifiers.contains(KeyModifiers::CONTROL) =>
5960
+ {
5961
+ if let Ok(mut queued) = handle.queued.lock() {
5962
+ queued.pop();
5963
+ state.queued_count = queued.len();
5964
+ state.queued_preview = queued.last().cloned();
5965
+ }
5966
+ }
5388
5967
  KeyCode::Up | KeyCode::Down | KeyCode::Home | KeyCode::End
5389
5968
  if state.navigate_composer(key, composer_width) => {}
5390
5969
  KeyCode::End => state.scroll_from_bottom = 0,
@@ -5393,6 +5972,8 @@ impl ChatTui {
5393
5972
  let text = state.take_prompt();
5394
5973
  if let Ok(mut queued) = handle.queued.lock() {
5395
5974
  queued.push(text);
5975
+ state.queued_count = queued.len();
5976
+ state.queued_preview = queued.last().cloned();
5396
5977
  }
5397
5978
  }
5398
5979
  }
@@ -5496,14 +6077,14 @@ mod dialog_tests {
5496
6077
  .map(|entry| entry.text.as_str())
5497
6078
  .collect::<Vec<_>>()
5498
6079
  .join("\n");
5499
- assert!(text.contains("Shell failed · 3.4s · exit 2"));
6080
+ assert!(text.contains("run_shell failed · 3.4s · exit 2"));
5500
6081
  assert_eq!(text.matches("Thought · 1.9s").count(), 1);
5501
- assert!(text.contains("Completed with 1 failure"));
6082
+ assert!(text.contains("✗ Failed"));
5502
6083
  assert!(text.contains("16.2s"));
5503
6084
  assert!(!state.tools[0].running());
5504
6085
  assert!(state.handle_thought_key(ctrl_t()));
5505
6086
  assert_eq!(
5506
- state.thought_modal.as_ref().unwrap().lines,
6087
+ state.thought_modal.as_ref().unwrap().lines[1..],
5507
6088
  vec!["Saved reasoning"]
5508
6089
  );
5509
6090
  state.handle_thought_key(make_key(KeyCode::Esc));
@@ -5558,6 +6139,29 @@ mod dialog_tests {
5558
6139
  std::fs::remove_dir_all(root).unwrap();
5559
6140
  }
5560
6141
 
6142
+ #[test]
6143
+ fn resume_restores_web_search_sources_in_transcript() {
6144
+ let (root, memory) = saved_activity_fixture(
6145
+ serde_json::json!([
6146
+ {"type":"ToolStart","data":{"callId":"call_1","action":"web_search","input":{"query":"rust ratatui"}}},
6147
+ {"type":"ToolEnd","data":{"callId":"call_1","action":"web_search","input":{"query":"rust ratatui"},"result":"1. Ratatui Docs\n URL: https://ratatui.rs\n Terminal UI library"}}
6148
+ ]),
6149
+ "completed",
6150
+ );
6151
+ let mut state = ChatViewState::default();
6152
+ state.reload_transcript_with(&memory, "resume-details", &root);
6153
+ let sources_entry = state.transcript.iter().find(|entry| {
6154
+ entry.role == TranscriptRole::Notice && entry.text.starts_with("Sources:\n")
6155
+ });
6156
+ assert!(
6157
+ sources_entry.is_some(),
6158
+ "Sources notice should be reconstructed upon resume"
6159
+ );
6160
+ let text = &sources_entry.unwrap().text;
6161
+ assert!(text.contains("1. Ratatui Docs\n https://ratatui.rs"));
6162
+ std::fs::remove_dir_all(root).unwrap();
6163
+ }
6164
+
5561
6165
  #[test]
5562
6166
  fn resume_interrupted_activity_keeps_partial_thought_and_never_restarts_spinner() {
5563
6167
  let events: Vec<mint_core::AgentProgress> = serde_json::from_value(serde_json::json!([
@@ -5577,7 +6181,7 @@ mod dialog_tests {
5577
6181
  assert!(super::super::tool_activity::running_lines(&state.tools, 80, 0).is_empty());
5578
6182
  assert!(state.handle_thought_key(ctrl_t()));
5579
6183
  assert_eq!(
5580
- state.thought_modal.as_ref().unwrap().lines,
6184
+ state.thought_modal.as_ref().unwrap().lines[1..],
5581
6185
  vec!["unfinished reasoning"]
5582
6186
  );
5583
6187
  state.reload_transcript_with(&memory, "another-session", &root);
@@ -5689,6 +6293,39 @@ mod dialog_tests {
5689
6293
  assert!(rendered.contains("Sample attachment unavailable"));
5690
6294
  }
5691
6295
 
6296
+ #[test]
6297
+ fn tui_suppresses_redundant_execution_update_notices() {
6298
+ use mint_core::{ExecutionEvidence, ExecutionState};
6299
+ let state = Arc::new(Mutex::new(ChatViewState::default()));
6300
+ let tui = TuiHandle {
6301
+ state: Arc::clone(&state),
6302
+ interrupted: Arc::new(AtomicBool::new(false)),
6303
+ queued: Arc::new(Mutex::new(Vec::new())),
6304
+ };
6305
+ let update = mint_core::AgentProgress::ExecutionUpdate {
6306
+ call_id: "test".into(),
6307
+ executions: vec![ExecutionEvidence {
6308
+ call_id: "test1".into(),
6309
+ command: "ls -la".into(),
6310
+ state: ExecutionState::Succeeded,
6311
+ exit_code: Some(0),
6312
+ job_id: None,
6313
+ revision: 1,
6314
+ check: false,
6315
+ condition_verified: None,
6316
+ }],
6317
+ };
6318
+ let published = crate::agent::publish_mcp_progress(Some(&tui), &update);
6319
+ assert!(!published, "ExecutionUpdate should be suppressed in TUI");
6320
+ let transcript = state.lock().unwrap().transcript.clone();
6321
+ assert!(
6322
+ !transcript
6323
+ .iter()
6324
+ .any(|entry| entry.text.contains("[Command]")),
6325
+ "TUI transcript must not receive redundant [Command] notices"
6326
+ );
6327
+ }
6328
+
5692
6329
  #[test]
5693
6330
  fn mint_watermark_frames_fit_available_terminal_height() {
5694
6331
  for height in [3, 7, WATERMARK_HEIGHT as usize] {
@@ -6765,7 +7402,7 @@ mod dialog_tests {
6765
7402
  let state = state.lock().unwrap();
6766
7403
  assert_eq!(state.transcript.len(), 3);
6767
7404
  let screen = thought_screen(&state, 100, 30).join("\n");
6768
- assert!(screen.contains("Shell completed"));
7405
+ assert!(screen.contains("run_shell completed"));
6769
7406
  assert!(screen.contains("Running 2 tasks · 1 shell command · 1 tool"));
6770
7407
  assert!(!screen.contains("stdout:"));
6771
7408
  }
@@ -6804,7 +7441,7 @@ mod dialog_tests {
6804
7441
  let state = state.lock().unwrap();
6805
7442
  assert_eq!(state.transcript.len(), 2);
6806
7443
  assert_eq!(
6807
- state.transcript[1].rendered_lines[0].style.fg,
7444
+ state.transcript[1].rendered_lines[0].spans[0].style.fg,
6808
7445
  Some(Color::Red)
6809
7446
  );
6810
7447
  assert!(
@@ -6872,6 +7509,10 @@ mod dialog_tests {
6872
7509
  assert_eq!(text.matches("first complete").count(), 1);
6873
7510
  assert_eq!(text.matches("second complete").count(), 1);
6874
7511
  assert!(!text.contains("partial"));
7512
+ let screen = thought_screen(&state, 100, 30).join("\n");
7513
+ assert!(screen.contains("Thought Process · 3.0s"), "{screen}");
7514
+ assert!(screen.contains("Thought 1 · 1.0s"), "{screen}");
7515
+ assert!(screen.contains("Thought 2 · 2.0s"), "{screen}");
6875
7516
  assert_eq!(state.transcript.len(), 2);
6876
7517
  }
6877
7518
  handle.reset_thoughts();
@@ -6953,7 +7594,7 @@ mod dialog_tests {
6953
7594
  assert_eq!(state.transcript.len(), 1);
6954
7595
  assert!(state.handle_thought_key(ctrl_t()));
6955
7596
  assert_eq!(
6956
- state.thought_modal.as_ref().unwrap().lines,
7597
+ state.thought_modal.as_ref().unwrap().lines[1..],
6957
7598
  vec!["complete reasoning"]
6958
7599
  );
6959
7600
  }
@@ -6967,7 +7608,7 @@ mod dialog_tests {
6967
7608
  handle.append_thought_delta("one", " second", std::time::Duration::from_secs(1));
6968
7609
  let mut state = state.lock().unwrap();
6969
7610
  assert_eq!(
6970
- state.thought_modal.as_ref().unwrap().lines,
7611
+ state.thought_modal.as_ref().unwrap().lines[1..],
6971
7612
  vec!["first second"]
6972
7613
  );
6973
7614
  assert!(state.handle_thought_key(make_key(KeyCode::Esc)));
@@ -6993,12 +7634,26 @@ mod dialog_tests {
6993
7634
  );
6994
7635
  assert!(state.handle_thought_key(ctrl_t()));
6995
7636
  assert_eq!(
6996
- state.thought_modal.as_ref().unwrap().lines,
7637
+ state.thought_modal.as_ref().unwrap().lines[1..],
6997
7638
  vec!["unfinished reasoning"]
6998
7639
  );
6999
7640
  assert_eq!(state.transcript.len(), 1);
7000
7641
  }
7001
7642
 
7643
+ #[test]
7644
+ fn queued_message_shows_in_composer_bottom_title() {
7645
+ let mut state = ChatViewState::default();
7646
+ state.queued_count = 1;
7647
+ state.queued_preview = Some("run next test".into());
7648
+ let rendered = thought_screen(&state, 80, 24).join("\n");
7649
+ assert!(rendered.contains("Queued (1): \"run next test\" · Ctrl+D drop"));
7650
+
7651
+ state.queued_count = 2;
7652
+ state.queued_preview = Some("deploy app".into());
7653
+ let rendered2 = thought_screen(&state, 80, 24).join("\n");
7654
+ assert!(rendered2.contains("Queued (2): \"deploy app\" · Ctrl+D drop"));
7655
+ }
7656
+
7002
7657
  #[test]
7003
7658
  fn update_dialog_requires_explicit_selection_before_installing() {
7004
7659
  let (tx, _rx) = mpsc::channel();
@@ -7851,3 +8506,350 @@ mod mod_surface_tests {
7851
8506
  assert!(text.contains("Write tests"));
7852
8507
  }
7853
8508
  }
8509
+
8510
+ #[cfg(test)]
8511
+ mod swarm_panel_tests {
8512
+ use super::*;
8513
+
8514
+ #[test]
8515
+ fn swarm_panel_is_hidden_when_empty() {
8516
+ let state = ChatViewState::default();
8517
+ let backend = ratatui::backend::TestBackend::new(100, 30);
8518
+ let mut terminal = Terminal::new(backend).unwrap();
8519
+ terminal
8520
+ .draw(|frame| {
8521
+ state.render(frame);
8522
+ })
8523
+ .unwrap();
8524
+ let text = terminal
8525
+ .backend()
8526
+ .buffer()
8527
+ .content
8528
+ .iter()
8529
+ .map(|c| c.symbol())
8530
+ .collect::<String>();
8531
+ assert!(!text.contains("Subagents"));
8532
+ }
8533
+
8534
+ #[test]
8535
+ fn swarm_panel_renders_running_and_completed_subagents() {
8536
+ let mut state = ChatViewState::default();
8537
+ state.swarm_agents.push(SwarmAgentUiState {
8538
+ label: "recon".to_string(),
8539
+ profile: "explorer".to_string(),
8540
+ task: "Searching for payment webhook endpoints...".to_string(),
8541
+ current_action: None,
8542
+ status: SwarmUiStatus::Running,
8543
+ started_at: std::time::Instant::now(),
8544
+ finished_elapsed_ms: None,
8545
+ summary_preview: None,
8546
+ });
8547
+ state.swarm_agents.push(SwarmAgentUiState {
8548
+ label: "config".to_string(),
8549
+ profile: "explorer".to_string(),
8550
+ task: "Checking config files".to_string(),
8551
+ current_action: None,
8552
+ status: SwarmUiStatus::Success,
8553
+ started_at: std::time::Instant::now(),
8554
+ finished_elapsed_ms: Some(3000),
8555
+ summary_preview: Some("Checked stripe API keys in .env".to_string()),
8556
+ });
8557
+
8558
+ let backend = ratatui::backend::TestBackend::new(100, 30);
8559
+ let mut terminal = Terminal::new(backend).unwrap();
8560
+ terminal
8561
+ .draw(|frame| {
8562
+ state.render(frame);
8563
+ })
8564
+ .unwrap();
8565
+ let text = terminal
8566
+ .backend()
8567
+ .buffer()
8568
+ .content
8569
+ .iter()
8570
+ .map(|c| c.symbol())
8571
+ .collect::<String>();
8572
+ assert!(text.contains("Running Subagents"));
8573
+ assert!(text.contains("[recon]"));
8574
+ assert!(text.contains("Searching for payment webhook endpoints..."));
8575
+ assert!(text.contains("[config]"));
8576
+ assert!(text.contains("Checked stripe API keys in .env"));
8577
+ assert!(text.contains("done 3s"));
8578
+ }
8579
+
8580
+ #[test]
8581
+ fn swarm_panel_handles_more_than_5_subagents_with_overflow() {
8582
+ let mut state = ChatViewState::default();
8583
+ for i in 1..=7 {
8584
+ state.swarm_agents.push(SwarmAgentUiState {
8585
+ label: format!("agent-{}", i),
8586
+ profile: "explorer".to_string(),
8587
+ task: format!("Task description for agent {}", i),
8588
+ current_action: None,
8589
+ status: SwarmUiStatus::Running,
8590
+ started_at: std::time::Instant::now(),
8591
+ finished_elapsed_ms: None,
8592
+ summary_preview: None,
8593
+ });
8594
+ }
8595
+
8596
+ let backend = ratatui::backend::TestBackend::new(100, 30);
8597
+ let mut terminal = Terminal::new(backend).unwrap();
8598
+ terminal
8599
+ .draw(|frame| {
8600
+ state.render(frame);
8601
+ })
8602
+ .unwrap();
8603
+ let text = terminal
8604
+ .backend()
8605
+ .buffer()
8606
+ .content
8607
+ .iter()
8608
+ .map(|c| c.symbol())
8609
+ .collect::<String>();
8610
+ assert!(text.contains("+3 more subagents..."));
8611
+ }
8612
+
8613
+ #[test]
8614
+ fn swarm_panel_compact_mode_on_short_screen() {
8615
+ let mut state = ChatViewState::default();
8616
+ state.swarm_agents.push(SwarmAgentUiState {
8617
+ label: "recon".to_string(),
8618
+ profile: "explorer".to_string(),
8619
+ task: "Searching files".to_string(),
8620
+ current_action: None,
8621
+ status: SwarmUiStatus::Running,
8622
+ started_at: std::time::Instant::now(),
8623
+ finished_elapsed_ms: None,
8624
+ summary_preview: None,
8625
+ });
8626
+
8627
+ let backend = ratatui::backend::TestBackend::new(80, 20);
8628
+ let mut terminal = Terminal::new(backend).unwrap();
8629
+ terminal
8630
+ .draw(|frame| {
8631
+ state.render(frame);
8632
+ })
8633
+ .unwrap();
8634
+ let text = terminal
8635
+ .backend()
8636
+ .buffer()
8637
+ .content
8638
+ .iter()
8639
+ .map(|c| c.symbol())
8640
+ .collect::<String>();
8641
+ assert!(text.contains("Running 1 subagent"));
8642
+ }
8643
+
8644
+ #[test]
8645
+ fn swarm_agents_cleared_on_user_input_and_clear() {
8646
+ let mut state = ChatViewState::default();
8647
+ state.swarm_agents.push(SwarmAgentUiState {
8648
+ label: "recon".to_string(),
8649
+ profile: "explorer".to_string(),
8650
+ task: "Searching files".to_string(),
8651
+ current_action: None,
8652
+ status: SwarmUiStatus::Running,
8653
+ started_at: std::time::Instant::now(),
8654
+ finished_elapsed_ms: None,
8655
+ summary_preview: None,
8656
+ });
8657
+ assert_eq!(state.swarm_agents.len(), 1);
8658
+
8659
+ state.push_user("hello".to_string());
8660
+ assert!(state.swarm_agents.is_empty());
8661
+
8662
+ state.swarm_agents.push(SwarmAgentUiState {
8663
+ label: "recon".to_string(),
8664
+ profile: "explorer".to_string(),
8665
+ task: "Searching files".to_string(),
8666
+ current_action: None,
8667
+ status: SwarmUiStatus::Running,
8668
+ started_at: std::time::Instant::now(),
8669
+ finished_elapsed_ms: None,
8670
+ summary_preview: None,
8671
+ });
8672
+ state.clear_transcript();
8673
+ assert!(state.swarm_agents.is_empty());
8674
+ }
8675
+
8676
+ #[test]
8677
+ fn record_tool_progress_updates_swarm_state() {
8678
+ let mut state = ChatViewState::default();
8679
+ let start_event = mint_core::AgentProgress::SubagentStarted {
8680
+ subagent: "worker".to_string(),
8681
+ profile: "explorer".to_string(),
8682
+ task: "Investigate database queries".to_string(),
8683
+ };
8684
+ state.record_tool_progress(&start_event);
8685
+ assert_eq!(state.swarm_agents.len(), 1);
8686
+ assert_eq!(state.swarm_agents[0].label, "worker");
8687
+ assert_eq!(state.swarm_agents[0].status, SwarmUiStatus::Running);
8688
+
8689
+ let tool_start = mint_core::AgentProgress::ToolStart {
8690
+ call_id: Some("call-1".to_string()),
8691
+ action: "run_shell".to_string(),
8692
+ input: serde_json::json!({"command": "cargo test"}),
8693
+ subagent: Some("worker".to_string()),
8694
+ };
8695
+ state.record_tool_progress(&tool_start);
8696
+ assert_eq!(
8697
+ state.swarm_agents[0].current_action.as_deref(),
8698
+ Some("Running `cargo test`")
8699
+ );
8700
+ // Subagent tools must NOT be pushed to the main transcript or tools list!
8701
+ assert!(
8702
+ state.transcript.is_empty(),
8703
+ "transcript must stay clean without subagent tool spam"
8704
+ );
8705
+ assert!(
8706
+ state.tools.is_empty(),
8707
+ "tools list must not include subagent micro-tools"
8708
+ );
8709
+
8710
+ let tool_end = mint_core::AgentProgress::ToolEnd {
8711
+ call_id: Some("call-1".to_string()),
8712
+ action: "run_shell".to_string(),
8713
+ input: serde_json::json!({"command": "cargo test"}),
8714
+ result: "test result ok".to_string(),
8715
+ status: Some(mint_core::integrations::mcp_result::ToolStatus::Success),
8716
+ subagent: Some("worker".to_string()),
8717
+ elapsed_ms: Some(120),
8718
+ };
8719
+ state.record_tool_progress(&tool_end);
8720
+ assert!(state.transcript.is_empty());
8721
+ assert!(state.tools.is_empty());
8722
+
8723
+ let finish_event = mint_core::AgentProgress::SubagentFinished {
8724
+ subagent: "worker".to_string(),
8725
+ status: "completed".to_string(),
8726
+ elapsed_ms: 4500,
8727
+ steps: 3,
8728
+ summary_preview: "All queries optimized".to_string(),
8729
+ };
8730
+ state.record_tool_progress(&finish_event);
8731
+ assert_eq!(state.swarm_agents[0].status, SwarmUiStatus::Success);
8732
+ assert_eq!(state.swarm_agents[0].finished_elapsed_ms, Some(4500));
8733
+ assert_eq!(
8734
+ state.swarm_agents[0].summary_preview.as_deref(),
8735
+ Some("All queries optimized")
8736
+ );
8737
+ assert!(state.transcript.is_empty());
8738
+ }
8739
+
8740
+ #[test]
8741
+ fn swarm_panel_renders_smoothly_in_plan_mode() {
8742
+ let mut state = ChatViewState::default();
8743
+ state.plan_mode = true;
8744
+ state.swarm_agents.push(SwarmAgentUiState {
8745
+ label: "recon".to_string(),
8746
+ profile: "explorer".to_string(),
8747
+ task: "Investigating schema for migration".to_string(),
8748
+ current_action: Some("Reading `schema.rs`".to_string()),
8749
+ status: SwarmUiStatus::Running,
8750
+ started_at: std::time::Instant::now(),
8751
+ finished_elapsed_ms: None,
8752
+ summary_preview: None,
8753
+ });
8754
+
8755
+ let backend = ratatui::backend::TestBackend::new(100, 30);
8756
+ let mut terminal = Terminal::new(backend).unwrap();
8757
+ terminal
8758
+ .draw(|frame| {
8759
+ state.render(frame);
8760
+ })
8761
+ .unwrap();
8762
+ let text = terminal
8763
+ .backend()
8764
+ .buffer()
8765
+ .content
8766
+ .iter()
8767
+ .map(|c| c.symbol())
8768
+ .collect::<String>();
8769
+ assert!(text.contains("Running Subagents"));
8770
+ assert!(text.contains("[recon]"));
8771
+ assert!(text.contains("Reading `schema.rs`"));
8772
+ assert!(text.contains("[Plan]"));
8773
+ }
8774
+
8775
+ #[test]
8776
+ fn tool_viewer_smart_jumps_to_web_search_when_sources_present() {
8777
+ use crate::interactive::tool_activity::ToolActivity;
8778
+ use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
8779
+ let mut state = ChatViewState::default();
8780
+ // Tool 0: web_search
8781
+ state.tools.push(ToolActivity {
8782
+ entry: 0,
8783
+ call_id: Some("call_web".into()),
8784
+ action: "web_search".into(),
8785
+ input: serde_json::json!({"query": "cosplay 4khd"}),
8786
+ subagent: None,
8787
+ started: std::time::Instant::now(),
8788
+ elapsed: Some(std::time::Duration::from_millis(1200)),
8789
+ result: Some("1. 4KHD Cosplay\n URL: https://4khd.com\n Preview text".into()),
8790
+ status: Some(mint_core::integrations::mcp_result::ToolStatus::Success),
8791
+ });
8792
+ // Tool 1: run_shell (ran afterwards)
8793
+ state.tools.push(ToolActivity {
8794
+ entry: 1,
8795
+ call_id: Some("call_shell".into()),
8796
+ action: "run_shell".into(),
8797
+ input: serde_json::json!({"command": "echo done"}),
8798
+ subagent: None,
8799
+ started: std::time::Instant::now(),
8800
+ elapsed: Some(std::time::Duration::from_millis(500)),
8801
+ result: Some("exit: 0\nstdout:\ndone\nstderr:".into()),
8802
+ status: Some(mint_core::integrations::mcp_result::ToolStatus::Success),
8803
+ });
8804
+
8805
+ let make_key = |code: KeyCode, modifiers: KeyModifiers| KeyEvent::new(code, modifiers);
8806
+
8807
+ // Without Sources notice, Ctrl+O opens the latest tool (index 1: run_shell)
8808
+ let key = make_key(KeyCode::Char('o'), KeyModifiers::CONTROL);
8809
+ assert!(state.handle_tool_key(key));
8810
+ assert_eq!(state.tool_viewer, Some(1));
8811
+ state.handle_tool_key(make_key(KeyCode::Esc, KeyModifiers::NONE));
8812
+ assert_eq!(state.tool_viewer, None);
8813
+
8814
+ // When Sources notice is in recent transcript, Ctrl+O smart jumps to web_search (index 0)
8815
+ state.push_notice("Sources:\n1. 4KHD Cosplay\n https://4khd.com\n … [+10 more sources] · Ctrl+O view web_search");
8816
+ state.push_notice("─ Worked for 10s • test ──────────────────────────────");
8817
+
8818
+ assert!(state.handle_tool_key(key));
8819
+ assert_eq!(state.tool_viewer, Some(0));
8820
+ assert_eq!(state.tools[state.tool_viewer.unwrap()].action, "web_search");
8821
+ }
8822
+
8823
+ #[test]
8824
+ fn format_tui_web_sources_renders_with_muted_and_blue_spans_in_transcript_entry() {
8825
+ let sources: Vec<(String, String)> = (1..=10)
8826
+ .map(|i| (format!("Title {i}"), format!("https://example.com/{i}")))
8827
+ .collect();
8828
+ let formatted = crate::agent::format_tui_web_sources(&sources, 5);
8829
+ let entry = TranscriptEntry::new(TranscriptRole::Notice, formatted);
8830
+
8831
+ let more_line = entry
8832
+ .rendered_lines
8833
+ .iter()
8834
+ .find(|line| {
8835
+ line.spans
8836
+ .iter()
8837
+ .any(|s| s.content.contains("more sources] · "))
8838
+ })
8839
+ .expect("more sources line should be present");
8840
+
8841
+ let muted_span = more_line
8842
+ .spans
8843
+ .iter()
8844
+ .find(|s| s.content.contains("more sources] · "))
8845
+ .expect("muted span found");
8846
+ assert_eq!(muted_span.style.fg, Some(crate::terminal_theme::MUTED));
8847
+
8848
+ let blue_span = more_line
8849
+ .spans
8850
+ .iter()
8851
+ .find(|s| s.content.contains("Ctrl+O view web_search"))
8852
+ .expect("blue span found");
8853
+ assert_eq!(blue_span.style.fg, Some(crate::terminal_theme::BLUE));
8854
+ }
8855
+ }