@pheem49/mint 1.14.0 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +1 -1
- package/Cargo.lock +291 -11
- package/Cargo.toml +1 -1
- package/README.md +71 -9
- package/ROADMAP.md +30 -0
- package/Release_Note.md +579 -465
- package/crates/mint-cli/Cargo.toml +3 -1
- package/crates/mint-cli/src/agent/approval_prompts.rs +16 -3
- package/crates/mint-cli/src/agent/live_status.rs +367 -118
- package/crates/mint-cli/src/agent/markdown_render.rs +601 -61
- package/crates/mint-cli/src/agent.rs +452 -215
- package/crates/mint-cli/src/commands/agent.rs +16 -21
- package/crates/mint-cli/src/commands/eval.rs +9 -5
- package/crates/mint-cli/src/commands/git.rs +204 -0
- package/crates/mint-cli/src/commands/integrations.rs +28 -0
- package/crates/mint-cli/src/commands/knowledge.rs +1 -0
- package/crates/mint-cli/src/commands/mod.rs +37 -2
- package/crates/mint-cli/src/commands/tailnet_web.rs +235 -0
- package/crates/mint-cli/src/image.rs +26 -3
- package/crates/mint-cli/src/interactive/chat_tui.rs +4742 -0
- package/crates/mint-cli/src/interactive/command_ui.rs +477 -0
- package/crates/mint-cli/src/interactive/format.rs +8 -0
- package/crates/mint-cli/src/interactive/input_box.rs +38 -2
- package/crates/mint-cli/src/interactive/picker.rs +180 -37
- package/crates/mint-cli/src/interactive/resume_picker.rs +686 -0
- package/crates/mint-cli/src/interactive/slash_commands.rs +868 -450
- package/crates/mint-cli/src/interactive/thought_viewer.rs +286 -0
- package/crates/mint-cli/src/interactive.rs +400 -136
- package/crates/mint-cli/src/main.rs +84 -23
- package/crates/mint-cli/src/markdown.rs +12 -5
- package/crates/mint-cli/src/onboard.rs +32 -30
- package/crates/mint-cli/src/plugins_cli.rs +8 -5
- package/crates/mint-cli/src/setup.rs +10 -8
- package/crates/mint-cli/src/terminal_theme.rs +187 -0
- package/crates/mint-cli/src/updater.rs +56 -21
- package/crates/mint-core/src/agent/agent_loop.rs +1 -0
- package/crates/mint-core/src/agent/chat.rs +843 -177
- package/crates/mint-core/src/agent/code_tools.rs +83 -2
- package/crates/mint-core/src/agent/memory.rs +658 -20
- package/crates/mint-core/src/agent/skills.rs +1 -1
- package/crates/mint-core/src/api_server/routes/chat.rs +31 -5
- package/crates/mint-core/src/api_server/routes/linked_folders.rs +118 -3
- package/crates/mint-core/src/api_server/routes/misc.rs +10 -14
- package/crates/mint-core/src/api_server/routes/sessions.rs +44 -0
- package/crates/mint-core/src/api_server.rs +22 -3
- package/crates/mint-core/src/avatar_bridge.rs +2 -0
- package/crates/mint-core/src/browser/cdp.rs +74 -83
- package/crates/mint-core/src/browser/evidence.rs +260 -0
- package/crates/mint-core/src/browser/input.rs +1 -1
- package/crates/mint-core/src/browser/interact.rs +98 -124
- package/crates/mint-core/src/browser/lifecycle.rs +75 -4
- package/crates/mint-core/src/browser/mod.rs +16 -2
- package/crates/mint-core/src/browser/navigate.rs +27 -19
- package/crates/mint-core/src/browser/observe.js +40 -0
- package/crates/mint-core/src/browser/session.rs +1558 -0
- package/crates/mint-core/src/git/branches.rs +348 -0
- package/crates/mint-core/src/git/checkpoint.rs +40 -0
- package/crates/mint-core/src/git/diff.rs +206 -0
- package/crates/mint-core/src/git/mod.rs +10 -2
- package/crates/mint-core/src/integrations/channels.rs +1 -0
- package/crates/mint-core/src/lib.rs +22 -14
- package/crates/mint-core/src/live_sync.rs +28 -9
- package/crates/mint-core/src/media/auto_shorts.rs +1 -0
- package/crates/mint-core/src/media/gemini_live.rs +12 -1
- package/crates/mint-core/src/media/mic_transcribe.rs +1 -0
- package/crates/mint-core/src/media/subtitle.rs +1 -0
- package/crates/mint-core/src/orchestration/context_render.rs +1 -0
- package/crates/mint-core/src/orchestration/memory_skill.rs +6 -1
- package/crates/mint-core/src/orchestration/mod.rs +1024 -271
- package/crates/mint-core/src/orchestration/tools/browser.rs +16 -139
- package/crates/mint-core/src/orchestration/tools/misc.rs +2 -1
- package/crates/mint-core/src/orchestration/tools/web.rs +1 -1
- package/crates/mint-core/src/prompts/agent.rs +58 -29
- package/crates/mint-core/src/prompts/chat.rs +1 -1
- package/crates/mint-core/src/prompts/persona.rs +1 -1
- package/crates/mint-core/src/prompts/tool_catalog.rs +93 -25
- package/crates/mint-core/src/search/linked_folders/index.rs +732 -0
- package/crates/mint-core/src/search/linked_folders.rs +391 -130
- package/crates/mint-core/src/slash/mod.rs +470 -22
- package/crates/mint-core/src/slash/model_fetcher.rs +12 -3
- package/crates/mint-core/src/slash/models.rs +66 -10
- package/crates/mint-core/src/system/config.rs +230 -0
- package/crates/mint-core/src/system/workspace.rs +228 -0
- package/crates/mint-core/src/system.rs +1 -0
- package/crates/mint-core/tests/memory_persistence.rs +39 -0
- package/mint-presentation-demo.mp4 +0 -0
- package/out/web/assets/CliSessionsView-BxUVWEEL.js +1 -0
- package/out/web/assets/CliSessionsView-CBDTXuQv.css +1 -0
- package/out/web/assets/CodeReviewPage-DkMgfcos.css +1 -0
- package/out/web/assets/CodeReviewPage-jKlmLJwT.js +3 -0
- package/out/web/assets/CommandPalette-DnwPA5hy.js +1 -0
- package/out/web/assets/ImageStudioPanel-BR1XFwhR.js +1 -0
- package/out/web/assets/ImageStudioPanel-D0lnhQV5.css +1 -0
- package/out/web/assets/LinkedFoldersView-bi-CWQ-I.js +1 -0
- package/out/web/assets/McpRegistryPicker-D5tEFnyq.js +1 -0
- package/out/web/assets/McpServersView-BGG1dhFM.js +1 -0
- package/out/web/assets/MintDashboard-BIglDEWX.js +20 -0
- package/out/web/assets/MintDashboard-DSMywSgs.css +1 -0
- package/out/web/assets/ModelPanel-CbJ1PFoZ.js +1 -0
- package/out/web/assets/PicturesLibrary-CQP0fLP1.css +1 -0
- package/out/web/assets/PicturesLibrary-DoYN7T1p.js +1 -0
- package/out/web/assets/PluginsView-CU1HWXGk.js +1 -0
- package/out/web/assets/ScheduledTasksView-Bnl36y2N.js +1 -0
- package/out/web/assets/SettingsWindow-DhWLAn9T.css +1 -0
- package/out/web/assets/SettingsWindow-Dw8L01pw.js +2 -0
- package/out/web/assets/SkillsView-cnl8aY5p.js +2 -0
- package/out/web/assets/ToolSurfacePage-CgsQw6l5.css +1 -0
- package/out/web/assets/ToolSurfacePage-Cz2VJAPZ.js +37 -0
- package/out/web/assets/VeoStudioPanel-D4JnERWR.js +4 -0
- package/out/web/assets/VeoStudioPanel-DOj7_WR3.css +1 -0
- package/out/web/assets/WorkspacePanel-CbJ1PFoZ.js +1 -0
- package/out/web/assets/{abnfDiagram-VCTEODGH-DAOBA7ZG.js → abnfDiagram-VCTEODGH-ByMyfanq.js} +1 -1
- package/out/web/assets/{architecture-7GRP2DOG-CgSwQOPQ.js → architecture-7GRP2DOG-CLq2kEOB.js} +1 -1
- package/out/web/assets/{architectureDiagram-5GKGNRK7-CYp3yupP.js → architectureDiagram-5GKGNRK7-6PoVSmNG.js} +1 -1
- package/out/web/assets/{blockDiagram-NRAW4CY4-CyWybDWr.js → blockDiagram-NRAW4CY4-cKw9mAKi.js} +1 -1
- package/out/web/assets/{c4Diagram-UCG6FXSJ-BvY3U709.js → c4Diagram-UCG6FXSJ-Cqy8N5Ge.js} +1 -1
- package/out/web/assets/{chunk-75Z2AOVW-TLXCoZYv.js → chunk-75Z2AOVW-3qybijF5.js} +1 -1
- package/out/web/assets/chunk-CKBBP62Z-cIrXq6jN.js +2 -0
- package/out/web/assets/{chunk-CLGD4ZFX-xjsKtNS7.js → chunk-CLGD4ZFX-CndDQkww.js} +1 -1
- package/out/web/assets/chunk-DSNCTWBM-Cc4NxvgD.js +2 -0
- package/out/web/assets/chunk-DU6HZSFF-drzh6GsU.js +128 -0
- package/out/web/assets/{chunk-F27PBJKO-BFpgF55A.js → chunk-F27PBJKO-FiY35l4v.js} +1 -1
- package/out/web/assets/{chunk-G27WJ6UU-DfF7qW-C.js → chunk-G27WJ6UU-Bjt9Il4A.js} +1 -1
- package/out/web/assets/{chunk-GMAD6QVW-C-558kh_.js → chunk-GMAD6QVW-Bppi3Ctd.js} +1 -1
- package/out/web/assets/{chunk-JQ64N6SF-wJmeGKAw.js → chunk-JQ64N6SF-DGg5kcEV.js} +1 -1
- package/out/web/assets/{chunk-LCL6LL3I-C1wHD8Ie.js → chunk-LCL6LL3I-CCYcjd7p.js} +1 -1
- package/out/web/assets/{chunk-OBVCFTLP-BsRTPBqs.js → chunk-OBVCFTLP-DJeNil5M.js} +1 -1
- package/out/web/assets/{chunk-P2QGCYS3-HZIiM7Ni.js → chunk-P2QGCYS3-lRzkRjBB.js} +1 -1
- package/out/web/assets/{chunk-POPQ4Y6H-Dk9wvVb0.js → chunk-POPQ4Y6H-DouASMBW.js} +1 -1
- package/out/web/assets/{chunk-PWAF6VOD-BmjYLNbq.js → chunk-PWAF6VOD-DMmD1vVf.js} +1 -1
- package/out/web/assets/{chunk-R7TYR2AO-CaHIf-lK.js → chunk-R7TYR2AO-CYLA5UC5.js} +1 -1
- package/out/web/assets/{chunk-RHFEMEQ7-_T561hOU.js → chunk-RHFEMEQ7-BiXwEcUT.js} +1 -1
- package/out/web/assets/{chunk-SVP7TREG-CM-GGYoY.js → chunk-SVP7TREG-BV-zPslF.js} +1 -1
- package/out/web/assets/{chunk-TEH6E4GO-K2A8Vg2C.js → chunk-TEH6E4GO-B2RGEohZ.js} +1 -1
- package/out/web/assets/classDiagram-DTDB5LWJ-Dq0smRWk.js +1 -0
- package/out/web/assets/classDiagram-v2-JRS7N3AN-Dq0smRWk.js +1 -0
- package/out/web/assets/config-C-ZFtipU.css +1 -0
- package/out/web/assets/config-eEDngJXO.js +1 -0
- package/out/web/assets/core-hQ2VA9Ti.js +1 -0
- package/out/web/assets/{cynefin-OW5HDTMX-ClzaB6cc.js → cynefin-OW5HDTMX-Cas4csHM.js} +1 -1
- package/out/web/assets/{cynefinDiagram-5FMLGOSQ-D_JzZBzf.js → cynefinDiagram-5FMLGOSQ-Bbpj66Y3.js} +1 -1
- package/out/web/assets/{dagre-3AP2YEHR-BDuUeMHj.js → dagre-3AP2YEHR-B0-2RDEd.js} +1 -1
- package/out/web/assets/{diagram-S7CK7UJ4-DgtcfE8P.js → diagram-S7CK7UJ4-BdzEjUyH.js} +1 -1
- package/out/web/assets/{diagram-UQ7AKVKN-DTLoEYti.js → diagram-UQ7AKVKN-CJDwyPxF.js} +1 -1
- package/out/web/assets/{diagram-VSXAHHWV-ChGl9pXz.js → diagram-VSXAHHWV-BxaG1r_B.js} +1 -1
- package/out/web/assets/{diagram-VX7I27RA-Be8DWz0S.js → diagram-VX7I27RA-BMmUqm8f.js} +1 -1
- package/out/web/assets/{diagram-Z3DM3KII-BMXjRTOF.js → diagram-Z3DM3KII-CFtd03eE.js} +1 -1
- package/out/web/assets/dist-js-Bf2bhoku.js +1 -0
- package/out/web/assets/{ebnfDiagram-PWID7BFC-8Q9pl1CJ.js → ebnfDiagram-PWID7BFC-DwAen1hO.js} +1 -1
- package/out/web/assets/{erDiagram-SSCWMZ5O-DjH8Lnkn.js → erDiagram-SSCWMZ5O-BCZSHACj.js} +1 -1
- package/out/web/assets/event-ChBVpRy0.js +1 -0
- package/out/web/assets/{eventmodeling-NTZA5JFV-BKUH_DOp.js → eventmodeling-NTZA5JFV-XHStE4E_.js} +1 -1
- package/out/web/assets/fira-code-latin-600-normal-BmSSHshu.woff +0 -0
- package/out/web/assets/fira-code-latin-600-normal-CvYZpPHg.woff2 +0 -0
- package/out/web/assets/fira-code-symbols2-600-normal-Dvq6IQE5.woff +0 -0
- package/out/web/assets/flowDiagram-A5DVABFB-BLg7nEcd.js +1 -0
- package/out/web/assets/{ganttDiagram-EL5Y4UJY-D7fZKJNM.js → ganttDiagram-EL5Y4UJY-BAEu1Cql.js} +1 -1
- package/out/web/assets/{gitGraph-4MIJSDKK-BypWaaBU.js → gitGraph-4MIJSDKK-r32Vyper.js} +1 -1
- package/out/web/assets/{gitGraphDiagram-WWUBYQGX-DWiw_3bq.js → gitGraphDiagram-WWUBYQGX-z9o9qt6V.js} +1 -1
- package/out/web/assets/index-Btsf4L8M.css +1 -0
- package/out/web/assets/index-D8D9MeRA.js +11 -0
- package/out/web/assets/{info-A6RAGUB7-KkAUxT4j.js → info-A6RAGUB7-BvLaC2cw.js} +1 -1
- package/out/web/assets/{infoDiagram-RXCK75RN-BNb6E48y.js → infoDiagram-RXCK75RN-Be6WAXXw.js} +1 -1
- package/out/web/assets/{ishikawaDiagram-5VMMS53U-Caa-JoAK.js → ishikawaDiagram-5VMMS53U-DZjoHJHC.js} +1 -1
- package/out/web/assets/{journeyDiagram-EYS64GPL-DOrmFGz6.js → journeyDiagram-EYS64GPL-CtVkjkGm.js} +1 -1
- package/out/web/assets/{kanban-definition-3QL26DDD-BOWCYcK0.js → kanban-definition-3QL26DDD-CW5FMv1w.js} +1 -1
- package/out/web/assets/lucide-react-Ip3L6Jtn.js +1 -0
- package/out/web/assets/markdown-BSeeUbJH.js +38 -0
- package/out/web/assets/{mermaid-parser.core-BQqjCkS_.js → mermaid-parser.core-aUgCqsZ5.js} +3 -3
- package/out/web/assets/mermaid.core-D57sEiSL.js +11 -0
- package/out/web/assets/{mindmap-definition-FBJOCRG2-jTceWpr0.js → mindmap-definition-FBJOCRG2-DAmSpM3a.js} +1 -1
- package/out/web/assets/modelManager-tMVmJVAW.js +2 -0
- package/out/web/assets/oauthManager-9jxicDWJ.js +1 -0
- package/out/web/assets/{packet-AYTQ26CC-CJ5RXgol.js → packet-AYTQ26CC-DJ27iIoJ.js} +1 -1
- package/out/web/assets/{pegDiagram-XKGWAZYB-y8wMtd0y.js → pegDiagram-XKGWAZYB-Bj3ii-gS.js} +1 -1
- package/out/web/assets/{pie-WAS4IAKB-72fTBbl4.js → pie-WAS4IAKB-DG5mCUbc.js} +1 -1
- package/out/web/assets/{pieDiagram-E7YTZNPT-e0O02qWq.js → pieDiagram-E7YTZNPT-BrJLPnDA.js} +1 -1
- package/out/web/assets/prompt-latin-700-normal-BfbftDSq.woff +0 -0
- package/out/web/assets/prompt-latin-700-normal-I2gc831J.woff2 +0 -0
- package/out/web/assets/prompt-thai-700-normal-Cb5ilR-c.woff +0 -0
- package/out/web/assets/prompt-thai-700-normal-Cg4aQ0Nn.woff2 +0 -0
- package/out/web/assets/{quadrantDiagram-AXDQQJYC-C9phYLom.js → quadrantDiagram-AXDQQJYC-3x_TmF3j.js} +1 -1
- package/out/web/assets/{radar-RG4KPBEZ-BAU2hzUT.js → radar-RG4KPBEZ-CrXaTTuV.js} +1 -1
- package/out/web/assets/{railroad-74A4TZTK-B0bCAVHC.js → railroad-74A4TZTK-BpqMH9BE.js} +1 -1
- package/out/web/assets/{railroad-abnf-HS5TGJTU-WhxO7ndE.js → railroad-abnf-HS5TGJTU-DHI0uLlV.js} +1 -1
- package/out/web/assets/{railroad-ebnf-LZEXJU2U-BkA0m7-F.js → railroad-ebnf-LZEXJU2U-CQCb316y.js} +1 -1
- package/out/web/assets/{railroad-peg-WCYAUIDC-BsVpHIaj.js → railroad-peg-WCYAUIDC-Ph1giKkH.js} +1 -1
- package/out/web/assets/{railroadDiagram-O6MQD6OU-CyOLN65Q.js → railroadDiagram-O6MQD6OU-BRq6wIxx.js} +1 -1
- package/out/web/assets/{requirementDiagram-EFPCY7ZU-DQXJ7Dud.js → requirementDiagram-EFPCY7ZU-DIJj6G1g.js} +1 -1
- package/out/web/assets/{sankeyDiagram-P5KCCOFB-B2XLyIIc.js → sankeyDiagram-P5KCCOFB-DZajSryq.js} +1 -1
- package/out/web/assets/{sequenceDiagram-WJ2MYXX4-DGQY4wwm.js → sequenceDiagram-WJ2MYXX4-DxJCWyZS.js} +1 -1
- package/out/web/assets/{stateDiagram-HBIQ2CUA-DHZpDwNy.js → stateDiagram-HBIQ2CUA-k6voi8Vf.js} +1 -1
- package/out/web/assets/stateDiagram-v2-4QOOHH4V-DeEc0lGZ.js +1 -0
- package/out/web/assets/studio-B1mk40wD.js +1 -0
- package/out/web/assets/{swimlanes-XN3QIQJK-Bn_jcZz-.js → swimlanes-XN3QIQJK-igYhTjXB.js} +1 -1
- package/out/web/assets/swimlanesDiagram-VK2B7HYN-DpVik9v7.js +8 -0
- package/out/web/assets/{timeline-definition-24CTP7MA-CdTERuJZ.js → timeline-definition-24CTP7MA-Dke2p93p.js} +1 -1
- package/out/web/assets/{treeView-Q6P3EWNA-TKBKQG6R.js → treeView-Q6P3EWNA-hNELnXUs.js} +1 -1
- package/out/web/assets/{treemap-WGGIJYW6-BP7gQoiC.js → treemap-WGGIJYW6-D2B6wDsx.js} +1 -1
- package/out/web/assets/{vennDiagram-4TSXK5OY-BHUmxDuK.js → vennDiagram-4TSXK5OY-CDkW7rUP.js} +1 -1
- package/out/web/assets/{wardley-WFR3VGLG-9bct5AAN.js → wardley-WFR3VGLG-BECdXETi.js} +1 -1
- package/out/web/assets/{wardleyDiagram-VM6X3IG4-BfJwDDso.js → wardleyDiagram-VM6X3IG4-B5BycpQ4.js} +1 -1
- package/out/web/assets/window-5qYXKoW7.js +1 -0
- package/out/web/assets/{xychartDiagram-S5SC5T6Z-Dqd9Mvpo.js → xychartDiagram-S5SC5T6Z-CtJS3b--.js} +1 -1
- package/out/web/index-web.html +3 -4
- package/out/web/index.html +3 -4
- package/package.json +17 -6
- package/skills-lock.json +36 -0
- package/slash-commands.json +9 -0
- package/src/renderer/index-web.html +1 -0
- package/src/renderer/index.html +1 -0
- package/src/renderer/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/src/renderer/shared/agentProgress.ts +168 -3
- package/src/renderer/shared/components/AgentActivityDrawer.tsx +6 -6
- package/src/renderer/shared/components/AgentActivityTable.tsx +192 -132
- package/src/renderer/shared/components/ArtifactPreviewPanel.tsx +4 -4
- package/src/renderer/shared/components/AuthGate.tsx +4 -9
- package/src/renderer/shared/components/CalculationCard.tsx +41 -15
- package/src/renderer/shared/components/ChatMessageItem.tsx +20 -21
- package/src/renderer/shared/components/ChatPanel.tsx +432 -193
- package/src/renderer/shared/components/ChunkErrorBoundary.tsx +198 -49
- package/src/renderer/shared/components/CliSessionsView.tsx +495 -0
- package/src/renderer/shared/components/CodeReviewPage.tsx +565 -0
- package/src/renderer/shared/components/CommandPalette.tsx +8 -8
- package/src/renderer/shared/components/DashboardSidebar.tsx +862 -125
- package/src/renderer/shared/components/DesktopTitlebar.tsx +345 -0
- package/src/renderer/shared/components/DiffReviewModal.tsx +3 -3
- package/src/renderer/shared/components/GitBranchSelector.tsx +442 -0
- package/src/renderer/shared/components/ImageGenCard.tsx +31 -12
- package/src/renderer/shared/components/ImageSearchCard.tsx +59 -38
- package/src/renderer/shared/components/ImageStudioPanel.tsx +40 -41
- package/src/renderer/shared/components/InlineThoughtNote.tsx +27 -0
- package/src/renderer/shared/components/LinkedFoldersView.tsx +365 -46
- package/src/renderer/shared/components/McpRegistryPicker.tsx +1 -1
- package/src/renderer/shared/components/McpServersView.tsx +24 -22
- package/src/renderer/shared/components/MermaidCard.tsx +14 -8
- package/src/renderer/shared/components/MintDashboard.tsx +1141 -508
- package/src/renderer/shared/components/ModelSelectorPopover.tsx +535 -214
- package/src/renderer/shared/components/PlanChecklistWidget.tsx +1 -1
- package/src/renderer/shared/components/PluginsView.tsx +1 -1
- package/src/renderer/shared/components/RewindModal.tsx +6 -6
- package/src/renderer/shared/components/RunSummaryDashboard.tsx +3 -3
- package/src/renderer/shared/components/ScheduledTasksView.tsx +4 -4
- package/src/renderer/shared/components/ScreenCaptureDialog.css +221 -0
- package/src/renderer/shared/components/ScreenCaptureDialog.tsx +199 -0
- package/src/renderer/shared/components/Settings/AgentsTab.tsx +34 -39
- package/src/renderer/shared/components/Settings/AudioTab.tsx +8 -8
- package/src/renderer/shared/components/Settings/AutomationTab.tsx +8 -58
- package/src/renderer/shared/components/Settings/AvatarCropModal.tsx +368 -0
- package/src/renderer/shared/components/Settings/GeneralTab.tsx +335 -81
- package/src/renderer/shared/components/Settings/MemoryTab.tsx +3 -3
- package/src/renderer/shared/components/Settings/PluginsTab.tsx +20 -12
- package/src/renderer/shared/components/Settings/ProfileTab.tsx +29 -5
- package/src/renderer/shared/components/Settings/SearchableModelCombobox.tsx +411 -0
- package/src/renderer/shared/components/Settings/ThemeTab.tsx +401 -158
- package/src/renderer/shared/components/SkillsView.tsx +41 -16
- package/src/renderer/shared/components/SlashSuggestions.tsx +3 -2
- package/src/renderer/shared/components/SourcesBlock.tsx +44 -32
- package/src/renderer/shared/components/StockCard.tsx +58 -24
- package/src/renderer/shared/components/SubagentDagView.tsx +4 -4
- package/src/renderer/shared/components/TerminalDock.tsx +241 -0
- package/src/renderer/shared/components/ThinkingBlock.tsx +14 -8
- package/src/renderer/shared/components/ToolSurfacePage.tsx +520 -0
- package/src/renderer/shared/components/UiFeatureCard.tsx +267 -0
- package/src/renderer/shared/components/UiGridCard.tsx +188 -0
- package/src/renderer/shared/components/UiMockupWidget.tsx +149 -0
- package/src/renderer/shared/components/VeoStudioPanel.tsx +13 -29
- package/src/renderer/shared/components/WeatherCard.tsx +3 -3
- package/src/renderer/shared/components/WorkspaceContextPopover.tsx +133 -0
- package/src/renderer/shared/components/WorkspaceSelector.tsx +149 -0
- package/src/renderer/shared/constants/config.ts +28 -3
- package/src/renderer/shared/constants/models.ts +189 -2
- package/src/renderer/shared/conversation/coordinator.test.ts +27 -0
- package/src/renderer/shared/conversation/coordinator.ts +82 -0
- package/src/renderer/shared/conversation/syncView.test.ts +46 -0
- package/src/renderer/shared/conversation/syncView.ts +43 -0
- package/src/renderer/shared/conversation/useConversationCoordinator.ts +106 -0
- package/src/renderer/shared/css/agent-observability.css +35 -3
- package/src/renderer/shared/css/auth-gate.css +2 -2
- package/src/renderer/shared/css/chat-ui-cards.css +495 -0
- package/src/renderer/shared/css/code-review.css +823 -0
- package/src/renderer/shared/css/code-sessions.css +452 -0
- package/src/renderer/shared/css/file-changes.css +132 -0
- package/src/renderer/shared/css/image-studio.css +16 -16
- package/src/renderer/shared/css/management-views.css +277 -27
- package/src/renderer/shared/css/model-selector.css +442 -42
- package/src/renderer/shared/css/settings/agents.css +1 -1
- package/src/renderer/shared/css/settings/automation.css +13 -13
- package/src/renderer/shared/css/settings/general.css +526 -5
- package/src/renderer/shared/css/settings/plugins.css +5 -5
- package/src/renderer/shared/css/settings/profile.css +331 -1
- package/src/renderer/shared/css/settings/theme.css +651 -3
- package/src/renderer/shared/css/veo-studio.css +16 -15
- package/src/renderer/shared/fonts.ts +19 -37
- package/src/renderer/shared/platform.test.ts +34 -0
- package/src/renderer/shared/platform.ts +173 -6
- package/src/renderer/shared/theme/themeManager.ts +144 -0
- package/src/renderer/shared/theme/themes.ts +116 -0
- package/src/renderer/shared/theme/tokens.css +318 -0
- package/src/renderer/shared/types.ts +82 -1
- package/src/renderer/shared/utils/agentActivity.ts +126 -5
- package/src/renderer/shared/utils/cardJson.test.ts +35 -0
- package/src/renderer/shared/utils/cardJson.ts +30 -0
- package/src/renderer/shared/utils/fileIcons.ts +1 -1
- package/src/renderer/shared/utils/markdown.tsx +329 -80
- package/src/renderer/shared/utils/markdown.webImages.test.tsx +40 -0
- package/src/renderer/shared/utils/providers.ts +8 -3
- package/src/renderer/shared/utils/screenCapture.ts +43 -0
- package/src/renderer/shared/utils/slashCommandProcessor.ts +4 -1
- package/src/renderer/shared/utils/ui.ts +4 -64
- package/src/renderer/src/App.tsx +7 -0
- package/src/renderer/src/components/BrowserShell.tsx +108 -0
- package/src/renderer/src/components/BrowserSuggestionsPopup.tsx +91 -0
- package/src/renderer/src/components/Live2DStage.tsx +32 -9
- package/src/renderer/src/components/MintDashboard.tsx +4 -2
- package/src/renderer/src/components/ModelPanel.tsx +2 -1
- package/src/renderer/src/components/PicturesLibrary.tsx +3 -2
- package/src/renderer/src/components/ScreenPicker.css +190 -0
- package/src/renderer/src/components/ScreenPicker.tsx +185 -540
- package/src/renderer/src/components/SettingsWindow.tsx +40 -2
- package/src/renderer/src/components/SpotlightWindow.tsx +1 -0
- package/src/renderer/src/components/WidgetWindow.tsx +27 -3
- package/src/renderer/src/components/WorkspacePanel.tsx +61 -43
- package/src/renderer/src/components/browser-shell.css +185 -0
- package/src/renderer/src/components/browser-suggestions-popup.css +55 -0
- package/src/renderer/src/components/liveTranslateFrames.test.ts +23 -0
- package/src/renderer/src/components/liveTranslateFrames.ts +34 -0
- package/src/renderer/src/css/app-shell.css +394 -113
- package/src/renderer/src/css/chat.css +1926 -380
- package/src/renderer/src/css/dashboard.css +11 -0
- package/src/renderer/src/css/desktop-tools.css +730 -0
- package/src/renderer/src/css/misc.css +19 -22
- package/src/renderer/src/css/model.css +49 -48
- package/src/renderer/src/css/pictures.css +144 -136
- package/src/renderer/src/css/settings/base.css +357 -123
- package/src/renderer/src/css/sidebar-workspace.css +930 -291
- package/src/renderer/src/css/spotlight.css +15 -26
- package/src/renderer/src/css/tool-surfaces.css +728 -0
- package/src/renderer/src/css/widget.css +35 -7
- package/src/renderer/src/env.d.ts +3 -0
- package/src/renderer/src/hooks/useProviderModels.ts +2 -9
- package/src/renderer/src/index.css +53 -46
- package/src/renderer/src/main.tsx +11 -0
- package/src/renderer/src/tauri.ts +201 -30
- package/src/renderer/src-web/App.tsx +40 -0
- package/src/renderer/src-web/components/MintDashboard.tsx +4 -2
- package/src/renderer/src-web/components/PicturesLibrary.tsx +3 -2
- package/src/renderer/src-web/components/PullToRefresh.tsx +107 -0
- package/src/renderer/src-web/components/SettingsWindow.tsx +28 -2
- package/src/renderer/src-web/css/app-shell.css +174 -96
- package/src/renderer/src-web/css/chat.css +1519 -316
- package/src/renderer/src-web/css/dashboard.css +11 -0
- package/src/renderer/src-web/css/misc.css +17 -17
- package/src/renderer/src-web/css/mobile.css +678 -0
- package/src/renderer/src-web/css/model.css +46 -46
- package/src/renderer/src-web/css/pictures.css +81 -34
- package/src/renderer/src-web/css/pull-to-refresh.css +54 -0
- package/src/renderer/src-web/css/settings/base.css +316 -100
- package/src/renderer/src-web/css/settings/mobile.css +320 -0
- package/src/renderer/src-web/css/sidebar-workspace.css +545 -100
- package/src/renderer/src-web/css/spotlight.css +9 -26
- package/src/renderer/src-web/css/widget.css +0 -5
- package/src/renderer/src-web/env.d.ts +3 -0
- package/src/renderer/src-web/hooks/useProviderModels.ts +2 -9
- package/src/renderer/src-web/index.css +53 -96
- package/src/renderer/src-web/main.tsx +11 -0
- package/src/renderer/src-web/tauri.ts +200 -30
- package/vite.config.web.ts +1 -0
- package/out/web/assets/MintDashboard-DWSqucgb.js +0 -57
- package/out/web/assets/SettingsWindow-DFM2aj5B.js +0 -2
- package/out/web/assets/chunk-CKBBP62Z-nr1uKPj9.js +0 -2
- package/out/web/assets/chunk-DSNCTWBM-Dtj8Rqsd.js +0 -2
- package/out/web/assets/chunk-DU6HZSFF-2tv5K1wT.js +0 -128
- package/out/web/assets/classDiagram-DTDB5LWJ-BdSFArgw.js +0 -1
- package/out/web/assets/classDiagram-v2-JRS7N3AN-BdSFArgw.js +0 -1
- package/out/web/assets/core-DImejIUG.js +0 -1
- package/out/web/assets/dist-js-BxuKEVWM.js +0 -1
- package/out/web/assets/event-BNl8Zahw.js +0 -1
- package/out/web/assets/fira-code-cyrillic-400-normal-UC0NFL4U.woff2 +0 -0
- package/out/web/assets/fira-code-cyrillic-400-normal-dc1q3VD7.woff +0 -0
- package/out/web/assets/fira-code-cyrillic-500-normal-Bu7VCL72.woff +0 -0
- package/out/web/assets/fira-code-cyrillic-500-normal-CX35h3Mg.woff2 +0 -0
- package/out/web/assets/fira-code-cyrillic-ext-400-normal-Buh61xzB.woff +0 -0
- package/out/web/assets/fira-code-cyrillic-ext-400-normal-txZ9Fk_1.woff2 +0 -0
- package/out/web/assets/fira-code-cyrillic-ext-500-normal-CYRspHgm.woff2 +0 -0
- package/out/web/assets/fira-code-cyrillic-ext-500-normal-CwtLmSFD.woff +0 -0
- package/out/web/assets/fira-code-greek-400-normal-B2Gh_Y8s.woff2 +0 -0
- package/out/web/assets/fira-code-greek-400-normal-DobhaxvF.woff +0 -0
- package/out/web/assets/fira-code-greek-500-normal-CVO0IRNt.woff2 +0 -0
- package/out/web/assets/fira-code-greek-500-normal-DEXIWiey.woff +0 -0
- package/out/web/assets/fira-code-greek-ext-400-normal-DR7mBgIM.woff2 +0 -0
- package/out/web/assets/fira-code-greek-ext-400-normal-DSPUheWg.woff +0 -0
- package/out/web/assets/fira-code-greek-ext-500-normal-BO3iq16n.woff2 +0 -0
- package/out/web/assets/fira-code-greek-ext-500-normal-CMiNLXER.woff +0 -0
- package/out/web/assets/fira-code-latin-ext-400-normal-DG73JjOf.woff +0 -0
- package/out/web/assets/fira-code-latin-ext-400-normal-KSMg0QLl.woff2 +0 -0
- package/out/web/assets/fira-code-latin-ext-500-normal-CaANqXjI.woff +0 -0
- package/out/web/assets/fira-code-latin-ext-500-normal-Crd9e_oI.woff2 +0 -0
- package/out/web/assets/flowDiagram-A5DVABFB-BpnHUSU7.js +0 -1
- package/out/web/assets/index-CVRg270z.css +0 -1
- package/out/web/assets/index-DxZQr9yD.js +0 -10
- package/out/web/assets/inter-cyrillic-400-normal-HOLc17fK.woff +0 -0
- package/out/web/assets/inter-cyrillic-400-normal-obahsSVq.woff2 +0 -0
- package/out/web/assets/inter-cyrillic-500-normal-BasfLYem.woff2 +0 -0
- package/out/web/assets/inter-cyrillic-500-normal-CxZf_p3X.woff +0 -0
- package/out/web/assets/inter-cyrillic-600-normal-4D_pXhcN.woff +0 -0
- package/out/web/assets/inter-cyrillic-600-normal-CWCymEST.woff2 +0 -0
- package/out/web/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2 +0 -0
- package/out/web/assets/inter-cyrillic-ext-400-normal-DQukG94-.woff +0 -0
- package/out/web/assets/inter-cyrillic-ext-500-normal-B0yAr1jD.woff2 +0 -0
- package/out/web/assets/inter-cyrillic-ext-500-normal-BmqWE9Dz.woff +0 -0
- package/out/web/assets/inter-cyrillic-ext-600-normal-Bcila6Z-.woff +0 -0
- package/out/web/assets/inter-cyrillic-ext-600-normal-Dfes3d0z.woff2 +0 -0
- package/out/web/assets/inter-greek-400-normal-B4URO6DV.woff2 +0 -0
- package/out/web/assets/inter-greek-400-normal-q2sYcFCs.woff +0 -0
- package/out/web/assets/inter-greek-500-normal-BIZE56-Y.woff2 +0 -0
- package/out/web/assets/inter-greek-500-normal-Xzm54t5V.woff +0 -0
- package/out/web/assets/inter-greek-600-normal-BZpKdvQh.woff +0 -0
- package/out/web/assets/inter-greek-600-normal-plRanbMR.woff2 +0 -0
- package/out/web/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2 +0 -0
- package/out/web/assets/inter-greek-ext-400-normal-KugGGMne.woff +0 -0
- package/out/web/assets/inter-greek-ext-500-normal-2j5mBUwD.woff +0 -0
- package/out/web/assets/inter-greek-ext-500-normal-C4iEst2y.woff2 +0 -0
- package/out/web/assets/inter-greek-ext-600-normal-B8X0CLgF.woff +0 -0
- package/out/web/assets/inter-greek-ext-600-normal-DRtmH8MT.woff2 +0 -0
- package/out/web/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
- package/out/web/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
- package/out/web/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
- package/out/web/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
- package/out/web/assets/inter-latin-600-normal-CiBQ2DWP.woff +0 -0
- package/out/web/assets/inter-latin-600-normal-LgqL8muc.woff2 +0 -0
- package/out/web/assets/inter-latin-ext-400-normal-77YHD8bZ.woff +0 -0
- package/out/web/assets/inter-latin-ext-400-normal-C1nco2VV.woff2 +0 -0
- package/out/web/assets/inter-latin-ext-500-normal-BxGbmqWO.woff +0 -0
- package/out/web/assets/inter-latin-ext-500-normal-CV4jyFjo.woff2 +0 -0
- package/out/web/assets/inter-latin-ext-600-normal-CIVaiw4L.woff +0 -0
- package/out/web/assets/inter-latin-ext-600-normal-D2bJ5OIk.woff2 +0 -0
- package/out/web/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff +0 -0
- package/out/web/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
- package/out/web/assets/inter-vietnamese-500-normal-DOriooB6.woff2 +0 -0
- package/out/web/assets/inter-vietnamese-500-normal-mJboJaSs.woff +0 -0
- package/out/web/assets/inter-vietnamese-600-normal-BuLX-rYi.woff +0 -0
- package/out/web/assets/inter-vietnamese-600-normal-Cc8MFFhd.woff2 +0 -0
- package/out/web/assets/kanit-latin-400-normal-BUlsQXH3.woff2 +0 -0
- package/out/web/assets/kanit-latin-400-normal-HVZWrfev.woff +0 -0
- package/out/web/assets/kanit-latin-500-normal-CX_4XcKi.woff2 +0 -0
- package/out/web/assets/kanit-latin-500-normal-qBha86O4.woff +0 -0
- package/out/web/assets/kanit-latin-600-normal-0lS78yAd.woff2 +0 -0
- package/out/web/assets/kanit-latin-600-normal-DlacpeTg.woff +0 -0
- package/out/web/assets/kanit-latin-ext-400-normal-B2xPf58u.woff2 +0 -0
- package/out/web/assets/kanit-latin-ext-400-normal-CHvNKHHD.woff +0 -0
- package/out/web/assets/kanit-latin-ext-500-normal-BFdWrG22.woff +0 -0
- package/out/web/assets/kanit-latin-ext-500-normal-EHs3suD6.woff2 +0 -0
- package/out/web/assets/kanit-latin-ext-600-normal-BBDzoLaj.woff +0 -0
- package/out/web/assets/kanit-latin-ext-600-normal-DAX3wtuq.woff2 +0 -0
- package/out/web/assets/kanit-thai-400-normal-D2nliXKa.woff +0 -0
- package/out/web/assets/kanit-thai-400-normal-D80Pglro.woff2 +0 -0
- package/out/web/assets/kanit-thai-500-normal-BB8gri04.woff2 +0 -0
- package/out/web/assets/kanit-thai-500-normal-Iy_w0a80.woff +0 -0
- package/out/web/assets/kanit-thai-600-normal-Bj6oiaDc.woff2 +0 -0
- package/out/web/assets/kanit-thai-600-normal-wbTlPO7I.woff +0 -0
- package/out/web/assets/kanit-vietnamese-400-normal-DRI8YWyb.woff2 +0 -0
- package/out/web/assets/kanit-vietnamese-400-normal-dow6Bnto.woff +0 -0
- package/out/web/assets/kanit-vietnamese-500-normal-BzTrpCM3.woff2 +0 -0
- package/out/web/assets/kanit-vietnamese-500-normal-T1ndT7MF.woff +0 -0
- package/out/web/assets/kanit-vietnamese-600-normal-Bi7fw3I4.woff2 +0 -0
- package/out/web/assets/kanit-vietnamese-600-normal-DXCRAa_8.woff +0 -0
- package/out/web/assets/mali-latin-400-normal-ByPcZ8Gx.woff +0 -0
- package/out/web/assets/mali-latin-400-normal-Cuc6Ykl8.woff2 +0 -0
- package/out/web/assets/mali-latin-500-normal-B01M-LP6.woff2 +0 -0
- package/out/web/assets/mali-latin-500-normal-Thgqw_9f.woff +0 -0
- package/out/web/assets/mali-latin-600-normal-B9TiUNpT.woff2 +0 -0
- package/out/web/assets/mali-latin-600-normal-CycpQCwU.woff +0 -0
- package/out/web/assets/mali-latin-ext-400-normal-DUVdJQO4.woff +0 -0
- package/out/web/assets/mali-latin-ext-400-normal-iCG1ALuJ.woff2 +0 -0
- package/out/web/assets/mali-latin-ext-500-normal-BfJE4UMZ.woff2 +0 -0
- package/out/web/assets/mali-latin-ext-500-normal-FoLEyOKS.woff +0 -0
- package/out/web/assets/mali-latin-ext-600-normal-BTvIfiCp.woff2 +0 -0
- package/out/web/assets/mali-latin-ext-600-normal-DAQcLVmD.woff +0 -0
- package/out/web/assets/mali-thai-400-normal-BO7A3bLZ.woff2 +0 -0
- package/out/web/assets/mali-thai-400-normal-CX9VrjTn.woff +0 -0
- package/out/web/assets/mali-thai-500-normal-Cph2qha9.woff +0 -0
- package/out/web/assets/mali-thai-500-normal-D89rMT77.woff2 +0 -0
- package/out/web/assets/mali-thai-600-normal-DPgXT6rZ.woff +0 -0
- package/out/web/assets/mali-thai-600-normal-DlTx3OsB.woff2 +0 -0
- package/out/web/assets/mali-vietnamese-400-normal-DUKxzXaz.woff2 +0 -0
- package/out/web/assets/mali-vietnamese-400-normal-gFDLvsOK.woff +0 -0
- package/out/web/assets/mali-vietnamese-500-normal--OY07q2c.woff +0 -0
- package/out/web/assets/mali-vietnamese-500-normal-KDrNRwfW.woff2 +0 -0
- package/out/web/assets/mali-vietnamese-600-normal-CtTMUU7T.woff +0 -0
- package/out/web/assets/mali-vietnamese-600-normal-DFlJr66u.woff2 +0 -0
- package/out/web/assets/mermaid.core-DYGGlqOf.js +0 -11
- package/out/web/assets/mitr-latin-400-normal-Cb18vPmZ.woff +0 -0
- package/out/web/assets/mitr-latin-400-normal-CwbkLQ4a.woff2 +0 -0
- package/out/web/assets/mitr-latin-500-normal-B4JOhzAi.woff +0 -0
- package/out/web/assets/mitr-latin-500-normal-BmClOow2.woff2 +0 -0
- package/out/web/assets/mitr-latin-ext-400-normal-B3CPG7Yo.woff2 +0 -0
- package/out/web/assets/mitr-latin-ext-400-normal-DTx65hiC.woff +0 -0
- package/out/web/assets/mitr-latin-ext-500-normal-B_Diajz1.woff2 +0 -0
- package/out/web/assets/mitr-latin-ext-500-normal-DYOsVaVT.woff +0 -0
- package/out/web/assets/mitr-thai-400-normal-CS4Do6aM.woff +0 -0
- package/out/web/assets/mitr-thai-400-normal-CXWaAdVj.woff2 +0 -0
- package/out/web/assets/mitr-thai-500-normal-CVdBrEVH.woff2 +0 -0
- package/out/web/assets/mitr-thai-500-normal-CW_B5D-i.woff +0 -0
- package/out/web/assets/mitr-vietnamese-400-normal-CPMGWyoC.woff2 +0 -0
- package/out/web/assets/mitr-vietnamese-400-normal-Z6XhIpdY.woff +0 -0
- package/out/web/assets/mitr-vietnamese-500-normal-CDrv0585.woff2 +0 -0
- package/out/web/assets/mitr-vietnamese-500-normal-CMQWyq-Z.woff +0 -0
- package/out/web/assets/noto-sans-thai-latin-400-normal-BaWBrqFP.woff2 +0 -0
- package/out/web/assets/noto-sans-thai-latin-400-normal-Dh_FJjOB.woff +0 -0
- package/out/web/assets/noto-sans-thai-latin-500-normal-BC04jsmm.woff +0 -0
- package/out/web/assets/noto-sans-thai-latin-500-normal-fyBKClF1.woff2 +0 -0
- package/out/web/assets/noto-sans-thai-latin-600-normal-CemcjnVR.woff2 +0 -0
- package/out/web/assets/noto-sans-thai-latin-600-normal-Dbc-dNO6.woff +0 -0
- package/out/web/assets/noto-sans-thai-latin-ext-400-normal-B-1H0YkH.woff +0 -0
- package/out/web/assets/noto-sans-thai-latin-ext-400-normal-nBP59pVw.woff2 +0 -0
- package/out/web/assets/noto-sans-thai-latin-ext-500-normal-B-ZWb8SZ.woff2 +0 -0
- package/out/web/assets/noto-sans-thai-latin-ext-500-normal-CrEHO7C8.woff +0 -0
- package/out/web/assets/noto-sans-thai-latin-ext-600-normal-PkMZo0xa.woff +0 -0
- package/out/web/assets/noto-sans-thai-latin-ext-600-normal-maHHBsez.woff2 +0 -0
- package/out/web/assets/noto-sans-thai-thai-400-normal-BEOmKAI1.woff2 +0 -0
- package/out/web/assets/noto-sans-thai-thai-400-normal-Dxb_unuU.woff +0 -0
- package/out/web/assets/noto-sans-thai-thai-500-normal-BOGXO2tw.woff +0 -0
- package/out/web/assets/noto-sans-thai-thai-500-normal-CU_X86GQ.woff2 +0 -0
- package/out/web/assets/noto-sans-thai-thai-600-normal-CmgB8_JK.woff +0 -0
- package/out/web/assets/noto-sans-thai-thai-600-normal-Cs73sVjl.woff2 +0 -0
- package/out/web/assets/oauthManager-DNiwM8Rn.js +0 -2
- package/out/web/assets/oauthManager-DuamS1Av.css +0 -1
- package/out/web/assets/outfit-latin-300-normal-AWLfuCom.woff +0 -0
- package/out/web/assets/outfit-latin-300-normal-CRYTwY6m.woff2 +0 -0
- package/out/web/assets/outfit-latin-400-normal-BGsTXAXT.woff2 +0 -0
- package/out/web/assets/outfit-latin-400-normal-DMwTpYkH.woff +0 -0
- package/out/web/assets/outfit-latin-500-normal-ClnHRwRh.woff +0 -0
- package/out/web/assets/outfit-latin-500-normal-DKnIMDSk.woff2 +0 -0
- package/out/web/assets/outfit-latin-600-normal-B7SfZ07L.woff2 +0 -0
- package/out/web/assets/outfit-latin-600-normal-BEfTtDA7.woff +0 -0
- package/out/web/assets/outfit-latin-ext-300-normal-BYS6Dpvq.woff2 +0 -0
- package/out/web/assets/outfit-latin-ext-300-normal-CMIMshEd.woff +0 -0
- package/out/web/assets/outfit-latin-ext-400-normal-5tcqmc2S.woff2 +0 -0
- package/out/web/assets/outfit-latin-ext-400-normal-DHm7mdGe.woff +0 -0
- package/out/web/assets/outfit-latin-ext-500-normal-DrCvqoFD.woff +0 -0
- package/out/web/assets/outfit-latin-ext-500-normal-zeox_O30.woff2 +0 -0
- package/out/web/assets/outfit-latin-ext-600-normal-B85nYjL1.woff2 +0 -0
- package/out/web/assets/outfit-latin-ext-600-normal-CWJcPgd7.woff +0 -0
- package/out/web/assets/preload-helper-D0uHx7FM.js +0 -1
- package/out/web/assets/prompt-latin-ext-400-normal-1pHbN9uy.woff +0 -0
- package/out/web/assets/prompt-latin-ext-400-normal-DdSafGZ9.woff2 +0 -0
- package/out/web/assets/prompt-latin-ext-500-normal--EZ1um7s.woff2 +0 -0
- package/out/web/assets/prompt-latin-ext-500-normal-D-lI1EVT.woff +0 -0
- package/out/web/assets/prompt-latin-ext-600-normal-C8b50x67.woff +0 -0
- package/out/web/assets/prompt-latin-ext-600-normal-Cg9L7iJU.woff2 +0 -0
- package/out/web/assets/prompt-vietnamese-400-normal-BCPzsgPT.woff2 +0 -0
- package/out/web/assets/prompt-vietnamese-400-normal-D4pLyeNK.woff +0 -0
- package/out/web/assets/prompt-vietnamese-500-normal-DmzxmPwa.woff2 +0 -0
- package/out/web/assets/prompt-vietnamese-500-normal-w_sS_j2F.woff +0 -0
- package/out/web/assets/prompt-vietnamese-600-normal-1dyohtNh.woff +0 -0
- package/out/web/assets/prompt-vietnamese-600-normal-7QWjJBsF.woff2 +0 -0
- package/out/web/assets/sarabun-latin-400-normal-DmguIS-7.woff +0 -0
- package/out/web/assets/sarabun-latin-400-normal-URPBxl-K.woff2 +0 -0
- package/out/web/assets/sarabun-latin-500-normal-BjUTcdxu.woff2 +0 -0
- package/out/web/assets/sarabun-latin-500-normal-CJexTAnl.woff +0 -0
- package/out/web/assets/sarabun-latin-600-normal-9FonlkKx.woff +0 -0
- package/out/web/assets/sarabun-latin-600-normal-DMD3TROr.woff2 +0 -0
- package/out/web/assets/sarabun-latin-ext-400-normal-BbP7GpLL.woff2 +0 -0
- package/out/web/assets/sarabun-latin-ext-400-normal-BsmTn0SS.woff +0 -0
- package/out/web/assets/sarabun-latin-ext-500-normal-Cot16Bd2.woff +0 -0
- package/out/web/assets/sarabun-latin-ext-500-normal-DE1LysqI.woff2 +0 -0
- package/out/web/assets/sarabun-latin-ext-600-normal-0tXu9x_i.woff +0 -0
- package/out/web/assets/sarabun-latin-ext-600-normal-BRxjKUQ6.woff2 +0 -0
- package/out/web/assets/sarabun-thai-400-normal-C2DaJlKK.woff2 +0 -0
- package/out/web/assets/sarabun-thai-400-normal-CH-UbWgg.woff +0 -0
- package/out/web/assets/sarabun-thai-500-normal-BVssjame.woff2 +0 -0
- package/out/web/assets/sarabun-thai-500-normal-C3iDLEzi.woff +0 -0
- package/out/web/assets/sarabun-thai-600-normal-3dIAQ-_s.woff2 +0 -0
- package/out/web/assets/sarabun-thai-600-normal-DWKeTe6a.woff +0 -0
- package/out/web/assets/sarabun-vietnamese-400-normal-DPfkSCMy.woff +0 -0
- package/out/web/assets/sarabun-vietnamese-400-normal-igdrzAGY.woff2 +0 -0
- package/out/web/assets/sarabun-vietnamese-500-normal-CpRVvGRU.woff +0 -0
- package/out/web/assets/sarabun-vietnamese-500-normal-Dpe7Br9m.woff2 +0 -0
- package/out/web/assets/sarabun-vietnamese-600-normal-BMbOgAW-.woff +0 -0
- package/out/web/assets/sarabun-vietnamese-600-normal-DkxrOlLB.woff2 +0 -0
- package/out/web/assets/stateDiagram-v2-4QOOHH4V-s6P9g2_b.js +0 -1
- package/out/web/assets/swimlanesDiagram-VK2B7HYN-CV9fOLrV.js +0 -8
- package/out/web/assets/tauri-CNrHQ2Gb.js +0 -3
- package/out/web/assets/window-DkIhgI7B.js +0 -1
|
@@ -1,41 +1,34 @@
|
|
|
1
|
-
import { type ChangeEvent, type CSSProperties, type FormEvent, useEffect, useRef, useState } from 'react'
|
|
2
|
-
import { mergeActivitySnapshots, trimAgentProgress } from '../agentProgress'
|
|
1
|
+
import { lazy, Suspense, type ChangeEvent, type CSSProperties, type FormEvent, useCallback, useEffect, useRef, useState } from 'react'
|
|
3
2
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
saveInteractionAgentActivity,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
import ChatPanel from './ChatPanel'
|
|
3
|
+
compactAgentProgressForPersistence,
|
|
4
|
+
mergeActivitySnapshots,
|
|
5
|
+
mergeFileChanges,
|
|
6
|
+
parseFileChangesFromProgress,
|
|
7
|
+
} from '../agentProgress'
|
|
8
|
+
import { catalogPlatform, conversationPlatform, mediaPlatform, runtimePlatform, type SlashResponse } from '../platform'
|
|
9
|
+
import type { AgentProgress, ChatResponse, ChatSession, DocumentAttachment, PictureEntry, RuntimeStatus } from '../types'
|
|
10
|
+
|
|
11
|
+
const {
|
|
12
|
+
clearChatHistory, deleteChatSession, renameChatSession,
|
|
13
|
+
getConversationSnapshot, getConversationChanges,
|
|
14
|
+
saveSystemInteraction, listChatSessions, updateChatSessionWorkspace, saveInteractionAgentActivity, streamChatMessage,
|
|
15
|
+
cancelChatMessage, submitToolApproval, listen, readClipboardImage,
|
|
16
|
+
} = conversationPlatform
|
|
17
|
+
const { getRuntimeStatus, setActiveModel, selectWorkspaceDirectory, selectLinkedFolderPath, isTauriRuntime } = runtimePlatform
|
|
18
|
+
const { listSavedPictures, convertFileSrc } = mediaPlatform
|
|
19
|
+
const {
|
|
20
|
+
listLearnedSkills, addLearnedSkill, deleteLearnedSkill, detectSystemTools, reauthMcpServer,
|
|
21
|
+
listMcpServerTools, setProfileValue, listCronJobs, addCronJob, removeCronJob,
|
|
22
|
+
setCronJobEnabled, listLinkedFolders, addLinkedFolder, removeLinkedFolder, runSlashCommand,
|
|
23
|
+
linkedFolderStatus, refreshLinkedFolder, listLinkedFolderNotes, readLinkedFolderNote, openLinkedFolderNote,
|
|
24
|
+
} = catalogPlatform
|
|
25
|
+
|
|
26
|
+
import ChatPanel, { type ConversationActions, type ConversationViewModel } from './ChatPanel'
|
|
27
|
+
import ScreenCaptureDialog from './ScreenCaptureDialog'
|
|
31
28
|
import DashboardSidebar, { type DashboardView } from './DashboardSidebar'
|
|
32
|
-
import
|
|
33
|
-
import VeoStudioPanel from './VeoStudioPanel'
|
|
34
|
-
import ModelPanel from '@/components/ModelPanel'
|
|
29
|
+
import DesktopTitlebar from './DesktopTitlebar'
|
|
35
30
|
import type { ModelInteraction } from '@/components/ModelPanel'
|
|
36
|
-
import
|
|
37
|
-
import WorkspacePanel from '@/components/WorkspacePanel'
|
|
38
|
-
import { CommandPalette } from './CommandPalette'
|
|
31
|
+
import type { ToolSurface } from './ToolSurfacePage'
|
|
39
32
|
import {
|
|
40
33
|
errorMessage,
|
|
41
34
|
readImage,
|
|
@@ -46,6 +39,9 @@ import {
|
|
|
46
39
|
parseUtcDate,
|
|
47
40
|
} from '../utils/ui'
|
|
48
41
|
import { executeSlashCommand } from '../utils/slashCommandProcessor'
|
|
42
|
+
import { captureScreenForChat } from '../utils/screenCapture'
|
|
43
|
+
import { useConversationCoordinator } from '../conversation/useConversationCoordinator'
|
|
44
|
+
import { matchesActiveRun, matchesActiveSession } from '../conversation/syncView'
|
|
49
45
|
|
|
50
46
|
|
|
51
47
|
const EXPRESSIONS = [
|
|
@@ -64,13 +60,27 @@ const ACCESSORIES = [
|
|
|
64
60
|
"Hold Pen",
|
|
65
61
|
]
|
|
66
62
|
|
|
67
|
-
import { DEFAULT_CONFIG } from '../constants/config'
|
|
63
|
+
import { DEFAULT_CONFIG, migrateTypographyScale } from '../constants/config'
|
|
68
64
|
|
|
69
65
|
const LAST_WORKSPACE_PATH_KEY = 'mint:last-workspace-path'
|
|
66
|
+
const RECENT_WORKSPACE_PATHS_KEY = 'mint:recent-workspace-paths'
|
|
67
|
+
const MAX_RECENT_WORKSPACES = 8
|
|
70
68
|
const ACTIVE_CONVERSATION_ID_KEY = 'mint:active-conversation-id'
|
|
71
69
|
const LAST_ACTIVE_TIME_KEY = 'mint:last-active-timestamp'
|
|
72
70
|
const DESKTOP_INACTIVITY_THRESHOLD_MS = 30 * 60 * 1000 // 30 minutes
|
|
73
71
|
|
|
72
|
+
function readRecentWorkspacePaths(): string[] {
|
|
73
|
+
if (typeof window === 'undefined') return []
|
|
74
|
+
try {
|
|
75
|
+
const parsed: unknown = JSON.parse(window.localStorage.getItem(RECENT_WORKSPACE_PATHS_KEY) || '[]')
|
|
76
|
+
return Array.isArray(parsed)
|
|
77
|
+
? [...new Set(parsed.filter((path): path is string => typeof path === 'string' && Boolean(path.trim())))].slice(0, MAX_RECENT_WORKSPACES)
|
|
78
|
+
: []
|
|
79
|
+
} catch {
|
|
80
|
+
return []
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
74
84
|
function touchActiveTimestamp() {
|
|
75
85
|
if (typeof window === 'undefined') return
|
|
76
86
|
try {
|
|
@@ -103,25 +113,14 @@ function isDesktopRecentlyActive(): boolean {
|
|
|
103
113
|
// Unsent composer text, stashed per conversation so switching chats or
|
|
104
114
|
// reloading the page doesn't lose an in-progress message.
|
|
105
115
|
const DRAFT_KEY_PREFIX = 'mint:draft:'
|
|
106
|
-
const draftStorageKey = (id: string) => `${DRAFT_KEY_PREFIX}${id}`
|
|
107
116
|
function readDraft(id: string | null | undefined): string {
|
|
108
117
|
if (!id) return ''
|
|
109
118
|
try {
|
|
110
|
-
return window.localStorage.getItem(
|
|
119
|
+
return window.localStorage.getItem(`${DRAFT_KEY_PREFIX}${id}`) || ''
|
|
111
120
|
} catch {
|
|
112
121
|
return ''
|
|
113
122
|
}
|
|
114
123
|
}
|
|
115
|
-
function writeDraft(id: string | null | undefined, value: string) {
|
|
116
|
-
if (!id) return
|
|
117
|
-
try {
|
|
118
|
-
if (value) window.localStorage.setItem(draftStorageKey(id), value)
|
|
119
|
-
else window.localStorage.removeItem(draftStorageKey(id))
|
|
120
|
-
} catch {
|
|
121
|
-
/* private mode / quota — draft persistence is best-effort */
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
124
|
const SIDEBAR_DEFAULT_WIDTH = 264
|
|
126
125
|
const SIDEBAR_MIN_WIDTH = 200
|
|
127
126
|
const SIDEBAR_MAX_WIDTH = 420
|
|
@@ -172,6 +171,10 @@ function isRootOrNewChatRoute(): boolean {
|
|
|
172
171
|
target.includes('imagine') ||
|
|
173
172
|
target.includes('veo-studio') ||
|
|
174
173
|
target.includes('veo') ||
|
|
174
|
+
target.includes('code') ||
|
|
175
|
+
target === '/cli' ||
|
|
176
|
+
target === 'cli' ||
|
|
177
|
+
target.includes('cli-sessions') ||
|
|
175
178
|
target.includes('settings')
|
|
176
179
|
) {
|
|
177
180
|
return false
|
|
@@ -200,7 +203,7 @@ function activeConversationId() {
|
|
|
200
203
|
}
|
|
201
204
|
}
|
|
202
205
|
|
|
203
|
-
// When visiting Root URL ('/' or '/chat' without specific ID), always start a fresh New
|
|
206
|
+
// When visiting Root URL ('/' or '/chat' without specific ID), always start a fresh New chat
|
|
204
207
|
// (matching ChatGPT / Claude / Gemini industry-standard UX).
|
|
205
208
|
// Applies to Web UI always, and Desktop App upon cold launch / inactivity / new day.
|
|
206
209
|
if (isRootOrNewChatRoute()) {
|
|
@@ -234,31 +237,26 @@ const MOCK_WELCOME_INTERACTION = {
|
|
|
234
237
|
}
|
|
235
238
|
|
|
236
239
|
|
|
237
|
-
import SkillsView from './SkillsView'
|
|
238
|
-
import ScheduledTasksView from './ScheduledTasksView'
|
|
239
|
-
import LinkedFoldersView from './LinkedFoldersView'
|
|
240
|
-
import McpServersView from './McpServersView'
|
|
241
|
-
import PluginsView from './PluginsView'
|
|
242
240
|
import { isSupportedDocument } from '../utils/documentTypes'
|
|
243
241
|
import { useCompanionWidget } from '@/companionWidget'
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}
|
|
261
|
-
|
|
242
|
+
|
|
243
|
+
const ModelPanel = lazy(() => import('@/components/ModelPanel'))
|
|
244
|
+
const WorkspacePanel = lazy(() => import('@/components/WorkspacePanel'))
|
|
245
|
+
const ToolSurfacePage = lazy(() => import('./ToolSurfacePage'))
|
|
246
|
+
const SkillsView = lazy(() => import('./SkillsView'))
|
|
247
|
+
const ScheduledTasksView = lazy(() => import('./ScheduledTasksView'))
|
|
248
|
+
const LinkedFoldersView = lazy(() => import('./LinkedFoldersView'))
|
|
249
|
+
const McpServersView = lazy(() => import('./McpServersView'))
|
|
250
|
+
const PluginsView = lazy(() => import('./PluginsView'))
|
|
251
|
+
const CliSessionsView = lazy(() => import('./CliSessionsView'))
|
|
252
|
+
const PicturesLibrary = lazy(() => import('@/components/PicturesLibrary'))
|
|
253
|
+
const ImageStudioPanel = lazy(() => import('./ImageStudioPanel'))
|
|
254
|
+
const VeoStudioPanel = lazy(() => import('./VeoStudioPanel'))
|
|
255
|
+
const CommandPalette = lazy(() => import('./CommandPalette').then(({ CommandPalette: Component }) => ({ default: Component })))
|
|
256
|
+
|
|
257
|
+
function LazyPanelFallback() {
|
|
258
|
+
return <div className="auth-gate-loading" style={{ minHeight: 160 }}>Loading panel…</div>
|
|
259
|
+
}
|
|
262
260
|
|
|
263
261
|
function getInitialViewFromUrl(): DashboardView {
|
|
264
262
|
if (typeof window === 'undefined') return 'chat'
|
|
@@ -272,6 +270,7 @@ function getInitialViewFromUrl(): DashboardView {
|
|
|
272
270
|
if (target.includes('picture')) return 'pictures'
|
|
273
271
|
if (target.includes('image-studio') || target.includes('imagine')) return 'imagine'
|
|
274
272
|
if (target.includes('veo-studio') || target.includes('veo')) return 'veo'
|
|
273
|
+
if (target.includes('code') || target === '/cli' || target === 'cli' || target.includes('cli-sessions')) return 'code'
|
|
275
274
|
return 'chat'
|
|
276
275
|
}
|
|
277
276
|
|
|
@@ -282,6 +281,7 @@ function getCleanPathForView(v: string, activeId?: string): string {
|
|
|
282
281
|
if (v === 'pictures') return '/pictures'
|
|
283
282
|
if (v === 'imagine') return '/image-studio'
|
|
284
283
|
if (v === 'veo' || v === 'veo_studio') return '/veo-studio'
|
|
284
|
+
if (v === 'code') return '/code'
|
|
285
285
|
if (v === 'settings') return '/settings'
|
|
286
286
|
if (activeId) return `/chat/${encodeURIComponent(activeId)}`
|
|
287
287
|
return '/chat'
|
|
@@ -331,13 +331,103 @@ export default function MintDashboard() {
|
|
|
331
331
|
const [view, setViewState] = useState<DashboardView>(getInitialViewFromUrl)
|
|
332
332
|
const [conversationId, setConversationId] = useState(activeConversationId)
|
|
333
333
|
// Declared here (not further down with the rest of the workspace-related
|
|
334
|
-
// state) so the URL-change effect below can read it
|
|
335
|
-
|
|
336
|
-
|
|
334
|
+
// state) so the URL-change effect below can read it.
|
|
335
|
+
const { conversation, actions: conversationActions } = useConversationCoordinator(
|
|
336
|
+
{
|
|
337
|
+
workspacePath: window.localStorage.getItem(LAST_WORKSPACE_PATH_KEY) || '',
|
|
338
|
+
message: readDraft(conversationId),
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
conversationId,
|
|
342
|
+
draftKeyPrefix: DRAFT_KEY_PREFIX,
|
|
343
|
+
workspaceStorageKey: LAST_WORKSPACE_PATH_KEY,
|
|
344
|
+
},
|
|
345
|
+
)
|
|
346
|
+
const {
|
|
347
|
+
workspacePath, message, imageAttachments, videoAttachments, documentAttachment,
|
|
348
|
+
sending, sendingMessage, sendingImageCount, sendingVideoCount, streamedReply,
|
|
349
|
+
streamedResponse, agentProgress,
|
|
350
|
+
} = conversation
|
|
351
|
+
const activeConversationRef = useRef(conversationId)
|
|
352
|
+
const sessionGenerationRef = useRef(0)
|
|
353
|
+
const runGenerationRef = useRef(0)
|
|
354
|
+
const conversationCursorRef = useRef<{ chatId: string; cursor: number } | null>(null)
|
|
355
|
+
const historyLoadSerialRef = useRef(0)
|
|
356
|
+
const [pendingApprovals, setPendingApprovals] = useState<Record<string, { token: string; approval: any }>>({})
|
|
357
|
+
const autoApprovedChatIdRef = useRef<string | null>(null)
|
|
358
|
+
const isCurrentSession = (chatId: string, generation: number) => matchesActiveSession(
|
|
359
|
+
{ chatId, generation },
|
|
360
|
+
{ chatId: activeConversationRef.current, generation: sessionGenerationRef.current },
|
|
361
|
+
)
|
|
362
|
+
const activateConversation = (id: string) => {
|
|
363
|
+
if (activeConversationRef.current !== id) {
|
|
364
|
+
activeConversationRef.current = id
|
|
365
|
+
sessionGenerationRef.current += 1
|
|
366
|
+
runGenerationRef.current += 1
|
|
367
|
+
conversationCursorRef.current = null
|
|
368
|
+
setInteractions([])
|
|
369
|
+
setHasOlderInteractions(false)
|
|
370
|
+
setAgentActivitySnapshots({})
|
|
371
|
+
setStreamingConversationId(null)
|
|
372
|
+
setActiveTurnId(null)
|
|
373
|
+
}
|
|
374
|
+
setConversationId(id)
|
|
375
|
+
}
|
|
376
|
+
async function loadConversationHistory(chatId: string, generation: number) {
|
|
377
|
+
const serial = ++historyLoadSerialRef.current
|
|
378
|
+
const snapshot = await getConversationSnapshot(chatId, null, 50)
|
|
379
|
+
if (!isCurrentSession(chatId, generation) || serial !== historyLoadSerialRef.current) return
|
|
380
|
+
const currentCursor = conversationCursorRef.current
|
|
381
|
+
if (currentCursor?.chatId === chatId && currentCursor.cursor > snapshot.cursor) return
|
|
382
|
+
conversationCursorRef.current = { chatId, cursor: snapshot.cursor }
|
|
383
|
+
setInteractions((current) => {
|
|
384
|
+
if (!isCurrentSession(chatId, generation) || serial !== historyLoadSerialRef.current) return current
|
|
385
|
+
if (conversationCursorRef.current?.chatId === chatId
|
|
386
|
+
&& conversationCursorRef.current.cursor > snapshot.cursor) return current
|
|
387
|
+
return snapshot.interactions
|
|
388
|
+
})
|
|
389
|
+
setHasOlderInteractions((current) => {
|
|
390
|
+
if (!isCurrentSession(chatId, generation) || serial !== historyLoadSerialRef.current) return current
|
|
391
|
+
if (conversationCursorRef.current?.chatId === chatId
|
|
392
|
+
&& conversationCursorRef.current.cursor > snapshot.cursor) return current
|
|
393
|
+
return snapshot.hasOlder
|
|
394
|
+
})
|
|
395
|
+
setAgentActivitySnapshots((current) => {
|
|
396
|
+
if (!isCurrentSession(chatId, generation) || serial !== historyLoadSerialRef.current) return current
|
|
397
|
+
if (conversationCursorRef.current?.chatId === chatId
|
|
398
|
+
&& conversationCursorRef.current.cursor > snapshot.cursor) return current
|
|
399
|
+
return mergeActivitySnapshots(current, snapshot.interactions)
|
|
400
|
+
})
|
|
401
|
+
}
|
|
337
402
|
// Web only in practice (desktop's window has no mobile-width breakpoint,
|
|
338
403
|
// so nothing ever sets this true there) — declared unconditionally so
|
|
339
404
|
// `changeView` can close it on every navigation without branching.
|
|
340
405
|
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false)
|
|
406
|
+
const [screenCaptureOpen, setScreenCaptureOpen] = useState(false)
|
|
407
|
+
|
|
408
|
+
useEffect(() => {
|
|
409
|
+
if (!mobileSidebarOpen) return
|
|
410
|
+
const closeOnEscape = (event: KeyboardEvent) => {
|
|
411
|
+
if (event.key === 'Escape') setMobileSidebarOpen(false)
|
|
412
|
+
}
|
|
413
|
+
window.addEventListener('keydown', closeOnEscape)
|
|
414
|
+
return () => window.removeEventListener('keydown', closeOnEscape)
|
|
415
|
+
}, [mobileSidebarOpen])
|
|
416
|
+
const [workspaceRefreshRevision, setWorkspaceRefreshRevision] = useState(0)
|
|
417
|
+
const [recentWorkspacePaths, setRecentWorkspacePaths] = useState<string[]>(readRecentWorkspacePaths)
|
|
418
|
+
|
|
419
|
+
useEffect(() => {
|
|
420
|
+
const currentPath = workspacePath.trim()
|
|
421
|
+
if (!currentPath) return
|
|
422
|
+
const recent = [currentPath, ...readRecentWorkspacePaths().filter((path) => path !== currentPath)]
|
|
423
|
+
.slice(0, MAX_RECENT_WORKSPACES)
|
|
424
|
+
try {
|
|
425
|
+
window.localStorage.setItem(RECENT_WORKSPACE_PATHS_KEY, JSON.stringify(recent))
|
|
426
|
+
} catch {
|
|
427
|
+
/* Keep the in-memory recent list usable when storage is unavailable. */
|
|
428
|
+
}
|
|
429
|
+
setRecentWorkspacePaths(recent)
|
|
430
|
+
}, [workspacePath])
|
|
341
431
|
|
|
342
432
|
const changeView = (newView: any, targetConversationId?: string) => {
|
|
343
433
|
setMobileSidebarOpen(false)
|
|
@@ -376,23 +466,17 @@ export default function MintDashboard() {
|
|
|
376
466
|
const urlSessionId = getConversationIdFromUrl()
|
|
377
467
|
if (urlSessionId && urlSessionId !== conversationId) {
|
|
378
468
|
window.localStorage.setItem(ACTIVE_CONVERSATION_ID_KEY, urlSessionId)
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
setAgentActivitySnapshots((current) => mergeActivitySnapshots(current, reversed))
|
|
469
|
+
activateConversation(urlSessionId)
|
|
470
|
+
const generation = sessionGenerationRef.current
|
|
471
|
+
loadConversationHistory(urlSessionId, generation).catch((error) => {
|
|
472
|
+
console.error('Failed to load conversation history:', error)
|
|
384
473
|
})
|
|
385
474
|
} else if (!urlSessionId && isRootOrNewChatRoute()) {
|
|
386
475
|
const next = createConversationId()
|
|
387
|
-
|
|
476
|
+
activateConversation(next)
|
|
388
477
|
setInteractions([])
|
|
389
478
|
setAgentActivitySnapshots({})
|
|
390
|
-
|
|
391
|
-
setStreamedResponse(null)
|
|
392
|
-
setMessage('')
|
|
393
|
-
setImageAttachments([])
|
|
394
|
-
setDocumentAttachment(null)
|
|
395
|
-
setAgentProgress([])
|
|
479
|
+
conversationActions.switchSession()
|
|
396
480
|
}
|
|
397
481
|
}
|
|
398
482
|
window.addEventListener('popstate', handleUrlChange)
|
|
@@ -417,36 +501,47 @@ export default function MintDashboard() {
|
|
|
417
501
|
}, [])
|
|
418
502
|
const [status, setStatus] = useState<RuntimeStatus | null>(null)
|
|
419
503
|
const [error, setError] = useState('')
|
|
420
|
-
const [message, setMessage] = useState(() => readDraft(conversationId))
|
|
421
504
|
// When `conversationId` changes we swap `message` to that chat's saved draft;
|
|
422
505
|
// this ref tells the persist effect to skip the render right after that swap,
|
|
423
506
|
// so the outgoing chat's text is never written under the incoming chat's key.
|
|
424
|
-
const skipDraftPersistRef = useRef(false)
|
|
425
507
|
const [interactions, setInteractions] = useState<any[]>([])
|
|
508
|
+
const [hasOlderInteractions, setHasOlderInteractions] = useState(false)
|
|
426
509
|
const [pictures, setPictures] = useState<PictureEntry[]>([])
|
|
427
|
-
const [sending, setSending] = useState(false)
|
|
428
|
-
const [sendingMessage, setSendingMessage] = useState('')
|
|
429
|
-
const [sendingImageCount, setSendingImageCount] = useState(0)
|
|
430
|
-
const [sendingVideoCount, setSendingVideoCount] = useState(0)
|
|
431
|
-
const [streamedReply, setStreamedReply] = useState('')
|
|
432
|
-
const [streamedResponse, setStreamedResponse] = useState<ChatResponse | null>(null)
|
|
433
510
|
const [streamingConversationId, setStreamingConversationId] = useState<string | null>(null)
|
|
434
|
-
const [
|
|
511
|
+
const [activeTurnId, setActiveTurnId] = useState<number | null>(null)
|
|
435
512
|
const [agentActivitySnapshots, setAgentActivitySnapshots] = useState<Record<string, AgentProgress[]>>({})
|
|
436
513
|
const [thinkingExpanded, setThinkingExpanded] = useState<Record<string, boolean>>({})
|
|
437
514
|
const liveThinkingOpenRef = useRef(true)
|
|
438
|
-
const
|
|
439
|
-
const [videoAttachments, setVideoAttachments] = useState<Array<{ dataUri: string; name: string }>>([])
|
|
440
|
-
const [documentAttachment, setDocumentAttachment] = useState<DocumentAttachment | null>(null)
|
|
441
|
-
const [pendingApproval, setPendingApproval] = useState<any | null>(null)
|
|
515
|
+
const liveExtendedThinkingOpenRef = useRef(true)
|
|
442
516
|
const [sessionAutoApproved, setSessionAutoApproved] = useState(false)
|
|
443
517
|
const sessionAutoApprovedRef = useRef(false)
|
|
444
518
|
const [sidebarCollapsed, setSidebarCollapsed] = useState(() => window.localStorage.getItem('mint:sidebar-collapsed') === 'true')
|
|
519
|
+
const [toolSurfaces, setToolSurfaces] = useState<ToolSurface[]>([])
|
|
520
|
+
const [activeSurfaceId, setActiveSurfaceId] = useState<string | null>(null)
|
|
521
|
+
const [toolsPanelOpen, setToolsPanelOpen] = useState(false)
|
|
522
|
+
const [terminalRightWidth, setTerminalRightWidth] = useState(() => {
|
|
523
|
+
const saved = Number(window.localStorage.getItem('mint:terminal-right-width'))
|
|
524
|
+
return saved >= 280 && saved <= 900 ? saved : 440
|
|
525
|
+
})
|
|
526
|
+
const terminalSaveTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
|
445
527
|
const [sidebarWidth, setSidebarWidth] = useState(() => {
|
|
446
528
|
const saved = Number(window.localStorage.getItem('mint:sidebar-width'))
|
|
447
529
|
return saved >= SIDEBAR_MIN_WIDTH && saved <= SIDEBAR_MAX_WIDTH ? saved : SIDEBAR_DEFAULT_WIDTH
|
|
448
530
|
})
|
|
449
|
-
const
|
|
531
|
+
const recentAgentChanges = parseFileChangesFromProgress(agentProgress)
|
|
532
|
+
const conversationReviewChanges = mergeFileChanges([
|
|
533
|
+
...interactions.map((interaction) => {
|
|
534
|
+
const interactionId = String(interaction.id)
|
|
535
|
+
return parseFileChangesFromProgress(agentActivitySnapshots[interactionId] ?? interaction.agentActivity ?? [])
|
|
536
|
+
}),
|
|
537
|
+
parseFileChangesFromProgress(agentProgress),
|
|
538
|
+
])
|
|
539
|
+
const workspaceSourceNames = [
|
|
540
|
+
...imageAttachments.map((attachment) => attachment.name),
|
|
541
|
+
...videoAttachments.map((attachment) => attachment.name),
|
|
542
|
+
documentAttachment?.filename || '',
|
|
543
|
+
]
|
|
544
|
+
|
|
450
545
|
const [agentMode, setAgentMode] = useState(() => window.localStorage.getItem('mint:agent-mode') === 'true')
|
|
451
546
|
const [planMode, setPlanMode] = useState(() => window.localStorage.getItem('mint:plan-mode') === 'true')
|
|
452
547
|
const [toastMessage, setToastMessage] = useState('')
|
|
@@ -598,55 +693,109 @@ export default function MintDashboard() {
|
|
|
598
693
|
// than the effect's own dependency array so a poll landing doesn't tear
|
|
599
694
|
// down and recreate the interval on every tick.
|
|
600
695
|
const interactionsRef = useRef(interactions)
|
|
696
|
+
const chatPollInFlightRef = useRef<{ chatId: string; generation: number } | null>(null)
|
|
601
697
|
useEffect(() => {
|
|
602
698
|
interactionsRef.current = interactions
|
|
603
699
|
}, [interactions])
|
|
700
|
+
useEffect(() => {
|
|
701
|
+
if (interactions.length === 0) setHasOlderInteractions(false)
|
|
702
|
+
}, [interactions.length])
|
|
604
703
|
|
|
605
704
|
// Load the saved draft whenever the active conversation changes. Declared
|
|
606
705
|
// before the persist effect so it runs first within the same commit. The
|
|
607
706
|
// first run is a no-op: `message`'s initial value already came from the
|
|
608
707
|
// lazy `useState` initializer above.
|
|
609
|
-
const draftLoadedRef = useRef(false)
|
|
610
|
-
useEffect(() => {
|
|
611
|
-
if (!draftLoadedRef.current) {
|
|
612
|
-
draftLoadedRef.current = true
|
|
613
|
-
return
|
|
614
|
-
}
|
|
615
|
-
skipDraftPersistRef.current = true
|
|
616
|
-
setMessage(readDraft(conversationId))
|
|
617
|
-
}, [conversationId])
|
|
618
|
-
|
|
619
|
-
// Persist the composer text for the current conversation (debounced).
|
|
620
|
-
useEffect(() => {
|
|
621
|
-
if (skipDraftPersistRef.current) {
|
|
622
|
-
skipDraftPersistRef.current = false
|
|
623
|
-
return
|
|
624
|
-
}
|
|
625
|
-
const timer = window.setTimeout(() => writeDraft(conversationId, message), 300)
|
|
626
|
-
return () => window.clearTimeout(timer)
|
|
627
|
-
}, [message, conversationId])
|
|
628
|
-
|
|
629
708
|
useEffect(() => {
|
|
630
709
|
if (view !== 'chat' || !conversationId) return
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
710
|
+
let disposed = false
|
|
711
|
+
const generation = sessionGenerationRef.current
|
|
712
|
+
const isCurrent = () => !disposed && isCurrentSession(conversationId, generation)
|
|
713
|
+
const syncHistory = async () => {
|
|
714
|
+
// A shared SQLite database has no cross-process event bus. Refresh as
|
|
715
|
+
// soon as the user returns, but avoid work while hidden or overlapping
|
|
716
|
+
// a slow read with the next polling tick.
|
|
717
|
+
if (
|
|
718
|
+
!isCurrent() ||
|
|
719
|
+
document.visibilityState !== 'visible' ||
|
|
720
|
+
(chatPollInFlightRef.current?.chatId === conversationId
|
|
721
|
+
&& chatPollInFlightRef.current.generation === generation)
|
|
722
|
+
) return
|
|
723
|
+
|
|
724
|
+
const poll = { chatId: conversationId, generation }
|
|
725
|
+
chatPollInFlightRef.current = poll
|
|
636
726
|
try {
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
727
|
+
if (conversationCursorRef.current?.chatId !== conversationId) {
|
|
728
|
+
await loadConversationHistory(conversationId, generation)
|
|
729
|
+
return
|
|
730
|
+
}
|
|
731
|
+
let cursor = conversationCursorRef.current.cursor
|
|
732
|
+
let changed = false
|
|
733
|
+
for (let page = 0; page < 10; page++) {
|
|
734
|
+
const batch = await getConversationChanges(conversationId, cursor, 100)
|
|
735
|
+
if (!isCurrent()) return
|
|
736
|
+
if (conversationCursorRef.current?.chatId === conversationId
|
|
737
|
+
&& conversationCursorRef.current.cursor > batch.cursor) return
|
|
738
|
+
cursor = batch.cursor
|
|
739
|
+
if (batch.changes.length > 0) {
|
|
740
|
+
changed = true
|
|
741
|
+
setInteractions((current) => {
|
|
742
|
+
if (!isCurrent()) return current
|
|
743
|
+
if (conversationCursorRef.current?.chatId === conversationId
|
|
744
|
+
&& conversationCursorRef.current.cursor > batch.cursor) return current
|
|
745
|
+
const byId = new Map(current.map((interaction) => [interaction.id, interaction]))
|
|
746
|
+
for (const change of batch.changes) {
|
|
747
|
+
if (change.interaction) byId.set(change.interactionId, change.interaction)
|
|
748
|
+
else byId.delete(change.interactionId)
|
|
749
|
+
}
|
|
750
|
+
return Array.from(byId.values()).sort((a, b) => a.id - b.id)
|
|
751
|
+
})
|
|
752
|
+
setAgentActivitySnapshots((current) => {
|
|
753
|
+
if (!isCurrent()) return current
|
|
754
|
+
if (conversationCursorRef.current?.chatId === conversationId
|
|
755
|
+
&& conversationCursorRef.current.cursor > batch.cursor) return current
|
|
756
|
+
const merged = { ...current }
|
|
757
|
+
for (const change of batch.changes) {
|
|
758
|
+
const key = String(change.interactionId)
|
|
759
|
+
if (change.interaction) {
|
|
760
|
+
if (change.interaction.agentActivity && Array.isArray(change.interaction.agentActivity)) {
|
|
761
|
+
merged[key] = change.interaction.agentActivity
|
|
762
|
+
}
|
|
763
|
+
} else {
|
|
764
|
+
delete merged[key]
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
return merged
|
|
768
|
+
})
|
|
769
|
+
}
|
|
770
|
+
if (!batch.hasMore) break
|
|
771
|
+
}
|
|
772
|
+
if (conversationCursorRef.current?.chatId === conversationId
|
|
773
|
+
&& conversationCursorRef.current.cursor > cursor) return
|
|
774
|
+
conversationCursorRef.current = { chatId: conversationId, cursor }
|
|
775
|
+
if (changed) {
|
|
776
|
+
const sessions = await listChatSessions()
|
|
777
|
+
if (isCurrent()) setChatSessions(sessions)
|
|
778
|
+
}
|
|
644
779
|
} catch {
|
|
645
780
|
// Best-effort — a transient fetch failure just waits for the next tick.
|
|
781
|
+
} finally {
|
|
782
|
+
if (chatPollInFlightRef.current === poll) chatPollInFlightRef.current = null
|
|
646
783
|
}
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
const syncWhenActive = () => { void syncHistory() }
|
|
787
|
+
syncWhenActive()
|
|
788
|
+
window.addEventListener('focus', syncWhenActive)
|
|
789
|
+
document.addEventListener('visibilitychange', syncWhenActive)
|
|
790
|
+
const interval = window.setInterval(syncWhenActive, 1500)
|
|
791
|
+
|
|
792
|
+
return () => {
|
|
793
|
+
disposed = true
|
|
794
|
+
window.clearInterval(interval)
|
|
795
|
+
window.removeEventListener('focus', syncWhenActive)
|
|
796
|
+
document.removeEventListener('visibilitychange', syncWhenActive)
|
|
797
|
+
}
|
|
798
|
+
}, [view, conversationId, workspacePath])
|
|
650
799
|
|
|
651
800
|
const filteredSessions = chatSessions.filter((session) => {
|
|
652
801
|
if (session.kind === 'cli' || session.id === 'conversation-default') return false
|
|
@@ -700,16 +849,81 @@ export default function MintDashboard() {
|
|
|
700
849
|
|
|
701
850
|
|
|
702
851
|
async function refreshHistory() {
|
|
703
|
-
const
|
|
704
|
-
const
|
|
705
|
-
|
|
706
|
-
setAgentActivitySnapshots((current) => mergeActivitySnapshots(current, reversed))
|
|
852
|
+
const chatId = conversationId
|
|
853
|
+
const generation = sessionGenerationRef.current
|
|
854
|
+
await loadConversationHistory(chatId, generation)
|
|
707
855
|
}
|
|
708
856
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
857
|
+
const refreshChatSessions = useCallback(async () => {
|
|
858
|
+
try {
|
|
859
|
+
const sessions = await listChatSessions()
|
|
860
|
+
setChatSessions((prev) => {
|
|
861
|
+
if (
|
|
862
|
+
prev.length === sessions.length &&
|
|
863
|
+
prev.every(
|
|
864
|
+
(s, i) =>
|
|
865
|
+
s.id === sessions[i]?.id &&
|
|
866
|
+
s.updatedAt === sessions[i]?.updatedAt &&
|
|
867
|
+
s.title === sessions[i]?.title &&
|
|
868
|
+
s.messageCount === sessions[i]?.messageCount &&
|
|
869
|
+
s.totalBytes === sessions[i]?.totalBytes
|
|
870
|
+
)
|
|
871
|
+
) {
|
|
872
|
+
return prev
|
|
873
|
+
}
|
|
874
|
+
return sessions
|
|
875
|
+
})
|
|
876
|
+
} catch (e) {
|
|
877
|
+
console.error('Failed to refresh chat sessions:', e)
|
|
878
|
+
}
|
|
879
|
+
}, [])
|
|
880
|
+
|
|
881
|
+
useEffect(() => {
|
|
882
|
+
const refreshVisible = () => {
|
|
883
|
+
if (document.visibilityState === 'visible') void refreshChatSessions()
|
|
884
|
+
}
|
|
885
|
+
const interval = window.setInterval(refreshVisible, 5000)
|
|
886
|
+
window.addEventListener('focus', refreshVisible)
|
|
887
|
+
document.addEventListener('visibilitychange', refreshVisible)
|
|
888
|
+
return () => {
|
|
889
|
+
window.clearInterval(interval)
|
|
890
|
+
window.removeEventListener('focus', refreshVisible)
|
|
891
|
+
document.removeEventListener('visibilitychange', refreshVisible)
|
|
892
|
+
}
|
|
893
|
+
}, [refreshChatSessions])
|
|
894
|
+
|
|
895
|
+
const loadOlderInteractions = useCallback(async () => {
|
|
896
|
+
const generation = sessionGenerationRef.current
|
|
897
|
+
const firstId = interactionsRef.current[0]?.id
|
|
898
|
+
if (firstId == null) return
|
|
899
|
+
const page = await getConversationSnapshot(conversationId, firstId, 50)
|
|
900
|
+
if (!isCurrentSession(conversationId, generation)) return
|
|
901
|
+
setHasOlderInteractions(page.hasOlder)
|
|
902
|
+
if (page.interactions.length === 0) return
|
|
903
|
+
setInteractions((current) => {
|
|
904
|
+
if (!isCurrentSession(conversationId, generation)) return current
|
|
905
|
+
const byId = new Map([...page.interactions, ...current].map((interaction) => [interaction.id, interaction]))
|
|
906
|
+
return Array.from(byId.values()).sort((a, b) => a.id - b.id)
|
|
907
|
+
})
|
|
908
|
+
}, [conversationId])
|
|
909
|
+
|
|
910
|
+
const handleUpdateSessionWorkspace = useCallback(async (sessionId: string, targetPath: string | null) => {
|
|
911
|
+
try {
|
|
912
|
+
await updateChatSessionWorkspace(sessionId, targetPath)
|
|
913
|
+
await refreshChatSessions()
|
|
914
|
+
} catch (e) {
|
|
915
|
+
console.error('Failed to update session workspace:', e)
|
|
916
|
+
}
|
|
917
|
+
}, [refreshChatSessions])
|
|
918
|
+
|
|
919
|
+
const handleBrowseFolderForMove = useCallback(async () => {
|
|
920
|
+
try {
|
|
921
|
+
const selected = await selectWorkspaceDirectory()
|
|
922
|
+
return selected || null
|
|
923
|
+
} catch {
|
|
924
|
+
return null
|
|
925
|
+
}
|
|
926
|
+
}, [])
|
|
713
927
|
|
|
714
928
|
const [picturesRefreshing, setPicturesRefreshing] = useState(false)
|
|
715
929
|
|
|
@@ -729,8 +943,9 @@ export default function MintDashboard() {
|
|
|
729
943
|
refreshChatSessions(),
|
|
730
944
|
window.settingsApi?.getSettings()
|
|
731
945
|
.then((loaded: any) => {
|
|
732
|
-
|
|
733
|
-
|
|
946
|
+
const migrated = migrateTypographyScale(loaded)
|
|
947
|
+
setSettingsConfig(migrated)
|
|
948
|
+
applyThemeStyles({ ...DEFAULT_CONFIG, ...migrated })
|
|
734
949
|
}),
|
|
735
950
|
]).then((results) => {
|
|
736
951
|
const failure = results.find((result) => result.status === 'rejected')
|
|
@@ -739,21 +954,22 @@ export default function MintDashboard() {
|
|
|
739
954
|
})
|
|
740
955
|
const unlistenSpotlight = window.api.onSpotlightToChat((query) => {
|
|
741
956
|
changeView('chat')
|
|
742
|
-
|
|
957
|
+
conversationActions.compose(query)
|
|
743
958
|
})
|
|
744
959
|
const unlistenVision = window.api.onVisionReady((image) => {
|
|
745
960
|
createTrimmedImagePreview(image)
|
|
746
961
|
.catch(() => image)
|
|
747
962
|
.then((previewDataUri) => {
|
|
748
|
-
|
|
963
|
+
conversationActions.attachImage({ dataUri: image, previewDataUri, name: 'Screen capture' })
|
|
749
964
|
})
|
|
750
965
|
})
|
|
751
966
|
const handleWindowFocus = () => {
|
|
752
967
|
getRuntimeStatus().then(setStatus).catch(() => {})
|
|
753
968
|
window.settingsApi?.getSettings?.().then((loaded: any) => {
|
|
754
969
|
if (loaded) {
|
|
755
|
-
|
|
756
|
-
|
|
970
|
+
const migrated = migrateTypographyScale(loaded)
|
|
971
|
+
setSettingsConfig(migrated)
|
|
972
|
+
applyThemeStyles(migrated)
|
|
757
973
|
}
|
|
758
974
|
}).catch(() => {})
|
|
759
975
|
window.api?.clearAiNotifications?.()
|
|
@@ -761,18 +977,21 @@ export default function MintDashboard() {
|
|
|
761
977
|
window.addEventListener('focus', handleWindowFocus)
|
|
762
978
|
|
|
763
979
|
window.api?.onSettingsChanged?.((loaded: any) => {
|
|
764
|
-
|
|
765
|
-
|
|
980
|
+
const migrated = migrateTypographyScale(loaded)
|
|
981
|
+
setSettingsConfig(migrated)
|
|
982
|
+
applyThemeStyles(migrated)
|
|
766
983
|
getRuntimeStatus().then(setStatus).catch(() => {})
|
|
767
984
|
})
|
|
768
985
|
|
|
769
|
-
const unlistenPromise = listen
|
|
770
|
-
|
|
986
|
+
const unlistenPromise = listen('tool-approval-requested', (event: { payload: any }) => {
|
|
987
|
+
const chatId = event.payload.chatId as string | undefined
|
|
988
|
+
if (!chatId) return
|
|
989
|
+
if (sessionAutoApprovedRef.current && autoApprovedChatIdRef.current === chatId) {
|
|
771
990
|
submitToolApproval(event.payload.token, true).catch((err) => {
|
|
772
991
|
console.error("Auto approval failed:", err)
|
|
773
992
|
})
|
|
774
993
|
} else {
|
|
775
|
-
|
|
994
|
+
setPendingApprovals((current) => ({ ...current, [chatId]: event.payload }))
|
|
776
995
|
notifyPendingApproval(event.payload)
|
|
777
996
|
}
|
|
778
997
|
})
|
|
@@ -797,15 +1016,145 @@ export default function MintDashboard() {
|
|
|
797
1016
|
if (view === 'workspace' && !agentMode) updateAgentMode(true)
|
|
798
1017
|
}, [view, agentMode])
|
|
799
1018
|
|
|
800
|
-
useEffect(() => {
|
|
801
|
-
chatEnd.current?.scrollIntoView({ behavior: 'smooth' })
|
|
802
|
-
}, [interactions, sending, streamedReply, pendingApproval, agentProgress])
|
|
803
|
-
|
|
804
1019
|
const showToast = (nextMessage: string) => {
|
|
805
1020
|
setToastMessage(nextMessage)
|
|
806
1021
|
setTimeout(() => setToastMessage((current) => current === nextMessage ? '' : current), 3000)
|
|
807
1022
|
}
|
|
808
1023
|
|
|
1024
|
+
const openMintBrowser = async (url: string) => {
|
|
1025
|
+
if (!isDesktopApp) {
|
|
1026
|
+
window.open(url, '_blank', 'noopener,noreferrer')
|
|
1027
|
+
return
|
|
1028
|
+
}
|
|
1029
|
+
try {
|
|
1030
|
+
showToast('Opening Co-browsing browser (Mint Auto)...')
|
|
1031
|
+
const { invoke } = await import('@tauri-apps/api/core')
|
|
1032
|
+
await invoke('open_mint_browser', { url })
|
|
1033
|
+
} catch (error) {
|
|
1034
|
+
showToast(`Could not open browser: ${String(error)}`)
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
const openTerminalSurface = () => {
|
|
1039
|
+
setToolsPanelOpen(true)
|
|
1040
|
+
const id = `terminal:${Date.now()}:${Math.random().toString(36).slice(2, 7)}`
|
|
1041
|
+
setToolSurfaces((current) => {
|
|
1042
|
+
const terminalCount = current.filter((surface) => surface.kind === 'terminal').length
|
|
1043
|
+
let baseTitle = 'terminal'
|
|
1044
|
+
if (workspacePath && workspacePath.trim()) {
|
|
1045
|
+
const cleanPath = workspacePath.trim().replace(/[\\/]+$/, '')
|
|
1046
|
+
const folderName = cleanPath.split(/[\\/]/).pop()
|
|
1047
|
+
if (folderName) baseTitle = folderName
|
|
1048
|
+
}
|
|
1049
|
+
const title = terminalCount === 0 ? baseTitle : `${baseTitle} (${terminalCount + 1})`
|
|
1050
|
+
const next = { id, kind: 'terminal' as const, title }
|
|
1051
|
+
setActiveSurfaceId(id)
|
|
1052
|
+
return [...current, next]
|
|
1053
|
+
})
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
const openNativeBrowser = (url = 'https://www.google.com') => {
|
|
1057
|
+
void openMintBrowser(url)
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
const duplicateToolSurface = (id: string) => {
|
|
1061
|
+
setToolSurfaces((current) => {
|
|
1062
|
+
const source = current.find((surface) => surface.id === id)
|
|
1063
|
+
if (!source) return current
|
|
1064
|
+
const duplicateId = `${source.kind}:${Date.now()}:${Math.random().toString(36).slice(2, 7)}`
|
|
1065
|
+
const duplicate = { ...source, id: duplicateId, title: `${source.title} copy` } as ToolSurface
|
|
1066
|
+
setActiveSurfaceId(duplicateId)
|
|
1067
|
+
return [...current, duplicate]
|
|
1068
|
+
})
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
const renameToolSurface = (id: string) => {
|
|
1072
|
+
const source = toolSurfaces.find((surface) => surface.id === id)
|
|
1073
|
+
if (!source) return
|
|
1074
|
+
const nextTitle = window.prompt('Rename tab', source.title)?.trim()
|
|
1075
|
+
if (!nextTitle) return
|
|
1076
|
+
setToolSurfaces((current) => current.map((surface) => surface.id === id ? { ...surface, title: nextTitle } : surface))
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
const closeOtherToolSurfaces = (id: string) => {
|
|
1080
|
+
setToolSurfaces((current) => current.filter((surface) => surface.id === id))
|
|
1081
|
+
setActiveSurfaceId(id)
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
const toggleTerminalSurface = () => {
|
|
1085
|
+
setToolSurfaces((current) => {
|
|
1086
|
+
const terminal = current.find((surface) => surface.kind === 'terminal')
|
|
1087
|
+
if (!terminal) {
|
|
1088
|
+
const id = `terminal:${Date.now()}:${Math.random().toString(36).slice(2, 7)}`
|
|
1089
|
+
setActiveSurfaceId(id)
|
|
1090
|
+
return [...current, { id, kind: 'terminal' as const, title: 'Terminal' }]
|
|
1091
|
+
}
|
|
1092
|
+
setActiveSurfaceId((active) => active === terminal.id ? null : terminal.id)
|
|
1093
|
+
return current
|
|
1094
|
+
})
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
const checkForUpdatesFromMenu = async () => {
|
|
1098
|
+
try {
|
|
1099
|
+
const update = await window.settingsApi.checkForUpdates()
|
|
1100
|
+
showToast(update?.available ? `Mint ${update.version} is available.` : 'Mint is up to date.')
|
|
1101
|
+
} catch (error) {
|
|
1102
|
+
showToast(`Could not check for updates: ${String(error)}`)
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
const openArtifactSurface = (artifact: import('./ArtifactPreviewPanel').ArtifactFile) => {
|
|
1107
|
+
setToolsPanelOpen(true)
|
|
1108
|
+
const fileName = artifact.path.replace(/\\/g, '/').split('/').pop() || artifact.path
|
|
1109
|
+
const id = `preview:${artifact.path}`
|
|
1110
|
+
setToolSurfaces((current) => {
|
|
1111
|
+
const next = current.filter((surface) => surface.id !== id)
|
|
1112
|
+
return [...next, { id, kind: 'preview', title: fileName, artifact }]
|
|
1113
|
+
})
|
|
1114
|
+
setActiveSurfaceId(id)
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
const openReviewSurface = (review: Extract<ToolSurface, { kind: 'review' }>) => {
|
|
1118
|
+
setToolsPanelOpen(true)
|
|
1119
|
+
setToolSurfaces((current) => [...current.filter((surface) => surface.id !== review.id), review])
|
|
1120
|
+
setActiveSurfaceId(review.id)
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
const openConversationReview = () => {
|
|
1124
|
+
setToolsPanelOpen(true)
|
|
1125
|
+
setToolSurfaces((current) => {
|
|
1126
|
+
const reviewCount = current.filter((surface) => surface.kind === 'review').length
|
|
1127
|
+
const id = `review:${Date.now()}:${Math.random().toString(36).slice(2, 7)}`
|
|
1128
|
+
const title = reviewCount === 0 ? 'Review' : `Review (${reviewCount + 1})`
|
|
1129
|
+
const next = {
|
|
1130
|
+
id,
|
|
1131
|
+
kind: 'review' as const,
|
|
1132
|
+
title,
|
|
1133
|
+
reviewTitle: 'All conversation changes',
|
|
1134
|
+
changes: conversationReviewChanges,
|
|
1135
|
+
}
|
|
1136
|
+
setActiveSurfaceId(id)
|
|
1137
|
+
return [...current, next]
|
|
1138
|
+
})
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
const closeToolSurface = (id: string) => {
|
|
1142
|
+
setToolSurfaces((current) => {
|
|
1143
|
+
const index = current.findIndex((surface) => surface.id === id)
|
|
1144
|
+
const next = current.filter((surface) => surface.id !== id)
|
|
1145
|
+
setActiveSurfaceId((active) => {
|
|
1146
|
+
if (active !== id) return active
|
|
1147
|
+
return next[Math.max(0, index - 1)]?.id ?? null
|
|
1148
|
+
})
|
|
1149
|
+
return next
|
|
1150
|
+
})
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
const closeAllToolSurfaces = () => {
|
|
1154
|
+
setToolSurfaces([])
|
|
1155
|
+
setActiveSurfaceId(null)
|
|
1156
|
+
}
|
|
1157
|
+
|
|
809
1158
|
const toggleSidebar = () => {
|
|
810
1159
|
if (window.innerWidth <= 760) {
|
|
811
1160
|
setMobileSidebarOpen(false)
|
|
@@ -835,11 +1184,6 @@ export default function MintDashboard() {
|
|
|
835
1184
|
window.localStorage.setItem('mint:sidebar-width', String(clamped))
|
|
836
1185
|
}
|
|
837
1186
|
|
|
838
|
-
const updateSmartContext = (enabled: boolean) => {
|
|
839
|
-
window.localStorage.setItem('mint:smart-context', String(enabled))
|
|
840
|
-
setSmartContext(enabled)
|
|
841
|
-
}
|
|
842
|
-
|
|
843
1187
|
const updateAgentMode = (enabled: boolean) => {
|
|
844
1188
|
window.localStorage.setItem('mint:agent-mode', String(enabled))
|
|
845
1189
|
setAgentMode(enabled)
|
|
@@ -852,48 +1196,56 @@ export default function MintDashboard() {
|
|
|
852
1196
|
|
|
853
1197
|
const updateWorkspacePath = (path: string) => {
|
|
854
1198
|
const next = path.trim()
|
|
855
|
-
|
|
856
|
-
window.localStorage.setItem(LAST_WORKSPACE_PATH_KEY, next)
|
|
857
|
-
} else {
|
|
858
|
-
window.localStorage.removeItem(LAST_WORKSPACE_PATH_KEY)
|
|
859
|
-
}
|
|
860
|
-
setWorkspacePath(next)
|
|
1199
|
+
conversationActions.selectWorkspace(next)
|
|
861
1200
|
}
|
|
862
1201
|
|
|
863
1202
|
useEffect(() => {
|
|
864
1203
|
if (!sending) {
|
|
865
1204
|
sessionAutoApprovedRef.current = false
|
|
1205
|
+
autoApprovedChatIdRef.current = null
|
|
866
1206
|
setSessionAutoApproved(false)
|
|
867
1207
|
}
|
|
868
1208
|
}, [sending])
|
|
869
1209
|
|
|
870
1210
|
async function handleApproval(approved: boolean, autoApproveSession = false, answer?: string) {
|
|
1211
|
+
const chatId = conversationId
|
|
1212
|
+
const pendingApproval = pendingApprovals[chatId]
|
|
871
1213
|
if (!pendingApproval) return
|
|
872
1214
|
try {
|
|
873
1215
|
if (autoApproveSession) {
|
|
874
1216
|
sessionAutoApprovedRef.current = true
|
|
1217
|
+
autoApprovedChatIdRef.current = chatId
|
|
875
1218
|
setSessionAutoApproved(true)
|
|
876
1219
|
}
|
|
877
1220
|
await submitToolApproval(pendingApproval.token, approved, answer)
|
|
1221
|
+
setPendingApprovals((current) => {
|
|
1222
|
+
if (current[chatId]?.token !== pendingApproval.token) return current
|
|
1223
|
+
const next = { ...current }
|
|
1224
|
+
delete next[chatId]
|
|
1225
|
+
return next
|
|
1226
|
+
})
|
|
878
1227
|
} catch (reason) {
|
|
879
1228
|
setError(errorMessage(reason))
|
|
880
|
-
} finally {
|
|
881
|
-
setPendingApproval(null)
|
|
882
1229
|
}
|
|
883
1230
|
}
|
|
884
1231
|
|
|
885
1232
|
async function handleCancelMessage() {
|
|
886
1233
|
if (!sending || !streamingConversationId) return
|
|
1234
|
+
runGenerationRef.current += 1
|
|
887
1235
|
try {
|
|
888
|
-
await
|
|
1236
|
+
await conversationActions.executeCancellation(() =>
|
|
1237
|
+
cancelChatMessage(streamingConversationId),
|
|
1238
|
+
)
|
|
889
1239
|
} catch (e) {
|
|
890
1240
|
console.error("Failed to cancel message stream:", e)
|
|
891
1241
|
} finally {
|
|
892
|
-
|
|
1242
|
+
setPendingApprovals((current) => {
|
|
1243
|
+
const next = { ...current }
|
|
1244
|
+
delete next[streamingConversationId]
|
|
1245
|
+
return next
|
|
1246
|
+
})
|
|
893
1247
|
setStreamingConversationId(null)
|
|
894
|
-
|
|
895
|
-
setSendingImageCount(0)
|
|
896
|
-
setSendingVideoCount(0)
|
|
1248
|
+
setActiveTurnId(null)
|
|
897
1249
|
}
|
|
898
1250
|
}
|
|
899
1251
|
|
|
@@ -911,6 +1263,17 @@ export default function MintDashboard() {
|
|
|
911
1263
|
} = {},
|
|
912
1264
|
) {
|
|
913
1265
|
if (sending) return
|
|
1266
|
+
const originChatId = conversationId
|
|
1267
|
+
const originWorkspacePath = workspacePath || null
|
|
1268
|
+
const sessionGeneration = sessionGenerationRef.current
|
|
1269
|
+
const runGeneration = ++runGenerationRef.current
|
|
1270
|
+
const originRun = { chatId: originChatId, sessionGeneration, runGeneration }
|
|
1271
|
+
const isCurrentRun = () => matchesActiveRun(originRun, {
|
|
1272
|
+
chatId: activeConversationRef.current,
|
|
1273
|
+
sessionGeneration: sessionGenerationRef.current,
|
|
1274
|
+
runGeneration: runGenerationRef.current,
|
|
1275
|
+
})
|
|
1276
|
+
let turnId: number | null = null
|
|
914
1277
|
const outgoingImages = options.imageAttachments ?? []
|
|
915
1278
|
const outgoingVideos = options.videoAttachments ?? []
|
|
916
1279
|
const outgoingDocument = options.documentAttachment ?? null
|
|
@@ -918,107 +1281,129 @@ export default function MintDashboard() {
|
|
|
918
1281
|
const outgoingImage = outgoingImages.map((img) => img.dataUri).join(' ')
|
|
919
1282
|
const outgoingVideo = outgoingVideos.map((vid) => vid.dataUri).join(' ')
|
|
920
1283
|
const outgoingImageCount = outgoingImages.length
|
|
921
|
-
|
|
1284
|
+
conversationActions.startRun(promptText, outgoingImageCount, outgoingVideos.length)
|
|
922
1285
|
setStreamingConversationId(conversationId)
|
|
923
|
-
|
|
924
|
-
setSendingImageCount(outgoingImageCount)
|
|
925
|
-
setSendingVideoCount(outgoingVideos.length)
|
|
1286
|
+
setActiveTurnId(null)
|
|
926
1287
|
setError('')
|
|
927
|
-
setStreamedReply('')
|
|
928
|
-
setStreamedResponse(null)
|
|
929
|
-
setAgentProgress([])
|
|
930
1288
|
liveThinkingOpenRef.current = true
|
|
931
|
-
|
|
1289
|
+
liveExtendedThinkingOpenRef.current = true
|
|
1290
|
+
setThinkingExpanded((current) => ({ ...current, live: true, 'live-extended': true }))
|
|
932
1291
|
const progressSnapshot: AgentProgress[] = []
|
|
1292
|
+
let pendingProgress: AgentProgress[] = []
|
|
1293
|
+
let progressFlushTimer: ReturnType<typeof setTimeout> | null = null
|
|
1294
|
+
const flushPendingProgress = () => {
|
|
1295
|
+
if (progressFlushTimer) {
|
|
1296
|
+
clearTimeout(progressFlushTimer)
|
|
1297
|
+
progressFlushTimer = null
|
|
1298
|
+
}
|
|
1299
|
+
if (pendingProgress.length === 0) return
|
|
1300
|
+
const batch = pendingProgress
|
|
1301
|
+
pendingProgress = []
|
|
1302
|
+
if (isCurrentRun()) conversationActions.receiveProgress(batch)
|
|
1303
|
+
}
|
|
1304
|
+
const queueProgress = (progress: AgentProgress) => {
|
|
1305
|
+
pendingProgress.push(progress)
|
|
1306
|
+
if (progress.type !== 'ThinkingDelta') {
|
|
1307
|
+
flushPendingProgress()
|
|
1308
|
+
} else if (!progressFlushTimer) {
|
|
1309
|
+
progressFlushTimer = setTimeout(flushPendingProgress, 75)
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
933
1312
|
if (options.clearComposer) {
|
|
934
|
-
|
|
935
|
-
setImageAttachments([])
|
|
936
|
-
setVideoAttachments([])
|
|
937
|
-
setDocumentAttachment(null)
|
|
1313
|
+
conversationActions.clearComposer()
|
|
938
1314
|
}
|
|
939
1315
|
|
|
940
1316
|
try {
|
|
941
|
-
const response = await streamChatMessage(
|
|
1317
|
+
const response = await conversationActions.executeStream((onChunk) => streamChatMessage(
|
|
942
1318
|
shouldUseAgentMode ? promptText : `/chat ${promptText}`,
|
|
943
|
-
|
|
1319
|
+
onChunk,
|
|
944
1320
|
outgoingImage,
|
|
945
1321
|
options.audioDataUri ?? null,
|
|
946
1322
|
outgoingVideo,
|
|
947
1323
|
options.systemInstruction ?? '',
|
|
948
1324
|
(progress) => {
|
|
949
1325
|
progressSnapshot.push(progress)
|
|
950
|
-
|
|
1326
|
+
queueProgress(progress)
|
|
951
1327
|
},
|
|
952
1328
|
outgoingDocument,
|
|
953
|
-
|
|
954
|
-
|
|
1329
|
+
originWorkspacePath,
|
|
1330
|
+
originChatId,
|
|
955
1331
|
undefined,
|
|
956
1332
|
shouldUseAgentMode ? planMode : false,
|
|
957
1333
|
options.pinnedMcpServer ?? null,
|
|
958
1334
|
(payload) => {
|
|
959
|
-
if (sessionAutoApprovedRef.current) {
|
|
1335
|
+
if (sessionAutoApprovedRef.current && autoApprovedChatIdRef.current === originChatId) {
|
|
960
1336
|
submitToolApproval(payload.token, true).catch((err) => {
|
|
961
1337
|
console.error("Auto approval failed:", err)
|
|
962
1338
|
})
|
|
963
1339
|
} else {
|
|
964
|
-
|
|
1340
|
+
setPendingApprovals((current) => ({ ...current, [originChatId]: payload }))
|
|
965
1341
|
notifyPendingApproval(payload)
|
|
966
1342
|
}
|
|
967
1343
|
},
|
|
968
|
-
|
|
969
|
-
|
|
1344
|
+
(id) => {
|
|
1345
|
+
turnId = id
|
|
1346
|
+
if (isCurrentRun()) setActiveTurnId(id)
|
|
1347
|
+
},
|
|
1348
|
+
), isCurrentRun)
|
|
1349
|
+
flushPendingProgress()
|
|
970
1350
|
if (document.hidden || !document.hasFocus()) {
|
|
971
1351
|
window.api?.notifyAiResponse?.(truncateForNotification(response.text))
|
|
972
1352
|
}
|
|
973
|
-
const
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
? { ...interaction, agentActivity: progressSnapshot }
|
|
984
|
-
: interaction,
|
|
985
|
-
)
|
|
986
|
-
setAgentActivitySnapshots((current) => ({
|
|
987
|
-
...current,
|
|
988
|
-
[interactionKey]: progressSnapshot.slice(),
|
|
989
|
-
}))
|
|
990
|
-
if (liveThinkingOpenRef.current) {
|
|
1353
|
+
const persistedProgress = compactAgentProgressForPersistence(progressSnapshot)
|
|
1354
|
+
if (persistedProgress.length > 0) {
|
|
1355
|
+
if (turnId != null) {
|
|
1356
|
+
const interactionKey = String(turnId)
|
|
1357
|
+
await saveInteractionAgentActivity(turnId, persistedProgress)
|
|
1358
|
+
if (isCurrentRun()) {
|
|
1359
|
+
setAgentActivitySnapshots((current) => ({
|
|
1360
|
+
...current,
|
|
1361
|
+
[interactionKey]: persistedProgress.slice(),
|
|
1362
|
+
}))
|
|
991
1363
|
setThinkingExpanded((current) => ({
|
|
992
1364
|
...current,
|
|
993
|
-
[interactionKey]: true,
|
|
1365
|
+
...(liveThinkingOpenRef.current ? { [interactionKey]: true } : {}),
|
|
1366
|
+
...(liveExtendedThinkingOpenRef.current ? { [`extended-${interactionKey}`]: true } : {}),
|
|
994
1367
|
}))
|
|
995
1368
|
}
|
|
996
|
-
|
|
1369
|
+
} else {
|
|
1370
|
+
console.warn('Agent activity was not saved because the stream did not provide a turn ID')
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
if (isCurrentRun()) {
|
|
1374
|
+
try {
|
|
1375
|
+
await loadConversationHistory(originChatId, sessionGeneration)
|
|
1376
|
+
} catch (error) {
|
|
1377
|
+
console.error('Failed to refresh completed conversation:', error)
|
|
997
1378
|
}
|
|
998
1379
|
}
|
|
999
|
-
setInteractions(enrichedHistory)
|
|
1000
|
-
setAgentActivitySnapshots((current) => mergeActivitySnapshots(current, enrichedHistory))
|
|
1001
1380
|
await refreshChatSessions()
|
|
1002
1381
|
await refreshPictures()
|
|
1003
|
-
if (typeof window !== 'undefined') {
|
|
1382
|
+
if (isCurrentRun() && typeof window !== 'undefined') {
|
|
1004
1383
|
const pathname = (window.location.pathname || '').replace(/\/+$/, '')
|
|
1005
1384
|
const hash = (window.location.hash || '').replace(/^#\/?/, '').replace(/\/+$/, '')
|
|
1006
1385
|
const target = (pathname || hash).toLowerCase()
|
|
1007
1386
|
if (!target || target === '' || target === '/chat' || target === 'chat' || target === '/index.html' || target === 'index.html') {
|
|
1008
|
-
window.history.replaceState({}, '', `/chat/${encodeURIComponent(
|
|
1387
|
+
window.history.replaceState({}, '', `/chat/${encodeURIComponent(originChatId)}`)
|
|
1009
1388
|
}
|
|
1010
1389
|
}
|
|
1011
1390
|
getRuntimeStatus().then(setStatus).catch(() => {})
|
|
1012
|
-
|
|
1013
|
-
setStreamedResponse(null)
|
|
1391
|
+
if (isCurrentRun()) conversationActions.clearStream()
|
|
1014
1392
|
} catch (reason) {
|
|
1015
|
-
setError(errorMessage(reason))
|
|
1393
|
+
if (isCurrentRun()) setError(errorMessage(reason))
|
|
1016
1394
|
} finally {
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1395
|
+
flushPendingProgress()
|
|
1396
|
+
setPendingApprovals((current) => {
|
|
1397
|
+
if (!current[originChatId]) return current
|
|
1398
|
+
const next = { ...current }
|
|
1399
|
+
delete next[originChatId]
|
|
1400
|
+
return next
|
|
1401
|
+
})
|
|
1402
|
+
if (isCurrentRun()) {
|
|
1403
|
+
conversationActions.finishRun()
|
|
1404
|
+
setStreamingConversationId(null)
|
|
1405
|
+
setActiveTurnId(null)
|
|
1406
|
+
}
|
|
1022
1407
|
}
|
|
1023
1408
|
}
|
|
1024
1409
|
|
|
@@ -1041,10 +1426,7 @@ export default function MintDashboard() {
|
|
|
1041
1426
|
engineResp = null
|
|
1042
1427
|
}
|
|
1043
1428
|
if (engineResp && engineResp.kind !== 'not_handled') {
|
|
1044
|
-
|
|
1045
|
-
setImageAttachments([])
|
|
1046
|
-
setVideoAttachments([])
|
|
1047
|
-
setDocumentAttachment(null)
|
|
1429
|
+
conversationActions.clearComposer()
|
|
1048
1430
|
await handleEngineSlashResponse(trimmed, engineResp)
|
|
1049
1431
|
return
|
|
1050
1432
|
}
|
|
@@ -1052,22 +1434,49 @@ export default function MintDashboard() {
|
|
|
1052
1434
|
const slashResult = executeSlashCommand(trimmed)
|
|
1053
1435
|
|
|
1054
1436
|
if (slashResult.handled) {
|
|
1055
|
-
|
|
1056
|
-
setImageAttachments([])
|
|
1057
|
-
setVideoAttachments([])
|
|
1058
|
-
setDocumentAttachment(null)
|
|
1437
|
+
conversationActions.clearComposer()
|
|
1059
1438
|
|
|
1060
1439
|
if (slashResult.action === 'open_image_picker') {
|
|
1061
1440
|
document.getElementById('vision-file-input')?.click()
|
|
1062
1441
|
return
|
|
1063
1442
|
} else if (slashResult.action === 'paste_image') {
|
|
1064
1443
|
readClipboardImage().then((uri) => {
|
|
1065
|
-
if (uri)
|
|
1444
|
+
if (uri) conversationActions.attachImage({ dataUri: uri, name: 'Clipboard Image' })
|
|
1066
1445
|
}).catch(() => {})
|
|
1067
1446
|
return
|
|
1068
1447
|
} else if (slashResult.action === 'generate_veo') {
|
|
1069
1448
|
changeView('veo')
|
|
1070
1449
|
return
|
|
1450
|
+
} else if (slashResult.action === 'resume_session') {
|
|
1451
|
+
const query = (slashResult.payload?.query || '').trim().toLowerCase()
|
|
1452
|
+
const target = query
|
|
1453
|
+
? chatSessions.find((s) => s.id.toLowerCase() === query || s.id.toLowerCase().includes(query) || s.title.toLowerCase().includes(query))
|
|
1454
|
+
: chatSessions.find((s) => s.id !== conversationId)
|
|
1455
|
+
if (target) {
|
|
1456
|
+
activateConversation(target.id)
|
|
1457
|
+
const targetPath = getCleanPathForView('chat', target.id)
|
|
1458
|
+
window.history.replaceState({}, '', targetPath)
|
|
1459
|
+
const systemMsg = {
|
|
1460
|
+
id: Date.now(),
|
|
1461
|
+
userText: trimmed,
|
|
1462
|
+
aiText: `🔄 Resumed session: **${target.title}** (\`${target.id}\`)`,
|
|
1463
|
+
createdAt: new Date().toISOString(),
|
|
1464
|
+
provider: 'system',
|
|
1465
|
+
model: 'mint-cli',
|
|
1466
|
+
}
|
|
1467
|
+
setInteractions((prev) => [...prev, systemMsg])
|
|
1468
|
+
} else {
|
|
1469
|
+
const systemMsg = {
|
|
1470
|
+
id: Date.now(),
|
|
1471
|
+
userText: trimmed,
|
|
1472
|
+
aiText: query ? `⚠️ No matching session found for "${query}".` : 'ℹ️ No other sessions found to resume.',
|
|
1473
|
+
createdAt: new Date().toISOString(),
|
|
1474
|
+
provider: 'system',
|
|
1475
|
+
model: 'mint-cli',
|
|
1476
|
+
}
|
|
1477
|
+
setInteractions((prev) => [...prev, systemMsg])
|
|
1478
|
+
}
|
|
1479
|
+
return
|
|
1071
1480
|
}
|
|
1072
1481
|
|
|
1073
1482
|
if (slashResult.systemText) {
|
|
@@ -1125,12 +1534,7 @@ export default function MintDashboard() {
|
|
|
1125
1534
|
const objectUrl = createObjectUrlPreview(file).objectUrl
|
|
1126
1535
|
const dataUri = await readImage(file)
|
|
1127
1536
|
const previewDataUri = await createTrimmedImagePreview(dataUri).catch(() => dataUri)
|
|
1128
|
-
|
|
1129
|
-
if (current.some((item) => item.name === file.name && item.dataUri === dataUri)) {
|
|
1130
|
-
return current
|
|
1131
|
-
}
|
|
1132
|
-
return [...current, { dataUri, previewDataUri, objectUrl, name: file.name }]
|
|
1133
|
-
})
|
|
1537
|
+
conversationActions.attachImage({ dataUri, previewDataUri, objectUrl, name: file.name })
|
|
1134
1538
|
} catch (reason) {
|
|
1135
1539
|
setError(errorMessage(reason))
|
|
1136
1540
|
} finally {
|
|
@@ -1152,12 +1556,7 @@ export default function MintDashboard() {
|
|
|
1152
1556
|
reader.onerror = reject
|
|
1153
1557
|
reader.readAsDataURL(file)
|
|
1154
1558
|
})
|
|
1155
|
-
|
|
1156
|
-
if (current.some((item) => item.name === file.name && item.dataUri === dataUri)) {
|
|
1157
|
-
return current
|
|
1158
|
-
}
|
|
1159
|
-
return [...current, { dataUri, name: file.name }]
|
|
1160
|
-
})
|
|
1559
|
+
conversationActions.attachVideo({ dataUri, name: file.name })
|
|
1161
1560
|
} catch (reason) {
|
|
1162
1561
|
setError(errorMessage(reason))
|
|
1163
1562
|
} finally {
|
|
@@ -1203,7 +1602,7 @@ export default function MintDashboard() {
|
|
|
1203
1602
|
createTrimmedImagePreview(dataUri)
|
|
1204
1603
|
.catch(() => dataUri)
|
|
1205
1604
|
.then((previewDataUri) => {
|
|
1206
|
-
|
|
1605
|
+
conversationActions.attachImage({ dataUri, previewDataUri, name })
|
|
1207
1606
|
})
|
|
1208
1607
|
}
|
|
1209
1608
|
}).catch((err) => {
|
|
@@ -1226,7 +1625,7 @@ export default function MintDashboard() {
|
|
|
1226
1625
|
createTrimmedImagePreview(dataUri)
|
|
1227
1626
|
.catch(() => dataUri)
|
|
1228
1627
|
.then((previewDataUri) => {
|
|
1229
|
-
|
|
1628
|
+
conversationActions.attachImage({ dataUri, previewDataUri, name })
|
|
1230
1629
|
})
|
|
1231
1630
|
})
|
|
1232
1631
|
.catch((reason) => setError(errorMessage(reason)))
|
|
@@ -1242,7 +1641,7 @@ export default function MintDashboard() {
|
|
|
1242
1641
|
if (!isSupportedDocument(file.name)) {
|
|
1243
1642
|
throw new Error('Unsupported document type')
|
|
1244
1643
|
}
|
|
1245
|
-
|
|
1644
|
+
conversationActions.attachDocument({
|
|
1246
1645
|
filename: file.name,
|
|
1247
1646
|
dataUri: await readDocument(file),
|
|
1248
1647
|
})
|
|
@@ -1255,12 +1654,12 @@ export default function MintDashboard() {
|
|
|
1255
1654
|
|
|
1256
1655
|
function startWebSearch() {
|
|
1257
1656
|
updateAgentMode(true)
|
|
1258
|
-
|
|
1657
|
+
conversationActions.compose(message.trim() ? `Search web: ${message.trim()}` : 'Search web: ')
|
|
1259
1658
|
}
|
|
1260
1659
|
|
|
1261
|
-
async function selectWorkspace() {
|
|
1660
|
+
async function selectWorkspace(path?: string) {
|
|
1262
1661
|
try {
|
|
1263
|
-
const selected = await selectWorkspaceDirectory()
|
|
1662
|
+
const selected = path || await selectWorkspaceDirectory()
|
|
1264
1663
|
if (selected) {
|
|
1265
1664
|
updateWorkspacePath(selected)
|
|
1266
1665
|
changeView('workspace')
|
|
@@ -1270,7 +1669,13 @@ export default function MintDashboard() {
|
|
|
1270
1669
|
}
|
|
1271
1670
|
}
|
|
1272
1671
|
|
|
1273
|
-
|
|
1672
|
+
function captureScreen() {
|
|
1673
|
+
setScreenCaptureOpen(true)
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
async function startLiveTranslation() {
|
|
1677
|
+
setScreenCaptureOpen(false)
|
|
1678
|
+
await new Promise<void>((resolve) => requestAnimationFrame(() => requestAnimationFrame(() => resolve())))
|
|
1274
1679
|
try {
|
|
1275
1680
|
await window.api.startVision()
|
|
1276
1681
|
} catch (reason) {
|
|
@@ -1278,20 +1683,38 @@ export default function MintDashboard() {
|
|
|
1278
1683
|
}
|
|
1279
1684
|
}
|
|
1280
1685
|
|
|
1281
|
-
|
|
1686
|
+
function attachScreenCapture(image: string) {
|
|
1687
|
+
void createTrimmedImagePreview(image)
|
|
1688
|
+
.catch(() => image)
|
|
1689
|
+
.then((previewDataUri) => {
|
|
1690
|
+
conversationActions.attachImage({ dataUri: image, previewDataUri, name: 'Screen capture' })
|
|
1691
|
+
setScreenCaptureOpen(false)
|
|
1692
|
+
})
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
async function clearHistory(action: 'New chat' | 'Clear history', targetWorkspacePath?: string | null) {
|
|
1696
|
+
const originChatId = conversationId
|
|
1697
|
+
const generation = sessionGenerationRef.current
|
|
1282
1698
|
try {
|
|
1283
1699
|
if (action === 'New chat') {
|
|
1284
1700
|
const next = createConversationId()
|
|
1285
|
-
|
|
1701
|
+
activateConversation(next)
|
|
1286
1702
|
setInteractions([])
|
|
1287
1703
|
setAgentActivitySnapshots({})
|
|
1288
|
-
|
|
1289
|
-
setStreamedResponse(null)
|
|
1290
|
-
setMessage('')
|
|
1291
|
-
setImageAttachments([])
|
|
1292
|
-
setDocumentAttachment(null)
|
|
1293
|
-
setAgentProgress([])
|
|
1704
|
+
conversationActions.switchSession()
|
|
1294
1705
|
setViewState('chat')
|
|
1706
|
+
|
|
1707
|
+
if (targetWorkspacePath !== undefined) {
|
|
1708
|
+
updateWorkspacePath(targetWorkspacePath || '')
|
|
1709
|
+
} else {
|
|
1710
|
+
const currentSession = chatSessions.find((s) => s.id === conversationId)
|
|
1711
|
+
if (!currentSession || !currentSession.workspacePath) {
|
|
1712
|
+
updateWorkspacePath('')
|
|
1713
|
+
} else {
|
|
1714
|
+
updateWorkspacePath(currentSession.workspacePath)
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1295
1718
|
if (typeof window !== 'undefined') {
|
|
1296
1719
|
const currentPath = (window.location.pathname || '').replace(/\/+$/, '')
|
|
1297
1720
|
if (currentPath !== '' && currentPath !== '/chat') {
|
|
@@ -1301,14 +1724,12 @@ export default function MintDashboard() {
|
|
|
1301
1724
|
return
|
|
1302
1725
|
} else {
|
|
1303
1726
|
if (!window.confirm(`${action} will clear the current conversation history. Continue?`)) return
|
|
1304
|
-
await clearChatHistory(
|
|
1727
|
+
await clearChatHistory(originChatId)
|
|
1305
1728
|
}
|
|
1729
|
+
if (!isCurrentSession(originChatId, generation)) return
|
|
1306
1730
|
setInteractions([])
|
|
1307
1731
|
setAgentActivitySnapshots({})
|
|
1308
|
-
|
|
1309
|
-
setStreamedResponse(null)
|
|
1310
|
-
setMessage('')
|
|
1311
|
-
setImageAttachments([])
|
|
1732
|
+
conversationActions.switchSession()
|
|
1312
1733
|
} catch (reason) {
|
|
1313
1734
|
setError(errorMessage(reason))
|
|
1314
1735
|
}
|
|
@@ -1360,7 +1781,7 @@ export default function MintDashboard() {
|
|
|
1360
1781
|
const wsChange = resp.effects.find((e) => e.kind === 'workspace_changed') as
|
|
1361
1782
|
| { kind: 'workspace_changed'; path: string }
|
|
1362
1783
|
| undefined
|
|
1363
|
-
if (wsChange)
|
|
1784
|
+
if (wsChange) conversationActions.selectWorkspace(wsChange.path)
|
|
1364
1785
|
const planModeChange = resp.effects.find((e) => e.kind === 'plan_mode_changed') as
|
|
1365
1786
|
| { kind: 'plan_mode_changed'; enabled: boolean }
|
|
1366
1787
|
| undefined
|
|
@@ -1385,8 +1806,12 @@ export default function MintDashboard() {
|
|
|
1385
1806
|
])
|
|
1386
1807
|
}
|
|
1387
1808
|
if (resp.effects.some((e) => e.kind === 'history_cleared')) {
|
|
1388
|
-
|
|
1389
|
-
|
|
1809
|
+
const chatId = conversationId
|
|
1810
|
+
const generation = sessionGenerationRef.current
|
|
1811
|
+
await clearChatHistory(chatId).catch(() => {})
|
|
1812
|
+
if (isCurrentSession(chatId, generation)) {
|
|
1813
|
+
setInteractions([])
|
|
1814
|
+
}
|
|
1390
1815
|
}
|
|
1391
1816
|
if (resp.markdown) pushSystemMessage(userText, resp.markdown)
|
|
1392
1817
|
if (resp.effects.some((e) => e.kind !== 'history_cleared' && e.kind !== 'workspace_changed')) {
|
|
@@ -1415,40 +1840,66 @@ export default function MintDashboard() {
|
|
|
1415
1840
|
|
|
1416
1841
|
function handleThinkingExpandedChange(key: string, open: boolean) {
|
|
1417
1842
|
if (key === 'live') liveThinkingOpenRef.current = open
|
|
1843
|
+
if (key === 'live-extended') liveExtendedThinkingOpenRef.current = open
|
|
1418
1844
|
setThinkingExpanded((current) => ({ ...current, [key]: open }))
|
|
1419
1845
|
}
|
|
1420
1846
|
|
|
1421
1847
|
async function selectConversation(id: string) {
|
|
1422
1848
|
window.localStorage.setItem(ACTIVE_CONVERSATION_ID_KEY, id)
|
|
1423
1849
|
touchActiveTimestamp()
|
|
1424
|
-
|
|
1850
|
+
activateConversation(id)
|
|
1851
|
+
const generation = sessionGenerationRef.current
|
|
1425
1852
|
changeView('chat', id)
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1853
|
+
conversationActions.switchSession()
|
|
1854
|
+
const session = chatSessions.find((item) => item.id === id)
|
|
1855
|
+
if (session) {
|
|
1856
|
+
if (session.workspacePath) {
|
|
1857
|
+
if (session.workspacePath !== workspacePath) {
|
|
1858
|
+
updateWorkspacePath(session.workspacePath)
|
|
1859
|
+
}
|
|
1860
|
+
} else {
|
|
1861
|
+
if (workspacePath) {
|
|
1862
|
+
updateWorkspacePath('')
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
try {
|
|
1867
|
+
await loadConversationHistory(id, generation)
|
|
1868
|
+
} catch (reason) {
|
|
1869
|
+
if (isCurrentSession(id, generation)) setError(errorMessage(reason))
|
|
1870
|
+
}
|
|
1436
1871
|
}
|
|
1437
1872
|
|
|
1873
|
+
const handleNewChatInProject = useCallback((targetPath: string) => {
|
|
1874
|
+
clearHistory('New chat', targetPath)
|
|
1875
|
+
}, [])
|
|
1876
|
+
|
|
1438
1877
|
async function deleteConversation(id: string) {
|
|
1439
|
-
if (id === 'cli')
|
|
1878
|
+
if (id === 'cli') {
|
|
1879
|
+
if (!window.confirm('Clear history for default CLI session? This cannot be undone.')) return
|
|
1880
|
+
try {
|
|
1881
|
+
await clearChatHistory('cli')
|
|
1882
|
+
await refreshHistory()
|
|
1883
|
+
await refreshChatSessions()
|
|
1884
|
+
showToast('CLI session history cleared')
|
|
1885
|
+
} catch (reason) {
|
|
1886
|
+
setError(errorMessage(reason))
|
|
1887
|
+
}
|
|
1888
|
+
return
|
|
1889
|
+
}
|
|
1440
1890
|
const session = chatSessions.find((item) => item.id === id)
|
|
1441
1891
|
const title = session?.title || 'this chat'
|
|
1442
1892
|
if (!window.confirm(`Delete "${title}"? This will remove the conversation and its messages.`)) return
|
|
1443
1893
|
|
|
1444
1894
|
try {
|
|
1445
1895
|
await deleteChatSession(id)
|
|
1446
|
-
const remaining = chatSessions.filter((item) => item.id !== id && item.kind !== 'cli' && item.id !== 'conversation-default')
|
|
1447
|
-
const
|
|
1896
|
+
const remaining = chatSessions.filter((item) => item.id !== id && item.kind !== 'cli' && !item.id.startsWith('cli') && item.id !== 'conversation-default')
|
|
1897
|
+
const currentChatId = activeConversationRef.current
|
|
1898
|
+
const nextActive = id === currentChatId
|
|
1448
1899
|
? (remaining[0]?.id ?? createConversationId())
|
|
1449
|
-
:
|
|
1900
|
+
: currentChatId
|
|
1450
1901
|
|
|
1451
|
-
if (nextActive !==
|
|
1902
|
+
if (nextActive !== currentChatId) {
|
|
1452
1903
|
if (remaining.length > 0 && remaining[0]?.id) {
|
|
1453
1904
|
window.localStorage.setItem(ACTIVE_CONVERSATION_ID_KEY, nextActive)
|
|
1454
1905
|
if (typeof window !== 'undefined') {
|
|
@@ -1460,21 +1911,16 @@ export default function MintDashboard() {
|
|
|
1460
1911
|
window.history.replaceState({}, '', '/chat')
|
|
1461
1912
|
}
|
|
1462
1913
|
}
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
setAgentActivitySnapshots((current) => mergeActivitySnapshots(current, reversed))
|
|
1914
|
+
activateConversation(nextActive)
|
|
1915
|
+
const generation = sessionGenerationRef.current
|
|
1916
|
+
conversationActions.clearProgress()
|
|
1917
|
+
await loadConversationHistory(nextActive, generation)
|
|
1918
|
+
if (!isCurrentSession(nextActive, generation)) return
|
|
1469
1919
|
}
|
|
1470
1920
|
|
|
1471
1921
|
await refreshChatSessions()
|
|
1472
|
-
if (id !==
|
|
1473
|
-
|
|
1474
|
-
setStreamedResponse(null)
|
|
1475
|
-
setMessage('')
|
|
1476
|
-
setImageAttachments([])
|
|
1477
|
-
setDocumentAttachment(null)
|
|
1922
|
+
if (id !== currentChatId) return
|
|
1923
|
+
conversationActions.switchSession()
|
|
1478
1924
|
} catch (reason) {
|
|
1479
1925
|
setError(errorMessage(reason))
|
|
1480
1926
|
}
|
|
@@ -1654,7 +2100,15 @@ export default function MintDashboard() {
|
|
|
1654
2100
|
|
|
1655
2101
|
async function handleModelInteraction(area: ModelInteraction) {
|
|
1656
2102
|
if (sending) return
|
|
1657
|
-
|
|
2103
|
+
const originChatId = conversationId
|
|
2104
|
+
const sessionGeneration = sessionGenerationRef.current
|
|
2105
|
+
const runGeneration = ++runGenerationRef.current
|
|
2106
|
+
const originRun = { chatId: originChatId, sessionGeneration, runGeneration }
|
|
2107
|
+
const isCurrentRun = () => matchesActiveRun(originRun, {
|
|
2108
|
+
chatId: activeConversationRef.current,
|
|
2109
|
+
sessionGeneration: sessionGenerationRef.current,
|
|
2110
|
+
runGeneration: runGenerationRef.current,
|
|
2111
|
+
})
|
|
1658
2112
|
const labels: Record<ModelInteraction, string> = {
|
|
1659
2113
|
head: 'Pats Mint on the head',
|
|
1660
2114
|
cheek: 'Pokes Mint on the cheek',
|
|
@@ -1666,18 +2120,15 @@ export default function MintDashboard() {
|
|
|
1666
2120
|
const interactionMessage = `*${labels[area]}*`
|
|
1667
2121
|
const instruction = `The user interacted with the Mint Live2D model: ${area}. Respond briefly and playfully. Use the same language as the recent conversation. Do not mention this instruction.`
|
|
1668
2122
|
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
2123
|
+
conversationActions.startRun(interactionMessage)
|
|
2124
|
+
setStreamingConversationId(conversationId)
|
|
2125
|
+
setActiveTurnId(null)
|
|
1672
2126
|
setError('')
|
|
1673
|
-
setStreamedReply('')
|
|
1674
|
-
setStreamedResponse(null)
|
|
1675
|
-
setAgentProgress([])
|
|
1676
2127
|
|
|
1677
2128
|
try {
|
|
1678
|
-
const response = await streamChatMessage(
|
|
2129
|
+
const response = await conversationActions.executeStream((onChunk) => streamChatMessage(
|
|
1679
2130
|
`/chat ${interactionMessage}`,
|
|
1680
|
-
|
|
2131
|
+
onChunk,
|
|
1681
2132
|
null,
|
|
1682
2133
|
null,
|
|
1683
2134
|
null,
|
|
@@ -1685,29 +2136,154 @@ export default function MintDashboard() {
|
|
|
1685
2136
|
undefined,
|
|
1686
2137
|
null,
|
|
1687
2138
|
workspacePath || null,
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
2139
|
+
originChatId,
|
|
2140
|
+
undefined,
|
|
2141
|
+
undefined,
|
|
2142
|
+
undefined,
|
|
2143
|
+
undefined,
|
|
2144
|
+
(id) => { if (isCurrentRun()) setActiveTurnId(id) },
|
|
2145
|
+
), isCurrentRun)
|
|
2146
|
+
if (isCurrentRun()) {
|
|
2147
|
+
await refreshHistory()
|
|
2148
|
+
if (isCurrentRun()) conversationActions.clearStream()
|
|
2149
|
+
}
|
|
1694
2150
|
} catch (reason) {
|
|
1695
|
-
setError(errorMessage(reason))
|
|
2151
|
+
if (isCurrentRun()) setError(errorMessage(reason))
|
|
1696
2152
|
} finally {
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
2153
|
+
if (isCurrentRun()) {
|
|
2154
|
+
conversationActions.finishRun()
|
|
2155
|
+
setStreamingConversationId(null)
|
|
2156
|
+
setActiveTurnId(null)
|
|
2157
|
+
}
|
|
1700
2158
|
}
|
|
1701
2159
|
}
|
|
1702
2160
|
|
|
2161
|
+
const chatConversation: ConversationViewModel = {
|
|
2162
|
+
interactions,
|
|
2163
|
+
hasOlder: hasOlderInteractions,
|
|
2164
|
+
sendingInteractionId: streamingConversationId === conversationId ? activeTurnId : null,
|
|
2165
|
+
sending: sending && streamingConversationId === conversationId,
|
|
2166
|
+
sendingMessage: streamingConversationId === conversationId ? sendingMessage : '',
|
|
2167
|
+
sendingImageCount: streamingConversationId === conversationId ? sendingImageCount : 0,
|
|
2168
|
+
sendingVideoCount: streamingConversationId === conversationId ? sendingVideoCount : 0,
|
|
2169
|
+
streamedReply: streamingConversationId === conversationId ? streamedReply : '',
|
|
2170
|
+
streamedResponse: streamingConversationId === conversationId ? streamedResponse : null,
|
|
2171
|
+
agentProgress: streamingConversationId === conversationId ? agentProgress : [],
|
|
2172
|
+
agentActivitySnapshots,
|
|
2173
|
+
thinkingExpanded,
|
|
2174
|
+
message,
|
|
2175
|
+
imageAttachments,
|
|
2176
|
+
videoAttachments,
|
|
2177
|
+
documentName: documentAttachment?.filename ?? '',
|
|
2178
|
+
pendingApproval: pendingApprovals[conversationId] ?? null,
|
|
2179
|
+
agentMode,
|
|
2180
|
+
planMode,
|
|
2181
|
+
status,
|
|
2182
|
+
workspacePath,
|
|
2183
|
+
chatId: conversationId,
|
|
2184
|
+
recentWorkspacePaths,
|
|
2185
|
+
chatEnd,
|
|
2186
|
+
welcomeInteraction: MOCK_WELCOME_INTERACTION,
|
|
2187
|
+
settingsConfig,
|
|
2188
|
+
isCliSession: conversationId.startsWith('cli') || conversationId === 'cli',
|
|
2189
|
+
cliSessionId: conversationId.startsWith('cli') ? conversationId : undefined,
|
|
2190
|
+
conversationTitle: chatSessions.find((session) => session.id === conversationId)?.title,
|
|
2191
|
+
}
|
|
2192
|
+
const chatActions: ConversationActions = {
|
|
2193
|
+
onLoadOlder: loadOlderInteractions,
|
|
2194
|
+
onThinkingExpandedChange: handleThinkingExpandedChange,
|
|
2195
|
+
onSubmit: handleSubmit,
|
|
2196
|
+
onSelectImage: selectImage,
|
|
2197
|
+
onSelectVideo: selectVideo,
|
|
2198
|
+
onSelectDocument: selectDocument,
|
|
2199
|
+
onPasteImage: pasteImage,
|
|
2200
|
+
onSetMessage: conversationActions.compose,
|
|
2201
|
+
onSendVoiceMessage: sendVoiceMessage,
|
|
2202
|
+
onRemoveImage: conversationActions.removeImage,
|
|
2203
|
+
onRemoveVideo: conversationActions.removeVideo,
|
|
2204
|
+
onRemoveDocument: () => conversationActions.attachDocument(null),
|
|
2205
|
+
onStartWebSearch: startWebSearch,
|
|
2206
|
+
onCaptureScreen: captureScreen,
|
|
2207
|
+
onSetAgentMode: updateAgentMode,
|
|
2208
|
+
onSetPlanMode: isDesktopApp ? updatePlanMode : undefined,
|
|
2209
|
+
onSetProvider: changeProvider,
|
|
2210
|
+
onSelectWorkspace: isDesktopApp ? selectWorkspace : undefined,
|
|
2211
|
+
onWorkspaceChanged: () => setWorkspaceRefreshRevision((revision) => revision + 1),
|
|
2212
|
+
onApproval: handleApproval,
|
|
2213
|
+
onUpdateSettings: (updated) => setSettingsConfig(updated),
|
|
2214
|
+
onSetModel: changeModel,
|
|
2215
|
+
onSelectModelAndProvider: changeProviderAndModel,
|
|
2216
|
+
onCancelMessage: handleCancelMessage,
|
|
2217
|
+
onClearMessages: () => clearHistory('Clear history'),
|
|
2218
|
+
onSetGeminiLiveVoice: changeGeminiLiveVoice,
|
|
2219
|
+
onToggleMobileSidebar: () => setMobileSidebarOpen(!mobileSidebarOpen),
|
|
2220
|
+
onBackToCode: () => changeView('code'),
|
|
2221
|
+
onOpenArtifact: isDesktopApp ? openArtifactSurface : undefined,
|
|
2222
|
+
onOpenReview: isDesktopApp ? openReviewSurface : undefined,
|
|
2223
|
+
}
|
|
2224
|
+
|
|
1703
2225
|
return (
|
|
1704
2226
|
<div className={`app-container ${startupReady ? '' : 'is-loading'}`}>
|
|
2227
|
+
{screenCaptureOpen && (
|
|
2228
|
+
<ScreenCaptureDialog
|
|
2229
|
+
onClose={() => setScreenCaptureOpen(false)}
|
|
2230
|
+
onAttach={attachScreenCapture}
|
|
2231
|
+
capture={() => captureScreenForChat(isDesktopApp)}
|
|
2232
|
+
onLiveTranslate={isDesktopApp ? () => { void startLiveTranslation() } : undefined}
|
|
2233
|
+
/>
|
|
2234
|
+
)}
|
|
2235
|
+
{isDesktopApp && (
|
|
2236
|
+
<DesktopTitlebar
|
|
2237
|
+
sidebarCollapsed={sidebarCollapsed}
|
|
2238
|
+
onToggleSidebar={toggleSidebar}
|
|
2239
|
+
onNewChat={() => clearHistory('New chat')}
|
|
2240
|
+
onOpenWorkspace={() => selectWorkspace()}
|
|
2241
|
+
onOpenTerminal={openTerminalSurface}
|
|
2242
|
+
onToggleTerminal={toggleTerminalSurface}
|
|
2243
|
+
onOpenBrowser={() => openNativeBrowser()}
|
|
2244
|
+
toolsPanelOpen={toolsPanelOpen}
|
|
2245
|
+
onToggleToolsPanel={() => setToolsPanelOpen((open) => !open)}
|
|
2246
|
+
onOpenSettings={() => changeView('settings')}
|
|
2247
|
+
onCheckForUpdates={checkForUpdatesFromMenu}
|
|
2248
|
+
onShowAbout={() => showToast('Mint Agent — AI workspace')}
|
|
2249
|
+
workspacePath={workspacePath}
|
|
2250
|
+
terminalCount={toolSurfaces.filter((surface) => surface.kind === 'terminal').length}
|
|
2251
|
+
sourceNames={workspaceSourceNames}
|
|
2252
|
+
recentChanges={recentAgentChanges}
|
|
2253
|
+
onOpenReview={(changes) => openReviewSurface({ id: `review:workspace:${Date.now()}`, kind: 'review', title: 'Review', reviewTitle: 'Recent agent changes', changes })}
|
|
2254
|
+
onRefreshWorkspace={() => setWorkspaceRefreshRevision((revision) => revision + 1)}
|
|
2255
|
+
/>
|
|
2256
|
+
)}
|
|
1705
2257
|
<div
|
|
1706
|
-
className={`app-body ${(sidebarCollapsed && window.innerWidth > 760) ? 'sidebar-collapsed' : ''} ${view === 'pictures' ? 'pictures-open' : ''} ${mobileSidebarOpen ? 'mobile-sidebar-open' : ''}`}
|
|
1707
|
-
style={{
|
|
2258
|
+
className={`app-body ${(sidebarCollapsed && window.innerWidth > 760) ? 'sidebar-collapsed' : ''} ${view === 'pictures' ? 'pictures-open' : ''} ${mobileSidebarOpen ? 'mobile-sidebar-open' : ''} ${toolsPanelOpen ? 'tool-surface-active' : ''}`}
|
|
2259
|
+
style={{
|
|
2260
|
+
'--sidebar-expanded-width': `${sidebarWidth}px`,
|
|
2261
|
+
'--terminal-dock-size': `${terminalRightWidth}px`,
|
|
2262
|
+
// A terminal shown in the right tool surface resizes the surface
|
|
2263
|
+
// itself (and therefore the remaining chat area), not just its
|
|
2264
|
+
// inner xterm viewport.
|
|
2265
|
+
'--tool-surface-width': `${terminalRightWidth}px`,
|
|
2266
|
+
} as CSSProperties}
|
|
1708
2267
|
>
|
|
2268
|
+
{!isDesktopApp && view !== 'chat' && (
|
|
2269
|
+
<button
|
|
2270
|
+
type="button"
|
|
2271
|
+
className="web-mobile-nav-btn"
|
|
2272
|
+
aria-label="Open navigation menu"
|
|
2273
|
+
aria-expanded={mobileSidebarOpen}
|
|
2274
|
+
onClick={() => setMobileSidebarOpen(true)}
|
|
2275
|
+
>
|
|
2276
|
+
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" aria-hidden="true">
|
|
2277
|
+
<line x1="3" y1="6" x2="21" y2="6" />
|
|
2278
|
+
<line x1="3" y1="12" x2="21" y2="12" />
|
|
2279
|
+
<line x1="3" y1="18" x2="21" y2="18" />
|
|
2280
|
+
</svg>
|
|
2281
|
+
</button>
|
|
2282
|
+
)}
|
|
1709
2283
|
{mobileSidebarOpen && (
|
|
1710
|
-
<
|
|
2284
|
+
<button
|
|
2285
|
+
type="button"
|
|
2286
|
+
aria-label="Close navigation menu"
|
|
1711
2287
|
className="sidebar-backdrop"
|
|
1712
2288
|
onClick={() => setMobileSidebarOpen(false)}
|
|
1713
2289
|
style={{
|
|
@@ -1753,8 +2329,13 @@ export default function MintDashboard() {
|
|
|
1753
2329
|
onSetSearchOpen={setIsSearchOpen}
|
|
1754
2330
|
showWorkspaceTab={isDesktopApp}
|
|
1755
2331
|
promoteMediaStudios={!isDesktopApp}
|
|
2332
|
+
activeWorkspacePath={workspacePath}
|
|
2333
|
+
recentWorkspacePaths={recentWorkspacePaths}
|
|
2334
|
+
onBrowseFolder={isDesktopApp ? handleBrowseFolderForMove : undefined}
|
|
2335
|
+
onUpdateSessionWorkspace={handleUpdateSessionWorkspace}
|
|
2336
|
+
onNewChatInProject={handleNewChatInProject}
|
|
1756
2337
|
/>
|
|
1757
|
-
<main className={`assistant-workspace ${layoutPreset === 'chat-wide' ? 'layout-chat-wide' : 'layout-model-wide'} ${modelVisible || view === 'workspace' ? '' : 'model-hidden'} ${view === 'workspace' ? 'workspace-open' : ''}`} style={(view === 'skills' || view === 'mcp' || view === 'plugins' || view === 'cron' || view === 'link' || view === 'pictures' || view === 'imagine' || view === 'veo') ? { display: 'none' } : undefined}>
|
|
2338
|
+
<main className={`assistant-workspace ${layoutPreset === 'chat-wide' ? 'layout-chat-wide' : 'layout-model-wide'} ${modelVisible || view === 'workspace' ? '' : 'model-hidden'} ${view === 'workspace' ? 'workspace-open' : ''}`} style={(view === 'skills' || view === 'mcp' || view === 'plugins' || view === 'cron' || view === 'link' || view === 'pictures' || view === 'imagine' || view === 'veo' || view === 'code') ? { display: 'none' } : undefined}>
|
|
1758
2339
|
{proactiveSuggestion && (
|
|
1759
2340
|
<div className="proactive-bar" style={{ position: 'absolute', top: 0, left: 0, right: 0, zIndex: 100 }}>
|
|
1760
2341
|
<div className="proactive-header">
|
|
@@ -1806,172 +2387,220 @@ export default function MintDashboard() {
|
|
|
1806
2387
|
</div>
|
|
1807
2388
|
)}
|
|
1808
2389
|
{view === 'workspace' && (
|
|
1809
|
-
<
|
|
1810
|
-
|
|
2390
|
+
<Suspense fallback={<LazyPanelFallback />}>
|
|
2391
|
+
<WorkspacePanel
|
|
2392
|
+
agentMode={agentMode}
|
|
2393
|
+
sending={sending}
|
|
2394
|
+
workspacePath={workspacePath}
|
|
2395
|
+
onEnableAgentMode={() => updateAgentMode(true)}
|
|
2396
|
+
onSetMessage={conversationActions.compose}
|
|
2397
|
+
onWorkspaceReady={updateWorkspacePath}
|
|
2398
|
+
refreshRevision={workspaceRefreshRevision}
|
|
2399
|
+
/>
|
|
2400
|
+
</Suspense>
|
|
2401
|
+
)}
|
|
2402
|
+
<Suspense fallback={null}>
|
|
2403
|
+
<ModelPanel
|
|
2404
|
+
scale={scale}
|
|
2405
|
+
expressionIndex={expressionIndex}
|
|
2406
|
+
accessoryIndex={accessoryIndex}
|
|
2407
|
+
isLocked={isLocked}
|
|
2408
|
+
isActive={modelVisible && view !== 'pictures' && view !== 'workspace' && view !== 'imagine' && view !== 'veo' && view !== 'skills' && view !== 'mcp' && view !== 'plugins'}
|
|
2409
|
+
layoutPreset={layoutPreset}
|
|
1811
2410
|
sending={sending}
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
2411
|
+
interactionEnabled={interactionEnabled}
|
|
2412
|
+
showInteractionGuide={showInteractionGuide}
|
|
2413
|
+
toastMessage={toastMessage}
|
|
2414
|
+
onSetScale={setScale}
|
|
2415
|
+
onSetLocked={setIsLocked}
|
|
2416
|
+
onSetView={changeView}
|
|
2417
|
+
onChangeLayoutPreset={changeLayoutPreset}
|
|
2418
|
+
onDismissToast={() => setToastMessage('')}
|
|
2419
|
+
onInteract={handleModelInteraction}
|
|
2420
|
+
onModelLoadComplete={() => setModelReady(true)}
|
|
1816
2421
|
/>
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
scale={scale}
|
|
1820
|
-
expressionIndex={expressionIndex}
|
|
1821
|
-
accessoryIndex={accessoryIndex}
|
|
1822
|
-
isLocked={isLocked}
|
|
1823
|
-
isActive={modelVisible && view !== 'pictures' && view !== 'workspace' && view !== 'imagine' && view !== 'veo' && view !== 'skills' && view !== 'mcp' && view !== 'plugins'}
|
|
1824
|
-
layoutPreset={layoutPreset}
|
|
1825
|
-
sending={sending}
|
|
1826
|
-
interactionEnabled={interactionEnabled}
|
|
1827
|
-
showInteractionGuide={showInteractionGuide}
|
|
1828
|
-
toastMessage={toastMessage}
|
|
1829
|
-
onSetScale={setScale}
|
|
1830
|
-
onSetLocked={setIsLocked}
|
|
1831
|
-
onSetView={changeView}
|
|
1832
|
-
onChangeLayoutPreset={changeLayoutPreset}
|
|
1833
|
-
onDismissToast={() => setToastMessage('')}
|
|
1834
|
-
onInteract={handleModelInteraction}
|
|
1835
|
-
onModelLoadComplete={() => setModelReady(true)}
|
|
1836
|
-
/>
|
|
1837
|
-
<ChatPanel
|
|
1838
|
-
interactions={interactions}
|
|
1839
|
-
sending={sending && streamingConversationId === conversationId}
|
|
1840
|
-
sendingMessage={streamingConversationId === conversationId ? sendingMessage : ''}
|
|
1841
|
-
sendingImageCount={streamingConversationId === conversationId ? sendingImageCount : 0}
|
|
1842
|
-
streamedReply={streamingConversationId === conversationId ? streamedReply : ''}
|
|
1843
|
-
streamedResponse={streamingConversationId === conversationId ? streamedResponse : null}
|
|
1844
|
-
agentProgress={streamingConversationId === conversationId ? agentProgress : []}
|
|
1845
|
-
sendingVideoCount={streamingConversationId === conversationId ? sendingVideoCount : 0}
|
|
1846
|
-
agentActivitySnapshots={agentActivitySnapshots}
|
|
1847
|
-
thinkingExpanded={thinkingExpanded}
|
|
1848
|
-
onThinkingExpandedChange={handleThinkingExpandedChange}
|
|
1849
|
-
message={message}
|
|
1850
|
-
imageAttachments={imageAttachments}
|
|
1851
|
-
videoAttachments={videoAttachments}
|
|
1852
|
-
documentName={documentAttachment?.filename ?? ''}
|
|
1853
|
-
pendingApproval={streamingConversationId === conversationId ? pendingApproval : null}
|
|
1854
|
-
smartContext={smartContext}
|
|
1855
|
-
agentMode={agentMode}
|
|
1856
|
-
planMode={planMode}
|
|
1857
|
-
status={status}
|
|
1858
|
-
workspacePath={workspacePath}
|
|
1859
|
-
chatEnd={chatEnd}
|
|
1860
|
-
welcomeInteraction={MOCK_WELCOME_INTERACTION}
|
|
1861
|
-
onSubmit={handleSubmit}
|
|
1862
|
-
onSelectImage={selectImage}
|
|
1863
|
-
onSelectVideo={selectVideo}
|
|
1864
|
-
onSelectDocument={selectDocument}
|
|
1865
|
-
onPasteImage={pasteImage}
|
|
1866
|
-
onSetMessage={setMessage}
|
|
1867
|
-
onSendVoiceMessage={sendVoiceMessage}
|
|
1868
|
-
onRemoveImage={(idx: number) => {
|
|
1869
|
-
setImageAttachments((current) => current.filter((_, i) => i !== idx))
|
|
1870
|
-
}}
|
|
1871
|
-
onRemoveVideo={(idx: number) => {
|
|
1872
|
-
setVideoAttachments((current) => current.filter((_, i) => i !== idx))
|
|
1873
|
-
}}
|
|
1874
|
-
onRemoveDocument={() => setDocumentAttachment(null)}
|
|
1875
|
-
onStartWebSearch={startWebSearch}
|
|
1876
|
-
onCaptureScreen={captureScreen}
|
|
1877
|
-
onSetSmartContext={updateSmartContext}
|
|
1878
|
-
onSetAgentMode={updateAgentMode}
|
|
1879
|
-
onSetPlanMode={isDesktopApp ? updatePlanMode : undefined}
|
|
1880
|
-
onSetProvider={changeProvider}
|
|
1881
|
-
onSelectWorkspace={isDesktopApp ? selectWorkspace : undefined}
|
|
1882
|
-
settingsConfig={settingsConfig}
|
|
1883
|
-
onSetModel={changeModel}
|
|
1884
|
-
onSelectModelAndProvider={changeProviderAndModel}
|
|
1885
|
-
onSetGeminiLiveVoice={changeGeminiLiveVoice}
|
|
1886
|
-
onApproval={handleApproval}
|
|
1887
|
-
onCancelMessage={handleCancelMessage}
|
|
1888
|
-
onClearMessages={() => clearHistory('Clear history')}
|
|
1889
|
-
onToggleMobileSidebar={() => setMobileSidebarOpen(!mobileSidebarOpen)}
|
|
1890
|
-
/>
|
|
2422
|
+
</Suspense>
|
|
2423
|
+
<ChatPanel conversation={chatConversation} actions={chatActions} />
|
|
1891
2424
|
</main>
|
|
1892
|
-
{
|
|
1893
|
-
<
|
|
1894
|
-
<
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
deleteSkill={deleteLearnedSkill}
|
|
2425
|
+
{isDesktopApp && toolsPanelOpen && (
|
|
2426
|
+
<Suspense fallback={<LazyPanelFallback />}>
|
|
2427
|
+
<ToolSurfacePage
|
|
2428
|
+
surfaces={toolSurfaces}
|
|
2429
|
+
activeSurfaceId={activeSurfaceId}
|
|
1898
2430
|
workspacePath={workspacePath}
|
|
2431
|
+
terminalSize={terminalRightWidth}
|
|
2432
|
+
onSelect={setActiveSurfaceId}
|
|
2433
|
+
onClose={closeToolSurface}
|
|
2434
|
+
onCloseAll={closeAllToolSurfaces}
|
|
2435
|
+
onDuplicate={duplicateToolSurface}
|
|
2436
|
+
onRename={renameToolSurface}
|
|
2437
|
+
onCloseOthers={closeOtherToolSurfaces}
|
|
2438
|
+
onOpenTerminal={openTerminalSurface}
|
|
2439
|
+
onOpenBrowser={() => openNativeBrowser()}
|
|
2440
|
+
onOpenReview={openConversationReview}
|
|
2441
|
+
onOpenFiles={() => {
|
|
2442
|
+
setActiveSurfaceId(null)
|
|
2443
|
+
setToolsPanelOpen(false)
|
|
2444
|
+
changeView('workspace')
|
|
2445
|
+
}}
|
|
2446
|
+
onOpenSideChat={() => { setActiveSurfaceId(null); setToolsPanelOpen(false) }}
|
|
2447
|
+
onClosePanel={() => setToolsPanelOpen(false)}
|
|
2448
|
+
onResizeTerminal={(size) => {
|
|
2449
|
+
setTerminalRightWidth(size)
|
|
2450
|
+
if (terminalSaveTimeoutRef.current) clearTimeout(terminalSaveTimeoutRef.current)
|
|
2451
|
+
terminalSaveTimeoutRef.current = setTimeout(() => {
|
|
2452
|
+
window.localStorage.setItem('mint:terminal-right-width', String(size))
|
|
2453
|
+
}, 250)
|
|
2454
|
+
}}
|
|
2455
|
+
onResizePanel={(size) => {
|
|
2456
|
+
setTerminalRightWidth(size)
|
|
2457
|
+
if (terminalSaveTimeoutRef.current) clearTimeout(terminalSaveTimeoutRef.current)
|
|
2458
|
+
terminalSaveTimeoutRef.current = setTimeout(() => {
|
|
2459
|
+
window.localStorage.setItem('mint:terminal-right-width', String(size))
|
|
2460
|
+
}, 250)
|
|
2461
|
+
}}
|
|
1899
2462
|
/>
|
|
2463
|
+
</Suspense>
|
|
2464
|
+
)}
|
|
2465
|
+
{view === 'skills' && (
|
|
2466
|
+
<div className="web-view-scroll" style={{ flex: 1, overflowY: 'auto', background: 'transparent' }}>
|
|
2467
|
+
<Suspense fallback={<LazyPanelFallback />}>
|
|
2468
|
+
<SkillsView
|
|
2469
|
+
listSkills={listLearnedSkills}
|
|
2470
|
+
addSkill={addLearnedSkill}
|
|
2471
|
+
deleteSkill={deleteLearnedSkill}
|
|
2472
|
+
workspacePath={workspacePath}
|
|
2473
|
+
/>
|
|
2474
|
+
</Suspense>
|
|
1900
2475
|
</div>
|
|
1901
2476
|
)}
|
|
1902
2477
|
{view === 'mcp' && (
|
|
1903
|
-
<div style={{ flex: 1, overflowY: 'auto', background: 'transparent' }}>
|
|
1904
|
-
<
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
2478
|
+
<div className="web-view-scroll" style={{ flex: 1, overflowY: 'auto', background: 'transparent' }}>
|
|
2479
|
+
<Suspense fallback={<LazyPanelFallback />}>
|
|
2480
|
+
<McpServersView
|
|
2481
|
+
config={settingsConfig || DEFAULT_CONFIG}
|
|
2482
|
+
updateField={handleUpdateSettingsField}
|
|
2483
|
+
mcpName={mcpName}
|
|
2484
|
+
setMcpName={setMcpName}
|
|
2485
|
+
mcpCmd={mcpCmd}
|
|
2486
|
+
setMcpCmd={setMcpCmd}
|
|
2487
|
+
mcpArgs={mcpArgs}
|
|
2488
|
+
setMcpArgs={setMcpArgs}
|
|
2489
|
+
mcpEnv={mcpEnv}
|
|
2490
|
+
setMcpEnv={setMcpEnv}
|
|
2491
|
+
mcpIcon={mcpIcon}
|
|
2492
|
+
setMcpIcon={setMcpIcon}
|
|
2493
|
+
handleAddMcpServer={handleAddMcpServer}
|
|
2494
|
+
handleRemoveMcpServer={handleRemoveMcpServer}
|
|
2495
|
+
detectTools={detectSystemTools}
|
|
2496
|
+
onReauth={reauthMcpServer}
|
|
2497
|
+
listServerTools={listMcpServerTools}
|
|
2498
|
+
/>
|
|
2499
|
+
</Suspense>
|
|
1923
2500
|
</div>
|
|
1924
2501
|
)}
|
|
1925
2502
|
{view === 'plugins' && (
|
|
1926
|
-
<div style={{ flex: 1, overflowY: 'auto', background: 'transparent' }}>
|
|
1927
|
-
<
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
2503
|
+
<div className="web-view-scroll" style={{ flex: 1, overflowY: 'auto', background: 'transparent' }}>
|
|
2504
|
+
<Suspense fallback={<LazyPanelFallback />}>
|
|
2505
|
+
<PluginsView
|
|
2506
|
+
config={settingsConfig || DEFAULT_CONFIG}
|
|
2507
|
+
updateField={handleUpdateSettingsField}
|
|
2508
|
+
handleConnectPlugin={handleConnectPlugin}
|
|
2509
|
+
/>
|
|
2510
|
+
</Suspense>
|
|
1932
2511
|
</div>
|
|
1933
2512
|
)}
|
|
1934
2513
|
{view === 'cron' && (
|
|
1935
|
-
<div style={{ flex: 1, overflowY: 'auto', background: 'transparent' }}>
|
|
1936
|
-
<
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
2514
|
+
<div className="web-view-scroll" style={{ flex: 1, overflowY: 'auto', background: 'transparent' }}>
|
|
2515
|
+
<Suspense fallback={<LazyPanelFallback />}>
|
|
2516
|
+
<ScheduledTasksView
|
|
2517
|
+
listCronJobs={listCronJobs}
|
|
2518
|
+
addCronJob={addCronJob}
|
|
2519
|
+
removeCronJob={removeCronJob}
|
|
2520
|
+
setCronJobEnabled={setCronJobEnabled}
|
|
2521
|
+
workspacePath={workspacePath}
|
|
2522
|
+
/>
|
|
2523
|
+
</Suspense>
|
|
1943
2524
|
</div>
|
|
1944
2525
|
)}
|
|
1945
2526
|
{view === 'link' && (
|
|
1946
|
-
<div style={{ flex: 1, overflowY: 'auto', background: 'transparent' }}>
|
|
1947
|
-
<
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
2527
|
+
<div className="web-view-scroll" style={{ flex: 1, overflowY: 'auto', background: 'transparent' }}>
|
|
2528
|
+
<Suspense fallback={<LazyPanelFallback />}>
|
|
2529
|
+
<LinkedFoldersView
|
|
2530
|
+
listLinkedFolders={listLinkedFolders}
|
|
2531
|
+
addLinkedFolder={addLinkedFolder}
|
|
2532
|
+
removeLinkedFolder={removeLinkedFolder}
|
|
2533
|
+
linkedFolderStatus={linkedFolderStatus}
|
|
2534
|
+
refreshLinkedFolder={refreshLinkedFolder}
|
|
2535
|
+
listLinkedFolderNotes={listLinkedFolderNotes}
|
|
2536
|
+
readLinkedFolderNote={readLinkedFolderNote}
|
|
2537
|
+
openLinkedFolderNote={openLinkedFolderNote}
|
|
2538
|
+
canOpenNote={isTauriRuntime()}
|
|
2539
|
+
// Desktop: native Tauri picker. Web: asks `mint web` (same
|
|
2540
|
+
// machine) to open its own dialog via a loopback-gated route.
|
|
2541
|
+
selectFolder={selectLinkedFolderPath}
|
|
2542
|
+
/>
|
|
2543
|
+
</Suspense>
|
|
1955
2544
|
</div>
|
|
1956
2545
|
)}
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
2546
|
+
{view === 'code' && (
|
|
2547
|
+
<div className="web-view-scroll" style={{ flex: 1, overflowY: 'auto', background: 'transparent' }}>
|
|
2548
|
+
<Suspense fallback={<LazyPanelFallback />}>
|
|
2549
|
+
<CliSessionsView
|
|
2550
|
+
chatSessions={chatSessions}
|
|
2551
|
+
activeConversationId={conversationId}
|
|
2552
|
+
workspacePath={workspacePath}
|
|
2553
|
+
onSelectSession={(id) => {
|
|
2554
|
+
selectConversation(id)
|
|
2555
|
+
}}
|
|
2556
|
+
onDeleteSession={deleteConversation}
|
|
2557
|
+
onRenameSession={renameConversation}
|
|
2558
|
+
onRefreshSessions={refreshChatSessions}
|
|
2559
|
+
onShowToast={showToast}
|
|
2560
|
+
/>
|
|
2561
|
+
</Suspense>
|
|
2562
|
+
</div>
|
|
2563
|
+
)}
|
|
2564
|
+
{view === 'pictures' && (
|
|
2565
|
+
<Suspense fallback={<LazyPanelFallback />}>
|
|
2566
|
+
<PicturesLibrary view={view} pictures={pictures} onSetView={changeView} onRefreshPictures={refreshPictures} />
|
|
2567
|
+
</Suspense>
|
|
2568
|
+
)}
|
|
2569
|
+
{view === 'imagine' && (
|
|
2570
|
+
<Suspense fallback={<LazyPanelFallback />}>
|
|
2571
|
+
<ImageStudioPanel
|
|
2572
|
+
view={view}
|
|
2573
|
+
onRefreshPictures={refreshPictures}
|
|
2574
|
+
onSendToChat={async (imagePath, imgPrompt) => {
|
|
2575
|
+
try {
|
|
2576
|
+
const response = await fetch(convertFileSrc(imagePath))
|
|
2577
|
+
if (!response.ok) throw new Error(`Unable to load image (${response.status})`)
|
|
2578
|
+
const blob = await response.blob()
|
|
2579
|
+
const imageName = imagePath.split(/[\\/]/).pop() || 'generated-image.png'
|
|
2580
|
+
const dataUri = await readImage(new File([blob], imageName, { type: blob.type || 'image/png' }))
|
|
2581
|
+
const previewDataUri = await createTrimmedImagePreview(dataUri).catch(() => dataUri)
|
|
2582
|
+
|
|
2583
|
+
changeView('chat')
|
|
2584
|
+
conversationActions.compose(imgPrompt)
|
|
2585
|
+
conversationActions.attachImage({ dataUri, previewDataUri, name: imageName })
|
|
2586
|
+
} catch (error) {
|
|
2587
|
+
showToast(`Could not attach image: ${errorMessage(error)}`)
|
|
2588
|
+
}
|
|
2589
|
+
}}
|
|
2590
|
+
/>
|
|
2591
|
+
</Suspense>
|
|
2592
|
+
)}
|
|
2593
|
+
{view === 'veo' && (
|
|
2594
|
+
<Suspense fallback={<LazyPanelFallback />}>
|
|
2595
|
+
<VeoStudioPanel
|
|
2596
|
+
view={view}
|
|
2597
|
+
onSendToChat={(vidPrompt) => {
|
|
2598
|
+
changeView('chat')
|
|
2599
|
+
conversationActions.compose(vidPrompt)
|
|
2600
|
+
}}
|
|
2601
|
+
/>
|
|
2602
|
+
</Suspense>
|
|
2603
|
+
)}
|
|
1975
2604
|
</div>
|
|
1976
2605
|
<div className={`startup-loading ${startupReady ? 'is-hidden' : ''}`} aria-live="polite" aria-busy={!startupReady}>
|
|
1977
2606
|
<div className="startup-loading-content">
|
|
@@ -1991,42 +2620,46 @@ export default function MintDashboard() {
|
|
|
1991
2620
|
</div>
|
|
1992
2621
|
)}
|
|
1993
2622
|
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2623
|
+
{isSearchOpen && (
|
|
2624
|
+
<Suspense fallback={null}>
|
|
2625
|
+
<CommandPalette
|
|
2626
|
+
isOpen
|
|
2627
|
+
onClose={() => setIsSearchOpen(false)}
|
|
2628
|
+
onSelectChat={(chatId) => {
|
|
2629
|
+
selectConversation(chatId)
|
|
2630
|
+
setIsSearchOpen(false)
|
|
2631
|
+
}}
|
|
2632
|
+
onNewChat={() => {
|
|
2633
|
+
clearHistory('New chat')
|
|
2634
|
+
setIsSearchOpen(false)
|
|
2635
|
+
}}
|
|
2636
|
+
onSelectWorkspace={isDesktopApp ? selectWorkspace : undefined}
|
|
2637
|
+
onOpenSettings={() => {
|
|
2638
|
+
changeView('settings')
|
|
2639
|
+
setIsSearchOpen(false)
|
|
2640
|
+
}}
|
|
2641
|
+
onChangeView={(targetView) => {
|
|
2642
|
+
changeView(targetView)
|
|
2643
|
+
setIsSearchOpen(false)
|
|
2644
|
+
}}
|
|
2645
|
+
onChangeModel={(model) => {
|
|
2646
|
+
handleUpdateSettingsField('model', model)
|
|
2647
|
+
setToastMessage(`Switched model to ${model}`)
|
|
2648
|
+
}}
|
|
2649
|
+
onChangeProvider={(provider) => {
|
|
2650
|
+
handleUpdateSettingsField('provider', provider)
|
|
2651
|
+
setToastMessage(`Switched provider to ${provider}`)
|
|
2652
|
+
}}
|
|
2653
|
+
onExecuteSlash={(cmd) => {
|
|
2654
|
+
conversationActions.compose(cmd + ' ')
|
|
2655
|
+
setIsSearchOpen(false)
|
|
2656
|
+
}}
|
|
2657
|
+
chatSessions={chatSessions}
|
|
2658
|
+
currentChatId={conversationId}
|
|
2659
|
+
workspacePath={workspacePath}
|
|
2660
|
+
/>
|
|
2661
|
+
</Suspense>
|
|
2662
|
+
)}
|
|
2030
2663
|
</div>
|
|
2031
2664
|
)
|
|
2032
2665
|
}
|