@pheem49/mint 1.15.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 (644) hide show
  1. package/Cargo.lock +1012 -69
  2. package/Cargo.toml +5 -2
  3. package/LICENSE +21 -654
  4. package/README.md +92 -817
  5. package/Release_Note.md +53 -560
  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 +6 -0
  13. package/crates/mint-cli/src/agent/live_status.rs +187 -39
  14. package/crates/mint-cli/src/agent.rs +323 -95
  15. package/crates/mint-cli/src/commands/agent.rs +69 -55
  16. package/crates/mint-cli/src/commands/integrations.rs +7 -0
  17. package/crates/mint-cli/src/commands/knowledge.rs +12 -32
  18. package/crates/mint-cli/src/commands/mod.rs +44 -0
  19. package/crates/mint-cli/src/image.rs +31 -33
  20. package/crates/mint-cli/src/interactive/chat_tui.rs +3594 -483
  21. package/crates/mint-cli/src/interactive/input_box.rs +56 -6
  22. package/crates/mint-cli/src/interactive/slash_commands.rs +208 -56
  23. package/crates/mint-cli/src/interactive/tool_activity.rs +328 -0
  24. package/crates/mint-cli/src/interactive.rs +64 -40
  25. package/crates/mint-cli/src/main.rs +13 -7
  26. package/crates/mint-cli/src/mcp.rs +5 -0
  27. package/crates/mint-cli/src/mod_host.rs +6 -0
  28. package/crates/mint-cli/src/mods_cli.rs +62 -0
  29. package/crates/mint-cli/src/mods_ui.rs +187 -0
  30. package/crates/mint-cli/src/onboard.rs +5 -31
  31. package/crates/mint-cli/src/terminal_theme.rs +3 -1
  32. package/crates/mint-cli/src/updater.rs +56 -2
  33. package/crates/mint-cli/tests/library_intake.rs +77 -0
  34. package/crates/mint-cli/tests/mods_testing.rs +133 -0
  35. package/crates/mint-companion-protocol/Cargo.toml +10 -0
  36. package/crates/mint-companion-protocol/src/lib.rs +163 -0
  37. package/crates/mint-core/Cargo.toml +6 -3
  38. package/crates/mint-core/build.rs +26 -0
  39. package/crates/mint-core/src/agent/chat.rs +167 -39
  40. package/crates/mint-core/src/agent/code_tools.rs +15 -0
  41. package/crates/mint-core/src/agent/memory/sources.rs +240 -0
  42. package/crates/mint-core/src/agent/memory.rs +147 -13
  43. package/crates/mint-core/src/agent/skill_inventory.rs +325 -0
  44. package/crates/mint-core/src/agent/skills.rs +437 -90
  45. package/crates/mint-core/src/agent.rs +1 -0
  46. package/crates/mint-core/src/api_server/routes/background_jobs.rs +310 -0
  47. package/crates/mint-core/src/api_server/routes/chat.rs +216 -199
  48. package/crates/mint-core/src/api_server/routes/html_preview.rs +77 -0
  49. package/crates/mint-core/src/api_server/routes/library.rs +97 -0
  50. package/crates/mint-core/src/api_server/routes/media_gen.rs +10 -57
  51. package/crates/mint-core/src/api_server/routes/misc.rs +104 -107
  52. package/crates/mint-core/src/api_server/routes/mod.rs +6 -0
  53. package/crates/mint-core/src/api_server/routes/mods.rs +31 -0
  54. package/crates/mint-core/src/api_server/routes/sessions.rs +41 -0
  55. package/crates/mint-core/src/api_server/routes/skills_subagents.rs +12 -42
  56. package/crates/mint-core/src/api_server/routes/slash.rs +50 -1
  57. package/crates/mint-core/src/api_server/routes/sources.rs +101 -0
  58. package/crates/mint-core/src/api_server.rs +118 -9
  59. package/crates/mint-core/src/avatar_bridge.rs +11 -2
  60. package/crates/mint-core/src/browser/session.rs +52 -0
  61. package/crates/mint-core/src/companion.rs +716 -0
  62. package/crates/mint-core/src/cron/scheduler.rs +34 -2
  63. package/crates/mint-core/src/integrations/channels.rs +87 -345
  64. package/crates/mint-core/src/integrations/mcp.rs +397 -50
  65. package/crates/mint-core/src/integrations/mcp_calls.rs +823 -0
  66. package/crates/mint-core/src/integrations/mcp_catalog.rs +267 -0
  67. package/crates/mint-core/src/integrations/mcp_device.rs +319 -0
  68. package/crates/mint-core/src/integrations/mcp_result.rs +356 -0
  69. package/crates/mint-core/src/integrations/webhooks.rs +539 -0
  70. package/crates/mint-core/src/integrations.rs +2 -0
  71. package/crates/mint-core/src/lib.rs +85 -26
  72. package/crates/mint-core/src/media/gemini_live.rs +134 -14
  73. package/crates/mint-core/src/media/image_models.rs +3 -27
  74. package/crates/mint-core/src/media/image_workflow.rs +216 -0
  75. package/crates/mint-core/src/media/library/intake.rs +144 -0
  76. package/crates/mint-core/src/media/library/migration.rs +56 -0
  77. package/crates/mint-core/src/media/library/removal.rs +55 -0
  78. package/crates/mint-core/src/media/library/tests.rs +730 -0
  79. package/crates/mint-core/src/media/library/thumbnails.rs +72 -0
  80. package/crates/mint-core/src/media/library.rs +545 -0
  81. package/crates/mint-core/src/media/model_catalog.rs +375 -0
  82. package/crates/mint-core/src/media/pictures.rs +79 -222
  83. package/crates/mint-core/src/media/video_models.rs +3 -22
  84. package/crates/mint-core/src/media.rs +3 -0
  85. package/crates/mint-core/src/mods/manager.rs +1124 -0
  86. package/crates/mint-core/src/mods/mod.rs +569 -0
  87. package/crates/mint-core/src/mods/operations.rs +204 -0
  88. package/crates/mint-core/src/mods/session.rs +146 -0
  89. package/crates/mint-core/src/mods/slash.rs +59 -0
  90. package/crates/mint-core/src/mods/telemetry.rs +306 -0
  91. package/crates/mint-core/src/orchestration/approvals.rs +344 -0
  92. package/crates/mint-core/src/orchestration/context_render.rs +104 -0
  93. package/crates/mint-core/src/orchestration/mcp_review.rs +153 -0
  94. package/crates/mint-core/src/orchestration/memory_skill.rs +104 -32
  95. package/crates/mint-core/src/orchestration/mod.rs +2139 -244
  96. package/crates/mint-core/src/orchestration/mod_authoring_regressions.rs +209 -0
  97. package/crates/mint-core/src/orchestration/progress_clock.rs +80 -0
  98. package/crates/mint-core/src/orchestration/repeated_failures.rs +116 -0
  99. package/crates/mint-core/src/orchestration/review_regressions.rs +449 -0
  100. package/crates/mint-core/src/orchestration/run_control.rs +196 -0
  101. package/crates/mint-core/src/orchestration/tools/files.rs +161 -14
  102. package/crates/mint-core/src/orchestration/tools/media.rs +37 -41
  103. package/crates/mint-core/src/orchestration/tools/misc.rs +3 -2
  104. package/crates/mint-core/src/orchestration/tools/mod.rs +2 -0
  105. package/crates/mint-core/src/orchestration/tools/mods.rs +161 -0
  106. package/crates/mint-core/src/orchestration/tools/plugins_mcp.rs +303 -71
  107. package/crates/mint-core/src/orchestration/tools/shell.rs +95 -2
  108. package/crates/mint-core/src/orchestration/workspace_helpers.rs +4 -1
  109. package/crates/mint-core/src/prompts/agent.rs +17 -2
  110. package/crates/mint-core/src/prompts/tool_catalog.rs +28 -2
  111. package/crates/mint-core/src/search/knowledge.rs +7 -1
  112. package/crates/mint-core/src/search/linked_folders/index.rs +177 -13
  113. package/crates/mint-core/src/search/linked_folders.rs +83 -2
  114. package/crates/mint-core/src/slash/catalog.rs +1 -1
  115. package/crates/mint-core/src/slash/mod.rs +174 -11
  116. package/crates/mint-core/src/slash/mods.rs +155 -0
  117. package/crates/mint-core/src/system/bg_shell.rs +1129 -95
  118. package/crates/mint-core/src/system/config.rs +5 -10
  119. package/crates/mint-core/src/system/html_preview.rs +398 -0
  120. package/crates/mint-core/src/system/mint_web.rs +164 -0
  121. package/crates/mint-core/src/system/release_notes.rs +18 -0
  122. package/crates/mint-core/src/system/shell.rs +21 -6
  123. package/crates/mint-core/src/system/workspace.rs +72 -8
  124. package/crates/mint-core/src/system/workspace_history.rs +604 -0
  125. package/crates/mint-core/src/system.rs +4 -0
  126. package/crates/mint-core/tests/background_retention.rs +34 -0
  127. package/crates/mint-core/tests/background_shutdown.rs +24 -0
  128. package/crates/mint-core/tests/library_http.rs +209 -0
  129. package/crates/mint-core/tests/mcp_contract.rs +283 -0
  130. package/crates/mint-core/tests/mcp_stdio.rs +11 -10
  131. package/crates/mint-core/tests/media_model_catalog_http.rs +403 -0
  132. package/crates/mint-core/tests/mods_http.rs +215 -0
  133. package/crates/mint-core/tests/terminal_shutdown.rs +109 -0
  134. package/crates/mint-mod-runtime/Cargo.toml +18 -0
  135. package/crates/mint-mod-runtime/src/lib.rs +507 -0
  136. package/crates/mint-mod-runtime/src/sdk.js +56 -0
  137. package/crates/mint-mod-runtime/src/test_sdk.js +32 -0
  138. package/crates/mint-mod-runtime/src/testing.rs +94 -0
  139. package/crates/mint-mod-runtime/tests/runtime.rs +156 -0
  140. package/docs/mods/AUTHORING.md +61 -0
  141. package/docs/mods/README.md +139 -0
  142. package/docs/mods/TESTING.md +56 -0
  143. package/docs/mods/mint-mods.d.ts +66 -0
  144. package/examples/device-mcp/README.md +22 -0
  145. package/examples/device-mcp/contract.md +49 -0
  146. package/examples/device-mcp/mock-device.mjs +66 -0
  147. package/examples/device-mcp/server.mjs +48 -0
  148. package/examples/device-mcp/server.test.mjs +78 -0
  149. package/examples/mods/task-checklist/README.md +1 -0
  150. package/examples/mods/task-checklist/main.ts +17 -0
  151. package/examples/mods/task-checklist/manifest.json +1 -0
  152. package/examples/mods/task-checklist/tests/checklist.test.ts +15 -0
  153. package/examples/mods/token-meter/README.md +1 -0
  154. package/examples/mods/token-meter/main.ts +8 -0
  155. package/examples/mods/token-meter/manifest.json +1 -0
  156. package/examples/mods/tool-guard/README.md +1 -0
  157. package/examples/mods/tool-guard/main.ts +9 -0
  158. package/examples/mods/tool-guard/manifest.json +1 -0
  159. package/out/web/assets/CliSessionsView-CtzUJpK_.css +1 -0
  160. package/out/web/assets/CliSessionsView-D7hw0Mgj.js +1 -0
  161. package/out/web/assets/CodeReviewPage-C7bEOJfd.js +4 -0
  162. package/out/web/assets/CodeReviewPage-Dte9uLiL.css +1 -0
  163. package/out/web/assets/CommandPalette-0RrF-AOT.js +1 -0
  164. package/out/web/assets/ImageStudioPanel-CdxkAf_r.js +1 -0
  165. package/out/web/assets/LibraryPage--Qfisp6D.js +2 -0
  166. package/out/web/assets/LibraryPage-DAxUTAg7.css +1 -0
  167. package/out/web/assets/LinkedFoldersView-2nfZbDgN.js +1 -0
  168. package/out/web/assets/McpRegistryPicker-h9uS8_wT.js +1 -0
  169. package/out/web/assets/McpServersView-slfQJzNB.js +1 -0
  170. package/out/web/assets/MintDashboard-BSR5XpXh.js +25 -0
  171. package/out/web/assets/MintDashboard-CWUcCGhd.css +1 -0
  172. package/out/web/assets/PluginsView-l7LSm503.js +1 -0
  173. package/out/web/assets/ScheduledTasksView-CttmLbq1.js +1 -0
  174. package/out/web/assets/SettingsWindow-BCMLYvEV.js +4 -0
  175. package/out/web/assets/SettingsWindow-DcMVmU9u.css +1 -0
  176. package/out/web/assets/SkillsView-rNs1qr_U.js +2 -0
  177. package/out/web/assets/ToolSurfacePage-B9DzEPWN.js +37 -0
  178. package/out/web/assets/ToolSurfacePage-CTfgggF2.css +1 -0
  179. package/out/web/assets/VeoStudioPanel-DiJs_Cg2.js +4 -0
  180. package/out/web/assets/WorkspaceSelector-B2xIp04D.js +1 -0
  181. package/out/web/assets/WorkspaceSelector-Ca8uJOsS.css +1 -0
  182. package/out/web/assets/{abnfDiagram-VCTEODGH-ByMyfanq.js → abnfDiagram-VCTEODGH-CD0CjoGl.js} +1 -1
  183. package/out/web/assets/{architecture-7GRP2DOG-CLq2kEOB.js → architecture-7GRP2DOG-RKV83OeZ.js} +1 -1
  184. package/out/web/assets/{architectureDiagram-5GKGNRK7-6PoVSmNG.js → architectureDiagram-5GKGNRK7-nN_HAFct.js} +1 -1
  185. package/out/web/assets/{blockDiagram-NRAW4CY4-cKw9mAKi.js → blockDiagram-NRAW4CY4-BrrqzHW5.js} +1 -1
  186. package/out/web/assets/{c4Diagram-UCG6FXSJ-Cqy8N5Ge.js → c4Diagram-UCG6FXSJ-DTdV8_zE.js} +1 -1
  187. package/out/web/assets/{chunk-75Z2AOVW-3qybijF5.js → chunk-75Z2AOVW-_M0z5olV.js} +1 -1
  188. package/out/web/assets/chunk-CKBBP62Z-BpQEgeHF.js +2 -0
  189. package/out/web/assets/{chunk-CLGD4ZFX-CndDQkww.js → chunk-CLGD4ZFX-D54yGvGS.js} +1 -1
  190. package/out/web/assets/{chunk-DSNCTWBM-Cc4NxvgD.js → chunk-DSNCTWBM-C-gvT2ru.js} +1 -1
  191. package/out/web/assets/{chunk-DU6HZSFF-drzh6GsU.js → chunk-DU6HZSFF-CnFngIhW.js} +1 -1
  192. package/out/web/assets/{chunk-F27PBJKO-FiY35l4v.js → chunk-F27PBJKO-BqtWrnEO.js} +1 -1
  193. package/out/web/assets/{chunk-G27WJ6UU-Bjt9Il4A.js → chunk-G27WJ6UU-Ckoq5mi2.js} +1 -1
  194. package/out/web/assets/{chunk-GMAD6QVW-Bppi3Ctd.js → chunk-GMAD6QVW-BuhEcgHq.js} +1 -1
  195. package/out/web/assets/{chunk-JQ64N6SF-DGg5kcEV.js → chunk-JQ64N6SF-CF8T7GiZ.js} +1 -1
  196. package/out/web/assets/{chunk-LCL6LL3I-CCYcjd7p.js → chunk-LCL6LL3I-BhXV9zyH.js} +1 -1
  197. package/out/web/assets/{chunk-OBVCFTLP-DJeNil5M.js → chunk-OBVCFTLP-CRIkunUB.js} +1 -1
  198. package/out/web/assets/{chunk-P2QGCYS3-lRzkRjBB.js → chunk-P2QGCYS3-UFEU6BxZ.js} +1 -1
  199. package/out/web/assets/{chunk-POPQ4Y6H-DouASMBW.js → chunk-POPQ4Y6H-CQcrNbjr.js} +1 -1
  200. package/out/web/assets/{chunk-PWAF6VOD-DMmD1vVf.js → chunk-PWAF6VOD-Cc2uVDsG.js} +1 -1
  201. package/out/web/assets/{chunk-R7TYR2AO-CYLA5UC5.js → chunk-R7TYR2AO-DiCxzdAY.js} +1 -1
  202. package/out/web/assets/{chunk-RHFEMEQ7-BiXwEcUT.js → chunk-RHFEMEQ7-b7hnPmrR.js} +1 -1
  203. package/out/web/assets/{chunk-SVP7TREG-BV-zPslF.js → chunk-SVP7TREG-Bu_yYb-V.js} +1 -1
  204. package/out/web/assets/{chunk-TEH6E4GO-B2RGEohZ.js → chunk-TEH6E4GO-G4Cdlyrt.js} +1 -1
  205. package/out/web/assets/classDiagram-DTDB5LWJ-RnC2mYO4.js +1 -0
  206. package/out/web/assets/classDiagram-v2-JRS7N3AN-RnC2mYO4.js +1 -0
  207. package/out/web/assets/config-CnvCChUM.js +2 -0
  208. package/out/web/assets/config-DM6oIVO3.css +1 -0
  209. package/out/web/assets/core-DsKkQ7ig.js +1 -0
  210. package/out/web/assets/{cynefin-OW5HDTMX-Cas4csHM.js → cynefin-OW5HDTMX-CnzQfOGp.js} +1 -1
  211. package/out/web/assets/{cynefinDiagram-5FMLGOSQ-Bbpj66Y3.js → cynefinDiagram-5FMLGOSQ-DVtQnfpm.js} +1 -1
  212. package/out/web/assets/{dagre-3AP2YEHR-B0-2RDEd.js → dagre-3AP2YEHR-DG76_k5_.js} +1 -1
  213. package/out/web/assets/{diagram-S7CK7UJ4-BdzEjUyH.js → diagram-S7CK7UJ4-CaouUoze.js} +1 -1
  214. package/out/web/assets/{diagram-UQ7AKVKN-CJDwyPxF.js → diagram-UQ7AKVKN-B4bEc26B.js} +1 -1
  215. package/out/web/assets/{diagram-VSXAHHWV-BxaG1r_B.js → diagram-VSXAHHWV-BJ86Ov2Y.js} +1 -1
  216. package/out/web/assets/{diagram-VX7I27RA-BMmUqm8f.js → diagram-VX7I27RA-7hH5IPYf.js} +1 -1
  217. package/out/web/assets/{diagram-Z3DM3KII-CFtd03eE.js → diagram-Z3DM3KII-CCM4clo8.js} +1 -1
  218. package/out/web/assets/dist-js-BkYNznHX.js +1 -0
  219. package/out/web/assets/{ebnfDiagram-PWID7BFC-DwAen1hO.js → ebnfDiagram-PWID7BFC-Da7WAM3k.js} +1 -1
  220. package/out/web/assets/{erDiagram-SSCWMZ5O-BCZSHACj.js → erDiagram-SSCWMZ5O-CzzmnZWT.js} +1 -1
  221. package/out/web/assets/{event-ChBVpRy0.js → event-Cdt7Byyj.js} +1 -1
  222. package/out/web/assets/{eventmodeling-NTZA5JFV-XHStE4E_.js → eventmodeling-NTZA5JFV-xcfsA0XD.js} +1 -1
  223. package/out/web/assets/flowDiagram-A5DVABFB-JdtH1673.js +1 -0
  224. package/out/web/assets/{ganttDiagram-EL5Y4UJY-BAEu1Cql.js → ganttDiagram-EL5Y4UJY-B3ClFGmL.js} +1 -1
  225. package/out/web/assets/{gitGraph-4MIJSDKK-r32Vyper.js → gitGraph-4MIJSDKK-BZ_y_cDU.js} +1 -1
  226. package/out/web/assets/{gitGraphDiagram-WWUBYQGX-z9o9qt6V.js → gitGraphDiagram-WWUBYQGX-drhRSYm3.js} +1 -1
  227. package/out/web/assets/index-BZ9xgmMP.css +1 -0
  228. package/out/web/assets/index-Ca8cCS4h.js +168 -0
  229. package/out/web/assets/{info-A6RAGUB7-BvLaC2cw.js → info-A6RAGUB7-B7I3K0F1.js} +1 -1
  230. package/out/web/assets/{infoDiagram-RXCK75RN-Be6WAXXw.js → infoDiagram-RXCK75RN-deX_1MPh.js} +1 -1
  231. package/out/web/assets/{ishikawaDiagram-5VMMS53U-DZjoHJHC.js → ishikawaDiagram-5VMMS53U-s38yo28y.js} +1 -1
  232. package/out/web/assets/{journeyDiagram-EYS64GPL-CtVkjkGm.js → journeyDiagram-EYS64GPL-CZn2kB8b.js} +1 -1
  233. package/out/web/assets/jsx-runtime-DN4NhQUK.js +1 -0
  234. package/out/web/assets/{kanban-definition-3QL26DDD-CW5FMv1w.js → kanban-definition-3QL26DDD-DodjgySL.js} +1 -1
  235. package/out/web/assets/markdown-CMhYIcWB.js +39 -0
  236. package/out/web/assets/{mermaid-parser.core-aUgCqsZ5.js → mermaid-parser.core-Whu2rlJC.js} +3 -3
  237. package/out/web/assets/{mermaid.core-D57sEiSL.js → mermaid.core-CKyPo8VH.js} +4 -4
  238. package/out/web/assets/{mindmap-definition-FBJOCRG2-DAmSpM3a.js → mindmap-definition-FBJOCRG2-260WBDxZ.js} +1 -1
  239. package/out/web/assets/modelManager-CUaGWMWu.js +2 -0
  240. package/out/web/assets/{oauthManager-9jxicDWJ.js → oauthManager-DlNhXJr6.js} +1 -1
  241. package/out/web/assets/{packet-AYTQ26CC-DJ27iIoJ.js → packet-AYTQ26CC-CEeIRKRG.js} +1 -1
  242. package/out/web/assets/{pegDiagram-XKGWAZYB-Bj3ii-gS.js → pegDiagram-XKGWAZYB-BYadI-KO.js} +1 -1
  243. package/out/web/assets/{pie-WAS4IAKB-DG5mCUbc.js → pie-WAS4IAKB-D8uf4dh5.js} +1 -1
  244. package/out/web/assets/{pieDiagram-E7YTZNPT-BrJLPnDA.js → pieDiagram-E7YTZNPT-CjSDy4hO.js} +1 -1
  245. package/out/web/assets/{quadrantDiagram-AXDQQJYC-3x_TmF3j.js → quadrantDiagram-AXDQQJYC-B8D3gU5d.js} +1 -1
  246. package/out/web/assets/{radar-RG4KPBEZ-CrXaTTuV.js → radar-RG4KPBEZ-DZJxnokY.js} +1 -1
  247. package/out/web/assets/{railroad-74A4TZTK-BpqMH9BE.js → railroad-74A4TZTK-DBysUiUi.js} +1 -1
  248. package/out/web/assets/{railroad-abnf-HS5TGJTU-DHI0uLlV.js → railroad-abnf-HS5TGJTU-CHWxoJYg.js} +1 -1
  249. package/out/web/assets/{railroad-ebnf-LZEXJU2U-CQCb316y.js → railroad-ebnf-LZEXJU2U-DDv7X6bY.js} +1 -1
  250. package/out/web/assets/{railroad-peg-WCYAUIDC-Ph1giKkH.js → railroad-peg-WCYAUIDC-DpfcYYNJ.js} +1 -1
  251. package/out/web/assets/{railroadDiagram-O6MQD6OU-BRq6wIxx.js → railroadDiagram-O6MQD6OU-CYtyv0t3.js} +1 -1
  252. package/out/web/assets/{requirementDiagram-EFPCY7ZU-DIJj6G1g.js → requirementDiagram-EFPCY7ZU-D2X-Ewik.js} +1 -1
  253. package/out/web/assets/{sankeyDiagram-P5KCCOFB-DZajSryq.js → sankeyDiagram-P5KCCOFB-Bn2x6C4Y.js} +1 -1
  254. package/out/web/assets/{sequenceDiagram-WJ2MYXX4-DxJCWyZS.js → sequenceDiagram-WJ2MYXX4-BvFLKtPd.js} +1 -1
  255. package/out/web/assets/{stateDiagram-HBIQ2CUA-k6voi8Vf.js → stateDiagram-HBIQ2CUA-Bx0GWeaY.js} +1 -1
  256. package/out/web/assets/stateDiagram-v2-4QOOHH4V--hol1yg_.js +1 -0
  257. package/out/web/assets/{swimlanes-XN3QIQJK-igYhTjXB.js → swimlanes-XN3QIQJK-CCma0T7L.js} +1 -1
  258. package/out/web/assets/swimlanesDiagram-VK2B7HYN-BkohoVsU.js +8 -0
  259. package/out/web/assets/{timeline-definition-24CTP7MA-Dke2p93p.js → timeline-definition-24CTP7MA-iCRhhJ7C.js} +1 -1
  260. package/out/web/assets/{treeView-Q6P3EWNA-hNELnXUs.js → treeView-Q6P3EWNA-DZ-y08qp.js} +1 -1
  261. package/out/web/assets/{treemap-WGGIJYW6-D2B6wDsx.js → treemap-WGGIJYW6-De0CxzMx.js} +1 -1
  262. package/out/web/assets/{vennDiagram-4TSXK5OY-CDkW7rUP.js → vennDiagram-4TSXK5OY-w_7aZ6xe.js} +1 -1
  263. package/out/web/assets/{wardley-WFR3VGLG-BECdXETi.js → wardley-WFR3VGLG-DT0y0xJ4.js} +1 -1
  264. package/out/web/assets/{wardleyDiagram-VM6X3IG4-B5BycpQ4.js → wardleyDiagram-VM6X3IG4-DAdXELbQ.js} +1 -1
  265. package/out/web/assets/window-BJCVtyET.js +1 -0
  266. package/out/web/assets/{xychartDiagram-S5SC5T6Z-CtJS3b--.js → xychartDiagram-S5SC5T6Z-IZIXf3Vo.js} +1 -1
  267. package/out/web/index-web.html +3 -2
  268. package/out/web/index.html +3 -2
  269. package/package.json +71 -22
  270. package/shared-modules/.github/workflows/ci.yml +120 -0
  271. package/shared-modules/.github/workflows/update.yaml +28 -0
  272. package/slash-commands.json +7 -2
  273. package/src/bin/auto-build.js +66 -0
  274. package/src/bin/desktop.js +113 -0
  275. package/src/bin/desktop.test.js +113 -0
  276. package/src/bin/index.js +18 -25
  277. package/src/bin/index.test.js +89 -0
  278. package/src/bin/measure-effects.mjs +53 -0
  279. package/src/bin/package.test.js +28 -0
  280. package/src/bin/release-notes.test.js +84 -0
  281. package/src/bin/styles.test.js +20 -0
  282. package/src/bin/web.js +5 -0
  283. package/src/bin/web.test.js +39 -0
  284. package/src/renderer/index.html +0 -2
  285. package/src/renderer/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  286. package/src/renderer/shared/agentProgress.ts +33 -0
  287. package/src/renderer/shared/components/AgentActivityDrawer.tsx +3 -2
  288. package/src/renderer/shared/components/AgentActivityTable.tsx +1 -1
  289. package/src/renderer/shared/components/ApprovalCard.test.tsx +24 -0
  290. package/src/renderer/shared/components/ApprovalCard.tsx +10 -3
  291. package/src/renderer/shared/components/ArtifactPreviewPanel.tsx +88 -37
  292. package/src/renderer/shared/components/AuthGate.tsx +75 -39
  293. package/src/renderer/shared/components/BackgroundTerminals.tsx +181 -0
  294. package/src/renderer/shared/components/ChatCodeBlock.tsx +8 -4
  295. package/src/renderer/shared/components/ChatMessageItem.test.tsx +68 -0
  296. package/src/renderer/shared/components/ChatMessageItem.tsx +36 -16
  297. package/src/renderer/shared/components/ChatPanel.test.tsx +21 -0
  298. package/src/renderer/shared/components/ChatPanel.tsx +294 -272
  299. package/src/renderer/shared/components/ChunkErrorBoundary.tsx +4 -102
  300. package/src/renderer/shared/components/CliSessionsView.test.tsx +125 -0
  301. package/src/renderer/shared/components/CliSessionsView.tsx +61 -13
  302. package/src/renderer/shared/components/CodeReviewPage.tsx +111 -8
  303. package/src/renderer/shared/components/CollapsiblePasteInput.tsx +90 -0
  304. package/src/renderer/shared/components/ContextCompactionStatus.tsx +17 -0
  305. package/src/renderer/shared/components/DashboardSidebar.tsx +15 -128
  306. package/src/renderer/shared/components/DesktopTitlebar.tsx +45 -19
  307. package/src/renderer/shared/components/ErrorNotice.tsx +29 -0
  308. package/src/renderer/shared/components/FormattedMessage.tsx +11 -0
  309. package/src/renderer/shared/components/GeminiLiveOverlay.css +86 -0
  310. package/src/renderer/shared/components/GeminiLiveOverlay.test.tsx +24 -0
  311. package/src/renderer/shared/components/GeminiLiveOverlay.tsx +85 -101
  312. package/src/renderer/shared/components/GlideSelect.css +138 -0
  313. package/src/renderer/shared/components/GlideSelect.d.ts +31 -0
  314. package/src/renderer/shared/components/GlideSelect.jsx +266 -0
  315. package/src/renderer/shared/components/ImageSearchCard.tsx +46 -56
  316. package/src/renderer/shared/components/ImageStudioPanel.tsx +9 -8
  317. package/src/renderer/shared/components/LibraryItemCard.tsx +72 -0
  318. package/src/renderer/shared/components/LibraryPage.tsx +165 -0
  319. package/src/renderer/shared/components/LibraryPreview.tsx +59 -0
  320. package/src/renderer/shared/components/McpServersView.tsx +27 -8
  321. package/src/renderer/shared/components/McpToolAllowlist.tsx +2 -4
  322. package/src/renderer/shared/components/McpToolResults.tsx +99 -0
  323. package/src/renderer/shared/components/MintDashboard.tsx +308 -770
  324. package/src/renderer/shared/components/ModSessionControls.tsx +8 -0
  325. package/src/renderer/shared/components/ModUi.test.tsx +65 -0
  326. package/src/renderer/shared/components/ModUi.tsx +26 -0
  327. package/src/renderer/shared/components/ModelSelectorPopover.tsx +14 -7
  328. package/src/renderer/shared/components/ModsPanel.tsx +156 -0
  329. package/src/renderer/shared/components/ProgressActivity.tsx +17 -0
  330. package/src/renderer/shared/components/ReviewHistory.tsx +42 -0
  331. package/src/renderer/shared/components/RewindModal.tsx +5 -12
  332. package/src/renderer/shared/components/RunSummaryDashboard.tsx +6 -12
  333. package/src/renderer/shared/components/ScheduledTasksView.tsx +7 -6
  334. package/src/renderer/shared/components/SelectField.test.tsx +27 -0
  335. package/src/renderer/shared/components/SelectField.tsx +38 -0
  336. package/src/renderer/shared/components/SessionSources.tsx +48 -0
  337. package/src/renderer/shared/components/SessionSourcesPopover.tsx +61 -0
  338. package/src/renderer/shared/components/Settings/AgentsTab.tsx +7 -6
  339. package/src/renderer/shared/components/Settings/AudioTab.tsx +8 -7
  340. package/src/renderer/shared/components/Settings/AutomationTab.tsx +2 -2
  341. package/src/renderer/shared/components/Settings/GeneralTab.tsx +33 -32
  342. package/src/renderer/shared/components/Settings/MemoryTab.test.tsx +37 -0
  343. package/src/renderer/shared/components/Settings/MemoryTab.tsx +71 -31
  344. package/src/renderer/shared/components/Settings/NotificationsTab.test.tsx +15 -0
  345. package/src/renderer/shared/components/Settings/NotificationsTab.tsx +84 -0
  346. package/src/renderer/shared/components/Settings/ThemeTab.tsx +19 -11
  347. package/src/renderer/shared/components/SlashChoicePanel.tsx +88 -0
  348. package/src/renderer/shared/components/SlashSuggestions.test.tsx +33 -0
  349. package/src/renderer/shared/components/SlashSuggestions.tsx +38 -10
  350. package/src/renderer/shared/components/SourcesBlock.tsx +12 -20
  351. package/src/renderer/shared/components/ToolSurfacePage.test.tsx +32 -0
  352. package/src/renderer/shared/components/ToolSurfacePage.tsx +59 -11
  353. package/src/renderer/shared/components/ToolsPanelToggle.tsx +13 -0
  354. package/src/renderer/shared/components/VeoStudioPanel.tsx +9 -8
  355. package/src/renderer/shared/components/ViewedImages.tsx +36 -0
  356. package/src/renderer/shared/components/VirtualChatHistory.tsx +82 -0
  357. package/src/renderer/shared/components/VoicePill.css +85 -0
  358. package/src/renderer/shared/components/VoicePill.d.ts +12 -0
  359. package/src/renderer/shared/components/VoicePill.jsx +190 -0
  360. package/src/renderer/shared/components/VoicePill.test.tsx +22 -0
  361. package/src/renderer/shared/components/WorkspaceContextPopover.tsx +20 -15
  362. package/src/renderer/shared/components/WorkspacePaneResizer.tsx +92 -0
  363. package/src/renderer/shared/components/WorkspacePreviewActions.test.tsx +44 -0
  364. package/src/renderer/shared/components/WorkspacePreviewActions.tsx +19 -0
  365. package/src/renderer/shared/components/WorkspaceSelector.tsx +13 -8
  366. package/src/renderer/shared/components/background-terminals.css +292 -0
  367. package/src/renderer/shared/components/ui/README.md +52 -0
  368. package/src/renderer/shared/components/ui/button.tsx +37 -0
  369. package/src/renderer/shared/components/ui/demo.tsx +26 -0
  370. package/src/renderer/shared/components/ui/error-recovery.css +35 -0
  371. package/src/renderer/shared/components/ui/error-recovery.tsx +35 -0
  372. package/src/renderer/shared/components/ui/voice-powered-orb.css +6 -0
  373. package/src/renderer/shared/components/ui/voice-powered-orb.tsx +374 -0
  374. package/src/renderer/shared/components/workspace-selector.css +248 -0
  375. package/src/renderer/shared/constants/config.ts +30 -1
  376. package/src/renderer/shared/constants/slashCommands.ts +1 -1
  377. package/src/renderer/shared/conversation/lifecycle.test.ts +362 -0
  378. package/src/renderer/shared/conversation/lifecycle.ts +418 -0
  379. package/src/renderer/shared/conversation/projectNavigation.test.ts +105 -0
  380. package/src/renderer/shared/conversation/projectNavigation.ts +39 -0
  381. package/src/renderer/shared/conversation/sourcesTransport.ts +27 -0
  382. package/src/renderer/shared/conversation/syncView.test.ts +1 -34
  383. package/src/renderer/shared/conversation/syncView.ts +0 -37
  384. package/src/renderer/shared/conversation/transport.test.ts +163 -0
  385. package/src/renderer/shared/conversation/transport.ts +159 -0
  386. package/src/renderer/shared/conversation/useConversationCoordinator.ts +30 -72
  387. package/src/renderer/shared/css/agent-observability.css +20 -21
  388. package/src/renderer/shared/css/auth-gate.css +112 -13
  389. package/src/renderer/shared/css/code-review.css +33 -0
  390. package/src/renderer/shared/css/code-sessions.css +27 -0
  391. package/src/renderer/shared/css/collapsed-paste.css +35 -0
  392. package/src/renderer/shared/css/effects.css +15 -0
  393. package/src/renderer/shared/css/error-notice.css +60 -0
  394. package/src/renderer/shared/css/library.css +476 -0
  395. package/src/renderer/shared/css/management-views.css +138 -0
  396. package/src/renderer/shared/css/mcp-results.css +11 -0
  397. package/src/renderer/shared/css/model-selector.css +163 -105
  398. package/src/renderer/shared/css/mods.css +77 -0
  399. package/src/renderer/shared/css/notification-notice.css +28 -0
  400. package/src/renderer/shared/css/session-sources-popover.css +9 -0
  401. package/src/renderer/shared/css/session-sources.css +23 -0
  402. package/src/renderer/shared/css/settings/memory.css +154 -0
  403. package/src/renderer/shared/css/settings/notifications.css +11 -0
  404. package/src/renderer/shared/css/settings/theme.css +5 -0
  405. package/src/renderer/shared/css/slash-choice.css +95 -0
  406. package/src/renderer/shared/css/slash-suggestions.css +68 -0
  407. package/src/renderer/shared/css/sources-block.css +91 -0
  408. package/src/renderer/shared/css/thinking-status.css +46 -0
  409. package/src/renderer/shared/css/tools-panel.css +7 -0
  410. package/src/renderer/shared/css/ui-tailwind.css +19 -0
  411. package/src/renderer/shared/css/viewed-images.css +15 -0
  412. package/src/renderer/shared/fonts.css +46 -0
  413. package/src/renderer/shared/fonts.ts +3 -12
  414. package/src/renderer/shared/lib/utils.ts +6 -0
  415. package/src/renderer/shared/library/controller.test.ts +61 -0
  416. package/src/renderer/shared/library/controller.ts +57 -0
  417. package/src/renderer/shared/library/transport.test.ts +26 -0
  418. package/src/renderer/shared/library/transport.ts +60 -0
  419. package/src/renderer/shared/library/useLibraryFile.ts +38 -0
  420. package/src/renderer/shared/mods.ts +58 -0
  421. package/src/renderer/shared/platform.test.ts +57 -1
  422. package/src/renderer/shared/platform.ts +46 -1
  423. package/src/renderer/shared/theme/themeManager.test.ts +43 -0
  424. package/src/renderer/shared/theme/themeManager.ts +17 -4
  425. package/src/renderer/shared/types.ts +56 -2
  426. package/src/renderer/shared/utils/agentActivity.test.ts +75 -0
  427. package/src/renderer/shared/utils/agentActivity.ts +42 -3
  428. package/src/renderer/shared/utils/approval.tsx +7 -0
  429. package/src/renderer/shared/utils/artifactBrowser.test.ts +80 -0
  430. package/src/renderer/shared/utils/artifactBrowser.ts +41 -0
  431. package/src/renderer/shared/utils/contextCompaction.test.tsx +48 -0
  432. package/src/renderer/shared/utils/contextCompaction.ts +21 -0
  433. package/src/renderer/shared/utils/effectVisibility.ts +9 -0
  434. package/src/renderer/shared/utils/markdown.tsx +3 -3
  435. package/src/renderer/shared/utils/mcpResults.test.tsx +91 -0
  436. package/src/renderer/shared/utils/modViewport.ts +7 -0
  437. package/src/renderer/shared/utils/nativeRecordingSession.test.ts +61 -0
  438. package/src/renderer/shared/utils/nativeRecordingSession.ts +46 -0
  439. package/src/renderer/shared/utils/notificationSettings.test.ts +14 -0
  440. package/src/renderer/shared/utils/notificationSettings.ts +23 -0
  441. package/src/renderer/shared/utils/notifications.test.ts +51 -0
  442. package/src/renderer/shared/utils/notifications.ts +54 -0
  443. package/src/renderer/shared/utils/pastedText.test.ts +20 -0
  444. package/src/renderer/shared/utils/pastedText.ts +13 -0
  445. package/src/renderer/shared/utils/progressCache.test.ts +32 -0
  446. package/src/renderer/shared/utils/sessionSources.test.ts +31 -0
  447. package/src/renderer/shared/utils/sessionSources.ts +34 -0
  448. package/src/renderer/shared/utils/slashCommandProcessor.ts +1 -1
  449. package/src/renderer/shared/utils/sourceAttachments.ts +28 -0
  450. package/src/renderer/shared/utils/speech.ts +51 -9
  451. package/src/renderer/shared/utils/syntaxHighlight.test.tsx +22 -0
  452. package/src/renderer/shared/utils/syntaxHighlight.tsx +26 -0
  453. package/src/renderer/shared/utils/useGeminiLiveVoice.ts +49 -5
  454. package/src/renderer/shared/utils/useLatestCallback.ts +9 -0
  455. package/src/renderer/shared/utils/useNativeVoiceInput.ts +80 -72
  456. package/src/renderer/shared/utils/useSessionSources.ts +33 -0
  457. package/src/renderer/shared/utils/viewedImages.ts +26 -0
  458. package/src/renderer/shared/utils/workspacePane.test.ts +33 -0
  459. package/src/renderer/shared/utils/workspacePane.ts +20 -0
  460. package/src/renderer/shared/utils/workspacePreview.test.ts +24 -0
  461. package/src/renderer/shared/utils/workspacePreview.ts +16 -0
  462. package/src/renderer/shared/utils/workspaceSnapshot.test.ts +49 -0
  463. package/src/renderer/shared/utils/workspaceSnapshot.ts +26 -0
  464. package/src/renderer/shared/utils/workspaces.ts +10 -0
  465. package/src/renderer/shared/workspaceUndo.ts +88 -0
  466. package/src/renderer/src/App.tsx +9 -1
  467. package/src/renderer/src/components/LiveTranslateControls.tsx +65 -0
  468. package/src/renderer/src/components/PicturesLibrary.tsx +2 -288
  469. package/src/renderer/src/components/ScreenPicker.css +67 -30
  470. package/src/renderer/src/components/ScreenPicker.tsx +201 -60
  471. package/src/renderer/src/components/SettingsWindow.tsx +10 -5
  472. package/src/renderer/src/components/WorkspacePanel.tsx +222 -32
  473. package/src/renderer/src/components/browser-shell.css +1 -1
  474. package/src/renderer/src/components/browser-suggestions-popup.css +1 -1
  475. package/src/renderer/src/components/liveTranslateFrames.test.ts +26 -5
  476. package/src/renderer/src/components/liveTranslateFrames.ts +18 -7
  477. package/src/renderer/src/components/liveTranslateLanguage.ts +6 -0
  478. package/src/renderer/src/css/app-shell.css +52 -137
  479. package/src/renderer/src/css/chat.css +21 -495
  480. package/src/renderer/src/css/desktop-tools.css +199 -1
  481. package/src/renderer/src/css/misc.css +0 -52
  482. package/src/renderer/src/css/pictures.css +2 -415
  483. package/src/renderer/src/css/settings/base.css +50 -47
  484. package/src/renderer/src/css/sidebar-workspace.css +151 -94
  485. package/src/renderer/src/css/tool-surfaces.css +65 -9
  486. package/src/renderer/src/css/widget.css +1 -1
  487. package/src/renderer/src/env.d.ts +1 -9
  488. package/src/renderer/src/index.css +1 -1
  489. package/src/renderer/src/main.tsx +2 -1
  490. package/src/renderer/src/proactiveSuggestions.ts +29 -0
  491. package/src/renderer/src/tauri.ts +122 -330
  492. package/src/renderer/src/voiceInput.ts +2 -1
  493. package/src/renderer/src-web/components/PicturesLibrary.tsx +2 -285
  494. package/src/renderer/src-web/components/PullToRefresh.tsx +1 -1
  495. package/src/renderer/src-web/components/SettingsWindow.tsx +10 -5
  496. package/src/renderer/src-web/css/app-shell.css +24 -121
  497. package/src/renderer/src-web/css/chat.css +21 -495
  498. package/src/renderer/src-web/css/misc.css +0 -52
  499. package/src/renderer/src-web/css/mobile.css +15 -14
  500. package/src/renderer/src-web/css/pictures.css +2 -462
  501. package/src/renderer/src-web/css/settings/base.css +50 -47
  502. package/src/renderer/src-web/css/sidebar-workspace.css +9 -95
  503. package/src/renderer/src-web/css/widget.css +1 -1
  504. package/src/renderer/src-web/env.d.ts +1 -12
  505. package/src/renderer/src-web/index.css +1 -1
  506. package/src/renderer/src-web/main.tsx +2 -1
  507. package/src/renderer/src-web/proactiveSuggestions.ts +3 -0
  508. package/src/renderer/src-web/tauri.ts +129 -354
  509. package/src/renderer/tests/backgroundTerminals.browser.html +81 -0
  510. package/src/renderer/tests/chatPanelFixture.ts +23 -0
  511. package/src/renderer/tests/chatPerformance.browser.html +71 -0
  512. package/src/renderer/tests/cliSessions.browser.html +82 -0
  513. package/src/renderer/tests/collapsedPaste.browser.html +70 -0
  514. package/src/renderer/tests/composerMenus.browser.html +116 -0
  515. package/src/renderer/tests/contextCompaction.browser.html +17 -0
  516. package/src/renderer/tests/conversationLifecycle.browser.html +70 -0
  517. package/src/renderer/tests/effectsPerformance.browser.html +13 -0
  518. package/src/renderer/tests/errorRecovery.browser.html +21 -0
  519. package/src/renderer/tests/glideSelect.browser.html +71 -0
  520. package/src/renderer/tests/glideSelect.preview.html +27 -0
  521. package/src/renderer/tests/library.browser.html +1 -0
  522. package/src/renderer/tests/library.browser.tsx +78 -0
  523. package/src/renderer/tests/liveOrb.browser.html +49 -0
  524. package/src/renderer/tests/liveVoice.browser.html +29 -0
  525. package/src/renderer/tests/modInput.browser.html +22 -0
  526. package/src/renderer/tests/sessionSources.browser.html +1 -0
  527. package/src/renderer/tests/sessionSources.browser.tsx +107 -0
  528. package/src/renderer/tests/skills.browser.html +24 -0
  529. package/src/renderer/tests/toolsPanel.browser.html +1 -0
  530. package/src/renderer/tests/toolsPanel.browser.tsx +113 -0
  531. package/src/renderer/tests/viewedImages.browser.html +1 -0
  532. package/src/renderer/tests/viewedImages.browser.tsx +93 -0
  533. package/src/renderer/tests/voicePill.browser.html +80 -0
  534. package/src/renderer/tests/voicePill.preview.html +34 -0
  535. package/src/renderer/tests/webSources.browser.html +1 -0
  536. package/src/renderer/tests/webSources.browser.tsx +98 -0
  537. package/src/renderer/tests/workspaceUndo.browser.html +92 -0
  538. package/src-tauri/Cargo.toml +40 -0
  539. package/src-tauri/build.rs +3 -0
  540. package/src-tauri/src/app/lifecycle.rs +277 -0
  541. package/src-tauri/src/app/mod.rs +4 -0
  542. package/src-tauri/src/app/shortcuts.rs +40 -0
  543. package/src-tauri/src/app/tray.rs +52 -0
  544. package/src-tauri/src/background/events.rs +70 -0
  545. package/src-tauri/src/background/headless.rs +230 -0
  546. package/src-tauri/src/background/mod.rs +4 -0
  547. package/src-tauri/src/background/proactive.rs +262 -0
  548. package/src-tauri/src/commands/approvals.rs +20 -0
  549. package/src-tauri/src/commands/auth.rs +127 -0
  550. package/src-tauri/src/commands/conversation.rs +642 -0
  551. package/src-tauri/src/commands/integrations.rs +157 -0
  552. package/src-tauri/src/commands/media.rs +179 -0
  553. package/src-tauri/src/commands/mod.rs +11 -0
  554. package/src-tauri/src/commands/mods.rs +6 -0
  555. package/src-tauri/src/commands/settings.rs +141 -0
  556. package/src-tauri/src/commands/voice.rs +153 -0
  557. package/src-tauri/src/commands/workspace.rs +501 -0
  558. package/src-tauri/src/lib.rs +10 -0
  559. package/src-tauri/src/main.rs +3 -0
  560. package/src-tauri/src/native/actions.rs +206 -0
  561. package/src-tauri/src/native/browser.rs +252 -0
  562. package/src-tauri/src/native/capture.rs +695 -0
  563. package/src-tauri/src/native/discord_rpc.rs +99 -0
  564. package/src-tauri/src/native/integrations.rs +126 -0
  565. package/src-tauri/src/native/mod.rs +12 -0
  566. package/src-tauri/src/native/notifications.rs +51 -0
  567. package/src-tauri/src/native/plugins.rs +14 -0
  568. package/src-tauri/src/native/system.rs +250 -0
  569. package/src-tauri/src/native/terminal.rs +201 -0
  570. package/src-tauri/src/native/updater.rs +148 -0
  571. package/src-tauri/src/native/windows.rs +143 -0
  572. package/tsconfig.json +2 -0
  573. package/vite.config.ts +4 -1
  574. package/vite.config.web.ts +4 -0
  575. package/.cargo/config.toml +0 -13
  576. package/.claude/settings.local.json +0 -182
  577. package/.codex +0 -0
  578. package/CLAUDE.md +0 -102
  579. package/ROADMAP.md +0 -30
  580. package/mint-presentation-demo.mp4 +0 -0
  581. package/out/web/Live2DCubismCore.js +0 -9
  582. package/out/web/assets/CliSessionsView-BxUVWEEL.js +0 -1
  583. package/out/web/assets/CliSessionsView-CBDTXuQv.css +0 -1
  584. package/out/web/assets/CodeReviewPage-DkMgfcos.css +0 -1
  585. package/out/web/assets/CodeReviewPage-jKlmLJwT.js +0 -3
  586. package/out/web/assets/CommandPalette-DnwPA5hy.js +0 -1
  587. package/out/web/assets/ImageStudioPanel-BR1XFwhR.js +0 -1
  588. package/out/web/assets/LinkedFoldersView-bi-CWQ-I.js +0 -1
  589. package/out/web/assets/McpRegistryPicker-D5tEFnyq.js +0 -1
  590. package/out/web/assets/McpServersView-BGG1dhFM.js +0 -1
  591. package/out/web/assets/MintDashboard-BIglDEWX.js +0 -20
  592. package/out/web/assets/MintDashboard-DSMywSgs.css +0 -1
  593. package/out/web/assets/ModelPanel-CbJ1PFoZ.js +0 -1
  594. package/out/web/assets/PicturesLibrary-CQP0fLP1.css +0 -1
  595. package/out/web/assets/PicturesLibrary-DoYN7T1p.js +0 -1
  596. package/out/web/assets/PluginsView-CU1HWXGk.js +0 -1
  597. package/out/web/assets/ScheduledTasksView-Bnl36y2N.js +0 -1
  598. package/out/web/assets/SettingsWindow-DhWLAn9T.css +0 -1
  599. package/out/web/assets/SettingsWindow-Dw8L01pw.js +0 -2
  600. package/out/web/assets/SkillsView-cnl8aY5p.js +0 -2
  601. package/out/web/assets/ToolSurfacePage-CgsQw6l5.css +0 -1
  602. package/out/web/assets/ToolSurfacePage-Cz2VJAPZ.js +0 -37
  603. package/out/web/assets/VeoStudioPanel-D4JnERWR.js +0 -4
  604. package/out/web/assets/chunk-CKBBP62Z-cIrXq6jN.js +0 -2
  605. package/out/web/assets/classDiagram-DTDB5LWJ-Dq0smRWk.js +0 -1
  606. package/out/web/assets/classDiagram-v2-JRS7N3AN-Dq0smRWk.js +0 -1
  607. package/out/web/assets/config-C-ZFtipU.css +0 -1
  608. package/out/web/assets/config-eEDngJXO.js +0 -1
  609. package/out/web/assets/core-hQ2VA9Ti.js +0 -1
  610. package/out/web/assets/dist-js-Bf2bhoku.js +0 -1
  611. package/out/web/assets/flowDiagram-A5DVABFB-BLg7nEcd.js +0 -1
  612. package/out/web/assets/index-Btsf4L8M.css +0 -1
  613. package/out/web/assets/index-D8D9MeRA.js +0 -11
  614. package/out/web/assets/lucide-react-Ip3L6Jtn.js +0 -1
  615. package/out/web/assets/markdown-BSeeUbJH.js +0 -38
  616. package/out/web/assets/modelManager-tMVmJVAW.js +0 -2
  617. package/out/web/assets/prompt-latin-400-normal-BQ9zjSN8.woff2 +0 -0
  618. package/out/web/assets/prompt-latin-400-normal-CxU4ec_r.woff +0 -0
  619. package/out/web/assets/prompt-latin-500-normal-B1edBDQ9.woff +0 -0
  620. package/out/web/assets/prompt-latin-500-normal-CxzxEHZc.woff2 +0 -0
  621. package/out/web/assets/prompt-latin-600-normal-CSDDLorv.woff +0 -0
  622. package/out/web/assets/prompt-latin-600-normal-hKZWXsc1.woff2 +0 -0
  623. package/out/web/assets/prompt-latin-700-normal-BfbftDSq.woff +0 -0
  624. package/out/web/assets/prompt-latin-700-normal-I2gc831J.woff2 +0 -0
  625. package/out/web/assets/prompt-thai-400-normal-BrkKv8cO.woff2 +0 -0
  626. package/out/web/assets/prompt-thai-400-normal-DJypnfr3.woff +0 -0
  627. package/out/web/assets/prompt-thai-500-normal-C18pDUoL.woff2 +0 -0
  628. package/out/web/assets/prompt-thai-500-normal-D7YNqUJD.woff +0 -0
  629. package/out/web/assets/prompt-thai-600-normal-CYPViXds.woff +0 -0
  630. package/out/web/assets/prompt-thai-600-normal-MrdfU7zR.woff2 +0 -0
  631. package/out/web/assets/prompt-thai-700-normal-Cb5ilR-c.woff +0 -0
  632. package/out/web/assets/prompt-thai-700-normal-Cg4aQ0Nn.woff2 +0 -0
  633. package/out/web/assets/stateDiagram-v2-4QOOHH4V-DeEc0lGZ.js +0 -1
  634. package/out/web/assets/swimlanesDiagram-VK2B7HYN-DpVik9v7.js +0 -8
  635. package/out/web/assets/window-5qYXKoW7.js +0 -1
  636. package/skills-lock.json +0 -77
  637. package/src/renderer/public/Live2DCubismCore.js +0 -9
  638. package/src/renderer/src/companionWidget.ts +0 -95
  639. package/src/renderer/src/components/Live2DStage.tsx +0 -412
  640. package/src/renderer/src/components/ModelPanel.tsx +0 -155
  641. package/src/renderer/src/css/model.css +0 -628
  642. package/src/renderer/src-web/companionWidget.ts +0 -37
  643. package/src/renderer/src-web/components/ModelPanel.tsx +0 -12
  644. package/src/renderer/src-web/css/model.css +0 -628
@@ -1,5 +1,10 @@
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, extendedThoughtsFrom, mergeFileChanges, parseFileChangesFromProgress } from '../agentProgress'
7
+ import { EMPTY_AGENT_PROGRESS, hasAgentToolActivity, thoughtsFrom, extendedThoughtsFrom, mergeFileChanges, parseFileChangesFromProgress } from '../agentProgress'
3
8
  import { visibleInteractionsDuringRun } from '../conversation/syncView'
4
9
  import {
5
10
  GEMINI_MODELS,
@@ -13,30 +18,38 @@ import {
13
18
  GEMINI_LIVE_VOICES,
14
19
  } from '../constants/models'
15
20
  import { badge, providerLabel, fallbackNotice } from '../utils/providers'
16
- 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'
17
24
  import SlashSuggestions, { type SlashSuggestionsHandle } from './SlashSuggestions'
18
- import { AgentActivityTable } from './AgentActivityTable'
19
25
  import { ChatCodeBlock } from './ChatCodeBlock'
20
26
  import { renderApprovalDetails, renderDiff, type ApprovalDetails } from '../utils/approval'
21
27
  import { ApprovalCard } from './ApprovalCard'
22
- import { renderFormattedMessage, readableAssistantText, cleanSpeechText, renderSpeakerIcon, renderCopyIcon } from '../utils/markdown'
28
+ import { readableAssistantText, cleanSpeechText, renderSpeakerIcon, renderCopyIcon } from '../utils/markdown'
23
29
  import { ThinkingBlock } from './ThinkingBlock'
24
- import SourcesBlock from './SourcesBlock'
25
30
  import ChatMessageItem from './ChatMessageItem'
26
- import { AgentActivityDrawer } from './AgentActivityDrawer'
31
+ import { FormattedMessage } from './FormattedMessage'
32
+ import { ProgressActivity } from './ProgressActivity'
33
+ import { VirtualChatHistory, type VirtualChatHistoryHandle } from './VirtualChatHistory'
27
34
  import { ArtifactPreviewPanel, type ArtifactFile } from './ArtifactPreviewPanel'
28
35
  import { RewindModal } from './RewindModal'
29
36
  import type { AgentProgress, ChatResponse, DiffHunk, FileChange, GitCheckpoint, RuntimeStatus } from '../types'
30
37
  import { numericSetting, shouldShowSessionDivider, formatSessionDividerLabel } from '../utils/ui'
31
38
  import { useVoiceInput } from '@/voiceInput'
39
+ import VoicePill from './VoicePill'
32
40
  import { useGeminiLiveVoice } from '../utils/useGeminiLiveVoice'
33
41
  import GeminiLiveOverlay from './GeminiLiveOverlay'
34
42
  import { isSupportedDocument, SUPPORTED_DOCUMENT_ACCEPT } from '../utils/documentTypes'
35
43
  import ModelSelectorPopover from './ModelSelectorPopover'
36
44
  import GitBranchSelector from './GitBranchSelector'
37
45
  import WorkspaceSelector from './WorkspaceSelector'
46
+ import ToolsPanelToggle from './ToolsPanelToggle'
47
+ import SessionSourcesPopover from './SessionSourcesPopover'
48
+ import { ModsPanel } from './ModsPanel'
38
49
  import CodeReviewPage from './CodeReviewPage'
39
50
  import type { ToolSurface } from './ToolSurfacePage'
51
+ import '../css/thinking-status.css'
52
+ import '../css/slash-choice.css'
40
53
 
41
54
  import { catalogPlatform, conversationPlatform, runtimePlatform } from '../platform'
42
55
 
@@ -139,8 +152,11 @@ interface ChatPanelContract {
139
152
  cliSessionId?: string
140
153
  onBackToCode?: () => void
141
154
  conversationTitle?: string
155
+ slashChoice?: { command: string; title: string; options: { label: string; value: string }[] } | null
142
156
  onOpenArtifact?: (artifact: ArtifactFile) => void
143
157
  onOpenReview?: (review: Extract<ToolSurface, { kind: 'review' }>) => void
158
+ onSelectSlashChoice?: (value: string) => void
159
+ onDismissSlashChoice?: () => void
144
160
  }
145
161
 
146
162
  export type ConversationViewModel = Pick<ChatPanelContract,
@@ -149,7 +165,7 @@ export type ConversationViewModel = Pick<ChatPanelContract,
149
165
  | 'thinkingExpanded' | 'message' | 'imageAttachments' | 'videoAttachments' | 'documentName'
150
166
  | 'pendingApproval' | 'agentMode' | 'planMode' | 'status' | 'workspacePath' | 'chatId' | 'recentWorkspacePaths'
151
167
  | 'chatEnd' | 'welcomeInteraction' | 'settingsConfig' | 'isCliSession' | 'cliSessionId'
152
- | 'conversationTitle'
168
+ | 'conversationTitle' | 'slashChoice'
153
169
  | 'hasOlder'
154
170
  | 'sendingInteractionId'
155
171
  >
@@ -158,11 +174,15 @@ export type ConversationActions = Omit<ChatPanelContract, keyof ConversationView
158
174
  interface ChatPanelProps {
159
175
  conversation: ConversationViewModel
160
176
  actions: ConversationActions
177
+ showSessionSources?: boolean
178
+ tools?: { modsPanelTarget: HTMLElement | null; onOpenMods: () => void; onToggle?: () => void; open: boolean; backgroundTaskCount: number }
161
179
  }
162
180
 
163
181
  export default function ChatPanel({
164
182
  conversation,
165
183
  actions,
184
+ tools,
185
+ showSessionSources = false,
166
186
  }: ChatPanelProps) {
167
187
  const {
168
188
  interactions,
@@ -178,7 +198,7 @@ export default function ChatPanel({
178
198
  agentProgress,
179
199
  agentActivitySnapshots,
180
200
  thinkingExpanded,
181
- onThinkingExpandedChange,
201
+ onThinkingExpandedChange: handleThinkingExpandedChange,
182
202
  message,
183
203
  imageAttachments,
184
204
  videoAttachments,
@@ -222,9 +242,13 @@ export default function ChatPanel({
222
242
  cliSessionId,
223
243
  onBackToCode,
224
244
  conversationTitle,
245
+ slashChoice,
225
246
  onOpenArtifact,
226
247
  onOpenReview,
248
+ onSelectSlashChoice,
249
+ onDismissSlashChoice,
227
250
  } = { ...conversation, ...actions }
251
+ const onThinkingExpandedChange = useLatestCallback(handleThinkingExpandedChange)
228
252
  // The initiating surface already renders a live prompt/reply pair below.
229
253
  // Hide its matching persisted turn until the local stream settles, while
230
254
  // still showing turns submitted from other surfaces during that time.
@@ -232,7 +256,6 @@ export default function ChatPanel({
232
256
  () => visibleInteractionsDuringRun(interactions, sending, sendingInteractionId),
233
257
  [interactions, sending, sendingInteractionId],
234
258
  )
235
- const agentActivities = activitiesFrom(agentProgress)
236
259
  // Keep the composer summary tied to the active/latest agent run. This is cheap
237
260
  // metadata, but memoizing it avoids parsing the activity stream while typing.
238
261
  const composerChanges = useMemo(() => parseFileChangesFromProgress(agentProgress), [agentProgress])
@@ -247,15 +270,17 @@ export default function ChatPanel({
247
270
  const composerChangeLabel = composerChanges.length === 1
248
271
  ? '1 file changed'
249
272
  : `${composerChanges.length} files changed`
250
- const conversationChanges = useMemo(() => {
273
+ const historicalChanges = useMemo(() => {
251
274
  const historicalGroups = interactions.map((interaction) => {
252
275
  const interactionId = String(interaction.id)
253
- const progress = agentActivitySnapshots[interactionId] ?? interaction.agentActivity ?? []
276
+ const progress = agentActivitySnapshots[interactionId] ?? interaction.agentActivity ?? EMPTY_AGENT_PROGRESS
254
277
  return parseFileChangesFromProgress(progress)
255
278
  })
256
- const activeChanges = parseFileChangesFromProgress(agentProgress)
257
- return mergeFileChanges([...historicalGroups, activeChanges])
258
- }, [agentActivitySnapshots, agentProgress, interactions])
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]))
259
284
 
260
285
  const projectName = useMemo(() => {
261
286
  if (!workspacePath) return null
@@ -270,7 +295,10 @@ export default function ChatPanel({
270
295
  const throttledStreamedReply = useThrottledValue(streamedReply, STREAM_MARKDOWN_UPDATE_MS)
271
296
  const liveWebSources = useMemo(() => parseWebSearchSources(agentProgress), [agentProgress])
272
297
  const activeFallbackNotice = fallbackNotice(streamedResponse)
273
- 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])
274
302
  let activeAgentName: string | null = null
275
303
  let activeModelName: string | null = null
276
304
  if (lastThinkingProgress && lastThinkingProgress.type === 'Thinking') {
@@ -284,18 +312,22 @@ export default function ChatPanel({
284
312
  const [reviewPage, setReviewPage] = useState<{ title: string; changes: FileChange[] } | null>(null)
285
313
  const [activeArtifact, setActiveArtifact] = useState<ArtifactFile | null>(null)
286
314
  const [toolMenuOpen, setToolMenuOpen] = useState(false)
315
+ const [sessionSourcesOpen, setSessionSourcesOpen] = useState(false)
287
316
  const [elapsedSeconds, setElapsedSeconds] = useState(0)
288
317
  const [dynamicOllamaModels, setDynamicOllamaModels] = useState<string[]>(OLLAMA_MODELS)
318
+ const toggleActivity = useCallback((id: string) => {
319
+ setOpenActivityIds(current => ({ ...current, [id]: !(current[id] ?? (id === 'live')) }))
320
+ }, [])
289
321
 
290
- const openArtifact = (artifact: ArtifactFile) => {
322
+ const openArtifact = useLatestCallback((artifact: ArtifactFile) => {
291
323
  if (onOpenArtifact) onOpenArtifact(artifact)
292
- else setActiveArtifact(artifact)
293
- }
324
+ else setActiveArtifact({ ...artifact, workspacePath: artifact.workspacePath ?? workspacePath })
325
+ })
294
326
 
295
- const openReview = (title: string, changes: FileChange[]) => {
327
+ const openReview = useLatestCallback((title: string, changes: FileChange[]) => {
296
328
  if (onOpenReview) onOpenReview({ id: `review:${Date.now()}`, kind: 'review', title: 'Review', reviewTitle: title, changes })
297
329
  else setReviewPage({ title, changes })
298
- }
330
+ })
299
331
 
300
332
  useEffect(() => {
301
333
  let cancelled = false
@@ -362,6 +394,7 @@ export default function ChatPanel({
362
394
  const [copiedId, setCopiedId] = useState<string | number | null>(null)
363
395
 
364
396
  const chatContainerRef = useRef<HTMLDivElement | null>(null)
397
+ const virtualHistoryRef = useRef<VirtualChatHistoryHandle | null>(null)
365
398
  const [showScrollToBottom, setShowScrollToBottom] = useState(false)
366
399
  const [loadingOlder, setLoadingOlder] = useState(false)
367
400
  const isNearBottomRef = useRef(true)
@@ -383,7 +416,7 @@ export default function ChatPanel({
383
416
  const element = chatContainerRef.current
384
417
  if (element && isNearBottomRef.current) {
385
418
  // Smooth scrolling on every token restarts animations and causes jank.
386
- element.scrollTop = element.scrollHeight
419
+ virtualHistoryRef.current?.scrollToEnd()
387
420
  }
388
421
  })
389
422
  }, [])
@@ -392,6 +425,12 @@ export default function ChatPanel({
392
425
  scheduleScrollToLatest()
393
426
  }, [interactions, sending, streamedReply, pendingApproval, agentProgress, scheduleScrollToLatest])
394
427
 
428
+ useEffect(() => {
429
+ isNearBottomRef.current = true
430
+ setShowScrollToBottom(false)
431
+ scheduleScrollToLatest()
432
+ }, [chatId, scheduleScrollToLatest])
433
+
395
434
  useEffect(() => () => {
396
435
  if (scrollFrameRef.current !== null) window.cancelAnimationFrame(scrollFrameRef.current)
397
436
  }, [])
@@ -405,8 +444,9 @@ export default function ChatPanel({
405
444
  }, [activeArtifact])
406
445
 
407
446
  const scrollToBottom = useCallback(() => {
408
- chatEnd.current?.scrollIntoView({ behavior: 'smooth' })
409
- }, [chatEnd])
447
+ isNearBottomRef.current = true
448
+ virtualHistoryRef.current?.scrollToEnd()
449
+ }, [])
410
450
 
411
451
  const [splitRatio, setSplitRatio] = useState<number>(() => {
412
452
  try {
@@ -692,6 +732,7 @@ export default function ChatPanel({
692
732
  voiceModeRef,
693
733
  startRecognition,
694
734
  stopRecognition,
735
+ cancelRecognition,
695
736
  scheduleVoiceListen,
696
737
  clearRestartTimer
697
738
  } = useVoiceInput({
@@ -715,8 +756,6 @@ export default function ChatPanel({
715
756
  const canSubmit = Boolean(message.trim() || imageAttachments.length > 0 || videoAttachments.length > 0 || documentName)
716
757
  const sendingImageMarkers = Array.from({ length: sendingImageCount }, (_, index) => `[Image #${index + 1}]`).join(' ')
717
758
  const sendingVideoMarkers = Array.from({ length: sendingVideoCount || 0 }, (_, index) => `[Video #${index + 1}]`).join(' ')
718
- const voiceStatus = speakingText ? 'speaking' : (sending || voiceAwaitingResponse) ? 'thinking' : isRecording ? 'listening' : voiceMode ? 'ready' : 'off'
719
- const voiceStatusLabel = voiceStatus === 'speaking' ? 'Speaking' : voiceStatus === 'thinking' ? 'Thinking' : voiceStatus === 'listening' ? 'Listening' : 'Ready'
720
759
 
721
760
  const getAvailableModels = (provider: string) => {
722
761
  switch (provider) {
@@ -826,10 +865,10 @@ export default function ChatPanel({
826
865
  }
827
866
  // "Edit" on a past user message: drop its text back into the composer so it
828
867
  // can be tweaked and sent again as a new message (nothing is deleted).
829
- const handleEditMessage = (text: string) => {
868
+ const handleEditMessage = useLatestCallback((text: string) => {
830
869
  setHistoryIndex(null)
831
870
  applyHistoryValue(text)
832
- }
871
+ })
833
872
  const navigateHistoryNext = () => {
834
873
  if (historyIndex === null) return false
835
874
  if (historyIndex === 0) {
@@ -964,7 +1003,7 @@ export default function ChatPanel({
964
1003
  scheduleVoiceListen(900)
965
1004
  }
966
1005
  }
967
- const speak = (text: string) => {
1006
+ const speak = useLatestCallback((text: string) => {
968
1007
  const speechText = cleanSpeechText(text)
969
1008
  if (!speechText) return
970
1009
  if (speakingText === text) {
@@ -984,18 +1023,8 @@ export default function ChatPanel({
984
1023
  return
985
1024
  }
986
1025
  speakNative(speechText, text)
987
- }
988
-
989
- const toggleRecording = () => {
990
- if (isRecording) {
991
- stopRecognition()
992
- cancelSpeech()
993
- return
994
- }
1026
+ })
995
1027
 
996
- cancelSpeech()
997
- startRecognition()
998
- }
999
1028
  const resizeInput = (element: HTMLTextAreaElement) => {
1000
1029
  element.style.height = 'auto'
1001
1030
  element.style.height = `${Math.min(element.scrollHeight, 120)}px`
@@ -1056,13 +1085,13 @@ export default function ChatPanel({
1056
1085
  }, [onPasteImage])
1057
1086
  useEffect(() => {
1058
1087
  const handleEscapeKeyDown = (event: globalThis.KeyboardEvent) => {
1059
- if (event.key === 'Escape' && sending) {
1088
+ if (event.key === 'Escape' && sending && !sessionSourcesOpen) {
1060
1089
  onCancelMessage()
1061
1090
  }
1062
1091
  }
1063
1092
  window.addEventListener('keydown', handleEscapeKeyDown, true)
1064
1093
  return () => window.removeEventListener('keydown', handleEscapeKeyDown, true)
1065
- }, [sending, onCancelMessage])
1094
+ }, [sending, onCancelMessage, sessionSourcesOpen])
1066
1095
  useEffect(() => {
1067
1096
  if (message) return
1068
1097
  const input = document.getElementById('chat-input') as HTMLTextAreaElement | null
@@ -1111,31 +1140,6 @@ export default function ChatPanel({
1111
1140
  appendWorkspaceReference(reference)
1112
1141
  }
1113
1142
  const isEmptyChat = interactions.length === 0 && !sending && !pendingApproval
1114
- const renderCompletedActivity = useCallback((interaction: any) => {
1115
- const interactionId = String(interaction.id)
1116
- const progress = agentActivitySnapshots[interactionId] ?? interaction.agentActivity ?? []
1117
- const activityView = activitiesFrom(progress)
1118
- const isOpen = Boolean(openActivityIds[interactionId])
1119
- return (
1120
- <AgentActivityDrawer
1121
- activityView={activityView}
1122
- isOpen={isOpen}
1123
- onToggle={() => setOpenActivityIds((current) => ({ ...current, [interactionId]: !current[interactionId] }))}
1124
- isHistorical={true}
1125
- rawProgress={progress}
1126
- />
1127
- )
1128
- }, [agentActivitySnapshots, openActivityIds])
1129
-
1130
- const renderWebSearchSources = useCallback((interaction: any) => {
1131
- const interactionId = String(interaction.id)
1132
- const progress = agentActivitySnapshots[interactionId] ?? interaction.agentActivity ?? []
1133
- const sources = parseWebSearchSources(progress)
1134
- if (sources.length === 0) return null
1135
-
1136
- return <SourcesBlock sources={sources} />
1137
- }, [agentActivitySnapshots])
1138
-
1139
1143
  const renderChangesList = (changes: ReturnType<typeof parseFileChangesFromProgress>, idPrefix: string) => {
1140
1144
  const showAll = Boolean(showAllFileChanges[idPrefix])
1141
1145
  const visibleChanges = showAll ? changes : changes.slice(0, 3)
@@ -1246,7 +1250,7 @@ export default function ChatPanel({
1246
1250
 
1247
1251
  const renderFileChanges = useCallback((interaction: any) => {
1248
1252
  const interactionId = String(interaction.id)
1249
- const progress = agentActivitySnapshots[interactionId] ?? interaction.agentActivity ?? []
1253
+ const progress = agentActivitySnapshots[interactionId] ?? interaction.agentActivity ?? EMPTY_AGENT_PROGRESS
1250
1254
  const changes = parseFileChangesFromProgress(progress)
1251
1255
  if (changes.length === 0) return null
1252
1256
 
@@ -1359,7 +1363,7 @@ export default function ChatPanel({
1359
1363
  className="file-changes-review-btn"
1360
1364
  title="Review changed code"
1361
1365
  onClick={() => {
1362
- openReview('All conversation changes', conversationChanges)
1366
+ openReview('All conversation changes', getConversationChanges())
1363
1367
  }}
1364
1368
  >
1365
1369
  Review
@@ -1370,10 +1374,10 @@ export default function ChatPanel({
1370
1374
  </div>
1371
1375
  </div>
1372
1376
  )
1373
- }, [agentActivitySnapshots, conversationChanges, openReviewIds, openFileDiffs, showAllFileChanges, workspacePath])
1377
+ }, [agentActivitySnapshots, getConversationChanges, openReviewIds, openFileDiffs, showAllFileChanges, workspacePath, onOpenArtifact, onOpenReview])
1374
1378
 
1375
1379
  const renderActiveFileChanges = () => {
1376
- const changes = parseFileChangesFromProgress(agentProgress)
1380
+ const changes = composerChanges
1377
1381
  if (changes.length === 0) return null
1378
1382
 
1379
1383
  const totalAdditions = changes.reduce((sum, c) => sum + c.additions, 0)
@@ -1410,7 +1414,7 @@ export default function ChatPanel({
1410
1414
  className="file-changes-review-btn"
1411
1415
  title="Review changed code"
1412
1416
  onClick={() => {
1413
- openReview('All conversation changes', conversationChanges)
1417
+ openReview('All conversation changes', getConversationChanges())
1414
1418
  }}
1415
1419
  >
1416
1420
  Review
@@ -1427,6 +1431,111 @@ export default function ChatPanel({
1427
1431
  )
1428
1432
  }
1429
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
+
1430
1539
  const sectionContent = (
1431
1540
  <section
1432
1541
  className={`conversation-panel ${isEmptyChat ? 'is-empty' : ''}`}
@@ -1542,6 +1651,8 @@ export default function ChatPanel({
1542
1651
  )}
1543
1652
  </div>
1544
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} />}
1545
1656
  {activeArtifact && (
1546
1657
  <button
1547
1658
  type="button"
@@ -1571,167 +1682,62 @@ export default function ChatPanel({
1571
1682
  </button>
1572
1683
  </div>
1573
1684
  </div>
1574
- <div className="chat-container" ref={chatContainerRef} onScroll={handleChatScroll}>
1685
+ <div className="chat-container" ref={chatContainerRef} onScroll={handleChatScroll} style={{ overflowAnchor: 'none' }}>
1575
1686
  {hasOlder && onLoadOlder && (
1576
1687
  <button type="button" className="load-older-messages" disabled={loadingOlder}
1577
1688
  style={{ display: 'block', margin: '0 auto 20px', padding: '7px 14px', borderRadius: 8,
1578
1689
  border: '1px solid var(--border-color, #3a3a3a)', background: 'var(--surface, #252525)',
1579
1690
  color: 'var(--text-secondary, #c0c0c0)', cursor: loadingOlder ? 'default' : 'pointer' }}
1580
1691
  onClick={async () => {
1581
- const container = chatContainerRef.current
1582
- const previousHeight = container?.scrollHeight ?? 0
1583
1692
  setLoadingOlder(true)
1584
1693
  try {
1585
1694
  await onLoadOlder()
1586
- window.requestAnimationFrame(() => {
1587
- if (container) container.scrollTop += container.scrollHeight - previousHeight
1588
- })
1589
1695
  } finally { setLoadingOlder(false) }
1590
1696
  }}>
1591
1697
  {loadingOlder ? 'Loading earlier messages…' : 'Load earlier messages'}
1592
1698
  </button>
1593
1699
  )}
1594
- {visibleInteractions.map((interaction, index) => (
1595
- <Fragment key={interaction.id}>
1596
- {index > 0 && shouldShowSessionDivider(visibleInteractions[index - 1].createdAt, interaction.createdAt) && (
1597
- <div className="system-event-divider">
1598
- <div className="system-event-line" />
1599
- <div className="system-event-pill">
1600
- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
1601
- <circle cx="12" cy="12" r="9" />
1602
- <polyline points="12 7 12 12 15.5 14" />
1603
- </svg>
1604
- <span>{formatSessionDividerLabel(interaction.createdAt)}</span>
1605
- </div>
1606
- <div className="system-event-line" />
1607
- </div>
1608
- )}
1609
- <ChatMessageItem
1610
- interaction={interaction}
1611
- copiedId={copiedId}
1612
- onEditMessage={handleEditMessage}
1613
- speakingText={speakingText}
1614
- agentActivitySnapshots={agentActivitySnapshots}
1615
- thinkingExpanded={thinkingExpanded}
1616
- openActivityIds={openActivityIds}
1617
- openReviewIds={openReviewIds}
1618
- openFileDiffs={openFileDiffs}
1619
- onThinkingExpandedChange={onThinkingExpandedChange}
1620
- handleCopyMessage={handleCopyMessage}
1621
- speak={speak}
1622
- renderCompletedActivity={renderCompletedActivity}
1623
- renderFileChanges={renderFileChanges}
1624
- renderWebSearchSources={renderWebSearchSources}
1625
- />
1626
- </Fragment>
1627
- ))}
1628
-
1629
- {sending && (
1630
- <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', marginBottom: '16px' }}>
1631
- <div className="message user-message"><div className="bubble-wrapper"><div className="message-bubble">{renderFormattedMessage([sendingMessage, sendingImageMarkers, sendingVideoMarkers].filter(Boolean).join(' '))}</div></div></div>
1632
- {agentMode && (
1633
- <AgentActivityDrawer
1634
- activityView={agentActivities}
1635
- isOpen={openActivityIds['live'] ?? true}
1636
- onToggle={() => setOpenActivityIds((current) => ({ ...current, live: !(current['live'] ?? true) }))}
1637
- pendingApproval={!!pendingApproval}
1638
- rawProgress={agentProgress}
1639
- />
1640
- )}
1641
- {renderActiveFileChanges()}
1642
- <div className="message ai-message thinking-message">
1643
- <div className="bubble-wrapper">
1644
- {!agentMode && extendedThoughtsFrom(agentProgress).length > 0 && (
1645
- <ThinkingBlock
1646
- blockKey="live-extended"
1647
- thoughts={extendedThoughtsFrom(agentProgress)}
1648
- isLive={true}
1649
- variant="extended"
1650
- expanded={thinkingExpanded['live-extended'] ?? true}
1651
- onExpandedChange={onThinkingExpandedChange}
1652
- />
1653
- )}
1654
- {!agentMode && thoughtsFrom(agentProgress).length > 0 && extendedThoughtsFrom(agentProgress).length === 0 && (
1655
- <ThinkingBlock
1656
- blockKey="live"
1657
- thoughts={thoughtsFrom(agentProgress)}
1658
- isLive={true}
1659
- expanded={thinkingExpanded.live ?? true}
1660
- onExpandedChange={onThinkingExpandedChange}
1661
- />
1662
- )}
1663
- <div className="message-bubble">
1664
- <span>
1665
- {throttledStreamedReply ? (
1666
- renderFormattedMessage(throttledStreamedReply, liveWebSources)
1667
- ) : (
1668
- <div style={{ display: 'flex', alignItems: 'center', gap: '8px', color: 'var(--text-soft, #94a3b8)' }}>
1669
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" style={{ display: 'inline-block', flexShrink: 0 }}>
1670
- <circle cx="12" cy="12" r="10" stroke="rgba(255, 255, 255, 0.12)" />
1671
- <path d="M12 2a10 10 0 0 1 10 10" stroke="var(--accent)" strokeLinecap="round">
1672
- <animateTransform
1673
- attributeName="transform"
1674
- type="rotate"
1675
- from="0 12 12"
1676
- to="360 12 12"
1677
- dur="0.9s"
1678
- repeatCount="indefinite"
1679
- />
1680
- </path>
1681
- </svg>
1682
- <span>
1683
- {activeAgentName && activeModelName
1684
- ? `${activeAgentName} (${activeModelName}) is thinking... (${elapsedSeconds}s)`
1685
- : `Thinking for ${elapsedSeconds}s (Esc to cancel)`
1686
- }
1687
- </span>
1688
- </div>
1689
- )}
1690
- </span>
1691
- </div>
1692
- {streamedResponse && (
1693
- <div className="message-time" style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
1694
- <span className="provider-model-chip" data-provider={(streamedResponse.provider || '').toLowerCase()} title={`${streamedResponse.provider} • ${streamedResponse.model}`}>
1695
- <span className="provider-chip-dot" aria-hidden="true" />
1696
- <span className="provider-chip-name">{streamedResponse.provider}</span>
1697
- <span className="provider-chip-divider">/</span>
1698
- <span className="provider-chip-model">{streamedResponse.model}</span>
1699
- </span>
1700
- {activeFallbackNotice && <span className="provider-fallback-notice">{activeFallbackNotice}</span>}
1701
- {throttledStreamedReply && (
1702
- <div className="message-action-buttons" style={{ display: 'flex', alignItems: 'center', gap: '4px', marginLeft: 'auto' }}>
1703
- <button
1704
- type="button"
1705
- className={`msg-action-btn copy-btn ${copiedId === 'live' ? 'is-copied' : ''}`}
1706
- onClick={() => handleCopyMessage('live', throttledStreamedReply)}
1707
- title={copiedId === 'live' ? 'คัดลอกแล้ว (Copied!)' : 'คัดลอกข้อความ (Copy message)'}
1708
- >
1709
- {renderCopyIcon(copiedId === 'live')}
1710
- </button>
1711
- <button
1712
- type="button"
1713
- className={`msg-action-btn tts-btn ${speakingText === throttledStreamedReply ? 'is-speaking' : ''}`}
1714
- onClick={() => speak(throttledStreamedReply)}
1715
- title={speakingText === throttledStreamedReply ? 'Stop reading' : 'Read aloud'}
1716
- >
1717
- {renderSpeakerIcon(speakingText === throttledStreamedReply)}
1718
- </button>
1719
- </div>
1720
- )}
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" />
1721
1717
  </div>
1722
1718
  )}
1723
- </div>
1724
- </div>
1725
- </div>
1726
- )}
1727
-
1728
- {pendingApproval && (
1729
- <ApprovalCard
1730
- key={pendingApproval.id || JSON.stringify(pendingApproval)}
1731
- pendingApproval={pendingApproval}
1732
- onApproval={onApproval}
1733
- />
1734
- )}
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} />
1735
1741
  {showScrollToBottom && (
1736
1742
  <button
1737
1743
  type="button"
@@ -1749,7 +1755,8 @@ export default function ChatPanel({
1749
1755
  <div ref={chatEnd} />
1750
1756
  </div>
1751
1757
 
1752
- <div className={`input-area ${voiceMode ? 'voice-active' : ''}`}>
1758
+ <div className="input-area">
1759
+ <ModsPanel workspacePath={workspacePath} chatId={chatId} panelTarget={tools?.modsPanelTarget} onOpen={tools?.onOpenMods ?? (() => {})} />
1753
1760
  {composerChanges.length > 0 && (
1754
1761
  <button
1755
1762
  type="button"
@@ -1808,37 +1815,6 @@ export default function ChatPanel({
1808
1815
  </label>
1809
1816
  )}
1810
1817
  </div>
1811
- {voiceMode && (
1812
- <div className="voice-mode-bar" data-state={voiceStatus}>
1813
- <span className="voice-mode-dot" />
1814
- {voiceTranscript ? (
1815
- voiceTranscript === 'Listening to microphone...' ||
1816
- voiceTranscript === 'Listening...' ||
1817
- voiceTranscript === 'No speech detected' ||
1818
- voiceTranscript === 'Sent audio to AI' ? (
1819
- <span>{voiceTranscript}</span>
1820
- ) : (
1821
- <span style={{ display: 'flex', alignItems: 'center', gap: '4px', minWidth: 0, overflow: 'hidden' }}>
1822
- <span>{voiceStatusLabel}:</span>
1823
- <span className="voice-mode-transcript">"{voiceTranscript}"</span>
1824
- </span>
1825
- )
1826
- ) : (
1827
- <span>{voiceStatusLabel}</span>
1828
- )}
1829
- </div>
1830
- )}
1831
-
1832
- <SlashSuggestions
1833
- ref={slashRef}
1834
- message={message}
1835
- onComplete={completeSuggestion}
1836
- workspacePath={workspacePath}
1837
- mcpServers={settingsConfig?.mcpServers}
1838
- anchorRef={textareaRef}
1839
- suppressed={historyIndex !== null}
1840
- />
1841
-
1842
1818
  <form
1843
1819
  id="chat-form"
1844
1820
  className={geminiLiveEnabled ? 'has-live-btn' : ''}
@@ -1859,6 +1835,14 @@ export default function ChatPanel({
1859
1835
  if (onPasteImage(event.clipboardData)) event.preventDefault()
1860
1836
  }}
1861
1837
  >
1838
+ {slashChoice && (
1839
+ <SlashChoicePanel
1840
+ choice={slashChoice}
1841
+ inputRef={textareaRef}
1842
+ onSelect={onSelectSlashChoice}
1843
+ onDismiss={onDismissSlashChoice}
1844
+ />
1845
+ )}
1862
1846
  {(imageAttachments.length > 0 || videoAttachments.length > 0 || documentName) && (
1863
1847
  <div className="mint-attachment">
1864
1848
  {imageAttachments.map((attachment, idx) => (
@@ -1930,10 +1914,15 @@ export default function ChatPanel({
1930
1914
  History {historyIndex + 1}/{promptHistory.length}
1931
1915
  </div>
1932
1916
  )}
1933
- <textarea
1917
+ <CollapsiblePasteInput
1934
1918
  id="chat-input"
1935
- ref={textareaRef}
1919
+ inputRef={textareaRef}
1936
1920
  value={message}
1921
+ onValueChange={(value) => {
1922
+ onSetMessage(value)
1923
+ if (historyIndex !== null) setHistoryIndex(null)
1924
+ }}
1925
+ onResizeInput={resizeInput}
1937
1926
  onChange={(event) => {
1938
1927
  resizeInput(event.currentTarget)
1939
1928
  onSetMessage(event.target.value)
@@ -1945,6 +1934,15 @@ export default function ChatPanel({
1945
1934
  placeholder="Ask anything, @ to mention, / for actions"
1946
1935
  rows={1}
1947
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
+ />
1948
1946
  <div className="chat-tool-menu-wrap" ref={toolMenuRef}>
1949
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' }}>
1950
1948
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
@@ -2036,27 +2034,43 @@ export default function ChatPanel({
2036
2034
  }}
2037
2035
  onUpdateSettings={onUpdateSettings}
2038
2036
  />
2039
- <button
2040
- id="mic-btn"
2041
- className={`${isRecording ? 'is-recording' : ''} ${voiceMode ? 'voice-mode-active' : ''}`}
2042
- type="button"
2043
- onClick={toggleRecording}
2044
- title={voiceMode ? 'Disable voice conversation' : 'Enable voice conversation'}
2045
- style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}
2046
- >
2047
- {isRecording ? (
2048
- <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
2049
- <rect x="4" y="4" width="16" height="16" rx="2" ry="2"></rect>
2050
- </svg>
2051
- ) : (
2052
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
2053
- <path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"></path>
2054
- <path d="M19 10v2a7 7 0 0 1-14 0v-2"></path>
2055
- <line x1="12" y1="19" x2="12" y2="23"></line>
2056
- <line x1="8" y1="23" x2="16" y2="23"></line>
2057
- </svg>
2058
- )}
2059
- </button>
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
+ }}
2073
+ />
2060
2074
  {geminiLiveEnabled && (
2061
2075
  <button
2062
2076
  id="gemini-live-btn"
@@ -2096,6 +2110,9 @@ export default function ChatPanel({
2096
2110
  </button>
2097
2111
  )}
2098
2112
  </form>
2113
+ {voiceMode && !isRecording && voiceTranscript && (
2114
+ <p className="composer-voice-feedback" role="status">{voiceTranscript}</p>
2115
+ )}
2099
2116
  </div>
2100
2117
  <p className="input-disclaimer">
2101
2118
  Mint Agent is an AI gateway. Responses via third-party APIs. Verify critical info.
@@ -2103,7 +2120,11 @@ export default function ChatPanel({
2103
2120
  {geminiLive.voiceMode && (
2104
2121
  <GeminiLiveOverlay
2105
2122
  status={
2106
- geminiLive.isPaused
2123
+ geminiLive.errorMessage
2124
+ ? 'error'
2125
+ : !geminiLive.isRecording
2126
+ ? 'connecting'
2127
+ : geminiLive.isPaused
2107
2128
  ? 'paused'
2108
2129
  : geminiLive.isSpeaking
2109
2130
  ? 'speaking'
@@ -2114,6 +2135,7 @@ export default function ChatPanel({
2114
2135
  userTranscript={geminiLive.userTranscript}
2115
2136
  assistantTranscript={geminiLive.assistantTranscript}
2116
2137
  isPaused={geminiLive.isPaused}
2138
+ analyserRef={geminiLive.analyserRef}
2117
2139
  onTogglePause={geminiLive.togglePause}
2118
2140
  onEndCall={() => geminiLive.setVoiceMode(false)}
2119
2141
  voice={settingsConfig?.geminiLiveVoice || 'Puck'}