@pheem49/mint 1.14.0 → 1.16.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 (925) hide show
  1. package/Cargo.lock +1258 -35
  2. package/Cargo.toml +5 -2
  3. package/LICENSE +21 -654
  4. package/README.md +93 -756
  5. package/Release_Note.md +53 -446
  6. package/apps/mint-companion/src-tauri/Cargo.toml +20 -0
  7. package/apps/mint-companion/src-tauri/build.rs +3 -0
  8. package/apps/mint-companion/src-tauri/src/main.rs +468 -0
  9. package/apps/mint-companion/tsconfig.json +20 -0
  10. package/apps/mint-companion/vite.config.ts +3 -0
  11. package/components.json +19 -0
  12. package/crates/mint-cli/Cargo.toml +9 -1
  13. package/crates/mint-cli/src/agent/approval_prompts.rs +16 -3
  14. package/crates/mint-cli/src/agent/live_status.rs +545 -148
  15. package/crates/mint-cli/src/agent/markdown_render.rs +601 -61
  16. package/crates/mint-cli/src/agent.rs +723 -258
  17. package/crates/mint-cli/src/commands/agent.rs +83 -74
  18. package/crates/mint-cli/src/commands/eval.rs +9 -5
  19. package/crates/mint-cli/src/commands/git.rs +204 -0
  20. package/crates/mint-cli/src/commands/integrations.rs +35 -0
  21. package/crates/mint-cli/src/commands/knowledge.rs +13 -32
  22. package/crates/mint-cli/src/commands/mod.rs +81 -2
  23. package/crates/mint-cli/src/commands/tailnet_web.rs +235 -0
  24. package/crates/mint-cli/src/image.rs +32 -11
  25. package/crates/mint-cli/src/interactive/chat_tui.rs +7853 -0
  26. package/crates/mint-cli/src/interactive/command_ui.rs +477 -0
  27. package/crates/mint-cli/src/interactive/format.rs +8 -0
  28. package/crates/mint-cli/src/interactive/input_box.rs +94 -8
  29. package/crates/mint-cli/src/interactive/picker.rs +180 -37
  30. package/crates/mint-cli/src/interactive/resume_picker.rs +686 -0
  31. package/crates/mint-cli/src/interactive/slash_commands.rs +1071 -501
  32. package/crates/mint-cli/src/interactive/thought_viewer.rs +286 -0
  33. package/crates/mint-cli/src/interactive/tool_activity.rs +328 -0
  34. package/crates/mint-cli/src/interactive.rs +454 -166
  35. package/crates/mint-cli/src/main.rs +93 -26
  36. package/crates/mint-cli/src/markdown.rs +12 -5
  37. package/crates/mint-cli/src/mcp.rs +5 -0
  38. package/crates/mint-cli/src/mod_host.rs +6 -0
  39. package/crates/mint-cli/src/mods_cli.rs +62 -0
  40. package/crates/mint-cli/src/mods_ui.rs +187 -0
  41. package/crates/mint-cli/src/onboard.rs +37 -61
  42. package/crates/mint-cli/src/plugins_cli.rs +8 -5
  43. package/crates/mint-cli/src/setup.rs +10 -8
  44. package/crates/mint-cli/src/terminal_theme.rs +189 -0
  45. package/crates/mint-cli/src/updater.rs +112 -23
  46. package/crates/mint-cli/tests/library_intake.rs +77 -0
  47. package/crates/mint-cli/tests/mods_testing.rs +133 -0
  48. package/crates/mint-companion-protocol/Cargo.toml +10 -0
  49. package/crates/mint-companion-protocol/src/lib.rs +163 -0
  50. package/crates/mint-core/Cargo.toml +6 -3
  51. package/crates/mint-core/build.rs +26 -0
  52. package/crates/mint-core/src/agent/agent_loop.rs +1 -0
  53. package/crates/mint-core/src/agent/chat.rs +1003 -209
  54. package/crates/mint-core/src/agent/code_tools.rs +98 -2
  55. package/crates/mint-core/src/agent/memory/sources.rs +240 -0
  56. package/crates/mint-core/src/agent/memory.rs +805 -33
  57. package/crates/mint-core/src/agent/skill_inventory.rs +325 -0
  58. package/crates/mint-core/src/agent/skills.rs +437 -90
  59. package/crates/mint-core/src/agent.rs +1 -0
  60. package/crates/mint-core/src/api_server/routes/background_jobs.rs +310 -0
  61. package/crates/mint-core/src/api_server/routes/chat.rs +233 -190
  62. package/crates/mint-core/src/api_server/routes/html_preview.rs +77 -0
  63. package/crates/mint-core/src/api_server/routes/library.rs +97 -0
  64. package/crates/mint-core/src/api_server/routes/linked_folders.rs +118 -3
  65. package/crates/mint-core/src/api_server/routes/media_gen.rs +10 -57
  66. package/crates/mint-core/src/api_server/routes/misc.rs +114 -121
  67. package/crates/mint-core/src/api_server/routes/mod.rs +6 -0
  68. package/crates/mint-core/src/api_server/routes/mods.rs +31 -0
  69. package/crates/mint-core/src/api_server/routes/sessions.rs +85 -0
  70. package/crates/mint-core/src/api_server/routes/skills_subagents.rs +12 -42
  71. package/crates/mint-core/src/api_server/routes/slash.rs +50 -1
  72. package/crates/mint-core/src/api_server/routes/sources.rs +101 -0
  73. package/crates/mint-core/src/api_server.rs +140 -12
  74. package/crates/mint-core/src/avatar_bridge.rs +13 -2
  75. package/crates/mint-core/src/browser/cdp.rs +74 -83
  76. package/crates/mint-core/src/browser/evidence.rs +260 -0
  77. package/crates/mint-core/src/browser/input.rs +1 -1
  78. package/crates/mint-core/src/browser/interact.rs +98 -124
  79. package/crates/mint-core/src/browser/lifecycle.rs +75 -4
  80. package/crates/mint-core/src/browser/mod.rs +16 -2
  81. package/crates/mint-core/src/browser/navigate.rs +27 -19
  82. package/crates/mint-core/src/browser/observe.js +40 -0
  83. package/crates/mint-core/src/browser/session.rs +1610 -0
  84. package/crates/mint-core/src/companion.rs +716 -0
  85. package/crates/mint-core/src/cron/scheduler.rs +34 -2
  86. package/crates/mint-core/src/git/branches.rs +348 -0
  87. package/crates/mint-core/src/git/checkpoint.rs +40 -0
  88. package/crates/mint-core/src/git/diff.rs +206 -0
  89. package/crates/mint-core/src/git/mod.rs +10 -2
  90. package/crates/mint-core/src/integrations/channels.rs +88 -345
  91. package/crates/mint-core/src/integrations/mcp.rs +397 -50
  92. package/crates/mint-core/src/integrations/mcp_calls.rs +823 -0
  93. package/crates/mint-core/src/integrations/mcp_catalog.rs +267 -0
  94. package/crates/mint-core/src/integrations/mcp_device.rs +319 -0
  95. package/crates/mint-core/src/integrations/mcp_result.rs +356 -0
  96. package/crates/mint-core/src/integrations/webhooks.rs +539 -0
  97. package/crates/mint-core/src/integrations.rs +2 -0
  98. package/crates/mint-core/src/lib.rs +107 -40
  99. package/crates/mint-core/src/live_sync.rs +28 -9
  100. package/crates/mint-core/src/media/auto_shorts.rs +1 -0
  101. package/crates/mint-core/src/media/gemini_live.rs +145 -14
  102. package/crates/mint-core/src/media/image_models.rs +3 -27
  103. package/crates/mint-core/src/media/image_workflow.rs +216 -0
  104. package/crates/mint-core/src/media/library/intake.rs +144 -0
  105. package/crates/mint-core/src/media/library/migration.rs +56 -0
  106. package/crates/mint-core/src/media/library/removal.rs +55 -0
  107. package/crates/mint-core/src/media/library/tests.rs +730 -0
  108. package/crates/mint-core/src/media/library/thumbnails.rs +72 -0
  109. package/crates/mint-core/src/media/library.rs +545 -0
  110. package/crates/mint-core/src/media/mic_transcribe.rs +1 -0
  111. package/crates/mint-core/src/media/model_catalog.rs +375 -0
  112. package/crates/mint-core/src/media/pictures.rs +79 -222
  113. package/crates/mint-core/src/media/subtitle.rs +1 -0
  114. package/crates/mint-core/src/media/video_models.rs +3 -22
  115. package/crates/mint-core/src/media.rs +3 -0
  116. package/crates/mint-core/src/mods/manager.rs +1124 -0
  117. package/crates/mint-core/src/mods/mod.rs +569 -0
  118. package/crates/mint-core/src/mods/operations.rs +204 -0
  119. package/crates/mint-core/src/mods/session.rs +146 -0
  120. package/crates/mint-core/src/mods/slash.rs +59 -0
  121. package/crates/mint-core/src/mods/telemetry.rs +306 -0
  122. package/crates/mint-core/src/orchestration/approvals.rs +344 -0
  123. package/crates/mint-core/src/orchestration/context_render.rs +105 -0
  124. package/crates/mint-core/src/orchestration/mcp_review.rs +153 -0
  125. package/crates/mint-core/src/orchestration/memory_skill.rs +110 -33
  126. package/crates/mint-core/src/orchestration/mod.rs +3129 -481
  127. package/crates/mint-core/src/orchestration/mod_authoring_regressions.rs +209 -0
  128. package/crates/mint-core/src/orchestration/progress_clock.rs +80 -0
  129. package/crates/mint-core/src/orchestration/repeated_failures.rs +116 -0
  130. package/crates/mint-core/src/orchestration/review_regressions.rs +449 -0
  131. package/crates/mint-core/src/orchestration/run_control.rs +196 -0
  132. package/crates/mint-core/src/orchestration/tools/browser.rs +16 -139
  133. package/crates/mint-core/src/orchestration/tools/files.rs +161 -14
  134. package/crates/mint-core/src/orchestration/tools/media.rs +37 -41
  135. package/crates/mint-core/src/orchestration/tools/misc.rs +5 -3
  136. package/crates/mint-core/src/orchestration/tools/mod.rs +2 -0
  137. package/crates/mint-core/src/orchestration/tools/mods.rs +161 -0
  138. package/crates/mint-core/src/orchestration/tools/plugins_mcp.rs +303 -71
  139. package/crates/mint-core/src/orchestration/tools/shell.rs +95 -2
  140. package/crates/mint-core/src/orchestration/tools/web.rs +1 -1
  141. package/crates/mint-core/src/orchestration/workspace_helpers.rs +4 -1
  142. package/crates/mint-core/src/prompts/agent.rs +75 -31
  143. package/crates/mint-core/src/prompts/chat.rs +1 -1
  144. package/crates/mint-core/src/prompts/persona.rs +1 -1
  145. package/crates/mint-core/src/prompts/tool_catalog.rs +121 -27
  146. package/crates/mint-core/src/search/knowledge.rs +7 -1
  147. package/crates/mint-core/src/search/linked_folders/index.rs +896 -0
  148. package/crates/mint-core/src/search/linked_folders.rs +473 -131
  149. package/crates/mint-core/src/slash/catalog.rs +1 -1
  150. package/crates/mint-core/src/slash/mod.rs +644 -33
  151. package/crates/mint-core/src/slash/model_fetcher.rs +12 -3
  152. package/crates/mint-core/src/slash/models.rs +66 -10
  153. package/crates/mint-core/src/slash/mods.rs +155 -0
  154. package/crates/mint-core/src/system/bg_shell.rs +1129 -95
  155. package/crates/mint-core/src/system/config.rs +235 -10
  156. package/crates/mint-core/src/system/html_preview.rs +398 -0
  157. package/crates/mint-core/src/system/mint_web.rs +164 -0
  158. package/crates/mint-core/src/system/release_notes.rs +18 -0
  159. package/crates/mint-core/src/system/shell.rs +21 -6
  160. package/crates/mint-core/src/system/workspace.rs +292 -0
  161. package/crates/mint-core/src/system/workspace_history.rs +604 -0
  162. package/crates/mint-core/src/system.rs +5 -0
  163. package/crates/mint-core/tests/background_retention.rs +34 -0
  164. package/crates/mint-core/tests/background_shutdown.rs +24 -0
  165. package/crates/mint-core/tests/library_http.rs +209 -0
  166. package/crates/mint-core/tests/mcp_contract.rs +283 -0
  167. package/crates/mint-core/tests/mcp_stdio.rs +11 -10
  168. package/crates/mint-core/tests/media_model_catalog_http.rs +403 -0
  169. package/crates/mint-core/tests/memory_persistence.rs +39 -0
  170. package/crates/mint-core/tests/mods_http.rs +215 -0
  171. package/crates/mint-core/tests/terminal_shutdown.rs +109 -0
  172. package/crates/mint-mod-runtime/Cargo.toml +18 -0
  173. package/crates/mint-mod-runtime/src/lib.rs +507 -0
  174. package/crates/mint-mod-runtime/src/sdk.js +56 -0
  175. package/crates/mint-mod-runtime/src/test_sdk.js +32 -0
  176. package/crates/mint-mod-runtime/src/testing.rs +94 -0
  177. package/crates/mint-mod-runtime/tests/runtime.rs +156 -0
  178. package/docs/mods/AUTHORING.md +61 -0
  179. package/docs/mods/README.md +139 -0
  180. package/docs/mods/TESTING.md +56 -0
  181. package/docs/mods/mint-mods.d.ts +66 -0
  182. package/examples/device-mcp/README.md +22 -0
  183. package/examples/device-mcp/contract.md +49 -0
  184. package/examples/device-mcp/mock-device.mjs +66 -0
  185. package/examples/device-mcp/server.mjs +48 -0
  186. package/examples/device-mcp/server.test.mjs +78 -0
  187. package/examples/mods/task-checklist/README.md +1 -0
  188. package/examples/mods/task-checklist/main.ts +17 -0
  189. package/examples/mods/task-checklist/manifest.json +1 -0
  190. package/examples/mods/task-checklist/tests/checklist.test.ts +15 -0
  191. package/examples/mods/token-meter/README.md +1 -0
  192. package/examples/mods/token-meter/main.ts +8 -0
  193. package/examples/mods/token-meter/manifest.json +1 -0
  194. package/examples/mods/tool-guard/README.md +1 -0
  195. package/examples/mods/tool-guard/main.ts +9 -0
  196. package/examples/mods/tool-guard/manifest.json +1 -0
  197. package/out/web/assets/CliSessionsView-CtzUJpK_.css +1 -0
  198. package/out/web/assets/CliSessionsView-D7hw0Mgj.js +1 -0
  199. package/out/web/assets/CodeReviewPage-C7bEOJfd.js +4 -0
  200. package/out/web/assets/CodeReviewPage-Dte9uLiL.css +1 -0
  201. package/out/web/assets/CommandPalette-0RrF-AOT.js +1 -0
  202. package/out/web/assets/ImageStudioPanel-CdxkAf_r.js +1 -0
  203. package/out/web/assets/ImageStudioPanel-D0lnhQV5.css +1 -0
  204. package/out/web/assets/LibraryPage--Qfisp6D.js +2 -0
  205. package/out/web/assets/LibraryPage-DAxUTAg7.css +1 -0
  206. package/out/web/assets/LinkedFoldersView-2nfZbDgN.js +1 -0
  207. package/out/web/assets/McpRegistryPicker-h9uS8_wT.js +1 -0
  208. package/out/web/assets/McpServersView-slfQJzNB.js +1 -0
  209. package/out/web/assets/MintDashboard-BSR5XpXh.js +25 -0
  210. package/out/web/assets/MintDashboard-CWUcCGhd.css +1 -0
  211. package/out/web/assets/PluginsView-l7LSm503.js +1 -0
  212. package/out/web/assets/ScheduledTasksView-CttmLbq1.js +1 -0
  213. package/out/web/assets/SettingsWindow-BCMLYvEV.js +4 -0
  214. package/out/web/assets/SettingsWindow-DcMVmU9u.css +1 -0
  215. package/out/web/assets/SkillsView-rNs1qr_U.js +2 -0
  216. package/out/web/assets/ToolSurfacePage-B9DzEPWN.js +37 -0
  217. package/out/web/assets/ToolSurfacePage-CTfgggF2.css +1 -0
  218. package/out/web/assets/VeoStudioPanel-DOj7_WR3.css +1 -0
  219. package/out/web/assets/VeoStudioPanel-DiJs_Cg2.js +4 -0
  220. package/out/web/assets/WorkspacePanel-CbJ1PFoZ.js +1 -0
  221. package/out/web/assets/WorkspaceSelector-B2xIp04D.js +1 -0
  222. package/out/web/assets/WorkspaceSelector-Ca8uJOsS.css +1 -0
  223. package/out/web/assets/{abnfDiagram-VCTEODGH-DAOBA7ZG.js → abnfDiagram-VCTEODGH-CD0CjoGl.js} +1 -1
  224. package/out/web/assets/{architecture-7GRP2DOG-CgSwQOPQ.js → architecture-7GRP2DOG-RKV83OeZ.js} +1 -1
  225. package/out/web/assets/{architectureDiagram-5GKGNRK7-CYp3yupP.js → architectureDiagram-5GKGNRK7-nN_HAFct.js} +1 -1
  226. package/out/web/assets/{blockDiagram-NRAW4CY4-CyWybDWr.js → blockDiagram-NRAW4CY4-BrrqzHW5.js} +1 -1
  227. package/out/web/assets/{c4Diagram-UCG6FXSJ-BvY3U709.js → c4Diagram-UCG6FXSJ-DTdV8_zE.js} +1 -1
  228. package/out/web/assets/{chunk-75Z2AOVW-TLXCoZYv.js → chunk-75Z2AOVW-_M0z5olV.js} +1 -1
  229. package/out/web/assets/chunk-CKBBP62Z-BpQEgeHF.js +2 -0
  230. package/out/web/assets/{chunk-CLGD4ZFX-xjsKtNS7.js → chunk-CLGD4ZFX-D54yGvGS.js} +1 -1
  231. package/out/web/assets/chunk-DSNCTWBM-C-gvT2ru.js +2 -0
  232. package/out/web/assets/chunk-DU6HZSFF-CnFngIhW.js +128 -0
  233. package/out/web/assets/{chunk-F27PBJKO-BFpgF55A.js → chunk-F27PBJKO-BqtWrnEO.js} +1 -1
  234. package/out/web/assets/{chunk-G27WJ6UU-DfF7qW-C.js → chunk-G27WJ6UU-Ckoq5mi2.js} +1 -1
  235. package/out/web/assets/{chunk-GMAD6QVW-C-558kh_.js → chunk-GMAD6QVW-BuhEcgHq.js} +1 -1
  236. package/out/web/assets/{chunk-JQ64N6SF-wJmeGKAw.js → chunk-JQ64N6SF-CF8T7GiZ.js} +1 -1
  237. package/out/web/assets/{chunk-LCL6LL3I-C1wHD8Ie.js → chunk-LCL6LL3I-BhXV9zyH.js} +1 -1
  238. package/out/web/assets/{chunk-OBVCFTLP-BsRTPBqs.js → chunk-OBVCFTLP-CRIkunUB.js} +1 -1
  239. package/out/web/assets/{chunk-P2QGCYS3-HZIiM7Ni.js → chunk-P2QGCYS3-UFEU6BxZ.js} +1 -1
  240. package/out/web/assets/{chunk-POPQ4Y6H-Dk9wvVb0.js → chunk-POPQ4Y6H-CQcrNbjr.js} +1 -1
  241. package/out/web/assets/{chunk-PWAF6VOD-BmjYLNbq.js → chunk-PWAF6VOD-Cc2uVDsG.js} +1 -1
  242. package/out/web/assets/{chunk-R7TYR2AO-CaHIf-lK.js → chunk-R7TYR2AO-DiCxzdAY.js} +1 -1
  243. package/out/web/assets/{chunk-RHFEMEQ7-_T561hOU.js → chunk-RHFEMEQ7-b7hnPmrR.js} +1 -1
  244. package/out/web/assets/{chunk-SVP7TREG-CM-GGYoY.js → chunk-SVP7TREG-Bu_yYb-V.js} +1 -1
  245. package/out/web/assets/{chunk-TEH6E4GO-K2A8Vg2C.js → chunk-TEH6E4GO-G4Cdlyrt.js} +1 -1
  246. package/out/web/assets/classDiagram-DTDB5LWJ-RnC2mYO4.js +1 -0
  247. package/out/web/assets/classDiagram-v2-JRS7N3AN-RnC2mYO4.js +1 -0
  248. package/out/web/assets/config-CnvCChUM.js +2 -0
  249. package/out/web/assets/config-DM6oIVO3.css +1 -0
  250. package/out/web/assets/core-DsKkQ7ig.js +1 -0
  251. package/out/web/assets/{cynefin-OW5HDTMX-ClzaB6cc.js → cynefin-OW5HDTMX-CnzQfOGp.js} +1 -1
  252. package/out/web/assets/{cynefinDiagram-5FMLGOSQ-D_JzZBzf.js → cynefinDiagram-5FMLGOSQ-DVtQnfpm.js} +1 -1
  253. package/out/web/assets/{dagre-3AP2YEHR-BDuUeMHj.js → dagre-3AP2YEHR-DG76_k5_.js} +1 -1
  254. package/out/web/assets/{diagram-S7CK7UJ4-DgtcfE8P.js → diagram-S7CK7UJ4-CaouUoze.js} +1 -1
  255. package/out/web/assets/{diagram-UQ7AKVKN-DTLoEYti.js → diagram-UQ7AKVKN-B4bEc26B.js} +1 -1
  256. package/out/web/assets/{diagram-VSXAHHWV-ChGl9pXz.js → diagram-VSXAHHWV-BJ86Ov2Y.js} +1 -1
  257. package/out/web/assets/{diagram-VX7I27RA-Be8DWz0S.js → diagram-VX7I27RA-7hH5IPYf.js} +1 -1
  258. package/out/web/assets/{diagram-Z3DM3KII-BMXjRTOF.js → diagram-Z3DM3KII-CCM4clo8.js} +1 -1
  259. package/out/web/assets/dist-js-BkYNznHX.js +1 -0
  260. package/out/web/assets/{ebnfDiagram-PWID7BFC-8Q9pl1CJ.js → ebnfDiagram-PWID7BFC-Da7WAM3k.js} +1 -1
  261. package/out/web/assets/{erDiagram-SSCWMZ5O-DjH8Lnkn.js → erDiagram-SSCWMZ5O-CzzmnZWT.js} +1 -1
  262. package/out/web/assets/event-Cdt7Byyj.js +1 -0
  263. package/out/web/assets/{eventmodeling-NTZA5JFV-BKUH_DOp.js → eventmodeling-NTZA5JFV-xcfsA0XD.js} +1 -1
  264. package/out/web/assets/fira-code-latin-600-normal-BmSSHshu.woff +0 -0
  265. package/out/web/assets/fira-code-latin-600-normal-CvYZpPHg.woff2 +0 -0
  266. package/out/web/assets/fira-code-symbols2-600-normal-Dvq6IQE5.woff +0 -0
  267. package/out/web/assets/flowDiagram-A5DVABFB-JdtH1673.js +1 -0
  268. package/out/web/assets/{ganttDiagram-EL5Y4UJY-D7fZKJNM.js → ganttDiagram-EL5Y4UJY-B3ClFGmL.js} +1 -1
  269. package/out/web/assets/{gitGraph-4MIJSDKK-BypWaaBU.js → gitGraph-4MIJSDKK-BZ_y_cDU.js} +1 -1
  270. package/out/web/assets/{gitGraphDiagram-WWUBYQGX-DWiw_3bq.js → gitGraphDiagram-WWUBYQGX-drhRSYm3.js} +1 -1
  271. package/out/web/assets/index-BZ9xgmMP.css +1 -0
  272. package/out/web/assets/index-Ca8cCS4h.js +168 -0
  273. package/out/web/assets/{info-A6RAGUB7-KkAUxT4j.js → info-A6RAGUB7-B7I3K0F1.js} +1 -1
  274. package/out/web/assets/{infoDiagram-RXCK75RN-BNb6E48y.js → infoDiagram-RXCK75RN-deX_1MPh.js} +1 -1
  275. package/out/web/assets/{ishikawaDiagram-5VMMS53U-Caa-JoAK.js → ishikawaDiagram-5VMMS53U-s38yo28y.js} +1 -1
  276. package/out/web/assets/{journeyDiagram-EYS64GPL-DOrmFGz6.js → journeyDiagram-EYS64GPL-CZn2kB8b.js} +1 -1
  277. package/out/web/assets/jsx-runtime-DN4NhQUK.js +1 -0
  278. package/out/web/assets/{kanban-definition-3QL26DDD-BOWCYcK0.js → kanban-definition-3QL26DDD-DodjgySL.js} +1 -1
  279. package/out/web/assets/markdown-CMhYIcWB.js +39 -0
  280. package/out/web/assets/{mermaid-parser.core-BQqjCkS_.js → mermaid-parser.core-Whu2rlJC.js} +3 -3
  281. package/out/web/assets/mermaid.core-CKyPo8VH.js +11 -0
  282. package/out/web/assets/{mindmap-definition-FBJOCRG2-jTceWpr0.js → mindmap-definition-FBJOCRG2-260WBDxZ.js} +1 -1
  283. package/out/web/assets/modelManager-CUaGWMWu.js +2 -0
  284. package/out/web/assets/oauthManager-DlNhXJr6.js +1 -0
  285. package/out/web/assets/{packet-AYTQ26CC-CJ5RXgol.js → packet-AYTQ26CC-CEeIRKRG.js} +1 -1
  286. package/out/web/assets/{pegDiagram-XKGWAZYB-y8wMtd0y.js → pegDiagram-XKGWAZYB-BYadI-KO.js} +1 -1
  287. package/out/web/assets/{pie-WAS4IAKB-72fTBbl4.js → pie-WAS4IAKB-D8uf4dh5.js} +1 -1
  288. package/out/web/assets/{pieDiagram-E7YTZNPT-e0O02qWq.js → pieDiagram-E7YTZNPT-CjSDy4hO.js} +1 -1
  289. package/out/web/assets/{quadrantDiagram-AXDQQJYC-C9phYLom.js → quadrantDiagram-AXDQQJYC-B8D3gU5d.js} +1 -1
  290. package/out/web/assets/{radar-RG4KPBEZ-BAU2hzUT.js → radar-RG4KPBEZ-DZJxnokY.js} +1 -1
  291. package/out/web/assets/{railroad-74A4TZTK-B0bCAVHC.js → railroad-74A4TZTK-DBysUiUi.js} +1 -1
  292. package/out/web/assets/{railroad-abnf-HS5TGJTU-WhxO7ndE.js → railroad-abnf-HS5TGJTU-CHWxoJYg.js} +1 -1
  293. package/out/web/assets/{railroad-ebnf-LZEXJU2U-BkA0m7-F.js → railroad-ebnf-LZEXJU2U-DDv7X6bY.js} +1 -1
  294. package/out/web/assets/{railroad-peg-WCYAUIDC-BsVpHIaj.js → railroad-peg-WCYAUIDC-DpfcYYNJ.js} +1 -1
  295. package/out/web/assets/{railroadDiagram-O6MQD6OU-CyOLN65Q.js → railroadDiagram-O6MQD6OU-CYtyv0t3.js} +1 -1
  296. package/out/web/assets/{requirementDiagram-EFPCY7ZU-DQXJ7Dud.js → requirementDiagram-EFPCY7ZU-D2X-Ewik.js} +1 -1
  297. package/out/web/assets/{sankeyDiagram-P5KCCOFB-B2XLyIIc.js → sankeyDiagram-P5KCCOFB-Bn2x6C4Y.js} +1 -1
  298. package/out/web/assets/{sequenceDiagram-WJ2MYXX4-DGQY4wwm.js → sequenceDiagram-WJ2MYXX4-BvFLKtPd.js} +1 -1
  299. package/out/web/assets/{stateDiagram-HBIQ2CUA-DHZpDwNy.js → stateDiagram-HBIQ2CUA-Bx0GWeaY.js} +1 -1
  300. package/out/web/assets/stateDiagram-v2-4QOOHH4V--hol1yg_.js +1 -0
  301. package/out/web/assets/studio-B1mk40wD.js +1 -0
  302. package/out/web/assets/{swimlanes-XN3QIQJK-Bn_jcZz-.js → swimlanes-XN3QIQJK-CCma0T7L.js} +1 -1
  303. package/out/web/assets/swimlanesDiagram-VK2B7HYN-BkohoVsU.js +8 -0
  304. package/out/web/assets/{timeline-definition-24CTP7MA-CdTERuJZ.js → timeline-definition-24CTP7MA-iCRhhJ7C.js} +1 -1
  305. package/out/web/assets/{treeView-Q6P3EWNA-TKBKQG6R.js → treeView-Q6P3EWNA-DZ-y08qp.js} +1 -1
  306. package/out/web/assets/{treemap-WGGIJYW6-BP7gQoiC.js → treemap-WGGIJYW6-De0CxzMx.js} +1 -1
  307. package/out/web/assets/{vennDiagram-4TSXK5OY-BHUmxDuK.js → vennDiagram-4TSXK5OY-w_7aZ6xe.js} +1 -1
  308. package/out/web/assets/{wardley-WFR3VGLG-9bct5AAN.js → wardley-WFR3VGLG-DT0y0xJ4.js} +1 -1
  309. package/out/web/assets/{wardleyDiagram-VM6X3IG4-BfJwDDso.js → wardleyDiagram-VM6X3IG4-DAdXELbQ.js} +1 -1
  310. package/out/web/assets/window-BJCVtyET.js +1 -0
  311. package/out/web/assets/{xychartDiagram-S5SC5T6Z-Dqd9Mvpo.js → xychartDiagram-S5SC5T6Z-IZIXf3Vo.js} +1 -1
  312. package/out/web/index-web.html +4 -4
  313. package/out/web/index.html +4 -4
  314. package/package.json +80 -20
  315. package/shared-modules/.github/workflows/ci.yml +120 -0
  316. package/shared-modules/.github/workflows/update.yaml +28 -0
  317. package/slash-commands.json +16 -2
  318. package/src/bin/auto-build.js +66 -0
  319. package/src/bin/desktop.js +113 -0
  320. package/src/bin/desktop.test.js +113 -0
  321. package/src/bin/index.js +18 -25
  322. package/src/bin/index.test.js +89 -0
  323. package/src/bin/measure-effects.mjs +53 -0
  324. package/src/bin/package.test.js +28 -0
  325. package/src/bin/release-notes.test.js +84 -0
  326. package/src/bin/styles.test.js +20 -0
  327. package/src/bin/web.js +5 -0
  328. package/src/bin/web.test.js +39 -0
  329. package/src/renderer/index-web.html +1 -0
  330. package/src/renderer/index.html +1 -2
  331. package/src/renderer/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  332. package/src/renderer/shared/agentProgress.ts +201 -3
  333. package/src/renderer/shared/components/AgentActivityDrawer.tsx +9 -8
  334. package/src/renderer/shared/components/AgentActivityTable.tsx +193 -133
  335. package/src/renderer/shared/components/ApprovalCard.test.tsx +24 -0
  336. package/src/renderer/shared/components/ApprovalCard.tsx +10 -3
  337. package/src/renderer/shared/components/ArtifactPreviewPanel.tsx +91 -40
  338. package/src/renderer/shared/components/AuthGate.tsx +79 -48
  339. package/src/renderer/shared/components/BackgroundTerminals.tsx +181 -0
  340. package/src/renderer/shared/components/CalculationCard.tsx +41 -15
  341. package/src/renderer/shared/components/ChatCodeBlock.tsx +8 -4
  342. package/src/renderer/shared/components/ChatMessageItem.test.tsx +68 -0
  343. package/src/renderer/shared/components/ChatMessageItem.tsx +52 -33
  344. package/src/renderer/shared/components/ChatPanel.test.tsx +21 -0
  345. package/src/renderer/shared/components/ChatPanel.tsx +676 -415
  346. package/src/renderer/shared/components/ChunkErrorBoundary.tsx +115 -64
  347. package/src/renderer/shared/components/CliSessionsView.test.tsx +125 -0
  348. package/src/renderer/shared/components/CliSessionsView.tsx +543 -0
  349. package/src/renderer/shared/components/CodeReviewPage.tsx +668 -0
  350. package/src/renderer/shared/components/CollapsiblePasteInput.tsx +90 -0
  351. package/src/renderer/shared/components/CommandPalette.tsx +8 -8
  352. package/src/renderer/shared/components/ContextCompactionStatus.tsx +17 -0
  353. package/src/renderer/shared/components/DashboardSidebar.tsx +853 -229
  354. package/src/renderer/shared/components/DesktopTitlebar.tsx +371 -0
  355. package/src/renderer/shared/components/DiffReviewModal.tsx +3 -3
  356. package/src/renderer/shared/components/ErrorNotice.tsx +29 -0
  357. package/src/renderer/shared/components/FormattedMessage.tsx +11 -0
  358. package/src/renderer/shared/components/GeminiLiveOverlay.css +86 -0
  359. package/src/renderer/shared/components/GeminiLiveOverlay.test.tsx +24 -0
  360. package/src/renderer/shared/components/GeminiLiveOverlay.tsx +85 -101
  361. package/src/renderer/shared/components/GitBranchSelector.tsx +442 -0
  362. package/src/renderer/shared/components/GlideSelect.css +138 -0
  363. package/src/renderer/shared/components/GlideSelect.d.ts +31 -0
  364. package/src/renderer/shared/components/GlideSelect.jsx +266 -0
  365. package/src/renderer/shared/components/ImageGenCard.tsx +31 -12
  366. package/src/renderer/shared/components/ImageSearchCard.tsx +76 -65
  367. package/src/renderer/shared/components/ImageStudioPanel.tsx +49 -49
  368. package/src/renderer/shared/components/InlineThoughtNote.tsx +27 -0
  369. package/src/renderer/shared/components/LibraryItemCard.tsx +72 -0
  370. package/src/renderer/shared/components/LibraryPage.tsx +165 -0
  371. package/src/renderer/shared/components/LibraryPreview.tsx +59 -0
  372. package/src/renderer/shared/components/LinkedFoldersView.tsx +365 -46
  373. package/src/renderer/shared/components/McpRegistryPicker.tsx +1 -1
  374. package/src/renderer/shared/components/McpServersView.tsx +51 -30
  375. package/src/renderer/shared/components/McpToolAllowlist.tsx +2 -4
  376. package/src/renderer/shared/components/McpToolResults.tsx +99 -0
  377. package/src/renderer/shared/components/MermaidCard.tsx +14 -8
  378. package/src/renderer/shared/components/MintDashboard.tsx +1002 -831
  379. package/src/renderer/shared/components/ModSessionControls.tsx +8 -0
  380. package/src/renderer/shared/components/ModUi.test.tsx +65 -0
  381. package/src/renderer/shared/components/ModUi.tsx +26 -0
  382. package/src/renderer/shared/components/ModelSelectorPopover.tsx +547 -219
  383. package/src/renderer/shared/components/ModsPanel.tsx +156 -0
  384. package/src/renderer/shared/components/PlanChecklistWidget.tsx +1 -1
  385. package/src/renderer/shared/components/PluginsView.tsx +1 -1
  386. package/src/renderer/shared/components/ProgressActivity.tsx +17 -0
  387. package/src/renderer/shared/components/ReviewHistory.tsx +42 -0
  388. package/src/renderer/shared/components/RewindModal.tsx +11 -18
  389. package/src/renderer/shared/components/RunSummaryDashboard.tsx +8 -14
  390. package/src/renderer/shared/components/ScheduledTasksView.tsx +11 -10
  391. package/src/renderer/shared/components/ScreenCaptureDialog.css +221 -0
  392. package/src/renderer/shared/components/ScreenCaptureDialog.tsx +199 -0
  393. package/src/renderer/shared/components/SelectField.test.tsx +27 -0
  394. package/src/renderer/shared/components/SelectField.tsx +38 -0
  395. package/src/renderer/shared/components/SessionSources.tsx +48 -0
  396. package/src/renderer/shared/components/SessionSourcesPopover.tsx +61 -0
  397. package/src/renderer/shared/components/Settings/AgentsTab.tsx +41 -45
  398. package/src/renderer/shared/components/Settings/AudioTab.tsx +16 -15
  399. package/src/renderer/shared/components/Settings/AutomationTab.tsx +10 -60
  400. package/src/renderer/shared/components/Settings/AvatarCropModal.tsx +368 -0
  401. package/src/renderer/shared/components/Settings/GeneralTab.tsx +368 -113
  402. package/src/renderer/shared/components/Settings/MemoryTab.test.tsx +37 -0
  403. package/src/renderer/shared/components/Settings/MemoryTab.tsx +71 -31
  404. package/src/renderer/shared/components/Settings/NotificationsTab.test.tsx +15 -0
  405. package/src/renderer/shared/components/Settings/NotificationsTab.tsx +84 -0
  406. package/src/renderer/shared/components/Settings/PluginsTab.tsx +20 -12
  407. package/src/renderer/shared/components/Settings/ProfileTab.tsx +29 -5
  408. package/src/renderer/shared/components/Settings/SearchableModelCombobox.tsx +411 -0
  409. package/src/renderer/shared/components/Settings/ThemeTab.tsx +416 -165
  410. package/src/renderer/shared/components/SkillsView.tsx +41 -16
  411. package/src/renderer/shared/components/SlashChoicePanel.tsx +88 -0
  412. package/src/renderer/shared/components/SlashSuggestions.test.tsx +33 -0
  413. package/src/renderer/shared/components/SlashSuggestions.tsx +41 -12
  414. package/src/renderer/shared/components/SourcesBlock.tsx +55 -51
  415. package/src/renderer/shared/components/StockCard.tsx +58 -24
  416. package/src/renderer/shared/components/SubagentDagView.tsx +4 -4
  417. package/src/renderer/shared/components/TerminalDock.tsx +241 -0
  418. package/src/renderer/shared/components/ThinkingBlock.tsx +14 -8
  419. package/src/renderer/shared/components/ToolSurfacePage.test.tsx +32 -0
  420. package/src/renderer/shared/components/ToolSurfacePage.tsx +568 -0
  421. package/src/renderer/shared/components/ToolsPanelToggle.tsx +13 -0
  422. package/src/renderer/shared/components/UiFeatureCard.tsx +267 -0
  423. package/src/renderer/shared/components/UiGridCard.tsx +188 -0
  424. package/src/renderer/shared/components/UiMockupWidget.tsx +149 -0
  425. package/src/renderer/shared/components/VeoStudioPanel.tsx +22 -37
  426. package/src/renderer/shared/components/ViewedImages.tsx +36 -0
  427. package/src/renderer/shared/components/VirtualChatHistory.tsx +82 -0
  428. package/src/renderer/shared/components/VoicePill.css +85 -0
  429. package/src/renderer/shared/components/VoicePill.d.ts +12 -0
  430. package/src/renderer/shared/components/VoicePill.jsx +190 -0
  431. package/src/renderer/shared/components/VoicePill.test.tsx +22 -0
  432. package/src/renderer/shared/components/WeatherCard.tsx +3 -3
  433. package/src/renderer/shared/components/WorkspaceContextPopover.tsx +138 -0
  434. package/src/renderer/shared/components/WorkspacePaneResizer.tsx +92 -0
  435. package/src/renderer/shared/components/WorkspacePreviewActions.test.tsx +44 -0
  436. package/src/renderer/shared/components/WorkspacePreviewActions.tsx +19 -0
  437. package/src/renderer/shared/components/WorkspaceSelector.tsx +154 -0
  438. package/src/renderer/shared/components/background-terminals.css +292 -0
  439. package/src/renderer/shared/components/ui/README.md +52 -0
  440. package/src/renderer/shared/components/ui/button.tsx +37 -0
  441. package/src/renderer/shared/components/ui/demo.tsx +26 -0
  442. package/src/renderer/shared/components/ui/error-recovery.css +35 -0
  443. package/src/renderer/shared/components/ui/error-recovery.tsx +35 -0
  444. package/src/renderer/shared/components/ui/voice-powered-orb.css +6 -0
  445. package/src/renderer/shared/components/ui/voice-powered-orb.tsx +374 -0
  446. package/src/renderer/shared/components/workspace-selector.css +248 -0
  447. package/src/renderer/shared/constants/config.ts +57 -3
  448. package/src/renderer/shared/constants/models.ts +189 -2
  449. package/src/renderer/shared/constants/slashCommands.ts +1 -1
  450. package/src/renderer/shared/conversation/coordinator.test.ts +27 -0
  451. package/src/renderer/shared/conversation/coordinator.ts +82 -0
  452. package/src/renderer/shared/conversation/lifecycle.test.ts +362 -0
  453. package/src/renderer/shared/conversation/lifecycle.ts +418 -0
  454. package/src/renderer/shared/conversation/projectNavigation.test.ts +105 -0
  455. package/src/renderer/shared/conversation/projectNavigation.ts +39 -0
  456. package/src/renderer/shared/conversation/sourcesTransport.ts +27 -0
  457. package/src/renderer/shared/conversation/syncView.test.ts +13 -0
  458. package/src/renderer/shared/conversation/syncView.ts +6 -0
  459. package/src/renderer/shared/conversation/transport.test.ts +163 -0
  460. package/src/renderer/shared/conversation/transport.ts +159 -0
  461. package/src/renderer/shared/conversation/useConversationCoordinator.ts +64 -0
  462. package/src/renderer/shared/css/agent-observability.css +46 -15
  463. package/src/renderer/shared/css/auth-gate.css +114 -15
  464. package/src/renderer/shared/css/chat-ui-cards.css +495 -0
  465. package/src/renderer/shared/css/code-review.css +856 -0
  466. package/src/renderer/shared/css/code-sessions.css +479 -0
  467. package/src/renderer/shared/css/collapsed-paste.css +35 -0
  468. package/src/renderer/shared/css/effects.css +15 -0
  469. package/src/renderer/shared/css/error-notice.css +60 -0
  470. package/src/renderer/shared/css/file-changes.css +132 -0
  471. package/src/renderer/shared/css/image-studio.css +16 -16
  472. package/src/renderer/shared/css/library.css +476 -0
  473. package/src/renderer/shared/css/management-views.css +415 -27
  474. package/src/renderer/shared/css/mcp-results.css +11 -0
  475. package/src/renderer/shared/css/model-selector.css +543 -85
  476. package/src/renderer/shared/css/mods.css +77 -0
  477. package/src/renderer/shared/css/notification-notice.css +28 -0
  478. package/src/renderer/shared/css/session-sources-popover.css +9 -0
  479. package/src/renderer/shared/css/session-sources.css +23 -0
  480. package/src/renderer/shared/css/settings/agents.css +1 -1
  481. package/src/renderer/shared/css/settings/automation.css +13 -13
  482. package/src/renderer/shared/css/settings/general.css +526 -5
  483. package/src/renderer/shared/css/settings/memory.css +154 -0
  484. package/src/renderer/shared/css/settings/notifications.css +11 -0
  485. package/src/renderer/shared/css/settings/plugins.css +5 -5
  486. package/src/renderer/shared/css/settings/profile.css +331 -1
  487. package/src/renderer/shared/css/settings/theme.css +656 -3
  488. package/src/renderer/shared/css/slash-choice.css +95 -0
  489. package/src/renderer/shared/css/slash-suggestions.css +68 -0
  490. package/src/renderer/shared/css/sources-block.css +91 -0
  491. package/src/renderer/shared/css/thinking-status.css +46 -0
  492. package/src/renderer/shared/css/tools-panel.css +7 -0
  493. package/src/renderer/shared/css/ui-tailwind.css +19 -0
  494. package/src/renderer/shared/css/veo-studio.css +16 -15
  495. package/src/renderer/shared/css/viewed-images.css +15 -0
  496. package/src/renderer/shared/fonts.css +46 -0
  497. package/src/renderer/shared/fonts.ts +10 -37
  498. package/src/renderer/shared/lib/utils.ts +6 -0
  499. package/src/renderer/shared/library/controller.test.ts +61 -0
  500. package/src/renderer/shared/library/controller.ts +57 -0
  501. package/src/renderer/shared/library/transport.test.ts +26 -0
  502. package/src/renderer/shared/library/transport.ts +60 -0
  503. package/src/renderer/shared/library/useLibraryFile.ts +38 -0
  504. package/src/renderer/shared/mods.ts +58 -0
  505. package/src/renderer/shared/platform.test.ts +90 -0
  506. package/src/renderer/shared/platform.ts +219 -7
  507. package/src/renderer/shared/theme/themeManager.test.ts +43 -0
  508. package/src/renderer/shared/theme/themeManager.ts +157 -0
  509. package/src/renderer/shared/theme/themes.ts +116 -0
  510. package/src/renderer/shared/theme/tokens.css +318 -0
  511. package/src/renderer/shared/types.ts +137 -2
  512. package/src/renderer/shared/utils/agentActivity.test.ts +75 -0
  513. package/src/renderer/shared/utils/agentActivity.ts +168 -8
  514. package/src/renderer/shared/utils/approval.tsx +7 -0
  515. package/src/renderer/shared/utils/artifactBrowser.test.ts +80 -0
  516. package/src/renderer/shared/utils/artifactBrowser.ts +41 -0
  517. package/src/renderer/shared/utils/cardJson.test.ts +35 -0
  518. package/src/renderer/shared/utils/cardJson.ts +30 -0
  519. package/src/renderer/shared/utils/contextCompaction.test.tsx +48 -0
  520. package/src/renderer/shared/utils/contextCompaction.ts +21 -0
  521. package/src/renderer/shared/utils/effectVisibility.ts +9 -0
  522. package/src/renderer/shared/utils/fileIcons.ts +1 -1
  523. package/src/renderer/shared/utils/markdown.tsx +330 -81
  524. package/src/renderer/shared/utils/markdown.webImages.test.tsx +40 -0
  525. package/src/renderer/shared/utils/mcpResults.test.tsx +91 -0
  526. package/src/renderer/shared/utils/modViewport.ts +7 -0
  527. package/src/renderer/shared/utils/nativeRecordingSession.test.ts +61 -0
  528. package/src/renderer/shared/utils/nativeRecordingSession.ts +46 -0
  529. package/src/renderer/shared/utils/notificationSettings.test.ts +14 -0
  530. package/src/renderer/shared/utils/notificationSettings.ts +23 -0
  531. package/src/renderer/shared/utils/notifications.test.ts +51 -0
  532. package/src/renderer/shared/utils/notifications.ts +54 -0
  533. package/src/renderer/shared/utils/pastedText.test.ts +20 -0
  534. package/src/renderer/shared/utils/pastedText.ts +13 -0
  535. package/src/renderer/shared/utils/progressCache.test.ts +32 -0
  536. package/src/renderer/shared/utils/providers.ts +8 -3
  537. package/src/renderer/shared/utils/screenCapture.ts +43 -0
  538. package/src/renderer/shared/utils/sessionSources.test.ts +31 -0
  539. package/src/renderer/shared/utils/sessionSources.ts +34 -0
  540. package/src/renderer/shared/utils/slashCommandProcessor.ts +5 -2
  541. package/src/renderer/shared/utils/sourceAttachments.ts +28 -0
  542. package/src/renderer/shared/utils/speech.ts +51 -9
  543. package/src/renderer/shared/utils/syntaxHighlight.test.tsx +22 -0
  544. package/src/renderer/shared/utils/syntaxHighlight.tsx +26 -0
  545. package/src/renderer/shared/utils/ui.ts +4 -64
  546. package/src/renderer/shared/utils/useGeminiLiveVoice.ts +49 -5
  547. package/src/renderer/shared/utils/useLatestCallback.ts +9 -0
  548. package/src/renderer/shared/utils/useNativeVoiceInput.ts +80 -72
  549. package/src/renderer/shared/utils/useSessionSources.ts +33 -0
  550. package/src/renderer/shared/utils/viewedImages.ts +26 -0
  551. package/src/renderer/shared/utils/workspacePane.test.ts +33 -0
  552. package/src/renderer/shared/utils/workspacePane.ts +20 -0
  553. package/src/renderer/shared/utils/workspacePreview.test.ts +24 -0
  554. package/src/renderer/shared/utils/workspacePreview.ts +16 -0
  555. package/src/renderer/shared/utils/workspaceSnapshot.test.ts +49 -0
  556. package/src/renderer/shared/utils/workspaceSnapshot.ts +26 -0
  557. package/src/renderer/shared/utils/workspaces.ts +10 -0
  558. package/src/renderer/shared/workspaceUndo.ts +88 -0
  559. package/src/renderer/src/App.tsx +16 -1
  560. package/src/renderer/src/components/BrowserShell.tsx +108 -0
  561. package/src/renderer/src/components/BrowserSuggestionsPopup.tsx +91 -0
  562. package/src/renderer/src/components/LiveTranslateControls.tsx +65 -0
  563. package/src/renderer/src/components/MintDashboard.tsx +4 -2
  564. package/src/renderer/src/components/PicturesLibrary.tsx +2 -287
  565. package/src/renderer/src/components/ScreenPicker.css +227 -0
  566. package/src/renderer/src/components/ScreenPicker.tsx +312 -526
  567. package/src/renderer/src/components/SettingsWindow.tsx +48 -5
  568. package/src/renderer/src/components/SpotlightWindow.tsx +1 -0
  569. package/src/renderer/src/components/WidgetWindow.tsx +27 -3
  570. package/src/renderer/src/components/WorkspacePanel.tsx +269 -61
  571. package/src/renderer/src/components/browser-shell.css +185 -0
  572. package/src/renderer/src/components/browser-suggestions-popup.css +55 -0
  573. package/src/renderer/src/components/liveTranslateFrames.test.ts +44 -0
  574. package/src/renderer/src/components/liveTranslateFrames.ts +45 -0
  575. package/src/renderer/src/components/liveTranslateLanguage.ts +6 -0
  576. package/src/renderer/src/css/app-shell.css +400 -204
  577. package/src/renderer/src/css/chat.css +1666 -594
  578. package/src/renderer/src/css/dashboard.css +11 -0
  579. package/src/renderer/src/css/desktop-tools.css +928 -0
  580. package/src/renderer/src/css/misc.css +5 -60
  581. package/src/renderer/src/css/pictures.css +2 -407
  582. package/src/renderer/src/css/settings/base.css +394 -157
  583. package/src/renderer/src/css/sidebar-workspace.css +1072 -376
  584. package/src/renderer/src/css/spotlight.css +15 -26
  585. package/src/renderer/src/css/tool-surfaces.css +784 -0
  586. package/src/renderer/src/css/widget.css +36 -8
  587. package/src/renderer/src/env.d.ts +4 -9
  588. package/src/renderer/src/hooks/useProviderModels.ts +2 -9
  589. package/src/renderer/src/index.css +53 -46
  590. package/src/renderer/src/main.tsx +12 -0
  591. package/src/renderer/src/proactiveSuggestions.ts +29 -0
  592. package/src/renderer/src/tauri.ts +302 -339
  593. package/src/renderer/src/voiceInput.ts +2 -1
  594. package/src/renderer/src-web/App.tsx +40 -0
  595. package/src/renderer/src-web/components/MintDashboard.tsx +4 -2
  596. package/src/renderer/src-web/components/PicturesLibrary.tsx +2 -284
  597. package/src/renderer/src-web/components/PullToRefresh.tsx +107 -0
  598. package/src/renderer/src-web/components/SettingsWindow.tsx +36 -5
  599. package/src/renderer/src-web/css/app-shell.css +188 -207
  600. package/src/renderer/src-web/css/chat.css +1236 -507
  601. package/src/renderer/src-web/css/dashboard.css +11 -0
  602. package/src/renderer/src-web/css/misc.css +3 -55
  603. package/src/renderer/src-web/css/mobile.css +679 -0
  604. package/src/renderer/src-web/css/pictures.css +2 -415
  605. package/src/renderer/src-web/css/pull-to-refresh.css +54 -0
  606. package/src/renderer/src-web/css/settings/base.css +353 -134
  607. package/src/renderer/src-web/css/settings/mobile.css +320 -0
  608. package/src/renderer/src-web/css/sidebar-workspace.css +546 -187
  609. package/src/renderer/src-web/css/spotlight.css +9 -26
  610. package/src/renderer/src-web/css/widget.css +1 -6
  611. package/src/renderer/src-web/env.d.ts +4 -12
  612. package/src/renderer/src-web/hooks/useProviderModels.ts +2 -9
  613. package/src/renderer/src-web/index.css +53 -96
  614. package/src/renderer/src-web/main.tsx +12 -0
  615. package/src/renderer/src-web/proactiveSuggestions.ts +3 -0
  616. package/src/renderer/src-web/tauri.ts +309 -364
  617. package/src/renderer/tests/backgroundTerminals.browser.html +81 -0
  618. package/src/renderer/tests/chatPanelFixture.ts +23 -0
  619. package/src/renderer/tests/chatPerformance.browser.html +71 -0
  620. package/src/renderer/tests/cliSessions.browser.html +82 -0
  621. package/src/renderer/tests/collapsedPaste.browser.html +70 -0
  622. package/src/renderer/tests/composerMenus.browser.html +116 -0
  623. package/src/renderer/tests/contextCompaction.browser.html +17 -0
  624. package/src/renderer/tests/conversationLifecycle.browser.html +70 -0
  625. package/src/renderer/tests/effectsPerformance.browser.html +13 -0
  626. package/src/renderer/tests/errorRecovery.browser.html +21 -0
  627. package/src/renderer/tests/glideSelect.browser.html +71 -0
  628. package/src/renderer/tests/glideSelect.preview.html +27 -0
  629. package/src/renderer/tests/library.browser.html +1 -0
  630. package/src/renderer/tests/library.browser.tsx +78 -0
  631. package/src/renderer/tests/liveOrb.browser.html +49 -0
  632. package/src/renderer/tests/liveVoice.browser.html +29 -0
  633. package/src/renderer/tests/modInput.browser.html +22 -0
  634. package/src/renderer/tests/sessionSources.browser.html +1 -0
  635. package/src/renderer/tests/sessionSources.browser.tsx +107 -0
  636. package/src/renderer/tests/skills.browser.html +24 -0
  637. package/src/renderer/tests/toolsPanel.browser.html +1 -0
  638. package/src/renderer/tests/toolsPanel.browser.tsx +113 -0
  639. package/src/renderer/tests/viewedImages.browser.html +1 -0
  640. package/src/renderer/tests/viewedImages.browser.tsx +93 -0
  641. package/src/renderer/tests/voicePill.browser.html +80 -0
  642. package/src/renderer/tests/voicePill.preview.html +34 -0
  643. package/src/renderer/tests/webSources.browser.html +1 -0
  644. package/src/renderer/tests/webSources.browser.tsx +98 -0
  645. package/src/renderer/tests/workspaceUndo.browser.html +92 -0
  646. package/src-tauri/Cargo.toml +40 -0
  647. package/src-tauri/build.rs +3 -0
  648. package/src-tauri/src/app/lifecycle.rs +277 -0
  649. package/src-tauri/src/app/mod.rs +4 -0
  650. package/src-tauri/src/app/shortcuts.rs +40 -0
  651. package/src-tauri/src/app/tray.rs +52 -0
  652. package/src-tauri/src/background/events.rs +70 -0
  653. package/src-tauri/src/background/headless.rs +230 -0
  654. package/src-tauri/src/background/mod.rs +4 -0
  655. package/src-tauri/src/background/proactive.rs +262 -0
  656. package/src-tauri/src/commands/approvals.rs +20 -0
  657. package/src-tauri/src/commands/auth.rs +127 -0
  658. package/src-tauri/src/commands/conversation.rs +642 -0
  659. package/src-tauri/src/commands/integrations.rs +157 -0
  660. package/src-tauri/src/commands/media.rs +179 -0
  661. package/src-tauri/src/commands/mod.rs +11 -0
  662. package/src-tauri/src/commands/mods.rs +6 -0
  663. package/src-tauri/src/commands/settings.rs +141 -0
  664. package/src-tauri/src/commands/voice.rs +153 -0
  665. package/src-tauri/src/commands/workspace.rs +501 -0
  666. package/src-tauri/src/lib.rs +10 -0
  667. package/src-tauri/src/main.rs +3 -0
  668. package/src-tauri/src/native/actions.rs +206 -0
  669. package/src-tauri/src/native/browser.rs +252 -0
  670. package/src-tauri/src/native/capture.rs +695 -0
  671. package/src-tauri/src/native/discord_rpc.rs +99 -0
  672. package/src-tauri/src/native/integrations.rs +126 -0
  673. package/src-tauri/src/native/mod.rs +12 -0
  674. package/src-tauri/src/native/notifications.rs +51 -0
  675. package/src-tauri/src/native/plugins.rs +14 -0
  676. package/src-tauri/src/native/system.rs +250 -0
  677. package/src-tauri/src/native/terminal.rs +201 -0
  678. package/src-tauri/src/native/updater.rs +148 -0
  679. package/src-tauri/src/native/windows.rs +143 -0
  680. package/tsconfig.json +2 -0
  681. package/vite.config.ts +4 -1
  682. package/vite.config.web.ts +5 -0
  683. package/.cargo/config.toml +0 -13
  684. package/.claude/settings.local.json +0 -182
  685. package/.codex +0 -0
  686. package/CLAUDE.md +0 -102
  687. package/out/web/Live2DCubismCore.js +0 -9
  688. package/out/web/assets/MintDashboard-DWSqucgb.js +0 -57
  689. package/out/web/assets/SettingsWindow-DFM2aj5B.js +0 -2
  690. package/out/web/assets/chunk-CKBBP62Z-nr1uKPj9.js +0 -2
  691. package/out/web/assets/chunk-DSNCTWBM-Dtj8Rqsd.js +0 -2
  692. package/out/web/assets/chunk-DU6HZSFF-2tv5K1wT.js +0 -128
  693. package/out/web/assets/classDiagram-DTDB5LWJ-BdSFArgw.js +0 -1
  694. package/out/web/assets/classDiagram-v2-JRS7N3AN-BdSFArgw.js +0 -1
  695. package/out/web/assets/core-DImejIUG.js +0 -1
  696. package/out/web/assets/dist-js-BxuKEVWM.js +0 -1
  697. package/out/web/assets/event-BNl8Zahw.js +0 -1
  698. package/out/web/assets/fira-code-cyrillic-400-normal-UC0NFL4U.woff2 +0 -0
  699. package/out/web/assets/fira-code-cyrillic-400-normal-dc1q3VD7.woff +0 -0
  700. package/out/web/assets/fira-code-cyrillic-500-normal-Bu7VCL72.woff +0 -0
  701. package/out/web/assets/fira-code-cyrillic-500-normal-CX35h3Mg.woff2 +0 -0
  702. package/out/web/assets/fira-code-cyrillic-ext-400-normal-Buh61xzB.woff +0 -0
  703. package/out/web/assets/fira-code-cyrillic-ext-400-normal-txZ9Fk_1.woff2 +0 -0
  704. package/out/web/assets/fira-code-cyrillic-ext-500-normal-CYRspHgm.woff2 +0 -0
  705. package/out/web/assets/fira-code-cyrillic-ext-500-normal-CwtLmSFD.woff +0 -0
  706. package/out/web/assets/fira-code-greek-400-normal-B2Gh_Y8s.woff2 +0 -0
  707. package/out/web/assets/fira-code-greek-400-normal-DobhaxvF.woff +0 -0
  708. package/out/web/assets/fira-code-greek-500-normal-CVO0IRNt.woff2 +0 -0
  709. package/out/web/assets/fira-code-greek-500-normal-DEXIWiey.woff +0 -0
  710. package/out/web/assets/fira-code-greek-ext-400-normal-DR7mBgIM.woff2 +0 -0
  711. package/out/web/assets/fira-code-greek-ext-400-normal-DSPUheWg.woff +0 -0
  712. package/out/web/assets/fira-code-greek-ext-500-normal-BO3iq16n.woff2 +0 -0
  713. package/out/web/assets/fira-code-greek-ext-500-normal-CMiNLXER.woff +0 -0
  714. package/out/web/assets/fira-code-latin-ext-400-normal-DG73JjOf.woff +0 -0
  715. package/out/web/assets/fira-code-latin-ext-400-normal-KSMg0QLl.woff2 +0 -0
  716. package/out/web/assets/fira-code-latin-ext-500-normal-CaANqXjI.woff +0 -0
  717. package/out/web/assets/fira-code-latin-ext-500-normal-Crd9e_oI.woff2 +0 -0
  718. package/out/web/assets/flowDiagram-A5DVABFB-BpnHUSU7.js +0 -1
  719. package/out/web/assets/index-CVRg270z.css +0 -1
  720. package/out/web/assets/index-DxZQr9yD.js +0 -10
  721. package/out/web/assets/inter-cyrillic-400-normal-HOLc17fK.woff +0 -0
  722. package/out/web/assets/inter-cyrillic-400-normal-obahsSVq.woff2 +0 -0
  723. package/out/web/assets/inter-cyrillic-500-normal-BasfLYem.woff2 +0 -0
  724. package/out/web/assets/inter-cyrillic-500-normal-CxZf_p3X.woff +0 -0
  725. package/out/web/assets/inter-cyrillic-600-normal-4D_pXhcN.woff +0 -0
  726. package/out/web/assets/inter-cyrillic-600-normal-CWCymEST.woff2 +0 -0
  727. package/out/web/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2 +0 -0
  728. package/out/web/assets/inter-cyrillic-ext-400-normal-DQukG94-.woff +0 -0
  729. package/out/web/assets/inter-cyrillic-ext-500-normal-B0yAr1jD.woff2 +0 -0
  730. package/out/web/assets/inter-cyrillic-ext-500-normal-BmqWE9Dz.woff +0 -0
  731. package/out/web/assets/inter-cyrillic-ext-600-normal-Bcila6Z-.woff +0 -0
  732. package/out/web/assets/inter-cyrillic-ext-600-normal-Dfes3d0z.woff2 +0 -0
  733. package/out/web/assets/inter-greek-400-normal-B4URO6DV.woff2 +0 -0
  734. package/out/web/assets/inter-greek-400-normal-q2sYcFCs.woff +0 -0
  735. package/out/web/assets/inter-greek-500-normal-BIZE56-Y.woff2 +0 -0
  736. package/out/web/assets/inter-greek-500-normal-Xzm54t5V.woff +0 -0
  737. package/out/web/assets/inter-greek-600-normal-BZpKdvQh.woff +0 -0
  738. package/out/web/assets/inter-greek-600-normal-plRanbMR.woff2 +0 -0
  739. package/out/web/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2 +0 -0
  740. package/out/web/assets/inter-greek-ext-400-normal-KugGGMne.woff +0 -0
  741. package/out/web/assets/inter-greek-ext-500-normal-2j5mBUwD.woff +0 -0
  742. package/out/web/assets/inter-greek-ext-500-normal-C4iEst2y.woff2 +0 -0
  743. package/out/web/assets/inter-greek-ext-600-normal-B8X0CLgF.woff +0 -0
  744. package/out/web/assets/inter-greek-ext-600-normal-DRtmH8MT.woff2 +0 -0
  745. package/out/web/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
  746. package/out/web/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
  747. package/out/web/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
  748. package/out/web/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
  749. package/out/web/assets/inter-latin-600-normal-CiBQ2DWP.woff +0 -0
  750. package/out/web/assets/inter-latin-600-normal-LgqL8muc.woff2 +0 -0
  751. package/out/web/assets/inter-latin-ext-400-normal-77YHD8bZ.woff +0 -0
  752. package/out/web/assets/inter-latin-ext-400-normal-C1nco2VV.woff2 +0 -0
  753. package/out/web/assets/inter-latin-ext-500-normal-BxGbmqWO.woff +0 -0
  754. package/out/web/assets/inter-latin-ext-500-normal-CV4jyFjo.woff2 +0 -0
  755. package/out/web/assets/inter-latin-ext-600-normal-CIVaiw4L.woff +0 -0
  756. package/out/web/assets/inter-latin-ext-600-normal-D2bJ5OIk.woff2 +0 -0
  757. package/out/web/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff +0 -0
  758. package/out/web/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
  759. package/out/web/assets/inter-vietnamese-500-normal-DOriooB6.woff2 +0 -0
  760. package/out/web/assets/inter-vietnamese-500-normal-mJboJaSs.woff +0 -0
  761. package/out/web/assets/inter-vietnamese-600-normal-BuLX-rYi.woff +0 -0
  762. package/out/web/assets/inter-vietnamese-600-normal-Cc8MFFhd.woff2 +0 -0
  763. package/out/web/assets/kanit-latin-400-normal-BUlsQXH3.woff2 +0 -0
  764. package/out/web/assets/kanit-latin-400-normal-HVZWrfev.woff +0 -0
  765. package/out/web/assets/kanit-latin-500-normal-CX_4XcKi.woff2 +0 -0
  766. package/out/web/assets/kanit-latin-500-normal-qBha86O4.woff +0 -0
  767. package/out/web/assets/kanit-latin-600-normal-0lS78yAd.woff2 +0 -0
  768. package/out/web/assets/kanit-latin-600-normal-DlacpeTg.woff +0 -0
  769. package/out/web/assets/kanit-latin-ext-400-normal-B2xPf58u.woff2 +0 -0
  770. package/out/web/assets/kanit-latin-ext-400-normal-CHvNKHHD.woff +0 -0
  771. package/out/web/assets/kanit-latin-ext-500-normal-BFdWrG22.woff +0 -0
  772. package/out/web/assets/kanit-latin-ext-500-normal-EHs3suD6.woff2 +0 -0
  773. package/out/web/assets/kanit-latin-ext-600-normal-BBDzoLaj.woff +0 -0
  774. package/out/web/assets/kanit-latin-ext-600-normal-DAX3wtuq.woff2 +0 -0
  775. package/out/web/assets/kanit-thai-400-normal-D2nliXKa.woff +0 -0
  776. package/out/web/assets/kanit-thai-400-normal-D80Pglro.woff2 +0 -0
  777. package/out/web/assets/kanit-thai-500-normal-BB8gri04.woff2 +0 -0
  778. package/out/web/assets/kanit-thai-500-normal-Iy_w0a80.woff +0 -0
  779. package/out/web/assets/kanit-thai-600-normal-Bj6oiaDc.woff2 +0 -0
  780. package/out/web/assets/kanit-thai-600-normal-wbTlPO7I.woff +0 -0
  781. package/out/web/assets/kanit-vietnamese-400-normal-DRI8YWyb.woff2 +0 -0
  782. package/out/web/assets/kanit-vietnamese-400-normal-dow6Bnto.woff +0 -0
  783. package/out/web/assets/kanit-vietnamese-500-normal-BzTrpCM3.woff2 +0 -0
  784. package/out/web/assets/kanit-vietnamese-500-normal-T1ndT7MF.woff +0 -0
  785. package/out/web/assets/kanit-vietnamese-600-normal-Bi7fw3I4.woff2 +0 -0
  786. package/out/web/assets/kanit-vietnamese-600-normal-DXCRAa_8.woff +0 -0
  787. package/out/web/assets/mali-latin-400-normal-ByPcZ8Gx.woff +0 -0
  788. package/out/web/assets/mali-latin-400-normal-Cuc6Ykl8.woff2 +0 -0
  789. package/out/web/assets/mali-latin-500-normal-B01M-LP6.woff2 +0 -0
  790. package/out/web/assets/mali-latin-500-normal-Thgqw_9f.woff +0 -0
  791. package/out/web/assets/mali-latin-600-normal-B9TiUNpT.woff2 +0 -0
  792. package/out/web/assets/mali-latin-600-normal-CycpQCwU.woff +0 -0
  793. package/out/web/assets/mali-latin-ext-400-normal-DUVdJQO4.woff +0 -0
  794. package/out/web/assets/mali-latin-ext-400-normal-iCG1ALuJ.woff2 +0 -0
  795. package/out/web/assets/mali-latin-ext-500-normal-BfJE4UMZ.woff2 +0 -0
  796. package/out/web/assets/mali-latin-ext-500-normal-FoLEyOKS.woff +0 -0
  797. package/out/web/assets/mali-latin-ext-600-normal-BTvIfiCp.woff2 +0 -0
  798. package/out/web/assets/mali-latin-ext-600-normal-DAQcLVmD.woff +0 -0
  799. package/out/web/assets/mali-thai-400-normal-BO7A3bLZ.woff2 +0 -0
  800. package/out/web/assets/mali-thai-400-normal-CX9VrjTn.woff +0 -0
  801. package/out/web/assets/mali-thai-500-normal-Cph2qha9.woff +0 -0
  802. package/out/web/assets/mali-thai-500-normal-D89rMT77.woff2 +0 -0
  803. package/out/web/assets/mali-thai-600-normal-DPgXT6rZ.woff +0 -0
  804. package/out/web/assets/mali-thai-600-normal-DlTx3OsB.woff2 +0 -0
  805. package/out/web/assets/mali-vietnamese-400-normal-DUKxzXaz.woff2 +0 -0
  806. package/out/web/assets/mali-vietnamese-400-normal-gFDLvsOK.woff +0 -0
  807. package/out/web/assets/mali-vietnamese-500-normal--OY07q2c.woff +0 -0
  808. package/out/web/assets/mali-vietnamese-500-normal-KDrNRwfW.woff2 +0 -0
  809. package/out/web/assets/mali-vietnamese-600-normal-CtTMUU7T.woff +0 -0
  810. package/out/web/assets/mali-vietnamese-600-normal-DFlJr66u.woff2 +0 -0
  811. package/out/web/assets/mermaid.core-DYGGlqOf.js +0 -11
  812. package/out/web/assets/mitr-latin-400-normal-Cb18vPmZ.woff +0 -0
  813. package/out/web/assets/mitr-latin-400-normal-CwbkLQ4a.woff2 +0 -0
  814. package/out/web/assets/mitr-latin-500-normal-B4JOhzAi.woff +0 -0
  815. package/out/web/assets/mitr-latin-500-normal-BmClOow2.woff2 +0 -0
  816. package/out/web/assets/mitr-latin-ext-400-normal-B3CPG7Yo.woff2 +0 -0
  817. package/out/web/assets/mitr-latin-ext-400-normal-DTx65hiC.woff +0 -0
  818. package/out/web/assets/mitr-latin-ext-500-normal-B_Diajz1.woff2 +0 -0
  819. package/out/web/assets/mitr-latin-ext-500-normal-DYOsVaVT.woff +0 -0
  820. package/out/web/assets/mitr-thai-400-normal-CS4Do6aM.woff +0 -0
  821. package/out/web/assets/mitr-thai-400-normal-CXWaAdVj.woff2 +0 -0
  822. package/out/web/assets/mitr-thai-500-normal-CVdBrEVH.woff2 +0 -0
  823. package/out/web/assets/mitr-thai-500-normal-CW_B5D-i.woff +0 -0
  824. package/out/web/assets/mitr-vietnamese-400-normal-CPMGWyoC.woff2 +0 -0
  825. package/out/web/assets/mitr-vietnamese-400-normal-Z6XhIpdY.woff +0 -0
  826. package/out/web/assets/mitr-vietnamese-500-normal-CDrv0585.woff2 +0 -0
  827. package/out/web/assets/mitr-vietnamese-500-normal-CMQWyq-Z.woff +0 -0
  828. package/out/web/assets/noto-sans-thai-latin-400-normal-BaWBrqFP.woff2 +0 -0
  829. package/out/web/assets/noto-sans-thai-latin-400-normal-Dh_FJjOB.woff +0 -0
  830. package/out/web/assets/noto-sans-thai-latin-500-normal-BC04jsmm.woff +0 -0
  831. package/out/web/assets/noto-sans-thai-latin-500-normal-fyBKClF1.woff2 +0 -0
  832. package/out/web/assets/noto-sans-thai-latin-600-normal-CemcjnVR.woff2 +0 -0
  833. package/out/web/assets/noto-sans-thai-latin-600-normal-Dbc-dNO6.woff +0 -0
  834. package/out/web/assets/noto-sans-thai-latin-ext-400-normal-B-1H0YkH.woff +0 -0
  835. package/out/web/assets/noto-sans-thai-latin-ext-400-normal-nBP59pVw.woff2 +0 -0
  836. package/out/web/assets/noto-sans-thai-latin-ext-500-normal-B-ZWb8SZ.woff2 +0 -0
  837. package/out/web/assets/noto-sans-thai-latin-ext-500-normal-CrEHO7C8.woff +0 -0
  838. package/out/web/assets/noto-sans-thai-latin-ext-600-normal-PkMZo0xa.woff +0 -0
  839. package/out/web/assets/noto-sans-thai-latin-ext-600-normal-maHHBsez.woff2 +0 -0
  840. package/out/web/assets/noto-sans-thai-thai-400-normal-BEOmKAI1.woff2 +0 -0
  841. package/out/web/assets/noto-sans-thai-thai-400-normal-Dxb_unuU.woff +0 -0
  842. package/out/web/assets/noto-sans-thai-thai-500-normal-BOGXO2tw.woff +0 -0
  843. package/out/web/assets/noto-sans-thai-thai-500-normal-CU_X86GQ.woff2 +0 -0
  844. package/out/web/assets/noto-sans-thai-thai-600-normal-CmgB8_JK.woff +0 -0
  845. package/out/web/assets/noto-sans-thai-thai-600-normal-Cs73sVjl.woff2 +0 -0
  846. package/out/web/assets/oauthManager-DNiwM8Rn.js +0 -2
  847. package/out/web/assets/oauthManager-DuamS1Av.css +0 -1
  848. package/out/web/assets/outfit-latin-300-normal-AWLfuCom.woff +0 -0
  849. package/out/web/assets/outfit-latin-300-normal-CRYTwY6m.woff2 +0 -0
  850. package/out/web/assets/outfit-latin-400-normal-BGsTXAXT.woff2 +0 -0
  851. package/out/web/assets/outfit-latin-400-normal-DMwTpYkH.woff +0 -0
  852. package/out/web/assets/outfit-latin-500-normal-ClnHRwRh.woff +0 -0
  853. package/out/web/assets/outfit-latin-500-normal-DKnIMDSk.woff2 +0 -0
  854. package/out/web/assets/outfit-latin-600-normal-B7SfZ07L.woff2 +0 -0
  855. package/out/web/assets/outfit-latin-600-normal-BEfTtDA7.woff +0 -0
  856. package/out/web/assets/outfit-latin-ext-300-normal-BYS6Dpvq.woff2 +0 -0
  857. package/out/web/assets/outfit-latin-ext-300-normal-CMIMshEd.woff +0 -0
  858. package/out/web/assets/outfit-latin-ext-400-normal-5tcqmc2S.woff2 +0 -0
  859. package/out/web/assets/outfit-latin-ext-400-normal-DHm7mdGe.woff +0 -0
  860. package/out/web/assets/outfit-latin-ext-500-normal-DrCvqoFD.woff +0 -0
  861. package/out/web/assets/outfit-latin-ext-500-normal-zeox_O30.woff2 +0 -0
  862. package/out/web/assets/outfit-latin-ext-600-normal-B85nYjL1.woff2 +0 -0
  863. package/out/web/assets/outfit-latin-ext-600-normal-CWJcPgd7.woff +0 -0
  864. package/out/web/assets/preload-helper-D0uHx7FM.js +0 -1
  865. package/out/web/assets/prompt-latin-400-normal-BQ9zjSN8.woff2 +0 -0
  866. package/out/web/assets/prompt-latin-400-normal-CxU4ec_r.woff +0 -0
  867. package/out/web/assets/prompt-latin-500-normal-B1edBDQ9.woff +0 -0
  868. package/out/web/assets/prompt-latin-500-normal-CxzxEHZc.woff2 +0 -0
  869. package/out/web/assets/prompt-latin-600-normal-CSDDLorv.woff +0 -0
  870. package/out/web/assets/prompt-latin-600-normal-hKZWXsc1.woff2 +0 -0
  871. package/out/web/assets/prompt-latin-ext-400-normal-1pHbN9uy.woff +0 -0
  872. package/out/web/assets/prompt-latin-ext-400-normal-DdSafGZ9.woff2 +0 -0
  873. package/out/web/assets/prompt-latin-ext-500-normal--EZ1um7s.woff2 +0 -0
  874. package/out/web/assets/prompt-latin-ext-500-normal-D-lI1EVT.woff +0 -0
  875. package/out/web/assets/prompt-latin-ext-600-normal-C8b50x67.woff +0 -0
  876. package/out/web/assets/prompt-latin-ext-600-normal-Cg9L7iJU.woff2 +0 -0
  877. package/out/web/assets/prompt-thai-400-normal-BrkKv8cO.woff2 +0 -0
  878. package/out/web/assets/prompt-thai-400-normal-DJypnfr3.woff +0 -0
  879. package/out/web/assets/prompt-thai-500-normal-C18pDUoL.woff2 +0 -0
  880. package/out/web/assets/prompt-thai-500-normal-D7YNqUJD.woff +0 -0
  881. package/out/web/assets/prompt-thai-600-normal-CYPViXds.woff +0 -0
  882. package/out/web/assets/prompt-thai-600-normal-MrdfU7zR.woff2 +0 -0
  883. package/out/web/assets/prompt-vietnamese-400-normal-BCPzsgPT.woff2 +0 -0
  884. package/out/web/assets/prompt-vietnamese-400-normal-D4pLyeNK.woff +0 -0
  885. package/out/web/assets/prompt-vietnamese-500-normal-DmzxmPwa.woff2 +0 -0
  886. package/out/web/assets/prompt-vietnamese-500-normal-w_sS_j2F.woff +0 -0
  887. package/out/web/assets/prompt-vietnamese-600-normal-1dyohtNh.woff +0 -0
  888. package/out/web/assets/prompt-vietnamese-600-normal-7QWjJBsF.woff2 +0 -0
  889. package/out/web/assets/sarabun-latin-400-normal-DmguIS-7.woff +0 -0
  890. package/out/web/assets/sarabun-latin-400-normal-URPBxl-K.woff2 +0 -0
  891. package/out/web/assets/sarabun-latin-500-normal-BjUTcdxu.woff2 +0 -0
  892. package/out/web/assets/sarabun-latin-500-normal-CJexTAnl.woff +0 -0
  893. package/out/web/assets/sarabun-latin-600-normal-9FonlkKx.woff +0 -0
  894. package/out/web/assets/sarabun-latin-600-normal-DMD3TROr.woff2 +0 -0
  895. package/out/web/assets/sarabun-latin-ext-400-normal-BbP7GpLL.woff2 +0 -0
  896. package/out/web/assets/sarabun-latin-ext-400-normal-BsmTn0SS.woff +0 -0
  897. package/out/web/assets/sarabun-latin-ext-500-normal-Cot16Bd2.woff +0 -0
  898. package/out/web/assets/sarabun-latin-ext-500-normal-DE1LysqI.woff2 +0 -0
  899. package/out/web/assets/sarabun-latin-ext-600-normal-0tXu9x_i.woff +0 -0
  900. package/out/web/assets/sarabun-latin-ext-600-normal-BRxjKUQ6.woff2 +0 -0
  901. package/out/web/assets/sarabun-thai-400-normal-C2DaJlKK.woff2 +0 -0
  902. package/out/web/assets/sarabun-thai-400-normal-CH-UbWgg.woff +0 -0
  903. package/out/web/assets/sarabun-thai-500-normal-BVssjame.woff2 +0 -0
  904. package/out/web/assets/sarabun-thai-500-normal-C3iDLEzi.woff +0 -0
  905. package/out/web/assets/sarabun-thai-600-normal-3dIAQ-_s.woff2 +0 -0
  906. package/out/web/assets/sarabun-thai-600-normal-DWKeTe6a.woff +0 -0
  907. package/out/web/assets/sarabun-vietnamese-400-normal-DPfkSCMy.woff +0 -0
  908. package/out/web/assets/sarabun-vietnamese-400-normal-igdrzAGY.woff2 +0 -0
  909. package/out/web/assets/sarabun-vietnamese-500-normal-CpRVvGRU.woff +0 -0
  910. package/out/web/assets/sarabun-vietnamese-500-normal-Dpe7Br9m.woff2 +0 -0
  911. package/out/web/assets/sarabun-vietnamese-600-normal-BMbOgAW-.woff +0 -0
  912. package/out/web/assets/sarabun-vietnamese-600-normal-DkxrOlLB.woff2 +0 -0
  913. package/out/web/assets/stateDiagram-v2-4QOOHH4V-s6P9g2_b.js +0 -1
  914. package/out/web/assets/swimlanesDiagram-VK2B7HYN-CV9fOLrV.js +0 -8
  915. package/out/web/assets/tauri-CNrHQ2Gb.js +0 -3
  916. package/out/web/assets/window-DkIhgI7B.js +0 -1
  917. package/skills-lock.json +0 -41
  918. package/src/renderer/public/Live2DCubismCore.js +0 -9
  919. package/src/renderer/src/companionWidget.ts +0 -95
  920. package/src/renderer/src/components/Live2DStage.tsx +0 -389
  921. package/src/renderer/src/components/ModelPanel.tsx +0 -154
  922. package/src/renderer/src/css/model.css +0 -627
  923. package/src/renderer/src-web/companionWidget.ts +0 -37
  924. package/src/renderer/src-web/components/ModelPanel.tsx +0 -12
  925. package/src/renderer/src-web/css/model.css +0 -628
@@ -1,5 +1,11 @@
1
+ import McpToolResults from './McpToolResults'
2
+ import ViewedImages from './ViewedImages'
3
+ import { CollapsiblePasteInput } from './CollapsiblePasteInput'
4
+ import { ContextCompactionStatus } from './ContextCompactionStatus'
5
+ import { activeCompactionFrom } from '../utils/contextCompaction'
1
6
  import { useEffect, useMemo, useRef, useState, useCallback, Fragment, type ChangeEvent, type ClipboardEvent, type DragEvent, type FormEvent, type KeyboardEvent, type RefObject } from 'react'
2
- import { hasAgentToolActivity, thoughtsFrom, parseFileChangesFromProgress } from '../agentProgress'
7
+ import { EMPTY_AGENT_PROGRESS, hasAgentToolActivity, thoughtsFrom, extendedThoughtsFrom, mergeFileChanges, parseFileChangesFromProgress } from '../agentProgress'
8
+ import { visibleInteractionsDuringRun } from '../conversation/syncView'
3
9
  import {
4
10
  GEMINI_MODELS,
5
11
  OPENAI_MODELS,
@@ -12,45 +18,82 @@ import {
12
18
  GEMINI_LIVE_VOICES,
13
19
  } from '../constants/models'
14
20
  import { badge, providerLabel, fallbackNotice } from '../utils/providers'
15
- import { activitiesFrom, parseWebSearchSources, type AgentActivity, type AgentActivityView } from '../utils/agentActivity'
21
+ import { parseWebSearchSources } from '../utils/agentActivity'
22
+ import { useLatestCallback } from '../utils/useLatestCallback'
23
+ import SlashChoicePanel from './SlashChoicePanel'
16
24
  import SlashSuggestions, { type SlashSuggestionsHandle } from './SlashSuggestions'
17
- import { AgentActivityTable } from './AgentActivityTable'
18
25
  import { ChatCodeBlock } from './ChatCodeBlock'
19
26
  import { renderApprovalDetails, renderDiff, type ApprovalDetails } from '../utils/approval'
20
27
  import { ApprovalCard } from './ApprovalCard'
21
- import { renderFormattedMessage, readableAssistantText, cleanSpeechText, renderSpeakerIcon, renderCopyIcon } from '../utils/markdown'
28
+ import { readableAssistantText, cleanSpeechText, renderSpeakerIcon, renderCopyIcon } from '../utils/markdown'
22
29
  import { ThinkingBlock } from './ThinkingBlock'
23
- import SourcesBlock from './SourcesBlock'
24
30
  import ChatMessageItem from './ChatMessageItem'
25
- import { AgentActivityDrawer } from './AgentActivityDrawer'
31
+ import { FormattedMessage } from './FormattedMessage'
32
+ import { ProgressActivity } from './ProgressActivity'
33
+ import { VirtualChatHistory, type VirtualChatHistoryHandle } from './VirtualChatHistory'
26
34
  import { ArtifactPreviewPanel, type ArtifactFile } from './ArtifactPreviewPanel'
27
35
  import { RewindModal } from './RewindModal'
28
- import type { DiffHunk, FileChange, GitCheckpoint } from '../types'
36
+ import type { AgentProgress, ChatResponse, DiffHunk, FileChange, GitCheckpoint, RuntimeStatus } from '../types'
29
37
  import { numericSetting, shouldShowSessionDivider, formatSessionDividerLabel } from '../utils/ui'
30
38
  import { useVoiceInput } from '@/voiceInput'
39
+ import VoicePill from './VoicePill'
31
40
  import { useGeminiLiveVoice } from '../utils/useGeminiLiveVoice'
32
41
  import GeminiLiveOverlay from './GeminiLiveOverlay'
33
42
  import { isSupportedDocument, SUPPORTED_DOCUMENT_ACCEPT } from '../utils/documentTypes'
34
43
  import ModelSelectorPopover from './ModelSelectorPopover'
44
+ import GitBranchSelector from './GitBranchSelector'
45
+ import WorkspaceSelector from './WorkspaceSelector'
46
+ import ToolsPanelToggle from './ToolsPanelToggle'
47
+ import SessionSourcesPopover from './SessionSourcesPopover'
48
+ import { ModsPanel } from './ModsPanel'
49
+ import CodeReviewPage from './CodeReviewPage'
50
+ import type { ToolSurface } from './ToolSurfacePage'
51
+ import '../css/thinking-status.css'
52
+ import '../css/slash-choice.css'
53
+
54
+ import { catalogPlatform, conversationPlatform, runtimePlatform } from '../platform'
55
+
56
+ const STREAM_MARKDOWN_UPDATE_MS = 120
57
+
58
+ function useThrottledValue<T>(value: T, intervalMs: number): T {
59
+ const [throttledValue, setThrottledValue] = useState(value)
60
+ const latestValueRef = useRef(value)
61
+ const lastUpdateRef = useRef(0)
62
+ const timerRef = useRef<ReturnType<typeof window.setTimeout> | null>(null)
35
63
 
36
- import {
37
- APP_ICON_PATH,
38
- type AgentProgress,
39
- type ChatResponse,
40
- type RuntimeStatus,
41
- getTtsUrls,
42
- startGeminiLiveSession,
43
- sendGeminiLiveAudioChunk,
44
- stopGeminiLiveSession,
45
- listGitCheckpoints,
46
- rollbackGitCheckpoint,
47
- undoGitCheckpoint,
48
- fetchProviderModels,
49
- } from '@/tauri'
64
+ useEffect(() => {
65
+ latestValueRef.current = value
66
+ if (Object.is(value, throttledValue)) return
50
67
 
68
+ const flush = () => {
69
+ timerRef.current = null
70
+ lastUpdateRef.current = Date.now()
71
+ setThrottledValue(latestValueRef.current)
72
+ }
73
+ const remaining = intervalMs - (Date.now() - lastUpdateRef.current)
74
+ if (remaining <= 0) flush()
75
+ else if (timerRef.current === null) timerRef.current = window.setTimeout(flush, remaining)
76
+ }, [value, throttledValue, intervalMs])
51
77
 
52
- interface ChatPanelProps {
78
+ useEffect(() => () => {
79
+ if (timerRef.current !== null) window.clearTimeout(timerRef.current)
80
+ }, [])
81
+
82
+ return throttledValue
83
+ }
84
+
85
+ const {
86
+ getTtsUrls, startGeminiLiveSession, sendGeminiLiveAudioChunk, stopGeminiLiveSession,
87
+ listGitCheckpoints, rollbackGitCheckpoint, undoGitCheckpoint,
88
+ } = conversationPlatform
89
+ const { fetchProviderModels } = catalogPlatform
90
+
91
+
92
+ interface ChatPanelContract {
53
93
  interactions: any[]
94
+ sendingInteractionId?: number | null
95
+ hasOlder?: boolean
96
+ onLoadOlder?: () => Promise<void>
54
97
  sending: boolean
55
98
  sendingMessage: string
56
99
  sendingImageCount: number
@@ -66,13 +109,13 @@ interface ChatPanelProps {
66
109
  videoAttachments: Array<{ dataUri: string; name: string }>
67
110
  documentName: string
68
111
  pendingApproval: any | null
69
- smartContext: boolean
70
112
  agentMode: boolean
71
113
  /** Desktop only — plan-mode-approval UI isn't available on web. */
72
114
  planMode?: boolean
73
115
  status: RuntimeStatus | null
74
116
  /** Desktop only — web has no local workspace-folder concept to select from. */
75
117
  workspacePath?: string
118
+ chatId: string
76
119
  chatEnd: RefObject<HTMLDivElement | null>
77
120
  welcomeInteraction: any
78
121
  onSubmit: (event: FormEvent<HTMLFormElement>) => void
@@ -87,15 +130,17 @@ interface ChatPanelProps {
87
130
  onRemoveDocument: () => void
88
131
  onStartWebSearch: () => void
89
132
  onCaptureScreen: () => void
90
- onSetSmartContext: (enabled: boolean) => void
91
133
  onSetAgentMode: (enabled: boolean) => void
92
134
  /** Desktop only — see `planMode`. */
93
135
  onSetPlanMode?: (enabled: boolean) => void
94
136
  onSetProvider: (provider: string) => void
95
137
  /** Desktop only — see `workspacePath`. */
96
- onSelectWorkspace?: () => void
138
+ onSelectWorkspace?: (path?: string) => void
139
+ onWorkspaceChanged?: () => void
140
+ recentWorkspacePaths: string[]
97
141
  onApproval: (approved: boolean, autoApproveSession?: boolean, answer?: string) => void
98
142
  settingsConfig: any
143
+ onUpdateSettings?: (config: any) => void
99
144
  onSetModel: (model: string) => void
100
145
  onSelectModelAndProvider?: (provider: string, model: string) => void
101
146
  onCancelMessage: () => void
@@ -103,11 +148,47 @@ interface ChatPanelProps {
103
148
  onSetGeminiLiveVoice: (voice: string) => Promise<void>
104
149
  /** Web only — desktop's window has no mobile-width sidebar to toggle. */
105
150
  onToggleMobileSidebar?: () => void
151
+ isCliSession?: boolean
152
+ cliSessionId?: string
153
+ onBackToCode?: () => void
154
+ conversationTitle?: string
155
+ slashChoice?: { command: string; title: string; options: { label: string; value: string }[] } | null
156
+ onOpenArtifact?: (artifact: ArtifactFile) => void
157
+ onOpenReview?: (review: Extract<ToolSurface, { kind: 'review' }>) => void
158
+ onSelectSlashChoice?: (value: string) => void
159
+ onDismissSlashChoice?: () => void
106
160
  }
107
161
 
162
+ export type ConversationViewModel = Pick<ChatPanelContract,
163
+ | 'interactions' | 'sending' | 'sendingMessage' | 'sendingImageCount' | 'sendingVideoCount'
164
+ | 'streamedReply' | 'streamedResponse' | 'agentProgress' | 'agentActivitySnapshots'
165
+ | 'thinkingExpanded' | 'message' | 'imageAttachments' | 'videoAttachments' | 'documentName'
166
+ | 'pendingApproval' | 'agentMode' | 'planMode' | 'status' | 'workspacePath' | 'chatId' | 'recentWorkspacePaths'
167
+ | 'chatEnd' | 'welcomeInteraction' | 'settingsConfig' | 'isCliSession' | 'cliSessionId'
168
+ | 'conversationTitle' | 'slashChoice'
169
+ | 'hasOlder'
170
+ | 'sendingInteractionId'
171
+ >
172
+ export type ConversationActions = Omit<ChatPanelContract, keyof ConversationViewModel>
173
+
174
+ interface ChatPanelProps {
175
+ conversation: ConversationViewModel
176
+ actions: ConversationActions
177
+ showSessionSources?: boolean
178
+ tools?: { modsPanelTarget: HTMLElement | null; onOpenMods: () => void; onToggle?: () => void; open: boolean; backgroundTaskCount: number }
179
+ }
108
180
 
109
181
  export default function ChatPanel({
182
+ conversation,
183
+ actions,
184
+ tools,
185
+ showSessionSources = false,
186
+ }: ChatPanelProps) {
187
+ const {
110
188
  interactions,
189
+ sendingInteractionId,
190
+ hasOlder,
191
+ onLoadOlder,
111
192
  sending,
112
193
  sendingMessage,
113
194
  sendingImageCount,
@@ -117,17 +198,18 @@ export default function ChatPanel({
117
198
  agentProgress,
118
199
  agentActivitySnapshots,
119
200
  thinkingExpanded,
120
- onThinkingExpandedChange,
201
+ onThinkingExpandedChange: handleThinkingExpandedChange,
121
202
  message,
122
203
  imageAttachments,
123
204
  videoAttachments,
124
205
  documentName,
125
206
  pendingApproval,
126
- smartContext,
127
207
  agentMode,
128
208
  planMode,
129
209
  status,
130
210
  workspacePath,
211
+ chatId,
212
+ recentWorkspacePaths,
131
213
  chatEnd,
132
214
  welcomeInteraction,
133
215
  onSubmit,
@@ -142,23 +224,81 @@ export default function ChatPanel({
142
224
  onRemoveDocument,
143
225
  onStartWebSearch,
144
226
  onCaptureScreen,
145
- onSetSmartContext,
146
227
  onSetAgentMode,
147
228
  onSetPlanMode,
148
229
  onSetProvider,
149
230
  onSelectWorkspace,
231
+ onWorkspaceChanged,
150
232
  onApproval,
151
233
  settingsConfig,
234
+ onUpdateSettings,
152
235
  onSetModel,
153
236
  onSelectModelAndProvider,
154
237
  onCancelMessage,
155
238
  onClearMessages,
156
239
  onSetGeminiLiveVoice,
157
240
  onToggleMobileSidebar,
158
- }: ChatPanelProps) {
159
- const agentActivities = activitiesFrom(agentProgress)
241
+ isCliSession,
242
+ cliSessionId,
243
+ onBackToCode,
244
+ conversationTitle,
245
+ slashChoice,
246
+ onOpenArtifact,
247
+ onOpenReview,
248
+ onSelectSlashChoice,
249
+ onDismissSlashChoice,
250
+ } = { ...conversation, ...actions }
251
+ const onThinkingExpandedChange = useLatestCallback(handleThinkingExpandedChange)
252
+ // The initiating surface already renders a live prompt/reply pair below.
253
+ // Hide its matching persisted turn until the local stream settles, while
254
+ // still showing turns submitted from other surfaces during that time.
255
+ const visibleInteractions = useMemo(
256
+ () => visibleInteractionsDuringRun(interactions, sending, sendingInteractionId),
257
+ [interactions, sending, sendingInteractionId],
258
+ )
259
+ // Keep the composer summary tied to the active/latest agent run. This is cheap
260
+ // metadata, but memoizing it avoids parsing the activity stream while typing.
261
+ const composerChanges = useMemo(() => parseFileChangesFromProgress(agentProgress), [agentProgress])
262
+ const composerAdditions = useMemo(
263
+ () => composerChanges.reduce((sum, change) => sum + change.additions, 0),
264
+ [composerChanges],
265
+ )
266
+ const composerDeletions = useMemo(
267
+ () => composerChanges.reduce((sum, change) => sum + change.deletions, 0),
268
+ [composerChanges],
269
+ )
270
+ const composerChangeLabel = composerChanges.length === 1
271
+ ? '1 file changed'
272
+ : `${composerChanges.length} files changed`
273
+ const historicalChanges = useMemo(() => {
274
+ const historicalGroups = interactions.map((interaction) => {
275
+ const interactionId = String(interaction.id)
276
+ const progress = agentActivitySnapshots[interactionId] ?? interaction.agentActivity ?? EMPTY_AGENT_PROGRESS
277
+ return parseFileChangesFromProgress(progress)
278
+ })
279
+ return mergeFileChanges(historicalGroups)
280
+ }, [agentActivitySnapshots, interactions])
281
+ // Review uses current data even from a memoized historical message's button.
282
+ // Merge the conversation only when requested, not on each progress update.
283
+ const getConversationChanges = useLatestCallback(() => mergeFileChanges([historicalChanges, composerChanges]))
284
+
285
+ const projectName = useMemo(() => {
286
+ if (!workspacePath) return null
287
+ const clean = workspacePath.replace(/[\\/]+$/, '').trim()
288
+ if (!clean) return null
289
+ const parts = clean.split(/[\\/]/)
290
+ return parts[parts.length - 1] || clean
291
+ }, [workspacePath])
292
+
293
+ // Markdown parsing can be expensive for code, tables, and interactive cards.
294
+ // Limit it to a steady cadence instead of parsing on every stream chunk.
295
+ const throttledStreamedReply = useThrottledValue(streamedReply, STREAM_MARKDOWN_UPDATE_MS)
296
+ const liveWebSources = useMemo(() => parseWebSearchSources(agentProgress), [agentProgress])
160
297
  const activeFallbackNotice = fallbackNotice(streamedResponse)
161
- const lastThinkingProgress = [...agentProgress].reverse().find(p => p.type === 'Thinking')
298
+ const compaction = useMemo(() => activeCompactionFrom(agentProgress), [agentProgress])
299
+ const liveThoughts = useMemo(() => thoughtsFrom(agentProgress), [agentProgress])
300
+ const liveExtendedThoughts = useMemo(() => extendedThoughtsFrom(agentProgress), [agentProgress])
301
+ const lastThinkingProgress = useMemo(() => [...agentProgress].reverse().find(p => p.type === 'Thinking'), [agentProgress])
162
302
  let activeAgentName: string | null = null
163
303
  let activeModelName: string | null = null
164
304
  if (lastThinkingProgress && lastThinkingProgress.type === 'Thinking') {
@@ -168,10 +308,26 @@ export default function ChatPanel({
168
308
  const [openActivityIds, setOpenActivityIds] = useState<Record<string, boolean>>({})
169
309
  const [openReviewIds, setOpenReviewIds] = useState<Record<string, boolean>>({})
170
310
  const [openFileDiffs, setOpenFileDiffs] = useState<Record<string, boolean>>({})
311
+ const [showAllFileChanges, setShowAllFileChanges] = useState<Record<string, boolean>>({})
312
+ const [reviewPage, setReviewPage] = useState<{ title: string; changes: FileChange[] } | null>(null)
171
313
  const [activeArtifact, setActiveArtifact] = useState<ArtifactFile | null>(null)
172
314
  const [toolMenuOpen, setToolMenuOpen] = useState(false)
315
+ const [sessionSourcesOpen, setSessionSourcesOpen] = useState(false)
173
316
  const [elapsedSeconds, setElapsedSeconds] = useState(0)
174
317
  const [dynamicOllamaModels, setDynamicOllamaModels] = useState<string[]>(OLLAMA_MODELS)
318
+ const toggleActivity = useCallback((id: string) => {
319
+ setOpenActivityIds(current => ({ ...current, [id]: !(current[id] ?? (id === 'live')) }))
320
+ }, [])
321
+
322
+ const openArtifact = useLatestCallback((artifact: ArtifactFile) => {
323
+ if (onOpenArtifact) onOpenArtifact(artifact)
324
+ else setActiveArtifact({ ...artifact, workspacePath: artifact.workspacePath ?? workspacePath })
325
+ })
326
+
327
+ const openReview = useLatestCallback((title: string, changes: FileChange[]) => {
328
+ if (onOpenReview) onOpenReview({ id: `review:${Date.now()}`, kind: 'review', title: 'Review', reviewTitle: title, changes })
329
+ else setReviewPage({ title, changes })
330
+ })
175
331
 
176
332
  useEffect(() => {
177
333
  let cancelled = false
@@ -238,8 +394,11 @@ export default function ChatPanel({
238
394
  const [copiedId, setCopiedId] = useState<string | number | null>(null)
239
395
 
240
396
  const chatContainerRef = useRef<HTMLDivElement | null>(null)
397
+ const virtualHistoryRef = useRef<VirtualChatHistoryHandle | null>(null)
241
398
  const [showScrollToBottom, setShowScrollToBottom] = useState(false)
399
+ const [loadingOlder, setLoadingOlder] = useState(false)
242
400
  const isNearBottomRef = useRef(true)
401
+ const scrollFrameRef = useRef<number | null>(null)
243
402
 
244
403
  const handleChatScroll = useCallback(() => {
245
404
  const el = chatContainerRef.current
@@ -250,6 +409,32 @@ export default function ChatPanel({
250
409
  isNearBottomRef.current = nearBottom
251
410
  }, [])
252
411
 
412
+ const scheduleScrollToLatest = useCallback(() => {
413
+ if (!isNearBottomRef.current || scrollFrameRef.current !== null) return
414
+ scrollFrameRef.current = window.requestAnimationFrame(() => {
415
+ scrollFrameRef.current = null
416
+ const element = chatContainerRef.current
417
+ if (element && isNearBottomRef.current) {
418
+ // Smooth scrolling on every token restarts animations and causes jank.
419
+ virtualHistoryRef.current?.scrollToEnd()
420
+ }
421
+ })
422
+ }, [])
423
+
424
+ useEffect(() => {
425
+ scheduleScrollToLatest()
426
+ }, [interactions, sending, streamedReply, pendingApproval, agentProgress, scheduleScrollToLatest])
427
+
428
+ useEffect(() => {
429
+ isNearBottomRef.current = true
430
+ setShowScrollToBottom(false)
431
+ scheduleScrollToLatest()
432
+ }, [chatId, scheduleScrollToLatest])
433
+
434
+ useEffect(() => () => {
435
+ if (scrollFrameRef.current !== null) window.cancelAnimationFrame(scrollFrameRef.current)
436
+ }, [])
437
+
253
438
  useEffect(() => {
254
439
  const el = chatContainerRef.current
255
440
  if (!el) return
@@ -259,8 +444,9 @@ export default function ChatPanel({
259
444
  }, [activeArtifact])
260
445
 
261
446
  const scrollToBottom = useCallback(() => {
262
- chatEnd.current?.scrollIntoView({ behavior: 'smooth' })
263
- }, [chatEnd])
447
+ isNearBottomRef.current = true
448
+ virtualHistoryRef.current?.scrollToEnd()
449
+ }, [])
264
450
 
265
451
  const [splitRatio, setSplitRatio] = useState<number>(() => {
266
452
  try {
@@ -546,6 +732,7 @@ export default function ChatPanel({
546
732
  voiceModeRef,
547
733
  startRecognition,
548
734
  stopRecognition,
735
+ cancelRecognition,
549
736
  scheduleVoiceListen,
550
737
  clearRestartTimer
551
738
  } = useVoiceInput({
@@ -560,6 +747,7 @@ export default function ChatPanel({
560
747
  const geminiLiveEnabled = settingsConfig?.voiceMode === 'geminiLive'
561
748
  const geminiLive = useGeminiLiveVoice({
562
749
  workspacePath,
750
+ chatId,
563
751
  startSession: startGeminiLiveSession,
564
752
  sendAudioChunk: sendGeminiLiveAudioChunk,
565
753
  stopSession: stopGeminiLiveSession
@@ -568,8 +756,6 @@ export default function ChatPanel({
568
756
  const canSubmit = Boolean(message.trim() || imageAttachments.length > 0 || videoAttachments.length > 0 || documentName)
569
757
  const sendingImageMarkers = Array.from({ length: sendingImageCount }, (_, index) => `[Image #${index + 1}]`).join(' ')
570
758
  const sendingVideoMarkers = Array.from({ length: sendingVideoCount || 0 }, (_, index) => `[Video #${index + 1}]`).join(' ')
571
- const voiceStatus = speakingText ? 'speaking' : (sending || voiceAwaitingResponse) ? 'thinking' : isRecording ? 'listening' : voiceMode ? 'ready' : 'off'
572
- const voiceStatusLabel = voiceStatus === 'speaking' ? 'Speaking' : voiceStatus === 'thinking' ? 'Thinking' : voiceStatus === 'listening' ? 'Listening' : 'Ready'
573
759
 
574
760
  const getAvailableModels = (provider: string) => {
575
761
  switch (provider) {
@@ -631,9 +817,6 @@ export default function ChatPanel({
631
817
  }
632
818
  }
633
819
  const activeModel = getActiveModel(activeProvider)
634
- const workspaceName = workspacePath
635
- ? workspacePath.split(/[\\/]/).filter(Boolean).pop() || workspacePath
636
- : 'Select Project'
637
820
  const textareaRef = useRef<HTMLTextAreaElement>(null)
638
821
  const slashRef = useRef<SlashSuggestionsHandle>(null)
639
822
 
@@ -682,10 +865,10 @@ export default function ChatPanel({
682
865
  }
683
866
  // "Edit" on a past user message: drop its text back into the composer so it
684
867
  // can be tweaked and sent again as a new message (nothing is deleted).
685
- const handleEditMessage = (text: string) => {
868
+ const handleEditMessage = useLatestCallback((text: string) => {
686
869
  setHistoryIndex(null)
687
870
  applyHistoryValue(text)
688
- }
871
+ })
689
872
  const navigateHistoryNext = () => {
690
873
  if (historyIndex === null) return false
691
874
  if (historyIndex === 0) {
@@ -820,7 +1003,7 @@ export default function ChatPanel({
820
1003
  scheduleVoiceListen(900)
821
1004
  }
822
1005
  }
823
- const speak = (text: string) => {
1006
+ const speak = useLatestCallback((text: string) => {
824
1007
  const speechText = cleanSpeechText(text)
825
1008
  if (!speechText) return
826
1009
  if (speakingText === text) {
@@ -840,18 +1023,8 @@ export default function ChatPanel({
840
1023
  return
841
1024
  }
842
1025
  speakNative(speechText, text)
843
- }
844
-
845
- const toggleRecording = () => {
846
- if (isRecording) {
847
- stopRecognition()
848
- cancelSpeech()
849
- return
850
- }
1026
+ })
851
1027
 
852
- cancelSpeech()
853
- startRecognition()
854
- }
855
1028
  const resizeInput = (element: HTMLTextAreaElement) => {
856
1029
  element.style.height = 'auto'
857
1030
  element.style.height = `${Math.min(element.scrollHeight, 120)}px`
@@ -912,13 +1085,13 @@ export default function ChatPanel({
912
1085
  }, [onPasteImage])
913
1086
  useEffect(() => {
914
1087
  const handleEscapeKeyDown = (event: globalThis.KeyboardEvent) => {
915
- if (event.key === 'Escape' && sending) {
1088
+ if (event.key === 'Escape' && sending && !sessionSourcesOpen) {
916
1089
  onCancelMessage()
917
1090
  }
918
1091
  }
919
1092
  window.addEventListener('keydown', handleEscapeKeyDown, true)
920
1093
  return () => window.removeEventListener('keydown', handleEscapeKeyDown, true)
921
- }, [sending, onCancelMessage])
1094
+ }, [sending, onCancelMessage, sessionSourcesOpen])
922
1095
  useEffect(() => {
923
1096
  if (message) return
924
1097
  const input = document.getElementById('chat-input') as HTMLTextAreaElement | null
@@ -967,35 +1140,12 @@ export default function ChatPanel({
967
1140
  appendWorkspaceReference(reference)
968
1141
  }
969
1142
  const isEmptyChat = interactions.length === 0 && !sending && !pendingApproval
970
- const renderCompletedActivity = useCallback((interaction: any) => {
971
- const interactionId = String(interaction.id)
972
- const progress = agentActivitySnapshots[interactionId] ?? interaction.agentActivity ?? []
973
- const activityView = activitiesFrom(progress)
974
- const isOpen = Boolean(openActivityIds[interactionId])
975
- return (
976
- <AgentActivityDrawer
977
- activityView={activityView}
978
- isOpen={isOpen}
979
- onToggle={() => setOpenActivityIds((current) => ({ ...current, [interactionId]: !current[interactionId] }))}
980
- isHistorical={true}
981
- rawProgress={progress}
982
- />
983
- )
984
- }, [agentActivitySnapshots, openActivityIds])
985
-
986
- const renderWebSearchSources = useCallback((interaction: any) => {
987
- const interactionId = String(interaction.id)
988
- const progress = agentActivitySnapshots[interactionId] ?? interaction.agentActivity ?? []
989
- const sources = parseWebSearchSources(progress)
990
- if (sources.length === 0) return null
991
-
992
- return <SourcesBlock sources={sources} />
993
- }, [agentActivitySnapshots])
994
-
995
1143
  const renderChangesList = (changes: ReturnType<typeof parseFileChangesFromProgress>, idPrefix: string) => {
1144
+ const showAll = Boolean(showAllFileChanges[idPrefix])
1145
+ const visibleChanges = showAll ? changes : changes.slice(0, 3)
996
1146
  return (
997
- <div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>
998
- {changes.map((change) => {
1147
+ <div className="file-changes-list" style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>
1148
+ {visibleChanges.map((change) => {
999
1149
  const fileKey = `${idPrefix}-${change.path}`
1000
1150
  const isDiffOpen = Boolean(openFileDiffs[fileKey])
1001
1151
  const fileName = change.path.split('/').pop() || change.path
@@ -1042,7 +1192,7 @@ export default function ChatPanel({
1042
1192
  change.created && change.hunks.length > 0
1043
1193
  ? change.hunks.map((h) => h.newText).filter(Boolean).join('\n')
1044
1194
  : undefined
1045
- setActiveArtifact({ path: change.path, content: fallbackContent })
1195
+ openArtifact({ path: change.path, content: fallbackContent })
1046
1196
  }}
1047
1197
  title="Open Live Preview Split View"
1048
1198
  >
@@ -1083,13 +1233,24 @@ export default function ChatPanel({
1083
1233
  </div>
1084
1234
  )
1085
1235
  })}
1236
+ {changes.length > 3 && (
1237
+ <button
1238
+ type="button"
1239
+ className="file-changes-show-more"
1240
+ aria-expanded={showAll}
1241
+ onClick={() => setShowAllFileChanges((current) => ({ ...current, [idPrefix]: !current[idPrefix] }))}
1242
+ >
1243
+ {showAll ? 'Show fewer files' : `Show ${changes.length - 3} more ${changes.length - 3 === 1 ? 'file' : 'files'}`}
1244
+ <span aria-hidden="true" className={showAll ? 'is-expanded' : ''}>⌄</span>
1245
+ </button>
1246
+ )}
1086
1247
  </div>
1087
1248
  )
1088
1249
  }
1089
1250
 
1090
1251
  const renderFileChanges = useCallback((interaction: any) => {
1091
1252
  const interactionId = String(interaction.id)
1092
- const progress = agentActivitySnapshots[interactionId] ?? interaction.agentActivity ?? []
1253
+ const progress = agentActivitySnapshots[interactionId] ?? interaction.agentActivity ?? EMPTY_AGENT_PROGRESS
1093
1254
  const changes = parseFileChangesFromProgress(progress)
1094
1255
  if (changes.length === 0) return null
1095
1256
 
@@ -1097,7 +1258,7 @@ export default function ChatPanel({
1097
1258
  const totalDeletions = changes.reduce((sum, c) => sum + c.deletions, 0)
1098
1259
  const createdCount = changes.filter((c) => c.created).length
1099
1260
  const modifiedCount = changes.length - createdCount
1100
- const isOpen = Boolean(openReviewIds[interactionId])
1261
+ const isOpen = openReviewIds[interactionId] ?? true
1101
1262
 
1102
1263
  let summaryLabel = ''
1103
1264
  if (createdCount > 0 && modifiedCount === 0) {
@@ -1171,108 +1332,97 @@ export default function ChatPanel({
1171
1332
  }
1172
1333
 
1173
1334
  return (
1174
- <div className="file-changes-summary-container" style={{ marginBottom: '8px' }}>
1175
- <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '8px' }}>
1176
- <button
1177
- type="button"
1178
- className="agent-activity-toggle file-changes-toggle"
1179
- aria-expanded={isOpen}
1180
- onClick={() => setOpenReviewIds((current) => ({ ...current, [interactionId]: !current[interactionId] }))}
1181
- >
1182
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{ marginRight: '2px' }}>
1183
- <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
1184
- <polyline points="22 4 12 14.01 9 11.01" />
1185
- </svg>
1186
- <span>
1187
- {summaryLabel}
1188
- {createdCount > 0 && modifiedCount === 0 ? (
1189
- <span className="file-changes-count-add" style={{ marginLeft: '6px' }}>
1190
- (+{totalAdditions} {totalAdditions === 1 ? 'line' : 'lines'})
1335
+ <div className="file-changes-summary-container">
1336
+ <div className="agent-activity-card file-changes-card">
1337
+ <div className="file-changes-summary-row">
1338
+ <div className="file-changes-summary">
1339
+ <span className="file-changes-summary-icon" aria-hidden="true">⊞</span>
1340
+ <span className="file-changes-summary-copy">
1341
+ <span className="file-changes-summary-label">{summaryLabel}</span>
1342
+ <span className="file-changes-summary-counts">
1343
+ {totalAdditions > 0 && <span className="file-changes-count-add">+{totalAdditions}</span>}
1344
+ {totalDeletions > 0 && <span className="file-changes-count-del">-{totalDeletions}</span>}
1191
1345
  </span>
1192
- ) : (
1193
- <>
1194
- {totalAdditions > 0 && <span className="file-changes-count-add" style={{ marginLeft: '6px' }}>+{totalAdditions}</span>}
1195
- {totalDeletions > 0 && <span className="file-changes-count-del" style={{ marginLeft: '4px' }}>-{totalDeletions}</span>}
1196
- </>
1197
- )}
1198
- </span>
1199
- <span aria-hidden="true">{isOpen ? '^' : '>'}</span>
1200
- </button>
1201
-
1202
- <button
1203
- type="button"
1204
- className="file-changes-rewind-btn"
1205
- onClick={handleRewind}
1206
- title="Rewind workspace to before these file edits (Git Checkpoint)"
1207
- >
1208
- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
1209
- <polyline points="1 4 1 10 7 10" />
1210
- <path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10" />
1211
- </svg>
1212
- Rewind
1213
- </button>
1214
- </div>
1215
-
1216
- {isOpen && (
1217
- <div className="agent-activity-card file-changes-card">
1218
- {renderChangesList(changes, interactionId)}
1346
+ </span>
1347
+ </div>
1348
+ <div className="file-changes-summary-actions">
1349
+ <button
1350
+ type="button"
1351
+ className="file-changes-rewind-btn"
1352
+ onClick={handleRewind}
1353
+ title="Rewind workspace to before these file edits (Git Checkpoint)"
1354
+ >
1355
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1356
+ <polyline points="1 4 7 4 7 10" />
1357
+ <path d="M3 9a9 9 0 1 0 2.13-5.36L1 7" />
1358
+ </svg>
1359
+ Undo
1360
+ </button>
1361
+ <button
1362
+ type="button"
1363
+ className="file-changes-review-btn"
1364
+ title="Review changed code"
1365
+ onClick={() => {
1366
+ openReview('All conversation changes', getConversationChanges())
1367
+ }}
1368
+ >
1369
+ Review
1370
+ </button>
1371
+ </div>
1219
1372
  </div>
1220
- )}
1373
+ {isOpen && <div className="file-changes-list-container">{renderChangesList(changes, interactionId)}</div>}
1374
+ </div>
1221
1375
  </div>
1222
1376
  )
1223
- }, [agentActivitySnapshots, openReviewIds, openFileDiffs, workspacePath])
1377
+ }, [agentActivitySnapshots, getConversationChanges, openReviewIds, openFileDiffs, showAllFileChanges, workspacePath, onOpenArtifact, onOpenReview])
1224
1378
 
1225
1379
  const renderActiveFileChanges = () => {
1226
- const changes = parseFileChangesFromProgress(agentProgress)
1380
+ const changes = composerChanges
1227
1381
  if (changes.length === 0) return null
1228
1382
 
1229
1383
  const totalAdditions = changes.reduce((sum, c) => sum + c.additions, 0)
1230
1384
  const totalDeletions = changes.reduce((sum, c) => sum + c.deletions, 0)
1231
1385
  const createdCount = changes.filter((c) => c.created).length
1232
1386
  const modifiedCount = changes.length - createdCount
1233
- const isOpen = Boolean(openReviewIds['active-run'])
1387
+ const isOpen = openReviewIds['active-run'] ?? true
1234
1388
 
1235
1389
  let summaryLabel = ''
1236
1390
  if (createdCount > 0 && modifiedCount === 0) {
1237
- summaryLabel = `${createdCount} ${createdCount === 1 ? 'file created' : 'files created'} in this run`
1391
+ summaryLabel = `${createdCount} ${createdCount === 1 ? 'file created' : 'files created'}`
1238
1392
  } else if (createdCount > 0 && modifiedCount > 0) {
1239
- summaryLabel = `${createdCount} created, ${modifiedCount} modified in this run`
1393
+ summaryLabel = `${createdCount} created, ${modifiedCount} modified`
1240
1394
  } else {
1241
- summaryLabel = `${changes.length} ${changes.length === 1 ? 'file changed' : 'files changed'} in this run`
1395
+ summaryLabel = `${changes.length} ${changes.length === 1 ? 'file changed' : 'files changed'}`
1242
1396
  }
1243
1397
 
1244
1398
  return (
1245
1399
  <div className="message ai-message agent-activity-message" style={{ marginTop: '4px', marginBottom: '8px' }}>
1246
1400
  <div className="agent-activity-card file-changes-card">
1247
- <button
1248
- type="button"
1249
- className="agent-activity-toggle file-changes-toggle"
1250
- aria-expanded={isOpen}
1251
- onClick={() => setOpenReviewIds((current) => ({ ...current, 'active-run': !current['active-run'] }))}
1252
- style={{ border: 0, background: 'transparent', padding: 0 }}
1253
- >
1254
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{ marginRight: '2px' }}>
1255
- <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
1256
- <polyline points="22 4 12 14.01 9 11.01" />
1257
- </svg>
1258
- <span>
1259
- {summaryLabel}
1260
- {createdCount > 0 && modifiedCount === 0 ? (
1261
- <span className="file-changes-count-add" style={{ marginLeft: '6px' }}>
1262
- (+{totalAdditions} {totalAdditions === 1 ? 'line' : 'lines'})
1401
+ <div className="file-changes-summary-row">
1402
+ <div className="file-changes-summary">
1403
+ <span className="file-changes-summary-icon" aria-hidden="true">✓</span>
1404
+ <span className="file-changes-summary-copy">
1405
+ <span className="file-changes-summary-label">{summaryLabel}</span>
1406
+ <span className="file-changes-summary-counts">
1407
+ {totalAdditions > 0 && <span className="file-changes-count-add">+{totalAdditions}</span>}
1408
+ {totalDeletions > 0 && <span className="file-changes-count-del">-{totalDeletions}</span>}
1263
1409
  </span>
1264
- ) : (
1265
- <>
1266
- {totalAdditions > 0 && <span className="file-changes-count-add" style={{ marginLeft: '6px' }}>+{totalAdditions}</span>}
1267
- {totalDeletions > 0 && <span className="file-changes-count-del" style={{ marginLeft: '4px' }}>-{totalDeletions}</span>}
1268
- </>
1269
- )}
1270
- </span>
1271
- <span aria-hidden="true">{isOpen ? '^' : '>'}</span>
1272
- </button>
1410
+ </span>
1411
+ </div>
1412
+ <button
1413
+ type="button"
1414
+ className="file-changes-review-btn"
1415
+ title="Review changed code"
1416
+ onClick={() => {
1417
+ openReview('All conversation changes', getConversationChanges())
1418
+ }}
1419
+ >
1420
+ Review
1421
+ </button>
1422
+ </div>
1273
1423
 
1274
1424
  {isOpen && (
1275
- <div style={{ marginTop: '8px' }}>
1425
+ <div className="file-changes-list-container" style={{ marginTop: '8px' }}>
1276
1426
  {renderChangesList(changes, 'active')}
1277
1427
  </div>
1278
1428
  )}
@@ -1281,6 +1431,111 @@ export default function ChatPanel({
1281
1431
  )
1282
1432
  }
1283
1433
 
1434
+ const liveTurn = sending || pendingApproval ? (
1435
+ <>
1436
+ {sending && (
1437
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', marginBottom: '16px' }}>
1438
+ <div className="message user-message"><div className="bubble-wrapper"><div className="message-bubble"><FormattedMessage text={[sendingMessage, sendingImageMarkers, sendingVideoMarkers].filter(Boolean).join(' ')} /></div></div></div>
1439
+ {agentMode && (
1440
+ <ProgressActivity
1441
+ progress={agentProgress}
1442
+ id="live"
1443
+ isOpen={openActivityIds['live'] ?? true}
1444
+ onToggle={toggleActivity}
1445
+ pendingApproval={!!pendingApproval}
1446
+ />
1447
+ )}
1448
+ {renderActiveFileChanges()}
1449
+ <div className="message ai-message thinking-message">
1450
+ <div className="bubble-wrapper">
1451
+ {!agentMode && liveExtendedThoughts.length > 0 && (
1452
+ <ThinkingBlock
1453
+ blockKey="live-extended"
1454
+ thoughts={liveExtendedThoughts}
1455
+ isLive={true}
1456
+ variant="extended"
1457
+ expanded={thinkingExpanded['live-extended'] ?? true}
1458
+ onExpandedChange={onThinkingExpandedChange}
1459
+ />
1460
+ )}
1461
+ {!agentMode && liveThoughts.length > 0 && liveExtendedThoughts.length === 0 && (
1462
+ <ThinkingBlock
1463
+ blockKey="live"
1464
+ thoughts={liveThoughts}
1465
+ isLive={true}
1466
+ expanded={thinkingExpanded.live ?? true}
1467
+ onExpandedChange={onThinkingExpandedChange}
1468
+ />
1469
+ )}
1470
+ <div className="message-bubble">
1471
+ <McpToolResults progress={agentProgress} running />
1472
+ <ViewedImages progress={agentProgress} />
1473
+ <span>
1474
+ {compaction ? (
1475
+ <ContextCompactionStatus key={compaction.index} />
1476
+ ) : throttledStreamedReply ? (
1477
+ <FormattedMessage text={throttledStreamedReply} sources={liveWebSources} />
1478
+ ) : (
1479
+ <div className="thinking-status">
1480
+ <span className="thinking-status-label">
1481
+ <span aria-hidden="true">✦ </span>
1482
+ {activeAgentName && activeModelName
1483
+ ? `${activeAgentName} (${activeModelName}) is thinking...`
1484
+ : 'Thinking'}
1485
+ </span>
1486
+ <span className="thinking-status-meta">
1487
+ {` · ${elapsedSeconds}s · Esc to cancel`}
1488
+ </span>
1489
+ </div>
1490
+ )}
1491
+ </span>
1492
+ </div>
1493
+ {streamedResponse && (
1494
+ <div className="message-time" style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
1495
+ <span className="provider-model-chip" data-provider={(streamedResponse.provider || '').toLowerCase()} title={`${streamedResponse.provider} • ${streamedResponse.model}`}>
1496
+ <span className="provider-chip-dot" aria-hidden="true" />
1497
+ <span className="provider-chip-name">{streamedResponse.provider}</span>
1498
+ <span className="provider-chip-divider">/</span>
1499
+ <span className="provider-chip-model">{streamedResponse.model}</span>
1500
+ </span>
1501
+ {activeFallbackNotice && <span className="provider-fallback-notice">{activeFallbackNotice}</span>}
1502
+ {throttledStreamedReply && (
1503
+ <div className="message-action-buttons" style={{ display: 'flex', alignItems: 'center', gap: '4px', marginLeft: 'auto' }}>
1504
+ <button
1505
+ type="button"
1506
+ className={`msg-action-btn copy-btn ${copiedId === 'live' ? 'is-copied' : ''}`}
1507
+ onClick={() => handleCopyMessage('live', throttledStreamedReply)}
1508
+ title={copiedId === 'live' ? 'คัดลอกแล้ว (Copied!)' : 'คัดลอกข้อความ (Copy message)'}
1509
+ >
1510
+ {renderCopyIcon(copiedId === 'live')}
1511
+ </button>
1512
+ <button
1513
+ type="button"
1514
+ className={`msg-action-btn tts-btn ${speakingText === throttledStreamedReply ? 'is-speaking' : ''}`}
1515
+ onClick={() => speak(throttledStreamedReply)}
1516
+ title={speakingText === throttledStreamedReply ? 'Stop reading' : 'Read aloud'}
1517
+ >
1518
+ {renderSpeakerIcon(speakingText === throttledStreamedReply)}
1519
+ </button>
1520
+ </div>
1521
+ )}
1522
+ </div>
1523
+ )}
1524
+ </div>
1525
+ </div>
1526
+ </div>
1527
+ )}
1528
+
1529
+ {pendingApproval && (
1530
+ <ApprovalCard
1531
+ key={pendingApproval.id || JSON.stringify(pendingApproval)}
1532
+ pendingApproval={pendingApproval}
1533
+ onApproval={onApproval}
1534
+ />
1535
+ )}
1536
+ </>
1537
+ ) : null
1538
+
1284
1539
  const sectionContent = (
1285
1540
  <section
1286
1541
  className={`conversation-panel ${isEmptyChat ? 'is-empty' : ''}`}
@@ -1288,7 +1543,7 @@ export default function ChatPanel({
1288
1543
  onDragOver={handleDragOver}
1289
1544
  onDragLeave={handleDragLeave}
1290
1545
  onDrop={handleDrop}
1291
- style={activeArtifact ? { flex: '0 0 calc(100% - var(--preview-width, 50%))', width: 'calc(100% - var(--preview-width, 50%))', minWidth: '320px', maxWidth: 'none', margin: 0, position: 'relative' } : undefined}
1546
+ style={activeArtifact || reviewPage ? { flex: '0 0 calc(100% - var(--preview-width, 50%))', width: 'calc(100% - var(--preview-width, 50%))', minWidth: '320px', maxWidth: 'none', margin: 0, position: 'relative' } : undefined}
1292
1547
  >
1293
1548
  {isDragging && (
1294
1549
  <div
@@ -1317,7 +1572,7 @@ export default function ChatPanel({
1317
1572
  pointerEvents: 'auto',
1318
1573
  }}
1319
1574
  >
1320
- <div style={{ marginBottom: '16px', color: 'var(--accent)' }}>
1575
+ <div style={{ marginBottom: '16px', color: 'var(--interactive-fg)' }}>
1321
1576
  <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1322
1577
  <rect x="3" y="3" width="18" height="18" rx="2" ry="2" />
1323
1578
  <circle cx="8.5" cy="8.5" r="1.5" />
@@ -1334,9 +1589,9 @@ export default function ChatPanel({
1334
1589
  className="mobile-menu-btn"
1335
1590
  type="button"
1336
1591
  onClick={onToggleMobileSidebar}
1337
- aria-label="Toggle menu"
1592
+ aria-label="Open navigation menu"
1338
1593
  >
1339
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1594
+ <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
1340
1595
  <line x1="3" y1="12" x2="21" y2="12" />
1341
1596
  <line x1="3" y1="6" x2="21" y2="6" />
1342
1597
  <line x1="3" y1="18" x2="21" y2="18" />
@@ -1344,35 +1599,81 @@ export default function ChatPanel({
1344
1599
  </button>
1345
1600
  )}
1346
1601
  <div className="chat-header-title">
1347
- <img src={APP_ICON_PATH} alt="Logo" className="chat-header-logo" />
1348
- <span>Mint Agent</span>
1602
+ {isCliSession ? (
1603
+ <div className="chat-header-breadcrumb">
1604
+ {onBackToCode && (
1605
+ <button
1606
+ type="button"
1607
+ className="chat-header-back-btn"
1608
+ onClick={onBackToCode}
1609
+ title="Back to Code sessions Hub"
1610
+ >
1611
+ <svg
1612
+ width="12"
1613
+ height="12"
1614
+ viewBox="0 0 24 24"
1615
+ fill="none"
1616
+ stroke="currentColor"
1617
+ strokeWidth="2.5"
1618
+ strokeLinecap="round"
1619
+ strokeLinejoin="round"
1620
+ >
1621
+ <path d="M15 18l-6-6 6-6" />
1622
+ </svg>
1623
+ <span>Code</span>
1624
+ </button>
1625
+ )}
1626
+ <span className="chat-header-sep">/</span>
1627
+ <span className="chat-header-session-tag" title={cliSessionId || 'CLI Session'}>
1628
+ <span>
1629
+ {cliSessionId ? (cliSessionId === 'cli' ? 'cli' : `cli::${cliSessionId.replace(/^cli::/, '').slice(0, 7)}`) : 'cli'}
1630
+ </span>
1631
+ </span>
1632
+ </div>
1633
+ ) : (
1634
+ <div className="chat-header-brand-group">
1635
+ <img src={runtimePlatform.appIconPath()} alt="Logo" className="chat-header-logo" />
1636
+ <span
1637
+ className="chat-header-title-text"
1638
+ title={conversationTitle && conversationTitle.trim() && conversationTitle !== 'New chat' ? conversationTitle.trim() : 'Mint Agent'}
1639
+ >
1640
+ {conversationTitle && conversationTitle.trim() && conversationTitle !== 'New chat' ? conversationTitle.trim() : 'Mint Agent'}
1641
+ </span>
1642
+ {projectName && (
1643
+ <span className="chat-header-project-pill" title={`Project: ${workspacePath}`}>
1644
+ <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
1645
+ <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path>
1646
+ </svg>
1647
+ <span>{projectName}</span>
1648
+ </span>
1649
+ )}
1650
+ </div>
1651
+ )}
1349
1652
  </div>
1350
- <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
1653
+ <div className="chat-header-actions">
1654
+ {showSessionSources && <SessionSourcesPopover chatId={chatId} liveProgress={agentProgress} open={sessionSourcesOpen} onOpenChange={setSessionSourcesOpen} />}
1655
+ {tools?.onToggle && <ToolsPanelToggle open={tools.open} count={tools.backgroundTaskCount} onToggle={tools.onToggle} />}
1351
1656
  {activeArtifact && (
1352
1657
  <button
1353
1658
  type="button"
1354
- className="chat-header-clear-btn"
1659
+ className="chat-header-pill-btn"
1355
1660
  title="Close Live Preview"
1356
1661
  onClick={() => setActiveArtifact(null)}
1357
- style={{
1358
- color: 'var(--accent)',
1359
- background: 'color-mix(in srgb, var(--accent) 12%, transparent)',
1360
- border: '1px solid color-mix(in srgb, var(--accent) 25%, transparent)',
1361
- padding: '2px 8px',
1362
- borderRadius: 'var(--radius-xs, 4px)',
1363
- fontSize: '0.74rem',
1364
- fontWeight: 600,
1365
- cursor: 'pointer',
1366
- display: 'inline-flex',
1367
- alignItems: 'center',
1368
- gap: '4px',
1369
- }}
1370
1662
  >
1371
- <span>Close Live Preview</span>
1663
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
1664
+ <line x1="18" y1="6" x2="6" y2="18"></line>
1665
+ <line x1="6" y1="6" x2="18" y2="18"></line>
1666
+ </svg>
1667
+ <span>Close preview</span>
1372
1668
  </button>
1373
1669
  )}
1374
- <button className="chat-header-clear-btn" title="Clear Messages" onClick={onClearMessages}>
1375
- <svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
1670
+ <button
1671
+ type="button"
1672
+ className="chat-header-action-btn"
1673
+ title="Clear conversation"
1674
+ onClick={onClearMessages}
1675
+ >
1676
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1376
1677
  <polyline points="3 6 5 6 21 6"></polyline>
1377
1678
  <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
1378
1679
  <line x1="10" y1="11" x2="10" y2="17"></line>
@@ -1381,142 +1682,62 @@ export default function ChatPanel({
1381
1682
  </button>
1382
1683
  </div>
1383
1684
  </div>
1384
- <div className="chat-container" ref={chatContainerRef} onScroll={handleChatScroll}>
1385
- {interactions.map((interaction, index) => (
1386
- <Fragment key={interaction.id}>
1387
- {index > 0 && shouldShowSessionDivider(interactions[index - 1].createdAt, interaction.createdAt) && (
1388
- <div className="system-event-divider">
1389
- <div className="system-event-line" />
1390
- <div className="system-event-pill">
1391
- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
1392
- <circle cx="12" cy="12" r="9" />
1393
- <polyline points="12 7 12 12 15.5 14" />
1394
- </svg>
1395
- <span>{formatSessionDividerLabel(interaction.createdAt)}</span>
1396
- </div>
1397
- <div className="system-event-line" />
1398
- </div>
1399
- )}
1400
- <ChatMessageItem
1401
- interaction={interaction}
1402
- copiedId={copiedId}
1403
- onEditMessage={handleEditMessage}
1404
- speakingText={speakingText}
1405
- agentActivitySnapshots={agentActivitySnapshots}
1406
- thinkingExpanded={thinkingExpanded}
1407
- openActivityIds={openActivityIds}
1408
- openReviewIds={openReviewIds}
1409
- openFileDiffs={openFileDiffs}
1410
- onThinkingExpandedChange={onThinkingExpandedChange}
1411
- handleCopyMessage={handleCopyMessage}
1412
- speak={speak}
1413
- renderCompletedActivity={renderCompletedActivity}
1414
- renderFileChanges={renderFileChanges}
1415
- renderWebSearchSources={renderWebSearchSources}
1416
- />
1417
- </Fragment>
1418
- ))}
1419
-
1420
- {sending && (
1421
- <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', marginBottom: '16px' }}>
1422
- <div className="message user-message"><div className="bubble-wrapper"><div className="message-bubble">{renderFormattedMessage([sendingMessage, sendingImageMarkers, sendingVideoMarkers].filter(Boolean).join(' '))}</div></div></div>
1423
- {agentMode && (
1424
- <AgentActivityDrawer
1425
- activityView={agentActivities}
1426
- isOpen={openActivityIds['live'] ?? true}
1427
- onToggle={() => setOpenActivityIds((current) => ({ ...current, live: !(current['live'] ?? true) }))}
1428
- pendingApproval={!!pendingApproval}
1429
- rawProgress={agentProgress}
1430
- />
1431
- )}
1432
- {renderActiveFileChanges()}
1433
- <div className="message ai-message thinking-message">
1434
- <div className="bubble-wrapper">
1435
- <ThinkingBlock
1436
- blockKey="live"
1437
- thoughts={thoughtsFrom(agentProgress)}
1438
- isLive={true}
1439
- expanded={thinkingExpanded.live ?? true}
1440
- onExpandedChange={onThinkingExpandedChange}
1441
- showEmptyHint={
1442
- agentMode
1443
- && hasAgentToolActivity(agentProgress)
1444
- && thoughtsFrom(agentProgress).length === 0
1445
- && !streamedReply
1446
- }
1447
- />
1448
- <div className="message-bubble">
1449
- <span>
1450
- {streamedReply ? (
1451
- renderFormattedMessage(streamedReply)
1452
- ) : (
1453
- <div style={{ display: 'flex', alignItems: 'center', gap: '8px', color: 'var(--text-soft, #94a3b8)' }}>
1454
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" style={{ display: 'inline-block', flexShrink: 0 }}>
1455
- <circle cx="12" cy="12" r="10" stroke="rgba(255, 255, 255, 0.12)" />
1456
- <path d="M12 2a10 10 0 0 1 10 10" stroke="var(--accent)" strokeLinecap="round">
1457
- <animateTransform
1458
- attributeName="transform"
1459
- type="rotate"
1460
- from="0 12 12"
1461
- to="360 12 12"
1462
- dur="0.9s"
1463
- repeatCount="indefinite"
1464
- />
1465
- </path>
1466
- </svg>
1467
- <span>
1468
- {activeAgentName && activeModelName
1469
- ? `${activeAgentName} (${activeModelName}) is thinking... (${elapsedSeconds}s)`
1470
- : `Thinking for ${elapsedSeconds}s (Esc to cancel)`
1471
- }
1472
- </span>
1473
- </div>
1474
- )}
1475
- </span>
1476
- </div>
1477
- {streamedResponse && (
1478
- <div className="message-time" style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
1479
- <span className="provider-model-chip" data-provider={(streamedResponse.provider || '').toLowerCase()} title={`${streamedResponse.provider} • ${streamedResponse.model}`}>
1480
- <span className="provider-chip-dot" aria-hidden="true" />
1481
- <span className="provider-chip-name">{streamedResponse.provider}</span>
1482
- <span className="provider-chip-divider">/</span>
1483
- <span className="provider-chip-model">{streamedResponse.model}</span>
1484
- </span>
1485
- {activeFallbackNotice && <span className="provider-fallback-notice">{activeFallbackNotice}</span>}
1486
- {streamedReply && (
1487
- <div className="message-action-buttons" style={{ display: 'flex', alignItems: 'center', gap: '4px', marginLeft: 'auto' }}>
1488
- <button
1489
- type="button"
1490
- className={`msg-action-btn copy-btn ${copiedId === 'live' ? 'is-copied' : ''}`}
1491
- onClick={() => handleCopyMessage('live', streamedReply)}
1492
- title={copiedId === 'live' ? 'คัดลอกแล้ว (Copied!)' : 'คัดลอกข้อความ (Copy message)'}
1493
- >
1494
- {renderCopyIcon(copiedId === 'live')}
1495
- </button>
1496
- <button
1497
- type="button"
1498
- className={`msg-action-btn tts-btn ${speakingText === streamedReply ? 'is-speaking' : ''}`}
1499
- onClick={() => speak(streamedReply)}
1500
- title={speakingText === streamedReply ? 'Stop reading' : 'Read aloud'}
1501
- >
1502
- {renderSpeakerIcon(speakingText === streamedReply)}
1503
- </button>
1504
- </div>
1505
- )}
1685
+ <div className="chat-container" ref={chatContainerRef} onScroll={handleChatScroll} style={{ overflowAnchor: 'none' }}>
1686
+ {hasOlder && onLoadOlder && (
1687
+ <button type="button" className="load-older-messages" disabled={loadingOlder}
1688
+ style={{ display: 'block', margin: '0 auto 20px', padding: '7px 14px', borderRadius: 8,
1689
+ border: '1px solid var(--border-color, #3a3a3a)', background: 'var(--surface, #252525)',
1690
+ color: 'var(--text-secondary, #c0c0c0)', cursor: loadingOlder ? 'default' : 'pointer' }}
1691
+ onClick={async () => {
1692
+ setLoadingOlder(true)
1693
+ try {
1694
+ await onLoadOlder()
1695
+ } finally { setLoadingOlder(false) }
1696
+ }}>
1697
+ {loadingOlder ? 'Loading earlier messages…' : 'Load earlier messages'}
1698
+ </button>
1699
+ )}
1700
+ <VirtualChatHistory key={chatId} ref={virtualHistoryRef} items={visibleInteractions}
1701
+ scrollRef={chatContainerRef} hasOlder={hasOlder}
1702
+ renderRow={(index) => {
1703
+ const interaction = visibleInteractions[index]
1704
+ return (
1705
+ <Fragment key={interaction.id}>
1706
+ {index > 0 && shouldShowSessionDivider(visibleInteractions[index - 1].createdAt, interaction.createdAt) && (
1707
+ <div className="system-event-divider">
1708
+ <div className="system-event-line" />
1709
+ <div className="system-event-pill">
1710
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
1711
+ <circle cx="12" cy="12" r="9" />
1712
+ <polyline points="12 7 12 12 15.5 14" />
1713
+ </svg>
1714
+ <span>{formatSessionDividerLabel(interaction.createdAt)}</span>
1715
+ </div>
1716
+ <div className="system-event-line" />
1506
1717
  </div>
1507
1718
  )}
1508
- </div>
1509
- </div>
1510
- </div>
1511
- )}
1512
-
1513
- {pendingApproval && (
1514
- <ApprovalCard
1515
- key={pendingApproval.id || JSON.stringify(pendingApproval)}
1516
- pendingApproval={pendingApproval}
1517
- onApproval={onApproval}
1518
- />
1519
- )}
1719
+ <ChatMessageItem
1720
+ interaction={interaction}
1721
+ copiedId={copiedId}
1722
+ onEditMessage={handleEditMessage}
1723
+ speakingText={speakingText}
1724
+ agentActivitySnapshots={agentActivitySnapshots}
1725
+ thinkingExpanded={thinkingExpanded}
1726
+ openActivityIds={openActivityIds}
1727
+ openReviewIds={openReviewIds}
1728
+ openFileDiffs={openFileDiffs}
1729
+ onThinkingExpandedChange={onThinkingExpandedChange}
1730
+ handleCopyMessage={handleCopyMessage}
1731
+ speak={speak}
1732
+ toggleActivity={toggleActivity}
1733
+ showAllFileChanges={showAllFileChanges}
1734
+ workspacePath={workspacePath}
1735
+ renderFileChanges={renderFileChanges}
1736
+ />
1737
+ </Fragment>
1738
+ )
1739
+ }}
1740
+ tail={liveTurn} />
1520
1741
  {showScrollToBottom && (
1521
1742
  <button
1522
1743
  type="button"
@@ -1534,75 +1755,66 @@ export default function ChatPanel({
1534
1755
  <div ref={chatEnd} />
1535
1756
  </div>
1536
1757
 
1537
- <div className={`input-area ${voiceMode ? 'voice-active' : ''}`}>
1538
- {isEmptyChat && <div className="empty-chat-prompt">Mint Agent is ready to work</div>}
1539
- {onSelectWorkspace && (
1540
- <button type="button" className="workspace-select-btn" onClick={onSelectWorkspace}>
1541
- <span aria-hidden="true" style={{ display: 'inline-flex', alignItems: 'center' }}>
1542
- <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round">
1543
- <path d="M3 6h7l2 2h9v10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z"></path>
1544
- </svg>
1758
+ <div className="input-area">
1759
+ <ModsPanel workspacePath={workspacePath} chatId={chatId} panelTarget={tools?.modsPanelTarget} onOpen={tools?.onOpenMods ?? (() => {})} />
1760
+ {composerChanges.length > 0 && (
1761
+ <button
1762
+ type="button"
1763
+ className={`composer-change-status ${sending ? 'is-live' : ''}`}
1764
+ onClick={() => openReview(composerChangeLabel, composerChanges)}
1765
+ title="Review recent agent changes"
1766
+ >
1767
+ <span className="composer-change-status-copy">
1768
+ {sending && <span className="composer-change-status-spinner" aria-hidden="true" />}
1769
+ <span>{sending ? `Editing ${composerChanges.length} ${composerChanges.length === 1 ? 'file' : 'files'}…` : composerChangeLabel}</span>
1770
+ </span>
1771
+ <span className="composer-change-status-counts" aria-label={`${composerAdditions} additions and ${composerDeletions} deletions`}>
1772
+ {composerAdditions > 0 && <strong>+{composerAdditions}</strong>}
1773
+ {composerDeletions > 0 && <em>-{composerDeletions}</em>}
1545
1774
  </span>
1546
- <span>{workspaceName}</span>
1547
- <span aria-hidden="true">⌄</span>
1548
1775
  </button>
1549
1776
  )}
1550
- <div className="smart-context-bar">
1551
- <div className="smart-context-label" style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
1552
- <label className="toggle-switch">
1553
- <input type="checkbox" checked={smartContext} onChange={(event) => onSetSmartContext(event.target.checked)} />
1554
- <span className="slider round" />
1555
- </label>
1556
- <span>Smart Context (Auto-Screen)</span>
1777
+ {isEmptyChat && (
1778
+ <div className="empty-chat-prompt-wrap">
1779
+ <div className="empty-chat-prompt">Mint Agent is ready to work</div>
1780
+ {projectName && (
1781
+ <div className="empty-chat-project-badge">
1782
+ <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
1783
+ <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path>
1784
+ </svg>
1785
+ <span>Working in <strong>{projectName}</strong></span>
1786
+ </div>
1787
+ )}
1788
+ </div>
1789
+ )}
1790
+ {onSelectWorkspace && (
1791
+ <div className="project-context-row">
1792
+ <WorkspaceSelector
1793
+ currentPath={workspacePath || ''}
1794
+ recentPaths={recentWorkspacePaths}
1795
+ onSelectWorkspace={onSelectWorkspace}
1796
+ />
1797
+ {workspacePath && <GitBranchSelector workspacePath={workspacePath} disabled={sending} onBranchChanged={onWorkspaceChanged} />}
1557
1798
  </div>
1558
- <div className="smart-context-label" style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
1559
- <label className="toggle-switch">
1799
+ )}
1800
+ <div className="smart-context-bar">
1801
+ <label className={`smart-context-option ${agentMode ? 'is-active' : ''}`}>
1802
+ <span className="toggle-switch">
1560
1803
  <input type="checkbox" checked={agentMode} onChange={(event) => onSetAgentMode(event.target.checked)} />
1561
1804
  <span className="slider round" />
1562
- </label>
1563
- <span>Agent Mode</span>
1564
- </div>
1805
+ </span>
1806
+ <span className="smart-context-copy"><span className="smart-context-title">Agent mode</span></span>
1807
+ </label>
1565
1808
  {onSetPlanMode && (
1566
- <div className="smart-context-label" style={{ display: 'flex', alignItems: 'center', gap: '8px' }} title="Investigate read-only and require plan approval before editing files or running commands">
1567
- <label className="toggle-switch">
1809
+ <label className={`smart-context-option ${planMode ? 'is-active' : ''}`} title="Investigate read-only and require plan approval before editing files or running commands">
1810
+ <span className="toggle-switch">
1568
1811
  <input type="checkbox" checked={Boolean(planMode)} onChange={(event) => onSetPlanMode(event.target.checked)} />
1569
1812
  <span className="slider round" />
1570
- </label>
1571
- <span>Plan Mode</span>
1572
- </div>
1813
+ </span>
1814
+ <span className="smart-context-copy"><span className="smart-context-title">Plan mode</span></span>
1815
+ </label>
1573
1816
  )}
1574
1817
  </div>
1575
- {voiceMode && (
1576
- <div className="voice-mode-bar" data-state={voiceStatus}>
1577
- <span className="voice-mode-dot" />
1578
- {voiceTranscript ? (
1579
- voiceTranscript === 'Listening to microphone...' ||
1580
- voiceTranscript === 'Listening...' ||
1581
- voiceTranscript === 'No speech detected' ||
1582
- voiceTranscript === 'Sent audio to AI' ? (
1583
- <span>{voiceTranscript}</span>
1584
- ) : (
1585
- <span style={{ display: 'flex', alignItems: 'center', gap: '4px', minWidth: 0, overflow: 'hidden' }}>
1586
- <span>{voiceStatusLabel}:</span>
1587
- <span className="voice-mode-transcript">"{voiceTranscript}"</span>
1588
- </span>
1589
- )
1590
- ) : (
1591
- <span>{voiceStatusLabel}</span>
1592
- )}
1593
- </div>
1594
- )}
1595
-
1596
- <SlashSuggestions
1597
- ref={slashRef}
1598
- message={message}
1599
- onComplete={completeSuggestion}
1600
- workspacePath={workspacePath}
1601
- mcpServers={settingsConfig?.mcpServers}
1602
- anchorRef={textareaRef}
1603
- suppressed={historyIndex !== null}
1604
- />
1605
-
1606
1818
  <form
1607
1819
  id="chat-form"
1608
1820
  className={geminiLiveEnabled ? 'has-live-btn' : ''}
@@ -1623,6 +1835,14 @@ export default function ChatPanel({
1623
1835
  if (onPasteImage(event.clipboardData)) event.preventDefault()
1624
1836
  }}
1625
1837
  >
1838
+ {slashChoice && (
1839
+ <SlashChoicePanel
1840
+ choice={slashChoice}
1841
+ inputRef={textareaRef}
1842
+ onSelect={onSelectSlashChoice}
1843
+ onDismiss={onDismissSlashChoice}
1844
+ />
1845
+ )}
1626
1846
  {(imageAttachments.length > 0 || videoAttachments.length > 0 || documentName) && (
1627
1847
  <div className="mint-attachment">
1628
1848
  {imageAttachments.map((attachment, idx) => (
@@ -1694,10 +1914,15 @@ export default function ChatPanel({
1694
1914
  History {historyIndex + 1}/{promptHistory.length}
1695
1915
  </div>
1696
1916
  )}
1697
- <textarea
1917
+ <CollapsiblePasteInput
1698
1918
  id="chat-input"
1699
- ref={textareaRef}
1919
+ inputRef={textareaRef}
1700
1920
  value={message}
1921
+ onValueChange={(value) => {
1922
+ onSetMessage(value)
1923
+ if (historyIndex !== null) setHistoryIndex(null)
1924
+ }}
1925
+ onResizeInput={resizeInput}
1701
1926
  onChange={(event) => {
1702
1927
  resizeInput(event.currentTarget)
1703
1928
  onSetMessage(event.target.value)
@@ -1709,6 +1934,15 @@ export default function ChatPanel({
1709
1934
  placeholder="Ask anything, @ to mention, / for actions"
1710
1935
  rows={1}
1711
1936
  />
1937
+ <SlashSuggestions
1938
+ ref={slashRef}
1939
+ message={message}
1940
+ onComplete={completeSuggestion}
1941
+ workspacePath={workspacePath}
1942
+ mcpServers={settingsConfig?.mcpServers}
1943
+ anchorRef={textareaRef}
1944
+ suppressed={historyIndex !== null || Boolean(slashChoice)}
1945
+ />
1712
1946
  <div className="chat-tool-menu-wrap" ref={toolMenuRef}>
1713
1947
  <button id="chat-tool-btn" type="button" aria-haspopup="menu" aria-expanded={toolMenuOpen} onClick={() => setToolMenuOpen((open) => !open)} style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>
1714
1948
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
@@ -1779,7 +2013,10 @@ export default function ChatPanel({
1779
2013
  <input id="video-file-input" type="file" accept="video/mp4,video/webm,video/quicktime,video/x-matroska" onChange={onSelectVideo} style={{ display: 'none' }} />
1780
2014
  <input id="document-file-input" type="file" accept={SUPPORTED_DOCUMENT_ACCEPT} onChange={onSelectDocument} style={{ display: 'none' }} />
1781
2015
  <button id="screen-capture-btn" type="button" onClick={onCaptureScreen} aria-label="Capture screen">
1782
- <span className="screen-capture-eye" aria-hidden="true" />
2016
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
2017
+ <rect x="2" y="3" width="20" height="15" rx="2" />
2018
+ <path d="M8 22h8M12 18v4M7 10h10M12 5v10" />
2019
+ </svg>
1783
2020
  </button>
1784
2021
  <ModelSelectorPopover
1785
2022
  activeProvider={status?.activeProvider ?? ''}
@@ -1795,28 +2032,45 @@ export default function ChatPanel({
1795
2032
  onSetModel(model)
1796
2033
  }
1797
2034
  }}
2035
+ onUpdateSettings={onUpdateSettings}
2036
+ />
2037
+ <VoicePill
2038
+ id="voice-input-btn"
2039
+ className="composer-voice-pill"
2040
+ active={isRecording}
2041
+ disabled={sending || voiceAwaitingResponse || geminiLive.voiceMode}
2042
+ ariaLabel="Voice input"
2043
+ title={isRecording ? 'Stop recording · Esc or slide left to cancel' : 'Tap to dictate · hold to record'}
2044
+ accentColor="#f5f5f5"
2045
+ iconColor="#a1a1aa"
2046
+ background="#27272a"
2047
+ size={28}
2048
+ shape="pill"
2049
+ reach={8}
2050
+ mode="auto"
2051
+ holdAfter={300}
2052
+ reactive="simulated"
2053
+ showTime
2054
+ waveform
2055
+ slideToCancel
2056
+ cancelDistance={64}
2057
+ attack={40}
2058
+ release={240}
2059
+ openDuration={200}
2060
+ pressScale={0.95}
2061
+ onStart={() => {
2062
+ cancelSpeech()
2063
+ return startRecognition()
2064
+ }}
2065
+ onStop={({ reason }) => {
2066
+ cancelSpeech()
2067
+ if (reason === 'release' || reason === 'tap' || reason === 'key') {
2068
+ void stopRecognition()
2069
+ } else {
2070
+ void cancelRecognition()
2071
+ }
2072
+ }}
1798
2073
  />
1799
- <button
1800
- id="mic-btn"
1801
- className={`${isRecording ? 'is-recording' : ''} ${voiceMode ? 'voice-mode-active' : ''}`}
1802
- type="button"
1803
- onClick={toggleRecording}
1804
- title={voiceMode ? 'Disable voice conversation' : 'Enable voice conversation'}
1805
- style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}
1806
- >
1807
- {isRecording ? (
1808
- <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1809
- <rect x="4" y="4" width="16" height="16" rx="2" ry="2"></rect>
1810
- </svg>
1811
- ) : (
1812
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1813
- <path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"></path>
1814
- <path d="M19 10v2a7 7 0 0 1-14 0v-2"></path>
1815
- <line x1="12" y1="19" x2="12" y2="23"></line>
1816
- <line x1="8" y1="23" x2="16" y2="23"></line>
1817
- </svg>
1818
- )}
1819
- </button>
1820
2074
  {geminiLiveEnabled && (
1821
2075
  <button
1822
2076
  id="gemini-live-btn"
@@ -1856,6 +2110,9 @@ export default function ChatPanel({
1856
2110
  </button>
1857
2111
  )}
1858
2112
  </form>
2113
+ {voiceMode && !isRecording && voiceTranscript && (
2114
+ <p className="composer-voice-feedback" role="status">{voiceTranscript}</p>
2115
+ )}
1859
2116
  </div>
1860
2117
  <p className="input-disclaimer">
1861
2118
  Mint Agent is an AI gateway. Responses via third-party APIs. Verify critical info.
@@ -1863,7 +2120,11 @@ export default function ChatPanel({
1863
2120
  {geminiLive.voiceMode && (
1864
2121
  <GeminiLiveOverlay
1865
2122
  status={
1866
- geminiLive.isPaused
2123
+ geminiLive.errorMessage
2124
+ ? 'error'
2125
+ : !geminiLive.isRecording
2126
+ ? 'connecting'
2127
+ : geminiLive.isPaused
1867
2128
  ? 'paused'
1868
2129
  : geminiLive.isSpeaking
1869
2130
  ? 'speaking'
@@ -1874,6 +2135,7 @@ export default function ChatPanel({
1874
2135
  userTranscript={geminiLive.userTranscript}
1875
2136
  assistantTranscript={geminiLive.assistantTranscript}
1876
2137
  isPaused={geminiLive.isPaused}
2138
+ analyserRef={geminiLive.analyserRef}
1877
2139
  onTogglePause={geminiLive.togglePause}
1878
2140
  onEndCall={() => geminiLive.setVoiceMode(false)}
1879
2141
  voice={settingsConfig?.geminiLiveVoice || 'Puck'}
@@ -1941,19 +2203,13 @@ export default function ChatPanel({
1941
2203
  return (
1942
2204
  <div
1943
2205
  ref={wrapperRef}
1944
- className={`chat-panel-split-wrapper ${activeArtifact ? 'has-preview' : 'no-preview'}`}
2206
+ className={`chat-panel-split-wrapper ${activeArtifact || reviewPage ? 'has-preview' : 'no-preview'}`}
1945
2207
  style={{
1946
- width: '100%',
1947
- height: '100%',
1948
- overflow: 'hidden',
1949
- position: 'relative',
1950
- gridColumn: '1 / -1',
1951
- zIndex: 1,
1952
2208
  '--preview-width': `${(splitRatio * 100).toFixed(2)}%`,
1953
2209
  } as React.CSSProperties}
1954
2210
  >
1955
2211
  {sectionContent}
1956
- {activeArtifact && (
2212
+ {(activeArtifact || reviewPage) && (
1957
2213
  <>
1958
2214
  <div
1959
2215
  className="preview-split-resizer"
@@ -1963,11 +2219,16 @@ export default function ChatPanel({
1963
2219
  >
1964
2220
  <div className="preview-split-resizer-grip" />
1965
2221
  </div>
1966
- <ArtifactPreviewPanel
1967
- artifact={activeArtifact}
1968
- onClose={() => setActiveArtifact(null)}
1969
- workspacePath={workspacePath}
1970
- />
2222
+ {reviewPage ? (
2223
+ <CodeReviewPage
2224
+ title={reviewPage.title}
2225
+ changes={reviewPage.changes}
2226
+ workspacePath={workspacePath}
2227
+ onBack={() => setReviewPage(null)}
2228
+ />
2229
+ ) : activeArtifact ? (
2230
+ <ArtifactPreviewPanel artifact={activeArtifact} onClose={() => setActiveArtifact(null)} workspacePath={workspacePath} />
2231
+ ) : null}
1971
2232
  </>
1972
2233
  )}
1973
2234
  {rewindModalState.isOpen && (