@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
@@ -0,0 +1,8 @@
1
+ import type { ModTestReport } from '../mods'
2
+
3
+ export function ModSessionControls({ enabled, busy, onToggle }: { enabled: boolean; busy: boolean; onToggle: (enabled: boolean) => void }) {
4
+ return <div className="mod-session-controls"><button type="button" disabled={busy} aria-pressed={enabled} onClick={() => onToggle(!enabled)}>Hot reload: {enabled ? 'On' : 'Off'}</button><p className="mod-hint">Applies to this session. Mods with permissions require review for each new revision.</p></div>
5
+ }
6
+ export function ModTestResults({ report }: { report: ModTestReport }) {
7
+ return <section aria-label="Mod test results"><p role="status">{report.passed} passed · {report.failed} failed</p>{report.tests.map((test,i) => <div key={i}><strong>{test.passed ? '✓' : '✗'} {test.name}</strong><p className="mod-hint">{test.file}</p>{test.error && <pre className="mod-error">{test.error}</pre>}</div>)}</section>
8
+ }
@@ -0,0 +1,65 @@
1
+ import React from 'react'
2
+ import { renderToStaticMarkup } from 'react-dom/server'
3
+ import { describe, it, expect } from 'vitest'
4
+ import { ModUi } from './ModUi'
5
+ import type { ModNode } from '../mods'
6
+ import { ModSessionControls, ModTestResults } from './ModSessionControls'
7
+ import { modViewport } from '../utils/modViewport'
8
+
9
+ describe('Mod UI', () => {
10
+ it('reports available band pixels and an estimated text width on both graphical surfaces', () => {
11
+ for (const surface of ['web','desktop'] as const) expect(modViewport(664,40,surface,true)).toEqual({surface,widthPx:640,heightPx:40,columns:80,rows:2,sidePanelOpen:true})
12
+ expect(modViewport(0,40,'web',false)).toBeNull()
13
+ })
14
+ it('shows session reload state and failing test diagnostics', () => {
15
+ const controls=renderToStaticMarkup(<ModSessionControls enabled busy={false} onToggle={() => {}} />)
16
+ expect(controls).toContain('aria-pressed="true"')
17
+ expect(controls).toContain('Hot reload')
18
+ const report=renderToStaticMarkup(<ModTestResults report={{ passed: 1, failed: 1, tests: [
19
+ { file: 'weather.test.ts', name: 'updates', passed: true },
20
+ { file: 'weather.test.ts', name: 'storm', passed: false, error: 'Expected Storm' },
21
+ ] }} />)
22
+ expect(report).toContain('1 passed')
23
+ expect(report).toContain('storm')
24
+ expect(report).toContain('Expected Storm')
25
+ })
26
+ it('inherits stack colors into controls and allows a child to restore default text', () => {
27
+ const html = renderToStaticMarkup(<ModUi node={{ type: 'stack', color: 'cyan', children: [
28
+ { type: 'button', label: 'Inspect', action: 'inspect' },
29
+ { type: 'badge', text: 'Measured' },
30
+ { type: 'text', text: 'Normal', color: 'default' },
31
+ ] }} onAction={() => {}} />)
32
+ expect(html).toContain('<button class="mod-color-cyan"')
33
+ expect(html).toContain('mod-badge mod-color-cyan')
34
+ expect(html).toContain('mod-text mod-color-default')
35
+ })
36
+ it('renders a weather row with a colored label and uncolored metrics', () => {
37
+ const html = renderToStaticMarkup(<ModUi node={{ type: 'stack', direction: 'row', children: [
38
+ { type: 'text', text: '☂ Showers', color: 'blue' },
39
+ { type: 'text', text: '67.2% · 134.4k / 200k · ▁▂▃▄▅▆▇█ · ▲ +98.3k last turn' },
40
+ ] } as ModNode} onAction={() => {}} />)
41
+ expect(html).toContain('mod-stack-row')
42
+ expect(html).toContain('mod-color-blue')
43
+ expect(html).toContain('☂ Showers')
44
+ expect(html).toContain('134.4k / 200k')
45
+ })
46
+ it('renders text literally and exposes a labeled control', () => {
47
+ const html = renderToStaticMarkup(<ModUi node={{ type: 'stack', children: [
48
+ { type: 'text', text: '<script>literal</script>' },
49
+ { type: 'button', label: 'Add task', action: 'add' },
50
+ ] }} onAction={() => {}} />)
51
+ expect(html).toContain('&lt;script&gt;literal&lt;/script&gt;')
52
+ expect(html).toContain('Add task')
53
+ expect(html).not.toContain('<script>')
54
+ })
55
+ it('renders accessible progress and tabular data', () => {
56
+ const html = renderToStaticMarkup(<ModUi node={{ type: 'stack', children: [
57
+ { type: 'progress', label: 'Budget', value: 20, max: 100 },
58
+ { type: 'table', columns: ['Task'], rows: [['Write tests']] },
59
+ ] }} onAction={() => {}} />)
60
+ expect(html).toContain('aria-label="Budget"')
61
+ expect(html).toContain('value="20"')
62
+ expect(html).toContain('<th>Task</th>')
63
+ expect(html).toContain('<td>Write tests</td>')
64
+ })
65
+ })
@@ -0,0 +1,26 @@
1
+ import { useEffect, useState } from 'react'
2
+ import type { ModNode } from '../mods'
3
+
4
+ function ModInput({ node, color, onAction }: { node: ModNode; color: string; onAction: (action: string, value?: string) => void }) {
5
+ const value = String(node.value ?? '')
6
+ const [draft, setDraft] = useState(value)
7
+ useEffect(() => { setDraft(value) }, [value, node.action])
8
+ return <label className={`mod-input${color}`}>{node.label}<input value={draft} onChange={event => setDraft(event.target.value)} onKeyDown={event => {
9
+ if (event.key === 'Enter' && node.action) { event.preventDefault(); onAction(node.action, event.currentTarget.value) }
10
+ }} /></label>
11
+ }
12
+
13
+ export function ModUi({ node, onAction, inheritedColor }: { node: ModNode; onAction: (action: string, value?: string) => void; inheritedColor?: ModNode['color'] }) {
14
+ const selectedColor = node.color ?? inheritedColor
15
+ const color = ['default', 'yellow', 'cyan', 'blue', 'magenta', 'red'].includes(selectedColor ?? '') ? ` mod-color-${selectedColor}` : ''
16
+ switch (node.type) {
17
+ case 'stack': return <div className={`mod-stack${node.direction === 'row' ? ' mod-stack-row' : ''}${color}`}>{node.children?.map((child, i) => <ModUi key={i} node={child} onAction={onAction} inheritedColor={selectedColor} />)}</div>
18
+ case 'text': return <p className={`mod-text${color}`}>{node.text}</p>
19
+ case 'badge': return <span className={`mod-badge${color}`}>{node.text}</span>
20
+ case 'button': return <button className={color.trim() || undefined} type="button" onClick={() => node.action && onAction(node.action)}>{node.label}</button>
21
+ case 'input': return <ModInput node={node} color={color} onAction={onAction} />
22
+ case 'progress': return <label className={`mod-progress${color}`}>{node.label}<progress aria-label={node.label} value={Number(node.value)} max={node.max} /></label>
23
+ case 'table': return <div className={`mod-table-scroll${color}`}><table><thead><tr>{node.columns?.map((column, i) => <th key={i}>{column}</th>)}</tr></thead><tbody>{node.rows?.map((row, i) => <tr key={i}>{row.map((cell, j) => <td key={j}>{cell}</td>)}</tr>)}</tbody></table></div>
24
+ default: return null
25
+ }
26
+ }
@@ -516,7 +516,15 @@ export default function ModelSelectorPopover({
516
516
 
517
517
  // Keyboard navigation
518
518
  const handleKeyDown = (e: React.KeyboardEvent) => {
519
- if (!isOpen) return
519
+ if (!isOpen || e.nativeEvent.isComposing) return
520
+ if (e.key === 'Escape') {
521
+ e.preventDefault()
522
+ setIsOpen(false)
523
+ triggerRef.current?.focus()
524
+ return
525
+ }
526
+ // Let tabs and thinking controls keep their own keyboard behavior.
527
+ if (mobilePane !== 'models' || e.target instanceof HTMLButtonElement) return
520
528
 
521
529
  if (e.key === 'ArrowDown') {
522
530
  e.preventDefault()
@@ -536,11 +544,8 @@ export default function ModelSelectorPopover({
536
544
  if (item) {
537
545
  onSelect(item.providerId, item.model)
538
546
  setIsOpen(false)
547
+ triggerRef.current?.focus()
539
548
  }
540
- } else if (e.key === 'Escape') {
541
- e.preventDefault()
542
- setIsOpen(false)
543
- triggerRef.current?.focus()
544
549
  }
545
550
  }
546
551
 
@@ -645,6 +650,7 @@ export default function ModelSelectorPopover({
645
650
  ref={searchInputRef}
646
651
  type="text"
647
652
  className="model-spotlight-input"
653
+ aria-label="Search models"
648
654
  placeholder="Search models..."
649
655
  value={search}
650
656
  onChange={(e) => setSearch(e.target.value)}
@@ -716,7 +722,8 @@ export default function ModelSelectorPopover({
716
722
  onClick={() => {
717
723
  setInspectedItem({ providerId: group.providerId, model: m })
718
724
  onSelect(group.providerId, m)
719
- if (window.matchMedia('(max-width: 760px)').matches) setMobilePane('options')
725
+ setIsOpen(false)
726
+ triggerRef.current?.focus()
720
727
  }}
721
728
  onMouseEnter={() => {
722
729
  setHighlightedIndex(currentIndex)
@@ -870,7 +877,7 @@ export default function ModelSelectorPopover({
870
877
  </div>
871
878
 
872
879
  {!inspectedThinking.supported && (
873
- <div className="model-unsupported-note" style={{ color: inspectedThinking.enabled ? 'var(--accent, #10b981)' : undefined }}>
880
+ <div className="model-unsupported-note" style={{ color: inspectedThinking.enabled ? 'var(--interactive-fg)' : undefined }}>
874
881
  {inspectedThinking.enabled
875
882
  ? 'Thinking enabled (force toggle)'
876
883
  : 'Not flagged as reasoning model by default (toggle to force enable)'}
@@ -0,0 +1,156 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'react'
2
+ import { createPortal } from 'react-dom'
3
+ import { ChevronDown, Puzzle, Upload } from 'lucide-react'
4
+ import { modsPlatform, runtimePlatform } from '../platform'
5
+ import type { ModOperation, ModRecord, ModResponse, ModTestReport } from '../mods'
6
+ import { ModUi } from './ModUi'
7
+ import { ModSessionControls, ModTestResults } from './ModSessionControls'
8
+ import { modViewport } from '../utils/modViewport'
9
+ import '../css/mods.css'
10
+
11
+ export function ModsPanel({ workspacePath, chatId, panelTarget, onOpen }: { workspacePath?: string | null; chatId: string; panelTarget?: HTMLElement | null; onOpen: () => void }) {
12
+ const [data, setData] = useState<ModResponse>({ mods: [] })
13
+ const open = Boolean(panelTarget)
14
+ const onOpenRef = useRef(onOpen); onOpenRef.current = onOpen
15
+ const [tab, setTab] = useState('manage')
16
+ const [error, setError] = useState('')
17
+ const [busy, setBusy] = useState(false)
18
+ const [loading, setLoading] = useState(true)
19
+ const [reports, setReports] = useState<Record<string, ModTestReport>>({})
20
+ const rootRef = useRef<HTMLDivElement>(null)
21
+ const openRef = useRef(open); openRef.current = open
22
+ const currentScope = useRef('')
23
+ currentScope.current = `${workspacePath}\0${chatId}`
24
+ const [scope, setScope] = useState<'chat' | 'workspace' | 'global'>('chat')
25
+ const generation = useRef(0)
26
+ const importRef = useRef<HTMLInputElement>(null)
27
+ const seen = useRef(new Set<string>())
28
+
29
+ useEffect(() => {
30
+ const current = ++generation.current
31
+ let stopped = false
32
+ let timer: ReturnType<typeof setTimeout>
33
+ setData({ mods: [] }); setLoading(Boolean(workspacePath && chatId)); setBusy(false); setError(''); setTab('manage'); seen.current.clear(); setReports({})
34
+ async function refresh() {
35
+ if (!workspacePath || !chatId || stopped) return
36
+ try {
37
+ const value = await modsPlatform.operation({ workspacePath, chatId, action: 'list' })
38
+ if (!stopped && generation.current === current) {
39
+ setData(value); setLoading(false)
40
+ const fresh = value.mods?.find(m => m.enabled && m.snapshot?.ui.side_panel && !seen.current.has(m.id))
41
+ value.mods?.filter(m => m.enabled).forEach(m => seen.current.add(m.id))
42
+ if (fresh) { onOpenRef.current(); setTab(fresh.id) }
43
+ }
44
+ } catch (e) { if (!stopped && generation.current === current) { setError(String(e)); setLoading(false) } }
45
+ if (!stopped) timer = setTimeout(refresh, 1000)
46
+ }
47
+ void refresh()
48
+ return () => {
49
+ stopped = true; clearTimeout(timer)
50
+ if (workspacePath && chatId) void modsPlatform.operation({ workspacePath, chatId, action: 'close' }).catch(() => {})
51
+ }
52
+ }, [workspacePath, chatId])
53
+
54
+ useEffect(() => {
55
+ const element=rootRef.current
56
+ if (!element || !workspacePath || !chatId) return
57
+ let stopped=false
58
+ let previous=''
59
+ let timer: ReturnType<typeof setTimeout> | undefined
60
+ const surface=runtimePlatform.isTauriRuntime() ? 'desktop' as const : 'web' as const
61
+ async function reportViewport() {
62
+ if (stopped) return
63
+ const bounds=element!.getBoundingClientRect()
64
+ const viewport=modViewport(bounds.width,bounds.height,surface,openRef.current)
65
+ if (!viewport) return
66
+ const signature=JSON.stringify(viewport)
67
+ if (signature===previous) return
68
+ previous=signature
69
+ try { await modsPlatform.operation({ workspacePath: workspacePath!, chatId, action: 'viewport', viewport }) }
70
+ catch (e) { if (!stopped) setError(String(e)) }
71
+ }
72
+ const schedule=() => { clearTimeout(timer); timer=setTimeout(() => { void reportViewport() }, 100) }
73
+ const observer=typeof ResizeObserver==='undefined' ? undefined : new ResizeObserver(schedule)
74
+ observer?.observe(element); window.addEventListener('resize',schedule); schedule()
75
+ return () => { stopped=true; clearTimeout(timer); observer?.disconnect(); window.removeEventListener('resize',schedule) }
76
+ }, [workspacePath, chatId, open])
77
+
78
+ const operate = useCallback(async (operation: Omit<ModOperation, 'workspacePath' | 'chatId'>) => {
79
+ if (!workspacePath || currentScope.current !== `${workspacePath}\0${chatId}`) return
80
+ const current = generation.current
81
+ setBusy(true); setError('')
82
+ try {
83
+ const value = await modsPlatform.operation({ ...operation, workspacePath, chatId })
84
+ if (current !== generation.current) return
85
+ if (value.testReport && operation.id) setReports(current => ({ ...current, [operation.id!]: value.testReport! }))
86
+ if (value.package) {
87
+ const bytes = Uint8Array.from(atob(value.package), c => c.charCodeAt(0))
88
+ const url = URL.createObjectURL(new Blob([bytes], { type: 'application/zip' }))
89
+ const link = document.createElement('a'); link.href = url; link.download = value.filename || 'mod.mintmod'; link.click(); URL.revokeObjectURL(url)
90
+ }
91
+ const latest = await modsPlatform.operation({ workspacePath, chatId, action: 'list' })
92
+ if (current === generation.current) setData(latest)
93
+ } catch (e) { if (current === generation.current) setError(String(e)) }
94
+ finally { if (current === generation.current) setBusy(false) }
95
+ }, [workspacePath, chatId])
96
+
97
+ const activate = (mod: ModRecord) => {
98
+ const permissions = mod.manifest?.permissions || []
99
+ if (permissions.length && !window.confirm(`Enable ${mod.name}?\nRevision: ${mod.hash}\nPermissions: ${permissions.join(', ')}\nReview the source below before approving.`)) return
100
+ if (scope !== 'chat' && !window.confirm(`Enable ${mod.name} for ${scope === 'global' ? 'all workspaces as a personal copy' : 'all chats in this workspace'}?`)) return
101
+ void operate({ action: 'enable', id: mod.id, scope, expectedHash: mod.hash, grantPermissions: permissions.length > 0 })
102
+ }
103
+ const action = (mod: ModRecord, name: string, value?: string) => void operate({ action: 'action', id: mod.id, instanceId: mod.instanceId, command: name, value })
104
+ const mods = data.mods || []
105
+ const active = mods.filter(m => m.enabled)
106
+ const sidePanelMods = active.filter(m => m.snapshot?.ui.side_panel)
107
+ const selected = mods.find(m => m.id === tab)
108
+
109
+ return <>
110
+ <div className="mint-mods" ref={rootRef}>
111
+ {active.map(mod => mod.snapshot?.ui.above_composer && <section key={mod.id} className="mod-band" aria-label={mod.name}>
112
+ <ModUi node={mod.snapshot.ui.above_composer} onAction={(name, value) => action(mod, name, value)} />
113
+ </section>)}
114
+ {panelTarget && createPortal(<aside className="mods-panel mint-mods" aria-label="Workspace mods">
115
+ <header className="mods-panel-header"><span className="mods-panel-icon" aria-hidden="true"><Puzzle size={18} /></span><div className="mods-panel-title"><strong>Mods</strong><p>{mods.length} installed · {active.length} active</p></div></header>
116
+ {sidePanelMods.length > 0 && <nav aria-label="Mod panels"><button type="button" aria-pressed={tab === 'manage'} onClick={() => setTab('manage')}>Manage</button>{sidePanelMods.map(m => <button key={m.id} type="button" aria-pressed={tab === m.id} onClick={() => setTab(m.id)}>{m.name}</button>)}</nav>}
117
+ {error && <p role="alert" className="mod-error">{error}</p>}
118
+ {selected?.snapshot?.ui.side_panel && tab !== 'manage' ? <section className="mod-content"><ModUi node={selected.snapshot.ui.side_panel} onAction={(name, value) => action(selected, name, value)} /></section> : <div className="mod-content">
119
+ <div className="mods-toolbar"><label htmlFor="mods-scope">Enable for <select id="mods-scope" value={scope} onChange={e => setScope(e.target.value as typeof scope)}><option value="chat">This chat</option><option value="workspace">This workspace</option><option value="global">All workspaces</option></select></label><button type="button" className="mods-import" disabled={busy || !workspacePath || !chatId} onClick={() => importRef.current?.click()}><Upload size={14} aria-hidden="true" />Import</button></div>
120
+ <input ref={importRef} type="file" accept=".mintmod" hidden onChange={async e => {
121
+ const file = e.target.files?.[0]; e.target.value = ''; if (!file) return
122
+ if (file.size > 1024 * 1024) { setError('Package exceeds 1 MiB'); return }
123
+ const bytes = new Uint8Array(await file.arrayBuffer())
124
+ let binary = ''; for (const b of bytes) binary += String.fromCharCode(b)
125
+ const packed = btoa(binary)
126
+ if (currentScope.current !== `${workspacePath}\0${chatId}`) return
127
+ try {
128
+ const info = await modsPlatform.operation({ workspacePath: workspacePath!, chatId, action: 'inspect_package', package: packed })
129
+ if (currentScope.current !== `${workspacePath}\0${chatId}`) return
130
+ if (info.expectedHash && !window.confirm(`Replace source for ${info.id}? The active revision stays unchanged until you enable the imported source.`)) return
131
+ await operate({ action: 'import', package: packed, expectedHash: info.expectedHash || undefined })
132
+ } catch (e) { if (currentScope.current === `${workspacePath}\0${chatId}`) setError(String(e)) }
133
+ }} />
134
+ {loading && <p role="status" className="mods-empty">Loading mods…</p>}
135
+ {!loading && !mods.length && <div className="mods-empty"><Puzzle size={22} aria-hidden="true" /><strong>{workspacePath ? 'No mods yet' : 'Choose a workspace'}</strong><p>{workspacePath ? 'Ask Mint to create one, or import a .mintmod package. Imported mods stay off until enabled.' : 'Choose a workspace in chat to manage its mods.'}</p></div>}
136
+ {mods.map(mod => <article key={mod.id} className="mod-entry">
137
+ <div className="mod-entry-heading"><div><strong>{mod.name}</strong><small>Version {mod.manifest?.version || 'unknown'}</small></div><span className={`mod-status ${mod.error ? 'is-error' : mod.enabled ? 'is-active' : ''}`}>{mod.error ? 'Error' : mod.enabled ? 'Active' : 'Off'}</span></div>
138
+ {mod.changed && <p className="mod-hint">Source changed · active revision preserved</p>}
139
+ {mod.reloadError && <p role="alert" className="mod-error">Reload: {mod.reloadError}</p>}
140
+ {(mod.error || mod.sourceError) && <p role="alert" className="mod-error">{mod.error || mod.sourceError}</p>}
141
+ <p className="mod-hint">{mod.manifest?.permissions?.join(', ') || 'UI, events and mod state'}</p>
142
+ <div className="mod-entry-footer"><button type="button" className={`mod-primary-action ${mod.enabled && !mod.changed ? 'is-disable' : ''}`} disabled={busy || !mod.manifest} onClick={() => mod.enabled && !mod.changed ? void operate({ action: 'disable', id: mod.id }) : activate(mod)}>{mod.enabled && !mod.changed ? 'Disable' : mod.changed ? 'Validate & reload' : 'Enable'}</button>
143
+ <details className="mod-entry-more"><summary>More options <ChevronDown size={13} aria-hidden="true" /></summary>
144
+ <div className="mod-actions"><button type="button" disabled={busy || !mod.source} onClick={() => void operate({ action: 'export', id: mod.id })}>Export</button><button type="button" disabled={busy || !mod.source} onClick={() => void operate({ action: 'test', id: mod.id })}>Run tests</button></div>
145
+ {reports[mod.id] && <ModTestResults report={reports[mod.id]} />}
146
+ <details><summary>Source & diagnostics</summary><pre>{mod.source}</pre><pre>{mod.snapshot?.logs?.join('\n') || 'No log messages'}</pre><p className="mod-hint">Active revision: {mod.activeHash || 'None'}</p></details>
147
+ {mod.revisions.length > 1 && <label className="mod-revisions">Restore source revision <select value="" disabled={busy} onChange={e => { const hash = e.target.value; if (hash && window.confirm('Restore this source revision? Review and enable it after restoring.')) void operate({ action: 'rollback', id: mod.id, hash, expectedHash: mod.hash }) }}><option value="">Choose revision</option>{mod.revisions.filter(h => h !== mod.hash).map(h => <option key={h} value={h}>{h.slice(0, 12)}</option>)}</select></label>}
148
+ </details></div>
149
+ </article>)}
150
+ {data.toolRequests?.map(request => <article className="mod-entry" key={request.id}><strong>{request.modId}: {request.action}</strong><pre>{JSON.stringify(request.input, null, 2)}</pre><button type="button" disabled={busy} onClick={() => { if (window.confirm(`Run ${request.action} requested by ${request.modId}?\n${JSON.stringify(request.input, null, 2)}`)) void operate({ action: 'run_request', command: request.id, grantPermissions: true }) }}>Review & run tool</button></article>)}
151
+ <details className="mod-session-settings"><summary>Session settings <ChevronDown size={13} aria-hidden="true" /></summary><ModSessionControls enabled={data.session?.hotReload ?? false} busy={busy} onToggle={enabled => void operate({ action: 'hot_reload', value: enabled })} /></details>
152
+ </div>}
153
+ </aside>, panelTarget)}
154
+ </div>
155
+ </>
156
+ }
@@ -0,0 +1,17 @@
1
+ import { memo, useCallback } from 'react'
2
+ import type { AgentProgress } from '../types'
3
+ import { activitiesFrom } from '../utils/agentActivity'
4
+ import { AgentActivityDrawer } from './AgentActivityDrawer'
5
+
6
+ export const ProgressActivity = memo(function ProgressActivity({ progress, id, isOpen, onToggle, historical = false, pendingApproval = false }: {
7
+ progress: AgentProgress[]
8
+ id: string
9
+ isOpen: boolean
10
+ onToggle: (id: string) => void
11
+ historical?: boolean
12
+ pendingApproval?: boolean
13
+ }) {
14
+ const toggle = useCallback(() => onToggle(id), [id, onToggle])
15
+ return <AgentActivityDrawer activityView={activitiesFrom(progress)} rawProgress={progress}
16
+ isOpen={isOpen} onToggle={toggle} isHistorical={historical} pendingApproval={pendingApproval} />
17
+ })
@@ -0,0 +1,42 @@
1
+ import { useEffect, useRef } from 'react'
2
+ import type { WorkspaceHistoryEntry } from '../types'
3
+
4
+ export function undoDescription(entry: WorkspaceHistoryEntry) {
5
+ switch (entry.kind) {
6
+ case 'edit': return entry.backup ? 'Restore the saved content from before this edit.' : 'Move the file created by this edit to Trash.'
7
+ case 'create': return 'Move this created file or folder to Trash.'
8
+ case 'trash': return 'Restore this file or folder to its original location.'
9
+ case 'move': return `Move ${entry.destination || entry.path} back to ${entry.path}.`
10
+ default: return entry.label
11
+ }
12
+ }
13
+
14
+ export function HistoryDetails({ entry }: { entry: WorkspaceHistoryEntry }) {
15
+ return <dl className="review-history-details">
16
+ <dt>File</dt><dd>{entry.path}</dd>
17
+ <dt>Action</dt><dd>{entry.label.replace(/^Undo /, '')}</dd>
18
+ {entry.destination && <><dt>Destination</dt><dd>{entry.destination}</dd></>}
19
+ <dt>Undo will</dt><dd>{undoDescription(entry)}</dd>
20
+ </dl>
21
+ }
22
+
23
+ export function UndoConfirmation({ entry, busy, error, onCancel, onConfirm }: {
24
+ entry: WorkspaceHistoryEntry; busy: boolean; error: string; onCancel: () => void; onConfirm: () => void
25
+ }) {
26
+ const dialog = useRef<HTMLDialogElement>(null)
27
+ useEffect(() => {
28
+ const element = dialog.current
29
+ element?.showModal()
30
+ return () => element?.close()
31
+ }, [])
32
+ return <dialog ref={dialog} className="review-undo-dialog" aria-labelledby="review-undo-title" onCancel={event => { event.preventDefault(); if (!busy) onCancel() }}>
33
+ <h3 id="review-undo-title">Confirm Undo</h3>
34
+ <HistoryDetails entry={entry} />
35
+ <p>Undo is refused if the file has changed since this action or the destination is occupied.</p>
36
+ {error && <p role="alert">{error}</p>}
37
+ <div className="review-undo-actions">
38
+ <button type="button" autoFocus disabled={busy} onClick={onCancel}>Cancel</button>
39
+ <button type="button" disabled={busy} onClick={onConfirm}>{busy ? 'Undoing…' : 'Confirm Undo'}</button>
40
+ </div>
41
+ </dialog>
42
+ }
@@ -1,3 +1,4 @@
1
+ import SelectField from './SelectField'
1
2
  import React, { useState, useEffect } from 'react'
2
3
  import type { GitCheckpoint, FileChange } from '../types'
3
4
 
@@ -192,26 +193,18 @@ export const RewindModal: React.FC<RewindModalProps> = ({
192
193
  Target Checkpoint
193
194
  </span>
194
195
  {checkpoints.length > 1 && (
195
- <select
196
+ <SelectField aria-label="Target checkpoint" fullWidth={false}
196
197
  value={selectedStep}
197
- onChange={(e) => setSelectedStep(Number(e.target.value))}
198
+ onValueChange={(nextValue) => setSelectedStep(Number(nextValue))}
198
199
  disabled={isLoading}
199
- style={{
200
- background: 'var(--input-bg, #111)',
201
- color: 'var(--text-main)',
202
- border: '1px solid var(--border)',
203
- borderRadius: '6px',
204
- fontSize: '12px',
205
- padding: '3px 8px',
206
- cursor: 'pointer',
207
- }}
200
+
208
201
  >
209
202
  {checkpoints.map((cp) => (
210
203
  <option key={cp.step} value={cp.step}>
211
204
  Step {cp.step} ({cp.commitHash.slice(0, 7)})
212
205
  </option>
213
206
  ))}
214
- </select>
207
+ </SelectField>
215
208
  )}
216
209
  </div>
217
210
 
@@ -32,19 +32,13 @@ export function RunSummaryDashboard({ summary, className = '' }: Props) {
32
32
  ? 'run-summary-badge rollback'
33
33
  : 'run-summary-badge failure'
34
34
 
35
- const statusColor = isSuccess
36
- ? 'var(--status-speaking, #22c55e)'
37
- : isRolledBack
38
- ? '#f59e0b'
39
- : 'var(--status-error, #ef4444)'
40
-
41
35
  return (
42
36
  <div className={`run-summary-card ${className}`}>
43
37
  {/* Header */}
44
38
  <div className="run-summary-header">
45
39
  <div className="run-summary-title">
46
- <Activity style={{ width: '15px', height: '15px', color: statusColor }} />
47
- <span>Run telemetry #{summary.runId}</span>
40
+ <Activity size={16} aria-hidden="true" />
41
+ <span className="run-summary-heading"><strong>Run summary</strong><small title={`Run ${summary.runId}`}>#{summary.runId}</small></span>
48
42
  </div>
49
43
  <div>
50
44
  <span className={badgeClass}>
@@ -80,8 +74,8 @@ export function RunSummaryDashboard({ summary, className = '' }: Props) {
80
74
  <span>Tools</span>
81
75
  </div>
82
76
  <div className="run-kpi-value">
83
- {summary.toolCallsCount}{' '}
84
- <span className="run-kpi-subtext">({summary.retriesCount} retry)</span>
77
+ {summary.toolCallsCount}
78
+ {summary.retriesCount > 0 && <span className="run-kpi-subtext"> · {summary.retriesCount} retried</span>}
85
79
  </div>
86
80
  </div>
87
81
 
@@ -100,12 +94,12 @@ export function RunSummaryDashboard({ summary, className = '' }: Props) {
100
94
  {summary.filesCreated.length}{' '}
101
95
  <span className="run-kpi-subtext">created</span>
102
96
  </>
103
- ) : (
97
+ ) : summary.filesChanged.length > 0 ? (
104
98
  <>
105
99
  {summary.filesChanged.length}{' '}
106
100
  <span className="run-kpi-subtext">modified</span>
107
101
  </>
108
- )}
102
+ ) : <>0 <span className="run-kpi-subtext">files</span></>}
109
103
  </div>
110
104
  </div>
111
105
  </div>
@@ -1,3 +1,4 @@
1
+ import SelectField from './SelectField'
1
2
  import React, { useState, useEffect, useMemo } from 'react'
2
3
  import { DateTime } from 'luxon'
3
4
  import { renderScheduledTasksSvgIcon, renderTaskLogoIcon } from '../constants/plugins'
@@ -465,17 +466,17 @@ export const ScheduledTasksView: React.FC<ScheduledTasksViewProps> = React.memo(
465
466
  <div className="management-form-group">
466
467
  <label className="management-label">When to run</label>
467
468
  <div className="schedule-inline-row">
468
- <select
469
+ <SelectField fullWidth={false} aria-label="When to run"
469
470
  className="management-input-field schedule-repeat-select"
470
471
  value={repeatMode}
471
- onChange={(e) => setRepeatMode(e.target.value as typeof repeatMode)}
472
+ onValueChange={(nextValue) => setRepeatMode(nextValue as typeof repeatMode)}
472
473
  >
473
474
  <option value="daily">Daily</option>
474
475
  <option value="weekly">Weekly</option>
475
476
  <option value="monthly">Monthly</option>
476
477
  <option value="once">One-time</option>
477
478
  <option value="custom">Custom (cron)</option>
478
- </select>
479
+ </SelectField>
479
480
 
480
481
  {repeatMode === 'weekly' && (
481
482
  <>
@@ -534,17 +535,17 @@ export const ScheduledTasksView: React.FC<ScheduledTasksViewProps> = React.memo(
534
535
  onChange={(e) => setTimeOfDay(e.target.value)}
535
536
  required
536
537
  />
537
- <select
538
+ <SelectField fullWidth={false} aria-label="Time zone"
538
539
  className="management-input-field schedule-timezone-select"
539
540
  value={taskTimezone}
540
- onChange={(e) => setTaskTimezone(e.target.value)}
541
+ onValueChange={(nextValue) => setTaskTimezone(nextValue)}
541
542
  >
542
543
  {timezoneOptions.map((tz) => (
543
544
  <option key={tz} value={tz}>
544
545
  {tz}
545
546
  </option>
546
547
  ))}
547
- </select>
548
+ </SelectField>
548
549
  </div>
549
550
  )}
550
551
  </div>
@@ -0,0 +1,27 @@
1
+ import React from 'react'
2
+ import { renderToStaticMarkup } from 'react-dom/server'
3
+ import { describe, expect, it } from 'vitest'
4
+
5
+ import SelectField from './SelectField'
6
+
7
+ describe('Mint dropdown field', () => {
8
+ it('preserves a controlled numeric checkpoint and its accessible label', async () => {
9
+ const html = renderToStaticMarkup(<SelectField value={2} id="checkpoint" aria-label="Target checkpoint" disabled>
10
+ <option value={1}>Step 1</option><option value={2}>Step 2</option>
11
+ </SelectField>)
12
+ expect(html).toContain('Step 2')
13
+ expect(html).toContain('role="combobox"')
14
+ expect(html).toContain('id="checkpoint"')
15
+ expect(html).toContain('aria-label="Target checkpoint"')
16
+ expect(html).toContain('disabled=""')
17
+ })
18
+ it('preserves conditional and mapped labels, including a custom model entry', async () => {
19
+ const html = renderToStaticMarkup(<SelectField value="custom">
20
+ {['a','b'].map(v=><option key={v} value={v}>{v}</option>)}
21
+ {false && <option value="hidden">Hidden</option>}
22
+ <option value="custom">Custom model ID…</option>
23
+ </SelectField>)
24
+ expect(html).toContain('Custom model ID…')
25
+ expect(html).not.toContain('Hidden')
26
+ })
27
+ })
@@ -0,0 +1,38 @@
1
+ import { Children, Fragment, isValidElement, type CSSProperties, type ReactNode } from 'react'
2
+ import GlideSelect, { type GlideOption } from './GlideSelect'
3
+
4
+ interface SelectFieldProps {
5
+ children: ReactNode
6
+ value?: string | number
7
+ defaultValue?: string | number
8
+ onValueChange?: (value: string) => void
9
+ disabled?: boolean
10
+ id?: string
11
+ 'aria-label'?: string
12
+ 'aria-labelledby'?: string
13
+ className?: string
14
+ title?: string
15
+ style?: CSSProperties
16
+ fullWidth?: boolean
17
+ }
18
+
19
+ function optionsFromChildren(children: ReactNode): GlideOption[] {
20
+ return Children.toArray(children).flatMap(child => {
21
+ if (!isValidElement<{ value?: string | number; children?: ReactNode }>(child)) return []
22
+ if (child.type === Fragment) return optionsFromChildren(child.props.children)
23
+ if (child.type !== 'option') return []
24
+ const label = Children.toArray(child.props.children).join('')
25
+ return [{ value: String(child.props.value ?? label), label }]
26
+ })
27
+ }
28
+
29
+ /** Shared field adapter keeps Mint's dynamic option lists and value callbacks intact. */
30
+ export default function SelectField({ children, value, defaultValue, onValueChange, disabled,
31
+ id, 'aria-label': ariaLabel, 'aria-labelledby': labelledBy, className, title, style, fullWidth = true }: SelectFieldProps) {
32
+ return <GlideSelect options={optionsFromChildren(children)}
33
+ value={value === undefined ? undefined : String(value)}
34
+ defaultValue={defaultValue === undefined ? undefined : String(defaultValue)}
35
+ onChange={onValueChange} disabled={disabled} id={id} ariaLabel={ariaLabel ?? title ?? 'Select'} labelledBy={labelledBy}
36
+ className={className ? `mint-select-field ${className}` : 'mint-select-field'} title={title}
37
+ style={style} fullWidth={fullWidth} />
38
+ }
@@ -0,0 +1,48 @@
1
+ import { useState } from 'react'
2
+ import { File, FileText, Globe, Image, Paperclip, Video } from 'lucide-react'
3
+ import type { SessionSource } from '../utils/sessionSources'
4
+ import '../css/session-sources.css'
5
+
6
+ function SourceIcon({ source }: { source: SessionSource }) {
7
+ const src = source.kind === 'web' ? source.faviconUrl : source.thumbnailDataUri
8
+ const [failedSrc, setFailedSrc] = useState<string>()
9
+ const Icon = source.kind === 'web' ? Globe : source.kind === 'image' ? Image : source.kind === 'video' ? Video : /\.(pdf|md|txt|docx?)$/i.test(source.name) ? FileText : File
10
+ return <span className={`session-source-icon is-${source.kind}`}>
11
+ {src && src !== failedSrc ? <img src={src} alt="" loading="lazy" referrerPolicy="no-referrer" onError={() => setFailedSrc(src)} /> : <Icon size={15} aria-hidden="true" />}
12
+ </span>
13
+ }
14
+
15
+ export default function SessionSources({ sources, loading, error, onRetry, onOpenLibrary }: {
16
+ sources: SessionSource[]; loading: boolean; error: string; onRetry: () => void; onOpenLibrary: (url: string) => void
17
+ }) {
18
+ const [expanded, setExpanded] = useState(false)
19
+ const groups = [
20
+ { label: 'Images', kinds: ['image'] },
21
+ { label: 'Files', kinds: ['file', 'video'] },
22
+ { label: 'Web searches', kinds: ['web'] },
23
+ ]
24
+ const initialSources = groups.flatMap(group => sources.filter(source => group.kinds.includes(source.kind)).slice(0, 2))
25
+ const shown = expanded ? sources : initialSources
26
+ return <section className="session-sources" aria-label="Session sources">
27
+ <header className="session-sources-heading"><span><Paperclip size={13} aria-hidden="true" />Sources <small>This session</small></span><span>{sources.length}</span></header>
28
+ {loading && <p className="session-sources-empty" role="status">Loading session sources…</p>}
29
+ {error && <div className="session-sources-error" role="status"><span>Could not load saved sources.</span><button type="button" onClick={onRetry}>Retry</button></div>}
30
+ {!loading && !error && sources.length === 0 && <p className="session-sources-empty">Images and files you send, and pages found by web search, will appear here.</p>}
31
+ {groups.map(group => {
32
+ const items = shown.filter(source => group.kinds.includes(source.kind))
33
+ if (!items.length) return null
34
+ return <div className="session-sources-group" key={group.label}>
35
+ <h3>{group.label}</h3>
36
+ <ul>{items.map(source => {
37
+ const content = <><SourceIcon source={source} /><span className="session-source-copy"><strong>{source.name}</strong><small>{source.detail}</small></span></>
38
+ return <li key={source.id}>{source.url ? <a className="session-source-row" href={source.url} target={source.kind === 'web' ? '_blank' : undefined} rel={source.kind === 'web' ? 'noopener noreferrer' : undefined} title={source.url} onClick={event => {
39
+ if (source.kind === 'web' || event.button !== 0 || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) return
40
+ event.preventDefault()
41
+ onOpenLibrary(source.url)
42
+ }}>{content}</a> : <div className="session-source-row" title={source.name}>{content}</div>}</li>
43
+ })}</ul>
44
+ </div>
45
+ })}
46
+ {sources.length > initialSources.length && <button type="button" className="session-sources-more" aria-expanded={expanded} onClick={() => setExpanded(value => !value)}>{expanded ? 'Show less' : `Show ${sources.length - shown.length} more sources`}</button>}
47
+ </section>
48
+ }