@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
@@ -1,3 +1,4 @@
1
+ import SelectField from '../SelectField'
1
2
  import React, { useState } from 'react'
2
3
  import { DEFAULT_CONFIG } from '../../constants/config'
3
4
  import { THEME_PRESETS, ACCENT_FLAVORS, ThemePreset, AccentFlavor } from '../../theme/themes'
@@ -305,6 +306,19 @@ export default function ThemeTab({ config, updateField, updateFields }: ThemeTab
305
306
  )}
306
307
  </div>
307
308
 
309
+ <div className="toggle-row reduced-effects-row">
310
+ <div>
311
+ <label id="reduced-effects-label" htmlFor="reduced-effects">Reduce effects</label>
312
+ <p className="hint">Keep the background and orb still. Also follows your system’s reduced motion preference.</p>
313
+ </div>
314
+ <label className="settings-toggle-switch">
315
+ <input id="reduced-effects" type="checkbox" role="switch" aria-labelledby="reduced-effects-label"
316
+ checked={config.reducedEffects === true}
317
+ onChange={event => updateField('reducedEffects', event.target.checked)} />
318
+ <span className="settings-toggle-slider" aria-hidden="true" />
319
+ </label>
320
+ </div>
321
+
308
322
  {/* Surface style: Opaque vs Glassmorphism */}
309
323
  <div className="setting-row stacked">
310
324
  <label>Surface style</label>
@@ -429,18 +443,12 @@ export default function ThemeTab({ config, updateField, updateFields }: ThemeTab
429
443
  <div className="form-grid">
430
444
  <div className="setting-row">
431
445
  <label>Font family</label>
432
- <select value={config.fontFamily} onChange={(e) => updateField('fontFamily', e.target.value)}>
433
- <option value="'Prompt', sans-serif">Prompt (Thai & Latin - Default)</option>
434
- <option value="'Outfit', sans-serif">Outfit (Geometric Modern)</option>
435
- <option value="'Inter', sans-serif">Inter (Clean Sans-Serif)</option>
436
- <option value="'Prompt', sans-serif">Prompt (Modern Thai)</option>
437
- <option value="'Noto Sans Thai', sans-serif">Noto Sans Thai (clean Thai)</option>
438
- <option value="'Sarabun', sans-serif">Sarabun (Formal Thai)</option>
439
- <option value="'Kanit', sans-serif">Kanit (Trendy Thai)</option>
440
- <option value="'Mitr', sans-serif">Mitr (Friendly Thai)</option>
441
- <option value="'Mali', cursive">Mali (Cute Thai Font)</option>
446
+ <SelectField aria-label="Font family" value={config.fontFamily} onValueChange={(nextValue) => updateField('fontFamily', nextValue)}>
447
+ <option value="'IBM Plex Sans Thai', 'Noto Sans Thai', 'Inter', ui-sans-serif, system-ui, sans-serif">IBM Plex Sans Thai (Default)</option>
448
+ <option value="'Inter', 'Noto Sans Thai', ui-sans-serif, system-ui, sans-serif">Inter + Noto Sans Thai</option>
449
+ <option value="'Noto Sans Thai', 'Inter', ui-sans-serif, system-ui, sans-serif">Noto Sans Thai</option>
442
450
  <option value="'Fira Code', monospace">Fira Code (developer code font)</option>
443
- </select>
451
+ </SelectField>
444
452
  </div>
445
453
  <div className="setting-row">
446
454
  <label>Font size</label>
@@ -0,0 +1,88 @@
1
+ import { useEffect, useRef, useState, type RefObject } from 'react'
2
+ import type { SlashChoice } from '../platform'
3
+ import '../css/slash-choice.css'
4
+
5
+ interface Props {
6
+ choice: { command: string; title: string; options: SlashChoice[] }
7
+ inputRef: RefObject<HTMLTextAreaElement | null>
8
+ onSelect?: (value: string) => void
9
+ onDismiss?: () => void
10
+ }
11
+
12
+ export default function SlashChoicePanel({ choice, inputRef, onSelect, onDismiss }: Props) {
13
+ const [selectedIndex, setSelectedIndex] = useState(0)
14
+ const panelRef = useRef<HTMLElement>(null)
15
+ const optionRefs = useRef<Array<HTMLButtonElement | null>>([])
16
+ const selected = Math.min(selectedIndex, Math.max(0, choice.options.length - 1))
17
+
18
+ useEffect(() => {
19
+ setSelectedIndex(0)
20
+ inputRef.current?.focus()
21
+ }, [choice, inputRef])
22
+
23
+ useEffect(() => {
24
+ optionRefs.current[selected]?.scrollIntoView({ block: 'nearest' })
25
+ }, [selected, choice])
26
+
27
+ useEffect(() => {
28
+ const onKeyDown = (event: globalThis.KeyboardEvent) => {
29
+ if (event.isComposing || event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return
30
+ const target = event.target as Node | null
31
+ const onInput = target === inputRef.current
32
+ const inPanel = target !== null && panelRef.current?.contains(target)
33
+ if (event.key !== 'Escape' && !onInput && !inPanel) return
34
+ // Keep native Enter activation for the dismiss button.
35
+ if (event.key === 'Enter' && !onInput && !optionRefs.current.includes(target as HTMLButtonElement)) return
36
+ if (event.key === 'Escape') {
37
+ event.preventDefault()
38
+ event.stopPropagation()
39
+ onDismiss?.()
40
+ inputRef.current?.focus()
41
+ return
42
+ }
43
+ if (!choice.options.length) return
44
+ if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
45
+ event.preventDefault()
46
+ event.stopPropagation()
47
+ const next = (selected + (event.key === 'ArrowDown' ? 1 : -1) + choice.options.length) % choice.options.length
48
+ setSelectedIndex(next)
49
+ if (inPanel) optionRefs.current[next]?.focus()
50
+ } else if (event.key === 'Enter') {
51
+ event.preventDefault()
52
+ event.stopPropagation()
53
+ onSelect?.(choice.options[selected].value)
54
+ inputRef.current?.focus()
55
+ }
56
+ }
57
+ // Capture before the composer's history/submit handlers claim these keys.
58
+ window.addEventListener('keydown', onKeyDown, true)
59
+ return () => window.removeEventListener('keydown', onKeyDown, true)
60
+ }, [choice, inputRef, onDismiss, onSelect, selected])
61
+
62
+ return (
63
+ <section ref={panelRef} className="slash-choice-panel" aria-label={`${choice.command} choices`}>
64
+ <header className="slash-choice-heading">
65
+ <div><span className="slash-choice-command">{choice.command}</span><p>{choice.title}</p></div>
66
+ <button type="button" onClick={onDismiss} aria-label="Dismiss choices">×</button>
67
+ </header>
68
+ <div className="slash-choice-options" role="group" aria-label="Options">
69
+ {choice.options.map((option, index) => (
70
+ <button
71
+ key={option.value}
72
+ ref={(element) => { optionRefs.current[index] = element }}
73
+ type="button"
74
+ aria-pressed={index === selected}
75
+ className={index === selected ? 'active' : undefined}
76
+ onPointerMove={() => setSelectedIndex(index)}
77
+ onFocus={() => setSelectedIndex(index)}
78
+ onClick={() => { onSelect?.(option.value); inputRef.current?.focus() }}
79
+ >
80
+ <span>{index + 1}.</span>{option.label}
81
+ </button>
82
+ ))}
83
+ </div>
84
+ <span className="slash-choice-status" role="status">{choice.options[selected]?.label}</span>
85
+ <div className="slash-choice-hint">↑↓ select · Enter choose · Esc dismiss</div>
86
+ </section>
87
+ )
88
+ }
@@ -0,0 +1,33 @@
1
+ import React from 'react'
2
+ import { renderToStaticMarkup } from 'react-dom/server'
3
+ import { describe, expect, it } from 'vitest'
4
+ import SlashSuggestions from './SlashSuggestions'
5
+
6
+ const render = (message: string, suppressed = false) => renderToStaticMarkup(
7
+ <SlashSuggestions message={message} onComplete={() => {}} anchorRef={{ current: null }} suppressed={suppressed} />,
8
+ )
9
+
10
+ describe('composer command suggestions', () => {
11
+ it('finds a command by its description while retaining its executable token', () => {
12
+ const html = render('/statistics')
13
+ expect(html).toContain('/stats')
14
+ expect(html).toContain('role="option"')
15
+ expect(html).not.toContain('/clear')
16
+ })
17
+ it('shows token-prefix matches before description-only matches', () => {
18
+ const html = render('/st')
19
+ expect(html.indexOf('>/stats<')).toBeLessThan(html.indexOf('>/mods<'))
20
+ })
21
+ it('keeps a command argument as a usage hint instead of unrelated search results', () => {
22
+ const html = render('/remember a durable fact')
23
+ expect(html).toContain('/remember')
24
+ expect(html).not.toContain('role="option"')
25
+ })
26
+ it('keeps CLI-only actions out of the graphical menu and hides it during history browsing', () => {
27
+ const html = render('/')
28
+ expect(html).toContain('/models')
29
+ expect(html).not.toContain('/exit')
30
+ expect(html).not.toContain('/theme')
31
+ expect(render('/', true)).toBe('')
32
+ })
33
+ })
@@ -8,6 +8,8 @@ import {
8
8
  type KeyboardEvent,
9
9
  type RefObject,
10
10
  } from 'react'
11
+ import { Terminal, Brain, Folder, Wrench, BookOpen, AtSign } from 'lucide-react'
12
+ import '../css/slash-suggestions.css'
11
13
  import { SLASH_COMMANDS, type SlashCommand } from '../constants/slashCommands'
12
14
  import { catalogPlatform } from '../platform'
13
15
  import type { LearnedSkill } from '../types'
@@ -96,8 +98,19 @@ const SlashSuggestions = forwardRef<SlashSuggestionsHandle, Props>(function Slas
96
98
  const slashMatches = useMemo(() => {
97
99
  if (mode !== 'slash') return [] as SlashCommand[]
98
100
  const q = raw.toLowerCase()
99
- const hits = SLASH_COMMANDS.filter((c) => c.command.toLowerCase().startsWith(q))
100
- return CATEGORY_ORDER.flatMap((cat) => hits.filter((h) => (h.category ?? 'tools') === cat))
101
+ const typingArguments = SLASH_COMMANDS.some((c) => q.startsWith(c.command.toLowerCase() + ' '))
102
+ const words = q.slice(1).trim().split(/\s+/).filter(Boolean)
103
+ const hits = SLASH_COMMANDS.filter((c) =>
104
+ c.command.toLowerCase().startsWith(q) ||
105
+ (!typingArguments && !/\s/.test(q) && words.every((word) => `${c.command} ${c.description}`.toLowerCase().includes(word))),
106
+ )
107
+ const byCategory = (commands: SlashCommand[]) => CATEGORY_ORDER.flatMap((cat) =>
108
+ commands.filter((command) => (command.category ?? 'tools') === cat),
109
+ )
110
+ return [
111
+ ...byCategory(hits.filter((command) => command.command.toLowerCase().startsWith(q))),
112
+ ...byCategory(hits.filter((command) => !command.command.toLowerCase().startsWith(q))),
113
+ ]
101
114
  }, [mode, raw])
102
115
 
103
116
  // The command whose arguments are being typed (raw is past its token) — used
@@ -207,6 +220,16 @@ const SlashSuggestions = forwardRef<SlashSuggestionsHandle, Props>(function Slas
207
220
  return true
208
221
  }
209
222
  if ((event.key === 'Enter' || event.key === 'Tab') && !event.shiftKey && !event.nativeEvent.isComposing) {
223
+ // A complete slash command is an invocation, not an autocomplete
224
+ // candidate. Let Enter reach the composer submit handler so commands
225
+ // such as `/models` can open their interactive picker on the first keypress.
226
+ if (
227
+ event.key === 'Enter' &&
228
+ mode === 'slash' &&
229
+ flat.some((item) => (item as SlashCommand).command.toLowerCase() === raw.trim().toLowerCase())
230
+ ) {
231
+ return false
232
+ }
210
233
  const item = flat[selIndex] ?? flat[0]
211
234
  if (!item) return false
212
235
  pick(item)
@@ -248,18 +271,22 @@ const SlashSuggestions = forwardRef<SlashSuggestionsHandle, Props>(function Slas
248
271
  aria-selected={idx === selIndex}
249
272
  data-idx={idx}
250
273
  className={`slash-suggestion-item ${idx === selIndex ? 'active' : ''}`}
251
- onMouseDown={(e) => {
252
- e.preventDefault()
253
- pick(item)
254
- }}
274
+ title={[name, usage, desc].filter(Boolean).join(" · ")}
275
+ onMouseDown={(e) => e.preventDefault()}
276
+ onClick={() => pick(item)}
255
277
  onPointerMove={() => setSelIndex(idx)}
256
278
  >
279
+ <span className="slash-cmd-icon" aria-hidden="true">
280
+ {mode === 'skill' ? <BookOpen size={15} /> : mode === 'at' ? <AtSign size={15} /> :
281
+ (item as SlashCommand).category === 'models' ? <Brain size={15} /> :
282
+ (item as SlashCommand).category === 'workspace' ? <Folder size={15} /> :
283
+ (item as SlashCommand).category === 'tools' ? <Wrench size={15} /> : <Terminal size={15} />}
284
+ </span>
257
285
  <span className="slash-cmd-name">{name}</span>
258
- {badge && <span className="skill-badge">{badge}</span>}
259
286
  <span className="slash-cmd-body">
260
287
  <span className="slash-cmd-desc">{desc}</span>
261
- {usage && <span className="slash-cmd-usage">{usage}</span>}
262
288
  </span>
289
+ {badge && <span className="skill-badge">{badge}</span>}
263
290
  </button>
264
291
  )
265
292
 
@@ -269,10 +296,10 @@ const SlashSuggestions = forwardRef<SlashSuggestionsHandle, Props>(function Slas
269
296
  {mode === 'slash' ? 'Slash Commands' : mode === 'skill' ? 'Learned Skills' : 'Context Mentions'}
270
297
  <span className="slash-suggestions-count">{headerLabel}</span>
271
298
  </div>
272
- <div className="slash-suggestions-list" ref={listRef} role="listbox">
299
+ <div className="slash-suggestions-list" ref={listRef} role="listbox" aria-label={mode === 'slash' ? 'Slash commands' : mode === 'skill' ? 'Skills' : 'Context mentions'}>
273
300
  {mode === 'slash' &&
274
301
  (flat.length > 0
275
- ? CATEGORY_ORDER.map((cat) => {
302
+ ? [...new Set(slashMatches.map((match) => match.category ?? 'tools'))].map((cat) => {
276
303
  const items = slashMatches.filter((m) => (m.category ?? 'tools') === cat)
277
304
  if (!items.length) return null
278
305
  return (
@@ -311,6 +338,7 @@ const SlashSuggestions = forwardRef<SlashSuggestionsHandle, Props>(function Slas
311
338
  row(item, idx, item.label, item.desc, item.kind === 'plugin' ? '[Plugin]' : '[Context]'),
312
339
  )}
313
340
  </div>
341
+ <div className="slash-suggestions-hint">↑↓ select · Tab complete · Enter send · Esc close</div>
314
342
  </div>
315
343
  )
316
344
  })
@@ -1,6 +1,7 @@
1
1
  import React, { useState, useMemo, useEffect } from 'react'
2
2
  import type { WebSearchSource } from '../utils/agentActivity'
3
3
  import { resolveMediaUrl } from '../utils/markdown'
4
+ import '../css/sources-block.css'
4
5
 
5
6
  export interface SourcesBlockProps {
6
7
  sources: WebSearchSource[]
@@ -87,7 +88,7 @@ export const SourcesBlock: React.FC<SourcesBlockProps> = React.memo(function Sou
87
88
  const hiddenGroups = domainGroups.slice(MAX_INITIAL_CARDS)
88
89
 
89
90
  return (
90
- <div style={{ display: 'flex', flexDirection: 'column', gap: '10px', marginBottom: '12px', marginTop: '4px' }}>
91
+ <div className="sources-block" style={{ display: 'flex', flexDirection: 'column', gap: '10px', marginBottom: '12px', marginTop: '4px' }}>
91
92
  {/* Header */}
92
93
  <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
93
94
  <svg
@@ -110,6 +111,7 @@ export const SourcesBlock: React.FC<SourcesBlockProps> = React.memo(function Sou
110
111
 
111
112
  {/* Domain Cards Container (wraps to next line if exceeding frame width) */}
112
113
  <div
114
+ className="sources-cards"
113
115
  style={{
114
116
  display: 'flex',
115
117
  flexWrap: 'wrap',
@@ -124,18 +126,11 @@ export const SourcesBlock: React.FC<SourcesBlockProps> = React.memo(function Sou
124
126
  return (
125
127
  <div
126
128
  key={group.domain}
127
- style={{
128
- position: 'relative',
129
- flex: '1 1 180px',
130
- maxWidth: '240px',
131
- minWidth: '160px',
132
- boxSizing: 'border-box',
133
- }}
129
+ className="source-card-group"
134
130
  >
135
131
  <div
132
+ className="source-card"
136
133
  style={{
137
- display: 'flex',
138
- flexDirection: 'column',
139
134
  justifyContent: 'space-between',
140
135
  borderRadius: '16px',
141
136
  background: 'var(--bg-surface-soft)',
@@ -143,7 +138,6 @@ export const SourcesBlock: React.FC<SourcesBlockProps> = React.memo(function Sou
143
138
  transition: 'all 0.15s ease',
144
139
  cursor: 'pointer',
145
140
  minHeight: '68px',
146
- height: '100%',
147
141
  boxSizing: 'border-box',
148
142
  overflow: 'hidden',
149
143
  }}
@@ -173,7 +167,7 @@ export const SourcesBlock: React.FC<SourcesBlockProps> = React.memo(function Sou
173
167
  >
174
168
  {/* Thumbnail (if this source has an associated image) */}
175
169
  {primaryItem.imageUrl && (
176
- <div style={{ width: '100%', height: '80px', overflow: 'hidden', background: 'var(--bg-surface-raised)', flexShrink: 0 }}>
170
+ <div className="source-card-thumbnail" style={{ overflow: 'hidden', background: 'var(--bg-surface-raised)', flexShrink: 0 }}>
177
171
  <img
178
172
  src={resolveMediaUrl(primaryItem.imageUrl)}
179
173
  alt={primaryItem.title}
@@ -185,7 +179,7 @@ export const SourcesBlock: React.FC<SourcesBlockProps> = React.memo(function Sou
185
179
  </div>
186
180
  )}
187
181
 
188
- <div style={{ display: 'flex', flexDirection: 'column', flex: 1, padding: '10px 12px' }}>
182
+ <div className="source-card-content" style={{ display: 'flex', flexDirection: 'column', flex: 1, padding: '10px 12px' }}>
189
183
  {/* Title */}
190
184
  <div
191
185
  title={primaryItem.title}
@@ -280,7 +274,6 @@ export const SourcesBlock: React.FC<SourcesBlockProps> = React.memo(function Sou
280
274
  position: 'absolute',
281
275
  top: '100%',
282
276
  left: 0,
283
- width: '260px',
284
277
  marginTop: '6px',
285
278
  background: 'var(--bg-overlay)',
286
279
  border: '1px solid var(--border-default)',
@@ -357,7 +350,10 @@ export const SourcesBlock: React.FC<SourcesBlockProps> = React.memo(function Sou
357
350
 
358
351
  {/* Overflow "View X more" Card */}
359
352
  {!isExpanded && remainingSourcesCount > 0 && (
360
- <div
353
+ <button
354
+ type="button"
355
+ className="sources-more-button"
356
+ aria-expanded={false}
361
357
  onClick={() => setIsExpanded(true)}
362
358
  style={{
363
359
  display: 'flex',
@@ -369,10 +365,6 @@ export const SourcesBlock: React.FC<SourcesBlockProps> = React.memo(function Sou
369
365
  border: `1px solid ${isDark ? 'rgba(255,255,255,0.08)' : 'rgba(15,23,42,0.1)'}`,
370
366
  cursor: 'pointer',
371
367
  transition: 'all 0.15s ease',
372
- minHeight: '68px',
373
- height: '100%',
374
- flex: '1 1 160px',
375
- maxWidth: '200px',
376
368
  boxSizing: 'border-box',
377
369
  }}
378
370
  onMouseEnter={(e) => {
@@ -412,7 +404,7 @@ export const SourcesBlock: React.FC<SourcesBlockProps> = React.memo(function Sou
412
404
  <span style={{ fontSize: '0.78rem', fontWeight: 500, color: '#94a3b8', marginLeft: '8px' }}>
413
405
  View {remainingSourcesCount} more
414
406
  </span>
415
- </div>
407
+ </button>
416
408
  )}
417
409
  </div>
418
410
 
@@ -0,0 +1,32 @@
1
+ import React from 'react'
2
+ import { renderToStaticMarkup } from 'react-dom/server'
3
+ import { describe, expect, it } from 'vitest'
4
+ import ToolSurfacePage from './ToolSurfacePage'
5
+
6
+ const noop = () => {}
7
+ const props = {
8
+ surfaces: [], activeSurfaceId: null, terminalSize: 440,
9
+ onSelect: noop, onClose: noop, onCloseAll: noop, onDuplicate: noop,
10
+ onRename: noop, onCloseOthers: noop, onResizeTerminal: noop, onResizePanel: noop,
11
+ onOpenTerminal: noop, onOpenBrowser: noop, onOpenReview: noop, onOpenFiles: noop,
12
+ onOpenMods: noop, onOpenBackgroundTasks: noop, onClosePanel: noop,
13
+ onModsPanelTarget: noop, onBackgroundPanelTarget: noop,
14
+ }
15
+
16
+ describe('Tools launcher', () => {
17
+ it('makes workspace mods and running background tasks discoverable on its first screen', () => {
18
+ const html = renderToStaticMarkup(<ToolSurfacePage {...props} backgroundTaskCount={2} />)
19
+ expect(html).toMatch(/role="menuitem"[^>]*title="Workspace mods"/)
20
+ expect(html).toMatch(/role="menuitem"[^>]*title="Background tasks"/)
21
+ expect(html).toContain('2 active background tasks')
22
+ expect(html).toContain('Integrated terminal')
23
+ })
24
+
25
+ it('does not offer a native shell or desktop workspace on the web', () => {
26
+ const html = renderToStaticMarkup(<ToolSurfacePage {...props} desktopTools={false} />)
27
+ expect(html).toContain('Workspace mods')
28
+ expect(html).toContain('Background tasks')
29
+ expect(html).not.toContain('Integrated terminal')
30
+ expect(html).not.toContain('Workspace files')
31
+ })
32
+ })
@@ -6,11 +6,13 @@ import { ArtifactPreviewPanel } from './ArtifactPreviewPanel'
6
6
  import CodeReviewPage from './CodeReviewPage'
7
7
  import TerminalDock from './TerminalDock'
8
8
  import type { FileChange } from '../types'
9
+ import { ListTodo, Puzzle } from 'lucide-react'
9
10
 
10
11
  export type ToolSurface =
11
12
  | { id: string; kind: 'preview'; title: string; artifact: ArtifactFile }
12
13
  | { id: string; kind: 'review'; title: string; reviewTitle: string; changes: FileChange[] }
13
14
  | { id: string; kind: 'terminal'; title: string }
15
+ | { id: string; kind: 'mods' | 'background'; title: string }
14
16
 
15
17
  interface Props {
16
18
  surfaces: ToolSurface[]
@@ -31,10 +33,18 @@ interface Props {
31
33
  onOpenFiles: () => void
32
34
  onOpenSideChat?: () => void
33
35
  onClosePanel: () => void
36
+ desktopTools?: boolean
37
+ backgroundTaskCount?: number
38
+ onOpenMods: () => void
39
+ onOpenBackgroundTasks: () => void
40
+ onModsPanelTarget: (target: HTMLDivElement | null) => void
41
+ onBackgroundPanelTarget: (target: HTMLDivElement | null) => void
34
42
  }
35
43
 
36
44
 
37
45
  function surfaceIcon(kind: ToolSurface['kind']) {
46
+ if (kind === 'mods') return <Puzzle size={13} aria-hidden="true" />
47
+ if (kind === 'background') return <ListTodo size={13} aria-hidden="true" />
38
48
  if (kind === 'terminal') {
39
49
  return (
40
50
  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" style={{ verticalAlign: '-1px' }}>
@@ -80,11 +90,34 @@ export default function ToolSurfacePage({
80
90
  onOpenFiles,
81
91
  onOpenSideChat,
82
92
  onClosePanel,
93
+ desktopTools = true,
94
+ backgroundTaskCount = 0,
95
+ onOpenMods,
96
+ onOpenBackgroundTasks,
97
+ onModsPanelTarget,
98
+ onBackgroundPanelTarget,
83
99
  }: Props) {
84
100
  const active = surfaces.find((surface) => surface.id === activeSurfaceId) ?? surfaces[0] ?? null
85
101
  const [switcherOpen, setSwitcherOpen] = useState(false)
86
102
  const [tabMenuState, setTabMenuState] = useState<{ id: string; x: number; y: number } | null>(null)
87
103
  const [isMaximized, setIsMaximized] = useState(false)
104
+ const panelRef = useRef<HTMLElement>(null)
105
+
106
+ useEffect(() => {
107
+ panelRef.current?.querySelector<HTMLButtonElement>('[role="tab"][aria-selected="true"], [role="menuitem"]')?.focus()
108
+ }, [active?.id])
109
+
110
+ useEffect(() => {
111
+ const dismiss = (event: KeyboardEvent) => {
112
+ if (event.key !== 'Escape' || event.defaultPrevented || !panelRef.current?.contains(event.target as Node)) return
113
+ event.preventDefault()
114
+ if (switcherOpen) { setSwitcherOpen(false); newTabWrapRef.current?.querySelector<HTMLButtonElement>('.tool-surface-dropdown-btn')?.focus() }
115
+ else if (tabMenuState) setTabMenuState(null)
116
+ else onClosePanel()
117
+ }
118
+ document.addEventListener('keydown', dismiss)
119
+ return () => document.removeEventListener('keydown', dismiss)
120
+ }, [onClosePanel, switcherOpen, tabMenuState])
88
121
 
89
122
  const [isEntering, setIsEntering] = useState(true)
90
123
  const [isResizing, setIsResizing] = useState(false)
@@ -193,10 +226,14 @@ export default function ToolSurfacePage({
193
226
  )
194
227
 
195
228
  const launcherItems = [
229
+ { label: 'Mods', title: 'Workspace mods', shortcut: '', icon: <Puzzle />, className: 'is-mods', action: onOpenMods },
230
+ { label: 'Background tasks', title: 'Background tasks', shortcut: '', icon: <ListTodo />, className: 'is-background', action: onOpenBackgroundTasks },
231
+ ...(desktopTools ? [
196
232
  { label: 'Review', title: 'Review changes', shortcut: 'Ctrl+Shift+G', icon: <IconReview />, className: 'is-review', action: onOpenReview },
197
- { label: 'Terminal', title: 'Integrated terminal', shortcut: 'Ctrl`', icon: <IconTerminal />, className: 'is-terminal', action: onOpenTerminal },
233
+ { label: 'Terminal', title: 'Integrated terminal', shortcut: 'Ctrl + `', icon: <IconTerminal />, className: 'is-terminal', action: onOpenTerminal },
198
234
  { label: 'Browser', title: 'Browser (Co-browsing with AI)', shortcut: 'Ctrl+T', icon: <IconBrowser />, className: 'is-browser', action: onOpenBrowser },
199
235
  { label: 'Workspace', title: 'Workspace files', shortcut: 'Ctrl+P', icon: <IconFiles />, className: 'is-files', action: onOpenFiles },
236
+ ] : []),
200
237
  ]
201
238
 
202
239
  const renderLauncher = (className = '') => (
@@ -204,7 +241,9 @@ export default function ToolSurfacePage({
204
241
  {launcherItems.map((item) => (
205
242
  <button type="button" role="menuitem" className="tool-surface-launcher-item" key={item.label} title={item.title} onClick={() => { item.action(); setSwitcherOpen(false) }}>
206
243
  <span className={`tool-surface-menu-icon ${item.className}`} aria-hidden="true">{item.icon}</span>
207
- <span>{item.label}</span><kbd>{item.shortcut}</kbd>
244
+ <span className="tool-surface-menu-copy"><span className="tool-surface-menu-label">{item.label}</span></span>
245
+ {item.className === 'is-background' && backgroundTaskCount > 0 && <span className="tools-task-count" aria-label={`${backgroundTaskCount} active background tasks`}>{backgroundTaskCount}</span>}
246
+ {item.shortcut && <kbd>{item.shortcut}</kbd>}
208
247
  </button>
209
248
  ))}
210
249
  </div>
@@ -218,7 +257,7 @@ export default function ToolSurfacePage({
218
257
  const next = !open
219
258
  if (next && newTabWrapRef.current) {
220
259
  const rect = newTabWrapRef.current.getBoundingClientRect()
221
- setMenuAlignRight(window.innerWidth - rect.left < 210)
260
+ setMenuAlignRight(window.innerWidth - rect.left < 260)
222
261
  }
223
262
  return next
224
263
  })
@@ -296,6 +335,10 @@ export default function ToolSurfacePage({
296
335
  }
297
336
 
298
337
  const handleAddNewTab = () => {
338
+ if (active?.kind === 'mods' || active?.kind === 'background') {
339
+ toggleSwitcher()
340
+ return
341
+ }
299
342
  if (active?.kind === 'review') {
300
343
  onOpenReview()
301
344
  } else if (active?.kind === 'preview') {
@@ -305,7 +348,7 @@ export default function ToolSurfacePage({
305
348
  }
306
349
  }
307
350
 
308
- const newTabTooltip = active?.kind === 'review'
351
+ const newTabTooltip = active?.kind === 'mods' || active?.kind === 'background' ? 'Open a tool' : active?.kind === 'review'
309
352
  ? 'New Review Tab'
310
353
  : active?.kind === 'preview'
311
354
  ? 'Duplicate Preview Tab'
@@ -313,9 +356,10 @@ export default function ToolSurfacePage({
313
356
 
314
357
  return (
315
358
  <section
359
+ ref={panelRef}
316
360
  className={`tool-surface-page ${isEntering ? 'is-entering' : ''} ${isMaximized ? 'is-maximized' : ''} ${isResizing ? 'is-resizing' : ''}`}
317
361
  onAnimationEnd={() => setIsEntering(false)}
318
- aria-label="Open tools"
362
+ aria-label="Tools"
319
363
  >
320
364
  {!isMaximized && (
321
365
  <div
@@ -416,6 +460,7 @@ export default function ToolSurfacePage({
416
460
  onClick={(e) => { e.stopPropagation(); toggleSwitcher() }}
417
461
  title="Switch tool or open page"
418
462
  aria-label="Switch tool"
463
+ aria-haspopup="menu"
419
464
  aria-expanded={switcherOpen}
420
465
  >
421
466
  <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
@@ -425,8 +470,9 @@ export default function ToolSurfacePage({
425
470
  {switcherOpen && (
426
471
  <div
427
472
  className={`tool-surface-switch-menu ${menuAlignRight ? 'is-align-right' : ''}`}
428
- role="menu"
473
+ aria-label="Tool menu"
429
474
  >
475
+ <div className="tool-surface-menu-heading">OPEN TOOL</div>
430
476
  {renderLauncher('is-switch-menu')}
431
477
  </div>
432
478
  )}
@@ -437,8 +483,8 @@ export default function ToolSurfacePage({
437
483
  type="button"
438
484
  className={`tool-surface-action-btn ${isMaximized ? 'is-active' : ''}`}
439
485
  onClick={() => setIsMaximized((prev) => !prev)}
440
- title={isMaximized ? 'Restore side split' : 'Maximize terminal (⤢)'}
441
- aria-label={isMaximized ? 'Restore side split' : 'Maximize terminal'}
486
+ title={isMaximized ? 'Restore side split' : 'Maximize tools (⤢)'}
487
+ aria-label={isMaximized ? 'Restore side split' : 'Maximize tools'}
442
488
  >
443
489
  {isMaximized ? (
444
490
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
@@ -474,9 +520,9 @@ export default function ToolSurfacePage({
474
520
  }}
475
521
  role="menu"
476
522
  >
477
- <button type="button" role="menuitem" onClick={() => { onDuplicate(tabMenuState.id); setTabMenuState(null) }}>
523
+ {surfaces.find(surface => surface.id === tabMenuState.id)?.kind !== 'mods' && surfaces.find(surface => surface.id === tabMenuState.id)?.kind !== 'background' && <button type="button" role="menuitem" onClick={() => { onDuplicate(tabMenuState.id); setTabMenuState(null) }}>
478
524
  Duplicate tab
479
- </button>
525
+ </button>}
480
526
  <button type="button" role="menuitem" onClick={() => { onRename(tabMenuState.id); setTabMenuState(null) }}>
481
527
  Rename tab
482
528
  </button>
@@ -493,7 +539,9 @@ export default function ToolSurfacePage({
493
539
 
494
540
  <div className={`tool-surface-content${active ? '' : ' is-launcher'}`}>
495
541
  {!active && renderLauncher()}
496
- {active?.kind === 'preview' && <ArtifactPreviewPanel artifact={active.artifact} onClose={() => active && onClose(active.id)} workspacePath={workspacePath || undefined} />}
542
+ {active?.kind === 'mods' && <div key="mods" className="tool-surface-panel-host" ref={onModsPanelTarget} />}
543
+ {active?.kind === 'background' && <div key="background" className="tool-surface-panel-host" ref={onBackgroundPanelTarget} />}
544
+ {active?.kind === 'preview' && <ArtifactPreviewPanel key={active.id} artifact={active.artifact} onClose={() => active && onClose(active.id)} workspacePath={workspacePath || undefined} />}
497
545
  {active?.kind === 'review' && (
498
546
  <CodeReviewPage
499
547
  title={active.reviewTitle}
@@ -0,0 +1,13 @@
1
+ import '../css/tools-panel.css'
2
+
3
+ export default function ToolsPanelToggle({ open, count = 0, onToggle, className = '' }: {
4
+ open: boolean; count?: number; onToggle: () => void; className?: string
5
+ }) {
6
+ return <button type="button" className={`tools-panel-toggle ${className}${open ? ' is-open' : ''}`}
7
+ aria-label={open ? 'Close tools panel' : 'Open tools panel'} aria-expanded={open}
8
+ title={open ? 'Close tools panel' : 'Open tools panel'} onClick={onToggle}>
9
+ <svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M15 4v16M18 8h1M18 12h1M18 16h1"/></svg>
10
+ <span className="tools-toggle-label">Tools</span>
11
+ {count > 0 && <span className="tools-task-count" aria-label={`${count} active background tasks`}>{count}</span>}
12
+ </button>
13
+ }