@pheem49/mint 1.14.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (925) hide show
  1. package/Cargo.lock +1258 -35
  2. package/Cargo.toml +5 -2
  3. package/LICENSE +21 -654
  4. package/README.md +93 -756
  5. package/Release_Note.md +53 -446
  6. package/apps/mint-companion/src-tauri/Cargo.toml +20 -0
  7. package/apps/mint-companion/src-tauri/build.rs +3 -0
  8. package/apps/mint-companion/src-tauri/src/main.rs +468 -0
  9. package/apps/mint-companion/tsconfig.json +20 -0
  10. package/apps/mint-companion/vite.config.ts +3 -0
  11. package/components.json +19 -0
  12. package/crates/mint-cli/Cargo.toml +9 -1
  13. package/crates/mint-cli/src/agent/approval_prompts.rs +16 -3
  14. package/crates/mint-cli/src/agent/live_status.rs +545 -148
  15. package/crates/mint-cli/src/agent/markdown_render.rs +601 -61
  16. package/crates/mint-cli/src/agent.rs +723 -258
  17. package/crates/mint-cli/src/commands/agent.rs +83 -74
  18. package/crates/mint-cli/src/commands/eval.rs +9 -5
  19. package/crates/mint-cli/src/commands/git.rs +204 -0
  20. package/crates/mint-cli/src/commands/integrations.rs +35 -0
  21. package/crates/mint-cli/src/commands/knowledge.rs +13 -32
  22. package/crates/mint-cli/src/commands/mod.rs +81 -2
  23. package/crates/mint-cli/src/commands/tailnet_web.rs +235 -0
  24. package/crates/mint-cli/src/image.rs +32 -11
  25. package/crates/mint-cli/src/interactive/chat_tui.rs +7853 -0
  26. package/crates/mint-cli/src/interactive/command_ui.rs +477 -0
  27. package/crates/mint-cli/src/interactive/format.rs +8 -0
  28. package/crates/mint-cli/src/interactive/input_box.rs +94 -8
  29. package/crates/mint-cli/src/interactive/picker.rs +180 -37
  30. package/crates/mint-cli/src/interactive/resume_picker.rs +686 -0
  31. package/crates/mint-cli/src/interactive/slash_commands.rs +1071 -501
  32. package/crates/mint-cli/src/interactive/thought_viewer.rs +286 -0
  33. package/crates/mint-cli/src/interactive/tool_activity.rs +328 -0
  34. package/crates/mint-cli/src/interactive.rs +454 -166
  35. package/crates/mint-cli/src/main.rs +93 -26
  36. package/crates/mint-cli/src/markdown.rs +12 -5
  37. package/crates/mint-cli/src/mcp.rs +5 -0
  38. package/crates/mint-cli/src/mod_host.rs +6 -0
  39. package/crates/mint-cli/src/mods_cli.rs +62 -0
  40. package/crates/mint-cli/src/mods_ui.rs +187 -0
  41. package/crates/mint-cli/src/onboard.rs +37 -61
  42. package/crates/mint-cli/src/plugins_cli.rs +8 -5
  43. package/crates/mint-cli/src/setup.rs +10 -8
  44. package/crates/mint-cli/src/terminal_theme.rs +189 -0
  45. package/crates/mint-cli/src/updater.rs +112 -23
  46. package/crates/mint-cli/tests/library_intake.rs +77 -0
  47. package/crates/mint-cli/tests/mods_testing.rs +133 -0
  48. package/crates/mint-companion-protocol/Cargo.toml +10 -0
  49. package/crates/mint-companion-protocol/src/lib.rs +163 -0
  50. package/crates/mint-core/Cargo.toml +6 -3
  51. package/crates/mint-core/build.rs +26 -0
  52. package/crates/mint-core/src/agent/agent_loop.rs +1 -0
  53. package/crates/mint-core/src/agent/chat.rs +1003 -209
  54. package/crates/mint-core/src/agent/code_tools.rs +98 -2
  55. package/crates/mint-core/src/agent/memory/sources.rs +240 -0
  56. package/crates/mint-core/src/agent/memory.rs +805 -33
  57. package/crates/mint-core/src/agent/skill_inventory.rs +325 -0
  58. package/crates/mint-core/src/agent/skills.rs +437 -90
  59. package/crates/mint-core/src/agent.rs +1 -0
  60. package/crates/mint-core/src/api_server/routes/background_jobs.rs +310 -0
  61. package/crates/mint-core/src/api_server/routes/chat.rs +233 -190
  62. package/crates/mint-core/src/api_server/routes/html_preview.rs +77 -0
  63. package/crates/mint-core/src/api_server/routes/library.rs +97 -0
  64. package/crates/mint-core/src/api_server/routes/linked_folders.rs +118 -3
  65. package/crates/mint-core/src/api_server/routes/media_gen.rs +10 -57
  66. package/crates/mint-core/src/api_server/routes/misc.rs +114 -121
  67. package/crates/mint-core/src/api_server/routes/mod.rs +6 -0
  68. package/crates/mint-core/src/api_server/routes/mods.rs +31 -0
  69. package/crates/mint-core/src/api_server/routes/sessions.rs +85 -0
  70. package/crates/mint-core/src/api_server/routes/skills_subagents.rs +12 -42
  71. package/crates/mint-core/src/api_server/routes/slash.rs +50 -1
  72. package/crates/mint-core/src/api_server/routes/sources.rs +101 -0
  73. package/crates/mint-core/src/api_server.rs +140 -12
  74. package/crates/mint-core/src/avatar_bridge.rs +13 -2
  75. package/crates/mint-core/src/browser/cdp.rs +74 -83
  76. package/crates/mint-core/src/browser/evidence.rs +260 -0
  77. package/crates/mint-core/src/browser/input.rs +1 -1
  78. package/crates/mint-core/src/browser/interact.rs +98 -124
  79. package/crates/mint-core/src/browser/lifecycle.rs +75 -4
  80. package/crates/mint-core/src/browser/mod.rs +16 -2
  81. package/crates/mint-core/src/browser/navigate.rs +27 -19
  82. package/crates/mint-core/src/browser/observe.js +40 -0
  83. package/crates/mint-core/src/browser/session.rs +1610 -0
  84. package/crates/mint-core/src/companion.rs +716 -0
  85. package/crates/mint-core/src/cron/scheduler.rs +34 -2
  86. package/crates/mint-core/src/git/branches.rs +348 -0
  87. package/crates/mint-core/src/git/checkpoint.rs +40 -0
  88. package/crates/mint-core/src/git/diff.rs +206 -0
  89. package/crates/mint-core/src/git/mod.rs +10 -2
  90. package/crates/mint-core/src/integrations/channels.rs +88 -345
  91. package/crates/mint-core/src/integrations/mcp.rs +397 -50
  92. package/crates/mint-core/src/integrations/mcp_calls.rs +823 -0
  93. package/crates/mint-core/src/integrations/mcp_catalog.rs +267 -0
  94. package/crates/mint-core/src/integrations/mcp_device.rs +319 -0
  95. package/crates/mint-core/src/integrations/mcp_result.rs +356 -0
  96. package/crates/mint-core/src/integrations/webhooks.rs +539 -0
  97. package/crates/mint-core/src/integrations.rs +2 -0
  98. package/crates/mint-core/src/lib.rs +107 -40
  99. package/crates/mint-core/src/live_sync.rs +28 -9
  100. package/crates/mint-core/src/media/auto_shorts.rs +1 -0
  101. package/crates/mint-core/src/media/gemini_live.rs +145 -14
  102. package/crates/mint-core/src/media/image_models.rs +3 -27
  103. package/crates/mint-core/src/media/image_workflow.rs +216 -0
  104. package/crates/mint-core/src/media/library/intake.rs +144 -0
  105. package/crates/mint-core/src/media/library/migration.rs +56 -0
  106. package/crates/mint-core/src/media/library/removal.rs +55 -0
  107. package/crates/mint-core/src/media/library/tests.rs +730 -0
  108. package/crates/mint-core/src/media/library/thumbnails.rs +72 -0
  109. package/crates/mint-core/src/media/library.rs +545 -0
  110. package/crates/mint-core/src/media/mic_transcribe.rs +1 -0
  111. package/crates/mint-core/src/media/model_catalog.rs +375 -0
  112. package/crates/mint-core/src/media/pictures.rs +79 -222
  113. package/crates/mint-core/src/media/subtitle.rs +1 -0
  114. package/crates/mint-core/src/media/video_models.rs +3 -22
  115. package/crates/mint-core/src/media.rs +3 -0
  116. package/crates/mint-core/src/mods/manager.rs +1124 -0
  117. package/crates/mint-core/src/mods/mod.rs +569 -0
  118. package/crates/mint-core/src/mods/operations.rs +204 -0
  119. package/crates/mint-core/src/mods/session.rs +146 -0
  120. package/crates/mint-core/src/mods/slash.rs +59 -0
  121. package/crates/mint-core/src/mods/telemetry.rs +306 -0
  122. package/crates/mint-core/src/orchestration/approvals.rs +344 -0
  123. package/crates/mint-core/src/orchestration/context_render.rs +105 -0
  124. package/crates/mint-core/src/orchestration/mcp_review.rs +153 -0
  125. package/crates/mint-core/src/orchestration/memory_skill.rs +110 -33
  126. package/crates/mint-core/src/orchestration/mod.rs +3129 -481
  127. package/crates/mint-core/src/orchestration/mod_authoring_regressions.rs +209 -0
  128. package/crates/mint-core/src/orchestration/progress_clock.rs +80 -0
  129. package/crates/mint-core/src/orchestration/repeated_failures.rs +116 -0
  130. package/crates/mint-core/src/orchestration/review_regressions.rs +449 -0
  131. package/crates/mint-core/src/orchestration/run_control.rs +196 -0
  132. package/crates/mint-core/src/orchestration/tools/browser.rs +16 -139
  133. package/crates/mint-core/src/orchestration/tools/files.rs +161 -14
  134. package/crates/mint-core/src/orchestration/tools/media.rs +37 -41
  135. package/crates/mint-core/src/orchestration/tools/misc.rs +5 -3
  136. package/crates/mint-core/src/orchestration/tools/mod.rs +2 -0
  137. package/crates/mint-core/src/orchestration/tools/mods.rs +161 -0
  138. package/crates/mint-core/src/orchestration/tools/plugins_mcp.rs +303 -71
  139. package/crates/mint-core/src/orchestration/tools/shell.rs +95 -2
  140. package/crates/mint-core/src/orchestration/tools/web.rs +1 -1
  141. package/crates/mint-core/src/orchestration/workspace_helpers.rs +4 -1
  142. package/crates/mint-core/src/prompts/agent.rs +75 -31
  143. package/crates/mint-core/src/prompts/chat.rs +1 -1
  144. package/crates/mint-core/src/prompts/persona.rs +1 -1
  145. package/crates/mint-core/src/prompts/tool_catalog.rs +121 -27
  146. package/crates/mint-core/src/search/knowledge.rs +7 -1
  147. package/crates/mint-core/src/search/linked_folders/index.rs +896 -0
  148. package/crates/mint-core/src/search/linked_folders.rs +473 -131
  149. package/crates/mint-core/src/slash/catalog.rs +1 -1
  150. package/crates/mint-core/src/slash/mod.rs +644 -33
  151. package/crates/mint-core/src/slash/model_fetcher.rs +12 -3
  152. package/crates/mint-core/src/slash/models.rs +66 -10
  153. package/crates/mint-core/src/slash/mods.rs +155 -0
  154. package/crates/mint-core/src/system/bg_shell.rs +1129 -95
  155. package/crates/mint-core/src/system/config.rs +235 -10
  156. package/crates/mint-core/src/system/html_preview.rs +398 -0
  157. package/crates/mint-core/src/system/mint_web.rs +164 -0
  158. package/crates/mint-core/src/system/release_notes.rs +18 -0
  159. package/crates/mint-core/src/system/shell.rs +21 -6
  160. package/crates/mint-core/src/system/workspace.rs +292 -0
  161. package/crates/mint-core/src/system/workspace_history.rs +604 -0
  162. package/crates/mint-core/src/system.rs +5 -0
  163. package/crates/mint-core/tests/background_retention.rs +34 -0
  164. package/crates/mint-core/tests/background_shutdown.rs +24 -0
  165. package/crates/mint-core/tests/library_http.rs +209 -0
  166. package/crates/mint-core/tests/mcp_contract.rs +283 -0
  167. package/crates/mint-core/tests/mcp_stdio.rs +11 -10
  168. package/crates/mint-core/tests/media_model_catalog_http.rs +403 -0
  169. package/crates/mint-core/tests/memory_persistence.rs +39 -0
  170. package/crates/mint-core/tests/mods_http.rs +215 -0
  171. package/crates/mint-core/tests/terminal_shutdown.rs +109 -0
  172. package/crates/mint-mod-runtime/Cargo.toml +18 -0
  173. package/crates/mint-mod-runtime/src/lib.rs +507 -0
  174. package/crates/mint-mod-runtime/src/sdk.js +56 -0
  175. package/crates/mint-mod-runtime/src/test_sdk.js +32 -0
  176. package/crates/mint-mod-runtime/src/testing.rs +94 -0
  177. package/crates/mint-mod-runtime/tests/runtime.rs +156 -0
  178. package/docs/mods/AUTHORING.md +61 -0
  179. package/docs/mods/README.md +139 -0
  180. package/docs/mods/TESTING.md +56 -0
  181. package/docs/mods/mint-mods.d.ts +66 -0
  182. package/examples/device-mcp/README.md +22 -0
  183. package/examples/device-mcp/contract.md +49 -0
  184. package/examples/device-mcp/mock-device.mjs +66 -0
  185. package/examples/device-mcp/server.mjs +48 -0
  186. package/examples/device-mcp/server.test.mjs +78 -0
  187. package/examples/mods/task-checklist/README.md +1 -0
  188. package/examples/mods/task-checklist/main.ts +17 -0
  189. package/examples/mods/task-checklist/manifest.json +1 -0
  190. package/examples/mods/task-checklist/tests/checklist.test.ts +15 -0
  191. package/examples/mods/token-meter/README.md +1 -0
  192. package/examples/mods/token-meter/main.ts +8 -0
  193. package/examples/mods/token-meter/manifest.json +1 -0
  194. package/examples/mods/tool-guard/README.md +1 -0
  195. package/examples/mods/tool-guard/main.ts +9 -0
  196. package/examples/mods/tool-guard/manifest.json +1 -0
  197. package/out/web/assets/CliSessionsView-CtzUJpK_.css +1 -0
  198. package/out/web/assets/CliSessionsView-D7hw0Mgj.js +1 -0
  199. package/out/web/assets/CodeReviewPage-C7bEOJfd.js +4 -0
  200. package/out/web/assets/CodeReviewPage-Dte9uLiL.css +1 -0
  201. package/out/web/assets/CommandPalette-0RrF-AOT.js +1 -0
  202. package/out/web/assets/ImageStudioPanel-CdxkAf_r.js +1 -0
  203. package/out/web/assets/ImageStudioPanel-D0lnhQV5.css +1 -0
  204. package/out/web/assets/LibraryPage--Qfisp6D.js +2 -0
  205. package/out/web/assets/LibraryPage-DAxUTAg7.css +1 -0
  206. package/out/web/assets/LinkedFoldersView-2nfZbDgN.js +1 -0
  207. package/out/web/assets/McpRegistryPicker-h9uS8_wT.js +1 -0
  208. package/out/web/assets/McpServersView-slfQJzNB.js +1 -0
  209. package/out/web/assets/MintDashboard-BSR5XpXh.js +25 -0
  210. package/out/web/assets/MintDashboard-CWUcCGhd.css +1 -0
  211. package/out/web/assets/PluginsView-l7LSm503.js +1 -0
  212. package/out/web/assets/ScheduledTasksView-CttmLbq1.js +1 -0
  213. package/out/web/assets/SettingsWindow-BCMLYvEV.js +4 -0
  214. package/out/web/assets/SettingsWindow-DcMVmU9u.css +1 -0
  215. package/out/web/assets/SkillsView-rNs1qr_U.js +2 -0
  216. package/out/web/assets/ToolSurfacePage-B9DzEPWN.js +37 -0
  217. package/out/web/assets/ToolSurfacePage-CTfgggF2.css +1 -0
  218. package/out/web/assets/VeoStudioPanel-DOj7_WR3.css +1 -0
  219. package/out/web/assets/VeoStudioPanel-DiJs_Cg2.js +4 -0
  220. package/out/web/assets/WorkspacePanel-CbJ1PFoZ.js +1 -0
  221. package/out/web/assets/WorkspaceSelector-B2xIp04D.js +1 -0
  222. package/out/web/assets/WorkspaceSelector-Ca8uJOsS.css +1 -0
  223. package/out/web/assets/{abnfDiagram-VCTEODGH-DAOBA7ZG.js → abnfDiagram-VCTEODGH-CD0CjoGl.js} +1 -1
  224. package/out/web/assets/{architecture-7GRP2DOG-CgSwQOPQ.js → architecture-7GRP2DOG-RKV83OeZ.js} +1 -1
  225. package/out/web/assets/{architectureDiagram-5GKGNRK7-CYp3yupP.js → architectureDiagram-5GKGNRK7-nN_HAFct.js} +1 -1
  226. package/out/web/assets/{blockDiagram-NRAW4CY4-CyWybDWr.js → blockDiagram-NRAW4CY4-BrrqzHW5.js} +1 -1
  227. package/out/web/assets/{c4Diagram-UCG6FXSJ-BvY3U709.js → c4Diagram-UCG6FXSJ-DTdV8_zE.js} +1 -1
  228. package/out/web/assets/{chunk-75Z2AOVW-TLXCoZYv.js → chunk-75Z2AOVW-_M0z5olV.js} +1 -1
  229. package/out/web/assets/chunk-CKBBP62Z-BpQEgeHF.js +2 -0
  230. package/out/web/assets/{chunk-CLGD4ZFX-xjsKtNS7.js → chunk-CLGD4ZFX-D54yGvGS.js} +1 -1
  231. package/out/web/assets/chunk-DSNCTWBM-C-gvT2ru.js +2 -0
  232. package/out/web/assets/chunk-DU6HZSFF-CnFngIhW.js +128 -0
  233. package/out/web/assets/{chunk-F27PBJKO-BFpgF55A.js → chunk-F27PBJKO-BqtWrnEO.js} +1 -1
  234. package/out/web/assets/{chunk-G27WJ6UU-DfF7qW-C.js → chunk-G27WJ6UU-Ckoq5mi2.js} +1 -1
  235. package/out/web/assets/{chunk-GMAD6QVW-C-558kh_.js → chunk-GMAD6QVW-BuhEcgHq.js} +1 -1
  236. package/out/web/assets/{chunk-JQ64N6SF-wJmeGKAw.js → chunk-JQ64N6SF-CF8T7GiZ.js} +1 -1
  237. package/out/web/assets/{chunk-LCL6LL3I-C1wHD8Ie.js → chunk-LCL6LL3I-BhXV9zyH.js} +1 -1
  238. package/out/web/assets/{chunk-OBVCFTLP-BsRTPBqs.js → chunk-OBVCFTLP-CRIkunUB.js} +1 -1
  239. package/out/web/assets/{chunk-P2QGCYS3-HZIiM7Ni.js → chunk-P2QGCYS3-UFEU6BxZ.js} +1 -1
  240. package/out/web/assets/{chunk-POPQ4Y6H-Dk9wvVb0.js → chunk-POPQ4Y6H-CQcrNbjr.js} +1 -1
  241. package/out/web/assets/{chunk-PWAF6VOD-BmjYLNbq.js → chunk-PWAF6VOD-Cc2uVDsG.js} +1 -1
  242. package/out/web/assets/{chunk-R7TYR2AO-CaHIf-lK.js → chunk-R7TYR2AO-DiCxzdAY.js} +1 -1
  243. package/out/web/assets/{chunk-RHFEMEQ7-_T561hOU.js → chunk-RHFEMEQ7-b7hnPmrR.js} +1 -1
  244. package/out/web/assets/{chunk-SVP7TREG-CM-GGYoY.js → chunk-SVP7TREG-Bu_yYb-V.js} +1 -1
  245. package/out/web/assets/{chunk-TEH6E4GO-K2A8Vg2C.js → chunk-TEH6E4GO-G4Cdlyrt.js} +1 -1
  246. package/out/web/assets/classDiagram-DTDB5LWJ-RnC2mYO4.js +1 -0
  247. package/out/web/assets/classDiagram-v2-JRS7N3AN-RnC2mYO4.js +1 -0
  248. package/out/web/assets/config-CnvCChUM.js +2 -0
  249. package/out/web/assets/config-DM6oIVO3.css +1 -0
  250. package/out/web/assets/core-DsKkQ7ig.js +1 -0
  251. package/out/web/assets/{cynefin-OW5HDTMX-ClzaB6cc.js → cynefin-OW5HDTMX-CnzQfOGp.js} +1 -1
  252. package/out/web/assets/{cynefinDiagram-5FMLGOSQ-D_JzZBzf.js → cynefinDiagram-5FMLGOSQ-DVtQnfpm.js} +1 -1
  253. package/out/web/assets/{dagre-3AP2YEHR-BDuUeMHj.js → dagre-3AP2YEHR-DG76_k5_.js} +1 -1
  254. package/out/web/assets/{diagram-S7CK7UJ4-DgtcfE8P.js → diagram-S7CK7UJ4-CaouUoze.js} +1 -1
  255. package/out/web/assets/{diagram-UQ7AKVKN-DTLoEYti.js → diagram-UQ7AKVKN-B4bEc26B.js} +1 -1
  256. package/out/web/assets/{diagram-VSXAHHWV-ChGl9pXz.js → diagram-VSXAHHWV-BJ86Ov2Y.js} +1 -1
  257. package/out/web/assets/{diagram-VX7I27RA-Be8DWz0S.js → diagram-VX7I27RA-7hH5IPYf.js} +1 -1
  258. package/out/web/assets/{diagram-Z3DM3KII-BMXjRTOF.js → diagram-Z3DM3KII-CCM4clo8.js} +1 -1
  259. package/out/web/assets/dist-js-BkYNznHX.js +1 -0
  260. package/out/web/assets/{ebnfDiagram-PWID7BFC-8Q9pl1CJ.js → ebnfDiagram-PWID7BFC-Da7WAM3k.js} +1 -1
  261. package/out/web/assets/{erDiagram-SSCWMZ5O-DjH8Lnkn.js → erDiagram-SSCWMZ5O-CzzmnZWT.js} +1 -1
  262. package/out/web/assets/event-Cdt7Byyj.js +1 -0
  263. package/out/web/assets/{eventmodeling-NTZA5JFV-BKUH_DOp.js → eventmodeling-NTZA5JFV-xcfsA0XD.js} +1 -1
  264. package/out/web/assets/fira-code-latin-600-normal-BmSSHshu.woff +0 -0
  265. package/out/web/assets/fira-code-latin-600-normal-CvYZpPHg.woff2 +0 -0
  266. package/out/web/assets/fira-code-symbols2-600-normal-Dvq6IQE5.woff +0 -0
  267. package/out/web/assets/flowDiagram-A5DVABFB-JdtH1673.js +1 -0
  268. package/out/web/assets/{ganttDiagram-EL5Y4UJY-D7fZKJNM.js → ganttDiagram-EL5Y4UJY-B3ClFGmL.js} +1 -1
  269. package/out/web/assets/{gitGraph-4MIJSDKK-BypWaaBU.js → gitGraph-4MIJSDKK-BZ_y_cDU.js} +1 -1
  270. package/out/web/assets/{gitGraphDiagram-WWUBYQGX-DWiw_3bq.js → gitGraphDiagram-WWUBYQGX-drhRSYm3.js} +1 -1
  271. package/out/web/assets/index-BZ9xgmMP.css +1 -0
  272. package/out/web/assets/index-Ca8cCS4h.js +168 -0
  273. package/out/web/assets/{info-A6RAGUB7-KkAUxT4j.js → info-A6RAGUB7-B7I3K0F1.js} +1 -1
  274. package/out/web/assets/{infoDiagram-RXCK75RN-BNb6E48y.js → infoDiagram-RXCK75RN-deX_1MPh.js} +1 -1
  275. package/out/web/assets/{ishikawaDiagram-5VMMS53U-Caa-JoAK.js → ishikawaDiagram-5VMMS53U-s38yo28y.js} +1 -1
  276. package/out/web/assets/{journeyDiagram-EYS64GPL-DOrmFGz6.js → journeyDiagram-EYS64GPL-CZn2kB8b.js} +1 -1
  277. package/out/web/assets/jsx-runtime-DN4NhQUK.js +1 -0
  278. package/out/web/assets/{kanban-definition-3QL26DDD-BOWCYcK0.js → kanban-definition-3QL26DDD-DodjgySL.js} +1 -1
  279. package/out/web/assets/markdown-CMhYIcWB.js +39 -0
  280. package/out/web/assets/{mermaid-parser.core-BQqjCkS_.js → mermaid-parser.core-Whu2rlJC.js} +3 -3
  281. package/out/web/assets/mermaid.core-CKyPo8VH.js +11 -0
  282. package/out/web/assets/{mindmap-definition-FBJOCRG2-jTceWpr0.js → mindmap-definition-FBJOCRG2-260WBDxZ.js} +1 -1
  283. package/out/web/assets/modelManager-CUaGWMWu.js +2 -0
  284. package/out/web/assets/oauthManager-DlNhXJr6.js +1 -0
  285. package/out/web/assets/{packet-AYTQ26CC-CJ5RXgol.js → packet-AYTQ26CC-CEeIRKRG.js} +1 -1
  286. package/out/web/assets/{pegDiagram-XKGWAZYB-y8wMtd0y.js → pegDiagram-XKGWAZYB-BYadI-KO.js} +1 -1
  287. package/out/web/assets/{pie-WAS4IAKB-72fTBbl4.js → pie-WAS4IAKB-D8uf4dh5.js} +1 -1
  288. package/out/web/assets/{pieDiagram-E7YTZNPT-e0O02qWq.js → pieDiagram-E7YTZNPT-CjSDy4hO.js} +1 -1
  289. package/out/web/assets/{quadrantDiagram-AXDQQJYC-C9phYLom.js → quadrantDiagram-AXDQQJYC-B8D3gU5d.js} +1 -1
  290. package/out/web/assets/{radar-RG4KPBEZ-BAU2hzUT.js → radar-RG4KPBEZ-DZJxnokY.js} +1 -1
  291. package/out/web/assets/{railroad-74A4TZTK-B0bCAVHC.js → railroad-74A4TZTK-DBysUiUi.js} +1 -1
  292. package/out/web/assets/{railroad-abnf-HS5TGJTU-WhxO7ndE.js → railroad-abnf-HS5TGJTU-CHWxoJYg.js} +1 -1
  293. package/out/web/assets/{railroad-ebnf-LZEXJU2U-BkA0m7-F.js → railroad-ebnf-LZEXJU2U-DDv7X6bY.js} +1 -1
  294. package/out/web/assets/{railroad-peg-WCYAUIDC-BsVpHIaj.js → railroad-peg-WCYAUIDC-DpfcYYNJ.js} +1 -1
  295. package/out/web/assets/{railroadDiagram-O6MQD6OU-CyOLN65Q.js → railroadDiagram-O6MQD6OU-CYtyv0t3.js} +1 -1
  296. package/out/web/assets/{requirementDiagram-EFPCY7ZU-DQXJ7Dud.js → requirementDiagram-EFPCY7ZU-D2X-Ewik.js} +1 -1
  297. package/out/web/assets/{sankeyDiagram-P5KCCOFB-B2XLyIIc.js → sankeyDiagram-P5KCCOFB-Bn2x6C4Y.js} +1 -1
  298. package/out/web/assets/{sequenceDiagram-WJ2MYXX4-DGQY4wwm.js → sequenceDiagram-WJ2MYXX4-BvFLKtPd.js} +1 -1
  299. package/out/web/assets/{stateDiagram-HBIQ2CUA-DHZpDwNy.js → stateDiagram-HBIQ2CUA-Bx0GWeaY.js} +1 -1
  300. package/out/web/assets/stateDiagram-v2-4QOOHH4V--hol1yg_.js +1 -0
  301. package/out/web/assets/studio-B1mk40wD.js +1 -0
  302. package/out/web/assets/{swimlanes-XN3QIQJK-Bn_jcZz-.js → swimlanes-XN3QIQJK-CCma0T7L.js} +1 -1
  303. package/out/web/assets/swimlanesDiagram-VK2B7HYN-BkohoVsU.js +8 -0
  304. package/out/web/assets/{timeline-definition-24CTP7MA-CdTERuJZ.js → timeline-definition-24CTP7MA-iCRhhJ7C.js} +1 -1
  305. package/out/web/assets/{treeView-Q6P3EWNA-TKBKQG6R.js → treeView-Q6P3EWNA-DZ-y08qp.js} +1 -1
  306. package/out/web/assets/{treemap-WGGIJYW6-BP7gQoiC.js → treemap-WGGIJYW6-De0CxzMx.js} +1 -1
  307. package/out/web/assets/{vennDiagram-4TSXK5OY-BHUmxDuK.js → vennDiagram-4TSXK5OY-w_7aZ6xe.js} +1 -1
  308. package/out/web/assets/{wardley-WFR3VGLG-9bct5AAN.js → wardley-WFR3VGLG-DT0y0xJ4.js} +1 -1
  309. package/out/web/assets/{wardleyDiagram-VM6X3IG4-BfJwDDso.js → wardleyDiagram-VM6X3IG4-DAdXELbQ.js} +1 -1
  310. package/out/web/assets/window-BJCVtyET.js +1 -0
  311. package/out/web/assets/{xychartDiagram-S5SC5T6Z-Dqd9Mvpo.js → xychartDiagram-S5SC5T6Z-IZIXf3Vo.js} +1 -1
  312. package/out/web/index-web.html +4 -4
  313. package/out/web/index.html +4 -4
  314. package/package.json +80 -20
  315. package/shared-modules/.github/workflows/ci.yml +120 -0
  316. package/shared-modules/.github/workflows/update.yaml +28 -0
  317. package/slash-commands.json +16 -2
  318. package/src/bin/auto-build.js +66 -0
  319. package/src/bin/desktop.js +113 -0
  320. package/src/bin/desktop.test.js +113 -0
  321. package/src/bin/index.js +18 -25
  322. package/src/bin/index.test.js +89 -0
  323. package/src/bin/measure-effects.mjs +53 -0
  324. package/src/bin/package.test.js +28 -0
  325. package/src/bin/release-notes.test.js +84 -0
  326. package/src/bin/styles.test.js +20 -0
  327. package/src/bin/web.js +5 -0
  328. package/src/bin/web.test.js +39 -0
  329. package/src/renderer/index-web.html +1 -0
  330. package/src/renderer/index.html +1 -2
  331. package/src/renderer/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  332. package/src/renderer/shared/agentProgress.ts +201 -3
  333. package/src/renderer/shared/components/AgentActivityDrawer.tsx +9 -8
  334. package/src/renderer/shared/components/AgentActivityTable.tsx +193 -133
  335. package/src/renderer/shared/components/ApprovalCard.test.tsx +24 -0
  336. package/src/renderer/shared/components/ApprovalCard.tsx +10 -3
  337. package/src/renderer/shared/components/ArtifactPreviewPanel.tsx +91 -40
  338. package/src/renderer/shared/components/AuthGate.tsx +79 -48
  339. package/src/renderer/shared/components/BackgroundTerminals.tsx +181 -0
  340. package/src/renderer/shared/components/CalculationCard.tsx +41 -15
  341. package/src/renderer/shared/components/ChatCodeBlock.tsx +8 -4
  342. package/src/renderer/shared/components/ChatMessageItem.test.tsx +68 -0
  343. package/src/renderer/shared/components/ChatMessageItem.tsx +52 -33
  344. package/src/renderer/shared/components/ChatPanel.test.tsx +21 -0
  345. package/src/renderer/shared/components/ChatPanel.tsx +676 -415
  346. package/src/renderer/shared/components/ChunkErrorBoundary.tsx +115 -64
  347. package/src/renderer/shared/components/CliSessionsView.test.tsx +125 -0
  348. package/src/renderer/shared/components/CliSessionsView.tsx +543 -0
  349. package/src/renderer/shared/components/CodeReviewPage.tsx +668 -0
  350. package/src/renderer/shared/components/CollapsiblePasteInput.tsx +90 -0
  351. package/src/renderer/shared/components/CommandPalette.tsx +8 -8
  352. package/src/renderer/shared/components/ContextCompactionStatus.tsx +17 -0
  353. package/src/renderer/shared/components/DashboardSidebar.tsx +853 -229
  354. package/src/renderer/shared/components/DesktopTitlebar.tsx +371 -0
  355. package/src/renderer/shared/components/DiffReviewModal.tsx +3 -3
  356. package/src/renderer/shared/components/ErrorNotice.tsx +29 -0
  357. package/src/renderer/shared/components/FormattedMessage.tsx +11 -0
  358. package/src/renderer/shared/components/GeminiLiveOverlay.css +86 -0
  359. package/src/renderer/shared/components/GeminiLiveOverlay.test.tsx +24 -0
  360. package/src/renderer/shared/components/GeminiLiveOverlay.tsx +85 -101
  361. package/src/renderer/shared/components/GitBranchSelector.tsx +442 -0
  362. package/src/renderer/shared/components/GlideSelect.css +138 -0
  363. package/src/renderer/shared/components/GlideSelect.d.ts +31 -0
  364. package/src/renderer/shared/components/GlideSelect.jsx +266 -0
  365. package/src/renderer/shared/components/ImageGenCard.tsx +31 -12
  366. package/src/renderer/shared/components/ImageSearchCard.tsx +76 -65
  367. package/src/renderer/shared/components/ImageStudioPanel.tsx +49 -49
  368. package/src/renderer/shared/components/InlineThoughtNote.tsx +27 -0
  369. package/src/renderer/shared/components/LibraryItemCard.tsx +72 -0
  370. package/src/renderer/shared/components/LibraryPage.tsx +165 -0
  371. package/src/renderer/shared/components/LibraryPreview.tsx +59 -0
  372. package/src/renderer/shared/components/LinkedFoldersView.tsx +365 -46
  373. package/src/renderer/shared/components/McpRegistryPicker.tsx +1 -1
  374. package/src/renderer/shared/components/McpServersView.tsx +51 -30
  375. package/src/renderer/shared/components/McpToolAllowlist.tsx +2 -4
  376. package/src/renderer/shared/components/McpToolResults.tsx +99 -0
  377. package/src/renderer/shared/components/MermaidCard.tsx +14 -8
  378. package/src/renderer/shared/components/MintDashboard.tsx +1002 -831
  379. package/src/renderer/shared/components/ModSessionControls.tsx +8 -0
  380. package/src/renderer/shared/components/ModUi.test.tsx +65 -0
  381. package/src/renderer/shared/components/ModUi.tsx +26 -0
  382. package/src/renderer/shared/components/ModelSelectorPopover.tsx +547 -219
  383. package/src/renderer/shared/components/ModsPanel.tsx +156 -0
  384. package/src/renderer/shared/components/PlanChecklistWidget.tsx +1 -1
  385. package/src/renderer/shared/components/PluginsView.tsx +1 -1
  386. package/src/renderer/shared/components/ProgressActivity.tsx +17 -0
  387. package/src/renderer/shared/components/ReviewHistory.tsx +42 -0
  388. package/src/renderer/shared/components/RewindModal.tsx +11 -18
  389. package/src/renderer/shared/components/RunSummaryDashboard.tsx +8 -14
  390. package/src/renderer/shared/components/ScheduledTasksView.tsx +11 -10
  391. package/src/renderer/shared/components/ScreenCaptureDialog.css +221 -0
  392. package/src/renderer/shared/components/ScreenCaptureDialog.tsx +199 -0
  393. package/src/renderer/shared/components/SelectField.test.tsx +27 -0
  394. package/src/renderer/shared/components/SelectField.tsx +38 -0
  395. package/src/renderer/shared/components/SessionSources.tsx +48 -0
  396. package/src/renderer/shared/components/SessionSourcesPopover.tsx +61 -0
  397. package/src/renderer/shared/components/Settings/AgentsTab.tsx +41 -45
  398. package/src/renderer/shared/components/Settings/AudioTab.tsx +16 -15
  399. package/src/renderer/shared/components/Settings/AutomationTab.tsx +10 -60
  400. package/src/renderer/shared/components/Settings/AvatarCropModal.tsx +368 -0
  401. package/src/renderer/shared/components/Settings/GeneralTab.tsx +368 -113
  402. package/src/renderer/shared/components/Settings/MemoryTab.test.tsx +37 -0
  403. package/src/renderer/shared/components/Settings/MemoryTab.tsx +71 -31
  404. package/src/renderer/shared/components/Settings/NotificationsTab.test.tsx +15 -0
  405. package/src/renderer/shared/components/Settings/NotificationsTab.tsx +84 -0
  406. package/src/renderer/shared/components/Settings/PluginsTab.tsx +20 -12
  407. package/src/renderer/shared/components/Settings/ProfileTab.tsx +29 -5
  408. package/src/renderer/shared/components/Settings/SearchableModelCombobox.tsx +411 -0
  409. package/src/renderer/shared/components/Settings/ThemeTab.tsx +416 -165
  410. package/src/renderer/shared/components/SkillsView.tsx +41 -16
  411. package/src/renderer/shared/components/SlashChoicePanel.tsx +88 -0
  412. package/src/renderer/shared/components/SlashSuggestions.test.tsx +33 -0
  413. package/src/renderer/shared/components/SlashSuggestions.tsx +41 -12
  414. package/src/renderer/shared/components/SourcesBlock.tsx +55 -51
  415. package/src/renderer/shared/components/StockCard.tsx +58 -24
  416. package/src/renderer/shared/components/SubagentDagView.tsx +4 -4
  417. package/src/renderer/shared/components/TerminalDock.tsx +241 -0
  418. package/src/renderer/shared/components/ThinkingBlock.tsx +14 -8
  419. package/src/renderer/shared/components/ToolSurfacePage.test.tsx +32 -0
  420. package/src/renderer/shared/components/ToolSurfacePage.tsx +568 -0
  421. package/src/renderer/shared/components/ToolsPanelToggle.tsx +13 -0
  422. package/src/renderer/shared/components/UiFeatureCard.tsx +267 -0
  423. package/src/renderer/shared/components/UiGridCard.tsx +188 -0
  424. package/src/renderer/shared/components/UiMockupWidget.tsx +149 -0
  425. package/src/renderer/shared/components/VeoStudioPanel.tsx +22 -37
  426. package/src/renderer/shared/components/ViewedImages.tsx +36 -0
  427. package/src/renderer/shared/components/VirtualChatHistory.tsx +82 -0
  428. package/src/renderer/shared/components/VoicePill.css +85 -0
  429. package/src/renderer/shared/components/VoicePill.d.ts +12 -0
  430. package/src/renderer/shared/components/VoicePill.jsx +190 -0
  431. package/src/renderer/shared/components/VoicePill.test.tsx +22 -0
  432. package/src/renderer/shared/components/WeatherCard.tsx +3 -3
  433. package/src/renderer/shared/components/WorkspaceContextPopover.tsx +138 -0
  434. package/src/renderer/shared/components/WorkspacePaneResizer.tsx +92 -0
  435. package/src/renderer/shared/components/WorkspacePreviewActions.test.tsx +44 -0
  436. package/src/renderer/shared/components/WorkspacePreviewActions.tsx +19 -0
  437. package/src/renderer/shared/components/WorkspaceSelector.tsx +154 -0
  438. package/src/renderer/shared/components/background-terminals.css +292 -0
  439. package/src/renderer/shared/components/ui/README.md +52 -0
  440. package/src/renderer/shared/components/ui/button.tsx +37 -0
  441. package/src/renderer/shared/components/ui/demo.tsx +26 -0
  442. package/src/renderer/shared/components/ui/error-recovery.css +35 -0
  443. package/src/renderer/shared/components/ui/error-recovery.tsx +35 -0
  444. package/src/renderer/shared/components/ui/voice-powered-orb.css +6 -0
  445. package/src/renderer/shared/components/ui/voice-powered-orb.tsx +374 -0
  446. package/src/renderer/shared/components/workspace-selector.css +248 -0
  447. package/src/renderer/shared/constants/config.ts +57 -3
  448. package/src/renderer/shared/constants/models.ts +189 -2
  449. package/src/renderer/shared/constants/slashCommands.ts +1 -1
  450. package/src/renderer/shared/conversation/coordinator.test.ts +27 -0
  451. package/src/renderer/shared/conversation/coordinator.ts +82 -0
  452. package/src/renderer/shared/conversation/lifecycle.test.ts +362 -0
  453. package/src/renderer/shared/conversation/lifecycle.ts +418 -0
  454. package/src/renderer/shared/conversation/projectNavigation.test.ts +105 -0
  455. package/src/renderer/shared/conversation/projectNavigation.ts +39 -0
  456. package/src/renderer/shared/conversation/sourcesTransport.ts +27 -0
  457. package/src/renderer/shared/conversation/syncView.test.ts +13 -0
  458. package/src/renderer/shared/conversation/syncView.ts +6 -0
  459. package/src/renderer/shared/conversation/transport.test.ts +163 -0
  460. package/src/renderer/shared/conversation/transport.ts +159 -0
  461. package/src/renderer/shared/conversation/useConversationCoordinator.ts +64 -0
  462. package/src/renderer/shared/css/agent-observability.css +46 -15
  463. package/src/renderer/shared/css/auth-gate.css +114 -15
  464. package/src/renderer/shared/css/chat-ui-cards.css +495 -0
  465. package/src/renderer/shared/css/code-review.css +856 -0
  466. package/src/renderer/shared/css/code-sessions.css +479 -0
  467. package/src/renderer/shared/css/collapsed-paste.css +35 -0
  468. package/src/renderer/shared/css/effects.css +15 -0
  469. package/src/renderer/shared/css/error-notice.css +60 -0
  470. package/src/renderer/shared/css/file-changes.css +132 -0
  471. package/src/renderer/shared/css/image-studio.css +16 -16
  472. package/src/renderer/shared/css/library.css +476 -0
  473. package/src/renderer/shared/css/management-views.css +415 -27
  474. package/src/renderer/shared/css/mcp-results.css +11 -0
  475. package/src/renderer/shared/css/model-selector.css +543 -85
  476. package/src/renderer/shared/css/mods.css +77 -0
  477. package/src/renderer/shared/css/notification-notice.css +28 -0
  478. package/src/renderer/shared/css/session-sources-popover.css +9 -0
  479. package/src/renderer/shared/css/session-sources.css +23 -0
  480. package/src/renderer/shared/css/settings/agents.css +1 -1
  481. package/src/renderer/shared/css/settings/automation.css +13 -13
  482. package/src/renderer/shared/css/settings/general.css +526 -5
  483. package/src/renderer/shared/css/settings/memory.css +154 -0
  484. package/src/renderer/shared/css/settings/notifications.css +11 -0
  485. package/src/renderer/shared/css/settings/plugins.css +5 -5
  486. package/src/renderer/shared/css/settings/profile.css +331 -1
  487. package/src/renderer/shared/css/settings/theme.css +656 -3
  488. package/src/renderer/shared/css/slash-choice.css +95 -0
  489. package/src/renderer/shared/css/slash-suggestions.css +68 -0
  490. package/src/renderer/shared/css/sources-block.css +91 -0
  491. package/src/renderer/shared/css/thinking-status.css +46 -0
  492. package/src/renderer/shared/css/tools-panel.css +7 -0
  493. package/src/renderer/shared/css/ui-tailwind.css +19 -0
  494. package/src/renderer/shared/css/veo-studio.css +16 -15
  495. package/src/renderer/shared/css/viewed-images.css +15 -0
  496. package/src/renderer/shared/fonts.css +46 -0
  497. package/src/renderer/shared/fonts.ts +10 -37
  498. package/src/renderer/shared/lib/utils.ts +6 -0
  499. package/src/renderer/shared/library/controller.test.ts +61 -0
  500. package/src/renderer/shared/library/controller.ts +57 -0
  501. package/src/renderer/shared/library/transport.test.ts +26 -0
  502. package/src/renderer/shared/library/transport.ts +60 -0
  503. package/src/renderer/shared/library/useLibraryFile.ts +38 -0
  504. package/src/renderer/shared/mods.ts +58 -0
  505. package/src/renderer/shared/platform.test.ts +90 -0
  506. package/src/renderer/shared/platform.ts +219 -7
  507. package/src/renderer/shared/theme/themeManager.test.ts +43 -0
  508. package/src/renderer/shared/theme/themeManager.ts +157 -0
  509. package/src/renderer/shared/theme/themes.ts +116 -0
  510. package/src/renderer/shared/theme/tokens.css +318 -0
  511. package/src/renderer/shared/types.ts +137 -2
  512. package/src/renderer/shared/utils/agentActivity.test.ts +75 -0
  513. package/src/renderer/shared/utils/agentActivity.ts +168 -8
  514. package/src/renderer/shared/utils/approval.tsx +7 -0
  515. package/src/renderer/shared/utils/artifactBrowser.test.ts +80 -0
  516. package/src/renderer/shared/utils/artifactBrowser.ts +41 -0
  517. package/src/renderer/shared/utils/cardJson.test.ts +35 -0
  518. package/src/renderer/shared/utils/cardJson.ts +30 -0
  519. package/src/renderer/shared/utils/contextCompaction.test.tsx +48 -0
  520. package/src/renderer/shared/utils/contextCompaction.ts +21 -0
  521. package/src/renderer/shared/utils/effectVisibility.ts +9 -0
  522. package/src/renderer/shared/utils/fileIcons.ts +1 -1
  523. package/src/renderer/shared/utils/markdown.tsx +330 -81
  524. package/src/renderer/shared/utils/markdown.webImages.test.tsx +40 -0
  525. package/src/renderer/shared/utils/mcpResults.test.tsx +91 -0
  526. package/src/renderer/shared/utils/modViewport.ts +7 -0
  527. package/src/renderer/shared/utils/nativeRecordingSession.test.ts +61 -0
  528. package/src/renderer/shared/utils/nativeRecordingSession.ts +46 -0
  529. package/src/renderer/shared/utils/notificationSettings.test.ts +14 -0
  530. package/src/renderer/shared/utils/notificationSettings.ts +23 -0
  531. package/src/renderer/shared/utils/notifications.test.ts +51 -0
  532. package/src/renderer/shared/utils/notifications.ts +54 -0
  533. package/src/renderer/shared/utils/pastedText.test.ts +20 -0
  534. package/src/renderer/shared/utils/pastedText.ts +13 -0
  535. package/src/renderer/shared/utils/progressCache.test.ts +32 -0
  536. package/src/renderer/shared/utils/providers.ts +8 -3
  537. package/src/renderer/shared/utils/screenCapture.ts +43 -0
  538. package/src/renderer/shared/utils/sessionSources.test.ts +31 -0
  539. package/src/renderer/shared/utils/sessionSources.ts +34 -0
  540. package/src/renderer/shared/utils/slashCommandProcessor.ts +5 -2
  541. package/src/renderer/shared/utils/sourceAttachments.ts +28 -0
  542. package/src/renderer/shared/utils/speech.ts +51 -9
  543. package/src/renderer/shared/utils/syntaxHighlight.test.tsx +22 -0
  544. package/src/renderer/shared/utils/syntaxHighlight.tsx +26 -0
  545. package/src/renderer/shared/utils/ui.ts +4 -64
  546. package/src/renderer/shared/utils/useGeminiLiveVoice.ts +49 -5
  547. package/src/renderer/shared/utils/useLatestCallback.ts +9 -0
  548. package/src/renderer/shared/utils/useNativeVoiceInput.ts +80 -72
  549. package/src/renderer/shared/utils/useSessionSources.ts +33 -0
  550. package/src/renderer/shared/utils/viewedImages.ts +26 -0
  551. package/src/renderer/shared/utils/workspacePane.test.ts +33 -0
  552. package/src/renderer/shared/utils/workspacePane.ts +20 -0
  553. package/src/renderer/shared/utils/workspacePreview.test.ts +24 -0
  554. package/src/renderer/shared/utils/workspacePreview.ts +16 -0
  555. package/src/renderer/shared/utils/workspaceSnapshot.test.ts +49 -0
  556. package/src/renderer/shared/utils/workspaceSnapshot.ts +26 -0
  557. package/src/renderer/shared/utils/workspaces.ts +10 -0
  558. package/src/renderer/shared/workspaceUndo.ts +88 -0
  559. package/src/renderer/src/App.tsx +16 -1
  560. package/src/renderer/src/components/BrowserShell.tsx +108 -0
  561. package/src/renderer/src/components/BrowserSuggestionsPopup.tsx +91 -0
  562. package/src/renderer/src/components/LiveTranslateControls.tsx +65 -0
  563. package/src/renderer/src/components/MintDashboard.tsx +4 -2
  564. package/src/renderer/src/components/PicturesLibrary.tsx +2 -287
  565. package/src/renderer/src/components/ScreenPicker.css +227 -0
  566. package/src/renderer/src/components/ScreenPicker.tsx +312 -526
  567. package/src/renderer/src/components/SettingsWindow.tsx +48 -5
  568. package/src/renderer/src/components/SpotlightWindow.tsx +1 -0
  569. package/src/renderer/src/components/WidgetWindow.tsx +27 -3
  570. package/src/renderer/src/components/WorkspacePanel.tsx +269 -61
  571. package/src/renderer/src/components/browser-shell.css +185 -0
  572. package/src/renderer/src/components/browser-suggestions-popup.css +55 -0
  573. package/src/renderer/src/components/liveTranslateFrames.test.ts +44 -0
  574. package/src/renderer/src/components/liveTranslateFrames.ts +45 -0
  575. package/src/renderer/src/components/liveTranslateLanguage.ts +6 -0
  576. package/src/renderer/src/css/app-shell.css +400 -204
  577. package/src/renderer/src/css/chat.css +1666 -594
  578. package/src/renderer/src/css/dashboard.css +11 -0
  579. package/src/renderer/src/css/desktop-tools.css +928 -0
  580. package/src/renderer/src/css/misc.css +5 -60
  581. package/src/renderer/src/css/pictures.css +2 -407
  582. package/src/renderer/src/css/settings/base.css +394 -157
  583. package/src/renderer/src/css/sidebar-workspace.css +1072 -376
  584. package/src/renderer/src/css/spotlight.css +15 -26
  585. package/src/renderer/src/css/tool-surfaces.css +784 -0
  586. package/src/renderer/src/css/widget.css +36 -8
  587. package/src/renderer/src/env.d.ts +4 -9
  588. package/src/renderer/src/hooks/useProviderModels.ts +2 -9
  589. package/src/renderer/src/index.css +53 -46
  590. package/src/renderer/src/main.tsx +12 -0
  591. package/src/renderer/src/proactiveSuggestions.ts +29 -0
  592. package/src/renderer/src/tauri.ts +302 -339
  593. package/src/renderer/src/voiceInput.ts +2 -1
  594. package/src/renderer/src-web/App.tsx +40 -0
  595. package/src/renderer/src-web/components/MintDashboard.tsx +4 -2
  596. package/src/renderer/src-web/components/PicturesLibrary.tsx +2 -284
  597. package/src/renderer/src-web/components/PullToRefresh.tsx +107 -0
  598. package/src/renderer/src-web/components/SettingsWindow.tsx +36 -5
  599. package/src/renderer/src-web/css/app-shell.css +188 -207
  600. package/src/renderer/src-web/css/chat.css +1236 -507
  601. package/src/renderer/src-web/css/dashboard.css +11 -0
  602. package/src/renderer/src-web/css/misc.css +3 -55
  603. package/src/renderer/src-web/css/mobile.css +679 -0
  604. package/src/renderer/src-web/css/pictures.css +2 -415
  605. package/src/renderer/src-web/css/pull-to-refresh.css +54 -0
  606. package/src/renderer/src-web/css/settings/base.css +353 -134
  607. package/src/renderer/src-web/css/settings/mobile.css +320 -0
  608. package/src/renderer/src-web/css/sidebar-workspace.css +546 -187
  609. package/src/renderer/src-web/css/spotlight.css +9 -26
  610. package/src/renderer/src-web/css/widget.css +1 -6
  611. package/src/renderer/src-web/env.d.ts +4 -12
  612. package/src/renderer/src-web/hooks/useProviderModels.ts +2 -9
  613. package/src/renderer/src-web/index.css +53 -96
  614. package/src/renderer/src-web/main.tsx +12 -0
  615. package/src/renderer/src-web/proactiveSuggestions.ts +3 -0
  616. package/src/renderer/src-web/tauri.ts +309 -364
  617. package/src/renderer/tests/backgroundTerminals.browser.html +81 -0
  618. package/src/renderer/tests/chatPanelFixture.ts +23 -0
  619. package/src/renderer/tests/chatPerformance.browser.html +71 -0
  620. package/src/renderer/tests/cliSessions.browser.html +82 -0
  621. package/src/renderer/tests/collapsedPaste.browser.html +70 -0
  622. package/src/renderer/tests/composerMenus.browser.html +116 -0
  623. package/src/renderer/tests/contextCompaction.browser.html +17 -0
  624. package/src/renderer/tests/conversationLifecycle.browser.html +70 -0
  625. package/src/renderer/tests/effectsPerformance.browser.html +13 -0
  626. package/src/renderer/tests/errorRecovery.browser.html +21 -0
  627. package/src/renderer/tests/glideSelect.browser.html +71 -0
  628. package/src/renderer/tests/glideSelect.preview.html +27 -0
  629. package/src/renderer/tests/library.browser.html +1 -0
  630. package/src/renderer/tests/library.browser.tsx +78 -0
  631. package/src/renderer/tests/liveOrb.browser.html +49 -0
  632. package/src/renderer/tests/liveVoice.browser.html +29 -0
  633. package/src/renderer/tests/modInput.browser.html +22 -0
  634. package/src/renderer/tests/sessionSources.browser.html +1 -0
  635. package/src/renderer/tests/sessionSources.browser.tsx +107 -0
  636. package/src/renderer/tests/skills.browser.html +24 -0
  637. package/src/renderer/tests/toolsPanel.browser.html +1 -0
  638. package/src/renderer/tests/toolsPanel.browser.tsx +113 -0
  639. package/src/renderer/tests/viewedImages.browser.html +1 -0
  640. package/src/renderer/tests/viewedImages.browser.tsx +93 -0
  641. package/src/renderer/tests/voicePill.browser.html +80 -0
  642. package/src/renderer/tests/voicePill.preview.html +34 -0
  643. package/src/renderer/tests/webSources.browser.html +1 -0
  644. package/src/renderer/tests/webSources.browser.tsx +98 -0
  645. package/src/renderer/tests/workspaceUndo.browser.html +92 -0
  646. package/src-tauri/Cargo.toml +40 -0
  647. package/src-tauri/build.rs +3 -0
  648. package/src-tauri/src/app/lifecycle.rs +277 -0
  649. package/src-tauri/src/app/mod.rs +4 -0
  650. package/src-tauri/src/app/shortcuts.rs +40 -0
  651. package/src-tauri/src/app/tray.rs +52 -0
  652. package/src-tauri/src/background/events.rs +70 -0
  653. package/src-tauri/src/background/headless.rs +230 -0
  654. package/src-tauri/src/background/mod.rs +4 -0
  655. package/src-tauri/src/background/proactive.rs +262 -0
  656. package/src-tauri/src/commands/approvals.rs +20 -0
  657. package/src-tauri/src/commands/auth.rs +127 -0
  658. package/src-tauri/src/commands/conversation.rs +642 -0
  659. package/src-tauri/src/commands/integrations.rs +157 -0
  660. package/src-tauri/src/commands/media.rs +179 -0
  661. package/src-tauri/src/commands/mod.rs +11 -0
  662. package/src-tauri/src/commands/mods.rs +6 -0
  663. package/src-tauri/src/commands/settings.rs +141 -0
  664. package/src-tauri/src/commands/voice.rs +153 -0
  665. package/src-tauri/src/commands/workspace.rs +501 -0
  666. package/src-tauri/src/lib.rs +10 -0
  667. package/src-tauri/src/main.rs +3 -0
  668. package/src-tauri/src/native/actions.rs +206 -0
  669. package/src-tauri/src/native/browser.rs +252 -0
  670. package/src-tauri/src/native/capture.rs +695 -0
  671. package/src-tauri/src/native/discord_rpc.rs +99 -0
  672. package/src-tauri/src/native/integrations.rs +126 -0
  673. package/src-tauri/src/native/mod.rs +12 -0
  674. package/src-tauri/src/native/notifications.rs +51 -0
  675. package/src-tauri/src/native/plugins.rs +14 -0
  676. package/src-tauri/src/native/system.rs +250 -0
  677. package/src-tauri/src/native/terminal.rs +201 -0
  678. package/src-tauri/src/native/updater.rs +148 -0
  679. package/src-tauri/src/native/windows.rs +143 -0
  680. package/tsconfig.json +2 -0
  681. package/vite.config.ts +4 -1
  682. package/vite.config.web.ts +5 -0
  683. package/.cargo/config.toml +0 -13
  684. package/.claude/settings.local.json +0 -182
  685. package/.codex +0 -0
  686. package/CLAUDE.md +0 -102
  687. package/out/web/Live2DCubismCore.js +0 -9
  688. package/out/web/assets/MintDashboard-DWSqucgb.js +0 -57
  689. package/out/web/assets/SettingsWindow-DFM2aj5B.js +0 -2
  690. package/out/web/assets/chunk-CKBBP62Z-nr1uKPj9.js +0 -2
  691. package/out/web/assets/chunk-DSNCTWBM-Dtj8Rqsd.js +0 -2
  692. package/out/web/assets/chunk-DU6HZSFF-2tv5K1wT.js +0 -128
  693. package/out/web/assets/classDiagram-DTDB5LWJ-BdSFArgw.js +0 -1
  694. package/out/web/assets/classDiagram-v2-JRS7N3AN-BdSFArgw.js +0 -1
  695. package/out/web/assets/core-DImejIUG.js +0 -1
  696. package/out/web/assets/dist-js-BxuKEVWM.js +0 -1
  697. package/out/web/assets/event-BNl8Zahw.js +0 -1
  698. package/out/web/assets/fira-code-cyrillic-400-normal-UC0NFL4U.woff2 +0 -0
  699. package/out/web/assets/fira-code-cyrillic-400-normal-dc1q3VD7.woff +0 -0
  700. package/out/web/assets/fira-code-cyrillic-500-normal-Bu7VCL72.woff +0 -0
  701. package/out/web/assets/fira-code-cyrillic-500-normal-CX35h3Mg.woff2 +0 -0
  702. package/out/web/assets/fira-code-cyrillic-ext-400-normal-Buh61xzB.woff +0 -0
  703. package/out/web/assets/fira-code-cyrillic-ext-400-normal-txZ9Fk_1.woff2 +0 -0
  704. package/out/web/assets/fira-code-cyrillic-ext-500-normal-CYRspHgm.woff2 +0 -0
  705. package/out/web/assets/fira-code-cyrillic-ext-500-normal-CwtLmSFD.woff +0 -0
  706. package/out/web/assets/fira-code-greek-400-normal-B2Gh_Y8s.woff2 +0 -0
  707. package/out/web/assets/fira-code-greek-400-normal-DobhaxvF.woff +0 -0
  708. package/out/web/assets/fira-code-greek-500-normal-CVO0IRNt.woff2 +0 -0
  709. package/out/web/assets/fira-code-greek-500-normal-DEXIWiey.woff +0 -0
  710. package/out/web/assets/fira-code-greek-ext-400-normal-DR7mBgIM.woff2 +0 -0
  711. package/out/web/assets/fira-code-greek-ext-400-normal-DSPUheWg.woff +0 -0
  712. package/out/web/assets/fira-code-greek-ext-500-normal-BO3iq16n.woff2 +0 -0
  713. package/out/web/assets/fira-code-greek-ext-500-normal-CMiNLXER.woff +0 -0
  714. package/out/web/assets/fira-code-latin-ext-400-normal-DG73JjOf.woff +0 -0
  715. package/out/web/assets/fira-code-latin-ext-400-normal-KSMg0QLl.woff2 +0 -0
  716. package/out/web/assets/fira-code-latin-ext-500-normal-CaANqXjI.woff +0 -0
  717. package/out/web/assets/fira-code-latin-ext-500-normal-Crd9e_oI.woff2 +0 -0
  718. package/out/web/assets/flowDiagram-A5DVABFB-BpnHUSU7.js +0 -1
  719. package/out/web/assets/index-CVRg270z.css +0 -1
  720. package/out/web/assets/index-DxZQr9yD.js +0 -10
  721. package/out/web/assets/inter-cyrillic-400-normal-HOLc17fK.woff +0 -0
  722. package/out/web/assets/inter-cyrillic-400-normal-obahsSVq.woff2 +0 -0
  723. package/out/web/assets/inter-cyrillic-500-normal-BasfLYem.woff2 +0 -0
  724. package/out/web/assets/inter-cyrillic-500-normal-CxZf_p3X.woff +0 -0
  725. package/out/web/assets/inter-cyrillic-600-normal-4D_pXhcN.woff +0 -0
  726. package/out/web/assets/inter-cyrillic-600-normal-CWCymEST.woff2 +0 -0
  727. package/out/web/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2 +0 -0
  728. package/out/web/assets/inter-cyrillic-ext-400-normal-DQukG94-.woff +0 -0
  729. package/out/web/assets/inter-cyrillic-ext-500-normal-B0yAr1jD.woff2 +0 -0
  730. package/out/web/assets/inter-cyrillic-ext-500-normal-BmqWE9Dz.woff +0 -0
  731. package/out/web/assets/inter-cyrillic-ext-600-normal-Bcila6Z-.woff +0 -0
  732. package/out/web/assets/inter-cyrillic-ext-600-normal-Dfes3d0z.woff2 +0 -0
  733. package/out/web/assets/inter-greek-400-normal-B4URO6DV.woff2 +0 -0
  734. package/out/web/assets/inter-greek-400-normal-q2sYcFCs.woff +0 -0
  735. package/out/web/assets/inter-greek-500-normal-BIZE56-Y.woff2 +0 -0
  736. package/out/web/assets/inter-greek-500-normal-Xzm54t5V.woff +0 -0
  737. package/out/web/assets/inter-greek-600-normal-BZpKdvQh.woff +0 -0
  738. package/out/web/assets/inter-greek-600-normal-plRanbMR.woff2 +0 -0
  739. package/out/web/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2 +0 -0
  740. package/out/web/assets/inter-greek-ext-400-normal-KugGGMne.woff +0 -0
  741. package/out/web/assets/inter-greek-ext-500-normal-2j5mBUwD.woff +0 -0
  742. package/out/web/assets/inter-greek-ext-500-normal-C4iEst2y.woff2 +0 -0
  743. package/out/web/assets/inter-greek-ext-600-normal-B8X0CLgF.woff +0 -0
  744. package/out/web/assets/inter-greek-ext-600-normal-DRtmH8MT.woff2 +0 -0
  745. package/out/web/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
  746. package/out/web/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
  747. package/out/web/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
  748. package/out/web/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
  749. package/out/web/assets/inter-latin-600-normal-CiBQ2DWP.woff +0 -0
  750. package/out/web/assets/inter-latin-600-normal-LgqL8muc.woff2 +0 -0
  751. package/out/web/assets/inter-latin-ext-400-normal-77YHD8bZ.woff +0 -0
  752. package/out/web/assets/inter-latin-ext-400-normal-C1nco2VV.woff2 +0 -0
  753. package/out/web/assets/inter-latin-ext-500-normal-BxGbmqWO.woff +0 -0
  754. package/out/web/assets/inter-latin-ext-500-normal-CV4jyFjo.woff2 +0 -0
  755. package/out/web/assets/inter-latin-ext-600-normal-CIVaiw4L.woff +0 -0
  756. package/out/web/assets/inter-latin-ext-600-normal-D2bJ5OIk.woff2 +0 -0
  757. package/out/web/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff +0 -0
  758. package/out/web/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
  759. package/out/web/assets/inter-vietnamese-500-normal-DOriooB6.woff2 +0 -0
  760. package/out/web/assets/inter-vietnamese-500-normal-mJboJaSs.woff +0 -0
  761. package/out/web/assets/inter-vietnamese-600-normal-BuLX-rYi.woff +0 -0
  762. package/out/web/assets/inter-vietnamese-600-normal-Cc8MFFhd.woff2 +0 -0
  763. package/out/web/assets/kanit-latin-400-normal-BUlsQXH3.woff2 +0 -0
  764. package/out/web/assets/kanit-latin-400-normal-HVZWrfev.woff +0 -0
  765. package/out/web/assets/kanit-latin-500-normal-CX_4XcKi.woff2 +0 -0
  766. package/out/web/assets/kanit-latin-500-normal-qBha86O4.woff +0 -0
  767. package/out/web/assets/kanit-latin-600-normal-0lS78yAd.woff2 +0 -0
  768. package/out/web/assets/kanit-latin-600-normal-DlacpeTg.woff +0 -0
  769. package/out/web/assets/kanit-latin-ext-400-normal-B2xPf58u.woff2 +0 -0
  770. package/out/web/assets/kanit-latin-ext-400-normal-CHvNKHHD.woff +0 -0
  771. package/out/web/assets/kanit-latin-ext-500-normal-BFdWrG22.woff +0 -0
  772. package/out/web/assets/kanit-latin-ext-500-normal-EHs3suD6.woff2 +0 -0
  773. package/out/web/assets/kanit-latin-ext-600-normal-BBDzoLaj.woff +0 -0
  774. package/out/web/assets/kanit-latin-ext-600-normal-DAX3wtuq.woff2 +0 -0
  775. package/out/web/assets/kanit-thai-400-normal-D2nliXKa.woff +0 -0
  776. package/out/web/assets/kanit-thai-400-normal-D80Pglro.woff2 +0 -0
  777. package/out/web/assets/kanit-thai-500-normal-BB8gri04.woff2 +0 -0
  778. package/out/web/assets/kanit-thai-500-normal-Iy_w0a80.woff +0 -0
  779. package/out/web/assets/kanit-thai-600-normal-Bj6oiaDc.woff2 +0 -0
  780. package/out/web/assets/kanit-thai-600-normal-wbTlPO7I.woff +0 -0
  781. package/out/web/assets/kanit-vietnamese-400-normal-DRI8YWyb.woff2 +0 -0
  782. package/out/web/assets/kanit-vietnamese-400-normal-dow6Bnto.woff +0 -0
  783. package/out/web/assets/kanit-vietnamese-500-normal-BzTrpCM3.woff2 +0 -0
  784. package/out/web/assets/kanit-vietnamese-500-normal-T1ndT7MF.woff +0 -0
  785. package/out/web/assets/kanit-vietnamese-600-normal-Bi7fw3I4.woff2 +0 -0
  786. package/out/web/assets/kanit-vietnamese-600-normal-DXCRAa_8.woff +0 -0
  787. package/out/web/assets/mali-latin-400-normal-ByPcZ8Gx.woff +0 -0
  788. package/out/web/assets/mali-latin-400-normal-Cuc6Ykl8.woff2 +0 -0
  789. package/out/web/assets/mali-latin-500-normal-B01M-LP6.woff2 +0 -0
  790. package/out/web/assets/mali-latin-500-normal-Thgqw_9f.woff +0 -0
  791. package/out/web/assets/mali-latin-600-normal-B9TiUNpT.woff2 +0 -0
  792. package/out/web/assets/mali-latin-600-normal-CycpQCwU.woff +0 -0
  793. package/out/web/assets/mali-latin-ext-400-normal-DUVdJQO4.woff +0 -0
  794. package/out/web/assets/mali-latin-ext-400-normal-iCG1ALuJ.woff2 +0 -0
  795. package/out/web/assets/mali-latin-ext-500-normal-BfJE4UMZ.woff2 +0 -0
  796. package/out/web/assets/mali-latin-ext-500-normal-FoLEyOKS.woff +0 -0
  797. package/out/web/assets/mali-latin-ext-600-normal-BTvIfiCp.woff2 +0 -0
  798. package/out/web/assets/mali-latin-ext-600-normal-DAQcLVmD.woff +0 -0
  799. package/out/web/assets/mali-thai-400-normal-BO7A3bLZ.woff2 +0 -0
  800. package/out/web/assets/mali-thai-400-normal-CX9VrjTn.woff +0 -0
  801. package/out/web/assets/mali-thai-500-normal-Cph2qha9.woff +0 -0
  802. package/out/web/assets/mali-thai-500-normal-D89rMT77.woff2 +0 -0
  803. package/out/web/assets/mali-thai-600-normal-DPgXT6rZ.woff +0 -0
  804. package/out/web/assets/mali-thai-600-normal-DlTx3OsB.woff2 +0 -0
  805. package/out/web/assets/mali-vietnamese-400-normal-DUKxzXaz.woff2 +0 -0
  806. package/out/web/assets/mali-vietnamese-400-normal-gFDLvsOK.woff +0 -0
  807. package/out/web/assets/mali-vietnamese-500-normal--OY07q2c.woff +0 -0
  808. package/out/web/assets/mali-vietnamese-500-normal-KDrNRwfW.woff2 +0 -0
  809. package/out/web/assets/mali-vietnamese-600-normal-CtTMUU7T.woff +0 -0
  810. package/out/web/assets/mali-vietnamese-600-normal-DFlJr66u.woff2 +0 -0
  811. package/out/web/assets/mermaid.core-DYGGlqOf.js +0 -11
  812. package/out/web/assets/mitr-latin-400-normal-Cb18vPmZ.woff +0 -0
  813. package/out/web/assets/mitr-latin-400-normal-CwbkLQ4a.woff2 +0 -0
  814. package/out/web/assets/mitr-latin-500-normal-B4JOhzAi.woff +0 -0
  815. package/out/web/assets/mitr-latin-500-normal-BmClOow2.woff2 +0 -0
  816. package/out/web/assets/mitr-latin-ext-400-normal-B3CPG7Yo.woff2 +0 -0
  817. package/out/web/assets/mitr-latin-ext-400-normal-DTx65hiC.woff +0 -0
  818. package/out/web/assets/mitr-latin-ext-500-normal-B_Diajz1.woff2 +0 -0
  819. package/out/web/assets/mitr-latin-ext-500-normal-DYOsVaVT.woff +0 -0
  820. package/out/web/assets/mitr-thai-400-normal-CS4Do6aM.woff +0 -0
  821. package/out/web/assets/mitr-thai-400-normal-CXWaAdVj.woff2 +0 -0
  822. package/out/web/assets/mitr-thai-500-normal-CVdBrEVH.woff2 +0 -0
  823. package/out/web/assets/mitr-thai-500-normal-CW_B5D-i.woff +0 -0
  824. package/out/web/assets/mitr-vietnamese-400-normal-CPMGWyoC.woff2 +0 -0
  825. package/out/web/assets/mitr-vietnamese-400-normal-Z6XhIpdY.woff +0 -0
  826. package/out/web/assets/mitr-vietnamese-500-normal-CDrv0585.woff2 +0 -0
  827. package/out/web/assets/mitr-vietnamese-500-normal-CMQWyq-Z.woff +0 -0
  828. package/out/web/assets/noto-sans-thai-latin-400-normal-BaWBrqFP.woff2 +0 -0
  829. package/out/web/assets/noto-sans-thai-latin-400-normal-Dh_FJjOB.woff +0 -0
  830. package/out/web/assets/noto-sans-thai-latin-500-normal-BC04jsmm.woff +0 -0
  831. package/out/web/assets/noto-sans-thai-latin-500-normal-fyBKClF1.woff2 +0 -0
  832. package/out/web/assets/noto-sans-thai-latin-600-normal-CemcjnVR.woff2 +0 -0
  833. package/out/web/assets/noto-sans-thai-latin-600-normal-Dbc-dNO6.woff +0 -0
  834. package/out/web/assets/noto-sans-thai-latin-ext-400-normal-B-1H0YkH.woff +0 -0
  835. package/out/web/assets/noto-sans-thai-latin-ext-400-normal-nBP59pVw.woff2 +0 -0
  836. package/out/web/assets/noto-sans-thai-latin-ext-500-normal-B-ZWb8SZ.woff2 +0 -0
  837. package/out/web/assets/noto-sans-thai-latin-ext-500-normal-CrEHO7C8.woff +0 -0
  838. package/out/web/assets/noto-sans-thai-latin-ext-600-normal-PkMZo0xa.woff +0 -0
  839. package/out/web/assets/noto-sans-thai-latin-ext-600-normal-maHHBsez.woff2 +0 -0
  840. package/out/web/assets/noto-sans-thai-thai-400-normal-BEOmKAI1.woff2 +0 -0
  841. package/out/web/assets/noto-sans-thai-thai-400-normal-Dxb_unuU.woff +0 -0
  842. package/out/web/assets/noto-sans-thai-thai-500-normal-BOGXO2tw.woff +0 -0
  843. package/out/web/assets/noto-sans-thai-thai-500-normal-CU_X86GQ.woff2 +0 -0
  844. package/out/web/assets/noto-sans-thai-thai-600-normal-CmgB8_JK.woff +0 -0
  845. package/out/web/assets/noto-sans-thai-thai-600-normal-Cs73sVjl.woff2 +0 -0
  846. package/out/web/assets/oauthManager-DNiwM8Rn.js +0 -2
  847. package/out/web/assets/oauthManager-DuamS1Av.css +0 -1
  848. package/out/web/assets/outfit-latin-300-normal-AWLfuCom.woff +0 -0
  849. package/out/web/assets/outfit-latin-300-normal-CRYTwY6m.woff2 +0 -0
  850. package/out/web/assets/outfit-latin-400-normal-BGsTXAXT.woff2 +0 -0
  851. package/out/web/assets/outfit-latin-400-normal-DMwTpYkH.woff +0 -0
  852. package/out/web/assets/outfit-latin-500-normal-ClnHRwRh.woff +0 -0
  853. package/out/web/assets/outfit-latin-500-normal-DKnIMDSk.woff2 +0 -0
  854. package/out/web/assets/outfit-latin-600-normal-B7SfZ07L.woff2 +0 -0
  855. package/out/web/assets/outfit-latin-600-normal-BEfTtDA7.woff +0 -0
  856. package/out/web/assets/outfit-latin-ext-300-normal-BYS6Dpvq.woff2 +0 -0
  857. package/out/web/assets/outfit-latin-ext-300-normal-CMIMshEd.woff +0 -0
  858. package/out/web/assets/outfit-latin-ext-400-normal-5tcqmc2S.woff2 +0 -0
  859. package/out/web/assets/outfit-latin-ext-400-normal-DHm7mdGe.woff +0 -0
  860. package/out/web/assets/outfit-latin-ext-500-normal-DrCvqoFD.woff +0 -0
  861. package/out/web/assets/outfit-latin-ext-500-normal-zeox_O30.woff2 +0 -0
  862. package/out/web/assets/outfit-latin-ext-600-normal-B85nYjL1.woff2 +0 -0
  863. package/out/web/assets/outfit-latin-ext-600-normal-CWJcPgd7.woff +0 -0
  864. package/out/web/assets/preload-helper-D0uHx7FM.js +0 -1
  865. package/out/web/assets/prompt-latin-400-normal-BQ9zjSN8.woff2 +0 -0
  866. package/out/web/assets/prompt-latin-400-normal-CxU4ec_r.woff +0 -0
  867. package/out/web/assets/prompt-latin-500-normal-B1edBDQ9.woff +0 -0
  868. package/out/web/assets/prompt-latin-500-normal-CxzxEHZc.woff2 +0 -0
  869. package/out/web/assets/prompt-latin-600-normal-CSDDLorv.woff +0 -0
  870. package/out/web/assets/prompt-latin-600-normal-hKZWXsc1.woff2 +0 -0
  871. package/out/web/assets/prompt-latin-ext-400-normal-1pHbN9uy.woff +0 -0
  872. package/out/web/assets/prompt-latin-ext-400-normal-DdSafGZ9.woff2 +0 -0
  873. package/out/web/assets/prompt-latin-ext-500-normal--EZ1um7s.woff2 +0 -0
  874. package/out/web/assets/prompt-latin-ext-500-normal-D-lI1EVT.woff +0 -0
  875. package/out/web/assets/prompt-latin-ext-600-normal-C8b50x67.woff +0 -0
  876. package/out/web/assets/prompt-latin-ext-600-normal-Cg9L7iJU.woff2 +0 -0
  877. package/out/web/assets/prompt-thai-400-normal-BrkKv8cO.woff2 +0 -0
  878. package/out/web/assets/prompt-thai-400-normal-DJypnfr3.woff +0 -0
  879. package/out/web/assets/prompt-thai-500-normal-C18pDUoL.woff2 +0 -0
  880. package/out/web/assets/prompt-thai-500-normal-D7YNqUJD.woff +0 -0
  881. package/out/web/assets/prompt-thai-600-normal-CYPViXds.woff +0 -0
  882. package/out/web/assets/prompt-thai-600-normal-MrdfU7zR.woff2 +0 -0
  883. package/out/web/assets/prompt-vietnamese-400-normal-BCPzsgPT.woff2 +0 -0
  884. package/out/web/assets/prompt-vietnamese-400-normal-D4pLyeNK.woff +0 -0
  885. package/out/web/assets/prompt-vietnamese-500-normal-DmzxmPwa.woff2 +0 -0
  886. package/out/web/assets/prompt-vietnamese-500-normal-w_sS_j2F.woff +0 -0
  887. package/out/web/assets/prompt-vietnamese-600-normal-1dyohtNh.woff +0 -0
  888. package/out/web/assets/prompt-vietnamese-600-normal-7QWjJBsF.woff2 +0 -0
  889. package/out/web/assets/sarabun-latin-400-normal-DmguIS-7.woff +0 -0
  890. package/out/web/assets/sarabun-latin-400-normal-URPBxl-K.woff2 +0 -0
  891. package/out/web/assets/sarabun-latin-500-normal-BjUTcdxu.woff2 +0 -0
  892. package/out/web/assets/sarabun-latin-500-normal-CJexTAnl.woff +0 -0
  893. package/out/web/assets/sarabun-latin-600-normal-9FonlkKx.woff +0 -0
  894. package/out/web/assets/sarabun-latin-600-normal-DMD3TROr.woff2 +0 -0
  895. package/out/web/assets/sarabun-latin-ext-400-normal-BbP7GpLL.woff2 +0 -0
  896. package/out/web/assets/sarabun-latin-ext-400-normal-BsmTn0SS.woff +0 -0
  897. package/out/web/assets/sarabun-latin-ext-500-normal-Cot16Bd2.woff +0 -0
  898. package/out/web/assets/sarabun-latin-ext-500-normal-DE1LysqI.woff2 +0 -0
  899. package/out/web/assets/sarabun-latin-ext-600-normal-0tXu9x_i.woff +0 -0
  900. package/out/web/assets/sarabun-latin-ext-600-normal-BRxjKUQ6.woff2 +0 -0
  901. package/out/web/assets/sarabun-thai-400-normal-C2DaJlKK.woff2 +0 -0
  902. package/out/web/assets/sarabun-thai-400-normal-CH-UbWgg.woff +0 -0
  903. package/out/web/assets/sarabun-thai-500-normal-BVssjame.woff2 +0 -0
  904. package/out/web/assets/sarabun-thai-500-normal-C3iDLEzi.woff +0 -0
  905. package/out/web/assets/sarabun-thai-600-normal-3dIAQ-_s.woff2 +0 -0
  906. package/out/web/assets/sarabun-thai-600-normal-DWKeTe6a.woff +0 -0
  907. package/out/web/assets/sarabun-vietnamese-400-normal-DPfkSCMy.woff +0 -0
  908. package/out/web/assets/sarabun-vietnamese-400-normal-igdrzAGY.woff2 +0 -0
  909. package/out/web/assets/sarabun-vietnamese-500-normal-CpRVvGRU.woff +0 -0
  910. package/out/web/assets/sarabun-vietnamese-500-normal-Dpe7Br9m.woff2 +0 -0
  911. package/out/web/assets/sarabun-vietnamese-600-normal-BMbOgAW-.woff +0 -0
  912. package/out/web/assets/sarabun-vietnamese-600-normal-DkxrOlLB.woff2 +0 -0
  913. package/out/web/assets/stateDiagram-v2-4QOOHH4V-s6P9g2_b.js +0 -1
  914. package/out/web/assets/swimlanesDiagram-VK2B7HYN-CV9fOLrV.js +0 -8
  915. package/out/web/assets/tauri-CNrHQ2Gb.js +0 -3
  916. package/out/web/assets/window-DkIhgI7B.js +0 -1
  917. package/skills-lock.json +0 -41
  918. package/src/renderer/public/Live2DCubismCore.js +0 -9
  919. package/src/renderer/src/companionWidget.ts +0 -95
  920. package/src/renderer/src/components/Live2DStage.tsx +0 -389
  921. package/src/renderer/src/components/ModelPanel.tsx +0 -154
  922. package/src/renderer/src/css/model.css +0 -627
  923. package/src/renderer/src-web/companionWidget.ts +0 -37
  924. package/src/renderer/src-web/components/ModelPanel.tsx +0 -12
  925. package/src/renderer/src-web/css/model.css +0 -628
@@ -1,10 +1,12 @@
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
 
7
7
  use crate::search::text_embedding::{encode_embedding, fact_embedding_backend};
8
+ mod sources;
9
+ pub use sources::{ConversationSources, SessionAttachment, SourceAttachment};
8
10
 
9
11
  pub const CHAT_CLI_ID: &str = "cli";
10
12
  pub const DEFAULT_CONVERSATION_ID: &str = "conversation-default";
@@ -27,11 +29,17 @@ pub fn scoped_chat_id(chat_id: &str, _workspace_path: Option<&str>) -> String {
27
29
  /// (`"cli::subagent::<name>"`, or `"cli::<hash>::subagent::<name>"`) —
28
30
  /// those must keep behaving like a normal, deletable conversation exactly
29
31
  /// as they do today, unaffected by workspace scoping.
30
- fn is_cli_chat_id(chat_id: &str) -> bool {
32
+ pub fn is_cli_chat_id(chat_id: &str) -> bool {
31
33
  chat_id == CHAT_CLI_ID
32
34
  || (chat_id.starts_with(&format!("{CHAT_CLI_ID}::")) && !chat_id.contains("::subagent::"))
33
35
  }
34
36
 
37
+ pub fn generate_cli_session_id() -> String {
38
+ let raw_uuid = uuid::Uuid::new_v4().to_string();
39
+ let short_id = &raw_uuid.replace('-', "")[..12];
40
+ format!("cli::{short_id}")
41
+ }
42
+
35
43
  /// The subagent name embedded in a chat id of the form
36
44
  /// `"<parent>::subagent::<name>"` (see `dispatch_one_subagent`), or `None` for
37
45
  /// an ordinary conversation. Used to scope which agent a fact belongs to and
@@ -45,6 +53,8 @@ pub fn subagent_name(chat_id: &str) -> Option<&str> {
45
53
 
46
54
  #[derive(Debug, Error)]
47
55
  pub enum MemoryError {
56
+ #[error("library error: {0}")]
57
+ Library(String),
48
58
  #[error("unable to determine the user config directory")]
49
59
  ConfigDirectoryUnavailable,
50
60
  #[error("unable to create database directory {path}: {source}")]
@@ -72,11 +82,36 @@ pub struct InteractionMemory {
72
82
  pub model: String,
73
83
  pub fallback_provider: Option<String>,
74
84
  pub created_at: String,
85
+ pub status: String,
75
86
  #[serde(default, skip_serializing_if = "Option::is_none")]
76
87
  pub agent_activity: Option<serde_json::Value>,
77
88
  }
78
89
 
79
- #[derive(Debug, Clone, Serialize, PartialEq, Eq)]
90
+ #[derive(Debug, Clone, Serialize)]
91
+ #[serde(rename_all = "camelCase")]
92
+ pub struct ConversationChange {
93
+ pub sequence: i64,
94
+ pub interaction_id: i64,
95
+ pub interaction: Option<InteractionMemory>,
96
+ }
97
+
98
+ #[derive(Debug, Clone, Serialize)]
99
+ #[serde(rename_all = "camelCase")]
100
+ pub struct ConversationChanges {
101
+ pub changes: Vec<ConversationChange>,
102
+ pub cursor: i64,
103
+ pub has_more: bool,
104
+ }
105
+
106
+ #[derive(Debug, Clone, Serialize)]
107
+ #[serde(rename_all = "camelCase")]
108
+ pub struct ConversationSnapshot {
109
+ pub interactions: Vec<InteractionMemory>,
110
+ pub cursor: i64,
111
+ pub has_older: bool,
112
+ }
113
+
114
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
80
115
  #[serde(rename_all = "camelCase")]
81
116
  pub struct ChatSession {
82
117
  pub id: String,
@@ -84,6 +119,16 @@ pub struct ChatSession {
84
119
  pub kind: String,
85
120
  pub created_at: String,
86
121
  pub updated_at: String,
122
+ #[serde(default, skip_serializing_if = "Option::is_none")]
123
+ pub workspace_path: Option<String>,
124
+ #[serde(default, skip_serializing_if = "Option::is_none")]
125
+ pub git_branch: Option<String>,
126
+ #[serde(default, skip_serializing_if = "Option::is_none")]
127
+ pub main_language: Option<String>,
128
+ #[serde(default)]
129
+ pub message_count: usize,
130
+ #[serde(default)]
131
+ pub total_bytes: usize,
87
132
  }
88
133
 
89
134
  #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
@@ -220,6 +265,232 @@ impl MemoryStore {
220
265
  Ok(connection.last_insert_rowid())
221
266
  }
222
267
 
268
+ /// Insert a visible prompt before any provider or tool work begins.
269
+ pub fn start_turn(&self, chat_id: &str, user_text: &str) -> Result<i64, MemoryError> {
270
+ let chat_id = normalized_chat_id(chat_id);
271
+ let mut connection = self.connection()?;
272
+ let tx = connection.transaction_with_behavior(TransactionBehavior::Immediate)?;
273
+ ensure_chat_session_row(&tx, &chat_id)?;
274
+ tx.execute(
275
+ "INSERT INTO interaction_memories (chat_id, user_text, ai_text, status, lease_until)
276
+ VALUES (?1, ?2, '', 'queued', unixepoch() + 45)",
277
+ params![chat_id, user_text],
278
+ )?;
279
+ let id = tx.last_insert_rowid();
280
+ tx.execute(
281
+ "UPDATE chat_sessions SET title = CASE
282
+ WHEN title = 'New chat' AND trim(?2) != '' THEN substr(trim(?2), 1, 80)
283
+ ELSE title END, updated_at = CURRENT_TIMESTAMP WHERE id = ?1",
284
+ params![chat_id, user_text],
285
+ )?;
286
+ tx.commit()?;
287
+ Ok(id)
288
+ }
289
+
290
+ /// Claim only the oldest unfinished turn. The short transaction never spans AI work.
291
+ pub fn claim_turn(&self, chat_id: &str, id: i64) -> Result<bool, MemoryError> {
292
+ let chat_id = normalized_chat_id(chat_id);
293
+ let mut connection = self.connection()?;
294
+ let tx = connection.transaction_with_behavior(TransactionBehavior::Immediate)?;
295
+ tx.execute(
296
+ "UPDATE interaction_memories SET status = 'interrupted', lease_until = 0
297
+ WHERE chat_id = ?1 AND status IN ('queued', 'running') AND lease_until < unixepoch()",
298
+ params![chat_id],
299
+ )?;
300
+ let own_status: Option<String> = tx
301
+ .query_row(
302
+ "SELECT status FROM interaction_memories WHERE id = ?1 AND chat_id = ?2",
303
+ params![id, chat_id],
304
+ |row| row.get(0),
305
+ )
306
+ .optional()?;
307
+ if own_status.as_deref() != Some("queued") {
308
+ tx.commit()?;
309
+ return Err(MemoryError::Database(rusqlite::Error::QueryReturnedNoRows));
310
+ }
311
+ let earlier: i64 = tx.query_row(
312
+ "SELECT count(*) FROM interaction_memories
313
+ WHERE chat_id = ?1 AND id < ?2 AND status IN ('queued', 'running')",
314
+ params![chat_id, id],
315
+ |row| row.get(0),
316
+ )?;
317
+ let claimed = if earlier == 0 {
318
+ tx.execute(
319
+ "UPDATE interaction_memories SET status = 'running', lease_until = unixepoch() + 45
320
+ WHERE id = ?1 AND chat_id = ?2 AND status = 'queued'",
321
+ params![id, chat_id],
322
+ )? == 1
323
+ } else {
324
+ false
325
+ };
326
+ tx.commit()?;
327
+ Ok(claimed)
328
+ }
329
+
330
+ pub fn renew_turn(&self, id: i64) -> Result<(), MemoryError> {
331
+ self.connection()?.execute(
332
+ "UPDATE interaction_memories SET lease_until = unixepoch() + 45
333
+ WHERE id = ?1 AND status IN ('queued', 'running')",
334
+ params![id],
335
+ )?;
336
+ Ok(())
337
+ }
338
+
339
+ fn expire_abandoned_turns(&self, chat_id: &str) -> Result<(), MemoryError> {
340
+ self.connection()?.execute(
341
+ "UPDATE interaction_memories SET status = 'interrupted', lease_until = 0
342
+ WHERE chat_id = ?1 AND status IN ('queued', 'running') AND lease_until < unixepoch()",
343
+ params![normalized_chat_id(chat_id)],
344
+ )?;
345
+ Ok(())
346
+ }
347
+
348
+ pub fn finish_turn(
349
+ &self,
350
+ id: i64,
351
+ ai_text: &str,
352
+ provider: &str,
353
+ model: &str,
354
+ fallback_provider: Option<&str>,
355
+ ) -> Result<(), MemoryError> {
356
+ let connection = self.connection()?;
357
+ let changed = connection.execute(
358
+ "UPDATE interaction_memories SET ai_text = ?2, provider = ?3, model = ?4,
359
+ fallback_provider = ?5, status = 'completed', lease_until = 0
360
+ WHERE id = ?1 AND status = 'running'",
361
+ params![id, ai_text, provider, model, fallback_provider],
362
+ )?;
363
+ if changed != 1 {
364
+ return Err(MemoryError::Database(rusqlite::Error::QueryReturnedNoRows));
365
+ }
366
+ Ok(())
367
+ }
368
+
369
+ pub fn end_turn(&self, id: i64, status: &str) -> Result<(), MemoryError> {
370
+ if !matches!(status, "failed" | "interrupted") {
371
+ return Ok(());
372
+ }
373
+ self.connection()?.execute(
374
+ "UPDATE interaction_memories SET status = ?2, lease_until = 0
375
+ WHERE id = ?1 AND status IN ('queued', 'running')",
376
+ params![id, status],
377
+ )?;
378
+ Ok(())
379
+ }
380
+
381
+ pub fn conversation_changes(
382
+ &self,
383
+ chat_id: &str,
384
+ after: i64,
385
+ limit: usize,
386
+ ) -> Result<ConversationChanges, MemoryError> {
387
+ let chat_id = normalized_chat_id(chat_id);
388
+ self.expire_abandoned_turns(&chat_id)?;
389
+ let connection = self.connection()?;
390
+ let mut statement = connection.prepare(
391
+ "SELECT c.sequence, c.interaction_id,
392
+ m.id, m.chat_id, m.user_text, m.ai_text, m.provider, m.model,
393
+ m.fallback_provider, m.created_at, m.agent_activity_json, m.status
394
+ FROM conversation_changes c
395
+ LEFT JOIN interaction_memories m ON m.id = c.interaction_id AND m.chat_id = c.chat_id
396
+ WHERE c.chat_id = ?1 AND c.sequence > ?2 ORDER BY c.sequence LIMIT ?3",
397
+ )?;
398
+ let rows = statement.query_map(
399
+ params![chat_id, after, limit.clamp(1, 200) as i64 + 1],
400
+ |row| {
401
+ let sequence: i64 = row.get(0)?;
402
+ let interaction_id: i64 = row.get(1)?;
403
+ let interaction = if row.get::<_, Option<i64>>(2)?.is_some() {
404
+ let agent_activity = row
405
+ .get::<_, Option<String>>(10)?
406
+ .and_then(|raw| serde_json::from_str(&raw).ok());
407
+ let created: String = row.get(9)?;
408
+ Some(InteractionMemory {
409
+ id: row.get(2)?,
410
+ chat_id: row.get(3)?,
411
+ user_text: row.get(4)?,
412
+ ai_text: row.get(5)?,
413
+ provider: row.get(6)?,
414
+ model: row.get(7)?,
415
+ fallback_provider: row.get(8)?,
416
+ created_at: normalize_sqlite_utc_timestamp(&created),
417
+ agent_activity,
418
+ status: row.get(11)?,
419
+ })
420
+ } else {
421
+ None
422
+ };
423
+ Ok(ConversationChange {
424
+ sequence,
425
+ interaction_id,
426
+ interaction,
427
+ })
428
+ },
429
+ )?;
430
+ let mut changes = rows.collect::<Result<Vec<_>, _>>()?;
431
+ let has_more = changes.len() > limit.clamp(1, 200);
432
+ if has_more {
433
+ changes.pop();
434
+ }
435
+ let cursor = changes.last().map_or(after, |change| change.sequence);
436
+ Ok(ConversationChanges {
437
+ changes,
438
+ cursor,
439
+ has_more,
440
+ })
441
+ }
442
+
443
+ pub fn latest_conversation_sequence(&self, chat_id: &str) -> Result<i64, MemoryError> {
444
+ self.expire_abandoned_turns(chat_id)?;
445
+ let connection = self.connection()?;
446
+ Ok(connection.query_row(
447
+ "SELECT coalesce(max(sequence), 0) FROM conversation_changes WHERE chat_id = ?1",
448
+ params![normalized_chat_id(chat_id)],
449
+ |row| row.get(0),
450
+ )?)
451
+ }
452
+
453
+ pub fn conversation_snapshot(
454
+ &self,
455
+ chat_id: &str,
456
+ before_id: Option<i64>,
457
+ limit: usize,
458
+ ) -> Result<ConversationSnapshot, MemoryError> {
459
+ let chat_id = normalized_chat_id(chat_id);
460
+ self.expire_abandoned_turns(&chat_id)?;
461
+ let mut connection = self.connection()?;
462
+ let tx = connection.transaction()?;
463
+ let cursor: i64 = tx.query_row(
464
+ "SELECT coalesce(max(sequence), 0) FROM conversation_changes WHERE chat_id = ?1",
465
+ params![chat_id],
466
+ |row| row.get(0),
467
+ )?;
468
+ let mut statement = tx.prepare(
469
+ "SELECT id, chat_id, user_text, ai_text, provider, model, fallback_provider,
470
+ created_at, agent_activity_json, status FROM interaction_memories
471
+ WHERE chat_id = ?1 AND (?2 IS NULL OR id < ?2)
472
+ ORDER BY id DESC LIMIT ?3",
473
+ )?;
474
+ let page_size = limit.clamp(1, 200);
475
+ let rows = statement.query_map(
476
+ params![chat_id, before_id, page_size as i64 + 1],
477
+ interaction_row,
478
+ )?;
479
+ let mut interactions = rows.collect::<Result<Vec<_>, _>>()?;
480
+ let has_older = interactions.len() > page_size;
481
+ if has_older {
482
+ interactions.pop();
483
+ }
484
+ interactions.reverse();
485
+ drop(statement);
486
+ tx.commit()?;
487
+ Ok(ConversationSnapshot {
488
+ interactions,
489
+ cursor,
490
+ has_older,
491
+ })
492
+ }
493
+
223
494
  pub fn recent_interactions(&self, limit: usize) -> Result<Vec<InteractionMemory>, MemoryError> {
224
495
  self.recent_interactions_for_chat(DEFAULT_CONVERSATION_ID, limit)
225
496
  }
@@ -233,7 +504,7 @@ impl MemoryStore {
233
504
  let connection = self.connection()?;
234
505
  ensure_builtin_chat_sessions(&connection)?;
235
506
  let mut statement = connection.prepare(
236
- "SELECT id, chat_id, user_text, ai_text, provider, model, fallback_provider, created_at, agent_activity_json
507
+ "SELECT id, chat_id, user_text, ai_text, provider, model, fallback_provider, created_at, agent_activity_json, status
237
508
  FROM interaction_memories
238
509
  WHERE chat_id = ?1
239
510
  ORDER BY id DESC
@@ -243,6 +514,45 @@ impl MemoryStore {
243
514
  rows.collect::<Result<Vec<_>, _>>().map_err(Into::into)
244
515
  }
245
516
 
517
+ pub fn recent_completed_interactions_for_chat(
518
+ &self,
519
+ chat_id: &str,
520
+ limit: usize,
521
+ ) -> Result<Vec<InteractionMemory>, MemoryError> {
522
+ let connection = self.connection()?;
523
+ let mut statement = connection.prepare(
524
+ "SELECT id, chat_id, user_text, ai_text, provider, model, fallback_provider,
525
+ created_at, agent_activity_json, status FROM interaction_memories
526
+ WHERE chat_id = ?1 AND status = 'completed' ORDER BY id DESC LIMIT ?2",
527
+ )?;
528
+ let rows = statement.query_map(
529
+ params![normalized_chat_id(chat_id), limit as i64],
530
+ interaction_row,
531
+ )?;
532
+ rows.collect::<Result<Vec<_>, _>>().map_err(Into::into)
533
+ }
534
+
535
+ /// Returns the complete transcript for one conversation in display order.
536
+ /// This deliberately has no caller supplied `LIMIT`: passing `usize::MAX`
537
+ /// through SQLite's signed limit is not portable and can wrap on 64-bit
538
+ /// platforms.
539
+ pub fn interactions_for_chat(
540
+ &self,
541
+ chat_id: &str,
542
+ ) -> Result<Vec<InteractionMemory>, MemoryError> {
543
+ let chat_id = normalized_chat_id(chat_id);
544
+ let connection = self.connection()?;
545
+ ensure_builtin_chat_sessions(&connection)?;
546
+ let mut statement = connection.prepare(
547
+ "SELECT id, chat_id, user_text, ai_text, provider, model, fallback_provider, created_at, agent_activity_json, status
548
+ FROM interaction_memories
549
+ WHERE chat_id = ?1
550
+ ORDER BY id ASC",
551
+ )?;
552
+ let rows = statement.query_map(params![chat_id], interaction_row)?;
553
+ rows.collect::<Result<Vec<_>, _>>().map_err(Into::into)
554
+ }
555
+
246
556
  /// Full-text search over `chat_id`'s past interactions for the turns most
247
557
  /// relevant to `query` (BM25 ranked), skipping the `exclude_recent` newest
248
558
  /// rows since those are already injected verbatim elsewhere. Returns
@@ -262,11 +572,12 @@ impl MemoryStore {
262
572
  let connection = self.connection()?;
263
573
  let mut statement = connection.prepare(
264
574
  "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
575
+ m.fallback_provider, m.created_at, m.agent_activity_json, m.status
266
576
  FROM interaction_fts
267
577
  JOIN interaction_memories m ON m.id = interaction_fts.rowid
268
578
  WHERE interaction_fts MATCH ?1
269
579
  AND m.chat_id = ?2
580
+ AND m.status = 'completed'
270
581
  AND m.id NOT IN (
271
582
  SELECT id FROM interaction_memories
272
583
  WHERE chat_id = ?2 ORDER BY id DESC LIMIT ?3
@@ -286,31 +597,122 @@ impl MemoryStore {
286
597
  ensure_builtin_chat_sessions(&connection)?;
287
598
  let _ = connection.execute(
288
599
  "DELETE FROM chat_sessions
289
- WHERE kind = 'conversation'
290
- AND id != ?1
600
+ WHERE id != ?1
601
+ AND id != ?2
602
+ AND kind = 'conversation'
291
603
  AND id NOT LIKE 'cron::%'
292
604
  AND (SELECT COUNT(*) FROM interaction_memories WHERE interaction_memories.chat_id = chat_sessions.id) = 0",
293
- params![DEFAULT_CONVERSATION_ID],
605
+ params![DEFAULT_CONVERSATION_ID, CHAT_CLI_ID],
294
606
  );
295
607
  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",
608
+ "SELECT s.id, s.title, s.kind, s.created_at, s.updated_at,
609
+ s.workspace_path, s.git_branch, s.main_language,
610
+ COUNT(m.id) AS msg_count,
611
+ COALESCE(SUM(LENGTH(m.user_text) + LENGTH(m.ai_text)), 0) AS total_bytes
612
+ FROM chat_sessions s
613
+ LEFT JOIN interaction_memories m ON m.chat_id = s.id
614
+ GROUP BY s.id
615
+ ORDER BY CASE WHEN s.id = ?1 THEN 0 ELSE 1 END, s.updated_at DESC",
299
616
  )?;
300
617
  let rows = statement.query_map(params![CHAT_CLI_ID], |row| {
301
618
  let created_raw: String = row.get(3)?;
302
619
  let updated_raw: String = row.get(4)?;
620
+ let msg_count: i64 = row.get(8)?;
621
+ let bytes: i64 = row.get(9)?;
303
622
  Ok(ChatSession {
304
623
  id: row.get(0)?,
305
624
  title: row.get(1)?,
306
625
  kind: row.get(2)?,
307
626
  created_at: normalize_sqlite_utc_timestamp(&created_raw),
308
627
  updated_at: normalize_sqlite_utc_timestamp(&updated_raw),
628
+ workspace_path: row.get(5)?,
629
+ git_branch: row.get(6)?,
630
+ main_language: row.get(7)?,
631
+ message_count: msg_count.max(0) as usize,
632
+ total_bytes: bytes.max(0) as usize,
309
633
  })
310
634
  })?;
311
635
  rows.collect::<Result<Vec<_>, _>>().map_err(Into::into)
312
636
  }
313
637
 
638
+ pub fn update_chat_session_metadata(
639
+ &self,
640
+ chat_id: &str,
641
+ workspace_path: Option<&str>,
642
+ git_branch: Option<&str>,
643
+ main_language: Option<&str>,
644
+ ) -> Result<(), MemoryError> {
645
+ let chat_id = normalized_chat_id(chat_id);
646
+ let connection = self.connection()?;
647
+ ensure_builtin_chat_sessions(&connection)?;
648
+ ensure_chat_session_row(&connection, &chat_id)?;
649
+ connection.execute(
650
+ "UPDATE chat_sessions
651
+ SET workspace_path = COALESCE(?2, workspace_path),
652
+ git_branch = COALESCE(?3, git_branch),
653
+ main_language = COALESCE(?4, main_language),
654
+ updated_at = CURRENT_TIMESTAMP
655
+ WHERE id = ?1",
656
+ params![chat_id, workspace_path, git_branch, main_language],
657
+ )?;
658
+ Ok(())
659
+ }
660
+
661
+ pub fn set_chat_session_workspace(
662
+ &self,
663
+ chat_id: &str,
664
+ workspace_path: Option<&str>,
665
+ ) -> Result<(), MemoryError> {
666
+ let chat_id = normalized_chat_id(chat_id);
667
+ let connection = self.connection()?;
668
+ ensure_builtin_chat_sessions(&connection)?;
669
+ ensure_chat_session_row(&connection, &chat_id)?;
670
+ connection.execute(
671
+ "UPDATE chat_sessions
672
+ SET workspace_path = ?2,
673
+ updated_at = CURRENT_TIMESTAMP
674
+ WHERE id = ?1",
675
+ params![chat_id, workspace_path],
676
+ )?;
677
+ Ok(())
678
+ }
679
+
680
+ pub fn create_cli_session(
681
+ &self,
682
+ workspace_path: Option<&str>,
683
+ git_branch: Option<&str>,
684
+ main_language: Option<&str>,
685
+ ) -> Result<String, MemoryError> {
686
+ let session_id = generate_cli_session_id();
687
+ self.register_cli_session(&session_id, workspace_path, git_branch, main_language)?;
688
+ Ok(session_id)
689
+ }
690
+
691
+ pub fn register_cli_session(
692
+ &self,
693
+ session_id: &str,
694
+ workspace_path: Option<&str>,
695
+ git_branch: Option<&str>,
696
+ main_language: Option<&str>,
697
+ ) -> Result<(), MemoryError> {
698
+ let connection = self.connection()?;
699
+ ensure_builtin_chat_sessions(&connection)?;
700
+ connection.execute(
701
+ "INSERT OR IGNORE INTO chat_sessions (id, title, kind, workspace_path, git_branch, main_language)
702
+ VALUES (?1, 'New chat', 'cli', ?2, ?3, ?4)",
703
+ params![session_id, workspace_path, git_branch, main_language],
704
+ )?;
705
+ Ok(())
706
+ }
707
+
708
+ pub fn get_session_preview(
709
+ &self,
710
+ chat_id: &str,
711
+ limit: usize,
712
+ ) -> Result<Vec<InteractionMemory>, MemoryError> {
713
+ self.recent_interactions_for_chat(chat_id, limit)
714
+ }
715
+
314
716
  /// Registers a chat session with an explicit title/kind up front instead
315
717
  /// of the "New chat" placeholder — used to give a scheduled task's
316
718
  /// conversation its task name immediately (visible in the sidebar even
@@ -353,6 +755,14 @@ impl MemoryStore {
353
755
  pub fn clear_interactions_for_chat(&self, chat_id: &str) -> Result<usize, MemoryError> {
354
756
  let chat_id = normalized_chat_id(chat_id);
355
757
  let connection = self.connection()?;
758
+ connection.execute(
759
+ "DELETE FROM library_references WHERE chat_id = ?1",
760
+ params![chat_id],
761
+ )?;
762
+ connection.execute(
763
+ "DELETE FROM session_skill_reads WHERE chat_id = ?1",
764
+ params![chat_id],
765
+ )?;
356
766
  Ok(connection.execute(
357
767
  "DELETE FROM interaction_memories WHERE chat_id = ?1",
358
768
  params![chat_id],
@@ -361,11 +771,19 @@ impl MemoryStore {
361
771
 
362
772
  pub fn delete_chat_session(&self, chat_id: &str) -> Result<usize, MemoryError> {
363
773
  let chat_id = normalized_chat_id(chat_id);
364
- if is_cli_chat_id(&chat_id) {
774
+ if chat_id == CHAT_CLI_ID {
365
775
  return Ok(0);
366
776
  }
367
777
  let connection = self.connection()?;
368
778
  let transaction = connection.unchecked_transaction()?;
779
+ transaction.execute(
780
+ "DELETE FROM library_references WHERE chat_id = ?1",
781
+ params![chat_id],
782
+ )?;
783
+ transaction.execute(
784
+ "DELETE FROM session_skill_reads WHERE chat_id = ?1",
785
+ params![chat_id],
786
+ )?;
369
787
  transaction.execute(
370
788
  "DELETE FROM interaction_memories WHERE chat_id = ?1",
371
789
  params![chat_id],
@@ -497,6 +915,14 @@ impl MemoryStore {
497
915
  )?)
498
916
  }
499
917
 
918
+ /// Source lookup for edit policy without loading every skill's full body.
919
+ pub(crate) fn learned_skill_sources(&self) -> Result<Vec<String>, MemoryError> {
920
+ let connection = self.connection()?;
921
+ let mut statement = connection.prepare("SELECT source_path FROM learned_skills")?;
922
+ let rows = statement.query_map([], |row| row.get(0))?;
923
+ Ok(rows.collect::<Result<Vec<_>, _>>()?)
924
+ }
925
+
500
926
  pub fn learned_skills(&self, limit: usize) -> Result<Vec<LearnedSkill>, MemoryError> {
501
927
  let connection = self.connection()?;
502
928
  let mut statement = connection.prepare(
@@ -507,6 +933,37 @@ impl MemoryStore {
507
933
  rows.collect::<Result<Vec<_>, _>>().map_err(Into::into)
508
934
  }
509
935
 
936
+ /// A receipt contains the exact bytes returned by a successful full skill read.
937
+ /// It is not a claim that the model still has those bytes in its context.
938
+ pub fn record_skill_read(
939
+ &self,
940
+ chat_id: &str,
941
+ path: &str,
942
+ content: &str,
943
+ ) -> Result<(), MemoryError> {
944
+ self.connection()?.execute(
945
+ "INSERT INTO session_skill_reads (chat_id, path, content) VALUES (?1, ?2, ?3)
946
+ ON CONFLICT(chat_id, path) DO UPDATE SET content = excluded.content",
947
+ params![normalized_chat_id(chat_id), path, content],
948
+ )?;
949
+ Ok(())
950
+ }
951
+
952
+ pub fn skill_read_content(
953
+ &self,
954
+ chat_id: &str,
955
+ path: &str,
956
+ ) -> Result<Option<String>, MemoryError> {
957
+ Ok(self
958
+ .connection()?
959
+ .query_row(
960
+ "SELECT content FROM session_skill_reads WHERE chat_id = ?1 AND path = ?2",
961
+ params![normalized_chat_id(chat_id), path],
962
+ |row| row.get(0),
963
+ )
964
+ .optional()?)
965
+ }
966
+
510
967
  pub fn delete_learned_skill(&self, identifier: &str) -> Result<usize, MemoryError> {
511
968
  let connection = self.connection()?;
512
969
  Ok(connection.execute(
@@ -718,7 +1175,11 @@ impl MemoryStore {
718
1175
  )?)
719
1176
  }
720
1177
 
721
- fn connection(&self) -> Result<Connection, MemoryError> {
1178
+ pub(crate) fn path(&self) -> &std::path::Path {
1179
+ &self.path
1180
+ }
1181
+
1182
+ pub(crate) fn connection(&self) -> Result<Connection, MemoryError> {
722
1183
  if let Some(directory) = self.path.parent() {
723
1184
  std::fs::create_dir_all(directory).map_err(|source| MemoryError::CreateDirectory {
724
1185
  path: directory.to_path_buf(),
@@ -738,24 +1199,22 @@ impl MemoryStore {
738
1199
  std::sync::Mutex<std::collections::HashSet<PathBuf>>,
739
1200
  > = std::sync::LazyLock::new(|| std::sync::Mutex::new(std::collections::HashSet::new()));
740
1201
 
741
- let needs_init = {
742
- let mut set = INITIALIZED_DATABASES.lock().unwrap();
743
- set.insert(self.path.clone())
744
- };
745
-
746
- if needs_init {
1202
+ // Publish readiness only after initialization succeeds. Companion and API
1203
+ // reads may open the same database concurrently during startup.
1204
+ let mut initialized = INITIALIZED_DATABASES
1205
+ .lock()
1206
+ .unwrap_or_else(|e| e.into_inner());
1207
+ if !initialized.contains(&self.path) {
747
1208
  initialize(
748
1209
  &connection,
749
1210
  memory_path().is_ok_and(|default_path| default_path == self.path),
750
1211
  )?;
751
- // This database holds OAuth tokens (see `oauth::save_oauth_tokens`,
752
- // stored in `user_profile`) alongside chat history — restrict it
753
- // to owner-only rather than leaving it at default (typically
754
- // world-readable) permissions. `needs_init` already gates this to
755
- // once per path per process, and any pre-existing database from
756
- // before this fix gets tightened the same way on its first open.
1212
+ // OAuth tokens live beside chat history; restrict the file once per
1213
+ // path per process, including databases created by older versions.
757
1214
  restrict_to_owner(&self.path);
1215
+ initialized.insert(self.path.clone());
758
1216
  }
1217
+ drop(initialized);
759
1218
  Ok(connection)
760
1219
  }
761
1220
  }
@@ -910,13 +1369,33 @@ fn initialize(
910
1369
  keywords TEXT DEFAULT '',
911
1370
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
912
1371
  );
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
1372
+ CREATE TABLE IF NOT EXISTS conversation_changes (
1373
+ sequence INTEGER PRIMARY KEY AUTOINCREMENT,
1374
+ chat_id TEXT NOT NULL,
1375
+ interaction_id INTEGER NOT NULL
919
1376
  );
1377
+ CREATE TABLE IF NOT EXISTS conversation_source_attachments (
1378
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
1379
+ interaction_id INTEGER NOT NULL,
1380
+ metadata TEXT NOT NULL,
1381
+ UNIQUE(interaction_id, metadata)
1382
+ );
1383
+ CREATE TRIGGER IF NOT EXISTS trg_interaction_sources_delete
1384
+ AFTER DELETE ON interaction_memories BEGIN
1385
+ DELETE FROM conversation_source_attachments WHERE interaction_id = OLD.id;
1386
+ END;
1387
+ CREATE INDEX IF NOT EXISTS idx_conversation_changes_chat_sequence
1388
+ ON conversation_changes(chat_id, sequence);
1389
+ CREATE TABLE IF NOT EXISTS chat_sessions (
1390
+ id TEXT PRIMARY KEY,
1391
+ title TEXT NOT NULL DEFAULT 'New chat',
1392
+ kind TEXT NOT NULL DEFAULT 'conversation',
1393
+ workspace_path TEXT DEFAULT NULL,
1394
+ git_branch TEXT DEFAULT NULL,
1395
+ main_language TEXT DEFAULT NULL,
1396
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
1397
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
1398
+ );
920
1399
  CREATE TABLE IF NOT EXISTS learned_skills (
921
1400
  id INTEGER PRIMARY KEY AUTOINCREMENT,
922
1401
  name TEXT NOT NULL,
@@ -925,6 +1404,12 @@ fn initialize(
925
1404
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
926
1405
  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
927
1406
  );
1407
+ CREATE TABLE IF NOT EXISTS session_skill_reads (
1408
+ chat_id TEXT NOT NULL,
1409
+ path TEXT NOT NULL,
1410
+ content TEXT NOT NULL,
1411
+ PRIMARY KEY(chat_id, path)
1412
+ );
928
1413
  CREATE TABLE IF NOT EXISTS workspace_sessions (
929
1414
  workspace_path TEXT PRIMARY KEY,
930
1415
  summary TEXT NOT NULL,
@@ -970,13 +1455,14 @@ fn initialize(
970
1455
  VALUES ('delete', old.id, old.user_text, old.ai_text);
971
1456
  END;
972
1457
  CREATE TRIGGER IF NOT EXISTS trg_interaction_fts_au
973
- AFTER UPDATE ON interaction_memories BEGIN
1458
+ AFTER UPDATE OF user_text, ai_text ON interaction_memories BEGIN
974
1459
  INSERT INTO interaction_fts(interaction_fts, rowid, user_text, ai_text)
975
1460
  VALUES ('delete', old.id, old.user_text, old.ai_text);
976
1461
  INSERT INTO interaction_fts(rowid, user_text, ai_text)
977
1462
  VALUES (new.id, new.user_text, new.ai_text);
978
1463
  END;",
979
1464
  )?;
1465
+ crate::library::initialize(connection)?;
980
1466
  ensure_column(
981
1467
  connection,
982
1468
  "interaction_memories",
@@ -1007,12 +1493,66 @@ fn initialize(
1007
1493
  "agent_activity_json",
1008
1494
  "TEXT DEFAULT NULL",
1009
1495
  )?;
1496
+ ensure_column(
1497
+ connection,
1498
+ "interaction_memories",
1499
+ "status",
1500
+ "TEXT NOT NULL DEFAULT 'completed'",
1501
+ )?;
1502
+ ensure_column(
1503
+ connection,
1504
+ "interaction_memories",
1505
+ "lease_until",
1506
+ "INTEGER NOT NULL DEFAULT 0",
1507
+ )?;
1508
+ connection.execute_batch(
1509
+ "DROP TRIGGER IF EXISTS trg_interaction_fts_au;
1510
+ CREATE TRIGGER trg_interaction_fts_au
1511
+ AFTER UPDATE OF user_text, ai_text ON interaction_memories BEGIN
1512
+ INSERT INTO interaction_fts(interaction_fts, rowid, user_text, ai_text)
1513
+ VALUES ('delete', old.id, old.user_text, old.ai_text);
1514
+ INSERT INTO interaction_fts(rowid, user_text, ai_text)
1515
+ VALUES (new.id, new.user_text, new.ai_text);
1516
+ END;
1517
+ DROP TRIGGER IF EXISTS trg_conversation_change_update;
1518
+ CREATE TRIGGER IF NOT EXISTS trg_conversation_change_insert
1519
+ AFTER INSERT ON interaction_memories BEGIN
1520
+ INSERT INTO conversation_changes(chat_id, interaction_id) VALUES (new.chat_id, new.id);
1521
+ END;
1522
+ CREATE TRIGGER trg_conversation_change_update
1523
+ AFTER UPDATE OF user_text, ai_text, provider, model, fallback_provider,
1524
+ status, agent_activity_json, chat_id ON interaction_memories BEGIN
1525
+ INSERT INTO conversation_changes(chat_id, interaction_id) VALUES (new.chat_id, new.id);
1526
+ END;
1527
+ CREATE TRIGGER IF NOT EXISTS trg_conversation_change_delete
1528
+ AFTER DELETE ON interaction_memories BEGIN
1529
+ INSERT INTO conversation_changes(chat_id, interaction_id) VALUES (old.chat_id, old.id);
1530
+ END;",
1531
+ )?;
1010
1532
  ensure_column(
1011
1533
  connection,
1012
1534
  "chat_sessions",
1013
1535
  "kind",
1014
1536
  "TEXT NOT NULL DEFAULT 'conversation'",
1015
1537
  )?;
1538
+ ensure_column(
1539
+ connection,
1540
+ "chat_sessions",
1541
+ "workspace_path",
1542
+ "TEXT DEFAULT NULL",
1543
+ )?;
1544
+ ensure_column(
1545
+ connection,
1546
+ "chat_sessions",
1547
+ "git_branch",
1548
+ "TEXT DEFAULT NULL",
1549
+ )?;
1550
+ ensure_column(
1551
+ connection,
1552
+ "chat_sessions",
1553
+ "main_language",
1554
+ "TEXT DEFAULT NULL",
1555
+ )?;
1016
1556
  // `agent_id` scopes a fact to the subagent that produced it (NULL = shared /
1017
1557
  // user-authored); `embedding` is the on-device similarity vector used for
1018
1558
  // relevance-ranked recall. Both are additive for databases created before
@@ -1233,6 +1773,7 @@ fn interaction_row(row: &rusqlite::Row<'_>) -> Result<InteractionMemory, rusqlit
1233
1773
  model: row.get(5)?,
1234
1774
  fallback_provider: row.get(6)?,
1235
1775
  created_at: normalize_sqlite_utc_timestamp(&raw_created),
1776
+ status: row.get(9)?,
1236
1777
  agent_activity,
1237
1778
  })
1238
1779
  }
@@ -1267,8 +1808,10 @@ fn ensure_builtin_chat_sessions(connection: &Connection) -> Result<(), rusqlite:
1267
1808
  }
1268
1809
 
1269
1810
  fn ensure_chat_session_row(connection: &Connection, chat_id: &str) -> Result<(), rusqlite::Error> {
1270
- let (title, kind) = if is_cli_chat_id(chat_id) {
1811
+ let (title, kind) = if chat_id == CHAT_CLI_ID {
1271
1812
  ("Chat CLI", "cli")
1813
+ } else if is_cli_chat_id(chat_id) {
1814
+ ("New chat", "cli")
1272
1815
  } else {
1273
1816
  ("New chat", "conversation")
1274
1817
  };
@@ -1280,6 +1823,235 @@ fn ensure_chat_session_row(connection: &Connection, chat_id: &str) -> Result<(),
1280
1823
  Ok(())
1281
1824
  }
1282
1825
 
1826
+ #[cfg(test)]
1827
+ mod conversation_sync_tests {
1828
+ #[test]
1829
+ fn concurrent_first_reads_wait_for_database_schema_initialization() {
1830
+ use std::sync::{Arc, Barrier};
1831
+ for _ in 0..3 {
1832
+ let root =
1833
+ std::env::temp_dir().join(format!("mint-schema-ordering-{}", uuid::Uuid::new_v4()));
1834
+ let store = super::MemoryStore::open(root.join("memory.sqlite"));
1835
+ let barrier = Arc::new(Barrier::new(16));
1836
+ let results = std::thread::scope(|scope| {
1837
+ let handles: Vec<_> = (0..16)
1838
+ .map(|_| {
1839
+ let barrier = Arc::clone(&barrier);
1840
+ let store = store.clone();
1841
+ scope.spawn(move || {
1842
+ barrier.wait();
1843
+ store.learned_skills(100)
1844
+ })
1845
+ })
1846
+ .collect();
1847
+ handles
1848
+ .into_iter()
1849
+ .map(|handle| handle.join().unwrap())
1850
+ .collect::<Vec<_>>()
1851
+ });
1852
+ let _ = std::fs::remove_dir_all(root);
1853
+ for result in results {
1854
+ assert!(result.is_ok(), "concurrent inventory read: {result:?}");
1855
+ }
1856
+ }
1857
+ }
1858
+
1859
+ use super::*;
1860
+
1861
+ fn store() -> MemoryStore {
1862
+ MemoryStore::open(std::env::temp_dir().join(format!(
1863
+ "mint-conversation-sync-{}.sqlite",
1864
+ uuid::Uuid::new_v4()
1865
+ )))
1866
+ }
1867
+
1868
+ #[test]
1869
+ fn listing_sessions_removes_empty_project_chat_placeholders() {
1870
+ let memory = store();
1871
+ memory
1872
+ .set_chat_session_workspace("conversation-empty", Some("/projects/demo"))
1873
+ .unwrap();
1874
+ memory
1875
+ .start_turn("conversation-used", "first message")
1876
+ .unwrap();
1877
+
1878
+ let sessions = memory.list_chat_sessions().unwrap();
1879
+
1880
+ assert!(
1881
+ !sessions
1882
+ .iter()
1883
+ .any(|session| session.id == "conversation-empty")
1884
+ );
1885
+ assert!(
1886
+ sessions
1887
+ .iter()
1888
+ .any(|session| session.id == "conversation-used")
1889
+ );
1890
+ }
1891
+
1892
+ #[test]
1893
+ fn prompt_and_reply_use_one_id_and_emit_changes() {
1894
+ let memory = store();
1895
+ let first = memory.start_turn("cli::one", "hello").unwrap();
1896
+ let other_process = MemoryStore::open(memory.path.clone());
1897
+ let second = other_process.start_turn("cli::one", "next").unwrap();
1898
+ let other = memory.start_turn("cli::two", "separate").unwrap();
1899
+ assert!(memory.claim_turn("cli::one", first).unwrap());
1900
+ assert!(!other_process.claim_turn("cli::one", second).unwrap());
1901
+ assert!(memory.claim_turn("cli::two", other).unwrap());
1902
+ assert_eq!(
1903
+ memory
1904
+ .recent_completed_interactions_for_chat("cli::one", 3)
1905
+ .unwrap()
1906
+ .len(),
1907
+ 0
1908
+ );
1909
+
1910
+ memory
1911
+ .finish_turn(first, "world", "test", "model", None)
1912
+ .unwrap();
1913
+ assert!(other_process.claim_turn("cli::one", second).unwrap());
1914
+ memory
1915
+ .finish_turn(second, "done", "test", "model", None)
1916
+ .unwrap();
1917
+
1918
+ let rows = memory.interactions_for_chat("cli::one").unwrap();
1919
+ assert_eq!(rows.len(), 2);
1920
+ assert_eq!(rows[0].id, first);
1921
+ assert_eq!(rows[0].ai_text, "world");
1922
+ assert_eq!(rows[1].status, "completed");
1923
+ let changes = memory.conversation_changes("cli::one", 0, 100).unwrap();
1924
+ assert!(changes.changes.iter().any(|c| {
1925
+ c.interaction_id == first
1926
+ && c.interaction
1927
+ .as_ref()
1928
+ .is_some_and(|row| row.ai_text == "world")
1929
+ }));
1930
+ assert!(changes.changes.iter().all(|c| c.interaction_id != other));
1931
+ assert!(
1932
+ memory
1933
+ .conversation_changes("cli::one", changes.cursor, 100)
1934
+ .unwrap()
1935
+ .changes
1936
+ .is_empty()
1937
+ );
1938
+ }
1939
+
1940
+ #[test]
1941
+ fn interrupted_turn_unblocks_queue_and_snapshot_pages() {
1942
+ let memory = store();
1943
+ let first = memory.start_turn("cli::one", "first").unwrap();
1944
+ let second = memory.start_turn("cli::one", "second").unwrap();
1945
+ assert!(memory.claim_turn("cli::one", first).unwrap());
1946
+ memory.end_turn(first, "interrupted").unwrap();
1947
+ assert!(memory.claim_turn("cli::one", second).unwrap());
1948
+ let page = memory.conversation_snapshot("cli::one", None, 1).unwrap();
1949
+ assert_eq!(page.interactions[0].id, second);
1950
+ assert!(page.has_older);
1951
+ let older = memory
1952
+ .conversation_snapshot("cli::one", Some(second), 1)
1953
+ .unwrap();
1954
+ assert_eq!(older.interactions[0].status, "interrupted");
1955
+ assert!(!older.has_older);
1956
+ }
1957
+
1958
+ #[test]
1959
+ fn abandoned_turn_is_reported_after_lease_expires() {
1960
+ let memory = store();
1961
+ let id = memory.start_turn("cli::one", "unfinished").unwrap();
1962
+ assert!(memory.claim_turn("cli::one", id).unwrap());
1963
+ memory
1964
+ .connection()
1965
+ .unwrap()
1966
+ .execute(
1967
+ "UPDATE interaction_memories SET lease_until = 0 WHERE id = ?1",
1968
+ params![id],
1969
+ )
1970
+ .unwrap();
1971
+ let changes = memory.conversation_changes("cli::one", 0, 100).unwrap();
1972
+ assert_eq!(
1973
+ changes
1974
+ .changes
1975
+ .last()
1976
+ .unwrap()
1977
+ .interaction
1978
+ .as_ref()
1979
+ .unwrap()
1980
+ .status,
1981
+ "interrupted"
1982
+ );
1983
+ assert!(
1984
+ memory
1985
+ .finish_turn(id, "late", "test", "model", None)
1986
+ .is_err()
1987
+ );
1988
+ }
1989
+
1990
+ #[test]
1991
+ fn old_completed_rows_migrate_without_losing_content() {
1992
+ let path = std::env::temp_dir().join(format!(
1993
+ "mint-conversation-legacy-{}.sqlite",
1994
+ uuid::Uuid::new_v4()
1995
+ ));
1996
+ let connection = Connection::open(&path).unwrap();
1997
+ connection
1998
+ .execute_batch(
1999
+ "CREATE TABLE interaction_memories (
2000
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
2001
+ chat_id TEXT NOT NULL DEFAULT 'conversation-default',
2002
+ user_text TEXT NOT NULL, ai_text TEXT NOT NULL,
2003
+ provider TEXT NOT NULL DEFAULT '', model TEXT NOT NULL DEFAULT '',
2004
+ fallback_provider TEXT DEFAULT NULL, keywords TEXT DEFAULT '',
2005
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
2006
+ );
2007
+ INSERT INTO interaction_memories(chat_id, user_text, ai_text)
2008
+ VALUES ('cli::old', 'old prompt', 'old reply');",
2009
+ )
2010
+ .unwrap();
2011
+ drop(connection);
2012
+ let memory = MemoryStore::open(path);
2013
+ let rows = memory.interactions_for_chat("cli::old").unwrap();
2014
+ assert_eq!(rows.len(), 1);
2015
+ assert_eq!(rows[0].status, "completed");
2016
+ assert_eq!(rows[0].ai_text, "old reply");
2017
+ }
2018
+
2019
+ #[test]
2020
+ fn clearing_history_emits_tombstones_for_open_views() {
2021
+ let memory = store();
2022
+ let id = memory
2023
+ .add_interaction_for_chat("cli::one", "hello", "world", "test", "model")
2024
+ .unwrap();
2025
+ let cursor = memory.latest_conversation_sequence("cli::one").unwrap();
2026
+ memory.clear_interactions_for_chat("cli::one").unwrap();
2027
+ let changes = memory
2028
+ .conversation_changes("cli::one", cursor, 100)
2029
+ .unwrap();
2030
+ assert!(
2031
+ changes
2032
+ .changes
2033
+ .iter()
2034
+ .any(|change| change.interaction_id == id && change.interaction.is_none())
2035
+ );
2036
+ }
2037
+
2038
+ #[test]
2039
+ fn heartbeat_does_not_emit_visible_changes() {
2040
+ let memory = store();
2041
+ let id = memory.start_turn("cli::one", "hello").unwrap();
2042
+ assert!(memory.claim_turn("cli::one", id).unwrap());
2043
+ let cursor = memory.latest_conversation_sequence("cli::one").unwrap();
2044
+ memory.renew_turn(id).unwrap();
2045
+ assert!(
2046
+ memory
2047
+ .conversation_changes("cli::one", cursor, 100)
2048
+ .unwrap()
2049
+ .changes
2050
+ .is_empty()
2051
+ );
2052
+ }
2053
+ }
2054
+
1283
2055
  #[cfg(test)]
1284
2056
  mod scoped_chat_id_tests {
1285
2057
  use super::*;