@pheem49/mint 1.14.0 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (585) hide show
  1. package/CLAUDE.md +1 -1
  2. package/Cargo.lock +291 -11
  3. package/Cargo.toml +1 -1
  4. package/README.md +71 -9
  5. package/ROADMAP.md +30 -0
  6. package/Release_Note.md +579 -465
  7. package/crates/mint-cli/Cargo.toml +3 -1
  8. package/crates/mint-cli/src/agent/approval_prompts.rs +16 -3
  9. package/crates/mint-cli/src/agent/live_status.rs +367 -118
  10. package/crates/mint-cli/src/agent/markdown_render.rs +601 -61
  11. package/crates/mint-cli/src/agent.rs +452 -215
  12. package/crates/mint-cli/src/commands/agent.rs +16 -21
  13. package/crates/mint-cli/src/commands/eval.rs +9 -5
  14. package/crates/mint-cli/src/commands/git.rs +204 -0
  15. package/crates/mint-cli/src/commands/integrations.rs +28 -0
  16. package/crates/mint-cli/src/commands/knowledge.rs +1 -0
  17. package/crates/mint-cli/src/commands/mod.rs +37 -2
  18. package/crates/mint-cli/src/commands/tailnet_web.rs +235 -0
  19. package/crates/mint-cli/src/image.rs +26 -3
  20. package/crates/mint-cli/src/interactive/chat_tui.rs +4742 -0
  21. package/crates/mint-cli/src/interactive/command_ui.rs +477 -0
  22. package/crates/mint-cli/src/interactive/format.rs +8 -0
  23. package/crates/mint-cli/src/interactive/input_box.rs +38 -2
  24. package/crates/mint-cli/src/interactive/picker.rs +180 -37
  25. package/crates/mint-cli/src/interactive/resume_picker.rs +686 -0
  26. package/crates/mint-cli/src/interactive/slash_commands.rs +868 -450
  27. package/crates/mint-cli/src/interactive/thought_viewer.rs +286 -0
  28. package/crates/mint-cli/src/interactive.rs +400 -136
  29. package/crates/mint-cli/src/main.rs +84 -23
  30. package/crates/mint-cli/src/markdown.rs +12 -5
  31. package/crates/mint-cli/src/onboard.rs +32 -30
  32. package/crates/mint-cli/src/plugins_cli.rs +8 -5
  33. package/crates/mint-cli/src/setup.rs +10 -8
  34. package/crates/mint-cli/src/terminal_theme.rs +187 -0
  35. package/crates/mint-cli/src/updater.rs +56 -21
  36. package/crates/mint-core/src/agent/agent_loop.rs +1 -0
  37. package/crates/mint-core/src/agent/chat.rs +843 -177
  38. package/crates/mint-core/src/agent/code_tools.rs +83 -2
  39. package/crates/mint-core/src/agent/memory.rs +658 -20
  40. package/crates/mint-core/src/agent/skills.rs +1 -1
  41. package/crates/mint-core/src/api_server/routes/chat.rs +31 -5
  42. package/crates/mint-core/src/api_server/routes/linked_folders.rs +118 -3
  43. package/crates/mint-core/src/api_server/routes/misc.rs +10 -14
  44. package/crates/mint-core/src/api_server/routes/sessions.rs +44 -0
  45. package/crates/mint-core/src/api_server.rs +22 -3
  46. package/crates/mint-core/src/avatar_bridge.rs +2 -0
  47. package/crates/mint-core/src/browser/cdp.rs +74 -83
  48. package/crates/mint-core/src/browser/evidence.rs +260 -0
  49. package/crates/mint-core/src/browser/input.rs +1 -1
  50. package/crates/mint-core/src/browser/interact.rs +98 -124
  51. package/crates/mint-core/src/browser/lifecycle.rs +75 -4
  52. package/crates/mint-core/src/browser/mod.rs +16 -2
  53. package/crates/mint-core/src/browser/navigate.rs +27 -19
  54. package/crates/mint-core/src/browser/observe.js +40 -0
  55. package/crates/mint-core/src/browser/session.rs +1558 -0
  56. package/crates/mint-core/src/git/branches.rs +348 -0
  57. package/crates/mint-core/src/git/checkpoint.rs +40 -0
  58. package/crates/mint-core/src/git/diff.rs +206 -0
  59. package/crates/mint-core/src/git/mod.rs +10 -2
  60. package/crates/mint-core/src/integrations/channels.rs +1 -0
  61. package/crates/mint-core/src/lib.rs +22 -14
  62. package/crates/mint-core/src/live_sync.rs +28 -9
  63. package/crates/mint-core/src/media/auto_shorts.rs +1 -0
  64. package/crates/mint-core/src/media/gemini_live.rs +12 -1
  65. package/crates/mint-core/src/media/mic_transcribe.rs +1 -0
  66. package/crates/mint-core/src/media/subtitle.rs +1 -0
  67. package/crates/mint-core/src/orchestration/context_render.rs +1 -0
  68. package/crates/mint-core/src/orchestration/memory_skill.rs +6 -1
  69. package/crates/mint-core/src/orchestration/mod.rs +1024 -271
  70. package/crates/mint-core/src/orchestration/tools/browser.rs +16 -139
  71. package/crates/mint-core/src/orchestration/tools/misc.rs +2 -1
  72. package/crates/mint-core/src/orchestration/tools/web.rs +1 -1
  73. package/crates/mint-core/src/prompts/agent.rs +58 -29
  74. package/crates/mint-core/src/prompts/chat.rs +1 -1
  75. package/crates/mint-core/src/prompts/persona.rs +1 -1
  76. package/crates/mint-core/src/prompts/tool_catalog.rs +93 -25
  77. package/crates/mint-core/src/search/linked_folders/index.rs +732 -0
  78. package/crates/mint-core/src/search/linked_folders.rs +391 -130
  79. package/crates/mint-core/src/slash/mod.rs +470 -22
  80. package/crates/mint-core/src/slash/model_fetcher.rs +12 -3
  81. package/crates/mint-core/src/slash/models.rs +66 -10
  82. package/crates/mint-core/src/system/config.rs +230 -0
  83. package/crates/mint-core/src/system/workspace.rs +228 -0
  84. package/crates/mint-core/src/system.rs +1 -0
  85. package/crates/mint-core/tests/memory_persistence.rs +39 -0
  86. package/mint-presentation-demo.mp4 +0 -0
  87. package/out/web/assets/CliSessionsView-BxUVWEEL.js +1 -0
  88. package/out/web/assets/CliSessionsView-CBDTXuQv.css +1 -0
  89. package/out/web/assets/CodeReviewPage-DkMgfcos.css +1 -0
  90. package/out/web/assets/CodeReviewPage-jKlmLJwT.js +3 -0
  91. package/out/web/assets/CommandPalette-DnwPA5hy.js +1 -0
  92. package/out/web/assets/ImageStudioPanel-BR1XFwhR.js +1 -0
  93. package/out/web/assets/ImageStudioPanel-D0lnhQV5.css +1 -0
  94. package/out/web/assets/LinkedFoldersView-bi-CWQ-I.js +1 -0
  95. package/out/web/assets/McpRegistryPicker-D5tEFnyq.js +1 -0
  96. package/out/web/assets/McpServersView-BGG1dhFM.js +1 -0
  97. package/out/web/assets/MintDashboard-BIglDEWX.js +20 -0
  98. package/out/web/assets/MintDashboard-DSMywSgs.css +1 -0
  99. package/out/web/assets/ModelPanel-CbJ1PFoZ.js +1 -0
  100. package/out/web/assets/PicturesLibrary-CQP0fLP1.css +1 -0
  101. package/out/web/assets/PicturesLibrary-DoYN7T1p.js +1 -0
  102. package/out/web/assets/PluginsView-CU1HWXGk.js +1 -0
  103. package/out/web/assets/ScheduledTasksView-Bnl36y2N.js +1 -0
  104. package/out/web/assets/SettingsWindow-DhWLAn9T.css +1 -0
  105. package/out/web/assets/SettingsWindow-Dw8L01pw.js +2 -0
  106. package/out/web/assets/SkillsView-cnl8aY5p.js +2 -0
  107. package/out/web/assets/ToolSurfacePage-CgsQw6l5.css +1 -0
  108. package/out/web/assets/ToolSurfacePage-Cz2VJAPZ.js +37 -0
  109. package/out/web/assets/VeoStudioPanel-D4JnERWR.js +4 -0
  110. package/out/web/assets/VeoStudioPanel-DOj7_WR3.css +1 -0
  111. package/out/web/assets/WorkspacePanel-CbJ1PFoZ.js +1 -0
  112. package/out/web/assets/{abnfDiagram-VCTEODGH-DAOBA7ZG.js → abnfDiagram-VCTEODGH-ByMyfanq.js} +1 -1
  113. package/out/web/assets/{architecture-7GRP2DOG-CgSwQOPQ.js → architecture-7GRP2DOG-CLq2kEOB.js} +1 -1
  114. package/out/web/assets/{architectureDiagram-5GKGNRK7-CYp3yupP.js → architectureDiagram-5GKGNRK7-6PoVSmNG.js} +1 -1
  115. package/out/web/assets/{blockDiagram-NRAW4CY4-CyWybDWr.js → blockDiagram-NRAW4CY4-cKw9mAKi.js} +1 -1
  116. package/out/web/assets/{c4Diagram-UCG6FXSJ-BvY3U709.js → c4Diagram-UCG6FXSJ-Cqy8N5Ge.js} +1 -1
  117. package/out/web/assets/{chunk-75Z2AOVW-TLXCoZYv.js → chunk-75Z2AOVW-3qybijF5.js} +1 -1
  118. package/out/web/assets/chunk-CKBBP62Z-cIrXq6jN.js +2 -0
  119. package/out/web/assets/{chunk-CLGD4ZFX-xjsKtNS7.js → chunk-CLGD4ZFX-CndDQkww.js} +1 -1
  120. package/out/web/assets/chunk-DSNCTWBM-Cc4NxvgD.js +2 -0
  121. package/out/web/assets/chunk-DU6HZSFF-drzh6GsU.js +128 -0
  122. package/out/web/assets/{chunk-F27PBJKO-BFpgF55A.js → chunk-F27PBJKO-FiY35l4v.js} +1 -1
  123. package/out/web/assets/{chunk-G27WJ6UU-DfF7qW-C.js → chunk-G27WJ6UU-Bjt9Il4A.js} +1 -1
  124. package/out/web/assets/{chunk-GMAD6QVW-C-558kh_.js → chunk-GMAD6QVW-Bppi3Ctd.js} +1 -1
  125. package/out/web/assets/{chunk-JQ64N6SF-wJmeGKAw.js → chunk-JQ64N6SF-DGg5kcEV.js} +1 -1
  126. package/out/web/assets/{chunk-LCL6LL3I-C1wHD8Ie.js → chunk-LCL6LL3I-CCYcjd7p.js} +1 -1
  127. package/out/web/assets/{chunk-OBVCFTLP-BsRTPBqs.js → chunk-OBVCFTLP-DJeNil5M.js} +1 -1
  128. package/out/web/assets/{chunk-P2QGCYS3-HZIiM7Ni.js → chunk-P2QGCYS3-lRzkRjBB.js} +1 -1
  129. package/out/web/assets/{chunk-POPQ4Y6H-Dk9wvVb0.js → chunk-POPQ4Y6H-DouASMBW.js} +1 -1
  130. package/out/web/assets/{chunk-PWAF6VOD-BmjYLNbq.js → chunk-PWAF6VOD-DMmD1vVf.js} +1 -1
  131. package/out/web/assets/{chunk-R7TYR2AO-CaHIf-lK.js → chunk-R7TYR2AO-CYLA5UC5.js} +1 -1
  132. package/out/web/assets/{chunk-RHFEMEQ7-_T561hOU.js → chunk-RHFEMEQ7-BiXwEcUT.js} +1 -1
  133. package/out/web/assets/{chunk-SVP7TREG-CM-GGYoY.js → chunk-SVP7TREG-BV-zPslF.js} +1 -1
  134. package/out/web/assets/{chunk-TEH6E4GO-K2A8Vg2C.js → chunk-TEH6E4GO-B2RGEohZ.js} +1 -1
  135. package/out/web/assets/classDiagram-DTDB5LWJ-Dq0smRWk.js +1 -0
  136. package/out/web/assets/classDiagram-v2-JRS7N3AN-Dq0smRWk.js +1 -0
  137. package/out/web/assets/config-C-ZFtipU.css +1 -0
  138. package/out/web/assets/config-eEDngJXO.js +1 -0
  139. package/out/web/assets/core-hQ2VA9Ti.js +1 -0
  140. package/out/web/assets/{cynefin-OW5HDTMX-ClzaB6cc.js → cynefin-OW5HDTMX-Cas4csHM.js} +1 -1
  141. package/out/web/assets/{cynefinDiagram-5FMLGOSQ-D_JzZBzf.js → cynefinDiagram-5FMLGOSQ-Bbpj66Y3.js} +1 -1
  142. package/out/web/assets/{dagre-3AP2YEHR-BDuUeMHj.js → dagre-3AP2YEHR-B0-2RDEd.js} +1 -1
  143. package/out/web/assets/{diagram-S7CK7UJ4-DgtcfE8P.js → diagram-S7CK7UJ4-BdzEjUyH.js} +1 -1
  144. package/out/web/assets/{diagram-UQ7AKVKN-DTLoEYti.js → diagram-UQ7AKVKN-CJDwyPxF.js} +1 -1
  145. package/out/web/assets/{diagram-VSXAHHWV-ChGl9pXz.js → diagram-VSXAHHWV-BxaG1r_B.js} +1 -1
  146. package/out/web/assets/{diagram-VX7I27RA-Be8DWz0S.js → diagram-VX7I27RA-BMmUqm8f.js} +1 -1
  147. package/out/web/assets/{diagram-Z3DM3KII-BMXjRTOF.js → diagram-Z3DM3KII-CFtd03eE.js} +1 -1
  148. package/out/web/assets/dist-js-Bf2bhoku.js +1 -0
  149. package/out/web/assets/{ebnfDiagram-PWID7BFC-8Q9pl1CJ.js → ebnfDiagram-PWID7BFC-DwAen1hO.js} +1 -1
  150. package/out/web/assets/{erDiagram-SSCWMZ5O-DjH8Lnkn.js → erDiagram-SSCWMZ5O-BCZSHACj.js} +1 -1
  151. package/out/web/assets/event-ChBVpRy0.js +1 -0
  152. package/out/web/assets/{eventmodeling-NTZA5JFV-BKUH_DOp.js → eventmodeling-NTZA5JFV-XHStE4E_.js} +1 -1
  153. package/out/web/assets/fira-code-latin-600-normal-BmSSHshu.woff +0 -0
  154. package/out/web/assets/fira-code-latin-600-normal-CvYZpPHg.woff2 +0 -0
  155. package/out/web/assets/fira-code-symbols2-600-normal-Dvq6IQE5.woff +0 -0
  156. package/out/web/assets/flowDiagram-A5DVABFB-BLg7nEcd.js +1 -0
  157. package/out/web/assets/{ganttDiagram-EL5Y4UJY-D7fZKJNM.js → ganttDiagram-EL5Y4UJY-BAEu1Cql.js} +1 -1
  158. package/out/web/assets/{gitGraph-4MIJSDKK-BypWaaBU.js → gitGraph-4MIJSDKK-r32Vyper.js} +1 -1
  159. package/out/web/assets/{gitGraphDiagram-WWUBYQGX-DWiw_3bq.js → gitGraphDiagram-WWUBYQGX-z9o9qt6V.js} +1 -1
  160. package/out/web/assets/index-Btsf4L8M.css +1 -0
  161. package/out/web/assets/index-D8D9MeRA.js +11 -0
  162. package/out/web/assets/{info-A6RAGUB7-KkAUxT4j.js → info-A6RAGUB7-BvLaC2cw.js} +1 -1
  163. package/out/web/assets/{infoDiagram-RXCK75RN-BNb6E48y.js → infoDiagram-RXCK75RN-Be6WAXXw.js} +1 -1
  164. package/out/web/assets/{ishikawaDiagram-5VMMS53U-Caa-JoAK.js → ishikawaDiagram-5VMMS53U-DZjoHJHC.js} +1 -1
  165. package/out/web/assets/{journeyDiagram-EYS64GPL-DOrmFGz6.js → journeyDiagram-EYS64GPL-CtVkjkGm.js} +1 -1
  166. package/out/web/assets/{kanban-definition-3QL26DDD-BOWCYcK0.js → kanban-definition-3QL26DDD-CW5FMv1w.js} +1 -1
  167. package/out/web/assets/lucide-react-Ip3L6Jtn.js +1 -0
  168. package/out/web/assets/markdown-BSeeUbJH.js +38 -0
  169. package/out/web/assets/{mermaid-parser.core-BQqjCkS_.js → mermaid-parser.core-aUgCqsZ5.js} +3 -3
  170. package/out/web/assets/mermaid.core-D57sEiSL.js +11 -0
  171. package/out/web/assets/{mindmap-definition-FBJOCRG2-jTceWpr0.js → mindmap-definition-FBJOCRG2-DAmSpM3a.js} +1 -1
  172. package/out/web/assets/modelManager-tMVmJVAW.js +2 -0
  173. package/out/web/assets/oauthManager-9jxicDWJ.js +1 -0
  174. package/out/web/assets/{packet-AYTQ26CC-CJ5RXgol.js → packet-AYTQ26CC-DJ27iIoJ.js} +1 -1
  175. package/out/web/assets/{pegDiagram-XKGWAZYB-y8wMtd0y.js → pegDiagram-XKGWAZYB-Bj3ii-gS.js} +1 -1
  176. package/out/web/assets/{pie-WAS4IAKB-72fTBbl4.js → pie-WAS4IAKB-DG5mCUbc.js} +1 -1
  177. package/out/web/assets/{pieDiagram-E7YTZNPT-e0O02qWq.js → pieDiagram-E7YTZNPT-BrJLPnDA.js} +1 -1
  178. package/out/web/assets/prompt-latin-700-normal-BfbftDSq.woff +0 -0
  179. package/out/web/assets/prompt-latin-700-normal-I2gc831J.woff2 +0 -0
  180. package/out/web/assets/prompt-thai-700-normal-Cb5ilR-c.woff +0 -0
  181. package/out/web/assets/prompt-thai-700-normal-Cg4aQ0Nn.woff2 +0 -0
  182. package/out/web/assets/{quadrantDiagram-AXDQQJYC-C9phYLom.js → quadrantDiagram-AXDQQJYC-3x_TmF3j.js} +1 -1
  183. package/out/web/assets/{radar-RG4KPBEZ-BAU2hzUT.js → radar-RG4KPBEZ-CrXaTTuV.js} +1 -1
  184. package/out/web/assets/{railroad-74A4TZTK-B0bCAVHC.js → railroad-74A4TZTK-BpqMH9BE.js} +1 -1
  185. package/out/web/assets/{railroad-abnf-HS5TGJTU-WhxO7ndE.js → railroad-abnf-HS5TGJTU-DHI0uLlV.js} +1 -1
  186. package/out/web/assets/{railroad-ebnf-LZEXJU2U-BkA0m7-F.js → railroad-ebnf-LZEXJU2U-CQCb316y.js} +1 -1
  187. package/out/web/assets/{railroad-peg-WCYAUIDC-BsVpHIaj.js → railroad-peg-WCYAUIDC-Ph1giKkH.js} +1 -1
  188. package/out/web/assets/{railroadDiagram-O6MQD6OU-CyOLN65Q.js → railroadDiagram-O6MQD6OU-BRq6wIxx.js} +1 -1
  189. package/out/web/assets/{requirementDiagram-EFPCY7ZU-DQXJ7Dud.js → requirementDiagram-EFPCY7ZU-DIJj6G1g.js} +1 -1
  190. package/out/web/assets/{sankeyDiagram-P5KCCOFB-B2XLyIIc.js → sankeyDiagram-P5KCCOFB-DZajSryq.js} +1 -1
  191. package/out/web/assets/{sequenceDiagram-WJ2MYXX4-DGQY4wwm.js → sequenceDiagram-WJ2MYXX4-DxJCWyZS.js} +1 -1
  192. package/out/web/assets/{stateDiagram-HBIQ2CUA-DHZpDwNy.js → stateDiagram-HBIQ2CUA-k6voi8Vf.js} +1 -1
  193. package/out/web/assets/stateDiagram-v2-4QOOHH4V-DeEc0lGZ.js +1 -0
  194. package/out/web/assets/studio-B1mk40wD.js +1 -0
  195. package/out/web/assets/{swimlanes-XN3QIQJK-Bn_jcZz-.js → swimlanes-XN3QIQJK-igYhTjXB.js} +1 -1
  196. package/out/web/assets/swimlanesDiagram-VK2B7HYN-DpVik9v7.js +8 -0
  197. package/out/web/assets/{timeline-definition-24CTP7MA-CdTERuJZ.js → timeline-definition-24CTP7MA-Dke2p93p.js} +1 -1
  198. package/out/web/assets/{treeView-Q6P3EWNA-TKBKQG6R.js → treeView-Q6P3EWNA-hNELnXUs.js} +1 -1
  199. package/out/web/assets/{treemap-WGGIJYW6-BP7gQoiC.js → treemap-WGGIJYW6-D2B6wDsx.js} +1 -1
  200. package/out/web/assets/{vennDiagram-4TSXK5OY-BHUmxDuK.js → vennDiagram-4TSXK5OY-CDkW7rUP.js} +1 -1
  201. package/out/web/assets/{wardley-WFR3VGLG-9bct5AAN.js → wardley-WFR3VGLG-BECdXETi.js} +1 -1
  202. package/out/web/assets/{wardleyDiagram-VM6X3IG4-BfJwDDso.js → wardleyDiagram-VM6X3IG4-B5BycpQ4.js} +1 -1
  203. package/out/web/assets/window-5qYXKoW7.js +1 -0
  204. package/out/web/assets/{xychartDiagram-S5SC5T6Z-Dqd9Mvpo.js → xychartDiagram-S5SC5T6Z-CtJS3b--.js} +1 -1
  205. package/out/web/index-web.html +3 -4
  206. package/out/web/index.html +3 -4
  207. package/package.json +17 -6
  208. package/skills-lock.json +36 -0
  209. package/slash-commands.json +9 -0
  210. package/src/renderer/index-web.html +1 -0
  211. package/src/renderer/index.html +1 -0
  212. package/src/renderer/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  213. package/src/renderer/shared/agentProgress.ts +168 -3
  214. package/src/renderer/shared/components/AgentActivityDrawer.tsx +6 -6
  215. package/src/renderer/shared/components/AgentActivityTable.tsx +192 -132
  216. package/src/renderer/shared/components/ArtifactPreviewPanel.tsx +4 -4
  217. package/src/renderer/shared/components/AuthGate.tsx +4 -9
  218. package/src/renderer/shared/components/CalculationCard.tsx +41 -15
  219. package/src/renderer/shared/components/ChatMessageItem.tsx +20 -21
  220. package/src/renderer/shared/components/ChatPanel.tsx +432 -193
  221. package/src/renderer/shared/components/ChunkErrorBoundary.tsx +198 -49
  222. package/src/renderer/shared/components/CliSessionsView.tsx +495 -0
  223. package/src/renderer/shared/components/CodeReviewPage.tsx +565 -0
  224. package/src/renderer/shared/components/CommandPalette.tsx +8 -8
  225. package/src/renderer/shared/components/DashboardSidebar.tsx +862 -125
  226. package/src/renderer/shared/components/DesktopTitlebar.tsx +345 -0
  227. package/src/renderer/shared/components/DiffReviewModal.tsx +3 -3
  228. package/src/renderer/shared/components/GitBranchSelector.tsx +442 -0
  229. package/src/renderer/shared/components/ImageGenCard.tsx +31 -12
  230. package/src/renderer/shared/components/ImageSearchCard.tsx +59 -38
  231. package/src/renderer/shared/components/ImageStudioPanel.tsx +40 -41
  232. package/src/renderer/shared/components/InlineThoughtNote.tsx +27 -0
  233. package/src/renderer/shared/components/LinkedFoldersView.tsx +365 -46
  234. package/src/renderer/shared/components/McpRegistryPicker.tsx +1 -1
  235. package/src/renderer/shared/components/McpServersView.tsx +24 -22
  236. package/src/renderer/shared/components/MermaidCard.tsx +14 -8
  237. package/src/renderer/shared/components/MintDashboard.tsx +1141 -508
  238. package/src/renderer/shared/components/ModelSelectorPopover.tsx +535 -214
  239. package/src/renderer/shared/components/PlanChecklistWidget.tsx +1 -1
  240. package/src/renderer/shared/components/PluginsView.tsx +1 -1
  241. package/src/renderer/shared/components/RewindModal.tsx +6 -6
  242. package/src/renderer/shared/components/RunSummaryDashboard.tsx +3 -3
  243. package/src/renderer/shared/components/ScheduledTasksView.tsx +4 -4
  244. package/src/renderer/shared/components/ScreenCaptureDialog.css +221 -0
  245. package/src/renderer/shared/components/ScreenCaptureDialog.tsx +199 -0
  246. package/src/renderer/shared/components/Settings/AgentsTab.tsx +34 -39
  247. package/src/renderer/shared/components/Settings/AudioTab.tsx +8 -8
  248. package/src/renderer/shared/components/Settings/AutomationTab.tsx +8 -58
  249. package/src/renderer/shared/components/Settings/AvatarCropModal.tsx +368 -0
  250. package/src/renderer/shared/components/Settings/GeneralTab.tsx +335 -81
  251. package/src/renderer/shared/components/Settings/MemoryTab.tsx +3 -3
  252. package/src/renderer/shared/components/Settings/PluginsTab.tsx +20 -12
  253. package/src/renderer/shared/components/Settings/ProfileTab.tsx +29 -5
  254. package/src/renderer/shared/components/Settings/SearchableModelCombobox.tsx +411 -0
  255. package/src/renderer/shared/components/Settings/ThemeTab.tsx +401 -158
  256. package/src/renderer/shared/components/SkillsView.tsx +41 -16
  257. package/src/renderer/shared/components/SlashSuggestions.tsx +3 -2
  258. package/src/renderer/shared/components/SourcesBlock.tsx +44 -32
  259. package/src/renderer/shared/components/StockCard.tsx +58 -24
  260. package/src/renderer/shared/components/SubagentDagView.tsx +4 -4
  261. package/src/renderer/shared/components/TerminalDock.tsx +241 -0
  262. package/src/renderer/shared/components/ThinkingBlock.tsx +14 -8
  263. package/src/renderer/shared/components/ToolSurfacePage.tsx +520 -0
  264. package/src/renderer/shared/components/UiFeatureCard.tsx +267 -0
  265. package/src/renderer/shared/components/UiGridCard.tsx +188 -0
  266. package/src/renderer/shared/components/UiMockupWidget.tsx +149 -0
  267. package/src/renderer/shared/components/VeoStudioPanel.tsx +13 -29
  268. package/src/renderer/shared/components/WeatherCard.tsx +3 -3
  269. package/src/renderer/shared/components/WorkspaceContextPopover.tsx +133 -0
  270. package/src/renderer/shared/components/WorkspaceSelector.tsx +149 -0
  271. package/src/renderer/shared/constants/config.ts +28 -3
  272. package/src/renderer/shared/constants/models.ts +189 -2
  273. package/src/renderer/shared/conversation/coordinator.test.ts +27 -0
  274. package/src/renderer/shared/conversation/coordinator.ts +82 -0
  275. package/src/renderer/shared/conversation/syncView.test.ts +46 -0
  276. package/src/renderer/shared/conversation/syncView.ts +43 -0
  277. package/src/renderer/shared/conversation/useConversationCoordinator.ts +106 -0
  278. package/src/renderer/shared/css/agent-observability.css +35 -3
  279. package/src/renderer/shared/css/auth-gate.css +2 -2
  280. package/src/renderer/shared/css/chat-ui-cards.css +495 -0
  281. package/src/renderer/shared/css/code-review.css +823 -0
  282. package/src/renderer/shared/css/code-sessions.css +452 -0
  283. package/src/renderer/shared/css/file-changes.css +132 -0
  284. package/src/renderer/shared/css/image-studio.css +16 -16
  285. package/src/renderer/shared/css/management-views.css +277 -27
  286. package/src/renderer/shared/css/model-selector.css +442 -42
  287. package/src/renderer/shared/css/settings/agents.css +1 -1
  288. package/src/renderer/shared/css/settings/automation.css +13 -13
  289. package/src/renderer/shared/css/settings/general.css +526 -5
  290. package/src/renderer/shared/css/settings/plugins.css +5 -5
  291. package/src/renderer/shared/css/settings/profile.css +331 -1
  292. package/src/renderer/shared/css/settings/theme.css +651 -3
  293. package/src/renderer/shared/css/veo-studio.css +16 -15
  294. package/src/renderer/shared/fonts.ts +19 -37
  295. package/src/renderer/shared/platform.test.ts +34 -0
  296. package/src/renderer/shared/platform.ts +173 -6
  297. package/src/renderer/shared/theme/themeManager.ts +144 -0
  298. package/src/renderer/shared/theme/themes.ts +116 -0
  299. package/src/renderer/shared/theme/tokens.css +318 -0
  300. package/src/renderer/shared/types.ts +82 -1
  301. package/src/renderer/shared/utils/agentActivity.ts +126 -5
  302. package/src/renderer/shared/utils/cardJson.test.ts +35 -0
  303. package/src/renderer/shared/utils/cardJson.ts +30 -0
  304. package/src/renderer/shared/utils/fileIcons.ts +1 -1
  305. package/src/renderer/shared/utils/markdown.tsx +329 -80
  306. package/src/renderer/shared/utils/markdown.webImages.test.tsx +40 -0
  307. package/src/renderer/shared/utils/providers.ts +8 -3
  308. package/src/renderer/shared/utils/screenCapture.ts +43 -0
  309. package/src/renderer/shared/utils/slashCommandProcessor.ts +4 -1
  310. package/src/renderer/shared/utils/ui.ts +4 -64
  311. package/src/renderer/src/App.tsx +7 -0
  312. package/src/renderer/src/components/BrowserShell.tsx +108 -0
  313. package/src/renderer/src/components/BrowserSuggestionsPopup.tsx +91 -0
  314. package/src/renderer/src/components/Live2DStage.tsx +32 -9
  315. package/src/renderer/src/components/MintDashboard.tsx +4 -2
  316. package/src/renderer/src/components/ModelPanel.tsx +2 -1
  317. package/src/renderer/src/components/PicturesLibrary.tsx +3 -2
  318. package/src/renderer/src/components/ScreenPicker.css +190 -0
  319. package/src/renderer/src/components/ScreenPicker.tsx +185 -540
  320. package/src/renderer/src/components/SettingsWindow.tsx +40 -2
  321. package/src/renderer/src/components/SpotlightWindow.tsx +1 -0
  322. package/src/renderer/src/components/WidgetWindow.tsx +27 -3
  323. package/src/renderer/src/components/WorkspacePanel.tsx +61 -43
  324. package/src/renderer/src/components/browser-shell.css +185 -0
  325. package/src/renderer/src/components/browser-suggestions-popup.css +55 -0
  326. package/src/renderer/src/components/liveTranslateFrames.test.ts +23 -0
  327. package/src/renderer/src/components/liveTranslateFrames.ts +34 -0
  328. package/src/renderer/src/css/app-shell.css +394 -113
  329. package/src/renderer/src/css/chat.css +1926 -380
  330. package/src/renderer/src/css/dashboard.css +11 -0
  331. package/src/renderer/src/css/desktop-tools.css +730 -0
  332. package/src/renderer/src/css/misc.css +19 -22
  333. package/src/renderer/src/css/model.css +49 -48
  334. package/src/renderer/src/css/pictures.css +144 -136
  335. package/src/renderer/src/css/settings/base.css +357 -123
  336. package/src/renderer/src/css/sidebar-workspace.css +930 -291
  337. package/src/renderer/src/css/spotlight.css +15 -26
  338. package/src/renderer/src/css/tool-surfaces.css +728 -0
  339. package/src/renderer/src/css/widget.css +35 -7
  340. package/src/renderer/src/env.d.ts +3 -0
  341. package/src/renderer/src/hooks/useProviderModels.ts +2 -9
  342. package/src/renderer/src/index.css +53 -46
  343. package/src/renderer/src/main.tsx +11 -0
  344. package/src/renderer/src/tauri.ts +201 -30
  345. package/src/renderer/src-web/App.tsx +40 -0
  346. package/src/renderer/src-web/components/MintDashboard.tsx +4 -2
  347. package/src/renderer/src-web/components/PicturesLibrary.tsx +3 -2
  348. package/src/renderer/src-web/components/PullToRefresh.tsx +107 -0
  349. package/src/renderer/src-web/components/SettingsWindow.tsx +28 -2
  350. package/src/renderer/src-web/css/app-shell.css +174 -96
  351. package/src/renderer/src-web/css/chat.css +1519 -316
  352. package/src/renderer/src-web/css/dashboard.css +11 -0
  353. package/src/renderer/src-web/css/misc.css +17 -17
  354. package/src/renderer/src-web/css/mobile.css +678 -0
  355. package/src/renderer/src-web/css/model.css +46 -46
  356. package/src/renderer/src-web/css/pictures.css +81 -34
  357. package/src/renderer/src-web/css/pull-to-refresh.css +54 -0
  358. package/src/renderer/src-web/css/settings/base.css +316 -100
  359. package/src/renderer/src-web/css/settings/mobile.css +320 -0
  360. package/src/renderer/src-web/css/sidebar-workspace.css +545 -100
  361. package/src/renderer/src-web/css/spotlight.css +9 -26
  362. package/src/renderer/src-web/css/widget.css +0 -5
  363. package/src/renderer/src-web/env.d.ts +3 -0
  364. package/src/renderer/src-web/hooks/useProviderModels.ts +2 -9
  365. package/src/renderer/src-web/index.css +53 -96
  366. package/src/renderer/src-web/main.tsx +11 -0
  367. package/src/renderer/src-web/tauri.ts +200 -30
  368. package/vite.config.web.ts +1 -0
  369. package/out/web/assets/MintDashboard-DWSqucgb.js +0 -57
  370. package/out/web/assets/SettingsWindow-DFM2aj5B.js +0 -2
  371. package/out/web/assets/chunk-CKBBP62Z-nr1uKPj9.js +0 -2
  372. package/out/web/assets/chunk-DSNCTWBM-Dtj8Rqsd.js +0 -2
  373. package/out/web/assets/chunk-DU6HZSFF-2tv5K1wT.js +0 -128
  374. package/out/web/assets/classDiagram-DTDB5LWJ-BdSFArgw.js +0 -1
  375. package/out/web/assets/classDiagram-v2-JRS7N3AN-BdSFArgw.js +0 -1
  376. package/out/web/assets/core-DImejIUG.js +0 -1
  377. package/out/web/assets/dist-js-BxuKEVWM.js +0 -1
  378. package/out/web/assets/event-BNl8Zahw.js +0 -1
  379. package/out/web/assets/fira-code-cyrillic-400-normal-UC0NFL4U.woff2 +0 -0
  380. package/out/web/assets/fira-code-cyrillic-400-normal-dc1q3VD7.woff +0 -0
  381. package/out/web/assets/fira-code-cyrillic-500-normal-Bu7VCL72.woff +0 -0
  382. package/out/web/assets/fira-code-cyrillic-500-normal-CX35h3Mg.woff2 +0 -0
  383. package/out/web/assets/fira-code-cyrillic-ext-400-normal-Buh61xzB.woff +0 -0
  384. package/out/web/assets/fira-code-cyrillic-ext-400-normal-txZ9Fk_1.woff2 +0 -0
  385. package/out/web/assets/fira-code-cyrillic-ext-500-normal-CYRspHgm.woff2 +0 -0
  386. package/out/web/assets/fira-code-cyrillic-ext-500-normal-CwtLmSFD.woff +0 -0
  387. package/out/web/assets/fira-code-greek-400-normal-B2Gh_Y8s.woff2 +0 -0
  388. package/out/web/assets/fira-code-greek-400-normal-DobhaxvF.woff +0 -0
  389. package/out/web/assets/fira-code-greek-500-normal-CVO0IRNt.woff2 +0 -0
  390. package/out/web/assets/fira-code-greek-500-normal-DEXIWiey.woff +0 -0
  391. package/out/web/assets/fira-code-greek-ext-400-normal-DR7mBgIM.woff2 +0 -0
  392. package/out/web/assets/fira-code-greek-ext-400-normal-DSPUheWg.woff +0 -0
  393. package/out/web/assets/fira-code-greek-ext-500-normal-BO3iq16n.woff2 +0 -0
  394. package/out/web/assets/fira-code-greek-ext-500-normal-CMiNLXER.woff +0 -0
  395. package/out/web/assets/fira-code-latin-ext-400-normal-DG73JjOf.woff +0 -0
  396. package/out/web/assets/fira-code-latin-ext-400-normal-KSMg0QLl.woff2 +0 -0
  397. package/out/web/assets/fira-code-latin-ext-500-normal-CaANqXjI.woff +0 -0
  398. package/out/web/assets/fira-code-latin-ext-500-normal-Crd9e_oI.woff2 +0 -0
  399. package/out/web/assets/flowDiagram-A5DVABFB-BpnHUSU7.js +0 -1
  400. package/out/web/assets/index-CVRg270z.css +0 -1
  401. package/out/web/assets/index-DxZQr9yD.js +0 -10
  402. package/out/web/assets/inter-cyrillic-400-normal-HOLc17fK.woff +0 -0
  403. package/out/web/assets/inter-cyrillic-400-normal-obahsSVq.woff2 +0 -0
  404. package/out/web/assets/inter-cyrillic-500-normal-BasfLYem.woff2 +0 -0
  405. package/out/web/assets/inter-cyrillic-500-normal-CxZf_p3X.woff +0 -0
  406. package/out/web/assets/inter-cyrillic-600-normal-4D_pXhcN.woff +0 -0
  407. package/out/web/assets/inter-cyrillic-600-normal-CWCymEST.woff2 +0 -0
  408. package/out/web/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2 +0 -0
  409. package/out/web/assets/inter-cyrillic-ext-400-normal-DQukG94-.woff +0 -0
  410. package/out/web/assets/inter-cyrillic-ext-500-normal-B0yAr1jD.woff2 +0 -0
  411. package/out/web/assets/inter-cyrillic-ext-500-normal-BmqWE9Dz.woff +0 -0
  412. package/out/web/assets/inter-cyrillic-ext-600-normal-Bcila6Z-.woff +0 -0
  413. package/out/web/assets/inter-cyrillic-ext-600-normal-Dfes3d0z.woff2 +0 -0
  414. package/out/web/assets/inter-greek-400-normal-B4URO6DV.woff2 +0 -0
  415. package/out/web/assets/inter-greek-400-normal-q2sYcFCs.woff +0 -0
  416. package/out/web/assets/inter-greek-500-normal-BIZE56-Y.woff2 +0 -0
  417. package/out/web/assets/inter-greek-500-normal-Xzm54t5V.woff +0 -0
  418. package/out/web/assets/inter-greek-600-normal-BZpKdvQh.woff +0 -0
  419. package/out/web/assets/inter-greek-600-normal-plRanbMR.woff2 +0 -0
  420. package/out/web/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2 +0 -0
  421. package/out/web/assets/inter-greek-ext-400-normal-KugGGMne.woff +0 -0
  422. package/out/web/assets/inter-greek-ext-500-normal-2j5mBUwD.woff +0 -0
  423. package/out/web/assets/inter-greek-ext-500-normal-C4iEst2y.woff2 +0 -0
  424. package/out/web/assets/inter-greek-ext-600-normal-B8X0CLgF.woff +0 -0
  425. package/out/web/assets/inter-greek-ext-600-normal-DRtmH8MT.woff2 +0 -0
  426. package/out/web/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
  427. package/out/web/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
  428. package/out/web/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
  429. package/out/web/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
  430. package/out/web/assets/inter-latin-600-normal-CiBQ2DWP.woff +0 -0
  431. package/out/web/assets/inter-latin-600-normal-LgqL8muc.woff2 +0 -0
  432. package/out/web/assets/inter-latin-ext-400-normal-77YHD8bZ.woff +0 -0
  433. package/out/web/assets/inter-latin-ext-400-normal-C1nco2VV.woff2 +0 -0
  434. package/out/web/assets/inter-latin-ext-500-normal-BxGbmqWO.woff +0 -0
  435. package/out/web/assets/inter-latin-ext-500-normal-CV4jyFjo.woff2 +0 -0
  436. package/out/web/assets/inter-latin-ext-600-normal-CIVaiw4L.woff +0 -0
  437. package/out/web/assets/inter-latin-ext-600-normal-D2bJ5OIk.woff2 +0 -0
  438. package/out/web/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff +0 -0
  439. package/out/web/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
  440. package/out/web/assets/inter-vietnamese-500-normal-DOriooB6.woff2 +0 -0
  441. package/out/web/assets/inter-vietnamese-500-normal-mJboJaSs.woff +0 -0
  442. package/out/web/assets/inter-vietnamese-600-normal-BuLX-rYi.woff +0 -0
  443. package/out/web/assets/inter-vietnamese-600-normal-Cc8MFFhd.woff2 +0 -0
  444. package/out/web/assets/kanit-latin-400-normal-BUlsQXH3.woff2 +0 -0
  445. package/out/web/assets/kanit-latin-400-normal-HVZWrfev.woff +0 -0
  446. package/out/web/assets/kanit-latin-500-normal-CX_4XcKi.woff2 +0 -0
  447. package/out/web/assets/kanit-latin-500-normal-qBha86O4.woff +0 -0
  448. package/out/web/assets/kanit-latin-600-normal-0lS78yAd.woff2 +0 -0
  449. package/out/web/assets/kanit-latin-600-normal-DlacpeTg.woff +0 -0
  450. package/out/web/assets/kanit-latin-ext-400-normal-B2xPf58u.woff2 +0 -0
  451. package/out/web/assets/kanit-latin-ext-400-normal-CHvNKHHD.woff +0 -0
  452. package/out/web/assets/kanit-latin-ext-500-normal-BFdWrG22.woff +0 -0
  453. package/out/web/assets/kanit-latin-ext-500-normal-EHs3suD6.woff2 +0 -0
  454. package/out/web/assets/kanit-latin-ext-600-normal-BBDzoLaj.woff +0 -0
  455. package/out/web/assets/kanit-latin-ext-600-normal-DAX3wtuq.woff2 +0 -0
  456. package/out/web/assets/kanit-thai-400-normal-D2nliXKa.woff +0 -0
  457. package/out/web/assets/kanit-thai-400-normal-D80Pglro.woff2 +0 -0
  458. package/out/web/assets/kanit-thai-500-normal-BB8gri04.woff2 +0 -0
  459. package/out/web/assets/kanit-thai-500-normal-Iy_w0a80.woff +0 -0
  460. package/out/web/assets/kanit-thai-600-normal-Bj6oiaDc.woff2 +0 -0
  461. package/out/web/assets/kanit-thai-600-normal-wbTlPO7I.woff +0 -0
  462. package/out/web/assets/kanit-vietnamese-400-normal-DRI8YWyb.woff2 +0 -0
  463. package/out/web/assets/kanit-vietnamese-400-normal-dow6Bnto.woff +0 -0
  464. package/out/web/assets/kanit-vietnamese-500-normal-BzTrpCM3.woff2 +0 -0
  465. package/out/web/assets/kanit-vietnamese-500-normal-T1ndT7MF.woff +0 -0
  466. package/out/web/assets/kanit-vietnamese-600-normal-Bi7fw3I4.woff2 +0 -0
  467. package/out/web/assets/kanit-vietnamese-600-normal-DXCRAa_8.woff +0 -0
  468. package/out/web/assets/mali-latin-400-normal-ByPcZ8Gx.woff +0 -0
  469. package/out/web/assets/mali-latin-400-normal-Cuc6Ykl8.woff2 +0 -0
  470. package/out/web/assets/mali-latin-500-normal-B01M-LP6.woff2 +0 -0
  471. package/out/web/assets/mali-latin-500-normal-Thgqw_9f.woff +0 -0
  472. package/out/web/assets/mali-latin-600-normal-B9TiUNpT.woff2 +0 -0
  473. package/out/web/assets/mali-latin-600-normal-CycpQCwU.woff +0 -0
  474. package/out/web/assets/mali-latin-ext-400-normal-DUVdJQO4.woff +0 -0
  475. package/out/web/assets/mali-latin-ext-400-normal-iCG1ALuJ.woff2 +0 -0
  476. package/out/web/assets/mali-latin-ext-500-normal-BfJE4UMZ.woff2 +0 -0
  477. package/out/web/assets/mali-latin-ext-500-normal-FoLEyOKS.woff +0 -0
  478. package/out/web/assets/mali-latin-ext-600-normal-BTvIfiCp.woff2 +0 -0
  479. package/out/web/assets/mali-latin-ext-600-normal-DAQcLVmD.woff +0 -0
  480. package/out/web/assets/mali-thai-400-normal-BO7A3bLZ.woff2 +0 -0
  481. package/out/web/assets/mali-thai-400-normal-CX9VrjTn.woff +0 -0
  482. package/out/web/assets/mali-thai-500-normal-Cph2qha9.woff +0 -0
  483. package/out/web/assets/mali-thai-500-normal-D89rMT77.woff2 +0 -0
  484. package/out/web/assets/mali-thai-600-normal-DPgXT6rZ.woff +0 -0
  485. package/out/web/assets/mali-thai-600-normal-DlTx3OsB.woff2 +0 -0
  486. package/out/web/assets/mali-vietnamese-400-normal-DUKxzXaz.woff2 +0 -0
  487. package/out/web/assets/mali-vietnamese-400-normal-gFDLvsOK.woff +0 -0
  488. package/out/web/assets/mali-vietnamese-500-normal--OY07q2c.woff +0 -0
  489. package/out/web/assets/mali-vietnamese-500-normal-KDrNRwfW.woff2 +0 -0
  490. package/out/web/assets/mali-vietnamese-600-normal-CtTMUU7T.woff +0 -0
  491. package/out/web/assets/mali-vietnamese-600-normal-DFlJr66u.woff2 +0 -0
  492. package/out/web/assets/mermaid.core-DYGGlqOf.js +0 -11
  493. package/out/web/assets/mitr-latin-400-normal-Cb18vPmZ.woff +0 -0
  494. package/out/web/assets/mitr-latin-400-normal-CwbkLQ4a.woff2 +0 -0
  495. package/out/web/assets/mitr-latin-500-normal-B4JOhzAi.woff +0 -0
  496. package/out/web/assets/mitr-latin-500-normal-BmClOow2.woff2 +0 -0
  497. package/out/web/assets/mitr-latin-ext-400-normal-B3CPG7Yo.woff2 +0 -0
  498. package/out/web/assets/mitr-latin-ext-400-normal-DTx65hiC.woff +0 -0
  499. package/out/web/assets/mitr-latin-ext-500-normal-B_Diajz1.woff2 +0 -0
  500. package/out/web/assets/mitr-latin-ext-500-normal-DYOsVaVT.woff +0 -0
  501. package/out/web/assets/mitr-thai-400-normal-CS4Do6aM.woff +0 -0
  502. package/out/web/assets/mitr-thai-400-normal-CXWaAdVj.woff2 +0 -0
  503. package/out/web/assets/mitr-thai-500-normal-CVdBrEVH.woff2 +0 -0
  504. package/out/web/assets/mitr-thai-500-normal-CW_B5D-i.woff +0 -0
  505. package/out/web/assets/mitr-vietnamese-400-normal-CPMGWyoC.woff2 +0 -0
  506. package/out/web/assets/mitr-vietnamese-400-normal-Z6XhIpdY.woff +0 -0
  507. package/out/web/assets/mitr-vietnamese-500-normal-CDrv0585.woff2 +0 -0
  508. package/out/web/assets/mitr-vietnamese-500-normal-CMQWyq-Z.woff +0 -0
  509. package/out/web/assets/noto-sans-thai-latin-400-normal-BaWBrqFP.woff2 +0 -0
  510. package/out/web/assets/noto-sans-thai-latin-400-normal-Dh_FJjOB.woff +0 -0
  511. package/out/web/assets/noto-sans-thai-latin-500-normal-BC04jsmm.woff +0 -0
  512. package/out/web/assets/noto-sans-thai-latin-500-normal-fyBKClF1.woff2 +0 -0
  513. package/out/web/assets/noto-sans-thai-latin-600-normal-CemcjnVR.woff2 +0 -0
  514. package/out/web/assets/noto-sans-thai-latin-600-normal-Dbc-dNO6.woff +0 -0
  515. package/out/web/assets/noto-sans-thai-latin-ext-400-normal-B-1H0YkH.woff +0 -0
  516. package/out/web/assets/noto-sans-thai-latin-ext-400-normal-nBP59pVw.woff2 +0 -0
  517. package/out/web/assets/noto-sans-thai-latin-ext-500-normal-B-ZWb8SZ.woff2 +0 -0
  518. package/out/web/assets/noto-sans-thai-latin-ext-500-normal-CrEHO7C8.woff +0 -0
  519. package/out/web/assets/noto-sans-thai-latin-ext-600-normal-PkMZo0xa.woff +0 -0
  520. package/out/web/assets/noto-sans-thai-latin-ext-600-normal-maHHBsez.woff2 +0 -0
  521. package/out/web/assets/noto-sans-thai-thai-400-normal-BEOmKAI1.woff2 +0 -0
  522. package/out/web/assets/noto-sans-thai-thai-400-normal-Dxb_unuU.woff +0 -0
  523. package/out/web/assets/noto-sans-thai-thai-500-normal-BOGXO2tw.woff +0 -0
  524. package/out/web/assets/noto-sans-thai-thai-500-normal-CU_X86GQ.woff2 +0 -0
  525. package/out/web/assets/noto-sans-thai-thai-600-normal-CmgB8_JK.woff +0 -0
  526. package/out/web/assets/noto-sans-thai-thai-600-normal-Cs73sVjl.woff2 +0 -0
  527. package/out/web/assets/oauthManager-DNiwM8Rn.js +0 -2
  528. package/out/web/assets/oauthManager-DuamS1Av.css +0 -1
  529. package/out/web/assets/outfit-latin-300-normal-AWLfuCom.woff +0 -0
  530. package/out/web/assets/outfit-latin-300-normal-CRYTwY6m.woff2 +0 -0
  531. package/out/web/assets/outfit-latin-400-normal-BGsTXAXT.woff2 +0 -0
  532. package/out/web/assets/outfit-latin-400-normal-DMwTpYkH.woff +0 -0
  533. package/out/web/assets/outfit-latin-500-normal-ClnHRwRh.woff +0 -0
  534. package/out/web/assets/outfit-latin-500-normal-DKnIMDSk.woff2 +0 -0
  535. package/out/web/assets/outfit-latin-600-normal-B7SfZ07L.woff2 +0 -0
  536. package/out/web/assets/outfit-latin-600-normal-BEfTtDA7.woff +0 -0
  537. package/out/web/assets/outfit-latin-ext-300-normal-BYS6Dpvq.woff2 +0 -0
  538. package/out/web/assets/outfit-latin-ext-300-normal-CMIMshEd.woff +0 -0
  539. package/out/web/assets/outfit-latin-ext-400-normal-5tcqmc2S.woff2 +0 -0
  540. package/out/web/assets/outfit-latin-ext-400-normal-DHm7mdGe.woff +0 -0
  541. package/out/web/assets/outfit-latin-ext-500-normal-DrCvqoFD.woff +0 -0
  542. package/out/web/assets/outfit-latin-ext-500-normal-zeox_O30.woff2 +0 -0
  543. package/out/web/assets/outfit-latin-ext-600-normal-B85nYjL1.woff2 +0 -0
  544. package/out/web/assets/outfit-latin-ext-600-normal-CWJcPgd7.woff +0 -0
  545. package/out/web/assets/preload-helper-D0uHx7FM.js +0 -1
  546. package/out/web/assets/prompt-latin-ext-400-normal-1pHbN9uy.woff +0 -0
  547. package/out/web/assets/prompt-latin-ext-400-normal-DdSafGZ9.woff2 +0 -0
  548. package/out/web/assets/prompt-latin-ext-500-normal--EZ1um7s.woff2 +0 -0
  549. package/out/web/assets/prompt-latin-ext-500-normal-D-lI1EVT.woff +0 -0
  550. package/out/web/assets/prompt-latin-ext-600-normal-C8b50x67.woff +0 -0
  551. package/out/web/assets/prompt-latin-ext-600-normal-Cg9L7iJU.woff2 +0 -0
  552. package/out/web/assets/prompt-vietnamese-400-normal-BCPzsgPT.woff2 +0 -0
  553. package/out/web/assets/prompt-vietnamese-400-normal-D4pLyeNK.woff +0 -0
  554. package/out/web/assets/prompt-vietnamese-500-normal-DmzxmPwa.woff2 +0 -0
  555. package/out/web/assets/prompt-vietnamese-500-normal-w_sS_j2F.woff +0 -0
  556. package/out/web/assets/prompt-vietnamese-600-normal-1dyohtNh.woff +0 -0
  557. package/out/web/assets/prompt-vietnamese-600-normal-7QWjJBsF.woff2 +0 -0
  558. package/out/web/assets/sarabun-latin-400-normal-DmguIS-7.woff +0 -0
  559. package/out/web/assets/sarabun-latin-400-normal-URPBxl-K.woff2 +0 -0
  560. package/out/web/assets/sarabun-latin-500-normal-BjUTcdxu.woff2 +0 -0
  561. package/out/web/assets/sarabun-latin-500-normal-CJexTAnl.woff +0 -0
  562. package/out/web/assets/sarabun-latin-600-normal-9FonlkKx.woff +0 -0
  563. package/out/web/assets/sarabun-latin-600-normal-DMD3TROr.woff2 +0 -0
  564. package/out/web/assets/sarabun-latin-ext-400-normal-BbP7GpLL.woff2 +0 -0
  565. package/out/web/assets/sarabun-latin-ext-400-normal-BsmTn0SS.woff +0 -0
  566. package/out/web/assets/sarabun-latin-ext-500-normal-Cot16Bd2.woff +0 -0
  567. package/out/web/assets/sarabun-latin-ext-500-normal-DE1LysqI.woff2 +0 -0
  568. package/out/web/assets/sarabun-latin-ext-600-normal-0tXu9x_i.woff +0 -0
  569. package/out/web/assets/sarabun-latin-ext-600-normal-BRxjKUQ6.woff2 +0 -0
  570. package/out/web/assets/sarabun-thai-400-normal-C2DaJlKK.woff2 +0 -0
  571. package/out/web/assets/sarabun-thai-400-normal-CH-UbWgg.woff +0 -0
  572. package/out/web/assets/sarabun-thai-500-normal-BVssjame.woff2 +0 -0
  573. package/out/web/assets/sarabun-thai-500-normal-C3iDLEzi.woff +0 -0
  574. package/out/web/assets/sarabun-thai-600-normal-3dIAQ-_s.woff2 +0 -0
  575. package/out/web/assets/sarabun-thai-600-normal-DWKeTe6a.woff +0 -0
  576. package/out/web/assets/sarabun-vietnamese-400-normal-DPfkSCMy.woff +0 -0
  577. package/out/web/assets/sarabun-vietnamese-400-normal-igdrzAGY.woff2 +0 -0
  578. package/out/web/assets/sarabun-vietnamese-500-normal-CpRVvGRU.woff +0 -0
  579. package/out/web/assets/sarabun-vietnamese-500-normal-Dpe7Br9m.woff2 +0 -0
  580. package/out/web/assets/sarabun-vietnamese-600-normal-BMbOgAW-.woff +0 -0
  581. package/out/web/assets/sarabun-vietnamese-600-normal-DkxrOlLB.woff2 +0 -0
  582. package/out/web/assets/stateDiagram-v2-4QOOHH4V-s6P9g2_b.js +0 -1
  583. package/out/web/assets/swimlanesDiagram-VK2B7HYN-CV9fOLrV.js +0 -8
  584. package/out/web/assets/tauri-CNrHQ2Gb.js +0 -3
  585. package/out/web/assets/window-DkIhgI7B.js +0 -1
@@ -1,6 +1,6 @@
1
1
  use std::path::{Path, PathBuf};
2
2
 
3
- use rusqlite::{Connection, OptionalExtension, params};
3
+ use rusqlite::{Connection, OptionalExtension, TransactionBehavior, params};
4
4
  use serde::{Deserialize, Serialize};
5
5
  use thiserror::Error;
6
6
 
@@ -27,11 +27,17 @@ pub fn scoped_chat_id(chat_id: &str, _workspace_path: Option<&str>) -> String {
27
27
  /// (`"cli::subagent::<name>"`, or `"cli::<hash>::subagent::<name>"`) —
28
28
  /// those must keep behaving like a normal, deletable conversation exactly
29
29
  /// as they do today, unaffected by workspace scoping.
30
- fn is_cli_chat_id(chat_id: &str) -> bool {
30
+ pub fn is_cli_chat_id(chat_id: &str) -> bool {
31
31
  chat_id == CHAT_CLI_ID
32
32
  || (chat_id.starts_with(&format!("{CHAT_CLI_ID}::")) && !chat_id.contains("::subagent::"))
33
33
  }
34
34
 
35
+ pub fn generate_cli_session_id() -> String {
36
+ let raw_uuid = uuid::Uuid::new_v4().to_string();
37
+ let short_id = &raw_uuid.replace('-', "")[..12];
38
+ format!("cli::{short_id}")
39
+ }
40
+
35
41
  /// The subagent name embedded in a chat id of the form
36
42
  /// `"<parent>::subagent::<name>"` (see `dispatch_one_subagent`), or `None` for
37
43
  /// an ordinary conversation. Used to scope which agent a fact belongs to and
@@ -72,11 +78,36 @@ pub struct InteractionMemory {
72
78
  pub model: String,
73
79
  pub fallback_provider: Option<String>,
74
80
  pub created_at: String,
81
+ pub status: String,
75
82
  #[serde(default, skip_serializing_if = "Option::is_none")]
76
83
  pub agent_activity: Option<serde_json::Value>,
77
84
  }
78
85
 
79
- #[derive(Debug, Clone, Serialize, PartialEq, Eq)]
86
+ #[derive(Debug, Clone, Serialize)]
87
+ #[serde(rename_all = "camelCase")]
88
+ pub struct ConversationChange {
89
+ pub sequence: i64,
90
+ pub interaction_id: i64,
91
+ pub interaction: Option<InteractionMemory>,
92
+ }
93
+
94
+ #[derive(Debug, Clone, Serialize)]
95
+ #[serde(rename_all = "camelCase")]
96
+ pub struct ConversationChanges {
97
+ pub changes: Vec<ConversationChange>,
98
+ pub cursor: i64,
99
+ pub has_more: bool,
100
+ }
101
+
102
+ #[derive(Debug, Clone, Serialize)]
103
+ #[serde(rename_all = "camelCase")]
104
+ pub struct ConversationSnapshot {
105
+ pub interactions: Vec<InteractionMemory>,
106
+ pub cursor: i64,
107
+ pub has_older: bool,
108
+ }
109
+
110
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
80
111
  #[serde(rename_all = "camelCase")]
81
112
  pub struct ChatSession {
82
113
  pub id: String,
@@ -84,6 +115,16 @@ pub struct ChatSession {
84
115
  pub kind: String,
85
116
  pub created_at: String,
86
117
  pub updated_at: String,
118
+ #[serde(default, skip_serializing_if = "Option::is_none")]
119
+ pub workspace_path: Option<String>,
120
+ #[serde(default, skip_serializing_if = "Option::is_none")]
121
+ pub git_branch: Option<String>,
122
+ #[serde(default, skip_serializing_if = "Option::is_none")]
123
+ pub main_language: Option<String>,
124
+ #[serde(default)]
125
+ pub message_count: usize,
126
+ #[serde(default)]
127
+ pub total_bytes: usize,
87
128
  }
88
129
 
89
130
  #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
@@ -220,6 +261,232 @@ impl MemoryStore {
220
261
  Ok(connection.last_insert_rowid())
221
262
  }
222
263
 
264
+ /// Insert a visible prompt before any provider or tool work begins.
265
+ pub fn start_turn(&self, chat_id: &str, user_text: &str) -> Result<i64, MemoryError> {
266
+ let chat_id = normalized_chat_id(chat_id);
267
+ let mut connection = self.connection()?;
268
+ let tx = connection.transaction_with_behavior(TransactionBehavior::Immediate)?;
269
+ ensure_chat_session_row(&tx, &chat_id)?;
270
+ tx.execute(
271
+ "INSERT INTO interaction_memories (chat_id, user_text, ai_text, status, lease_until)
272
+ VALUES (?1, ?2, '', 'queued', unixepoch() + 45)",
273
+ params![chat_id, user_text],
274
+ )?;
275
+ let id = tx.last_insert_rowid();
276
+ tx.execute(
277
+ "UPDATE chat_sessions SET title = CASE
278
+ WHEN title = 'New chat' AND trim(?2) != '' THEN substr(trim(?2), 1, 80)
279
+ ELSE title END, updated_at = CURRENT_TIMESTAMP WHERE id = ?1",
280
+ params![chat_id, user_text],
281
+ )?;
282
+ tx.commit()?;
283
+ Ok(id)
284
+ }
285
+
286
+ /// Claim only the oldest unfinished turn. The short transaction never spans AI work.
287
+ pub fn claim_turn(&self, chat_id: &str, id: i64) -> Result<bool, MemoryError> {
288
+ let chat_id = normalized_chat_id(chat_id);
289
+ let mut connection = self.connection()?;
290
+ let tx = connection.transaction_with_behavior(TransactionBehavior::Immediate)?;
291
+ tx.execute(
292
+ "UPDATE interaction_memories SET status = 'interrupted', lease_until = 0
293
+ WHERE chat_id = ?1 AND status IN ('queued', 'running') AND lease_until < unixepoch()",
294
+ params![chat_id],
295
+ )?;
296
+ let own_status: Option<String> = tx
297
+ .query_row(
298
+ "SELECT status FROM interaction_memories WHERE id = ?1 AND chat_id = ?2",
299
+ params![id, chat_id],
300
+ |row| row.get(0),
301
+ )
302
+ .optional()?;
303
+ if own_status.as_deref() != Some("queued") {
304
+ tx.commit()?;
305
+ return Err(MemoryError::Database(rusqlite::Error::QueryReturnedNoRows));
306
+ }
307
+ let earlier: i64 = tx.query_row(
308
+ "SELECT count(*) FROM interaction_memories
309
+ WHERE chat_id = ?1 AND id < ?2 AND status IN ('queued', 'running')",
310
+ params![chat_id, id],
311
+ |row| row.get(0),
312
+ )?;
313
+ let claimed = if earlier == 0 {
314
+ tx.execute(
315
+ "UPDATE interaction_memories SET status = 'running', lease_until = unixepoch() + 45
316
+ WHERE id = ?1 AND chat_id = ?2 AND status = 'queued'",
317
+ params![id, chat_id],
318
+ )? == 1
319
+ } else {
320
+ false
321
+ };
322
+ tx.commit()?;
323
+ Ok(claimed)
324
+ }
325
+
326
+ pub fn renew_turn(&self, id: i64) -> Result<(), MemoryError> {
327
+ self.connection()?.execute(
328
+ "UPDATE interaction_memories SET lease_until = unixepoch() + 45
329
+ WHERE id = ?1 AND status IN ('queued', 'running')",
330
+ params![id],
331
+ )?;
332
+ Ok(())
333
+ }
334
+
335
+ fn expire_abandoned_turns(&self, chat_id: &str) -> Result<(), MemoryError> {
336
+ self.connection()?.execute(
337
+ "UPDATE interaction_memories SET status = 'interrupted', lease_until = 0
338
+ WHERE chat_id = ?1 AND status IN ('queued', 'running') AND lease_until < unixepoch()",
339
+ params![normalized_chat_id(chat_id)],
340
+ )?;
341
+ Ok(())
342
+ }
343
+
344
+ pub fn finish_turn(
345
+ &self,
346
+ id: i64,
347
+ ai_text: &str,
348
+ provider: &str,
349
+ model: &str,
350
+ fallback_provider: Option<&str>,
351
+ ) -> Result<(), MemoryError> {
352
+ let connection = self.connection()?;
353
+ let changed = connection.execute(
354
+ "UPDATE interaction_memories SET ai_text = ?2, provider = ?3, model = ?4,
355
+ fallback_provider = ?5, status = 'completed', lease_until = 0
356
+ WHERE id = ?1 AND status = 'running'",
357
+ params![id, ai_text, provider, model, fallback_provider],
358
+ )?;
359
+ if changed != 1 {
360
+ return Err(MemoryError::Database(rusqlite::Error::QueryReturnedNoRows));
361
+ }
362
+ Ok(())
363
+ }
364
+
365
+ pub fn end_turn(&self, id: i64, status: &str) -> Result<(), MemoryError> {
366
+ if !matches!(status, "failed" | "interrupted") {
367
+ return Ok(());
368
+ }
369
+ self.connection()?.execute(
370
+ "UPDATE interaction_memories SET status = ?2, lease_until = 0
371
+ WHERE id = ?1 AND status IN ('queued', 'running')",
372
+ params![id, status],
373
+ )?;
374
+ Ok(())
375
+ }
376
+
377
+ pub fn conversation_changes(
378
+ &self,
379
+ chat_id: &str,
380
+ after: i64,
381
+ limit: usize,
382
+ ) -> Result<ConversationChanges, MemoryError> {
383
+ let chat_id = normalized_chat_id(chat_id);
384
+ self.expire_abandoned_turns(&chat_id)?;
385
+ let connection = self.connection()?;
386
+ let mut statement = connection.prepare(
387
+ "SELECT c.sequence, c.interaction_id,
388
+ m.id, m.chat_id, m.user_text, m.ai_text, m.provider, m.model,
389
+ m.fallback_provider, m.created_at, m.agent_activity_json, m.status
390
+ FROM conversation_changes c
391
+ LEFT JOIN interaction_memories m ON m.id = c.interaction_id AND m.chat_id = c.chat_id
392
+ WHERE c.chat_id = ?1 AND c.sequence > ?2 ORDER BY c.sequence LIMIT ?3",
393
+ )?;
394
+ let rows = statement.query_map(
395
+ params![chat_id, after, limit.clamp(1, 200) as i64 + 1],
396
+ |row| {
397
+ let sequence: i64 = row.get(0)?;
398
+ let interaction_id: i64 = row.get(1)?;
399
+ let interaction = if row.get::<_, Option<i64>>(2)?.is_some() {
400
+ let agent_activity = row
401
+ .get::<_, Option<String>>(10)?
402
+ .and_then(|raw| serde_json::from_str(&raw).ok());
403
+ let created: String = row.get(9)?;
404
+ Some(InteractionMemory {
405
+ id: row.get(2)?,
406
+ chat_id: row.get(3)?,
407
+ user_text: row.get(4)?,
408
+ ai_text: row.get(5)?,
409
+ provider: row.get(6)?,
410
+ model: row.get(7)?,
411
+ fallback_provider: row.get(8)?,
412
+ created_at: normalize_sqlite_utc_timestamp(&created),
413
+ agent_activity,
414
+ status: row.get(11)?,
415
+ })
416
+ } else {
417
+ None
418
+ };
419
+ Ok(ConversationChange {
420
+ sequence,
421
+ interaction_id,
422
+ interaction,
423
+ })
424
+ },
425
+ )?;
426
+ let mut changes = rows.collect::<Result<Vec<_>, _>>()?;
427
+ let has_more = changes.len() > limit.clamp(1, 200);
428
+ if has_more {
429
+ changes.pop();
430
+ }
431
+ let cursor = changes.last().map_or(after, |change| change.sequence);
432
+ Ok(ConversationChanges {
433
+ changes,
434
+ cursor,
435
+ has_more,
436
+ })
437
+ }
438
+
439
+ pub fn latest_conversation_sequence(&self, chat_id: &str) -> Result<i64, MemoryError> {
440
+ self.expire_abandoned_turns(chat_id)?;
441
+ let connection = self.connection()?;
442
+ Ok(connection.query_row(
443
+ "SELECT coalesce(max(sequence), 0) FROM conversation_changes WHERE chat_id = ?1",
444
+ params![normalized_chat_id(chat_id)],
445
+ |row| row.get(0),
446
+ )?)
447
+ }
448
+
449
+ pub fn conversation_snapshot(
450
+ &self,
451
+ chat_id: &str,
452
+ before_id: Option<i64>,
453
+ limit: usize,
454
+ ) -> Result<ConversationSnapshot, MemoryError> {
455
+ let chat_id = normalized_chat_id(chat_id);
456
+ self.expire_abandoned_turns(&chat_id)?;
457
+ let mut connection = self.connection()?;
458
+ let tx = connection.transaction()?;
459
+ let cursor: i64 = tx.query_row(
460
+ "SELECT coalesce(max(sequence), 0) FROM conversation_changes WHERE chat_id = ?1",
461
+ params![chat_id],
462
+ |row| row.get(0),
463
+ )?;
464
+ let mut statement = tx.prepare(
465
+ "SELECT id, chat_id, user_text, ai_text, provider, model, fallback_provider,
466
+ created_at, agent_activity_json, status FROM interaction_memories
467
+ WHERE chat_id = ?1 AND (?2 IS NULL OR id < ?2)
468
+ ORDER BY id DESC LIMIT ?3",
469
+ )?;
470
+ let page_size = limit.clamp(1, 200);
471
+ let rows = statement.query_map(
472
+ params![chat_id, before_id, page_size as i64 + 1],
473
+ interaction_row,
474
+ )?;
475
+ let mut interactions = rows.collect::<Result<Vec<_>, _>>()?;
476
+ let has_older = interactions.len() > page_size;
477
+ if has_older {
478
+ interactions.pop();
479
+ }
480
+ interactions.reverse();
481
+ drop(statement);
482
+ tx.commit()?;
483
+ Ok(ConversationSnapshot {
484
+ interactions,
485
+ cursor,
486
+ has_older,
487
+ })
488
+ }
489
+
223
490
  pub fn recent_interactions(&self, limit: usize) -> Result<Vec<InteractionMemory>, MemoryError> {
224
491
  self.recent_interactions_for_chat(DEFAULT_CONVERSATION_ID, limit)
225
492
  }
@@ -233,7 +500,7 @@ impl MemoryStore {
233
500
  let connection = self.connection()?;
234
501
  ensure_builtin_chat_sessions(&connection)?;
235
502
  let mut statement = connection.prepare(
236
- "SELECT id, chat_id, user_text, ai_text, provider, model, fallback_provider, created_at, agent_activity_json
503
+ "SELECT id, chat_id, user_text, ai_text, provider, model, fallback_provider, created_at, agent_activity_json, status
237
504
  FROM interaction_memories
238
505
  WHERE chat_id = ?1
239
506
  ORDER BY id DESC
@@ -243,6 +510,45 @@ impl MemoryStore {
243
510
  rows.collect::<Result<Vec<_>, _>>().map_err(Into::into)
244
511
  }
245
512
 
513
+ pub fn recent_completed_interactions_for_chat(
514
+ &self,
515
+ chat_id: &str,
516
+ limit: usize,
517
+ ) -> Result<Vec<InteractionMemory>, MemoryError> {
518
+ let connection = self.connection()?;
519
+ let mut statement = connection.prepare(
520
+ "SELECT id, chat_id, user_text, ai_text, provider, model, fallback_provider,
521
+ created_at, agent_activity_json, status FROM interaction_memories
522
+ WHERE chat_id = ?1 AND status = 'completed' ORDER BY id DESC LIMIT ?2",
523
+ )?;
524
+ let rows = statement.query_map(
525
+ params![normalized_chat_id(chat_id), limit as i64],
526
+ interaction_row,
527
+ )?;
528
+ rows.collect::<Result<Vec<_>, _>>().map_err(Into::into)
529
+ }
530
+
531
+ /// Returns the complete transcript for one conversation in display order.
532
+ /// This deliberately has no caller supplied `LIMIT`: passing `usize::MAX`
533
+ /// through SQLite's signed limit is not portable and can wrap on 64-bit
534
+ /// platforms.
535
+ pub fn interactions_for_chat(
536
+ &self,
537
+ chat_id: &str,
538
+ ) -> Result<Vec<InteractionMemory>, MemoryError> {
539
+ let chat_id = normalized_chat_id(chat_id);
540
+ let connection = self.connection()?;
541
+ ensure_builtin_chat_sessions(&connection)?;
542
+ let mut statement = connection.prepare(
543
+ "SELECT id, chat_id, user_text, ai_text, provider, model, fallback_provider, created_at, agent_activity_json, status
544
+ FROM interaction_memories
545
+ WHERE chat_id = ?1
546
+ ORDER BY id ASC",
547
+ )?;
548
+ let rows = statement.query_map(params![chat_id], interaction_row)?;
549
+ rows.collect::<Result<Vec<_>, _>>().map_err(Into::into)
550
+ }
551
+
246
552
  /// Full-text search over `chat_id`'s past interactions for the turns most
247
553
  /// relevant to `query` (BM25 ranked), skipping the `exclude_recent` newest
248
554
  /// rows since those are already injected verbatim elsewhere. Returns
@@ -262,11 +568,12 @@ impl MemoryStore {
262
568
  let connection = self.connection()?;
263
569
  let mut statement = connection.prepare(
264
570
  "SELECT m.id, m.chat_id, m.user_text, m.ai_text, m.provider, m.model,
265
- m.fallback_provider, m.created_at, m.agent_activity_json
571
+ m.fallback_provider, m.created_at, m.agent_activity_json, m.status
266
572
  FROM interaction_fts
267
573
  JOIN interaction_memories m ON m.id = interaction_fts.rowid
268
574
  WHERE interaction_fts MATCH ?1
269
575
  AND m.chat_id = ?2
576
+ AND m.status = 'completed'
270
577
  AND m.id NOT IN (
271
578
  SELECT id FROM interaction_memories
272
579
  WHERE chat_id = ?2 ORDER BY id DESC LIMIT ?3
@@ -286,31 +593,121 @@ impl MemoryStore {
286
593
  ensure_builtin_chat_sessions(&connection)?;
287
594
  let _ = connection.execute(
288
595
  "DELETE FROM chat_sessions
289
- WHERE kind = 'conversation'
290
- AND id != ?1
596
+ WHERE id != ?1
597
+ AND id != ?2
291
598
  AND id NOT LIKE 'cron::%'
292
599
  AND (SELECT COUNT(*) FROM interaction_memories WHERE interaction_memories.chat_id = chat_sessions.id) = 0",
293
- params![DEFAULT_CONVERSATION_ID],
600
+ params![DEFAULT_CONVERSATION_ID, CHAT_CLI_ID],
294
601
  );
295
602
  let mut statement = connection.prepare(
296
- "SELECT id, title, kind, created_at, updated_at
297
- FROM chat_sessions
298
- ORDER BY CASE WHEN id = ?1 THEN 0 ELSE 1 END, updated_at DESC",
603
+ "SELECT s.id, s.title, s.kind, s.created_at, s.updated_at,
604
+ s.workspace_path, s.git_branch, s.main_language,
605
+ COUNT(m.id) AS msg_count,
606
+ COALESCE(SUM(LENGTH(m.user_text) + LENGTH(m.ai_text)), 0) AS total_bytes
607
+ FROM chat_sessions s
608
+ LEFT JOIN interaction_memories m ON m.chat_id = s.id
609
+ GROUP BY s.id
610
+ ORDER BY CASE WHEN s.id = ?1 THEN 0 ELSE 1 END, s.updated_at DESC",
299
611
  )?;
300
612
  let rows = statement.query_map(params![CHAT_CLI_ID], |row| {
301
613
  let created_raw: String = row.get(3)?;
302
614
  let updated_raw: String = row.get(4)?;
615
+ let msg_count: i64 = row.get(8)?;
616
+ let bytes: i64 = row.get(9)?;
303
617
  Ok(ChatSession {
304
618
  id: row.get(0)?,
305
619
  title: row.get(1)?,
306
620
  kind: row.get(2)?,
307
621
  created_at: normalize_sqlite_utc_timestamp(&created_raw),
308
622
  updated_at: normalize_sqlite_utc_timestamp(&updated_raw),
623
+ workspace_path: row.get(5)?,
624
+ git_branch: row.get(6)?,
625
+ main_language: row.get(7)?,
626
+ message_count: msg_count.max(0) as usize,
627
+ total_bytes: bytes.max(0) as usize,
309
628
  })
310
629
  })?;
311
630
  rows.collect::<Result<Vec<_>, _>>().map_err(Into::into)
312
631
  }
313
632
 
633
+ pub fn update_chat_session_metadata(
634
+ &self,
635
+ chat_id: &str,
636
+ workspace_path: Option<&str>,
637
+ git_branch: Option<&str>,
638
+ main_language: Option<&str>,
639
+ ) -> Result<(), MemoryError> {
640
+ let chat_id = normalized_chat_id(chat_id);
641
+ let connection = self.connection()?;
642
+ ensure_builtin_chat_sessions(&connection)?;
643
+ ensure_chat_session_row(&connection, &chat_id)?;
644
+ connection.execute(
645
+ "UPDATE chat_sessions
646
+ SET workspace_path = COALESCE(?2, workspace_path),
647
+ git_branch = COALESCE(?3, git_branch),
648
+ main_language = COALESCE(?4, main_language),
649
+ updated_at = CURRENT_TIMESTAMP
650
+ WHERE id = ?1",
651
+ params![chat_id, workspace_path, git_branch, main_language],
652
+ )?;
653
+ Ok(())
654
+ }
655
+
656
+ pub fn set_chat_session_workspace(
657
+ &self,
658
+ chat_id: &str,
659
+ workspace_path: Option<&str>,
660
+ ) -> Result<(), MemoryError> {
661
+ let chat_id = normalized_chat_id(chat_id);
662
+ let connection = self.connection()?;
663
+ ensure_builtin_chat_sessions(&connection)?;
664
+ ensure_chat_session_row(&connection, &chat_id)?;
665
+ connection.execute(
666
+ "UPDATE chat_sessions
667
+ SET workspace_path = ?2,
668
+ updated_at = CURRENT_TIMESTAMP
669
+ WHERE id = ?1",
670
+ params![chat_id, workspace_path],
671
+ )?;
672
+ Ok(())
673
+ }
674
+
675
+ pub fn create_cli_session(
676
+ &self,
677
+ workspace_path: Option<&str>,
678
+ git_branch: Option<&str>,
679
+ main_language: Option<&str>,
680
+ ) -> Result<String, MemoryError> {
681
+ let session_id = generate_cli_session_id();
682
+ self.register_cli_session(&session_id, workspace_path, git_branch, main_language)?;
683
+ Ok(session_id)
684
+ }
685
+
686
+ pub fn register_cli_session(
687
+ &self,
688
+ session_id: &str,
689
+ workspace_path: Option<&str>,
690
+ git_branch: Option<&str>,
691
+ main_language: Option<&str>,
692
+ ) -> Result<(), MemoryError> {
693
+ let connection = self.connection()?;
694
+ ensure_builtin_chat_sessions(&connection)?;
695
+ connection.execute(
696
+ "INSERT OR IGNORE INTO chat_sessions (id, title, kind, workspace_path, git_branch, main_language)
697
+ VALUES (?1, 'New chat', 'cli', ?2, ?3, ?4)",
698
+ params![session_id, workspace_path, git_branch, main_language],
699
+ )?;
700
+ Ok(())
701
+ }
702
+
703
+ pub fn get_session_preview(
704
+ &self,
705
+ chat_id: &str,
706
+ limit: usize,
707
+ ) -> Result<Vec<InteractionMemory>, MemoryError> {
708
+ self.recent_interactions_for_chat(chat_id, limit)
709
+ }
710
+
314
711
  /// Registers a chat session with an explicit title/kind up front instead
315
712
  /// of the "New chat" placeholder — used to give a scheduled task's
316
713
  /// conversation its task name immediately (visible in the sidebar even
@@ -361,7 +758,7 @@ impl MemoryStore {
361
758
 
362
759
  pub fn delete_chat_session(&self, chat_id: &str) -> Result<usize, MemoryError> {
363
760
  let chat_id = normalized_chat_id(chat_id);
364
- if is_cli_chat_id(&chat_id) {
761
+ if chat_id == CHAT_CLI_ID {
365
762
  return Ok(0);
366
763
  }
367
764
  let connection = self.connection()?;
@@ -910,13 +1307,23 @@ fn initialize(
910
1307
  keywords TEXT DEFAULT '',
911
1308
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
912
1309
  );
913
- CREATE TABLE IF NOT EXISTS chat_sessions (
914
- id TEXT PRIMARY KEY,
915
- title TEXT NOT NULL DEFAULT 'New chat',
916
- kind TEXT NOT NULL DEFAULT 'conversation',
917
- created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
918
- updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
1310
+ CREATE TABLE IF NOT EXISTS conversation_changes (
1311
+ sequence INTEGER PRIMARY KEY AUTOINCREMENT,
1312
+ chat_id TEXT NOT NULL,
1313
+ interaction_id INTEGER NOT NULL
919
1314
  );
1315
+ CREATE INDEX IF NOT EXISTS idx_conversation_changes_chat_sequence
1316
+ ON conversation_changes(chat_id, sequence);
1317
+ CREATE TABLE IF NOT EXISTS chat_sessions (
1318
+ id TEXT PRIMARY KEY,
1319
+ title TEXT NOT NULL DEFAULT 'New chat',
1320
+ kind TEXT NOT NULL DEFAULT 'conversation',
1321
+ workspace_path TEXT DEFAULT NULL,
1322
+ git_branch TEXT DEFAULT NULL,
1323
+ main_language TEXT DEFAULT NULL,
1324
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
1325
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
1326
+ );
920
1327
  CREATE TABLE IF NOT EXISTS learned_skills (
921
1328
  id INTEGER PRIMARY KEY AUTOINCREMENT,
922
1329
  name TEXT NOT NULL,
@@ -970,7 +1377,7 @@ fn initialize(
970
1377
  VALUES ('delete', old.id, old.user_text, old.ai_text);
971
1378
  END;
972
1379
  CREATE TRIGGER IF NOT EXISTS trg_interaction_fts_au
973
- AFTER UPDATE ON interaction_memories BEGIN
1380
+ AFTER UPDATE OF user_text, ai_text ON interaction_memories BEGIN
974
1381
  INSERT INTO interaction_fts(interaction_fts, rowid, user_text, ai_text)
975
1382
  VALUES ('delete', old.id, old.user_text, old.ai_text);
976
1383
  INSERT INTO interaction_fts(rowid, user_text, ai_text)
@@ -1007,12 +1414,66 @@ fn initialize(
1007
1414
  "agent_activity_json",
1008
1415
  "TEXT DEFAULT NULL",
1009
1416
  )?;
1417
+ ensure_column(
1418
+ connection,
1419
+ "interaction_memories",
1420
+ "status",
1421
+ "TEXT NOT NULL DEFAULT 'completed'",
1422
+ )?;
1423
+ ensure_column(
1424
+ connection,
1425
+ "interaction_memories",
1426
+ "lease_until",
1427
+ "INTEGER NOT NULL DEFAULT 0",
1428
+ )?;
1429
+ connection.execute_batch(
1430
+ "DROP TRIGGER IF EXISTS trg_interaction_fts_au;
1431
+ CREATE TRIGGER trg_interaction_fts_au
1432
+ AFTER UPDATE OF user_text, ai_text ON interaction_memories BEGIN
1433
+ INSERT INTO interaction_fts(interaction_fts, rowid, user_text, ai_text)
1434
+ VALUES ('delete', old.id, old.user_text, old.ai_text);
1435
+ INSERT INTO interaction_fts(rowid, user_text, ai_text)
1436
+ VALUES (new.id, new.user_text, new.ai_text);
1437
+ END;
1438
+ DROP TRIGGER IF EXISTS trg_conversation_change_update;
1439
+ CREATE TRIGGER IF NOT EXISTS trg_conversation_change_insert
1440
+ AFTER INSERT ON interaction_memories BEGIN
1441
+ INSERT INTO conversation_changes(chat_id, interaction_id) VALUES (new.chat_id, new.id);
1442
+ END;
1443
+ CREATE TRIGGER trg_conversation_change_update
1444
+ AFTER UPDATE OF user_text, ai_text, provider, model, fallback_provider,
1445
+ status, agent_activity_json, chat_id ON interaction_memories BEGIN
1446
+ INSERT INTO conversation_changes(chat_id, interaction_id) VALUES (new.chat_id, new.id);
1447
+ END;
1448
+ CREATE TRIGGER IF NOT EXISTS trg_conversation_change_delete
1449
+ AFTER DELETE ON interaction_memories BEGIN
1450
+ INSERT INTO conversation_changes(chat_id, interaction_id) VALUES (old.chat_id, old.id);
1451
+ END;",
1452
+ )?;
1010
1453
  ensure_column(
1011
1454
  connection,
1012
1455
  "chat_sessions",
1013
1456
  "kind",
1014
1457
  "TEXT NOT NULL DEFAULT 'conversation'",
1015
1458
  )?;
1459
+ ensure_column(
1460
+ connection,
1461
+ "chat_sessions",
1462
+ "workspace_path",
1463
+ "TEXT DEFAULT NULL",
1464
+ )?;
1465
+ ensure_column(
1466
+ connection,
1467
+ "chat_sessions",
1468
+ "git_branch",
1469
+ "TEXT DEFAULT NULL",
1470
+ )?;
1471
+ ensure_column(
1472
+ connection,
1473
+ "chat_sessions",
1474
+ "main_language",
1475
+ "TEXT DEFAULT NULL",
1476
+ )?;
1016
1477
  // `agent_id` scopes a fact to the subagent that produced it (NULL = shared /
1017
1478
  // user-authored); `embedding` is the on-device similarity vector used for
1018
1479
  // relevance-ranked recall. Both are additive for databases created before
@@ -1233,6 +1694,7 @@ fn interaction_row(row: &rusqlite::Row<'_>) -> Result<InteractionMemory, rusqlit
1233
1694
  model: row.get(5)?,
1234
1695
  fallback_provider: row.get(6)?,
1235
1696
  created_at: normalize_sqlite_utc_timestamp(&raw_created),
1697
+ status: row.get(9)?,
1236
1698
  agent_activity,
1237
1699
  })
1238
1700
  }
@@ -1267,8 +1729,10 @@ fn ensure_builtin_chat_sessions(connection: &Connection) -> Result<(), rusqlite:
1267
1729
  }
1268
1730
 
1269
1731
  fn ensure_chat_session_row(connection: &Connection, chat_id: &str) -> Result<(), rusqlite::Error> {
1270
- let (title, kind) = if is_cli_chat_id(chat_id) {
1732
+ let (title, kind) = if chat_id == CHAT_CLI_ID {
1271
1733
  ("Chat CLI", "cli")
1734
+ } else if is_cli_chat_id(chat_id) {
1735
+ ("New chat", "cli")
1272
1736
  } else {
1273
1737
  ("New chat", "conversation")
1274
1738
  };
@@ -1280,6 +1744,180 @@ fn ensure_chat_session_row(connection: &Connection, chat_id: &str) -> Result<(),
1280
1744
  Ok(())
1281
1745
  }
1282
1746
 
1747
+ #[cfg(test)]
1748
+ mod conversation_sync_tests {
1749
+ use super::*;
1750
+
1751
+ fn store() -> MemoryStore {
1752
+ MemoryStore::open(std::env::temp_dir().join(format!(
1753
+ "mint-conversation-sync-{}.sqlite",
1754
+ uuid::Uuid::new_v4()
1755
+ )))
1756
+ }
1757
+
1758
+ #[test]
1759
+ fn prompt_and_reply_use_one_id_and_emit_changes() {
1760
+ let memory = store();
1761
+ let first = memory.start_turn("cli::one", "hello").unwrap();
1762
+ let other_process = MemoryStore::open(memory.path.clone());
1763
+ let second = other_process.start_turn("cli::one", "next").unwrap();
1764
+ let other = memory.start_turn("cli::two", "separate").unwrap();
1765
+ assert!(memory.claim_turn("cli::one", first).unwrap());
1766
+ assert!(!other_process.claim_turn("cli::one", second).unwrap());
1767
+ assert!(memory.claim_turn("cli::two", other).unwrap());
1768
+ assert_eq!(
1769
+ memory
1770
+ .recent_completed_interactions_for_chat("cli::one", 3)
1771
+ .unwrap()
1772
+ .len(),
1773
+ 0
1774
+ );
1775
+
1776
+ memory
1777
+ .finish_turn(first, "world", "test", "model", None)
1778
+ .unwrap();
1779
+ assert!(other_process.claim_turn("cli::one", second).unwrap());
1780
+ memory
1781
+ .finish_turn(second, "done", "test", "model", None)
1782
+ .unwrap();
1783
+
1784
+ let rows = memory.interactions_for_chat("cli::one").unwrap();
1785
+ assert_eq!(rows.len(), 2);
1786
+ assert_eq!(rows[0].id, first);
1787
+ assert_eq!(rows[0].ai_text, "world");
1788
+ assert_eq!(rows[1].status, "completed");
1789
+ let changes = memory.conversation_changes("cli::one", 0, 100).unwrap();
1790
+ assert!(changes.changes.iter().any(|c| {
1791
+ c.interaction_id == first
1792
+ && c.interaction
1793
+ .as_ref()
1794
+ .is_some_and(|row| row.ai_text == "world")
1795
+ }));
1796
+ assert!(changes.changes.iter().all(|c| c.interaction_id != other));
1797
+ assert!(
1798
+ memory
1799
+ .conversation_changes("cli::one", changes.cursor, 100)
1800
+ .unwrap()
1801
+ .changes
1802
+ .is_empty()
1803
+ );
1804
+ }
1805
+
1806
+ #[test]
1807
+ fn interrupted_turn_unblocks_queue_and_snapshot_pages() {
1808
+ let memory = store();
1809
+ let first = memory.start_turn("cli::one", "first").unwrap();
1810
+ let second = memory.start_turn("cli::one", "second").unwrap();
1811
+ assert!(memory.claim_turn("cli::one", first).unwrap());
1812
+ memory.end_turn(first, "interrupted").unwrap();
1813
+ assert!(memory.claim_turn("cli::one", second).unwrap());
1814
+ let page = memory.conversation_snapshot("cli::one", None, 1).unwrap();
1815
+ assert_eq!(page.interactions[0].id, second);
1816
+ assert!(page.has_older);
1817
+ let older = memory
1818
+ .conversation_snapshot("cli::one", Some(second), 1)
1819
+ .unwrap();
1820
+ assert_eq!(older.interactions[0].status, "interrupted");
1821
+ assert!(!older.has_older);
1822
+ }
1823
+
1824
+ #[test]
1825
+ fn abandoned_turn_is_reported_after_lease_expires() {
1826
+ let memory = store();
1827
+ let id = memory.start_turn("cli::one", "unfinished").unwrap();
1828
+ assert!(memory.claim_turn("cli::one", id).unwrap());
1829
+ memory
1830
+ .connection()
1831
+ .unwrap()
1832
+ .execute(
1833
+ "UPDATE interaction_memories SET lease_until = 0 WHERE id = ?1",
1834
+ params![id],
1835
+ )
1836
+ .unwrap();
1837
+ let changes = memory.conversation_changes("cli::one", 0, 100).unwrap();
1838
+ assert_eq!(
1839
+ changes
1840
+ .changes
1841
+ .last()
1842
+ .unwrap()
1843
+ .interaction
1844
+ .as_ref()
1845
+ .unwrap()
1846
+ .status,
1847
+ "interrupted"
1848
+ );
1849
+ assert!(
1850
+ memory
1851
+ .finish_turn(id, "late", "test", "model", None)
1852
+ .is_err()
1853
+ );
1854
+ }
1855
+
1856
+ #[test]
1857
+ fn old_completed_rows_migrate_without_losing_content() {
1858
+ let path = std::env::temp_dir().join(format!(
1859
+ "mint-conversation-legacy-{}.sqlite",
1860
+ uuid::Uuid::new_v4()
1861
+ ));
1862
+ let connection = Connection::open(&path).unwrap();
1863
+ connection
1864
+ .execute_batch(
1865
+ "CREATE TABLE interaction_memories (
1866
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
1867
+ chat_id TEXT NOT NULL DEFAULT 'conversation-default',
1868
+ user_text TEXT NOT NULL, ai_text TEXT NOT NULL,
1869
+ provider TEXT NOT NULL DEFAULT '', model TEXT NOT NULL DEFAULT '',
1870
+ fallback_provider TEXT DEFAULT NULL, keywords TEXT DEFAULT '',
1871
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
1872
+ );
1873
+ INSERT INTO interaction_memories(chat_id, user_text, ai_text)
1874
+ VALUES ('cli::old', 'old prompt', 'old reply');",
1875
+ )
1876
+ .unwrap();
1877
+ drop(connection);
1878
+ let memory = MemoryStore::open(path);
1879
+ let rows = memory.interactions_for_chat("cli::old").unwrap();
1880
+ assert_eq!(rows.len(), 1);
1881
+ assert_eq!(rows[0].status, "completed");
1882
+ assert_eq!(rows[0].ai_text, "old reply");
1883
+ }
1884
+
1885
+ #[test]
1886
+ fn clearing_history_emits_tombstones_for_open_views() {
1887
+ let memory = store();
1888
+ let id = memory
1889
+ .add_interaction_for_chat("cli::one", "hello", "world", "test", "model")
1890
+ .unwrap();
1891
+ let cursor = memory.latest_conversation_sequence("cli::one").unwrap();
1892
+ memory.clear_interactions_for_chat("cli::one").unwrap();
1893
+ let changes = memory
1894
+ .conversation_changes("cli::one", cursor, 100)
1895
+ .unwrap();
1896
+ assert!(
1897
+ changes
1898
+ .changes
1899
+ .iter()
1900
+ .any(|change| change.interaction_id == id && change.interaction.is_none())
1901
+ );
1902
+ }
1903
+
1904
+ #[test]
1905
+ fn heartbeat_does_not_emit_visible_changes() {
1906
+ let memory = store();
1907
+ let id = memory.start_turn("cli::one", "hello").unwrap();
1908
+ assert!(memory.claim_turn("cli::one", id).unwrap());
1909
+ let cursor = memory.latest_conversation_sequence("cli::one").unwrap();
1910
+ memory.renew_turn(id).unwrap();
1911
+ assert!(
1912
+ memory
1913
+ .conversation_changes("cli::one", cursor, 100)
1914
+ .unwrap()
1915
+ .changes
1916
+ .is_empty()
1917
+ );
1918
+ }
1919
+ }
1920
+
1283
1921
  #[cfg(test)]
1284
1922
  mod scoped_chat_id_tests {
1285
1923
  use super::*;