@pheem49/mint 1.14.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (925) hide show
  1. package/Cargo.lock +1258 -35
  2. package/Cargo.toml +5 -2
  3. package/LICENSE +21 -654
  4. package/README.md +93 -756
  5. package/Release_Note.md +53 -446
  6. package/apps/mint-companion/src-tauri/Cargo.toml +20 -0
  7. package/apps/mint-companion/src-tauri/build.rs +3 -0
  8. package/apps/mint-companion/src-tauri/src/main.rs +468 -0
  9. package/apps/mint-companion/tsconfig.json +20 -0
  10. package/apps/mint-companion/vite.config.ts +3 -0
  11. package/components.json +19 -0
  12. package/crates/mint-cli/Cargo.toml +9 -1
  13. package/crates/mint-cli/src/agent/approval_prompts.rs +16 -3
  14. package/crates/mint-cli/src/agent/live_status.rs +545 -148
  15. package/crates/mint-cli/src/agent/markdown_render.rs +601 -61
  16. package/crates/mint-cli/src/agent.rs +723 -258
  17. package/crates/mint-cli/src/commands/agent.rs +83 -74
  18. package/crates/mint-cli/src/commands/eval.rs +9 -5
  19. package/crates/mint-cli/src/commands/git.rs +204 -0
  20. package/crates/mint-cli/src/commands/integrations.rs +35 -0
  21. package/crates/mint-cli/src/commands/knowledge.rs +13 -32
  22. package/crates/mint-cli/src/commands/mod.rs +81 -2
  23. package/crates/mint-cli/src/commands/tailnet_web.rs +235 -0
  24. package/crates/mint-cli/src/image.rs +32 -11
  25. package/crates/mint-cli/src/interactive/chat_tui.rs +7853 -0
  26. package/crates/mint-cli/src/interactive/command_ui.rs +477 -0
  27. package/crates/mint-cli/src/interactive/format.rs +8 -0
  28. package/crates/mint-cli/src/interactive/input_box.rs +94 -8
  29. package/crates/mint-cli/src/interactive/picker.rs +180 -37
  30. package/crates/mint-cli/src/interactive/resume_picker.rs +686 -0
  31. package/crates/mint-cli/src/interactive/slash_commands.rs +1071 -501
  32. package/crates/mint-cli/src/interactive/thought_viewer.rs +286 -0
  33. package/crates/mint-cli/src/interactive/tool_activity.rs +328 -0
  34. package/crates/mint-cli/src/interactive.rs +454 -166
  35. package/crates/mint-cli/src/main.rs +93 -26
  36. package/crates/mint-cli/src/markdown.rs +12 -5
  37. package/crates/mint-cli/src/mcp.rs +5 -0
  38. package/crates/mint-cli/src/mod_host.rs +6 -0
  39. package/crates/mint-cli/src/mods_cli.rs +62 -0
  40. package/crates/mint-cli/src/mods_ui.rs +187 -0
  41. package/crates/mint-cli/src/onboard.rs +37 -61
  42. package/crates/mint-cli/src/plugins_cli.rs +8 -5
  43. package/crates/mint-cli/src/setup.rs +10 -8
  44. package/crates/mint-cli/src/terminal_theme.rs +189 -0
  45. package/crates/mint-cli/src/updater.rs +112 -23
  46. package/crates/mint-cli/tests/library_intake.rs +77 -0
  47. package/crates/mint-cli/tests/mods_testing.rs +133 -0
  48. package/crates/mint-companion-protocol/Cargo.toml +10 -0
  49. package/crates/mint-companion-protocol/src/lib.rs +163 -0
  50. package/crates/mint-core/Cargo.toml +6 -3
  51. package/crates/mint-core/build.rs +26 -0
  52. package/crates/mint-core/src/agent/agent_loop.rs +1 -0
  53. package/crates/mint-core/src/agent/chat.rs +1003 -209
  54. package/crates/mint-core/src/agent/code_tools.rs +98 -2
  55. package/crates/mint-core/src/agent/memory/sources.rs +240 -0
  56. package/crates/mint-core/src/agent/memory.rs +805 -33
  57. package/crates/mint-core/src/agent/skill_inventory.rs +325 -0
  58. package/crates/mint-core/src/agent/skills.rs +437 -90
  59. package/crates/mint-core/src/agent.rs +1 -0
  60. package/crates/mint-core/src/api_server/routes/background_jobs.rs +310 -0
  61. package/crates/mint-core/src/api_server/routes/chat.rs +233 -190
  62. package/crates/mint-core/src/api_server/routes/html_preview.rs +77 -0
  63. package/crates/mint-core/src/api_server/routes/library.rs +97 -0
  64. package/crates/mint-core/src/api_server/routes/linked_folders.rs +118 -3
  65. package/crates/mint-core/src/api_server/routes/media_gen.rs +10 -57
  66. package/crates/mint-core/src/api_server/routes/misc.rs +114 -121
  67. package/crates/mint-core/src/api_server/routes/mod.rs +6 -0
  68. package/crates/mint-core/src/api_server/routes/mods.rs +31 -0
  69. package/crates/mint-core/src/api_server/routes/sessions.rs +85 -0
  70. package/crates/mint-core/src/api_server/routes/skills_subagents.rs +12 -42
  71. package/crates/mint-core/src/api_server/routes/slash.rs +50 -1
  72. package/crates/mint-core/src/api_server/routes/sources.rs +101 -0
  73. package/crates/mint-core/src/api_server.rs +140 -12
  74. package/crates/mint-core/src/avatar_bridge.rs +13 -2
  75. package/crates/mint-core/src/browser/cdp.rs +74 -83
  76. package/crates/mint-core/src/browser/evidence.rs +260 -0
  77. package/crates/mint-core/src/browser/input.rs +1 -1
  78. package/crates/mint-core/src/browser/interact.rs +98 -124
  79. package/crates/mint-core/src/browser/lifecycle.rs +75 -4
  80. package/crates/mint-core/src/browser/mod.rs +16 -2
  81. package/crates/mint-core/src/browser/navigate.rs +27 -19
  82. package/crates/mint-core/src/browser/observe.js +40 -0
  83. package/crates/mint-core/src/browser/session.rs +1610 -0
  84. package/crates/mint-core/src/companion.rs +716 -0
  85. package/crates/mint-core/src/cron/scheduler.rs +34 -2
  86. package/crates/mint-core/src/git/branches.rs +348 -0
  87. package/crates/mint-core/src/git/checkpoint.rs +40 -0
  88. package/crates/mint-core/src/git/diff.rs +206 -0
  89. package/crates/mint-core/src/git/mod.rs +10 -2
  90. package/crates/mint-core/src/integrations/channels.rs +88 -345
  91. package/crates/mint-core/src/integrations/mcp.rs +397 -50
  92. package/crates/mint-core/src/integrations/mcp_calls.rs +823 -0
  93. package/crates/mint-core/src/integrations/mcp_catalog.rs +267 -0
  94. package/crates/mint-core/src/integrations/mcp_device.rs +319 -0
  95. package/crates/mint-core/src/integrations/mcp_result.rs +356 -0
  96. package/crates/mint-core/src/integrations/webhooks.rs +539 -0
  97. package/crates/mint-core/src/integrations.rs +2 -0
  98. package/crates/mint-core/src/lib.rs +107 -40
  99. package/crates/mint-core/src/live_sync.rs +28 -9
  100. package/crates/mint-core/src/media/auto_shorts.rs +1 -0
  101. package/crates/mint-core/src/media/gemini_live.rs +145 -14
  102. package/crates/mint-core/src/media/image_models.rs +3 -27
  103. package/crates/mint-core/src/media/image_workflow.rs +216 -0
  104. package/crates/mint-core/src/media/library/intake.rs +144 -0
  105. package/crates/mint-core/src/media/library/migration.rs +56 -0
  106. package/crates/mint-core/src/media/library/removal.rs +55 -0
  107. package/crates/mint-core/src/media/library/tests.rs +730 -0
  108. package/crates/mint-core/src/media/library/thumbnails.rs +72 -0
  109. package/crates/mint-core/src/media/library.rs +545 -0
  110. package/crates/mint-core/src/media/mic_transcribe.rs +1 -0
  111. package/crates/mint-core/src/media/model_catalog.rs +375 -0
  112. package/crates/mint-core/src/media/pictures.rs +79 -222
  113. package/crates/mint-core/src/media/subtitle.rs +1 -0
  114. package/crates/mint-core/src/media/video_models.rs +3 -22
  115. package/crates/mint-core/src/media.rs +3 -0
  116. package/crates/mint-core/src/mods/manager.rs +1124 -0
  117. package/crates/mint-core/src/mods/mod.rs +569 -0
  118. package/crates/mint-core/src/mods/operations.rs +204 -0
  119. package/crates/mint-core/src/mods/session.rs +146 -0
  120. package/crates/mint-core/src/mods/slash.rs +59 -0
  121. package/crates/mint-core/src/mods/telemetry.rs +306 -0
  122. package/crates/mint-core/src/orchestration/approvals.rs +344 -0
  123. package/crates/mint-core/src/orchestration/context_render.rs +105 -0
  124. package/crates/mint-core/src/orchestration/mcp_review.rs +153 -0
  125. package/crates/mint-core/src/orchestration/memory_skill.rs +110 -33
  126. package/crates/mint-core/src/orchestration/mod.rs +3129 -481
  127. package/crates/mint-core/src/orchestration/mod_authoring_regressions.rs +209 -0
  128. package/crates/mint-core/src/orchestration/progress_clock.rs +80 -0
  129. package/crates/mint-core/src/orchestration/repeated_failures.rs +116 -0
  130. package/crates/mint-core/src/orchestration/review_regressions.rs +449 -0
  131. package/crates/mint-core/src/orchestration/run_control.rs +196 -0
  132. package/crates/mint-core/src/orchestration/tools/browser.rs +16 -139
  133. package/crates/mint-core/src/orchestration/tools/files.rs +161 -14
  134. package/crates/mint-core/src/orchestration/tools/media.rs +37 -41
  135. package/crates/mint-core/src/orchestration/tools/misc.rs +5 -3
  136. package/crates/mint-core/src/orchestration/tools/mod.rs +2 -0
  137. package/crates/mint-core/src/orchestration/tools/mods.rs +161 -0
  138. package/crates/mint-core/src/orchestration/tools/plugins_mcp.rs +303 -71
  139. package/crates/mint-core/src/orchestration/tools/shell.rs +95 -2
  140. package/crates/mint-core/src/orchestration/tools/web.rs +1 -1
  141. package/crates/mint-core/src/orchestration/workspace_helpers.rs +4 -1
  142. package/crates/mint-core/src/prompts/agent.rs +75 -31
  143. package/crates/mint-core/src/prompts/chat.rs +1 -1
  144. package/crates/mint-core/src/prompts/persona.rs +1 -1
  145. package/crates/mint-core/src/prompts/tool_catalog.rs +121 -27
  146. package/crates/mint-core/src/search/knowledge.rs +7 -1
  147. package/crates/mint-core/src/search/linked_folders/index.rs +896 -0
  148. package/crates/mint-core/src/search/linked_folders.rs +473 -131
  149. package/crates/mint-core/src/slash/catalog.rs +1 -1
  150. package/crates/mint-core/src/slash/mod.rs +644 -33
  151. package/crates/mint-core/src/slash/model_fetcher.rs +12 -3
  152. package/crates/mint-core/src/slash/models.rs +66 -10
  153. package/crates/mint-core/src/slash/mods.rs +155 -0
  154. package/crates/mint-core/src/system/bg_shell.rs +1129 -95
  155. package/crates/mint-core/src/system/config.rs +235 -10
  156. package/crates/mint-core/src/system/html_preview.rs +398 -0
  157. package/crates/mint-core/src/system/mint_web.rs +164 -0
  158. package/crates/mint-core/src/system/release_notes.rs +18 -0
  159. package/crates/mint-core/src/system/shell.rs +21 -6
  160. package/crates/mint-core/src/system/workspace.rs +292 -0
  161. package/crates/mint-core/src/system/workspace_history.rs +604 -0
  162. package/crates/mint-core/src/system.rs +5 -0
  163. package/crates/mint-core/tests/background_retention.rs +34 -0
  164. package/crates/mint-core/tests/background_shutdown.rs +24 -0
  165. package/crates/mint-core/tests/library_http.rs +209 -0
  166. package/crates/mint-core/tests/mcp_contract.rs +283 -0
  167. package/crates/mint-core/tests/mcp_stdio.rs +11 -10
  168. package/crates/mint-core/tests/media_model_catalog_http.rs +403 -0
  169. package/crates/mint-core/tests/memory_persistence.rs +39 -0
  170. package/crates/mint-core/tests/mods_http.rs +215 -0
  171. package/crates/mint-core/tests/terminal_shutdown.rs +109 -0
  172. package/crates/mint-mod-runtime/Cargo.toml +18 -0
  173. package/crates/mint-mod-runtime/src/lib.rs +507 -0
  174. package/crates/mint-mod-runtime/src/sdk.js +56 -0
  175. package/crates/mint-mod-runtime/src/test_sdk.js +32 -0
  176. package/crates/mint-mod-runtime/src/testing.rs +94 -0
  177. package/crates/mint-mod-runtime/tests/runtime.rs +156 -0
  178. package/docs/mods/AUTHORING.md +61 -0
  179. package/docs/mods/README.md +139 -0
  180. package/docs/mods/TESTING.md +56 -0
  181. package/docs/mods/mint-mods.d.ts +66 -0
  182. package/examples/device-mcp/README.md +22 -0
  183. package/examples/device-mcp/contract.md +49 -0
  184. package/examples/device-mcp/mock-device.mjs +66 -0
  185. package/examples/device-mcp/server.mjs +48 -0
  186. package/examples/device-mcp/server.test.mjs +78 -0
  187. package/examples/mods/task-checklist/README.md +1 -0
  188. package/examples/mods/task-checklist/main.ts +17 -0
  189. package/examples/mods/task-checklist/manifest.json +1 -0
  190. package/examples/mods/task-checklist/tests/checklist.test.ts +15 -0
  191. package/examples/mods/token-meter/README.md +1 -0
  192. package/examples/mods/token-meter/main.ts +8 -0
  193. package/examples/mods/token-meter/manifest.json +1 -0
  194. package/examples/mods/tool-guard/README.md +1 -0
  195. package/examples/mods/tool-guard/main.ts +9 -0
  196. package/examples/mods/tool-guard/manifest.json +1 -0
  197. package/out/web/assets/CliSessionsView-CtzUJpK_.css +1 -0
  198. package/out/web/assets/CliSessionsView-D7hw0Mgj.js +1 -0
  199. package/out/web/assets/CodeReviewPage-C7bEOJfd.js +4 -0
  200. package/out/web/assets/CodeReviewPage-Dte9uLiL.css +1 -0
  201. package/out/web/assets/CommandPalette-0RrF-AOT.js +1 -0
  202. package/out/web/assets/ImageStudioPanel-CdxkAf_r.js +1 -0
  203. package/out/web/assets/ImageStudioPanel-D0lnhQV5.css +1 -0
  204. package/out/web/assets/LibraryPage--Qfisp6D.js +2 -0
  205. package/out/web/assets/LibraryPage-DAxUTAg7.css +1 -0
  206. package/out/web/assets/LinkedFoldersView-2nfZbDgN.js +1 -0
  207. package/out/web/assets/McpRegistryPicker-h9uS8_wT.js +1 -0
  208. package/out/web/assets/McpServersView-slfQJzNB.js +1 -0
  209. package/out/web/assets/MintDashboard-BSR5XpXh.js +25 -0
  210. package/out/web/assets/MintDashboard-CWUcCGhd.css +1 -0
  211. package/out/web/assets/PluginsView-l7LSm503.js +1 -0
  212. package/out/web/assets/ScheduledTasksView-CttmLbq1.js +1 -0
  213. package/out/web/assets/SettingsWindow-BCMLYvEV.js +4 -0
  214. package/out/web/assets/SettingsWindow-DcMVmU9u.css +1 -0
  215. package/out/web/assets/SkillsView-rNs1qr_U.js +2 -0
  216. package/out/web/assets/ToolSurfacePage-B9DzEPWN.js +37 -0
  217. package/out/web/assets/ToolSurfacePage-CTfgggF2.css +1 -0
  218. package/out/web/assets/VeoStudioPanel-DOj7_WR3.css +1 -0
  219. package/out/web/assets/VeoStudioPanel-DiJs_Cg2.js +4 -0
  220. package/out/web/assets/WorkspacePanel-CbJ1PFoZ.js +1 -0
  221. package/out/web/assets/WorkspaceSelector-B2xIp04D.js +1 -0
  222. package/out/web/assets/WorkspaceSelector-Ca8uJOsS.css +1 -0
  223. package/out/web/assets/{abnfDiagram-VCTEODGH-DAOBA7ZG.js → abnfDiagram-VCTEODGH-CD0CjoGl.js} +1 -1
  224. package/out/web/assets/{architecture-7GRP2DOG-CgSwQOPQ.js → architecture-7GRP2DOG-RKV83OeZ.js} +1 -1
  225. package/out/web/assets/{architectureDiagram-5GKGNRK7-CYp3yupP.js → architectureDiagram-5GKGNRK7-nN_HAFct.js} +1 -1
  226. package/out/web/assets/{blockDiagram-NRAW4CY4-CyWybDWr.js → blockDiagram-NRAW4CY4-BrrqzHW5.js} +1 -1
  227. package/out/web/assets/{c4Diagram-UCG6FXSJ-BvY3U709.js → c4Diagram-UCG6FXSJ-DTdV8_zE.js} +1 -1
  228. package/out/web/assets/{chunk-75Z2AOVW-TLXCoZYv.js → chunk-75Z2AOVW-_M0z5olV.js} +1 -1
  229. package/out/web/assets/chunk-CKBBP62Z-BpQEgeHF.js +2 -0
  230. package/out/web/assets/{chunk-CLGD4ZFX-xjsKtNS7.js → chunk-CLGD4ZFX-D54yGvGS.js} +1 -1
  231. package/out/web/assets/chunk-DSNCTWBM-C-gvT2ru.js +2 -0
  232. package/out/web/assets/chunk-DU6HZSFF-CnFngIhW.js +128 -0
  233. package/out/web/assets/{chunk-F27PBJKO-BFpgF55A.js → chunk-F27PBJKO-BqtWrnEO.js} +1 -1
  234. package/out/web/assets/{chunk-G27WJ6UU-DfF7qW-C.js → chunk-G27WJ6UU-Ckoq5mi2.js} +1 -1
  235. package/out/web/assets/{chunk-GMAD6QVW-C-558kh_.js → chunk-GMAD6QVW-BuhEcgHq.js} +1 -1
  236. package/out/web/assets/{chunk-JQ64N6SF-wJmeGKAw.js → chunk-JQ64N6SF-CF8T7GiZ.js} +1 -1
  237. package/out/web/assets/{chunk-LCL6LL3I-C1wHD8Ie.js → chunk-LCL6LL3I-BhXV9zyH.js} +1 -1
  238. package/out/web/assets/{chunk-OBVCFTLP-BsRTPBqs.js → chunk-OBVCFTLP-CRIkunUB.js} +1 -1
  239. package/out/web/assets/{chunk-P2QGCYS3-HZIiM7Ni.js → chunk-P2QGCYS3-UFEU6BxZ.js} +1 -1
  240. package/out/web/assets/{chunk-POPQ4Y6H-Dk9wvVb0.js → chunk-POPQ4Y6H-CQcrNbjr.js} +1 -1
  241. package/out/web/assets/{chunk-PWAF6VOD-BmjYLNbq.js → chunk-PWAF6VOD-Cc2uVDsG.js} +1 -1
  242. package/out/web/assets/{chunk-R7TYR2AO-CaHIf-lK.js → chunk-R7TYR2AO-DiCxzdAY.js} +1 -1
  243. package/out/web/assets/{chunk-RHFEMEQ7-_T561hOU.js → chunk-RHFEMEQ7-b7hnPmrR.js} +1 -1
  244. package/out/web/assets/{chunk-SVP7TREG-CM-GGYoY.js → chunk-SVP7TREG-Bu_yYb-V.js} +1 -1
  245. package/out/web/assets/{chunk-TEH6E4GO-K2A8Vg2C.js → chunk-TEH6E4GO-G4Cdlyrt.js} +1 -1
  246. package/out/web/assets/classDiagram-DTDB5LWJ-RnC2mYO4.js +1 -0
  247. package/out/web/assets/classDiagram-v2-JRS7N3AN-RnC2mYO4.js +1 -0
  248. package/out/web/assets/config-CnvCChUM.js +2 -0
  249. package/out/web/assets/config-DM6oIVO3.css +1 -0
  250. package/out/web/assets/core-DsKkQ7ig.js +1 -0
  251. package/out/web/assets/{cynefin-OW5HDTMX-ClzaB6cc.js → cynefin-OW5HDTMX-CnzQfOGp.js} +1 -1
  252. package/out/web/assets/{cynefinDiagram-5FMLGOSQ-D_JzZBzf.js → cynefinDiagram-5FMLGOSQ-DVtQnfpm.js} +1 -1
  253. package/out/web/assets/{dagre-3AP2YEHR-BDuUeMHj.js → dagre-3AP2YEHR-DG76_k5_.js} +1 -1
  254. package/out/web/assets/{diagram-S7CK7UJ4-DgtcfE8P.js → diagram-S7CK7UJ4-CaouUoze.js} +1 -1
  255. package/out/web/assets/{diagram-UQ7AKVKN-DTLoEYti.js → diagram-UQ7AKVKN-B4bEc26B.js} +1 -1
  256. package/out/web/assets/{diagram-VSXAHHWV-ChGl9pXz.js → diagram-VSXAHHWV-BJ86Ov2Y.js} +1 -1
  257. package/out/web/assets/{diagram-VX7I27RA-Be8DWz0S.js → diagram-VX7I27RA-7hH5IPYf.js} +1 -1
  258. package/out/web/assets/{diagram-Z3DM3KII-BMXjRTOF.js → diagram-Z3DM3KII-CCM4clo8.js} +1 -1
  259. package/out/web/assets/dist-js-BkYNznHX.js +1 -0
  260. package/out/web/assets/{ebnfDiagram-PWID7BFC-8Q9pl1CJ.js → ebnfDiagram-PWID7BFC-Da7WAM3k.js} +1 -1
  261. package/out/web/assets/{erDiagram-SSCWMZ5O-DjH8Lnkn.js → erDiagram-SSCWMZ5O-CzzmnZWT.js} +1 -1
  262. package/out/web/assets/event-Cdt7Byyj.js +1 -0
  263. package/out/web/assets/{eventmodeling-NTZA5JFV-BKUH_DOp.js → eventmodeling-NTZA5JFV-xcfsA0XD.js} +1 -1
  264. package/out/web/assets/fira-code-latin-600-normal-BmSSHshu.woff +0 -0
  265. package/out/web/assets/fira-code-latin-600-normal-CvYZpPHg.woff2 +0 -0
  266. package/out/web/assets/fira-code-symbols2-600-normal-Dvq6IQE5.woff +0 -0
  267. package/out/web/assets/flowDiagram-A5DVABFB-JdtH1673.js +1 -0
  268. package/out/web/assets/{ganttDiagram-EL5Y4UJY-D7fZKJNM.js → ganttDiagram-EL5Y4UJY-B3ClFGmL.js} +1 -1
  269. package/out/web/assets/{gitGraph-4MIJSDKK-BypWaaBU.js → gitGraph-4MIJSDKK-BZ_y_cDU.js} +1 -1
  270. package/out/web/assets/{gitGraphDiagram-WWUBYQGX-DWiw_3bq.js → gitGraphDiagram-WWUBYQGX-drhRSYm3.js} +1 -1
  271. package/out/web/assets/index-BZ9xgmMP.css +1 -0
  272. package/out/web/assets/index-Ca8cCS4h.js +168 -0
  273. package/out/web/assets/{info-A6RAGUB7-KkAUxT4j.js → info-A6RAGUB7-B7I3K0F1.js} +1 -1
  274. package/out/web/assets/{infoDiagram-RXCK75RN-BNb6E48y.js → infoDiagram-RXCK75RN-deX_1MPh.js} +1 -1
  275. package/out/web/assets/{ishikawaDiagram-5VMMS53U-Caa-JoAK.js → ishikawaDiagram-5VMMS53U-s38yo28y.js} +1 -1
  276. package/out/web/assets/{journeyDiagram-EYS64GPL-DOrmFGz6.js → journeyDiagram-EYS64GPL-CZn2kB8b.js} +1 -1
  277. package/out/web/assets/jsx-runtime-DN4NhQUK.js +1 -0
  278. package/out/web/assets/{kanban-definition-3QL26DDD-BOWCYcK0.js → kanban-definition-3QL26DDD-DodjgySL.js} +1 -1
  279. package/out/web/assets/markdown-CMhYIcWB.js +39 -0
  280. package/out/web/assets/{mermaid-parser.core-BQqjCkS_.js → mermaid-parser.core-Whu2rlJC.js} +3 -3
  281. package/out/web/assets/mermaid.core-CKyPo8VH.js +11 -0
  282. package/out/web/assets/{mindmap-definition-FBJOCRG2-jTceWpr0.js → mindmap-definition-FBJOCRG2-260WBDxZ.js} +1 -1
  283. package/out/web/assets/modelManager-CUaGWMWu.js +2 -0
  284. package/out/web/assets/oauthManager-DlNhXJr6.js +1 -0
  285. package/out/web/assets/{packet-AYTQ26CC-CJ5RXgol.js → packet-AYTQ26CC-CEeIRKRG.js} +1 -1
  286. package/out/web/assets/{pegDiagram-XKGWAZYB-y8wMtd0y.js → pegDiagram-XKGWAZYB-BYadI-KO.js} +1 -1
  287. package/out/web/assets/{pie-WAS4IAKB-72fTBbl4.js → pie-WAS4IAKB-D8uf4dh5.js} +1 -1
  288. package/out/web/assets/{pieDiagram-E7YTZNPT-e0O02qWq.js → pieDiagram-E7YTZNPT-CjSDy4hO.js} +1 -1
  289. package/out/web/assets/{quadrantDiagram-AXDQQJYC-C9phYLom.js → quadrantDiagram-AXDQQJYC-B8D3gU5d.js} +1 -1
  290. package/out/web/assets/{radar-RG4KPBEZ-BAU2hzUT.js → radar-RG4KPBEZ-DZJxnokY.js} +1 -1
  291. package/out/web/assets/{railroad-74A4TZTK-B0bCAVHC.js → railroad-74A4TZTK-DBysUiUi.js} +1 -1
  292. package/out/web/assets/{railroad-abnf-HS5TGJTU-WhxO7ndE.js → railroad-abnf-HS5TGJTU-CHWxoJYg.js} +1 -1
  293. package/out/web/assets/{railroad-ebnf-LZEXJU2U-BkA0m7-F.js → railroad-ebnf-LZEXJU2U-DDv7X6bY.js} +1 -1
  294. package/out/web/assets/{railroad-peg-WCYAUIDC-BsVpHIaj.js → railroad-peg-WCYAUIDC-DpfcYYNJ.js} +1 -1
  295. package/out/web/assets/{railroadDiagram-O6MQD6OU-CyOLN65Q.js → railroadDiagram-O6MQD6OU-CYtyv0t3.js} +1 -1
  296. package/out/web/assets/{requirementDiagram-EFPCY7ZU-DQXJ7Dud.js → requirementDiagram-EFPCY7ZU-D2X-Ewik.js} +1 -1
  297. package/out/web/assets/{sankeyDiagram-P5KCCOFB-B2XLyIIc.js → sankeyDiagram-P5KCCOFB-Bn2x6C4Y.js} +1 -1
  298. package/out/web/assets/{sequenceDiagram-WJ2MYXX4-DGQY4wwm.js → sequenceDiagram-WJ2MYXX4-BvFLKtPd.js} +1 -1
  299. package/out/web/assets/{stateDiagram-HBIQ2CUA-DHZpDwNy.js → stateDiagram-HBIQ2CUA-Bx0GWeaY.js} +1 -1
  300. package/out/web/assets/stateDiagram-v2-4QOOHH4V--hol1yg_.js +1 -0
  301. package/out/web/assets/studio-B1mk40wD.js +1 -0
  302. package/out/web/assets/{swimlanes-XN3QIQJK-Bn_jcZz-.js → swimlanes-XN3QIQJK-CCma0T7L.js} +1 -1
  303. package/out/web/assets/swimlanesDiagram-VK2B7HYN-BkohoVsU.js +8 -0
  304. package/out/web/assets/{timeline-definition-24CTP7MA-CdTERuJZ.js → timeline-definition-24CTP7MA-iCRhhJ7C.js} +1 -1
  305. package/out/web/assets/{treeView-Q6P3EWNA-TKBKQG6R.js → treeView-Q6P3EWNA-DZ-y08qp.js} +1 -1
  306. package/out/web/assets/{treemap-WGGIJYW6-BP7gQoiC.js → treemap-WGGIJYW6-De0CxzMx.js} +1 -1
  307. package/out/web/assets/{vennDiagram-4TSXK5OY-BHUmxDuK.js → vennDiagram-4TSXK5OY-w_7aZ6xe.js} +1 -1
  308. package/out/web/assets/{wardley-WFR3VGLG-9bct5AAN.js → wardley-WFR3VGLG-DT0y0xJ4.js} +1 -1
  309. package/out/web/assets/{wardleyDiagram-VM6X3IG4-BfJwDDso.js → wardleyDiagram-VM6X3IG4-DAdXELbQ.js} +1 -1
  310. package/out/web/assets/window-BJCVtyET.js +1 -0
  311. package/out/web/assets/{xychartDiagram-S5SC5T6Z-Dqd9Mvpo.js → xychartDiagram-S5SC5T6Z-IZIXf3Vo.js} +1 -1
  312. package/out/web/index-web.html +4 -4
  313. package/out/web/index.html +4 -4
  314. package/package.json +80 -20
  315. package/shared-modules/.github/workflows/ci.yml +120 -0
  316. package/shared-modules/.github/workflows/update.yaml +28 -0
  317. package/slash-commands.json +16 -2
  318. package/src/bin/auto-build.js +66 -0
  319. package/src/bin/desktop.js +113 -0
  320. package/src/bin/desktop.test.js +113 -0
  321. package/src/bin/index.js +18 -25
  322. package/src/bin/index.test.js +89 -0
  323. package/src/bin/measure-effects.mjs +53 -0
  324. package/src/bin/package.test.js +28 -0
  325. package/src/bin/release-notes.test.js +84 -0
  326. package/src/bin/styles.test.js +20 -0
  327. package/src/bin/web.js +5 -0
  328. package/src/bin/web.test.js +39 -0
  329. package/src/renderer/index-web.html +1 -0
  330. package/src/renderer/index.html +1 -2
  331. package/src/renderer/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  332. package/src/renderer/shared/agentProgress.ts +201 -3
  333. package/src/renderer/shared/components/AgentActivityDrawer.tsx +9 -8
  334. package/src/renderer/shared/components/AgentActivityTable.tsx +193 -133
  335. package/src/renderer/shared/components/ApprovalCard.test.tsx +24 -0
  336. package/src/renderer/shared/components/ApprovalCard.tsx +10 -3
  337. package/src/renderer/shared/components/ArtifactPreviewPanel.tsx +91 -40
  338. package/src/renderer/shared/components/AuthGate.tsx +79 -48
  339. package/src/renderer/shared/components/BackgroundTerminals.tsx +181 -0
  340. package/src/renderer/shared/components/CalculationCard.tsx +41 -15
  341. package/src/renderer/shared/components/ChatCodeBlock.tsx +8 -4
  342. package/src/renderer/shared/components/ChatMessageItem.test.tsx +68 -0
  343. package/src/renderer/shared/components/ChatMessageItem.tsx +52 -33
  344. package/src/renderer/shared/components/ChatPanel.test.tsx +21 -0
  345. package/src/renderer/shared/components/ChatPanel.tsx +676 -415
  346. package/src/renderer/shared/components/ChunkErrorBoundary.tsx +115 -64
  347. package/src/renderer/shared/components/CliSessionsView.test.tsx +125 -0
  348. package/src/renderer/shared/components/CliSessionsView.tsx +543 -0
  349. package/src/renderer/shared/components/CodeReviewPage.tsx +668 -0
  350. package/src/renderer/shared/components/CollapsiblePasteInput.tsx +90 -0
  351. package/src/renderer/shared/components/CommandPalette.tsx +8 -8
  352. package/src/renderer/shared/components/ContextCompactionStatus.tsx +17 -0
  353. package/src/renderer/shared/components/DashboardSidebar.tsx +853 -229
  354. package/src/renderer/shared/components/DesktopTitlebar.tsx +371 -0
  355. package/src/renderer/shared/components/DiffReviewModal.tsx +3 -3
  356. package/src/renderer/shared/components/ErrorNotice.tsx +29 -0
  357. package/src/renderer/shared/components/FormattedMessage.tsx +11 -0
  358. package/src/renderer/shared/components/GeminiLiveOverlay.css +86 -0
  359. package/src/renderer/shared/components/GeminiLiveOverlay.test.tsx +24 -0
  360. package/src/renderer/shared/components/GeminiLiveOverlay.tsx +85 -101
  361. package/src/renderer/shared/components/GitBranchSelector.tsx +442 -0
  362. package/src/renderer/shared/components/GlideSelect.css +138 -0
  363. package/src/renderer/shared/components/GlideSelect.d.ts +31 -0
  364. package/src/renderer/shared/components/GlideSelect.jsx +266 -0
  365. package/src/renderer/shared/components/ImageGenCard.tsx +31 -12
  366. package/src/renderer/shared/components/ImageSearchCard.tsx +76 -65
  367. package/src/renderer/shared/components/ImageStudioPanel.tsx +49 -49
  368. package/src/renderer/shared/components/InlineThoughtNote.tsx +27 -0
  369. package/src/renderer/shared/components/LibraryItemCard.tsx +72 -0
  370. package/src/renderer/shared/components/LibraryPage.tsx +165 -0
  371. package/src/renderer/shared/components/LibraryPreview.tsx +59 -0
  372. package/src/renderer/shared/components/LinkedFoldersView.tsx +365 -46
  373. package/src/renderer/shared/components/McpRegistryPicker.tsx +1 -1
  374. package/src/renderer/shared/components/McpServersView.tsx +51 -30
  375. package/src/renderer/shared/components/McpToolAllowlist.tsx +2 -4
  376. package/src/renderer/shared/components/McpToolResults.tsx +99 -0
  377. package/src/renderer/shared/components/MermaidCard.tsx +14 -8
  378. package/src/renderer/shared/components/MintDashboard.tsx +1002 -831
  379. package/src/renderer/shared/components/ModSessionControls.tsx +8 -0
  380. package/src/renderer/shared/components/ModUi.test.tsx +65 -0
  381. package/src/renderer/shared/components/ModUi.tsx +26 -0
  382. package/src/renderer/shared/components/ModelSelectorPopover.tsx +547 -219
  383. package/src/renderer/shared/components/ModsPanel.tsx +156 -0
  384. package/src/renderer/shared/components/PlanChecklistWidget.tsx +1 -1
  385. package/src/renderer/shared/components/PluginsView.tsx +1 -1
  386. package/src/renderer/shared/components/ProgressActivity.tsx +17 -0
  387. package/src/renderer/shared/components/ReviewHistory.tsx +42 -0
  388. package/src/renderer/shared/components/RewindModal.tsx +11 -18
  389. package/src/renderer/shared/components/RunSummaryDashboard.tsx +8 -14
  390. package/src/renderer/shared/components/ScheduledTasksView.tsx +11 -10
  391. package/src/renderer/shared/components/ScreenCaptureDialog.css +221 -0
  392. package/src/renderer/shared/components/ScreenCaptureDialog.tsx +199 -0
  393. package/src/renderer/shared/components/SelectField.test.tsx +27 -0
  394. package/src/renderer/shared/components/SelectField.tsx +38 -0
  395. package/src/renderer/shared/components/SessionSources.tsx +48 -0
  396. package/src/renderer/shared/components/SessionSourcesPopover.tsx +61 -0
  397. package/src/renderer/shared/components/Settings/AgentsTab.tsx +41 -45
  398. package/src/renderer/shared/components/Settings/AudioTab.tsx +16 -15
  399. package/src/renderer/shared/components/Settings/AutomationTab.tsx +10 -60
  400. package/src/renderer/shared/components/Settings/AvatarCropModal.tsx +368 -0
  401. package/src/renderer/shared/components/Settings/GeneralTab.tsx +368 -113
  402. package/src/renderer/shared/components/Settings/MemoryTab.test.tsx +37 -0
  403. package/src/renderer/shared/components/Settings/MemoryTab.tsx +71 -31
  404. package/src/renderer/shared/components/Settings/NotificationsTab.test.tsx +15 -0
  405. package/src/renderer/shared/components/Settings/NotificationsTab.tsx +84 -0
  406. package/src/renderer/shared/components/Settings/PluginsTab.tsx +20 -12
  407. package/src/renderer/shared/components/Settings/ProfileTab.tsx +29 -5
  408. package/src/renderer/shared/components/Settings/SearchableModelCombobox.tsx +411 -0
  409. package/src/renderer/shared/components/Settings/ThemeTab.tsx +416 -165
  410. package/src/renderer/shared/components/SkillsView.tsx +41 -16
  411. package/src/renderer/shared/components/SlashChoicePanel.tsx +88 -0
  412. package/src/renderer/shared/components/SlashSuggestions.test.tsx +33 -0
  413. package/src/renderer/shared/components/SlashSuggestions.tsx +41 -12
  414. package/src/renderer/shared/components/SourcesBlock.tsx +55 -51
  415. package/src/renderer/shared/components/StockCard.tsx +58 -24
  416. package/src/renderer/shared/components/SubagentDagView.tsx +4 -4
  417. package/src/renderer/shared/components/TerminalDock.tsx +241 -0
  418. package/src/renderer/shared/components/ThinkingBlock.tsx +14 -8
  419. package/src/renderer/shared/components/ToolSurfacePage.test.tsx +32 -0
  420. package/src/renderer/shared/components/ToolSurfacePage.tsx +568 -0
  421. package/src/renderer/shared/components/ToolsPanelToggle.tsx +13 -0
  422. package/src/renderer/shared/components/UiFeatureCard.tsx +267 -0
  423. package/src/renderer/shared/components/UiGridCard.tsx +188 -0
  424. package/src/renderer/shared/components/UiMockupWidget.tsx +149 -0
  425. package/src/renderer/shared/components/VeoStudioPanel.tsx +22 -37
  426. package/src/renderer/shared/components/ViewedImages.tsx +36 -0
  427. package/src/renderer/shared/components/VirtualChatHistory.tsx +82 -0
  428. package/src/renderer/shared/components/VoicePill.css +85 -0
  429. package/src/renderer/shared/components/VoicePill.d.ts +12 -0
  430. package/src/renderer/shared/components/VoicePill.jsx +190 -0
  431. package/src/renderer/shared/components/VoicePill.test.tsx +22 -0
  432. package/src/renderer/shared/components/WeatherCard.tsx +3 -3
  433. package/src/renderer/shared/components/WorkspaceContextPopover.tsx +138 -0
  434. package/src/renderer/shared/components/WorkspacePaneResizer.tsx +92 -0
  435. package/src/renderer/shared/components/WorkspacePreviewActions.test.tsx +44 -0
  436. package/src/renderer/shared/components/WorkspacePreviewActions.tsx +19 -0
  437. package/src/renderer/shared/components/WorkspaceSelector.tsx +154 -0
  438. package/src/renderer/shared/components/background-terminals.css +292 -0
  439. package/src/renderer/shared/components/ui/README.md +52 -0
  440. package/src/renderer/shared/components/ui/button.tsx +37 -0
  441. package/src/renderer/shared/components/ui/demo.tsx +26 -0
  442. package/src/renderer/shared/components/ui/error-recovery.css +35 -0
  443. package/src/renderer/shared/components/ui/error-recovery.tsx +35 -0
  444. package/src/renderer/shared/components/ui/voice-powered-orb.css +6 -0
  445. package/src/renderer/shared/components/ui/voice-powered-orb.tsx +374 -0
  446. package/src/renderer/shared/components/workspace-selector.css +248 -0
  447. package/src/renderer/shared/constants/config.ts +57 -3
  448. package/src/renderer/shared/constants/models.ts +189 -2
  449. package/src/renderer/shared/constants/slashCommands.ts +1 -1
  450. package/src/renderer/shared/conversation/coordinator.test.ts +27 -0
  451. package/src/renderer/shared/conversation/coordinator.ts +82 -0
  452. package/src/renderer/shared/conversation/lifecycle.test.ts +362 -0
  453. package/src/renderer/shared/conversation/lifecycle.ts +418 -0
  454. package/src/renderer/shared/conversation/projectNavigation.test.ts +105 -0
  455. package/src/renderer/shared/conversation/projectNavigation.ts +39 -0
  456. package/src/renderer/shared/conversation/sourcesTransport.ts +27 -0
  457. package/src/renderer/shared/conversation/syncView.test.ts +13 -0
  458. package/src/renderer/shared/conversation/syncView.ts +6 -0
  459. package/src/renderer/shared/conversation/transport.test.ts +163 -0
  460. package/src/renderer/shared/conversation/transport.ts +159 -0
  461. package/src/renderer/shared/conversation/useConversationCoordinator.ts +64 -0
  462. package/src/renderer/shared/css/agent-observability.css +46 -15
  463. package/src/renderer/shared/css/auth-gate.css +114 -15
  464. package/src/renderer/shared/css/chat-ui-cards.css +495 -0
  465. package/src/renderer/shared/css/code-review.css +856 -0
  466. package/src/renderer/shared/css/code-sessions.css +479 -0
  467. package/src/renderer/shared/css/collapsed-paste.css +35 -0
  468. package/src/renderer/shared/css/effects.css +15 -0
  469. package/src/renderer/shared/css/error-notice.css +60 -0
  470. package/src/renderer/shared/css/file-changes.css +132 -0
  471. package/src/renderer/shared/css/image-studio.css +16 -16
  472. package/src/renderer/shared/css/library.css +476 -0
  473. package/src/renderer/shared/css/management-views.css +415 -27
  474. package/src/renderer/shared/css/mcp-results.css +11 -0
  475. package/src/renderer/shared/css/model-selector.css +543 -85
  476. package/src/renderer/shared/css/mods.css +77 -0
  477. package/src/renderer/shared/css/notification-notice.css +28 -0
  478. package/src/renderer/shared/css/session-sources-popover.css +9 -0
  479. package/src/renderer/shared/css/session-sources.css +23 -0
  480. package/src/renderer/shared/css/settings/agents.css +1 -1
  481. package/src/renderer/shared/css/settings/automation.css +13 -13
  482. package/src/renderer/shared/css/settings/general.css +526 -5
  483. package/src/renderer/shared/css/settings/memory.css +154 -0
  484. package/src/renderer/shared/css/settings/notifications.css +11 -0
  485. package/src/renderer/shared/css/settings/plugins.css +5 -5
  486. package/src/renderer/shared/css/settings/profile.css +331 -1
  487. package/src/renderer/shared/css/settings/theme.css +656 -3
  488. package/src/renderer/shared/css/slash-choice.css +95 -0
  489. package/src/renderer/shared/css/slash-suggestions.css +68 -0
  490. package/src/renderer/shared/css/sources-block.css +91 -0
  491. package/src/renderer/shared/css/thinking-status.css +46 -0
  492. package/src/renderer/shared/css/tools-panel.css +7 -0
  493. package/src/renderer/shared/css/ui-tailwind.css +19 -0
  494. package/src/renderer/shared/css/veo-studio.css +16 -15
  495. package/src/renderer/shared/css/viewed-images.css +15 -0
  496. package/src/renderer/shared/fonts.css +46 -0
  497. package/src/renderer/shared/fonts.ts +10 -37
  498. package/src/renderer/shared/lib/utils.ts +6 -0
  499. package/src/renderer/shared/library/controller.test.ts +61 -0
  500. package/src/renderer/shared/library/controller.ts +57 -0
  501. package/src/renderer/shared/library/transport.test.ts +26 -0
  502. package/src/renderer/shared/library/transport.ts +60 -0
  503. package/src/renderer/shared/library/useLibraryFile.ts +38 -0
  504. package/src/renderer/shared/mods.ts +58 -0
  505. package/src/renderer/shared/platform.test.ts +90 -0
  506. package/src/renderer/shared/platform.ts +219 -7
  507. package/src/renderer/shared/theme/themeManager.test.ts +43 -0
  508. package/src/renderer/shared/theme/themeManager.ts +157 -0
  509. package/src/renderer/shared/theme/themes.ts +116 -0
  510. package/src/renderer/shared/theme/tokens.css +318 -0
  511. package/src/renderer/shared/types.ts +137 -2
  512. package/src/renderer/shared/utils/agentActivity.test.ts +75 -0
  513. package/src/renderer/shared/utils/agentActivity.ts +168 -8
  514. package/src/renderer/shared/utils/approval.tsx +7 -0
  515. package/src/renderer/shared/utils/artifactBrowser.test.ts +80 -0
  516. package/src/renderer/shared/utils/artifactBrowser.ts +41 -0
  517. package/src/renderer/shared/utils/cardJson.test.ts +35 -0
  518. package/src/renderer/shared/utils/cardJson.ts +30 -0
  519. package/src/renderer/shared/utils/contextCompaction.test.tsx +48 -0
  520. package/src/renderer/shared/utils/contextCompaction.ts +21 -0
  521. package/src/renderer/shared/utils/effectVisibility.ts +9 -0
  522. package/src/renderer/shared/utils/fileIcons.ts +1 -1
  523. package/src/renderer/shared/utils/markdown.tsx +330 -81
  524. package/src/renderer/shared/utils/markdown.webImages.test.tsx +40 -0
  525. package/src/renderer/shared/utils/mcpResults.test.tsx +91 -0
  526. package/src/renderer/shared/utils/modViewport.ts +7 -0
  527. package/src/renderer/shared/utils/nativeRecordingSession.test.ts +61 -0
  528. package/src/renderer/shared/utils/nativeRecordingSession.ts +46 -0
  529. package/src/renderer/shared/utils/notificationSettings.test.ts +14 -0
  530. package/src/renderer/shared/utils/notificationSettings.ts +23 -0
  531. package/src/renderer/shared/utils/notifications.test.ts +51 -0
  532. package/src/renderer/shared/utils/notifications.ts +54 -0
  533. package/src/renderer/shared/utils/pastedText.test.ts +20 -0
  534. package/src/renderer/shared/utils/pastedText.ts +13 -0
  535. package/src/renderer/shared/utils/progressCache.test.ts +32 -0
  536. package/src/renderer/shared/utils/providers.ts +8 -3
  537. package/src/renderer/shared/utils/screenCapture.ts +43 -0
  538. package/src/renderer/shared/utils/sessionSources.test.ts +31 -0
  539. package/src/renderer/shared/utils/sessionSources.ts +34 -0
  540. package/src/renderer/shared/utils/slashCommandProcessor.ts +5 -2
  541. package/src/renderer/shared/utils/sourceAttachments.ts +28 -0
  542. package/src/renderer/shared/utils/speech.ts +51 -9
  543. package/src/renderer/shared/utils/syntaxHighlight.test.tsx +22 -0
  544. package/src/renderer/shared/utils/syntaxHighlight.tsx +26 -0
  545. package/src/renderer/shared/utils/ui.ts +4 -64
  546. package/src/renderer/shared/utils/useGeminiLiveVoice.ts +49 -5
  547. package/src/renderer/shared/utils/useLatestCallback.ts +9 -0
  548. package/src/renderer/shared/utils/useNativeVoiceInput.ts +80 -72
  549. package/src/renderer/shared/utils/useSessionSources.ts +33 -0
  550. package/src/renderer/shared/utils/viewedImages.ts +26 -0
  551. package/src/renderer/shared/utils/workspacePane.test.ts +33 -0
  552. package/src/renderer/shared/utils/workspacePane.ts +20 -0
  553. package/src/renderer/shared/utils/workspacePreview.test.ts +24 -0
  554. package/src/renderer/shared/utils/workspacePreview.ts +16 -0
  555. package/src/renderer/shared/utils/workspaceSnapshot.test.ts +49 -0
  556. package/src/renderer/shared/utils/workspaceSnapshot.ts +26 -0
  557. package/src/renderer/shared/utils/workspaces.ts +10 -0
  558. package/src/renderer/shared/workspaceUndo.ts +88 -0
  559. package/src/renderer/src/App.tsx +16 -1
  560. package/src/renderer/src/components/BrowserShell.tsx +108 -0
  561. package/src/renderer/src/components/BrowserSuggestionsPopup.tsx +91 -0
  562. package/src/renderer/src/components/LiveTranslateControls.tsx +65 -0
  563. package/src/renderer/src/components/MintDashboard.tsx +4 -2
  564. package/src/renderer/src/components/PicturesLibrary.tsx +2 -287
  565. package/src/renderer/src/components/ScreenPicker.css +227 -0
  566. package/src/renderer/src/components/ScreenPicker.tsx +312 -526
  567. package/src/renderer/src/components/SettingsWindow.tsx +48 -5
  568. package/src/renderer/src/components/SpotlightWindow.tsx +1 -0
  569. package/src/renderer/src/components/WidgetWindow.tsx +27 -3
  570. package/src/renderer/src/components/WorkspacePanel.tsx +269 -61
  571. package/src/renderer/src/components/browser-shell.css +185 -0
  572. package/src/renderer/src/components/browser-suggestions-popup.css +55 -0
  573. package/src/renderer/src/components/liveTranslateFrames.test.ts +44 -0
  574. package/src/renderer/src/components/liveTranslateFrames.ts +45 -0
  575. package/src/renderer/src/components/liveTranslateLanguage.ts +6 -0
  576. package/src/renderer/src/css/app-shell.css +400 -204
  577. package/src/renderer/src/css/chat.css +1666 -594
  578. package/src/renderer/src/css/dashboard.css +11 -0
  579. package/src/renderer/src/css/desktop-tools.css +928 -0
  580. package/src/renderer/src/css/misc.css +5 -60
  581. package/src/renderer/src/css/pictures.css +2 -407
  582. package/src/renderer/src/css/settings/base.css +394 -157
  583. package/src/renderer/src/css/sidebar-workspace.css +1072 -376
  584. package/src/renderer/src/css/spotlight.css +15 -26
  585. package/src/renderer/src/css/tool-surfaces.css +784 -0
  586. package/src/renderer/src/css/widget.css +36 -8
  587. package/src/renderer/src/env.d.ts +4 -9
  588. package/src/renderer/src/hooks/useProviderModels.ts +2 -9
  589. package/src/renderer/src/index.css +53 -46
  590. package/src/renderer/src/main.tsx +12 -0
  591. package/src/renderer/src/proactiveSuggestions.ts +29 -0
  592. package/src/renderer/src/tauri.ts +302 -339
  593. package/src/renderer/src/voiceInput.ts +2 -1
  594. package/src/renderer/src-web/App.tsx +40 -0
  595. package/src/renderer/src-web/components/MintDashboard.tsx +4 -2
  596. package/src/renderer/src-web/components/PicturesLibrary.tsx +2 -284
  597. package/src/renderer/src-web/components/PullToRefresh.tsx +107 -0
  598. package/src/renderer/src-web/components/SettingsWindow.tsx +36 -5
  599. package/src/renderer/src-web/css/app-shell.css +188 -207
  600. package/src/renderer/src-web/css/chat.css +1236 -507
  601. package/src/renderer/src-web/css/dashboard.css +11 -0
  602. package/src/renderer/src-web/css/misc.css +3 -55
  603. package/src/renderer/src-web/css/mobile.css +679 -0
  604. package/src/renderer/src-web/css/pictures.css +2 -415
  605. package/src/renderer/src-web/css/pull-to-refresh.css +54 -0
  606. package/src/renderer/src-web/css/settings/base.css +353 -134
  607. package/src/renderer/src-web/css/settings/mobile.css +320 -0
  608. package/src/renderer/src-web/css/sidebar-workspace.css +546 -187
  609. package/src/renderer/src-web/css/spotlight.css +9 -26
  610. package/src/renderer/src-web/css/widget.css +1 -6
  611. package/src/renderer/src-web/env.d.ts +4 -12
  612. package/src/renderer/src-web/hooks/useProviderModels.ts +2 -9
  613. package/src/renderer/src-web/index.css +53 -96
  614. package/src/renderer/src-web/main.tsx +12 -0
  615. package/src/renderer/src-web/proactiveSuggestions.ts +3 -0
  616. package/src/renderer/src-web/tauri.ts +309 -364
  617. package/src/renderer/tests/backgroundTerminals.browser.html +81 -0
  618. package/src/renderer/tests/chatPanelFixture.ts +23 -0
  619. package/src/renderer/tests/chatPerformance.browser.html +71 -0
  620. package/src/renderer/tests/cliSessions.browser.html +82 -0
  621. package/src/renderer/tests/collapsedPaste.browser.html +70 -0
  622. package/src/renderer/tests/composerMenus.browser.html +116 -0
  623. package/src/renderer/tests/contextCompaction.browser.html +17 -0
  624. package/src/renderer/tests/conversationLifecycle.browser.html +70 -0
  625. package/src/renderer/tests/effectsPerformance.browser.html +13 -0
  626. package/src/renderer/tests/errorRecovery.browser.html +21 -0
  627. package/src/renderer/tests/glideSelect.browser.html +71 -0
  628. package/src/renderer/tests/glideSelect.preview.html +27 -0
  629. package/src/renderer/tests/library.browser.html +1 -0
  630. package/src/renderer/tests/library.browser.tsx +78 -0
  631. package/src/renderer/tests/liveOrb.browser.html +49 -0
  632. package/src/renderer/tests/liveVoice.browser.html +29 -0
  633. package/src/renderer/tests/modInput.browser.html +22 -0
  634. package/src/renderer/tests/sessionSources.browser.html +1 -0
  635. package/src/renderer/tests/sessionSources.browser.tsx +107 -0
  636. package/src/renderer/tests/skills.browser.html +24 -0
  637. package/src/renderer/tests/toolsPanel.browser.html +1 -0
  638. package/src/renderer/tests/toolsPanel.browser.tsx +113 -0
  639. package/src/renderer/tests/viewedImages.browser.html +1 -0
  640. package/src/renderer/tests/viewedImages.browser.tsx +93 -0
  641. package/src/renderer/tests/voicePill.browser.html +80 -0
  642. package/src/renderer/tests/voicePill.preview.html +34 -0
  643. package/src/renderer/tests/webSources.browser.html +1 -0
  644. package/src/renderer/tests/webSources.browser.tsx +98 -0
  645. package/src/renderer/tests/workspaceUndo.browser.html +92 -0
  646. package/src-tauri/Cargo.toml +40 -0
  647. package/src-tauri/build.rs +3 -0
  648. package/src-tauri/src/app/lifecycle.rs +277 -0
  649. package/src-tauri/src/app/mod.rs +4 -0
  650. package/src-tauri/src/app/shortcuts.rs +40 -0
  651. package/src-tauri/src/app/tray.rs +52 -0
  652. package/src-tauri/src/background/events.rs +70 -0
  653. package/src-tauri/src/background/headless.rs +230 -0
  654. package/src-tauri/src/background/mod.rs +4 -0
  655. package/src-tauri/src/background/proactive.rs +262 -0
  656. package/src-tauri/src/commands/approvals.rs +20 -0
  657. package/src-tauri/src/commands/auth.rs +127 -0
  658. package/src-tauri/src/commands/conversation.rs +642 -0
  659. package/src-tauri/src/commands/integrations.rs +157 -0
  660. package/src-tauri/src/commands/media.rs +179 -0
  661. package/src-tauri/src/commands/mod.rs +11 -0
  662. package/src-tauri/src/commands/mods.rs +6 -0
  663. package/src-tauri/src/commands/settings.rs +141 -0
  664. package/src-tauri/src/commands/voice.rs +153 -0
  665. package/src-tauri/src/commands/workspace.rs +501 -0
  666. package/src-tauri/src/lib.rs +10 -0
  667. package/src-tauri/src/main.rs +3 -0
  668. package/src-tauri/src/native/actions.rs +206 -0
  669. package/src-tauri/src/native/browser.rs +252 -0
  670. package/src-tauri/src/native/capture.rs +695 -0
  671. package/src-tauri/src/native/discord_rpc.rs +99 -0
  672. package/src-tauri/src/native/integrations.rs +126 -0
  673. package/src-tauri/src/native/mod.rs +12 -0
  674. package/src-tauri/src/native/notifications.rs +51 -0
  675. package/src-tauri/src/native/plugins.rs +14 -0
  676. package/src-tauri/src/native/system.rs +250 -0
  677. package/src-tauri/src/native/terminal.rs +201 -0
  678. package/src-tauri/src/native/updater.rs +148 -0
  679. package/src-tauri/src/native/windows.rs +143 -0
  680. package/tsconfig.json +2 -0
  681. package/vite.config.ts +4 -1
  682. package/vite.config.web.ts +5 -0
  683. package/.cargo/config.toml +0 -13
  684. package/.claude/settings.local.json +0 -182
  685. package/.codex +0 -0
  686. package/CLAUDE.md +0 -102
  687. package/out/web/Live2DCubismCore.js +0 -9
  688. package/out/web/assets/MintDashboard-DWSqucgb.js +0 -57
  689. package/out/web/assets/SettingsWindow-DFM2aj5B.js +0 -2
  690. package/out/web/assets/chunk-CKBBP62Z-nr1uKPj9.js +0 -2
  691. package/out/web/assets/chunk-DSNCTWBM-Dtj8Rqsd.js +0 -2
  692. package/out/web/assets/chunk-DU6HZSFF-2tv5K1wT.js +0 -128
  693. package/out/web/assets/classDiagram-DTDB5LWJ-BdSFArgw.js +0 -1
  694. package/out/web/assets/classDiagram-v2-JRS7N3AN-BdSFArgw.js +0 -1
  695. package/out/web/assets/core-DImejIUG.js +0 -1
  696. package/out/web/assets/dist-js-BxuKEVWM.js +0 -1
  697. package/out/web/assets/event-BNl8Zahw.js +0 -1
  698. package/out/web/assets/fira-code-cyrillic-400-normal-UC0NFL4U.woff2 +0 -0
  699. package/out/web/assets/fira-code-cyrillic-400-normal-dc1q3VD7.woff +0 -0
  700. package/out/web/assets/fira-code-cyrillic-500-normal-Bu7VCL72.woff +0 -0
  701. package/out/web/assets/fira-code-cyrillic-500-normal-CX35h3Mg.woff2 +0 -0
  702. package/out/web/assets/fira-code-cyrillic-ext-400-normal-Buh61xzB.woff +0 -0
  703. package/out/web/assets/fira-code-cyrillic-ext-400-normal-txZ9Fk_1.woff2 +0 -0
  704. package/out/web/assets/fira-code-cyrillic-ext-500-normal-CYRspHgm.woff2 +0 -0
  705. package/out/web/assets/fira-code-cyrillic-ext-500-normal-CwtLmSFD.woff +0 -0
  706. package/out/web/assets/fira-code-greek-400-normal-B2Gh_Y8s.woff2 +0 -0
  707. package/out/web/assets/fira-code-greek-400-normal-DobhaxvF.woff +0 -0
  708. package/out/web/assets/fira-code-greek-500-normal-CVO0IRNt.woff2 +0 -0
  709. package/out/web/assets/fira-code-greek-500-normal-DEXIWiey.woff +0 -0
  710. package/out/web/assets/fira-code-greek-ext-400-normal-DR7mBgIM.woff2 +0 -0
  711. package/out/web/assets/fira-code-greek-ext-400-normal-DSPUheWg.woff +0 -0
  712. package/out/web/assets/fira-code-greek-ext-500-normal-BO3iq16n.woff2 +0 -0
  713. package/out/web/assets/fira-code-greek-ext-500-normal-CMiNLXER.woff +0 -0
  714. package/out/web/assets/fira-code-latin-ext-400-normal-DG73JjOf.woff +0 -0
  715. package/out/web/assets/fira-code-latin-ext-400-normal-KSMg0QLl.woff2 +0 -0
  716. package/out/web/assets/fira-code-latin-ext-500-normal-CaANqXjI.woff +0 -0
  717. package/out/web/assets/fira-code-latin-ext-500-normal-Crd9e_oI.woff2 +0 -0
  718. package/out/web/assets/flowDiagram-A5DVABFB-BpnHUSU7.js +0 -1
  719. package/out/web/assets/index-CVRg270z.css +0 -1
  720. package/out/web/assets/index-DxZQr9yD.js +0 -10
  721. package/out/web/assets/inter-cyrillic-400-normal-HOLc17fK.woff +0 -0
  722. package/out/web/assets/inter-cyrillic-400-normal-obahsSVq.woff2 +0 -0
  723. package/out/web/assets/inter-cyrillic-500-normal-BasfLYem.woff2 +0 -0
  724. package/out/web/assets/inter-cyrillic-500-normal-CxZf_p3X.woff +0 -0
  725. package/out/web/assets/inter-cyrillic-600-normal-4D_pXhcN.woff +0 -0
  726. package/out/web/assets/inter-cyrillic-600-normal-CWCymEST.woff2 +0 -0
  727. package/out/web/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2 +0 -0
  728. package/out/web/assets/inter-cyrillic-ext-400-normal-DQukG94-.woff +0 -0
  729. package/out/web/assets/inter-cyrillic-ext-500-normal-B0yAr1jD.woff2 +0 -0
  730. package/out/web/assets/inter-cyrillic-ext-500-normal-BmqWE9Dz.woff +0 -0
  731. package/out/web/assets/inter-cyrillic-ext-600-normal-Bcila6Z-.woff +0 -0
  732. package/out/web/assets/inter-cyrillic-ext-600-normal-Dfes3d0z.woff2 +0 -0
  733. package/out/web/assets/inter-greek-400-normal-B4URO6DV.woff2 +0 -0
  734. package/out/web/assets/inter-greek-400-normal-q2sYcFCs.woff +0 -0
  735. package/out/web/assets/inter-greek-500-normal-BIZE56-Y.woff2 +0 -0
  736. package/out/web/assets/inter-greek-500-normal-Xzm54t5V.woff +0 -0
  737. package/out/web/assets/inter-greek-600-normal-BZpKdvQh.woff +0 -0
  738. package/out/web/assets/inter-greek-600-normal-plRanbMR.woff2 +0 -0
  739. package/out/web/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2 +0 -0
  740. package/out/web/assets/inter-greek-ext-400-normal-KugGGMne.woff +0 -0
  741. package/out/web/assets/inter-greek-ext-500-normal-2j5mBUwD.woff +0 -0
  742. package/out/web/assets/inter-greek-ext-500-normal-C4iEst2y.woff2 +0 -0
  743. package/out/web/assets/inter-greek-ext-600-normal-B8X0CLgF.woff +0 -0
  744. package/out/web/assets/inter-greek-ext-600-normal-DRtmH8MT.woff2 +0 -0
  745. package/out/web/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
  746. package/out/web/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
  747. package/out/web/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
  748. package/out/web/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
  749. package/out/web/assets/inter-latin-600-normal-CiBQ2DWP.woff +0 -0
  750. package/out/web/assets/inter-latin-600-normal-LgqL8muc.woff2 +0 -0
  751. package/out/web/assets/inter-latin-ext-400-normal-77YHD8bZ.woff +0 -0
  752. package/out/web/assets/inter-latin-ext-400-normal-C1nco2VV.woff2 +0 -0
  753. package/out/web/assets/inter-latin-ext-500-normal-BxGbmqWO.woff +0 -0
  754. package/out/web/assets/inter-latin-ext-500-normal-CV4jyFjo.woff2 +0 -0
  755. package/out/web/assets/inter-latin-ext-600-normal-CIVaiw4L.woff +0 -0
  756. package/out/web/assets/inter-latin-ext-600-normal-D2bJ5OIk.woff2 +0 -0
  757. package/out/web/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff +0 -0
  758. package/out/web/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
  759. package/out/web/assets/inter-vietnamese-500-normal-DOriooB6.woff2 +0 -0
  760. package/out/web/assets/inter-vietnamese-500-normal-mJboJaSs.woff +0 -0
  761. package/out/web/assets/inter-vietnamese-600-normal-BuLX-rYi.woff +0 -0
  762. package/out/web/assets/inter-vietnamese-600-normal-Cc8MFFhd.woff2 +0 -0
  763. package/out/web/assets/kanit-latin-400-normal-BUlsQXH3.woff2 +0 -0
  764. package/out/web/assets/kanit-latin-400-normal-HVZWrfev.woff +0 -0
  765. package/out/web/assets/kanit-latin-500-normal-CX_4XcKi.woff2 +0 -0
  766. package/out/web/assets/kanit-latin-500-normal-qBha86O4.woff +0 -0
  767. package/out/web/assets/kanit-latin-600-normal-0lS78yAd.woff2 +0 -0
  768. package/out/web/assets/kanit-latin-600-normal-DlacpeTg.woff +0 -0
  769. package/out/web/assets/kanit-latin-ext-400-normal-B2xPf58u.woff2 +0 -0
  770. package/out/web/assets/kanit-latin-ext-400-normal-CHvNKHHD.woff +0 -0
  771. package/out/web/assets/kanit-latin-ext-500-normal-BFdWrG22.woff +0 -0
  772. package/out/web/assets/kanit-latin-ext-500-normal-EHs3suD6.woff2 +0 -0
  773. package/out/web/assets/kanit-latin-ext-600-normal-BBDzoLaj.woff +0 -0
  774. package/out/web/assets/kanit-latin-ext-600-normal-DAX3wtuq.woff2 +0 -0
  775. package/out/web/assets/kanit-thai-400-normal-D2nliXKa.woff +0 -0
  776. package/out/web/assets/kanit-thai-400-normal-D80Pglro.woff2 +0 -0
  777. package/out/web/assets/kanit-thai-500-normal-BB8gri04.woff2 +0 -0
  778. package/out/web/assets/kanit-thai-500-normal-Iy_w0a80.woff +0 -0
  779. package/out/web/assets/kanit-thai-600-normal-Bj6oiaDc.woff2 +0 -0
  780. package/out/web/assets/kanit-thai-600-normal-wbTlPO7I.woff +0 -0
  781. package/out/web/assets/kanit-vietnamese-400-normal-DRI8YWyb.woff2 +0 -0
  782. package/out/web/assets/kanit-vietnamese-400-normal-dow6Bnto.woff +0 -0
  783. package/out/web/assets/kanit-vietnamese-500-normal-BzTrpCM3.woff2 +0 -0
  784. package/out/web/assets/kanit-vietnamese-500-normal-T1ndT7MF.woff +0 -0
  785. package/out/web/assets/kanit-vietnamese-600-normal-Bi7fw3I4.woff2 +0 -0
  786. package/out/web/assets/kanit-vietnamese-600-normal-DXCRAa_8.woff +0 -0
  787. package/out/web/assets/mali-latin-400-normal-ByPcZ8Gx.woff +0 -0
  788. package/out/web/assets/mali-latin-400-normal-Cuc6Ykl8.woff2 +0 -0
  789. package/out/web/assets/mali-latin-500-normal-B01M-LP6.woff2 +0 -0
  790. package/out/web/assets/mali-latin-500-normal-Thgqw_9f.woff +0 -0
  791. package/out/web/assets/mali-latin-600-normal-B9TiUNpT.woff2 +0 -0
  792. package/out/web/assets/mali-latin-600-normal-CycpQCwU.woff +0 -0
  793. package/out/web/assets/mali-latin-ext-400-normal-DUVdJQO4.woff +0 -0
  794. package/out/web/assets/mali-latin-ext-400-normal-iCG1ALuJ.woff2 +0 -0
  795. package/out/web/assets/mali-latin-ext-500-normal-BfJE4UMZ.woff2 +0 -0
  796. package/out/web/assets/mali-latin-ext-500-normal-FoLEyOKS.woff +0 -0
  797. package/out/web/assets/mali-latin-ext-600-normal-BTvIfiCp.woff2 +0 -0
  798. package/out/web/assets/mali-latin-ext-600-normal-DAQcLVmD.woff +0 -0
  799. package/out/web/assets/mali-thai-400-normal-BO7A3bLZ.woff2 +0 -0
  800. package/out/web/assets/mali-thai-400-normal-CX9VrjTn.woff +0 -0
  801. package/out/web/assets/mali-thai-500-normal-Cph2qha9.woff +0 -0
  802. package/out/web/assets/mali-thai-500-normal-D89rMT77.woff2 +0 -0
  803. package/out/web/assets/mali-thai-600-normal-DPgXT6rZ.woff +0 -0
  804. package/out/web/assets/mali-thai-600-normal-DlTx3OsB.woff2 +0 -0
  805. package/out/web/assets/mali-vietnamese-400-normal-DUKxzXaz.woff2 +0 -0
  806. package/out/web/assets/mali-vietnamese-400-normal-gFDLvsOK.woff +0 -0
  807. package/out/web/assets/mali-vietnamese-500-normal--OY07q2c.woff +0 -0
  808. package/out/web/assets/mali-vietnamese-500-normal-KDrNRwfW.woff2 +0 -0
  809. package/out/web/assets/mali-vietnamese-600-normal-CtTMUU7T.woff +0 -0
  810. package/out/web/assets/mali-vietnamese-600-normal-DFlJr66u.woff2 +0 -0
  811. package/out/web/assets/mermaid.core-DYGGlqOf.js +0 -11
  812. package/out/web/assets/mitr-latin-400-normal-Cb18vPmZ.woff +0 -0
  813. package/out/web/assets/mitr-latin-400-normal-CwbkLQ4a.woff2 +0 -0
  814. package/out/web/assets/mitr-latin-500-normal-B4JOhzAi.woff +0 -0
  815. package/out/web/assets/mitr-latin-500-normal-BmClOow2.woff2 +0 -0
  816. package/out/web/assets/mitr-latin-ext-400-normal-B3CPG7Yo.woff2 +0 -0
  817. package/out/web/assets/mitr-latin-ext-400-normal-DTx65hiC.woff +0 -0
  818. package/out/web/assets/mitr-latin-ext-500-normal-B_Diajz1.woff2 +0 -0
  819. package/out/web/assets/mitr-latin-ext-500-normal-DYOsVaVT.woff +0 -0
  820. package/out/web/assets/mitr-thai-400-normal-CS4Do6aM.woff +0 -0
  821. package/out/web/assets/mitr-thai-400-normal-CXWaAdVj.woff2 +0 -0
  822. package/out/web/assets/mitr-thai-500-normal-CVdBrEVH.woff2 +0 -0
  823. package/out/web/assets/mitr-thai-500-normal-CW_B5D-i.woff +0 -0
  824. package/out/web/assets/mitr-vietnamese-400-normal-CPMGWyoC.woff2 +0 -0
  825. package/out/web/assets/mitr-vietnamese-400-normal-Z6XhIpdY.woff +0 -0
  826. package/out/web/assets/mitr-vietnamese-500-normal-CDrv0585.woff2 +0 -0
  827. package/out/web/assets/mitr-vietnamese-500-normal-CMQWyq-Z.woff +0 -0
  828. package/out/web/assets/noto-sans-thai-latin-400-normal-BaWBrqFP.woff2 +0 -0
  829. package/out/web/assets/noto-sans-thai-latin-400-normal-Dh_FJjOB.woff +0 -0
  830. package/out/web/assets/noto-sans-thai-latin-500-normal-BC04jsmm.woff +0 -0
  831. package/out/web/assets/noto-sans-thai-latin-500-normal-fyBKClF1.woff2 +0 -0
  832. package/out/web/assets/noto-sans-thai-latin-600-normal-CemcjnVR.woff2 +0 -0
  833. package/out/web/assets/noto-sans-thai-latin-600-normal-Dbc-dNO6.woff +0 -0
  834. package/out/web/assets/noto-sans-thai-latin-ext-400-normal-B-1H0YkH.woff +0 -0
  835. package/out/web/assets/noto-sans-thai-latin-ext-400-normal-nBP59pVw.woff2 +0 -0
  836. package/out/web/assets/noto-sans-thai-latin-ext-500-normal-B-ZWb8SZ.woff2 +0 -0
  837. package/out/web/assets/noto-sans-thai-latin-ext-500-normal-CrEHO7C8.woff +0 -0
  838. package/out/web/assets/noto-sans-thai-latin-ext-600-normal-PkMZo0xa.woff +0 -0
  839. package/out/web/assets/noto-sans-thai-latin-ext-600-normal-maHHBsez.woff2 +0 -0
  840. package/out/web/assets/noto-sans-thai-thai-400-normal-BEOmKAI1.woff2 +0 -0
  841. package/out/web/assets/noto-sans-thai-thai-400-normal-Dxb_unuU.woff +0 -0
  842. package/out/web/assets/noto-sans-thai-thai-500-normal-BOGXO2tw.woff +0 -0
  843. package/out/web/assets/noto-sans-thai-thai-500-normal-CU_X86GQ.woff2 +0 -0
  844. package/out/web/assets/noto-sans-thai-thai-600-normal-CmgB8_JK.woff +0 -0
  845. package/out/web/assets/noto-sans-thai-thai-600-normal-Cs73sVjl.woff2 +0 -0
  846. package/out/web/assets/oauthManager-DNiwM8Rn.js +0 -2
  847. package/out/web/assets/oauthManager-DuamS1Av.css +0 -1
  848. package/out/web/assets/outfit-latin-300-normal-AWLfuCom.woff +0 -0
  849. package/out/web/assets/outfit-latin-300-normal-CRYTwY6m.woff2 +0 -0
  850. package/out/web/assets/outfit-latin-400-normal-BGsTXAXT.woff2 +0 -0
  851. package/out/web/assets/outfit-latin-400-normal-DMwTpYkH.woff +0 -0
  852. package/out/web/assets/outfit-latin-500-normal-ClnHRwRh.woff +0 -0
  853. package/out/web/assets/outfit-latin-500-normal-DKnIMDSk.woff2 +0 -0
  854. package/out/web/assets/outfit-latin-600-normal-B7SfZ07L.woff2 +0 -0
  855. package/out/web/assets/outfit-latin-600-normal-BEfTtDA7.woff +0 -0
  856. package/out/web/assets/outfit-latin-ext-300-normal-BYS6Dpvq.woff2 +0 -0
  857. package/out/web/assets/outfit-latin-ext-300-normal-CMIMshEd.woff +0 -0
  858. package/out/web/assets/outfit-latin-ext-400-normal-5tcqmc2S.woff2 +0 -0
  859. package/out/web/assets/outfit-latin-ext-400-normal-DHm7mdGe.woff +0 -0
  860. package/out/web/assets/outfit-latin-ext-500-normal-DrCvqoFD.woff +0 -0
  861. package/out/web/assets/outfit-latin-ext-500-normal-zeox_O30.woff2 +0 -0
  862. package/out/web/assets/outfit-latin-ext-600-normal-B85nYjL1.woff2 +0 -0
  863. package/out/web/assets/outfit-latin-ext-600-normal-CWJcPgd7.woff +0 -0
  864. package/out/web/assets/preload-helper-D0uHx7FM.js +0 -1
  865. package/out/web/assets/prompt-latin-400-normal-BQ9zjSN8.woff2 +0 -0
  866. package/out/web/assets/prompt-latin-400-normal-CxU4ec_r.woff +0 -0
  867. package/out/web/assets/prompt-latin-500-normal-B1edBDQ9.woff +0 -0
  868. package/out/web/assets/prompt-latin-500-normal-CxzxEHZc.woff2 +0 -0
  869. package/out/web/assets/prompt-latin-600-normal-CSDDLorv.woff +0 -0
  870. package/out/web/assets/prompt-latin-600-normal-hKZWXsc1.woff2 +0 -0
  871. package/out/web/assets/prompt-latin-ext-400-normal-1pHbN9uy.woff +0 -0
  872. package/out/web/assets/prompt-latin-ext-400-normal-DdSafGZ9.woff2 +0 -0
  873. package/out/web/assets/prompt-latin-ext-500-normal--EZ1um7s.woff2 +0 -0
  874. package/out/web/assets/prompt-latin-ext-500-normal-D-lI1EVT.woff +0 -0
  875. package/out/web/assets/prompt-latin-ext-600-normal-C8b50x67.woff +0 -0
  876. package/out/web/assets/prompt-latin-ext-600-normal-Cg9L7iJU.woff2 +0 -0
  877. package/out/web/assets/prompt-thai-400-normal-BrkKv8cO.woff2 +0 -0
  878. package/out/web/assets/prompt-thai-400-normal-DJypnfr3.woff +0 -0
  879. package/out/web/assets/prompt-thai-500-normal-C18pDUoL.woff2 +0 -0
  880. package/out/web/assets/prompt-thai-500-normal-D7YNqUJD.woff +0 -0
  881. package/out/web/assets/prompt-thai-600-normal-CYPViXds.woff +0 -0
  882. package/out/web/assets/prompt-thai-600-normal-MrdfU7zR.woff2 +0 -0
  883. package/out/web/assets/prompt-vietnamese-400-normal-BCPzsgPT.woff2 +0 -0
  884. package/out/web/assets/prompt-vietnamese-400-normal-D4pLyeNK.woff +0 -0
  885. package/out/web/assets/prompt-vietnamese-500-normal-DmzxmPwa.woff2 +0 -0
  886. package/out/web/assets/prompt-vietnamese-500-normal-w_sS_j2F.woff +0 -0
  887. package/out/web/assets/prompt-vietnamese-600-normal-1dyohtNh.woff +0 -0
  888. package/out/web/assets/prompt-vietnamese-600-normal-7QWjJBsF.woff2 +0 -0
  889. package/out/web/assets/sarabun-latin-400-normal-DmguIS-7.woff +0 -0
  890. package/out/web/assets/sarabun-latin-400-normal-URPBxl-K.woff2 +0 -0
  891. package/out/web/assets/sarabun-latin-500-normal-BjUTcdxu.woff2 +0 -0
  892. package/out/web/assets/sarabun-latin-500-normal-CJexTAnl.woff +0 -0
  893. package/out/web/assets/sarabun-latin-600-normal-9FonlkKx.woff +0 -0
  894. package/out/web/assets/sarabun-latin-600-normal-DMD3TROr.woff2 +0 -0
  895. package/out/web/assets/sarabun-latin-ext-400-normal-BbP7GpLL.woff2 +0 -0
  896. package/out/web/assets/sarabun-latin-ext-400-normal-BsmTn0SS.woff +0 -0
  897. package/out/web/assets/sarabun-latin-ext-500-normal-Cot16Bd2.woff +0 -0
  898. package/out/web/assets/sarabun-latin-ext-500-normal-DE1LysqI.woff2 +0 -0
  899. package/out/web/assets/sarabun-latin-ext-600-normal-0tXu9x_i.woff +0 -0
  900. package/out/web/assets/sarabun-latin-ext-600-normal-BRxjKUQ6.woff2 +0 -0
  901. package/out/web/assets/sarabun-thai-400-normal-C2DaJlKK.woff2 +0 -0
  902. package/out/web/assets/sarabun-thai-400-normal-CH-UbWgg.woff +0 -0
  903. package/out/web/assets/sarabun-thai-500-normal-BVssjame.woff2 +0 -0
  904. package/out/web/assets/sarabun-thai-500-normal-C3iDLEzi.woff +0 -0
  905. package/out/web/assets/sarabun-thai-600-normal-3dIAQ-_s.woff2 +0 -0
  906. package/out/web/assets/sarabun-thai-600-normal-DWKeTe6a.woff +0 -0
  907. package/out/web/assets/sarabun-vietnamese-400-normal-DPfkSCMy.woff +0 -0
  908. package/out/web/assets/sarabun-vietnamese-400-normal-igdrzAGY.woff2 +0 -0
  909. package/out/web/assets/sarabun-vietnamese-500-normal-CpRVvGRU.woff +0 -0
  910. package/out/web/assets/sarabun-vietnamese-500-normal-Dpe7Br9m.woff2 +0 -0
  911. package/out/web/assets/sarabun-vietnamese-600-normal-BMbOgAW-.woff +0 -0
  912. package/out/web/assets/sarabun-vietnamese-600-normal-DkxrOlLB.woff2 +0 -0
  913. package/out/web/assets/stateDiagram-v2-4QOOHH4V-s6P9g2_b.js +0 -1
  914. package/out/web/assets/swimlanesDiagram-VK2B7HYN-CV9fOLrV.js +0 -8
  915. package/out/web/assets/tauri-CNrHQ2Gb.js +0 -3
  916. package/out/web/assets/window-DkIhgI7B.js +0 -1
  917. package/skills-lock.json +0 -41
  918. package/src/renderer/public/Live2DCubismCore.js +0 -9
  919. package/src/renderer/src/companionWidget.ts +0 -95
  920. package/src/renderer/src/components/Live2DStage.tsx +0 -389
  921. package/src/renderer/src/components/ModelPanel.tsx +0 -154
  922. package/src/renderer/src/css/model.css +0 -627
  923. package/src/renderer/src-web/companionWidget.ts +0 -37
  924. package/src/renderer/src-web/components/ModelPanel.tsx +0 -12
  925. package/src/renderer/src-web/css/model.css +0 -628
@@ -0,0 +1,71 @@
1
+ <!doctype html>
2
+ <html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Mint GlideSelect interaction checks</title></head>
3
+ <body style="margin:24px;background:#18181b;color:#f5f5f5;font-family:system-ui"><h1>Mint dropdowns</h1><div id="root"></div><pre id="result">RUNNING</pre>
4
+ <script type="module">
5
+ import React from 'react';
6
+ import { createRoot } from 'react-dom/client';
7
+ const results=[];
8
+ const wait=(ms=60)=>new Promise(resolve=>setTimeout(resolve,ms));
9
+ const assert=(ok,message)=>{if(!ok)throw new Error(message);results.push(message)};
10
+ try {
11
+ const {default:SelectField}=await import('../shared/components/SelectField');
12
+ const {default:GlideSelect}=await import('../shared/components/GlideSelect');
13
+ const picks=[];
14
+ function Fixture(){
15
+ const [value,setValue]=React.useState('png');
16
+ return React.createElement('div',{style:{display:'flex',gap:16,flexWrap:'wrap'}},
17
+ React.createElement('label',null,'Export format ',React.createElement(SelectField,{value,onValueChange:v=>{picks.push(v);setValue(v)},'aria-label':'Export format'},
18
+ React.createElement('option',{value:'png'},'PNG'),React.createElement('option',{value:'jpg'},'JPG'),React.createElement('option',{value:'webp'},'WebP'))),
19
+ React.createElement(GlideSelect,{options:[{value:'fast',label:'Fast',tag:'Low latency'},{value:'deep',label:'Deep',tag:'Reasoning'}],defaultValue:'deep',ariaLabel:'Reasoning effort'}),
20
+ React.createElement(SelectField,{value:'2',disabled:true,'aria-label':'Disabled checkpoint'},React.createElement('option',{value:2},'Step 2')),
21
+ React.createElement(GlideSelect,{options:[],ariaLabel:'Empty options'}),
22
+ React.createElement(GlideSelect,{options:Array.from({length:40},(_,i)=>({value:String(i),label:`Model ${i}`})),defaultValue:'0',ariaLabel:'Long list'}),
23
+ React.createElement('div',{style:{position:'fixed',right:8,bottom:8,width:100,overflow:'hidden'}},React.createElement(GlideSelect,{options:['One','Two','Three'],ariaLabel:'Edge menu'})));
24
+ }
25
+ createRoot(document.getElementById('root')).render(React.createElement(Fixture));
26
+ await wait(200);
27
+ const trigger=label=>document.querySelector(`[role="combobox"][aria-label="${label}"]`);
28
+ const key=(el,key)=>el.dispatchEvent(new KeyboardEvent('keydown',{key,bubbles:true}));
29
+ const open=async el=>{el.dispatchEvent(new PointerEvent('pointerdown',{button:0,pointerId:1,bubbles:true}));await wait()};
30
+ const t=trigger('Export format');
31
+ assert(t.textContent.includes('PNG'),'controlled initial value preserved');
32
+ await open(t);
33
+ assert(t.getAttribute('aria-expanded')==='true','pointer opens menu');
34
+ const listId=t.getAttribute('aria-controls');const list=document.getElementById(listId);
35
+ const box=list.getBoundingClientRect();
36
+ // The first pixels of the second row must select the second row, not the previous row.
37
+ list.dispatchEvent(new PointerEvent('pointerdown',{clientY:box.top+32,clientX:box.left+10,pointerId:7,bubbles:true}));
38
+ list.dispatchEvent(new PointerEvent('pointerup',{clientY:box.top+32,clientX:box.left+10,pointerId:7,bubbles:true}));
39
+ await wait();
40
+ assert(t.textContent.includes('JPG')&&picks.join(',')==='jpg','pointer selects correct row at its top edge');
41
+ assert(document.activeElement===t,'focus returns to trigger after selection');
42
+ await open(t);key(t,'Home');await wait();key(t,'Enter');await wait();
43
+ assert(t.textContent.includes('PNG'),'Home and Enter select first option');
44
+ await open(t);key(t,'w');await wait();key(t,'Enter');await wait();
45
+ assert(t.textContent.includes('WebP'),'typeahead selects matching option');
46
+ const count=picks.length;await open(t);key(t,'Enter');await wait();
47
+ assert(picks.length===count,'reselecting current value does not call onChange');
48
+ await open(t);key(t,'ArrowUp');await wait();key(t,'Escape');await wait();
49
+ assert(t.textContent.includes('WebP')&&t.getAttribute('aria-expanded')==='false','Escape cancels without changing value');
50
+ await open(t);key(t,'Tab');await wait();assert(t.getAttribute('aria-expanded')==='false','Tab dismisses list');
51
+ await open(t);document.body.dispatchEvent(new PointerEvent('pointerdown',{bubbles:true}));await wait(180);
52
+ assert(t.getAttribute('aria-expanded')==='false'&&!document.getElementById(listId),'outside pointer dismisses and removes closing menu');
53
+ assert(trigger('Disabled checkpoint').disabled&&trigger('Disabled checkpoint').textContent.includes('Step 2'),'disabled numeric checkpoint remains selected');
54
+ assert(trigger('Empty options').disabled,'empty list is safely disabled');
55
+ const long=trigger('Long list');await open(long);key(long,'End');await wait();
56
+ const longList=document.getElementById(long.getAttribute('aria-controls'));const last=longList.querySelector('[data-index="39"]');
57
+ const lr=longList.getBoundingClientRect(),rr=last.getBoundingClientRect();
58
+ assert(longList.scrollHeight>longList.clientHeight&&rr.top>=lr.top&&rr.bottom<=lr.bottom+1,'long list scrolls active keyboard option into view');
59
+ key(long,'Escape');await wait();
60
+ const effort=trigger('Reasoning effort');await open(effort);
61
+ assert(document.querySelector('.glide-select__tag')?.textContent==='Low latency','option tags render');
62
+ const rows=document.querySelectorAll('.glide-select__option');rows[0].dispatchEvent(new PointerEvent('pointerover',{bubbles:true,pointerType:'mouse'}));await wait();const pill=document.querySelector('.glide-select__pill');
63
+ assert(getComputedStyle(pill).transitionDuration.includes('0.22s'),'authored glide duration is 220ms');
64
+ key(effort,'Escape');await wait();
65
+ const edge=trigger('Edge menu');await open(edge);
66
+ const edgeMenu=document.querySelector('.glide-select__menu');const er=edgeMenu.getBoundingClientRect();
67
+ assert(edgeMenu.dataset.side==='top'&&er.left>=0&&er.right<=window.innerWidth&&er.bottom<=window.innerHeight,'edge menu flips, fits viewport, and escapes clipping parent');
68
+ key(edge,'Escape');await wait();
69
+ document.getElementById('result').textContent='PASS\n'+results.join('\n');
70
+ } catch(error){document.getElementById('result').textContent='FAIL: '+error.message+'\n'+results.join('\n');console.error(error)}
71
+ </script></body></html>
@@ -0,0 +1,27 @@
1
+ <!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Mint GlideSelect — Audio settings</title></head>
2
+ <body><div id="root"></div><script type="module">
3
+ import React from 'react';
4
+ import {createRoot} from 'react-dom/client';
5
+ import AudioTab from '../shared/components/Settings/AudioTab';
6
+ import {DEFAULT_CONFIG} from '../shared/constants/config';
7
+ import '../shared/theme/tokens.css';
8
+ import '../src-web/css/settings/base.css';
9
+ import '../shared/css/settings/general.css';
10
+ import '../src-web/css/settings/mobile.css';
11
+ function App(){
12
+ const [config,setConfig]=React.useState({...DEFAULT_CONFIG,voiceMode:'geminiLive'});
13
+ return React.createElement('main',{className:'settings-container',style:{overflow:'auto',height:'100vh',padding:'24px',background:'#18181b'}},
14
+ React.createElement('div',{className:'settings-content',style:{maxWidth:900,margin:'0 auto',height:'auto',overflow:'visible'}},React.createElement(AudioTab,{config,apiKey:'',updateField:(field,value)=>setConfig(c=>({...c,[field]:value}))})));
15
+ }
16
+ createRoot(document.getElementById('root')).render(React.createElement(App));
17
+ setTimeout(()=>{
18
+ const trigger=document.querySelector('[role="combobox"][aria-label="Live voice"]');
19
+ if(!trigger)return;
20
+ trigger.scrollIntoView({block:'center'});
21
+ trigger.dispatchEvent(new PointerEvent('pointerdown',{button:0,pointerId:1,bubbles:true}));
22
+ setTimeout(()=>{
23
+ const row=document.querySelector('.glide-select__option[data-index="2"]');
24
+ row?.dispatchEvent(new PointerEvent('pointerover',{bubbles:true,pointerType:'mouse'}));
25
+ },300);
26
+ },800);
27
+ </script></body></html>
@@ -0,0 +1 @@
1
+ <!doctype html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1"></head><body><div id="root"></div><script type="module" src="./library.browser.tsx"></script></body></html>
@@ -0,0 +1,78 @@
1
+ import React from 'react'
2
+ import {createRoot} from 'react-dom/client'
3
+ import LibraryPage from '../shared/components/LibraryPage'
4
+ import {installRendererPlatform,type RendererAdapter} from '../shared/platform'
5
+ import type {LibraryItem,LibraryQuery} from '../shared/types'
6
+ let failAction=false;let offline=false;let openChat='';let contentReads=0
7
+ const canvas=document.createElement('canvas');canvas.width=480;canvas.height=300;const ctx=canvas.getContext('2d')!;ctx.fillStyle='#286454';ctx.fillRect(0,0,480,300);ctx.fillStyle='#daeee6';ctx.font='26px sans-serif';ctx.fillText('Library reference',100,160)
8
+ const image=await new Promise<Blob>(resolve=>canvas.toBlob(blob=>resolve(blob!)))
9
+ const make=(id:string,name:string,kind:LibraryItem['kind']):LibraryItem=>({id,name,filename:`${id}.bin`,kind,mimeType:kind==='file'?'text/markdown':kind==='video'?'video/mp4':'image/png',size:1280,createdAt:'2026-10-15T08:00:00Z',origin:'uploaded',source:'chat',message:'',deletedAt:null,thumbnailStatus:kind==='file'?'unavailable':'ready',availability:'ready',references:[{chatId:'A',interactionId:12}]})
10
+ let items=[make('image','ภาพอ้างอิง.png','image'),make('video','Demo recording.mp4','video'),make('notes','01_slr_model_assumptions.md','file'),make('lost','Missing original.pdf','file'),make('old','Archived notes.md','file')];items[3].availability='missing';items[4].deletedAt='2026-10-15T08:00:00Z'
11
+ items[0].message='/chat ช่วยดูภาพอ้างอิงนี้แล้วอธิบายรายละเอียดให้หน่อย โดยเปรียบเทียบโครงสร้าง สี และองค์ประกอบต่าง ๆ ที่ปรากฏในรูปภาพเพื่อใช้ประกอบการออกแบบหน้าจอของเรา รวมถึงส่วนที่ควรปรับปรุงให้เหมาะกับการใช้งานบนมือถือ [Image #1]'
12
+
13
+ installRendererPlatform({
14
+ listLibrary:async(q:LibraryQuery)=>{if(offline)throw new Error('Offline');return {items:items.filter(i=>Boolean(i.deletedAt)===Boolean(q.trashed)&&(!q.kind||i.kind===q.kind)&&(!q.search||i.name.toLowerCase().includes(q.search.toLowerCase()))),nextCursor:null}},
15
+ getLibraryItem:async(id:string)=>{const i=items.find(i=>i.id===id);if(!i)throw new Error('Missing item');return i},
16
+ readLibraryFile:async(id:string,thumb:boolean)=>{if(!thumb)contentReads++;return id==='notes'||id==='old'?new Blob(['# Notes\nRegression reference'],{type:'text/markdown'}):image},
17
+ removeLibraryItem:async(id:string)=>{if(failAction)throw new Error('System Trash unavailable');items=items.filter(i=>i.id!==id)},
18
+ setLibraryTrashed:async(id:string,trashed:boolean)=>{if(failAction)throw new Error('Storage unavailable');items=items.map(i=>i.id===id?{...i,deletedAt:trashed?'2026-10-15':null}:i)},
19
+ } as unknown as RendererAdapter)
20
+ createRoot(document.getElementById('root')!).render(<><style>{`*{box-sizing:border-box}body{margin:0;font-family:Arial,sans-serif;--bg-gradient:#101112;--bg-overlay:#18191b;--bg-surface-soft:#1a1c1e;--bg-surface-hover:#242729;--border:#303438;--text-main:#edf0ee;--text-soft:#abb6b0;--text-muted:#89958e;--accent:#91d6b5;--radius-md:10px}#root{position:relative;height:100dvh}#qa-results{position:fixed;bottom:4px;left:8px;color:#a9e5c7;font-size:10px;pointer-events:none;white-space:pre-wrap;z-index:99999}`}</style><LibraryPage chatId="A" onClose={()=>{}} onOpenConversation={id=>{openChat=id}}/><pre id="qa-results">Running…</pre></>)
21
+ const delay=(ms=40)=>new Promise(r=>setTimeout(r,ms))
22
+ async function waitFor(check:()=>boolean,name:string){for(let i=0;i<100;i++){if(check())return;await delay()}throw new Error(name)}
23
+ const results:string[]=[];const check=(value:unknown,name:string)=>{if(!value)throw new Error(name);results.push(`PASS ${name}`)}
24
+ const click=(selector:string)=>{const el=document.querySelector<HTMLElement>(selector);if(!el)throw new Error(`Missing ${selector}`);el.focus();el.click()}
25
+ async function run(){
26
+ if(location.search.includes('item=old')){
27
+ await waitFor(()=>Boolean(document.querySelector('.library-item.is-linked')),'Source link highlights its Library entry in Trash')
28
+ check(document.querySelector('.library-item.is-linked')?.textContent?.includes('Archived notes.md'),'linked Trash entry is visible')
29
+ document.getElementById('qa-results')!.textContent=results.join('\n')+'\nALL PASSED';return
30
+ }
31
+ await waitFor(()=>document.querySelectorAll('.library-item').length===4,'Library lists active items')
32
+ check(contentReads===0,'listing never loads original media')
33
+ check(!document.querySelector('[data-remove]'),'remove action is available only in Library Trash')
34
+ check(document.documentElement.scrollWidth<=innerWidth,'Library fits viewport')
35
+ if(new URLSearchParams(location.search).has('preview')){document.getElementById('qa-results')!.textContent='';return}
36
+ click('[data-preview="image"]');await waitFor(()=>Boolean(document.querySelector('.library-preview img')),'Image preview')
37
+ const excerpt=document.querySelector<HTMLElement>('.library-preview-source p')
38
+ check(excerpt?.textContent?.startsWith('ช่วยดูภาพอ้างอิงนี้'),'image preview shows the source message without transport markers')
39
+ check(!excerpt?.textContent?.includes('[Image #1]'),'source excerpt omits attachment markers')
40
+ check(excerpt!.clientHeight<=parseFloat(getComputedStyle(excerpt!).lineHeight)*2+1,'source message fits within two lines')
41
+ if(innerWidth<600)check(excerpt!.scrollHeight>excerpt!.clientHeight,'long source message is visually truncated')
42
+ check(document.documentElement.scrollWidth<=innerWidth,'long source message fits viewport')
43
+ if(location.search.includes('source-preview')){document.getElementById('qa-results')!.textContent='';return}
44
+ document.dispatchEvent(new KeyboardEvent('keydown',{key:'Escape',bubbles:true}));await waitFor(()=>!document.querySelector('.library-preview'),'Close image preview')
45
+ click('[data-filter="file"]');await waitFor(()=>document.querySelectorAll('.library-item').length===2,'Files filter')
46
+ click('[data-preview="notes"]');await waitFor(()=>Boolean(document.querySelector('.library-preview pre')?.textContent?.includes('Regression reference')),'Document preview')
47
+ check(document.querySelector('.library-preview pre')?.textContent?.includes('Regression reference'),'text preview reads original file')
48
+ check(!document.querySelector('.library-preview-source'),'preview without a source message omits the excerpt')
49
+ click('.library-preview [data-open-chat]');check(openChat==='A','source conversation opens')
50
+ document.dispatchEvent(new KeyboardEvent('keydown',{key:'Escape',bubbles:true}));await waitFor(()=>!document.querySelector('.library-preview'),'Escape closes preview')
51
+ check(document.activeElement===document.querySelector('[data-preview="notes"]'),'preview restores keyboard focus')
52
+ failAction=true;click('[data-trash="notes"]');await waitFor(()=>Boolean(document.querySelector('.library-action-error')),'Trash error')
53
+ check(Boolean(document.querySelector('[data-preview="notes"]')),'failed Trash keeps file visible')
54
+ failAction=false;click('[data-trash="notes"]');await waitFor(()=>!document.querySelector('[data-preview="notes"]'),'Successful Trash')
55
+ click('[data-view="trash"]');await waitFor(()=>document.querySelectorAll('.library-item').length===2,'Trash view')
56
+ check(Boolean(document.querySelector('[data-remove="old"]')),'Library Trash offers remove from Mint')
57
+ failAction=true;click('[data-remove="old"]');await waitFor(()=>Boolean(document.querySelector('.library-action-error')),'System Trash error')
58
+ check(Boolean(document.querySelector('[data-remove="old"]')),'failed system Trash keeps entry visible')
59
+ failAction=false;click('[data-remove="old"]');await waitFor(()=>!document.querySelector('[data-remove="old"]'),'Removed from Mint')
60
+ click('[data-restore="notes"]');await waitFor(()=>!document.querySelector('[data-restore="notes"]'),'Restore')
61
+ click('[data-view="active"]');await waitFor(()=>Boolean(document.querySelector('[data-preview="notes"]')),'Restored file')
62
+ check(Boolean(document.querySelector('[data-preview="lost"][disabled]')),'missing original remains visible with disabled preview')
63
+ offline=true;click('[aria-label="Refresh library"]');await waitFor(()=>Boolean(document.querySelector('.library-error')),'Refresh error')
64
+ check(document.querySelectorAll('.library-item').length===2,'failed refresh preserves known files')
65
+ offline=false;click('.library-error button');await waitFor(()=>!document.querySelector('.library-error'),'Retry')
66
+ const search=document.querySelector<HTMLInputElement>('input[type="search"]')!;Object.getOwnPropertyDescriptor(HTMLInputElement.prototype,'value')!.set!.call(search,'absent');search.dispatchEvent(new Event('input',{bubbles:true}));await waitFor(()=>Boolean(document.querySelector('.library-empty')),'Empty search')
67
+ check(document.querySelector('.library-empty')?.textContent?.includes('No files match'),'empty search explains filters')
68
+ const navigate=(query:string)=>{history.pushState({},'',`?${query}`);window.dispatchEvent(new PopStateEvent('popstate'))}
69
+ navigate('item=image');await waitFor(()=>Boolean(document.querySelector('.library-preview img')),'Source navigation opens while Library remains mounted')
70
+ check(document.querySelector<HTMLInputElement>('input[type="search"]')?.value==='','source navigation clears filters hiding the target')
71
+ items.push({...make('source-trash','Another archived file.md','file'),deletedAt:'2026-10-15'})
72
+ navigate('item=source-trash&trash=1');await waitFor(()=>Boolean(document.querySelector('[data-remove="source-trash"]')),'Second source navigation switches to Trash')
73
+ check(!document.querySelector('.library-preview'),'second source navigation closes the previous preview')
74
+ check(document.querySelector('.library-item.is-linked')?.textContent?.includes('Another archived file.md'),'second source navigation highlights its own entry')
75
+ navigate('item=notes');await waitFor(()=>Boolean(document.querySelector('.library-preview pre')),'Source navigation returns from Trash to an active original')
76
+ document.getElementById('qa-results')!.textContent=results.join('\n')+'\nALL PASSED'
77
+ }
78
+ run().catch(error=>{document.getElementById('qa-results')!.textContent=results.join('\n')+`\nFAIL ${error.message}`})
@@ -0,0 +1,49 @@
1
+ <!doctype html><html><head><meta name="viewport" content="width=device-width, initial-scale=1"><title>Live orb regression</title></head>
2
+ <body><button id="launcher">Live</button><div id="chat-host" style="position:absolute;left:80px;top:140px;width:260px;height:160px;transform:translateZ(0);overflow:hidden"><div id="root"></div></div><pre id="result">RUNNING</pre><script type="module">
3
+ import React from 'react';import {createRoot} from 'react-dom/client';
4
+ import GeminiLiveOverlay from '../shared/components/GeminiLiveOverlay';
5
+ import {VoicePoweredOrb} from '../shared/components/ui/voice-powered-orb';
6
+ import '@fontsource/prompt/400.css';import '@fontsource/prompt/500.css';
7
+ import '../shared/theme/tokens.css';import '../src-web/css/app-shell.css';
8
+ const results=[];const assert=(ok,msg)=>{if(!ok)throw Error(msg);results.push(msg)};
9
+ const wait=ms=>new Promise(r=>setTimeout(r,ms));
10
+ let paused=false,ended=false,voice='Puck';const analyserRef={current:{frequencyBinCount:256,getByteFrequencyData(buf){buf.fill(100)}}};
11
+ let micRequests=0;Object.defineProperty(navigator,'mediaDevices',{configurable:true,value:{getUserMedia:async()=>{micRequests++;throw Error('Unexpected second microphone')}}});
12
+ const previousOverflow=document.body.style.overflow;
13
+ const root=createRoot(document.getElementById('root'));
14
+ const frames=new Map();let frameId=0;window.requestAnimationFrame=cb=>{frames.set(++frameId,cb);return frameId};window.cancelAnimationFrame=id=>frames.delete(id);
15
+ const advance=()=>{for(let i=0;i<30;i++){const batch=[...frames.values()];frames.clear();batch.forEach(cb=>cb(performance.now()+i*16));}};
16
+ const render=(status='listening')=>root.render(React.createElement(GeminiLiveOverlay,{status,isPaused:paused,userTranscript:'สวัสดี Mint',assistantTranscript:'Hello, how can I help?',voice,voices:['Puck','Kore'],analyserRef,onTogglePause:()=>{paused=!paused;render(paused?'paused':'listening')},onEndCall:()=>{ended=true;root.unmount()},onChangeVoice:v=>{voice=v;render()}}));
17
+ try{
18
+ if(location.search.includes('preview')){document.getElementById('result').style.display='none';document.getElementById('launcher').style.visibility='hidden'}
19
+ document.getElementById('launcher').focus();render();await wait(400);advance();
20
+ const overlay=document.querySelector('.gemini-live-overlay');const bounds=overlay.getBoundingClientRect();
21
+ assert(bounds.left===0&&bounds.top===0&&bounds.width===innerWidth&&bounds.height===innerHeight,'popup covers viewport outside clipped chat');
22
+ assert(document.body.style.overflow==='hidden','popup locks background scrolling');
23
+ assert(overlay.contains(document.elementFromPoint(10,10)),'backdrop intercepts clicks outside card');
24
+ const panel=document.querySelector('.gemini-live-card').getBoundingClientRect();assert(Math.abs((panel.left+panel.right)/2-innerWidth/2)<2&&Math.abs((panel.top+panel.bottom)/2-innerHeight/2)<2,'popup is centered in viewport');
25
+ const canvas=document.querySelector('.voice-powered-orb canvas');assert(canvas,'supplied orb renders a WebGL canvas');
26
+ assert(micRequests===0,'existing session analyser does not open another microphone');
27
+ const gl=canvas.getContext('webgl2')||canvas.getContext('webgl');const px=new Uint8Array(canvas.width*canvas.height*4);gl.readPixels(0,0,canvas.width,canvas.height,gl.RGBA,gl.UNSIGNED_BYTE,px);
28
+ assert(px.some((v,i)=>i%4!==3&&v>40),'shader produces visible colored pixels');
29
+ if(location.search.includes('reduced')){
30
+ assert(matchMedia('(prefers-reduced-motion: reduce)').matches,'browser reports reduced-motion preference');
31
+ advance();const still=new Uint8Array(px.length);gl.readPixels(0,0,canvas.width,canvas.height,gl.RGBA,gl.UNSIGNED_BYTE,still);assert(px.every((v,i)=>v===still[i]),'reduced motion freezes shader rotation and distortion');
32
+ }
33
+ assert(canvas.width<=canvas.clientWidth*2+1,'device pixel ratio is applied once and capped');
34
+ const card=document.querySelector('.gemini-live-card').getBoundingClientRect();assert(card.left>=0&&card.right<=innerWidth&&card.top>=0&&card.bottom<=innerHeight,'call fits viewport');
35
+ const endButton=document.querySelector('[aria-label="End Live conversation"]').getBoundingClientRect();assert(endButton.left>=panel.left&&endButton.right<=panel.right&&endButton.bottom<=panel.bottom,'end control stays inside popup');
36
+ if(!location.search.includes('preview')){
37
+ const transcript=document.querySelector('[aria-label="Conversation transcript"]');transcript.focus();document.dispatchEvent(new KeyboardEvent('keydown',{key:'Tab',shiftKey:true,bubbles:true,cancelable:true}));assert(document.activeElement.getAttribute('aria-label')==='End Live conversation','keyboard focus stays inside call');
38
+ document.querySelector('[aria-label="Pause microphone"]').click();await wait(100);advance();assert(document.querySelector('[aria-label="Resume microphone"]'),'pause remains usable with orb');
39
+ document.querySelector('[aria-label="Resume microphone"]').click();await wait(100);
40
+ document.querySelector('[aria-label="Change voice"]').click();await wait(100);document.querySelector('[role="option"][data-voice="Kore"]').click();await wait(100);assert(voice==='Kore','voice selection retains callback');
41
+ document.dispatchEvent(new KeyboardEvent('keydown',{key:'Escape',bubbles:true}));await wait(100);assert(ended,'Escape ends call');assert(document.body.style.overflow===previousOverflow,'ending call restores background scrolling');assert(document.activeElement.id==='launcher','call returns focus');assert(frames.size===0,'orb releases animation frame on end');
42
+ let resolveMic;const stream={getTracks:()=>[{stop(){stream.stopped=true}}],stopped:false};navigator.mediaDevices.getUserMedia=()=>{micRequests++;return new Promise(r=>resolveMic=r)};
43
+ const standalone=createRoot(document.getElementById('root'));standalone.render(React.createElement('div',{style:{width:200,height:200}},React.createElement(VoicePoweredOrb)));await wait(100);assert(micRequests===1,'standalone orb opens microphone once');standalone.unmount();resolveMic(stream);await wait(100);assert(stream.stopped,'late standalone permission releases microphone on unmount');assert(frames.size===0,'standalone orb releases RAF');
44
+ const original=HTMLCanvasElement.prototype.getContext;HTMLCanvasElement.prototype.getContext=function(type,...args){return type.startsWith('webgl')?null:original.call(this,type,...args)};
45
+ const fallback=createRoot(document.getElementById('root'));fallback.render(React.createElement(GeminiLiveOverlay,{status:'error',isPaused:false,userTranscript:'',assistantTranscript:'Permission denied',voice:'Puck',voices:['Puck'],onTogglePause(){},onEndCall(){},onChangeVoice(){}}));await wait(100);assert(document.querySelector('.voice-powered-orb__fallback')&&document.querySelector('[aria-label="End Live conversation"]'),'graphics failure retains call status and end control');fallback.unmount();HTMLCanvasElement.prototype.getContext=original;
46
+ }
47
+ document.getElementById('result').textContent='PASS\n'+results.join('\n');
48
+ }catch(e){document.getElementById('result').textContent='FAIL: '+e.message+'\n'+results.join('\n');}
49
+ </script></body></html>
@@ -0,0 +1,29 @@
1
+ <!doctype html><html><body><div id="root"></div><pre id="result">RUNNING</pre><script type="module">
2
+ import React from 'react';import {createRoot} from 'react-dom/client';import {useGeminiLiveVoice} from '../shared/utils/useGeminiLiveVoice';
3
+ const wait=ms=>new Promise(r=>setTimeout(r,ms)),defer=()=>{let resolve;return {promise:new Promise(r=>resolve=r),resolve:v=>resolve(v)}};
4
+ const results=[];const assert=(ok,msg)=>{if(!ok)throw Error(msg);results.push(msg)};
5
+ let permission,session,voice,eventHandler;const calls=[],contexts=[];
6
+ Object.defineProperty(navigator,'mediaDevices',{configurable:true,value:{getUserMedia:()=>permission.promise}});
7
+ class Node{connections=[];connect(n){this.connections.push(n)}disconnect(){this.connections=[]}}
8
+ class Context{state='running';currentTime=0;sampleRate=48000;destination=new Node();sources=[];constructor(){contexts.push(this)}createAnalyser(){return Object.assign(new Node(),{frequencyBinCount:256,getByteFrequencyData:b=>b.fill(80)})}createMediaStreamSource(){return new Node()}createScriptProcessor(){return new Node()}createBuffer(n,length,rate){return{duration:length/rate,getChannelData:()=>new Float32Array(length)}}createBufferSource(){const n=Object.assign(new Node(),{start(){},stop(){this.stopped=true},stopped:false});this.sources.push(n);return n}close(){this.state='closed';return Promise.resolve()}resume(){return Promise.resolve()}}
9
+ window.AudioContext=Context;
10
+ const backend={startSession:cb=>{eventHandler=cb;calls.push('start');return session.promise},sendAudioChunk:async()=>{},stopSession:async id=>calls.push('stop:'+id)};
11
+ function Harness(){voice=useGeminiLiveVoice(backend);return React.createElement('div',null,voice.isRecording?'recording':'idle')}
12
+ let root=createRoot(document.getElementById('root'));root.render(React.createElement(Harness));await wait(100);
13
+ const stream=()=>{const track={stopped:false,stop(){this.stopped=true}};return{track,getTracks:()=>[track]}};
14
+ try{
15
+ permission=defer();session=defer();voice.setVoiceMode(true);await wait(50);voice.setVoiceMode(false);await wait(50);const late=stream();permission.resolve(late);await wait(100);
16
+ assert(late.track.stopped&&calls.length===0,'ending during microphone permission stops late tracks and never opens session');
17
+ permission=defer();session=defer();voice.setVoiceMode(true);await wait(50);const pending=stream();permission.resolve(pending);await wait(50);voice.setVoiceMode(false);await wait(50);session.resolve('late-session');await wait(100);
18
+ assert(pending.track.stopped&&calls.includes('stop:late-session')&&!voice.isRecording,'ending during connection closes the late backend session');
19
+ permission=defer();session=defer();voice.setVoiceMode(true);await wait(50);const live=stream();permission.resolve(live);await wait(50);session.resolve('live');await wait(100);
20
+ assert(voice.isRecording&&voice.analyserRef.current,'active call exposes its existing audio analyser');
21
+ eventHandler({type:'audioChunk',data:btoa('\0\0\0\0')});await wait(50);const ctx=contexts.at(-1);assert(ctx.sources.length===1,'normal streamed playback still works');
22
+ voice.setVoiceMode(false);await wait(100);
23
+ assert(live.track.stopped&&ctx.state==='closed'&&ctx.sources[0].stopped&&!voice.analyserRef.current,'ending releases microphone, output audio, analyser and audio context');
24
+ const count=ctx.sources.length;eventHandler({type:'audioChunk',data:btoa('\0\0')});await wait(50);assert(ctx.sources.length===count&&contexts.length===1,'late events cannot restart audio after call ends');
25
+ permission=defer();session=defer();voice.setVoiceMode(true);await wait(50);const closing=stream();permission.resolve(closing);await wait(50);session.resolve('closing');await wait(100);eventHandler({type:'closed'});await wait(100);
26
+ assert(closing.track.stopped&&contexts.at(-1).state==='closed'&&!voice.analyserRef.current&&voice.errorMessage,'server closure releases audio and exposes connection status');
27
+ root.unmount();document.getElementById('result').textContent='PASS\n'+results.join('\n');
28
+ }catch(e){root.unmount();document.getElementById('result').textContent='FAIL: '+e.message+'\n'+results.join('\n');}
29
+ </script></body></html>
@@ -0,0 +1,22 @@
1
+ <!doctype html><html><head><meta charset="utf-8"><title>Mod input synchronization</title></head><body><div id="root"></div><pre id="result">RUNNING</pre><script type="module">
2
+ import React from 'react';
3
+ import { createRoot } from 'react-dom/client';
4
+ import { ModUi } from '../shared/components/ModUi';
5
+ const root = createRoot(document.getElementById('root'));
6
+ const submitted = [];
7
+ const render = value => root.render(React.createElement(ModUi, { node: { type: 'input', label: 'Draft', action: 'save', value }, onAction: (action, value) => submitted.push([action, value]) }));
8
+ const pause = () => new Promise(resolve => setTimeout(resolve, 70));
9
+ const check = (ok, message) => { if (!ok) throw Error(message); };
10
+ const input = () => document.querySelector('input');
11
+ const submit = () => input().dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, cancelable: true }));
12
+ const edit = value => { Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set.call(input(), value); input().dispatchEvent(new Event('input', { bubbles: true })); };
13
+ try {
14
+ render('existing'); await pause(); submit();
15
+ check(submitted[0]?.[1] === 'existing', 'Initial value was not submitted');
16
+ edit('editing'); await pause(); render('existing'); await pause();
17
+ check(input().value === 'editing', 'Polling discarded unsent edits');
18
+ render('UPDATED'); await pause(); submit();
19
+ check(input().value === 'UPDATED' && submitted[1]?.[1] === 'UPDATED', 'Authoritative value did not replace the edited draft');
20
+ document.getElementById('result').textContent = 'PASS: initial value, stable polling edits and updated mod value submission';
21
+ } catch (error) { document.getElementById('result').textContent = 'FAIL: ' + error.message; }
22
+ </script></body></html>
@@ -0,0 +1 @@
1
+ <!doctype html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1"></head><body><div id="root"></div><script type="module" src="./sessionSources.browser.tsx"></script></body></html>
@@ -0,0 +1,107 @@
1
+ import React, { useState } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import WorkspaceContextPopover from '../shared/components/WorkspaceContextPopover'
4
+ import SessionSources from '../shared/components/SessionSources'
5
+ import { installRendererPlatform, installWorkspacePlatform, type RendererAdapter, type WorkspacePlatform } from '../shared/platform'
6
+ import type { ConversationSources } from '../shared/types'
7
+ import { sourceAttachments } from '../shared/utils/sourceAttachments'
8
+ import '../src/css/desktop-tools.css'
9
+
10
+ const canvas = document.createElement('canvas'); canvas.width = 640; canvas.height = 400
11
+ const context = canvas.getContext('2d')!; context.fillStyle = '#256853'; context.fillRect(0, 0, 640, 400); context.fillStyle = '#dcfce7'; context.font = '36px sans-serif'; context.fillText('Test image', 200, 210)
12
+ const originalImage = canvas.toDataURL('image/png')
13
+ const preview = await sourceAttachments({ imageAttachments: [{ name: 'reference.png', dataUri: originalImage }] })
14
+ const data: ConversationSources = {
15
+ attachments: [
16
+ { ...preview[0], id: 1, interactionId: 2, libraryItemId: 'reference-item' },
17
+ ...['Math-Data-Science-Exam.pdf', '01_slr_model_assumptions.md', '02_least_squares_estimation.md', '03_coefficient_accuracy.md', '04_r_squared_rse.md', '05_statistic.md'].map((name, index) => ({ id: index + 2, interactionId: 4 + index, name, kind: 'file' as const, mimeType: name.endsWith('.pdf') ? 'application/pdf' : 'text/markdown', thumbnailDataUri: null })),
18
+ ],
19
+ webSearchProgress: [{ type: 'ToolEnd', data: { action: 'web_search', input: { query: 'linear regression' }, result: '1. Linear regression reference\nURL: https://example.com/regression\nReference material\n\n2. Least squares guide\nURL: https://docs.example.com/least-squares\nA guide' } }],
20
+ }
21
+ let fail = false
22
+ let deferA = false
23
+ let resolveA: ((value: ConversationSources) => void) | null = null
24
+ installRendererPlatform({ getConversationSources: async (chatId: string) => {
25
+ if (fail) throw new Error('Offline')
26
+ if (chatId === 'A' && deferA) return new Promise<ConversationSources>(resolve => { resolveA = resolve })
27
+ return chatId === 'A' ? data : { attachments: [], webSearchProgress: [] }
28
+ } } as unknown as RendererAdapter)
29
+ installWorkspacePlatform({ getGitBranchInfo: async () => ({ isRepository: true, currentBranch: 'Rust', isDirty: true, branches: [], remoteBranches: [], detachedHead: null }) } as unknown as WorkspacePlatform)
30
+
31
+ function Fixture() {
32
+ const [chatId, setChatId] = useState('A')
33
+ return <>
34
+ <style>{`*{box-sizing:border-box}body{margin:0;background:#111113;color:#e8eaed;font-family:Arial,sans-serif;--text-main:#e8eaed;--text-secondary:#c5cad1;--text-muted:#8b939f;--bg-overlay:#111113;--surface-strong:#25262b;--border:#33353b;--accent:#7edbb5;--border-subtle:#27292d;--bg-surface-soft:#1a1b20;--bg-surface-hover:#22242a}.fixture-bar{display:flex;align-items:center;justify-content:flex-end;gap:12px;height:50px;padding:8px 16px;border-bottom:1px solid #33353b}#qa-results{position:fixed;bottom:6px;left:8px;max-width:calc(100vw - 16px);font-size:10px;white-space:pre-wrap;pointer-events:none}`}</style>
35
+ <header className="fixture-bar"><span>Session sources fixture</span><button id="switch-chat" onClick={() => setChatId(id => id === 'A' ? 'B' : 'A')}>Switch session</button><WorkspaceContextPopover workspacePath="/workspace/Mint-CLI" terminalCount={0} chatId={chatId} liveProgress={[]} recentChanges={[]} onOpenWorkspace={() => {}} onOpenReview={() => {}} onRefreshWorkspace={() => {}} /></header>
36
+ <pre id="qa-results">Running…</pre>
37
+ </>
38
+ }
39
+ createRoot(document.getElementById('root')!).render(<Fixture />)
40
+ const delay = (ms = 50) => new Promise(resolve => setTimeout(resolve, ms))
41
+ async function waitFor(check: () => boolean, name: string) { for (let i = 0; i < 100; i++) { if (check()) return; await delay() } throw new Error(name) }
42
+ const results: string[] = []
43
+ const check = (condition: unknown, name: string) => { if (!condition) throw new Error(name); results.push(`PASS ${name}`) }
44
+ function click(selector: string) { const target = document.querySelector<HTMLElement>(selector); if (!target) throw new Error(`Missing ${selector}`); target.click() }
45
+ async function run() {
46
+ await waitFor(() => Boolean(document.querySelector('.workspace-context-trigger')), 'Trigger')
47
+ click('.workspace-context-trigger')
48
+ await waitFor(() => Boolean(document.querySelector('.session-source-row')), 'Saved sources')
49
+ check(document.querySelectorAll('.session-source-row').length === 5, 'initial list shows every source category without flooding the popover')
50
+ check(document.querySelector<HTMLAnchorElement>('.session-source-row[href^="/library"]')?.getAttribute('href') === '/library?item=reference-item', 'source image links to its Library original')
51
+ check(document.querySelector('.session-source-icon img'), 'sent image has a thumbnail')
52
+ check(preview[0].name === 'reference.png' && (preview[0].thumbnailDataUri?.length || 0) < 262144, 'thumbnail generation preserves name and bounds payload size')
53
+ check(document.querySelector('.session-sources')?.textContent?.includes('Math-Data-Science-Exam.pdf'), 'sent document appears with filename')
54
+ if (location.search.includes('preview')) { document.getElementById('qa-results')!.textContent = ''; return }
55
+ click('.session-sources-more')
56
+ await waitFor(() => document.querySelectorAll('.session-source-row').length === 9, 'Expanded list')
57
+ check(document.querySelectorAll('.session-source-row').length === 9, 'show more reveals all session sources')
58
+ check(document.querySelector<HTMLAnchorElement>('.session-source-row[href^="https:"]')?.href === 'https://example.com/regression', 'historical web searches link to source pages')
59
+ const popover = document.querySelector<HTMLElement>('.workspace-context-popover')!
60
+ check(popover.getBoundingClientRect().right <= innerWidth && popover.getBoundingClientRect().left >= 0, 'popover fits viewport')
61
+ check(getComputedStyle(popover).overflowY === 'auto', 'expanded sources can scroll')
62
+ fail = true; await waitFor(() => Boolean(document.querySelector('.session-sources-error')), 'Error state')
63
+ check(document.querySelectorAll('.session-source-row').length === 9, 'refresh error preserves known sources')
64
+ fail = false; click('.session-sources-error button'); await waitFor(() => !document.querySelector('.session-sources-error'), 'Retry')
65
+ check(true, 'retry recovers')
66
+ deferA = true; click('.workspace-context-trigger'); await delay(); click('.workspace-context-trigger'); await waitFor(() => Boolean(resolveA), 'Pending A request')
67
+ click('#switch-chat'); await waitFor(() => Boolean(document.querySelector('.session-sources-empty')), 'Empty B')
68
+ resolveA!(data); await delay()
69
+ check(document.querySelectorAll('.session-source-row').length === 0, 'late response cannot leak another session sources')
70
+ check(document.querySelector('.session-sources-empty')?.textContent?.includes('Images and files you send'), 'empty session explains what appears here')
71
+ deferA=false;click('#switch-chat')
72
+ await waitFor(()=>Boolean(document.querySelector('.session-source-row[href^="/library"]')),'Sources for internal navigation')
73
+ let navigated=false
74
+ const navigation=()=>{navigated=true}
75
+ window.addEventListener('popstate',navigation)
76
+ const libraryLink=document.querySelector<HTMLAnchorElement>('.session-source-row[href^="/library"]')!
77
+ const clickEvent=new MouseEvent('click',{bubbles:true,cancelable:true,button:0})
78
+ let preventedByComponent=false
79
+ const suppressReload=(event:MouseEvent)=>{preventedByComponent=event.defaultPrevented;event.preventDefault()}
80
+ document.addEventListener('click',suppressReload)
81
+ libraryLink.dispatchEvent(clickEvent)
82
+ document.removeEventListener('click',suppressReload)
83
+ check(preventedByComponent && navigated, 'Library source navigation preserves the live application and composer')
84
+ window.removeEventListener('popstate',navigation)
85
+ await waitFor(()=>!document.querySelector('.workspace-context-popover'),'Source navigation closes its popover')
86
+ const iconFixture = document.createElement('div')
87
+ document.body.append(iconFixture)
88
+ const iconRoot = createRoot(iconFixture)
89
+ iconRoot.render(<SessionSources sources={[
90
+ { id: 'web-good', kind: 'web', name: 'Website with icon', detail: 'example.com', url: 'https://example.com/with-icon', faviconUrl: originalImage },
91
+ { id: 'web-broken', kind: 'web', name: 'Website without icon', detail: 'other.example', url: 'https://other.example/no-icon', faviconUrl: 'data:image/png;base64,AA==' },
92
+ { id: 'image-thumbnail', kind: 'image', name: 'reference.png', detail: 'Image', thumbnailDataUri: originalImage },
93
+ ]} loading={false} error="" onRetry={() => {}} onOpenLibrary={() => {}} />)
94
+ await waitFor(() => Boolean(iconFixture.querySelector<HTMLImageElement>('.is-web img')?.naturalWidth), 'Website favicon loads')
95
+ const favicon = iconFixture.querySelector<HTMLImageElement>('.is-web img')!
96
+ check(favicon.width === 20 && favicon.height === 20, 'website favicon fits its existing icon slot')
97
+ check(favicon.referrerPolicy === 'no-referrer', 'favicon request omits the chat page referrer')
98
+ await waitFor(() => Boolean(iconFixture.querySelector('[href="https://other.example/no-icon"] .is-web svg')), 'Unavailable favicon falls back')
99
+ check(!iconFixture.querySelector('[href="https://other.example/no-icon"] img'), 'failed favicon uses the globe instead of a broken image')
100
+ check(iconFixture.querySelector<HTMLImageElement>('.is-image img')?.width === 30, 'attachment thumbnails retain their existing size')
101
+ favicon.dispatchEvent(new Event('error'))
102
+ await waitFor(() => Boolean(iconFixture.querySelector('[href="https://example.com/with-icon"] .is-web svg')), 'Late favicon failure falls back')
103
+ check(Boolean(iconFixture.querySelector('[href="https://example.com/with-icon"]')), 'favicon failure preserves the source link')
104
+ iconRoot.unmount(); iconFixture.remove()
105
+ document.getElementById('qa-results')!.textContent = results.join('\n') + '\nALL PASSED'
106
+ }
107
+ run().catch(error => { document.getElementById('qa-results')!.textContent = results.join('\n') + `\nFAIL ${error.message}` })
@@ -0,0 +1,24 @@
1
+ <!doctype html>
2
+ <html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
3
+ <style>*{box-sizing:border-box}body{margin:24px;background:#121212;color:#eee;font-family:Arial,sans-serif}pre{white-space:pre-wrap}</style></head>
4
+ <body><div id="root"></div><pre id="result">RUNNING</pre>
5
+ <script type="module">
6
+ import React from 'react';
7
+ import {createRoot} from 'react-dom/client';
8
+ import {AgentActivityTable} from '/shared/components/AgentActivityTable.tsx';
9
+ import {activitiesFrom} from '/shared/utils/agentActivity.ts';
10
+ const root=createRoot(document.getElementById('root'));
11
+ const input={path:'/repo/.agents/skills/review/SKILL.md',skill_name:'review'};
12
+ const start={type:'ToolStart',data:{action:'read_file',input}};
13
+ const end=result=>({type:'ToolEnd',data:{action:'read_file',input,result}});
14
+ async function render(events){root.render(React.createElement(AgentActivityTable,{activityView:activitiesFrom(events)}));await new Promise(resolve=>setTimeout(resolve,50));}
15
+ function check(text){if(!document.getElementById('root').textContent.includes(text))throw Error(`Missing ${text}`)}
16
+ try {
17
+ await render([start]);check('Reading skill: review');
18
+ await render([start,end('[Loaded skill: review]\nReview the changed files.')]);check('Loaded skill: review');
19
+ await render([start,end('Error: denied')]);check('Failed to read skill: review');
20
+ await render([start,end('1 | header only')]);check('Read skill preview: review');
21
+ await render([start,end('[Loaded skill: review]\nReview the changed files.')]);
22
+ document.getElementById('result').textContent='PASS: rendered reading, loaded, failed, and preview states';
23
+ } catch(error){document.getElementById('result').textContent='FAIL: '+error.stack;}
24
+ </script></body></html>
@@ -0,0 +1 @@
1
+ <!doctype html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1"></head><body><div id="root"></div><script type="module" src="./toolsPanel.browser.tsx"></script></body></html>
@@ -0,0 +1,113 @@
1
+ import React, { useState } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import ToolSurfacePage, { type ToolSurface } from '../shared/components/ToolSurfacePage'
4
+ import ToolsPanelToggle from '../shared/components/ToolsPanelToggle'
5
+ import { ModsPanel } from '../shared/components/ModsPanel'
6
+ import { BackgroundTerminals } from '../shared/components/BackgroundTerminals'
7
+ import { installRendererPlatform, type RendererAdapter } from '../shared/platform'
8
+ import type { BackgroundJob } from '../shared/types'
9
+
10
+ // Isolated browser fixture: only the external runtime boundary is replaced.
11
+ const job: BackgroundJob = { id: 'job-1', command: 'npm run dev', cwd: '/workspace/alpha', workspacePath: '/workspace/alpha', chatId: 'chat-a', pid: 10, status: 'running', exitCode: null, error: null, startedAt: 0, endedAt: null, elapsedSeconds: 12, serverUrl: null }
12
+ const other = { ...job, id: 'job-2', workspacePath: '/workspace/beta', cwd: '/workspace/beta' }
13
+ let jobs = [job, other]
14
+ let failJobs = false
15
+ let modCloses = 0
16
+ let listCalls = 0
17
+ let outputCalls = 0
18
+ let stopCalls = 0
19
+ const enabledMod = { id: 'weather', name: 'Weather', enabled: true, hash: 'rev-1', activeHash: 'rev-1', revisions: ['rev-1'], manifest: { version: '1.0.0', permissions: [] }, snapshot: { ui: { above_composer: { type: 'text', text: 'Weather band' } } } }
20
+ let mods = [enabledMod]
21
+ installRendererPlatform({
22
+ isTauriRuntime: () => false,
23
+ listBackgroundJobs: async (workspace?: string) => { listCalls++; if (failJobs) throw new Error('offline'); return workspace ? jobs.filter(j => j.workspacePath === workspace) : [...jobs] },
24
+ getBackgroundJob: async (id: string) => { outputCalls++; return { ...jobs.find(j => j.id === id), stdout: 'Server ready', stderr: '', truncated: false } },
25
+ stopBackgroundJob: async (id: string) => { stopCalls++; jobs = jobs.map(j => j.id === id ? { ...j, status: 'stopped', exitCode: 0 } : j); return jobs.find(j => j.id === id) },
26
+ deleteBackgroundJob: async (id: string) => { jobs = jobs.filter(j => j.id !== id) },
27
+ modsOperation: async (op: { action: string; workspacePath: string }) => {
28
+ if (op.action === 'close') modCloses++
29
+ return { mods: op.workspacePath.endsWith('alpha') ? mods : [], session: { hotReload: false } }
30
+ },
31
+ } as unknown as RendererAdapter)
32
+
33
+ function Fixture() {
34
+ const [open, setOpen] = useState(false)
35
+ const [surfaces, setSurfaces] = useState<ToolSurface[]>([])
36
+ const [active, setActive] = useState<string | null>(null)
37
+ const [workspace, setWorkspace] = useState('/workspace/alpha')
38
+ const [count, setCount] = useState(0)
39
+ const [modsTarget, setModsTarget] = useState<HTMLDivElement | null>(null)
40
+ const [tasksTarget, setTasksTarget] = useState<HTMLDivElement | null>(null)
41
+ const desktop = new URLSearchParams(location.search).has('desktop')
42
+ const utility = (kind: 'mods' | 'background') => {
43
+ setOpen(true); setActive(kind)
44
+ setSurfaces(previous => previous.some(s => s.id === kind) ? previous : [...previous, { id: kind, kind, title: kind === 'mods' ? 'Mods' : 'Background tasks' }])
45
+ }
46
+ const noop = () => {}
47
+ return <>
48
+ <style>{`*{box-sizing:border-box}body{margin:0;font-family:Arial,sans-serif;--text-main:#e7ece9;--text-muted:#9aa5a0;--bg-surface:#181c1a;--panel-bg:#181c1a;--surface-bg:#222824;--surface-strong:#2c342e;--border:#38413b;--accent:#7edbb5;--accent-subtle:#253e32;background:#111613;color:var(--text-main)}.app-body{position:relative;height:calc(100dvh - 50px);display:flex}.assistant-workspace{flex:1;padding:24px;min-width:0}.fixture-header{height:50px;display:flex;align-items:center;gap:12px;padding:8px 16px}.fixture-composer{margin-top:60px}#qa-results{position:fixed;bottom:0;left:0;z-index:1000;max-width:45vw;font-size:10px;white-space:pre-wrap;pointer-events:none}`}</style>
49
+ <header className="fixture-header"><span>Mint Tools fixture</span><ToolsPanelToggle open={open} count={count} onToggle={() => setOpen(v => !v)} className={desktop ? 'mint-titlebar-icon-button' : ''} /><button id="switch-workspace" onClick={() => setWorkspace(w => w.endsWith('alpha') ? '/workspace/beta' : '/workspace/alpha')}>Switch workspace</button></header>
50
+ <div className={`app-body ${open ? 'tool-surface-active' : ''}`} style={{ '--tool-surface-width': '440px' } as React.CSSProperties}>
51
+ <main className="assistant-workspace"><h1>Conversation</h1><p>{workspace}</p><div className="fixture-composer"><ModsPanel workspacePath={workspace} chatId="chat-a" panelTarget={modsTarget} onOpen={() => utility('mods')} /><textarea aria-label="Message" placeholder="Ask Mint…" /></div></main>
52
+ {open && <ToolSurfacePage surfaces={surfaces} activeSurfaceId={active} workspacePath={workspace} terminalSize={440} desktopTools={desktop} backgroundTaskCount={count}
53
+ onSelect={setActive} onClose={id => { setSurfaces(s => s.filter(v => v.id !== id)); setActive(null) }} onCloseAll={noop} onDuplicate={noop} onRename={noop} onCloseOthers={noop} onResizeTerminal={noop} onResizePanel={noop}
54
+ onOpenTerminal={noop} onOpenBrowser={noop} onOpenReview={noop} onOpenFiles={noop} onOpenMods={() => utility('mods')} onOpenBackgroundTasks={() => utility('background')} onModsPanelTarget={setModsTarget} onBackgroundPanelTarget={setTasksTarget} onClosePanel={() => setOpen(false)} />}
55
+ <BackgroundTerminals workspacePath={workspace} panelTarget={tasksTarget} onCountChange={setCount} />
56
+ </div>
57
+ <pre id="qa-results">Running…</pre>
58
+ </>
59
+ }
60
+ createRoot(document.getElementById('root')!).render(<Fixture />)
61
+
62
+ const delay = (ms = 50) => new Promise(resolve => setTimeout(resolve, ms))
63
+ async function waitFor(check: () => boolean, label: string) {
64
+ for (let n = 0; n < 100; n++) { if (check()) return; await delay() }
65
+ throw new Error(label)
66
+ }
67
+ function click(selector: string) { const target = document.querySelector<HTMLElement>(selector); if (!target) throw new Error(`Missing ${selector}`); target.click() }
68
+ const results: string[] = []
69
+ const check = (condition: unknown, name: string) => { if (!condition) throw new Error(name); results.push(`PASS ${name}`) }
70
+ async function run() {
71
+ await waitFor(() => Boolean(document.querySelector('.tools-task-count')), 'Initial task count')
72
+ check(document.querySelector('.tools-task-count')?.textContent === '1', 'badge counts current workspace while Tools is closed')
73
+ check(document.body.textContent?.includes('Weather band'), 'mod band renders with Tools closed')
74
+ click('.tools-panel-toggle'); await delay()
75
+ click('[title="Background tasks"]'); await waitFor(() => Boolean(document.querySelector('.background-terminal-job')), 'Tasks panel')
76
+ check(document.querySelector('.tool-surface-page .background-terminal-panel'), 'tasks render inside Tools')
77
+ check(document.querySelectorAll('.background-terminal-job').length === 1, 'workspace filter excludes other jobs')
78
+ click('.background-terminal-actions button'); await waitFor(() => Boolean(document.querySelector('.background-terminal-log')?.textContent?.includes('Server ready')), 'Output')
79
+ check(outputCalls > 0, 'output loads on demand')
80
+ click('.background-terminal-stop'); await waitFor(() => stopCalls === 1 && !document.querySelector('.tools-panel-toggle .tools-task-count'), 'Stop and badge')
81
+ check(document.querySelector('.background-terminal-state')?.textContent === 'stopped', 'Stop updates job status and badge')
82
+ click('[aria-label="Close tools panel"]'); await delay()
83
+ const callsBefore = listCalls; await delay(1100)
84
+ check(listCalls > callsBefore, 'monitor keeps polling while Tools is closed')
85
+ check(modCloses === 0, 'closing Tools keeps mod session alive')
86
+ click('.tools-panel-toggle'); await delay()
87
+ click('[aria-label="Switch tool"]'); await delay(); click('[title="Workspace mods"]')
88
+ await waitFor(() => Boolean(document.querySelector('.mods-panel')), 'Mods panel')
89
+ check(document.querySelector('.tool-surface-page .mods-panel'), 'mods render inside Tools')
90
+ check(document.querySelector('.mods-panel')?.textContent?.includes('Weather'), 'installed mod appears in Tools')
91
+ check(document.body.textContent?.includes('Weather band'), 'mod band survives tab switching')
92
+ click('#switch-workspace'); await waitFor(() => Boolean(document.querySelector('.mods-empty')), 'New workspace mods')
93
+ check(!document.querySelector('.mods-panel')?.textContent?.includes('Weather'), 'workspace switch clears previous mods')
94
+ await waitFor(() => document.querySelector('.tools-panel-toggle .tools-task-count')?.textContent === '1', 'New workspace count')
95
+ check(true, 'workspace switch refreshes badge')
96
+ click('[role="tab"]'); await waitFor(() => Boolean(document.querySelector('.background-terminal-job')), 'Other workspace tasks')
97
+ check(document.querySelector('.background-terminal-job')?.textContent?.includes('job-2'), 'tasks follow workspace switch')
98
+ failJobs = true; await waitFor(() => Boolean(document.querySelector('.background-terminal-error')), 'Error state')
99
+ check(document.querySelector('.background-terminal-stop')?.hasAttribute('disabled'), 'connection failure disables Stop')
100
+ failJobs = false; await delay(1100)
101
+ check(!document.querySelector('.background-terminal-error'), 'polling recovers after connection failure')
102
+ // Measure the resting layout rather than an in-flight entrance transform.
103
+ document.getAnimations().forEach(animation => animation.finish())
104
+ await delay()
105
+ check(document.documentElement.scrollWidth <= innerWidth, 'no page horizontal overflow')
106
+ const filter = document.querySelector<HTMLInputElement>('.background-terminal-filter input')!
107
+ filter.focus()
108
+ filter.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }))
109
+ await delay()
110
+ check(!document.querySelector('.tool-surface-page'), 'Escape closes Tools from portalled task content')
111
+ document.getElementById('qa-results')!.textContent = results.join('\n') + '\nALL PASSED'
112
+ }
113
+ if (!location.search.includes('preview')) run().catch(error => { document.getElementById('qa-results')!.textContent = results.join('\n') + `\nFAIL ${error.message}` })
@@ -0,0 +1 @@
1
+ <!doctype html><html data-theme="dark"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1"></head><body><div id="root"></div><script type="module" src="./viewedImages.browser.tsx"></script></body></html>