@pheem49/mint 1.15.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (644) hide show
  1. package/Cargo.lock +1012 -69
  2. package/Cargo.toml +5 -2
  3. package/LICENSE +21 -654
  4. package/README.md +92 -817
  5. package/Release_Note.md +53 -560
  6. package/apps/mint-companion/src-tauri/Cargo.toml +20 -0
  7. package/apps/mint-companion/src-tauri/build.rs +3 -0
  8. package/apps/mint-companion/src-tauri/src/main.rs +468 -0
  9. package/apps/mint-companion/tsconfig.json +20 -0
  10. package/apps/mint-companion/vite.config.ts +3 -0
  11. package/components.json +19 -0
  12. package/crates/mint-cli/Cargo.toml +6 -0
  13. package/crates/mint-cli/src/agent/live_status.rs +187 -39
  14. package/crates/mint-cli/src/agent.rs +323 -95
  15. package/crates/mint-cli/src/commands/agent.rs +69 -55
  16. package/crates/mint-cli/src/commands/integrations.rs +7 -0
  17. package/crates/mint-cli/src/commands/knowledge.rs +12 -32
  18. package/crates/mint-cli/src/commands/mod.rs +44 -0
  19. package/crates/mint-cli/src/image.rs +31 -33
  20. package/crates/mint-cli/src/interactive/chat_tui.rs +3594 -483
  21. package/crates/mint-cli/src/interactive/input_box.rs +56 -6
  22. package/crates/mint-cli/src/interactive/slash_commands.rs +208 -56
  23. package/crates/mint-cli/src/interactive/tool_activity.rs +328 -0
  24. package/crates/mint-cli/src/interactive.rs +64 -40
  25. package/crates/mint-cli/src/main.rs +13 -7
  26. package/crates/mint-cli/src/mcp.rs +5 -0
  27. package/crates/mint-cli/src/mod_host.rs +6 -0
  28. package/crates/mint-cli/src/mods_cli.rs +62 -0
  29. package/crates/mint-cli/src/mods_ui.rs +187 -0
  30. package/crates/mint-cli/src/onboard.rs +5 -31
  31. package/crates/mint-cli/src/terminal_theme.rs +3 -1
  32. package/crates/mint-cli/src/updater.rs +56 -2
  33. package/crates/mint-cli/tests/library_intake.rs +77 -0
  34. package/crates/mint-cli/tests/mods_testing.rs +133 -0
  35. package/crates/mint-companion-protocol/Cargo.toml +10 -0
  36. package/crates/mint-companion-protocol/src/lib.rs +163 -0
  37. package/crates/mint-core/Cargo.toml +6 -3
  38. package/crates/mint-core/build.rs +26 -0
  39. package/crates/mint-core/src/agent/chat.rs +167 -39
  40. package/crates/mint-core/src/agent/code_tools.rs +15 -0
  41. package/crates/mint-core/src/agent/memory/sources.rs +240 -0
  42. package/crates/mint-core/src/agent/memory.rs +147 -13
  43. package/crates/mint-core/src/agent/skill_inventory.rs +325 -0
  44. package/crates/mint-core/src/agent/skills.rs +437 -90
  45. package/crates/mint-core/src/agent.rs +1 -0
  46. package/crates/mint-core/src/api_server/routes/background_jobs.rs +310 -0
  47. package/crates/mint-core/src/api_server/routes/chat.rs +216 -199
  48. package/crates/mint-core/src/api_server/routes/html_preview.rs +77 -0
  49. package/crates/mint-core/src/api_server/routes/library.rs +97 -0
  50. package/crates/mint-core/src/api_server/routes/media_gen.rs +10 -57
  51. package/crates/mint-core/src/api_server/routes/misc.rs +104 -107
  52. package/crates/mint-core/src/api_server/routes/mod.rs +6 -0
  53. package/crates/mint-core/src/api_server/routes/mods.rs +31 -0
  54. package/crates/mint-core/src/api_server/routes/sessions.rs +41 -0
  55. package/crates/mint-core/src/api_server/routes/skills_subagents.rs +12 -42
  56. package/crates/mint-core/src/api_server/routes/slash.rs +50 -1
  57. package/crates/mint-core/src/api_server/routes/sources.rs +101 -0
  58. package/crates/mint-core/src/api_server.rs +118 -9
  59. package/crates/mint-core/src/avatar_bridge.rs +11 -2
  60. package/crates/mint-core/src/browser/session.rs +52 -0
  61. package/crates/mint-core/src/companion.rs +716 -0
  62. package/crates/mint-core/src/cron/scheduler.rs +34 -2
  63. package/crates/mint-core/src/integrations/channels.rs +87 -345
  64. package/crates/mint-core/src/integrations/mcp.rs +397 -50
  65. package/crates/mint-core/src/integrations/mcp_calls.rs +823 -0
  66. package/crates/mint-core/src/integrations/mcp_catalog.rs +267 -0
  67. package/crates/mint-core/src/integrations/mcp_device.rs +319 -0
  68. package/crates/mint-core/src/integrations/mcp_result.rs +356 -0
  69. package/crates/mint-core/src/integrations/webhooks.rs +539 -0
  70. package/crates/mint-core/src/integrations.rs +2 -0
  71. package/crates/mint-core/src/lib.rs +85 -26
  72. package/crates/mint-core/src/media/gemini_live.rs +134 -14
  73. package/crates/mint-core/src/media/image_models.rs +3 -27
  74. package/crates/mint-core/src/media/image_workflow.rs +216 -0
  75. package/crates/mint-core/src/media/library/intake.rs +144 -0
  76. package/crates/mint-core/src/media/library/migration.rs +56 -0
  77. package/crates/mint-core/src/media/library/removal.rs +55 -0
  78. package/crates/mint-core/src/media/library/tests.rs +730 -0
  79. package/crates/mint-core/src/media/library/thumbnails.rs +72 -0
  80. package/crates/mint-core/src/media/library.rs +545 -0
  81. package/crates/mint-core/src/media/model_catalog.rs +375 -0
  82. package/crates/mint-core/src/media/pictures.rs +79 -222
  83. package/crates/mint-core/src/media/video_models.rs +3 -22
  84. package/crates/mint-core/src/media.rs +3 -0
  85. package/crates/mint-core/src/mods/manager.rs +1124 -0
  86. package/crates/mint-core/src/mods/mod.rs +569 -0
  87. package/crates/mint-core/src/mods/operations.rs +204 -0
  88. package/crates/mint-core/src/mods/session.rs +146 -0
  89. package/crates/mint-core/src/mods/slash.rs +59 -0
  90. package/crates/mint-core/src/mods/telemetry.rs +306 -0
  91. package/crates/mint-core/src/orchestration/approvals.rs +344 -0
  92. package/crates/mint-core/src/orchestration/context_render.rs +104 -0
  93. package/crates/mint-core/src/orchestration/mcp_review.rs +153 -0
  94. package/crates/mint-core/src/orchestration/memory_skill.rs +104 -32
  95. package/crates/mint-core/src/orchestration/mod.rs +2139 -244
  96. package/crates/mint-core/src/orchestration/mod_authoring_regressions.rs +209 -0
  97. package/crates/mint-core/src/orchestration/progress_clock.rs +80 -0
  98. package/crates/mint-core/src/orchestration/repeated_failures.rs +116 -0
  99. package/crates/mint-core/src/orchestration/review_regressions.rs +449 -0
  100. package/crates/mint-core/src/orchestration/run_control.rs +196 -0
  101. package/crates/mint-core/src/orchestration/tools/files.rs +161 -14
  102. package/crates/mint-core/src/orchestration/tools/media.rs +37 -41
  103. package/crates/mint-core/src/orchestration/tools/misc.rs +3 -2
  104. package/crates/mint-core/src/orchestration/tools/mod.rs +2 -0
  105. package/crates/mint-core/src/orchestration/tools/mods.rs +161 -0
  106. package/crates/mint-core/src/orchestration/tools/plugins_mcp.rs +303 -71
  107. package/crates/mint-core/src/orchestration/tools/shell.rs +95 -2
  108. package/crates/mint-core/src/orchestration/workspace_helpers.rs +4 -1
  109. package/crates/mint-core/src/prompts/agent.rs +17 -2
  110. package/crates/mint-core/src/prompts/tool_catalog.rs +28 -2
  111. package/crates/mint-core/src/search/knowledge.rs +7 -1
  112. package/crates/mint-core/src/search/linked_folders/index.rs +177 -13
  113. package/crates/mint-core/src/search/linked_folders.rs +83 -2
  114. package/crates/mint-core/src/slash/catalog.rs +1 -1
  115. package/crates/mint-core/src/slash/mod.rs +174 -11
  116. package/crates/mint-core/src/slash/mods.rs +155 -0
  117. package/crates/mint-core/src/system/bg_shell.rs +1129 -95
  118. package/crates/mint-core/src/system/config.rs +5 -10
  119. package/crates/mint-core/src/system/html_preview.rs +398 -0
  120. package/crates/mint-core/src/system/mint_web.rs +164 -0
  121. package/crates/mint-core/src/system/release_notes.rs +18 -0
  122. package/crates/mint-core/src/system/shell.rs +21 -6
  123. package/crates/mint-core/src/system/workspace.rs +72 -8
  124. package/crates/mint-core/src/system/workspace_history.rs +604 -0
  125. package/crates/mint-core/src/system.rs +4 -0
  126. package/crates/mint-core/tests/background_retention.rs +34 -0
  127. package/crates/mint-core/tests/background_shutdown.rs +24 -0
  128. package/crates/mint-core/tests/library_http.rs +209 -0
  129. package/crates/mint-core/tests/mcp_contract.rs +283 -0
  130. package/crates/mint-core/tests/mcp_stdio.rs +11 -10
  131. package/crates/mint-core/tests/media_model_catalog_http.rs +403 -0
  132. package/crates/mint-core/tests/mods_http.rs +215 -0
  133. package/crates/mint-core/tests/terminal_shutdown.rs +109 -0
  134. package/crates/mint-mod-runtime/Cargo.toml +18 -0
  135. package/crates/mint-mod-runtime/src/lib.rs +507 -0
  136. package/crates/mint-mod-runtime/src/sdk.js +56 -0
  137. package/crates/mint-mod-runtime/src/test_sdk.js +32 -0
  138. package/crates/mint-mod-runtime/src/testing.rs +94 -0
  139. package/crates/mint-mod-runtime/tests/runtime.rs +156 -0
  140. package/docs/mods/AUTHORING.md +61 -0
  141. package/docs/mods/README.md +139 -0
  142. package/docs/mods/TESTING.md +56 -0
  143. package/docs/mods/mint-mods.d.ts +66 -0
  144. package/examples/device-mcp/README.md +22 -0
  145. package/examples/device-mcp/contract.md +49 -0
  146. package/examples/device-mcp/mock-device.mjs +66 -0
  147. package/examples/device-mcp/server.mjs +48 -0
  148. package/examples/device-mcp/server.test.mjs +78 -0
  149. package/examples/mods/task-checklist/README.md +1 -0
  150. package/examples/mods/task-checklist/main.ts +17 -0
  151. package/examples/mods/task-checklist/manifest.json +1 -0
  152. package/examples/mods/task-checklist/tests/checklist.test.ts +15 -0
  153. package/examples/mods/token-meter/README.md +1 -0
  154. package/examples/mods/token-meter/main.ts +8 -0
  155. package/examples/mods/token-meter/manifest.json +1 -0
  156. package/examples/mods/tool-guard/README.md +1 -0
  157. package/examples/mods/tool-guard/main.ts +9 -0
  158. package/examples/mods/tool-guard/manifest.json +1 -0
  159. package/out/web/assets/CliSessionsView-CtzUJpK_.css +1 -0
  160. package/out/web/assets/CliSessionsView-D7hw0Mgj.js +1 -0
  161. package/out/web/assets/CodeReviewPage-C7bEOJfd.js +4 -0
  162. package/out/web/assets/CodeReviewPage-Dte9uLiL.css +1 -0
  163. package/out/web/assets/CommandPalette-0RrF-AOT.js +1 -0
  164. package/out/web/assets/ImageStudioPanel-CdxkAf_r.js +1 -0
  165. package/out/web/assets/LibraryPage--Qfisp6D.js +2 -0
  166. package/out/web/assets/LibraryPage-DAxUTAg7.css +1 -0
  167. package/out/web/assets/LinkedFoldersView-2nfZbDgN.js +1 -0
  168. package/out/web/assets/McpRegistryPicker-h9uS8_wT.js +1 -0
  169. package/out/web/assets/McpServersView-slfQJzNB.js +1 -0
  170. package/out/web/assets/MintDashboard-BSR5XpXh.js +25 -0
  171. package/out/web/assets/MintDashboard-CWUcCGhd.css +1 -0
  172. package/out/web/assets/PluginsView-l7LSm503.js +1 -0
  173. package/out/web/assets/ScheduledTasksView-CttmLbq1.js +1 -0
  174. package/out/web/assets/SettingsWindow-BCMLYvEV.js +4 -0
  175. package/out/web/assets/SettingsWindow-DcMVmU9u.css +1 -0
  176. package/out/web/assets/SkillsView-rNs1qr_U.js +2 -0
  177. package/out/web/assets/ToolSurfacePage-B9DzEPWN.js +37 -0
  178. package/out/web/assets/ToolSurfacePage-CTfgggF2.css +1 -0
  179. package/out/web/assets/VeoStudioPanel-DiJs_Cg2.js +4 -0
  180. package/out/web/assets/WorkspaceSelector-B2xIp04D.js +1 -0
  181. package/out/web/assets/WorkspaceSelector-Ca8uJOsS.css +1 -0
  182. package/out/web/assets/{abnfDiagram-VCTEODGH-ByMyfanq.js → abnfDiagram-VCTEODGH-CD0CjoGl.js} +1 -1
  183. package/out/web/assets/{architecture-7GRP2DOG-CLq2kEOB.js → architecture-7GRP2DOG-RKV83OeZ.js} +1 -1
  184. package/out/web/assets/{architectureDiagram-5GKGNRK7-6PoVSmNG.js → architectureDiagram-5GKGNRK7-nN_HAFct.js} +1 -1
  185. package/out/web/assets/{blockDiagram-NRAW4CY4-cKw9mAKi.js → blockDiagram-NRAW4CY4-BrrqzHW5.js} +1 -1
  186. package/out/web/assets/{c4Diagram-UCG6FXSJ-Cqy8N5Ge.js → c4Diagram-UCG6FXSJ-DTdV8_zE.js} +1 -1
  187. package/out/web/assets/{chunk-75Z2AOVW-3qybijF5.js → chunk-75Z2AOVW-_M0z5olV.js} +1 -1
  188. package/out/web/assets/chunk-CKBBP62Z-BpQEgeHF.js +2 -0
  189. package/out/web/assets/{chunk-CLGD4ZFX-CndDQkww.js → chunk-CLGD4ZFX-D54yGvGS.js} +1 -1
  190. package/out/web/assets/{chunk-DSNCTWBM-Cc4NxvgD.js → chunk-DSNCTWBM-C-gvT2ru.js} +1 -1
  191. package/out/web/assets/{chunk-DU6HZSFF-drzh6GsU.js → chunk-DU6HZSFF-CnFngIhW.js} +1 -1
  192. package/out/web/assets/{chunk-F27PBJKO-FiY35l4v.js → chunk-F27PBJKO-BqtWrnEO.js} +1 -1
  193. package/out/web/assets/{chunk-G27WJ6UU-Bjt9Il4A.js → chunk-G27WJ6UU-Ckoq5mi2.js} +1 -1
  194. package/out/web/assets/{chunk-GMAD6QVW-Bppi3Ctd.js → chunk-GMAD6QVW-BuhEcgHq.js} +1 -1
  195. package/out/web/assets/{chunk-JQ64N6SF-DGg5kcEV.js → chunk-JQ64N6SF-CF8T7GiZ.js} +1 -1
  196. package/out/web/assets/{chunk-LCL6LL3I-CCYcjd7p.js → chunk-LCL6LL3I-BhXV9zyH.js} +1 -1
  197. package/out/web/assets/{chunk-OBVCFTLP-DJeNil5M.js → chunk-OBVCFTLP-CRIkunUB.js} +1 -1
  198. package/out/web/assets/{chunk-P2QGCYS3-lRzkRjBB.js → chunk-P2QGCYS3-UFEU6BxZ.js} +1 -1
  199. package/out/web/assets/{chunk-POPQ4Y6H-DouASMBW.js → chunk-POPQ4Y6H-CQcrNbjr.js} +1 -1
  200. package/out/web/assets/{chunk-PWAF6VOD-DMmD1vVf.js → chunk-PWAF6VOD-Cc2uVDsG.js} +1 -1
  201. package/out/web/assets/{chunk-R7TYR2AO-CYLA5UC5.js → chunk-R7TYR2AO-DiCxzdAY.js} +1 -1
  202. package/out/web/assets/{chunk-RHFEMEQ7-BiXwEcUT.js → chunk-RHFEMEQ7-b7hnPmrR.js} +1 -1
  203. package/out/web/assets/{chunk-SVP7TREG-BV-zPslF.js → chunk-SVP7TREG-Bu_yYb-V.js} +1 -1
  204. package/out/web/assets/{chunk-TEH6E4GO-B2RGEohZ.js → chunk-TEH6E4GO-G4Cdlyrt.js} +1 -1
  205. package/out/web/assets/classDiagram-DTDB5LWJ-RnC2mYO4.js +1 -0
  206. package/out/web/assets/classDiagram-v2-JRS7N3AN-RnC2mYO4.js +1 -0
  207. package/out/web/assets/config-CnvCChUM.js +2 -0
  208. package/out/web/assets/config-DM6oIVO3.css +1 -0
  209. package/out/web/assets/core-DsKkQ7ig.js +1 -0
  210. package/out/web/assets/{cynefin-OW5HDTMX-Cas4csHM.js → cynefin-OW5HDTMX-CnzQfOGp.js} +1 -1
  211. package/out/web/assets/{cynefinDiagram-5FMLGOSQ-Bbpj66Y3.js → cynefinDiagram-5FMLGOSQ-DVtQnfpm.js} +1 -1
  212. package/out/web/assets/{dagre-3AP2YEHR-B0-2RDEd.js → dagre-3AP2YEHR-DG76_k5_.js} +1 -1
  213. package/out/web/assets/{diagram-S7CK7UJ4-BdzEjUyH.js → diagram-S7CK7UJ4-CaouUoze.js} +1 -1
  214. package/out/web/assets/{diagram-UQ7AKVKN-CJDwyPxF.js → diagram-UQ7AKVKN-B4bEc26B.js} +1 -1
  215. package/out/web/assets/{diagram-VSXAHHWV-BxaG1r_B.js → diagram-VSXAHHWV-BJ86Ov2Y.js} +1 -1
  216. package/out/web/assets/{diagram-VX7I27RA-BMmUqm8f.js → diagram-VX7I27RA-7hH5IPYf.js} +1 -1
  217. package/out/web/assets/{diagram-Z3DM3KII-CFtd03eE.js → diagram-Z3DM3KII-CCM4clo8.js} +1 -1
  218. package/out/web/assets/dist-js-BkYNznHX.js +1 -0
  219. package/out/web/assets/{ebnfDiagram-PWID7BFC-DwAen1hO.js → ebnfDiagram-PWID7BFC-Da7WAM3k.js} +1 -1
  220. package/out/web/assets/{erDiagram-SSCWMZ5O-BCZSHACj.js → erDiagram-SSCWMZ5O-CzzmnZWT.js} +1 -1
  221. package/out/web/assets/{event-ChBVpRy0.js → event-Cdt7Byyj.js} +1 -1
  222. package/out/web/assets/{eventmodeling-NTZA5JFV-XHStE4E_.js → eventmodeling-NTZA5JFV-xcfsA0XD.js} +1 -1
  223. package/out/web/assets/flowDiagram-A5DVABFB-JdtH1673.js +1 -0
  224. package/out/web/assets/{ganttDiagram-EL5Y4UJY-BAEu1Cql.js → ganttDiagram-EL5Y4UJY-B3ClFGmL.js} +1 -1
  225. package/out/web/assets/{gitGraph-4MIJSDKK-r32Vyper.js → gitGraph-4MIJSDKK-BZ_y_cDU.js} +1 -1
  226. package/out/web/assets/{gitGraphDiagram-WWUBYQGX-z9o9qt6V.js → gitGraphDiagram-WWUBYQGX-drhRSYm3.js} +1 -1
  227. package/out/web/assets/index-BZ9xgmMP.css +1 -0
  228. package/out/web/assets/index-Ca8cCS4h.js +168 -0
  229. package/out/web/assets/{info-A6RAGUB7-BvLaC2cw.js → info-A6RAGUB7-B7I3K0F1.js} +1 -1
  230. package/out/web/assets/{infoDiagram-RXCK75RN-Be6WAXXw.js → infoDiagram-RXCK75RN-deX_1MPh.js} +1 -1
  231. package/out/web/assets/{ishikawaDiagram-5VMMS53U-DZjoHJHC.js → ishikawaDiagram-5VMMS53U-s38yo28y.js} +1 -1
  232. package/out/web/assets/{journeyDiagram-EYS64GPL-CtVkjkGm.js → journeyDiagram-EYS64GPL-CZn2kB8b.js} +1 -1
  233. package/out/web/assets/jsx-runtime-DN4NhQUK.js +1 -0
  234. package/out/web/assets/{kanban-definition-3QL26DDD-CW5FMv1w.js → kanban-definition-3QL26DDD-DodjgySL.js} +1 -1
  235. package/out/web/assets/markdown-CMhYIcWB.js +39 -0
  236. package/out/web/assets/{mermaid-parser.core-aUgCqsZ5.js → mermaid-parser.core-Whu2rlJC.js} +3 -3
  237. package/out/web/assets/{mermaid.core-D57sEiSL.js → mermaid.core-CKyPo8VH.js} +4 -4
  238. package/out/web/assets/{mindmap-definition-FBJOCRG2-DAmSpM3a.js → mindmap-definition-FBJOCRG2-260WBDxZ.js} +1 -1
  239. package/out/web/assets/modelManager-CUaGWMWu.js +2 -0
  240. package/out/web/assets/{oauthManager-9jxicDWJ.js → oauthManager-DlNhXJr6.js} +1 -1
  241. package/out/web/assets/{packet-AYTQ26CC-DJ27iIoJ.js → packet-AYTQ26CC-CEeIRKRG.js} +1 -1
  242. package/out/web/assets/{pegDiagram-XKGWAZYB-Bj3ii-gS.js → pegDiagram-XKGWAZYB-BYadI-KO.js} +1 -1
  243. package/out/web/assets/{pie-WAS4IAKB-DG5mCUbc.js → pie-WAS4IAKB-D8uf4dh5.js} +1 -1
  244. package/out/web/assets/{pieDiagram-E7YTZNPT-BrJLPnDA.js → pieDiagram-E7YTZNPT-CjSDy4hO.js} +1 -1
  245. package/out/web/assets/{quadrantDiagram-AXDQQJYC-3x_TmF3j.js → quadrantDiagram-AXDQQJYC-B8D3gU5d.js} +1 -1
  246. package/out/web/assets/{radar-RG4KPBEZ-CrXaTTuV.js → radar-RG4KPBEZ-DZJxnokY.js} +1 -1
  247. package/out/web/assets/{railroad-74A4TZTK-BpqMH9BE.js → railroad-74A4TZTK-DBysUiUi.js} +1 -1
  248. package/out/web/assets/{railroad-abnf-HS5TGJTU-DHI0uLlV.js → railroad-abnf-HS5TGJTU-CHWxoJYg.js} +1 -1
  249. package/out/web/assets/{railroad-ebnf-LZEXJU2U-CQCb316y.js → railroad-ebnf-LZEXJU2U-DDv7X6bY.js} +1 -1
  250. package/out/web/assets/{railroad-peg-WCYAUIDC-Ph1giKkH.js → railroad-peg-WCYAUIDC-DpfcYYNJ.js} +1 -1
  251. package/out/web/assets/{railroadDiagram-O6MQD6OU-BRq6wIxx.js → railroadDiagram-O6MQD6OU-CYtyv0t3.js} +1 -1
  252. package/out/web/assets/{requirementDiagram-EFPCY7ZU-DIJj6G1g.js → requirementDiagram-EFPCY7ZU-D2X-Ewik.js} +1 -1
  253. package/out/web/assets/{sankeyDiagram-P5KCCOFB-DZajSryq.js → sankeyDiagram-P5KCCOFB-Bn2x6C4Y.js} +1 -1
  254. package/out/web/assets/{sequenceDiagram-WJ2MYXX4-DxJCWyZS.js → sequenceDiagram-WJ2MYXX4-BvFLKtPd.js} +1 -1
  255. package/out/web/assets/{stateDiagram-HBIQ2CUA-k6voi8Vf.js → stateDiagram-HBIQ2CUA-Bx0GWeaY.js} +1 -1
  256. package/out/web/assets/stateDiagram-v2-4QOOHH4V--hol1yg_.js +1 -0
  257. package/out/web/assets/{swimlanes-XN3QIQJK-igYhTjXB.js → swimlanes-XN3QIQJK-CCma0T7L.js} +1 -1
  258. package/out/web/assets/swimlanesDiagram-VK2B7HYN-BkohoVsU.js +8 -0
  259. package/out/web/assets/{timeline-definition-24CTP7MA-Dke2p93p.js → timeline-definition-24CTP7MA-iCRhhJ7C.js} +1 -1
  260. package/out/web/assets/{treeView-Q6P3EWNA-hNELnXUs.js → treeView-Q6P3EWNA-DZ-y08qp.js} +1 -1
  261. package/out/web/assets/{treemap-WGGIJYW6-D2B6wDsx.js → treemap-WGGIJYW6-De0CxzMx.js} +1 -1
  262. package/out/web/assets/{vennDiagram-4TSXK5OY-CDkW7rUP.js → vennDiagram-4TSXK5OY-w_7aZ6xe.js} +1 -1
  263. package/out/web/assets/{wardley-WFR3VGLG-BECdXETi.js → wardley-WFR3VGLG-DT0y0xJ4.js} +1 -1
  264. package/out/web/assets/{wardleyDiagram-VM6X3IG4-B5BycpQ4.js → wardleyDiagram-VM6X3IG4-DAdXELbQ.js} +1 -1
  265. package/out/web/assets/window-BJCVtyET.js +1 -0
  266. package/out/web/assets/{xychartDiagram-S5SC5T6Z-CtJS3b--.js → xychartDiagram-S5SC5T6Z-IZIXf3Vo.js} +1 -1
  267. package/out/web/index-web.html +3 -2
  268. package/out/web/index.html +3 -2
  269. package/package.json +71 -22
  270. package/shared-modules/.github/workflows/ci.yml +120 -0
  271. package/shared-modules/.github/workflows/update.yaml +28 -0
  272. package/slash-commands.json +7 -2
  273. package/src/bin/auto-build.js +66 -0
  274. package/src/bin/desktop.js +113 -0
  275. package/src/bin/desktop.test.js +113 -0
  276. package/src/bin/index.js +18 -25
  277. package/src/bin/index.test.js +89 -0
  278. package/src/bin/measure-effects.mjs +53 -0
  279. package/src/bin/package.test.js +28 -0
  280. package/src/bin/release-notes.test.js +84 -0
  281. package/src/bin/styles.test.js +20 -0
  282. package/src/bin/web.js +5 -0
  283. package/src/bin/web.test.js +39 -0
  284. package/src/renderer/index.html +0 -2
  285. package/src/renderer/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  286. package/src/renderer/shared/agentProgress.ts +33 -0
  287. package/src/renderer/shared/components/AgentActivityDrawer.tsx +3 -2
  288. package/src/renderer/shared/components/AgentActivityTable.tsx +1 -1
  289. package/src/renderer/shared/components/ApprovalCard.test.tsx +24 -0
  290. package/src/renderer/shared/components/ApprovalCard.tsx +10 -3
  291. package/src/renderer/shared/components/ArtifactPreviewPanel.tsx +88 -37
  292. package/src/renderer/shared/components/AuthGate.tsx +75 -39
  293. package/src/renderer/shared/components/BackgroundTerminals.tsx +181 -0
  294. package/src/renderer/shared/components/ChatCodeBlock.tsx +8 -4
  295. package/src/renderer/shared/components/ChatMessageItem.test.tsx +68 -0
  296. package/src/renderer/shared/components/ChatMessageItem.tsx +36 -16
  297. package/src/renderer/shared/components/ChatPanel.test.tsx +21 -0
  298. package/src/renderer/shared/components/ChatPanel.tsx +294 -272
  299. package/src/renderer/shared/components/ChunkErrorBoundary.tsx +4 -102
  300. package/src/renderer/shared/components/CliSessionsView.test.tsx +125 -0
  301. package/src/renderer/shared/components/CliSessionsView.tsx +61 -13
  302. package/src/renderer/shared/components/CodeReviewPage.tsx +111 -8
  303. package/src/renderer/shared/components/CollapsiblePasteInput.tsx +90 -0
  304. package/src/renderer/shared/components/ContextCompactionStatus.tsx +17 -0
  305. package/src/renderer/shared/components/DashboardSidebar.tsx +15 -128
  306. package/src/renderer/shared/components/DesktopTitlebar.tsx +45 -19
  307. package/src/renderer/shared/components/ErrorNotice.tsx +29 -0
  308. package/src/renderer/shared/components/FormattedMessage.tsx +11 -0
  309. package/src/renderer/shared/components/GeminiLiveOverlay.css +86 -0
  310. package/src/renderer/shared/components/GeminiLiveOverlay.test.tsx +24 -0
  311. package/src/renderer/shared/components/GeminiLiveOverlay.tsx +85 -101
  312. package/src/renderer/shared/components/GlideSelect.css +138 -0
  313. package/src/renderer/shared/components/GlideSelect.d.ts +31 -0
  314. package/src/renderer/shared/components/GlideSelect.jsx +266 -0
  315. package/src/renderer/shared/components/ImageSearchCard.tsx +46 -56
  316. package/src/renderer/shared/components/ImageStudioPanel.tsx +9 -8
  317. package/src/renderer/shared/components/LibraryItemCard.tsx +72 -0
  318. package/src/renderer/shared/components/LibraryPage.tsx +165 -0
  319. package/src/renderer/shared/components/LibraryPreview.tsx +59 -0
  320. package/src/renderer/shared/components/McpServersView.tsx +27 -8
  321. package/src/renderer/shared/components/McpToolAllowlist.tsx +2 -4
  322. package/src/renderer/shared/components/McpToolResults.tsx +99 -0
  323. package/src/renderer/shared/components/MintDashboard.tsx +308 -770
  324. package/src/renderer/shared/components/ModSessionControls.tsx +8 -0
  325. package/src/renderer/shared/components/ModUi.test.tsx +65 -0
  326. package/src/renderer/shared/components/ModUi.tsx +26 -0
  327. package/src/renderer/shared/components/ModelSelectorPopover.tsx +14 -7
  328. package/src/renderer/shared/components/ModsPanel.tsx +156 -0
  329. package/src/renderer/shared/components/ProgressActivity.tsx +17 -0
  330. package/src/renderer/shared/components/ReviewHistory.tsx +42 -0
  331. package/src/renderer/shared/components/RewindModal.tsx +5 -12
  332. package/src/renderer/shared/components/RunSummaryDashboard.tsx +6 -12
  333. package/src/renderer/shared/components/ScheduledTasksView.tsx +7 -6
  334. package/src/renderer/shared/components/SelectField.test.tsx +27 -0
  335. package/src/renderer/shared/components/SelectField.tsx +38 -0
  336. package/src/renderer/shared/components/SessionSources.tsx +48 -0
  337. package/src/renderer/shared/components/SessionSourcesPopover.tsx +61 -0
  338. package/src/renderer/shared/components/Settings/AgentsTab.tsx +7 -6
  339. package/src/renderer/shared/components/Settings/AudioTab.tsx +8 -7
  340. package/src/renderer/shared/components/Settings/AutomationTab.tsx +2 -2
  341. package/src/renderer/shared/components/Settings/GeneralTab.tsx +33 -32
  342. package/src/renderer/shared/components/Settings/MemoryTab.test.tsx +37 -0
  343. package/src/renderer/shared/components/Settings/MemoryTab.tsx +71 -31
  344. package/src/renderer/shared/components/Settings/NotificationsTab.test.tsx +15 -0
  345. package/src/renderer/shared/components/Settings/NotificationsTab.tsx +84 -0
  346. package/src/renderer/shared/components/Settings/ThemeTab.tsx +19 -11
  347. package/src/renderer/shared/components/SlashChoicePanel.tsx +88 -0
  348. package/src/renderer/shared/components/SlashSuggestions.test.tsx +33 -0
  349. package/src/renderer/shared/components/SlashSuggestions.tsx +38 -10
  350. package/src/renderer/shared/components/SourcesBlock.tsx +12 -20
  351. package/src/renderer/shared/components/ToolSurfacePage.test.tsx +32 -0
  352. package/src/renderer/shared/components/ToolSurfacePage.tsx +59 -11
  353. package/src/renderer/shared/components/ToolsPanelToggle.tsx +13 -0
  354. package/src/renderer/shared/components/VeoStudioPanel.tsx +9 -8
  355. package/src/renderer/shared/components/ViewedImages.tsx +36 -0
  356. package/src/renderer/shared/components/VirtualChatHistory.tsx +82 -0
  357. package/src/renderer/shared/components/VoicePill.css +85 -0
  358. package/src/renderer/shared/components/VoicePill.d.ts +12 -0
  359. package/src/renderer/shared/components/VoicePill.jsx +190 -0
  360. package/src/renderer/shared/components/VoicePill.test.tsx +22 -0
  361. package/src/renderer/shared/components/WorkspaceContextPopover.tsx +20 -15
  362. package/src/renderer/shared/components/WorkspacePaneResizer.tsx +92 -0
  363. package/src/renderer/shared/components/WorkspacePreviewActions.test.tsx +44 -0
  364. package/src/renderer/shared/components/WorkspacePreviewActions.tsx +19 -0
  365. package/src/renderer/shared/components/WorkspaceSelector.tsx +13 -8
  366. package/src/renderer/shared/components/background-terminals.css +292 -0
  367. package/src/renderer/shared/components/ui/README.md +52 -0
  368. package/src/renderer/shared/components/ui/button.tsx +37 -0
  369. package/src/renderer/shared/components/ui/demo.tsx +26 -0
  370. package/src/renderer/shared/components/ui/error-recovery.css +35 -0
  371. package/src/renderer/shared/components/ui/error-recovery.tsx +35 -0
  372. package/src/renderer/shared/components/ui/voice-powered-orb.css +6 -0
  373. package/src/renderer/shared/components/ui/voice-powered-orb.tsx +374 -0
  374. package/src/renderer/shared/components/workspace-selector.css +248 -0
  375. package/src/renderer/shared/constants/config.ts +30 -1
  376. package/src/renderer/shared/constants/slashCommands.ts +1 -1
  377. package/src/renderer/shared/conversation/lifecycle.test.ts +362 -0
  378. package/src/renderer/shared/conversation/lifecycle.ts +418 -0
  379. package/src/renderer/shared/conversation/projectNavigation.test.ts +105 -0
  380. package/src/renderer/shared/conversation/projectNavigation.ts +39 -0
  381. package/src/renderer/shared/conversation/sourcesTransport.ts +27 -0
  382. package/src/renderer/shared/conversation/syncView.test.ts +1 -34
  383. package/src/renderer/shared/conversation/syncView.ts +0 -37
  384. package/src/renderer/shared/conversation/transport.test.ts +163 -0
  385. package/src/renderer/shared/conversation/transport.ts +159 -0
  386. package/src/renderer/shared/conversation/useConversationCoordinator.ts +30 -72
  387. package/src/renderer/shared/css/agent-observability.css +20 -21
  388. package/src/renderer/shared/css/auth-gate.css +112 -13
  389. package/src/renderer/shared/css/code-review.css +33 -0
  390. package/src/renderer/shared/css/code-sessions.css +27 -0
  391. package/src/renderer/shared/css/collapsed-paste.css +35 -0
  392. package/src/renderer/shared/css/effects.css +15 -0
  393. package/src/renderer/shared/css/error-notice.css +60 -0
  394. package/src/renderer/shared/css/library.css +476 -0
  395. package/src/renderer/shared/css/management-views.css +138 -0
  396. package/src/renderer/shared/css/mcp-results.css +11 -0
  397. package/src/renderer/shared/css/model-selector.css +163 -105
  398. package/src/renderer/shared/css/mods.css +77 -0
  399. package/src/renderer/shared/css/notification-notice.css +28 -0
  400. package/src/renderer/shared/css/session-sources-popover.css +9 -0
  401. package/src/renderer/shared/css/session-sources.css +23 -0
  402. package/src/renderer/shared/css/settings/memory.css +154 -0
  403. package/src/renderer/shared/css/settings/notifications.css +11 -0
  404. package/src/renderer/shared/css/settings/theme.css +5 -0
  405. package/src/renderer/shared/css/slash-choice.css +95 -0
  406. package/src/renderer/shared/css/slash-suggestions.css +68 -0
  407. package/src/renderer/shared/css/sources-block.css +91 -0
  408. package/src/renderer/shared/css/thinking-status.css +46 -0
  409. package/src/renderer/shared/css/tools-panel.css +7 -0
  410. package/src/renderer/shared/css/ui-tailwind.css +19 -0
  411. package/src/renderer/shared/css/viewed-images.css +15 -0
  412. package/src/renderer/shared/fonts.css +46 -0
  413. package/src/renderer/shared/fonts.ts +3 -12
  414. package/src/renderer/shared/lib/utils.ts +6 -0
  415. package/src/renderer/shared/library/controller.test.ts +61 -0
  416. package/src/renderer/shared/library/controller.ts +57 -0
  417. package/src/renderer/shared/library/transport.test.ts +26 -0
  418. package/src/renderer/shared/library/transport.ts +60 -0
  419. package/src/renderer/shared/library/useLibraryFile.ts +38 -0
  420. package/src/renderer/shared/mods.ts +58 -0
  421. package/src/renderer/shared/platform.test.ts +57 -1
  422. package/src/renderer/shared/platform.ts +46 -1
  423. package/src/renderer/shared/theme/themeManager.test.ts +43 -0
  424. package/src/renderer/shared/theme/themeManager.ts +17 -4
  425. package/src/renderer/shared/types.ts +56 -2
  426. package/src/renderer/shared/utils/agentActivity.test.ts +75 -0
  427. package/src/renderer/shared/utils/agentActivity.ts +42 -3
  428. package/src/renderer/shared/utils/approval.tsx +7 -0
  429. package/src/renderer/shared/utils/artifactBrowser.test.ts +80 -0
  430. package/src/renderer/shared/utils/artifactBrowser.ts +41 -0
  431. package/src/renderer/shared/utils/contextCompaction.test.tsx +48 -0
  432. package/src/renderer/shared/utils/contextCompaction.ts +21 -0
  433. package/src/renderer/shared/utils/effectVisibility.ts +9 -0
  434. package/src/renderer/shared/utils/markdown.tsx +3 -3
  435. package/src/renderer/shared/utils/mcpResults.test.tsx +91 -0
  436. package/src/renderer/shared/utils/modViewport.ts +7 -0
  437. package/src/renderer/shared/utils/nativeRecordingSession.test.ts +61 -0
  438. package/src/renderer/shared/utils/nativeRecordingSession.ts +46 -0
  439. package/src/renderer/shared/utils/notificationSettings.test.ts +14 -0
  440. package/src/renderer/shared/utils/notificationSettings.ts +23 -0
  441. package/src/renderer/shared/utils/notifications.test.ts +51 -0
  442. package/src/renderer/shared/utils/notifications.ts +54 -0
  443. package/src/renderer/shared/utils/pastedText.test.ts +20 -0
  444. package/src/renderer/shared/utils/pastedText.ts +13 -0
  445. package/src/renderer/shared/utils/progressCache.test.ts +32 -0
  446. package/src/renderer/shared/utils/sessionSources.test.ts +31 -0
  447. package/src/renderer/shared/utils/sessionSources.ts +34 -0
  448. package/src/renderer/shared/utils/slashCommandProcessor.ts +1 -1
  449. package/src/renderer/shared/utils/sourceAttachments.ts +28 -0
  450. package/src/renderer/shared/utils/speech.ts +51 -9
  451. package/src/renderer/shared/utils/syntaxHighlight.test.tsx +22 -0
  452. package/src/renderer/shared/utils/syntaxHighlight.tsx +26 -0
  453. package/src/renderer/shared/utils/useGeminiLiveVoice.ts +49 -5
  454. package/src/renderer/shared/utils/useLatestCallback.ts +9 -0
  455. package/src/renderer/shared/utils/useNativeVoiceInput.ts +80 -72
  456. package/src/renderer/shared/utils/useSessionSources.ts +33 -0
  457. package/src/renderer/shared/utils/viewedImages.ts +26 -0
  458. package/src/renderer/shared/utils/workspacePane.test.ts +33 -0
  459. package/src/renderer/shared/utils/workspacePane.ts +20 -0
  460. package/src/renderer/shared/utils/workspacePreview.test.ts +24 -0
  461. package/src/renderer/shared/utils/workspacePreview.ts +16 -0
  462. package/src/renderer/shared/utils/workspaceSnapshot.test.ts +49 -0
  463. package/src/renderer/shared/utils/workspaceSnapshot.ts +26 -0
  464. package/src/renderer/shared/utils/workspaces.ts +10 -0
  465. package/src/renderer/shared/workspaceUndo.ts +88 -0
  466. package/src/renderer/src/App.tsx +9 -1
  467. package/src/renderer/src/components/LiveTranslateControls.tsx +65 -0
  468. package/src/renderer/src/components/PicturesLibrary.tsx +2 -288
  469. package/src/renderer/src/components/ScreenPicker.css +67 -30
  470. package/src/renderer/src/components/ScreenPicker.tsx +201 -60
  471. package/src/renderer/src/components/SettingsWindow.tsx +10 -5
  472. package/src/renderer/src/components/WorkspacePanel.tsx +222 -32
  473. package/src/renderer/src/components/browser-shell.css +1 -1
  474. package/src/renderer/src/components/browser-suggestions-popup.css +1 -1
  475. package/src/renderer/src/components/liveTranslateFrames.test.ts +26 -5
  476. package/src/renderer/src/components/liveTranslateFrames.ts +18 -7
  477. package/src/renderer/src/components/liveTranslateLanguage.ts +6 -0
  478. package/src/renderer/src/css/app-shell.css +52 -137
  479. package/src/renderer/src/css/chat.css +21 -495
  480. package/src/renderer/src/css/desktop-tools.css +199 -1
  481. package/src/renderer/src/css/misc.css +0 -52
  482. package/src/renderer/src/css/pictures.css +2 -415
  483. package/src/renderer/src/css/settings/base.css +50 -47
  484. package/src/renderer/src/css/sidebar-workspace.css +151 -94
  485. package/src/renderer/src/css/tool-surfaces.css +65 -9
  486. package/src/renderer/src/css/widget.css +1 -1
  487. package/src/renderer/src/env.d.ts +1 -9
  488. package/src/renderer/src/index.css +1 -1
  489. package/src/renderer/src/main.tsx +2 -1
  490. package/src/renderer/src/proactiveSuggestions.ts +29 -0
  491. package/src/renderer/src/tauri.ts +122 -330
  492. package/src/renderer/src/voiceInput.ts +2 -1
  493. package/src/renderer/src-web/components/PicturesLibrary.tsx +2 -285
  494. package/src/renderer/src-web/components/PullToRefresh.tsx +1 -1
  495. package/src/renderer/src-web/components/SettingsWindow.tsx +10 -5
  496. package/src/renderer/src-web/css/app-shell.css +24 -121
  497. package/src/renderer/src-web/css/chat.css +21 -495
  498. package/src/renderer/src-web/css/misc.css +0 -52
  499. package/src/renderer/src-web/css/mobile.css +15 -14
  500. package/src/renderer/src-web/css/pictures.css +2 -462
  501. package/src/renderer/src-web/css/settings/base.css +50 -47
  502. package/src/renderer/src-web/css/sidebar-workspace.css +9 -95
  503. package/src/renderer/src-web/css/widget.css +1 -1
  504. package/src/renderer/src-web/env.d.ts +1 -12
  505. package/src/renderer/src-web/index.css +1 -1
  506. package/src/renderer/src-web/main.tsx +2 -1
  507. package/src/renderer/src-web/proactiveSuggestions.ts +3 -0
  508. package/src/renderer/src-web/tauri.ts +129 -354
  509. package/src/renderer/tests/backgroundTerminals.browser.html +81 -0
  510. package/src/renderer/tests/chatPanelFixture.ts +23 -0
  511. package/src/renderer/tests/chatPerformance.browser.html +71 -0
  512. package/src/renderer/tests/cliSessions.browser.html +82 -0
  513. package/src/renderer/tests/collapsedPaste.browser.html +70 -0
  514. package/src/renderer/tests/composerMenus.browser.html +116 -0
  515. package/src/renderer/tests/contextCompaction.browser.html +17 -0
  516. package/src/renderer/tests/conversationLifecycle.browser.html +70 -0
  517. package/src/renderer/tests/effectsPerformance.browser.html +13 -0
  518. package/src/renderer/tests/errorRecovery.browser.html +21 -0
  519. package/src/renderer/tests/glideSelect.browser.html +71 -0
  520. package/src/renderer/tests/glideSelect.preview.html +27 -0
  521. package/src/renderer/tests/library.browser.html +1 -0
  522. package/src/renderer/tests/library.browser.tsx +78 -0
  523. package/src/renderer/tests/liveOrb.browser.html +49 -0
  524. package/src/renderer/tests/liveVoice.browser.html +29 -0
  525. package/src/renderer/tests/modInput.browser.html +22 -0
  526. package/src/renderer/tests/sessionSources.browser.html +1 -0
  527. package/src/renderer/tests/sessionSources.browser.tsx +107 -0
  528. package/src/renderer/tests/skills.browser.html +24 -0
  529. package/src/renderer/tests/toolsPanel.browser.html +1 -0
  530. package/src/renderer/tests/toolsPanel.browser.tsx +113 -0
  531. package/src/renderer/tests/viewedImages.browser.html +1 -0
  532. package/src/renderer/tests/viewedImages.browser.tsx +93 -0
  533. package/src/renderer/tests/voicePill.browser.html +80 -0
  534. package/src/renderer/tests/voicePill.preview.html +34 -0
  535. package/src/renderer/tests/webSources.browser.html +1 -0
  536. package/src/renderer/tests/webSources.browser.tsx +98 -0
  537. package/src/renderer/tests/workspaceUndo.browser.html +92 -0
  538. package/src-tauri/Cargo.toml +40 -0
  539. package/src-tauri/build.rs +3 -0
  540. package/src-tauri/src/app/lifecycle.rs +277 -0
  541. package/src-tauri/src/app/mod.rs +4 -0
  542. package/src-tauri/src/app/shortcuts.rs +40 -0
  543. package/src-tauri/src/app/tray.rs +52 -0
  544. package/src-tauri/src/background/events.rs +70 -0
  545. package/src-tauri/src/background/headless.rs +230 -0
  546. package/src-tauri/src/background/mod.rs +4 -0
  547. package/src-tauri/src/background/proactive.rs +262 -0
  548. package/src-tauri/src/commands/approvals.rs +20 -0
  549. package/src-tauri/src/commands/auth.rs +127 -0
  550. package/src-tauri/src/commands/conversation.rs +642 -0
  551. package/src-tauri/src/commands/integrations.rs +157 -0
  552. package/src-tauri/src/commands/media.rs +179 -0
  553. package/src-tauri/src/commands/mod.rs +11 -0
  554. package/src-tauri/src/commands/mods.rs +6 -0
  555. package/src-tauri/src/commands/settings.rs +141 -0
  556. package/src-tauri/src/commands/voice.rs +153 -0
  557. package/src-tauri/src/commands/workspace.rs +501 -0
  558. package/src-tauri/src/lib.rs +10 -0
  559. package/src-tauri/src/main.rs +3 -0
  560. package/src-tauri/src/native/actions.rs +206 -0
  561. package/src-tauri/src/native/browser.rs +252 -0
  562. package/src-tauri/src/native/capture.rs +695 -0
  563. package/src-tauri/src/native/discord_rpc.rs +99 -0
  564. package/src-tauri/src/native/integrations.rs +126 -0
  565. package/src-tauri/src/native/mod.rs +12 -0
  566. package/src-tauri/src/native/notifications.rs +51 -0
  567. package/src-tauri/src/native/plugins.rs +14 -0
  568. package/src-tauri/src/native/system.rs +250 -0
  569. package/src-tauri/src/native/terminal.rs +201 -0
  570. package/src-tauri/src/native/updater.rs +148 -0
  571. package/src-tauri/src/native/windows.rs +143 -0
  572. package/tsconfig.json +2 -0
  573. package/vite.config.ts +4 -1
  574. package/vite.config.web.ts +4 -0
  575. package/.cargo/config.toml +0 -13
  576. package/.claude/settings.local.json +0 -182
  577. package/.codex +0 -0
  578. package/CLAUDE.md +0 -102
  579. package/ROADMAP.md +0 -30
  580. package/mint-presentation-demo.mp4 +0 -0
  581. package/out/web/Live2DCubismCore.js +0 -9
  582. package/out/web/assets/CliSessionsView-BxUVWEEL.js +0 -1
  583. package/out/web/assets/CliSessionsView-CBDTXuQv.css +0 -1
  584. package/out/web/assets/CodeReviewPage-DkMgfcos.css +0 -1
  585. package/out/web/assets/CodeReviewPage-jKlmLJwT.js +0 -3
  586. package/out/web/assets/CommandPalette-DnwPA5hy.js +0 -1
  587. package/out/web/assets/ImageStudioPanel-BR1XFwhR.js +0 -1
  588. package/out/web/assets/LinkedFoldersView-bi-CWQ-I.js +0 -1
  589. package/out/web/assets/McpRegistryPicker-D5tEFnyq.js +0 -1
  590. package/out/web/assets/McpServersView-BGG1dhFM.js +0 -1
  591. package/out/web/assets/MintDashboard-BIglDEWX.js +0 -20
  592. package/out/web/assets/MintDashboard-DSMywSgs.css +0 -1
  593. package/out/web/assets/ModelPanel-CbJ1PFoZ.js +0 -1
  594. package/out/web/assets/PicturesLibrary-CQP0fLP1.css +0 -1
  595. package/out/web/assets/PicturesLibrary-DoYN7T1p.js +0 -1
  596. package/out/web/assets/PluginsView-CU1HWXGk.js +0 -1
  597. package/out/web/assets/ScheduledTasksView-Bnl36y2N.js +0 -1
  598. package/out/web/assets/SettingsWindow-DhWLAn9T.css +0 -1
  599. package/out/web/assets/SettingsWindow-Dw8L01pw.js +0 -2
  600. package/out/web/assets/SkillsView-cnl8aY5p.js +0 -2
  601. package/out/web/assets/ToolSurfacePage-CgsQw6l5.css +0 -1
  602. package/out/web/assets/ToolSurfacePage-Cz2VJAPZ.js +0 -37
  603. package/out/web/assets/VeoStudioPanel-D4JnERWR.js +0 -4
  604. package/out/web/assets/chunk-CKBBP62Z-cIrXq6jN.js +0 -2
  605. package/out/web/assets/classDiagram-DTDB5LWJ-Dq0smRWk.js +0 -1
  606. package/out/web/assets/classDiagram-v2-JRS7N3AN-Dq0smRWk.js +0 -1
  607. package/out/web/assets/config-C-ZFtipU.css +0 -1
  608. package/out/web/assets/config-eEDngJXO.js +0 -1
  609. package/out/web/assets/core-hQ2VA9Ti.js +0 -1
  610. package/out/web/assets/dist-js-Bf2bhoku.js +0 -1
  611. package/out/web/assets/flowDiagram-A5DVABFB-BLg7nEcd.js +0 -1
  612. package/out/web/assets/index-Btsf4L8M.css +0 -1
  613. package/out/web/assets/index-D8D9MeRA.js +0 -11
  614. package/out/web/assets/lucide-react-Ip3L6Jtn.js +0 -1
  615. package/out/web/assets/markdown-BSeeUbJH.js +0 -38
  616. package/out/web/assets/modelManager-tMVmJVAW.js +0 -2
  617. package/out/web/assets/prompt-latin-400-normal-BQ9zjSN8.woff2 +0 -0
  618. package/out/web/assets/prompt-latin-400-normal-CxU4ec_r.woff +0 -0
  619. package/out/web/assets/prompt-latin-500-normal-B1edBDQ9.woff +0 -0
  620. package/out/web/assets/prompt-latin-500-normal-CxzxEHZc.woff2 +0 -0
  621. package/out/web/assets/prompt-latin-600-normal-CSDDLorv.woff +0 -0
  622. package/out/web/assets/prompt-latin-600-normal-hKZWXsc1.woff2 +0 -0
  623. package/out/web/assets/prompt-latin-700-normal-BfbftDSq.woff +0 -0
  624. package/out/web/assets/prompt-latin-700-normal-I2gc831J.woff2 +0 -0
  625. package/out/web/assets/prompt-thai-400-normal-BrkKv8cO.woff2 +0 -0
  626. package/out/web/assets/prompt-thai-400-normal-DJypnfr3.woff +0 -0
  627. package/out/web/assets/prompt-thai-500-normal-C18pDUoL.woff2 +0 -0
  628. package/out/web/assets/prompt-thai-500-normal-D7YNqUJD.woff +0 -0
  629. package/out/web/assets/prompt-thai-600-normal-CYPViXds.woff +0 -0
  630. package/out/web/assets/prompt-thai-600-normal-MrdfU7zR.woff2 +0 -0
  631. package/out/web/assets/prompt-thai-700-normal-Cb5ilR-c.woff +0 -0
  632. package/out/web/assets/prompt-thai-700-normal-Cg4aQ0Nn.woff2 +0 -0
  633. package/out/web/assets/stateDiagram-v2-4QOOHH4V-DeEc0lGZ.js +0 -1
  634. package/out/web/assets/swimlanesDiagram-VK2B7HYN-DpVik9v7.js +0 -8
  635. package/out/web/assets/window-5qYXKoW7.js +0 -1
  636. package/skills-lock.json +0 -77
  637. package/src/renderer/public/Live2DCubismCore.js +0 -9
  638. package/src/renderer/src/companionWidget.ts +0 -95
  639. package/src/renderer/src/components/Live2DStage.tsx +0 -412
  640. package/src/renderer/src/components/ModelPanel.tsx +0 -155
  641. package/src/renderer/src/css/model.css +0 -628
  642. package/src/renderer/src-web/companionWidget.ts +0 -37
  643. package/src/renderer/src-web/components/ModelPanel.tsx +0 -12
  644. package/src/renderer/src-web/css/model.css +0 -628
@@ -225,6 +225,12 @@ impl KnowledgeStore {
225
225
 
226
226
  pub fn extract_document_text(path: &Path, config: &MintConfig) -> Result<String, KnowledgeError> {
227
227
  let path = assert_path_capability(path, Capability::Read, config)?;
228
+ extract_managed_document_text(&path)
229
+ }
230
+
231
+ // Only Library may bypass workspace policy after validating a managed original.
232
+ pub(crate) fn extract_managed_document_text(path: &Path) -> Result<String, KnowledgeError> {
233
+ let path = path.to_path_buf();
228
234
  let metadata = fs::metadata(&path).map_err(|source| KnowledgeError::Read {
229
235
  path: path.clone(),
230
236
  source,
@@ -245,7 +251,7 @@ pub fn extract_document_text(path: &Path, config: &MintConfig) -> Result<String,
245
251
  Ok(content)
246
252
  }
247
253
 
248
- fn supported(path: &Path) -> bool {
254
+ pub(crate) fn supported(path: &Path) -> bool {
249
255
  path.extension()
250
256
  .and_then(|extension| extension.to_str())
251
257
  .is_some_and(|extension| {
@@ -7,7 +7,7 @@ use std::time::UNIX_EPOCH;
7
7
 
8
8
  use chrono::Local;
9
9
  use ignore::WalkBuilder;
10
- use rusqlite::{Connection, OptionalExtension, params};
10
+ use rusqlite::{Connection, OptionalExtension, TransactionBehavior, params};
11
11
  use uuid::Uuid;
12
12
 
13
13
  use super::{LinkedFolder, LinkedFolderNote, LinkedFolderStatus};
@@ -21,13 +21,37 @@ const CHUNK_CHARS: usize = 1000;
21
21
  const CHUNK_OVERLAP: usize = 200;
22
22
 
23
23
  fn db() -> Result<Connection, String> {
24
- let path = memory_path().map_err(|e| e.to_string())?;
24
+ open_db().map_err(|error| error.to_string())
25
+ }
26
+
27
+ pub(super) type ClaimedJob = (String, String, String, i64);
28
+
29
+ #[derive(Debug, thiserror::Error)]
30
+ pub(super) enum ClaimError {
31
+ #[error(transparent)]
32
+ Database(#[from] rusqlite::Error),
33
+ #[error("{0}")]
34
+ Setup(String),
35
+ }
36
+
37
+ impl ClaimError {
38
+ pub(super) fn is_busy(&self) -> bool {
39
+ matches!(self, Self::Database(rusqlite::Error::SqliteFailure(error, _))
40
+ if matches!(error.code, rusqlite::ErrorCode::DatabaseBusy | rusqlite::ErrorCode::DatabaseLocked))
41
+ }
42
+ }
43
+
44
+ fn open_db() -> Result<Connection, ClaimError> {
45
+ let path = memory_path().map_err(|e| ClaimError::Setup(e.to_string()))?;
46
+ open_db_at(&path)
47
+ }
48
+
49
+ fn open_db_at(path: &Path) -> Result<Connection, ClaimError> {
25
50
  if let Some(parent) = path.parent() {
26
- fs::create_dir_all(parent).map_err(|e| e.to_string())?;
51
+ fs::create_dir_all(parent).map_err(|e| ClaimError::Setup(e.to_string()))?;
27
52
  }
28
- let conn = Connection::open(path).map_err(|e| e.to_string())?;
29
- conn.busy_timeout(std::time::Duration::from_secs(5))
30
- .map_err(|e| e.to_string())?;
53
+ let conn = Connection::open(path)?;
54
+ conn.busy_timeout(std::time::Duration::from_secs(5))?;
31
55
  conn.execute_batch(
32
56
  "CREATE TABLE IF NOT EXISTS linked_folder_files (
33
57
  folder TEXT NOT NULL, root TEXT NOT NULL, path TEXT NOT NULL,
@@ -50,7 +74,7 @@ fn db() -> Result<Connection, String> {
50
74
  id TEXT PRIMARY KEY, user_text TEXT NOT NULL, ai_text TEXT NOT NULL,
51
75
  status TEXT NOT NULL, attempts INTEGER NOT NULL DEFAULT 0,
52
76
  error TEXT, created_at TEXT NOT NULL, claimed_at INTEGER);"
53
- ).map_err(|e| e.to_string())?;
77
+ )?;
54
78
  Ok(conn)
55
79
  }
56
80
 
@@ -654,15 +678,20 @@ pub(super) fn queue_job(id: &str, user_text: &str, ai_text: &str) -> Result<(),
654
678
  Ok(())
655
679
  }
656
680
 
657
- pub(super) fn claim_job() -> Result<Option<(String, String, String, i64)>, String> {
658
- let mut conn = db()?;
659
- let tx = conn.transaction().map_err(|e| e.to_string())?;
681
+ pub(super) fn claim_job() -> Result<Option<ClaimedJob>, ClaimError> {
682
+ claim_job_on(&mut open_db()?)
683
+ }
684
+
685
+ fn claim_job_on(conn: &mut Connection) -> Result<Option<ClaimedJob>, ClaimError> {
686
+ // Acquire the writer slot before reading: a deferred transaction can read
687
+ // an outdated WAL snapshot and fail immediately when upgrading to a writer.
688
+ let tx = conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
660
689
  let job = tx.query_row("SELECT id,user_text,ai_text,attempts FROM linked_folder_jobs WHERE (status='pending' AND (claimed_at IS NULL OR claimed_at <= unixepoch())) OR (status='running' AND claimed_at < unixepoch()-600) ORDER BY created_at LIMIT 1", [],
661
- |r| Ok((r.get::<_,String>(0)?,r.get::<_,String>(1)?,r.get::<_,String>(2)?,r.get::<_,i64>(3)?))).optional().map_err(|e| e.to_string())?;
690
+ |r| Ok((r.get::<_,String>(0)?,r.get::<_,String>(1)?,r.get::<_,String>(2)?,r.get::<_,i64>(3)?))).optional()?;
662
691
  if let Some((ref id, _, _, _)) = job {
663
- tx.execute("UPDATE linked_folder_jobs SET status='running',attempts=attempts+1,claimed_at=unixepoch() WHERE id=?1",[id]).map_err(|e| e.to_string())?;
692
+ tx.execute("UPDATE linked_folder_jobs SET status='running',attempts=attempts+1,claimed_at=unixepoch() WHERE id=?1",[id])?;
664
693
  }
665
- tx.commit().map_err(|e| e.to_string())?;
694
+ tx.commit()?;
666
695
  Ok(job)
667
696
  }
668
697
 
@@ -686,6 +715,141 @@ pub(super) fn retry_job(id: &str, error: &str, delay_seconds: i64) -> Result<(),
686
715
  mod tests {
687
716
  use super::*;
688
717
 
718
+ fn claim_test_db() -> (std::path::PathBuf, Connection) {
719
+ let dir = std::env::temp_dir().join(format!("mint-linked-claim-{}", Uuid::new_v4()));
720
+ let path = dir.join("jobs.sqlite");
721
+ let conn = open_db_at(&path).unwrap();
722
+ conn.execute_batch("PRAGMA journal_mode=WAL;").unwrap();
723
+ (path, conn)
724
+ }
725
+
726
+ fn insert_test_job(conn: &Connection, id: &str) {
727
+ conn.execute("INSERT INTO linked_folder_jobs(id,user_text,ai_text,status,created_at) VALUES(?1,'user','ai','pending','2026-10-02')", [id]).unwrap();
728
+ }
729
+
730
+ #[test]
731
+ fn concurrent_claims_take_each_job_once() {
732
+ let (path, conn) = claim_test_db();
733
+ for i in 0..8 {
734
+ insert_test_job(&conn, &format!("job-{i}"));
735
+ }
736
+ let barrier = std::sync::Arc::new(std::sync::Barrier::new(8));
737
+ let mut workers = Vec::new();
738
+ for _ in 0..8 {
739
+ let mut worker_conn = open_db_at(&path).unwrap();
740
+ let barrier = barrier.clone();
741
+ workers.push(std::thread::spawn(move || {
742
+ barrier.wait();
743
+ claim_job_on(&mut worker_conn).unwrap().unwrap()
744
+ }));
745
+ }
746
+ let jobs: Vec<_> = workers
747
+ .into_iter()
748
+ .map(|worker| worker.join().unwrap())
749
+ .collect();
750
+ assert_eq!(
751
+ jobs.iter().map(|job| &job.0).collect::<HashSet<_>>().len(),
752
+ 8
753
+ );
754
+ assert!(jobs.iter().all(|job| job.3 == 0));
755
+ let running: i64 = conn
756
+ .query_row(
757
+ "SELECT count(*) FROM linked_folder_jobs WHERE status='running' AND attempts=1",
758
+ [],
759
+ |row| row.get(0),
760
+ )
761
+ .unwrap();
762
+ assert_eq!(running, 8);
763
+ drop(conn);
764
+ fs::remove_dir_all(path.parent().unwrap()).unwrap();
765
+ }
766
+
767
+ #[test]
768
+ fn claim_waits_for_writer_and_failed_lock_does_not_consume_job_attempt() {
769
+ let (path, mut writer) = claim_test_db();
770
+ insert_test_job(&writer, "job");
771
+ let mut claimant = open_db_at(&path).unwrap();
772
+ claimant.busy_timeout(std::time::Duration::ZERO).unwrap();
773
+ let tx = writer
774
+ .transaction_with_behavior(TransactionBehavior::Immediate)
775
+ .unwrap();
776
+ let error = claim_job_on(&mut claimant).unwrap_err();
777
+ assert!(error.is_busy());
778
+ let attempts: i64 = tx
779
+ .query_row(
780
+ "SELECT attempts FROM linked_folder_jobs WHERE id='job'",
781
+ [],
782
+ |row| row.get(0),
783
+ )
784
+ .unwrap();
785
+ assert_eq!(attempts, 0);
786
+ claimant
787
+ .busy_timeout(std::time::Duration::from_secs(5))
788
+ .unwrap();
789
+ let (started_tx, started_rx) = std::sync::mpsc::channel();
790
+ let (result_tx, result_rx) = std::sync::mpsc::channel();
791
+ let worker = std::thread::spawn(move || {
792
+ started_tx.send(()).unwrap();
793
+ result_tx.send(claim_job_on(&mut claimant)).unwrap();
794
+ });
795
+ started_rx.recv().unwrap();
796
+ assert!(matches!(
797
+ result_rx.recv_timeout(std::time::Duration::from_millis(50)),
798
+ Err(std::sync::mpsc::RecvTimeoutError::Timeout)
799
+ ));
800
+ tx.commit().unwrap();
801
+ let job = result_rx
802
+ .recv_timeout(std::time::Duration::from_secs(5))
803
+ .unwrap()
804
+ .unwrap()
805
+ .unwrap();
806
+ assert_eq!(job.0, "job");
807
+ assert_eq!(job.3, 0);
808
+ worker.join().unwrap();
809
+ assert!(claim_job_on(&mut writer).unwrap().is_none());
810
+ drop(writer);
811
+ fs::remove_dir_all(path.parent().unwrap()).unwrap();
812
+ }
813
+
814
+ #[tokio::test]
815
+ async fn claim_retry_recovers_after_real_database_lock_is_released() {
816
+ let (path, mut writer) = claim_test_db();
817
+ insert_test_job(&writer, "job");
818
+ let mut claimant = open_db_at(&path).unwrap();
819
+ claimant.busy_timeout(std::time::Duration::ZERO).unwrap();
820
+ let mut lock = Some(
821
+ writer
822
+ .transaction_with_behavior(TransactionBehavior::Immediate)
823
+ .unwrap(),
824
+ );
825
+ let mut calls = 0;
826
+ let job = super::super::claim_job_with_retry(|| {
827
+ calls += 1;
828
+ if calls == 2 {
829
+ lock.take().unwrap().commit().unwrap();
830
+ }
831
+ std::future::ready(claim_job_on(&mut claimant))
832
+ })
833
+ .await
834
+ .unwrap()
835
+ .unwrap();
836
+ assert_eq!(calls, 2);
837
+ assert_eq!(job.0, "job");
838
+ assert_eq!(job.3, 0);
839
+ let attempts: i64 = claimant
840
+ .query_row(
841
+ "SELECT attempts FROM linked_folder_jobs WHERE id='job'",
842
+ [],
843
+ |row| row.get(0),
844
+ )
845
+ .unwrap();
846
+ assert_eq!(attempts, 1);
847
+ drop(lock);
848
+ drop(claimant);
849
+ drop(writer);
850
+ fs::remove_dir_all(path.parent().unwrap()).unwrap();
851
+ }
852
+
689
853
  #[test]
690
854
  fn concurrent_appends_keep_each_note_once() {
691
855
  let dir = std::env::temp_dir().join(format!("mint-linked-write-{}", Uuid::new_v4()));
@@ -447,7 +447,7 @@ fn parse_model_notes(
447
447
  /// Fire-and-forget: after a chat turn, ask the model (in a second, separate
448
448
  /// call) whether it touched on a linked folder's topic closely enough to be
449
449
  /// worth a note, and if so append one to `<folder>/mint-notes/<date>.md`.
450
- /// Mirrors [`crate::orchestration::spawn_auto_skill_write`] — never blocks or
450
+ /// Like background memory extraction, this never blocks or
451
451
  /// fails the turn that triggered it.
452
452
  pub fn spawn_linked_folder_note(
453
453
  config: MintConfig,
@@ -465,13 +465,41 @@ pub fn spawn_linked_folder_note(
465
465
  resume_linked_folder_jobs(config);
466
466
  }
467
467
 
468
+ const CLAIM_LOCK_RETRIES: usize = 3;
469
+
470
+ async fn claim_job_with_retry<Claim, Fut>(
471
+ mut claim: Claim,
472
+ ) -> Result<Option<index::ClaimedJob>, index::ClaimError>
473
+ where
474
+ Claim: FnMut() -> Fut,
475
+ Fut: std::future::Future<Output = Result<Option<index::ClaimedJob>, index::ClaimError>>,
476
+ {
477
+ for retry in 0..=CLAIM_LOCK_RETRIES {
478
+ match claim().await {
479
+ Err(error) if error.is_busy() && retry < CLAIM_LOCK_RETRIES => {
480
+ tokio::time::sleep(std::time::Duration::from_millis(100 << retry)).await;
481
+ }
482
+ result => return result,
483
+ }
484
+ }
485
+ unreachable!("last attempt always returns")
486
+ }
487
+
468
488
  fn resume_linked_folder_jobs(config: MintConfig) {
469
489
  let Ok(runtime) = tokio::runtime::Handle::try_current() else {
470
490
  return;
471
491
  };
472
492
  runtime.spawn(async move {
473
493
  loop {
474
- let job = match index::claim_job() {
494
+ let job = match claim_job_with_retry(|| async {
495
+ // SQLite may wait up to five seconds for a writer. Keep that
496
+ // blocking wait off the async runtime's worker threads.
497
+ tokio::task::spawn_blocking(index::claim_job)
498
+ .await
499
+ .map_err(|error| index::ClaimError::Setup(error.to_string()))?
500
+ })
501
+ .await
502
+ {
475
503
  Ok(Some(job)) => job,
476
504
  Ok(None) => break,
477
505
  Err(error) => {
@@ -675,6 +703,59 @@ Use an empty notes array when nothing is worth saving."#
675
703
  mod tests {
676
704
  use super::*;
677
705
 
706
+ fn database_error(code: i32) -> index::ClaimError {
707
+ rusqlite::Error::SqliteFailure(rusqlite::ffi::Error::new(code), None).into()
708
+ }
709
+
710
+ #[tokio::test]
711
+ async fn claim_retries_busy_errors_then_returns_recovered_job() {
712
+ let mut calls = 0;
713
+ let job = claim_job_with_retry(|| {
714
+ calls += 1;
715
+ std::future::ready(if calls <= 2 {
716
+ Err(database_error(rusqlite::ffi::SQLITE_BUSY))
717
+ } else {
718
+ Ok(Some(("job".into(), "user".into(), "ai".into(), 0)))
719
+ })
720
+ })
721
+ .await
722
+ .unwrap()
723
+ .unwrap();
724
+ assert_eq!(calls, 3);
725
+ assert_eq!(job.0, "job");
726
+ assert_eq!(job.3, 0);
727
+ }
728
+
729
+ #[tokio::test]
730
+ async fn claim_stops_retrying_after_budget_and_does_not_retry_other_errors() {
731
+ for code in [rusqlite::ffi::SQLITE_BUSY, rusqlite::ffi::SQLITE_LOCKED] {
732
+ let mut calls = 0;
733
+ let error = claim_job_with_retry(|| {
734
+ calls += 1;
735
+ std::future::ready(Err(database_error(code)))
736
+ })
737
+ .await
738
+ .unwrap_err();
739
+ assert!(error.is_busy());
740
+ assert_eq!(calls, CLAIM_LOCK_RETRIES + 1);
741
+ }
742
+ let mut calls = 0;
743
+ let error = claim_job_with_retry(|| {
744
+ calls += 1;
745
+ std::future::ready(Err(database_error(rusqlite::ffi::SQLITE_CORRUPT)))
746
+ })
747
+ .await
748
+ .unwrap_err();
749
+ assert!(!error.is_busy());
750
+ assert_eq!(calls, 1);
751
+ assert!(
752
+ claim_job_with_retry(|| std::future::ready(Ok(None)))
753
+ .await
754
+ .unwrap()
755
+ .is_none()
756
+ );
757
+ }
758
+
678
759
  #[test]
679
760
  fn model_response_can_save_distinct_notes_in_multiple_candidate_folders() {
680
761
  let candidates = ["Food".to_string(), "Travel".to_string()].into();
@@ -4,7 +4,7 @@
4
4
  //! surface: the Rust CLI (`crates/mint-cli/src/interactive/`), this engine, and
5
5
  //! the Web/Desktop renderer (`src/renderer/shared/constants/slashCommands.ts`,
6
6
  //! which imports the same JSON). Each entry's `surfaces` array says which UIs
7
- //! list it — CLI-only commands (`/bg`, `/jobs`, `/shells`, `/exit`, `/plan`, and
7
+ //! list it — CLI-only commands (`/bg`, `/jobs`, `/exit`, `/plan`, and
8
8
  //! the `Ctrl+V` / `↑ / ↓` help rows) carry just `["cli"]`.
9
9
 
10
10
  #[derive(serde::Deserialize)]
@@ -1,7 +1,7 @@
1
1
  //! UI-agnostic slash-command engine, shared by the CLI
2
2
  //! (`crates/mint-cli/src/interactive/slash_commands.rs`), the web API server
3
3
  //! (`crate::api_server::routes::slash`), and the desktop Tauri host
4
- //! (`src-tauri/src/lib.rs::run_slash_command`).
4
+ //! (`src-tauri/src/commands/conversation.rs::run_slash_command`).
5
5
  //!
6
6
  //! `execute` is a pure function of its `input` string plus the `MintConfig` it
7
7
  //! is handed: it mutates the config in place for config commands and reports
@@ -17,6 +17,7 @@
17
17
 
18
18
  use crate::MintConfig;
19
19
  use std::path::{Path, PathBuf};
20
+ mod mods;
20
21
 
21
22
  /// The instruction `/init` hands to the code agent (via
22
23
  /// [`SlashResponse::ForwardToAgent`]). Mirrors Claude Code's `/init`, but
@@ -48,6 +49,8 @@ use render::{local_time, md_heading, md_list, md_table};
48
49
  #[derive(serde::Deserialize)]
49
50
  pub struct SlashRequest {
50
51
  pub input: String,
52
+ #[serde(default)]
53
+ pub chat_id: Option<String>,
51
54
  /// Active workspace directory; defaults to the process cwd.
52
55
  #[serde(default)]
53
56
  pub cwd: Option<String>,
@@ -128,6 +131,7 @@ pub enum SlashEffect {
128
131
  WorkspaceChanged {
129
132
  path: String,
130
133
  },
134
+ WorkspaceFilesChanged,
131
135
  /// `/clear` — caller wipes the current conversation.
132
136
  HistoryCleared,
133
137
  FastModeChanged {
@@ -193,20 +197,37 @@ pub fn execute(req: &SlashRequest, config: &mut MintConfig) -> SlashResponse {
193
197
  return SlashResponse::NotHandled;
194
198
  };
195
199
 
200
+ if token == "/mods" || token.starts_with("/mods:") {
201
+ let Some(chat) = req.chat_id.as_deref().filter(|s| !s.is_empty()) else {
202
+ return error("Mods require an explicit chat ID");
203
+ };
204
+ let root = req.workspace();
205
+ if let Err(e) = crate::assert_path_capability(&root, crate::Capability::Read, config) {
206
+ return error(e.to_string());
207
+ }
208
+ if token == "/mods" {
209
+ if let Some(response) = mods::picker(&root, chat, rest) {
210
+ return response.unwrap_or_else(error);
211
+ }
212
+ }
213
+ return match crate::mods::slash(&root, chat, &req.input) {
214
+ Ok(text) => message(text),
215
+ Err(e) => error(e),
216
+ };
217
+ }
196
218
  match token.as_str() {
219
+ "/mint-web" => match crate::system::mint_web::command(&req.workspace(), rest, None, config) { Ok(text) => message(text), Err(err) => error(err) },
220
+ "/shells" if !req.is_cli() => match crate::bg_shell::shells_command(rest, &req.workspace(), &None, config) {
221
+ Ok(text) => message(text), Err(err) => error(err.to_string()),
222
+ },
223
+ "/preview" => match crate::system::html_preview::command(&req.workspace(), rest, None, config) { Ok(text) => message(text), Err(err) => error(err) },
197
224
  "/help" => cmd_help(req.is_cli()),
198
225
  "/init" => SlashResponse::ForwardToAgent {
199
226
  prompt: INIT_AGENTS_MD_PROMPT.to_string(),
200
227
  agent_mode: true,
201
228
  plan_mode: false,
202
229
  },
203
- "/release-notes" => message(
204
- include_str!(concat!(
205
- env!("CARGO_MANIFEST_DIR"),
206
- "/../../Release_Note.md"
207
- ))
208
- .trim(),
209
- ),
230
+ "/release-notes" => message(crate::release_notes::text()),
210
231
  "/clear" => SlashResponse::Applied {
211
232
  markdown: "🧹 Conversation history cleared.".into(),
212
233
  effects: vec![SlashEffect::HistoryCleared],
@@ -219,7 +240,7 @@ pub fn execute(req: &SlashRequest, config: &mut MintConfig) -> SlashResponse {
219
240
  "/autoskill" => cmd_bool_toggle(
220
241
  rest,
221
242
  "/autoskill",
222
- "Auto Skill Writing",
243
+ "Skill Suggestions (approval required to save)",
223
244
  config.auto_skill_writing,
224
245
  |cfg, v| cfg.auto_skill_writing = v,
225
246
  config,
@@ -270,6 +291,10 @@ pub fn execute(req: &SlashRequest, config: &mut MintConfig) -> SlashResponse {
270
291
  }
271
292
  }
272
293
  "/rewind" => cmd_rewind(req, rest),
294
+ "/history" | "/undo" => {
295
+ if !rest.trim().is_empty() { error(format!("Usage: {token}")) }
296
+ else { cmd_workspace_history(req, token == "/undo", config) }
297
+ }
273
298
  "/fast" => match parse_on_off(rest) {
274
299
  None if rest.is_empty() => needs_on_off("/fast", "Fast Mode (hide thinking)"),
275
300
  None => error("Usage: /fast [on|off]"),
@@ -576,6 +601,44 @@ fn cmd_bool_toggle(
576
601
  }
577
602
  }
578
603
 
604
+ fn cmd_workspace_history(req: &SlashRequest, undo: bool, config: &MintConfig) -> SlashResponse {
605
+ let capability = if undo {
606
+ crate::Capability::Write
607
+ } else {
608
+ crate::Capability::Read
609
+ };
610
+ let root = match crate::assert_path_capability(&req.workspace(), capability, config) {
611
+ Ok(root) => root,
612
+ Err(reason) => return error(reason),
613
+ };
614
+ if undo {
615
+ match crate::system::workspace_history::undo(&root, None) {
616
+ Ok(Some(entry)) => SlashResponse::Applied {
617
+ markdown: format!("✅ {}", entry.label),
618
+ effects: vec![SlashEffect::WorkspaceFilesChanged],
619
+ },
620
+ Ok(None) => message("There is no workspace action to undo."),
621
+ Err(reason) => error(reason),
622
+ }
623
+ } else {
624
+ match crate::system::workspace_history::list(&root) {
625
+ Ok(entries) if entries.is_empty() => message(
626
+ "No workspace file history yet. File edits are backed up before changes, including projects without Git.",
627
+ ),
628
+ Ok(entries) => message(format!(
629
+ "Recent workspace file actions (newest first):\n\n{}\n\nUse `/undo` to undo the latest action. Changed files and occupied restore paths are protected.",
630
+ entries
631
+ .iter()
632
+ .take(20)
633
+ .map(|entry| format!("- {}", entry.label.trim_start_matches("Undo ")))
634
+ .collect::<Vec<_>>()
635
+ .join("\n")
636
+ )),
637
+ Err(reason) => error(reason),
638
+ }
639
+ }
640
+ }
641
+
579
642
  fn cmd_rewind(req: &SlashRequest, rest: &str) -> SlashResponse {
580
643
  let chat_id = crate::CHAT_CLI_ID;
581
644
  let root = req.workspace();
@@ -2237,6 +2300,7 @@ fn cmd_mcp(rest: &str, config: &mut MintConfig) -> SlashResponse {
2237
2300
  url: Some(target.to_string()),
2238
2301
  headers: None,
2239
2302
  transport: Some("sse".to_string()),
2303
+ timeout_secs: None,
2240
2304
  }
2241
2305
  } else {
2242
2306
  crate::McpServer {
@@ -2248,6 +2312,7 @@ fn cmd_mcp(rest: &str, config: &mut MintConfig) -> SlashResponse {
2248
2312
  url: None,
2249
2313
  headers: None,
2250
2314
  transport: None,
2315
+ timeout_secs: None,
2251
2316
  }
2252
2317
  };
2253
2318
  match crate::upsert_server_in(config, name, server) {
@@ -2297,9 +2362,21 @@ fn cmd_mcp(rest: &str, config: &mut MintConfig) -> SlashResponse {
2297
2362
  "edit" => {
2298
2363
  let mut parts = args.splitn(3, char::is_whitespace);
2299
2364
  let (Some(name), Some(field)) = (parts.next(), parts.next()) else {
2300
- return error("Usage: /mcp edit <name> command|args|icon <value>");
2365
+ return error("Usage: /mcp edit <name> command|args|icon|timeout <value>");
2301
2366
  };
2302
2367
  let value = parts.next().unwrap_or("").trim();
2368
+ if matches!(
2369
+ field.to_ascii_lowercase().as_str(),
2370
+ "timeout" | "timeoutsecs" | "timeout-secs"
2371
+ ) {
2372
+ return match crate::mcp::parse_mcp_timeout(value)
2373
+ .and_then(|seconds| crate::mcp::set_server_timeout_in(config, name, seconds))
2374
+ {
2375
+ Ok(true) => applied(format!("🔌 Updated `{name}` tool timeout.")),
2376
+ Ok(false) => error(format!("No MCP server named `{name}`.")),
2377
+ Err(e) => error(e),
2378
+ };
2379
+ }
2303
2380
  let edit = match field.to_ascii_lowercase().as_str() {
2304
2381
  "command" if !value.is_empty() => (Some(value.to_string()), None, None),
2305
2382
  "command" => return error("`/mcp edit <name> command <value>` needs a value"),
@@ -2313,7 +2390,7 @@ fn cmd_mcp(rest: &str, config: &mut MintConfig) -> SlashResponse {
2313
2390
  None,
2314
2391
  Some((!value.is_empty()).then(|| value.to_string())),
2315
2392
  ),
2316
- _ => return error("Editable fields: command | args | icon"),
2393
+ _ => return error("Editable fields: command | args | icon | timeout"),
2317
2394
  };
2318
2395
  match crate::update_server_in(config, name, edit.0, edit.1, None, edit.2) {
2319
2396
  Ok(true) => applied(format!("🔌 Updated `{name}`.")),
@@ -2429,6 +2506,7 @@ mod tests {
2429
2506
  input: input.to_string(),
2430
2507
  cwd: None,
2431
2508
  surface: None,
2509
+ chat_id: None,
2432
2510
  }
2433
2511
  }
2434
2512
 
@@ -2437,6 +2515,43 @@ mod tests {
2437
2515
  input: input.to_string(),
2438
2516
  cwd: None,
2439
2517
  surface: Some(surface.to_string()),
2518
+ chat_id: None,
2519
+ }
2520
+ }
2521
+
2522
+ #[test]
2523
+ fn mint_web_command_is_registered_and_validates_usage_on_all_surfaces() {
2524
+ for surface in ["cli", "desktop", "web"] {
2525
+ assert!(catalog::SLASH_COMMANDS.iter().any(
2526
+ |spec| spec.token == "/mint-web" && spec.surfaces.iter().any(|s| s == surface)
2527
+ ));
2528
+ match execute(
2529
+ &req_surface("/mint-web unexpected", surface),
2530
+ &mut MintConfig::default(),
2531
+ ) {
2532
+ SlashResponse::Message { markdown } => {
2533
+ assert!(markdown.contains("Usage: /mint-web"))
2534
+ }
2535
+ _ => panic!("Mint Web command was not routed on {surface}"),
2536
+ }
2537
+ }
2538
+ }
2539
+
2540
+ #[test]
2541
+ fn release_notes_are_available_on_every_surface() {
2542
+ for surface in ["cli", "desktop", "web"] {
2543
+ match execute(
2544
+ &req_surface("/release-notes", surface),
2545
+ &mut MintConfig::default(),
2546
+ ) {
2547
+ SlashResponse::Message { markdown } => {
2548
+ assert!(markdown.starts_with("# Release Notes - Mint Agent"));
2549
+ }
2550
+ other => panic!(
2551
+ "expected release notes on {surface}, got {}",
2552
+ serde_json::to_value(other).unwrap()
2553
+ ),
2554
+ }
2440
2555
  }
2441
2556
  }
2442
2557
 
@@ -2657,6 +2772,44 @@ mod tests {
2657
2772
  ));
2658
2773
  }
2659
2774
 
2775
+ #[test]
2776
+ fn review_timeout_slash_validates_without_corrupting_config_on_every_surface() {
2777
+ for surface in ["cli", "desktop", "web"] {
2778
+ let mut cfg = MintConfig::default();
2779
+ execute(&req_surface("/mcp add timer sh -c cat", surface), &mut cfg);
2780
+ for (field, value) in [("timeout", 1), ("timeoutSecs", 300), ("timeout-secs", 3600)] {
2781
+ let response = execute(
2782
+ &req_surface(&format!("/mcp edit timer {field} {value}"), surface),
2783
+ &mut cfg,
2784
+ );
2785
+ assert!(
2786
+ matches!(response, SlashResponse::Applied { .. }),
2787
+ "timeout edit was not applied on {surface}"
2788
+ );
2789
+ assert_eq!(cfg.extra["mcpServers"]["timer"]["timeoutSecs"], value);
2790
+ }
2791
+ let saved = cfg.extra.clone();
2792
+ for invalid in ["0", "3601", "1.5", "banana", ""] {
2793
+ assert!(matches!(
2794
+ execute(
2795
+ &req_surface(&format!("/mcp edit timer timeout {invalid}"), surface),
2796
+ &mut cfg
2797
+ ),
2798
+ SlashResponse::Message { .. }
2799
+ ));
2800
+ assert_eq!(cfg.extra, saved, "invalid input modified config");
2801
+ }
2802
+ assert!(matches!(
2803
+ execute(
2804
+ &req_surface("/mcp edit ghost timeout 600", surface),
2805
+ &mut cfg
2806
+ ),
2807
+ SlashResponse::Message { .. }
2808
+ ));
2809
+ assert_eq!(cfg.extra, saved);
2810
+ }
2811
+ }
2812
+
2660
2813
  #[test]
2661
2814
  fn mcp_registry_lists_the_catalog() {
2662
2815
  let mut cfg = MintConfig::default();
@@ -2743,6 +2896,16 @@ mod tests {
2743
2896
  }
2744
2897
  }
2745
2898
 
2899
+ #[test]
2900
+ fn mods_are_discoverable_in_help_on_every_surface() {
2901
+ for surface in ["cli", "desktop", "web"] {
2902
+ match execute(&req_surface("/help", surface), &mut MintConfig::default()) {
2903
+ SlashResponse::Message { markdown } => assert!(markdown.contains("`/mods`")),
2904
+ _ => panic!("expected help Message"),
2905
+ }
2906
+ }
2907
+ }
2908
+
2746
2909
  #[test]
2747
2910
  fn plan_toggles_and_forwards_task() {
2748
2911
  let mut cfg = MintConfig::default();