@openspecui/web 3.10.0 → 3.11.1

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 (619) hide show
  1. package/dist/assets/{BufferResource-D3AKV5w_.js → BufferResource-C08dlE1_.js} +1 -1
  2. package/dist/assets/CanvasRenderer-Bs7UxSWT.js +1 -0
  3. package/dist/assets/{Geometry-C-MCm9EO.js → Geometry-Dr8DqqDe.js} +1 -1
  4. package/dist/assets/{ImageSource-B22J1qWQ.js → ImageSource-CGpyv_SH.js} +1 -1
  5. package/dist/assets/{RenderTargetSystem-a2OW-r9i.js → RenderTargetSystem-COjjAuAB.js} +1 -1
  6. package/dist/assets/WebGLRenderer-l71uR9MI.js +1 -0
  7. package/dist/assets/WebGPURenderer-tjCbVxRm.js +1 -0
  8. package/dist/assets/add-DoVE8GY7.js +1 -0
  9. package/dist/assets/add-note-CWFgco4Z.js +1 -0
  10. package/dist/assets/add-playlist-CcOrN2f2.js +1 -0
  11. package/dist/assets/add-user-DX0Eywi4.js +1 -0
  12. package/dist/assets/airplay-Cn8zJk1w.js +1 -0
  13. package/dist/assets/{angular-html-JCbR6NhA.js → angular-html-DRwRMfwy.js} +1 -1
  14. package/dist/assets/{angular-ts-CNWwWDzo.js → angular-ts-eNLzy5MM.js} +1 -1
  15. package/dist/assets/{apl--EneV-pF.js → apl-DCKZGJwU.js} +1 -1
  16. package/dist/assets/arrow-collapse-C7ZIzYk9.js +1 -0
  17. package/dist/assets/arrow-collapse-in-Ccsen9kh.js +1 -0
  18. package/dist/assets/arrow-down-C9z5oBQ2.js +1 -0
  19. package/dist/assets/arrow-expand-BeEEym4e.js +1 -0
  20. package/dist/assets/arrow-expand-out-DjS8Havw.js +1 -0
  21. package/dist/assets/arrow-left-FPT5WhLa.js +1 -0
  22. package/dist/assets/arrow-right-c774CXK7.js +1 -0
  23. package/dist/assets/arrow-up-BVPQ_jz2.js +1 -0
  24. package/dist/assets/{astro-BbXT629y.js → astro-EVzibiTP.js} +1 -1
  25. package/dist/assets/audio-preview-DF-g2nKV.js +1 -0
  26. package/dist/assets/{blade-DCeMo3Gz.js → blade-BlgBU4xi.js} +1 -1
  27. package/dist/assets/bookmark-xq6HKihJ.js +1 -0
  28. package/dist/assets/browserAll-BDY91DxA.js +1 -0
  29. package/dist/assets/{bsl-baasCE8P.js → bsl-ROP5CocM.js} +1 -1
  30. package/dist/assets/{c-B5E81XOM.js → c-CYXkGxNJ.js} +1 -1
  31. package/dist/assets/{cairo-BkvliMUx.js → cairo-Y91V9cKj.js} +1 -1
  32. package/dist/assets/camera-DcgmsZFY.js +1 -0
  33. package/dist/assets/chapters-CWCRU4NE.js +1 -0
  34. package/dist/assets/chat-CjBvkjJQ.js +1 -0
  35. package/dist/assets/chat-collapse-D7uSBds2.js +1 -0
  36. package/dist/assets/chevron-down-DnbqQaM_.js +1 -0
  37. package/dist/assets/chevron-left-BLH8sfz-.js +1 -0
  38. package/dist/assets/chevron-right-Cx9jMJWP.js +1 -0
  39. package/dist/assets/chevron-up-ZO9wrLsS.js +1 -0
  40. package/dist/assets/chromecast-BINNmv53.js +1 -0
  41. package/dist/assets/chunk-XC5AOFRA-DNdxRVGN.js +1 -0
  42. package/dist/assets/chunk-XPDWGPRV-G9jotk_X.js +1 -0
  43. package/dist/assets/client-CNtwgWOm.js +9 -0
  44. package/dist/assets/clip-C8Wd7-v1.js +1 -0
  45. package/dist/assets/closed-captions-Cz7lecqe.js +1 -0
  46. package/dist/assets/closed-captions-on-BTsU9xHi.js +1 -0
  47. package/dist/assets/{cobol-DFA-05z0.js → cobol-DwyfNZUw.js} +1 -1
  48. package/dist/assets/{coffee-BIEZ2_PA.js → coffee-B8v2Wa7-.js} +1 -1
  49. package/dist/assets/comment-B3rCor45.js +1 -0
  50. package/dist/assets/common-DiWYGJu_.js +22 -0
  51. package/dist/assets/computer-BGdi_vvC.js +1 -0
  52. package/dist/assets/{cpp-DYT7t0SZ.js → cpp-ljtJvfZQ.js} +1 -1
  53. package/dist/assets/{crystal-OPLKg2mT.js → crystal-D8eXAHcv.js} +1 -1
  54. package/dist/assets/{css-B1O5LeXo.js → css-xQqtr90G.js} +1 -1
  55. package/dist/assets/cursor-editorTextHighlight-kG3uUOwL.svg +8 -0
  56. package/dist/assets/device-CxeIuxPi.js +1 -0
  57. package/dist/assets/dist--JzlUmDP.js +1 -0
  58. package/dist/assets/dist-B09y0Ph7.js +1 -0
  59. package/dist/assets/dist-BttXL4wz.js +1 -0
  60. package/dist/assets/dist-C9BN4134.js +1 -0
  61. package/dist/assets/dist-CCD9CqTu.js +1 -0
  62. package/dist/assets/{dist-B3TCWeQI.js → dist-CaORa3GR.js} +1 -1
  63. package/dist/assets/{dist-DB2qgDuh.js → dist-CaejG1dm.js} +1 -1
  64. package/dist/assets/{dist-0COy00zm.js → dist-Ct1D1r3D.js} +1 -1
  65. package/dist/assets/{dist-CCRZBEfv.js → dist-D65w4-0d.js} +1 -1
  66. package/dist/assets/{dist-BlZibS7L.js → dist-DBzjiykV.js} +1 -1
  67. package/dist/assets/dist-DdsOxRxJ.js +1 -0
  68. package/dist/assets/{dist-DK_X22KS.js → dist-DhToCcpI.js} +1 -1
  69. package/dist/assets/dist-DjM_Envn.js +1 -0
  70. package/dist/assets/{dist-Dwec7KIH.js → dist-DtDYJdOe.js} +1 -1
  71. package/dist/assets/dist-Dx00xLFT.js +1 -0
  72. package/dist/assets/dist-DxmYOUGn.js +1 -0
  73. package/dist/assets/dist-F0lgtwe2.js +1 -0
  74. package/dist/assets/dist-UpX5-9sH.js +1 -0
  75. package/dist/assets/{dist-DygtUgm8.js → dist-YdUjCFVN.js} +1 -1
  76. package/dist/assets/{dist-yu78ax1a.js → dist-jDblB_T7.js} +1 -1
  77. package/dist/assets/{dist-C4ldnarW.js → dist-lNuHRy_r.js} +1 -1
  78. package/dist/assets/dist-rGlPGEMw.js +1 -0
  79. package/dist/assets/{dockerfile-Ci0-ApQC.js → dockerfile-B9WyxmEu.js} +1 -1
  80. package/dist/assets/download-Cce-H-ZM.js +1 -0
  81. package/dist/assets/{edge-B_Hxxh_T.js → edge-BF9yTvjv.js} +1 -1
  82. package/dist/assets/{elixir-CexTPAef.js → elixir-B_B5En4k.js} +1 -1
  83. package/dist/assets/{elm-DVPcuGsD.js → elm-gyEPvRKn.js} +1 -1
  84. package/dist/assets/episodes-BvkaMZ8-.js +1 -0
  85. package/dist/assets/{erb-DK41lvap.js → erb-CrCiRjX6.js} +1 -1
  86. package/dist/assets/{erlang-vfCdWglx.js → erlang-Bt6NlFdF.js} +1 -1
  87. package/dist/assets/errors-DVESjK3y.js +1 -0
  88. package/dist/assets/eye-D5-_oy4W.js +1 -0
  89. package/dist/assets/{factor-DMvifS-k.js → factor-DRSLM7tp.js} +1 -1
  90. package/dist/assets/fast-backward-D9dXd1Qy.js +1 -0
  91. package/dist/assets/fast-forward-CYUMds_X.js +1 -0
  92. package/dist/assets/flag-Dtmr-9b8.js +1 -0
  93. package/dist/assets/{fortran-fixed-form-eRZkDVxE.js → fortran-fixed-form-BlyL6vAi.js} +1 -1
  94. package/dist/assets/{fsharp-lKBUVRnt.js → fsharp-CPUyN5V2.js} +1 -1
  95. package/dist/assets/fullscreen-CmB1c4--.js +1 -0
  96. package/dist/assets/fullscreen-arrow-C3VfgtaN.js +1 -0
  97. package/dist/assets/fullscreen-arrow-exit-DqOXxDMG.js +1 -0
  98. package/dist/assets/fullscreen-exit-DU7tI9hu.js +1 -0
  99. package/dist/assets/{gdresource-C_R0x-CQ.js → gdresource-3p4mNHpb.js} +1 -1
  100. package/dist/assets/{getTextureBatchBindGroup-MoChLDk_.js → getTextureBatchBindGroup-BfHjyiAV.js} +1 -1
  101. package/dist/assets/ghostty-web-CxzCiCWn.js +13 -0
  102. package/dist/assets/{git-commit-SMAxcXsl.js → git-commit-BUEnSUuI.js} +1 -1
  103. package/dist/assets/{git-rebase-QkxbQN1W.js → git-rebase-C31Q9wLE.js} +1 -1
  104. package/dist/assets/{glimmer-js-Ci9Jniu_.js → glimmer-js-C52Y4fUH.js} +1 -1
  105. package/dist/assets/{glimmer-ts-f6mheIFE.js → glimmer-ts-BWcx8nGq.js} +1 -1
  106. package/dist/assets/{glsl-CE_tGyBF.js → glsl-B14Nf0bw.js} +1 -1
  107. package/dist/assets/{graphql-DMHKd7V7.js → graphql-sQJ6gIy3.js} +1 -1
  108. package/dist/assets/{hack-Bd7yRRDg.js → hack-B3o_6UdT.js} +1 -1
  109. package/dist/assets/{haml-B-zh4HcV.js → haml-b85W5NJa.js} +1 -1
  110. package/dist/assets/{handlebars-73p99hU2.js → handlebars-D0WfzX4P.js} +1 -1
  111. package/dist/assets/heart-C5fn_wNi.js +1 -0
  112. package/dist/assets/{html-dLhzswBO.js → html-BUh_K1Ws.js} +1 -1
  113. package/dist/assets/{html-derivative-CRPsQPjv.js → html-derivative-CI0a_UC2.js} +1 -1
  114. package/dist/assets/{http-BmUbDDZ3.js → http-D2LmS59K.js} +1 -1
  115. package/dist/assets/{hurl-D8J5iekO.js → hurl-COx-msQh.js} +1 -1
  116. package/dist/assets/{hxml-BNnDhNNK.js → hxml-PXekqTur.js} +1 -1
  117. package/dist/assets/image-preview-BvROjYK5.js +1 -0
  118. package/dist/assets/image-preview-DbXbUOzB.css +1 -0
  119. package/dist/assets/info-BSFfpD3X.js +1 -0
  120. package/dist/assets/init-C46YDZ2H.js +1 -0
  121. package/dist/assets/{java-BMDGffNu.js → java-CY_ZDz_b.js} +1 -1
  122. package/dist/assets/{javascript-Dbc2F9Uj.js → javascript-CVtEj2Ax.js} +1 -1
  123. package/dist/assets/{jinja-ByHiV4iy.js → jinja-DqDhfavg.js} +1 -1
  124. package/dist/assets/{jison-BTOyGOJM.js → jison-AZhthQMg.js} +1 -1
  125. package/dist/assets/{json-BhpxJ_uj.js → json-C5SgWOeO.js} +1 -1
  126. package/dist/assets/{jsx-CPDjNUh8.js → jsx-lP4LEWkV.js} +1 -1
  127. package/dist/assets/jsx-runtime-1jQlXmIx.js +1 -0
  128. package/dist/assets/{julia-Cl6n8WOO.js → julia-Cj513uz1.js} +1 -1
  129. package/dist/assets/language-C_l1DBQe.js +1 -0
  130. package/dist/assets/{latex-C0_SOykc.js → latex-DwZK1V4M.js} +1 -1
  131. package/dist/assets/link-DH5zaMZ1.js +1 -0
  132. package/dist/assets/{liquid-Cr1xVqMM.js → liquid-Bq0P5vJ7.js} +1 -1
  133. package/dist/assets/lock-closed-BUf3MBxW.js +1 -0
  134. package/dist/assets/lock-open-BQ4FTuPQ.js +1 -0
  135. package/dist/assets/{lua-BWPGgBUj.js → lua-C-xH-Hms.js} +1 -1
  136. package/dist/assets/main-B2c4pZCT.css +1 -0
  137. package/dist/assets/main-Wj4p5q80.js +1654 -0
  138. package/dist/assets/{marko-BPXt0CD8.js → marko-B0ZA9L6u.js} +1 -1
  139. package/dist/assets/{mdc-CIsV3UeT.js → mdc-BjV-9MeS.js} +1 -1
  140. package/dist/assets/media-preview-D7f05nnk.css +1 -0
  141. package/dist/assets/media-preview-DWkSTGaX.js +2 -0
  142. package/dist/assets/media-ui-VgHJ-PHx.js +2 -0
  143. package/dist/assets/menu-horizontal-B6s-1vTa.js +1 -0
  144. package/dist/assets/menu-vertical-CWyBtj8F.js +1 -0
  145. package/dist/assets/microphone-BY0rFANt.js +1 -0
  146. package/dist/assets/mobile-BrxUhnS0.js +1 -0
  147. package/dist/assets/modulepreload-polyfill-CXK8biUa.js +1 -0
  148. package/dist/assets/moon-DnE1rK16.js +1 -0
  149. package/dist/assets/music-DgWl84sr.js +1 -0
  150. package/dist/assets/music-off-BIZK0PLj.js +1 -0
  151. package/dist/assets/mute-Wv31sLaT.js +1 -0
  152. package/dist/assets/next-Cl9F67W2.js +1 -0
  153. package/dist/assets/{nginx-CxaJu6Pj.js → nginx-BlGA_Yc6.js} +1 -1
  154. package/dist/assets/{nim-DEeX4yt_.js → nim-BRY7cBHe.js} +1 -1
  155. package/dist/assets/notification-DO_HNWPB.js +1 -0
  156. package/dist/assets/{nsis-BbRIeGvl.js → nsis-BOISW3t0.js} +1 -1
  157. package/dist/assets/odometer-ByhVM-4K.js +1 -0
  158. package/dist/assets/pause-D49Xseka.js +1 -0
  159. package/dist/assets/pdf-preview-C7gTFuZg.js +55 -0
  160. package/dist/assets/pdf-preview-DatbxdFW.css +1 -0
  161. package/dist/assets/pdf.worker.min-iDqQPrd3.mjs +31 -0
  162. package/dist/assets/pdf_viewer-C0F_ZnIy.js +501 -0
  163. package/dist/assets/{perl-nNEiznlj.js → perl-ZYxvPTl8.js} +1 -1
  164. package/dist/assets/{php-CFhEnfPT.js → php-BkicJQpQ.js} +1 -1
  165. package/dist/assets/picture-in-picture-DN7RmJ3z.js +1 -0
  166. package/dist/assets/picture-in-picture-exit-BwgCZZdp.js +1 -0
  167. package/dist/assets/play-CVvMlNWu.js +1 -0
  168. package/dist/assets/playback-speed-circle-CWnhxJ8o.js +1 -0
  169. package/dist/assets/playlist-CNLCJZTu.js +1 -0
  170. package/dist/assets/preload-helper-DgFuoWHe.js +1 -0
  171. package/dist/assets/previous-GulzH3pC.js +1 -0
  172. package/dist/assets/prod-B_gvu_Yr.js +5 -0
  173. package/dist/assets/prod-H1gIJ3Nt.js +1 -0
  174. package/dist/assets/provider-BoUAVVe0.js +1 -0
  175. package/dist/assets/provider-CfNWDDig.js +1 -0
  176. package/dist/assets/provider-Cj58hbuJ.js +1 -0
  177. package/dist/assets/provider-gmPj3q5A.js +1 -0
  178. package/dist/assets/{pug-B1jWkhMW.js → pug-CtobE3oR.js} +1 -1
  179. package/dist/assets/{pug-D1ZtszdL.js → pug-RUWq2f7J.js} +1 -1
  180. package/dist/assets/{qml-B3LbNeX2.js → qml-bFAbyxEk.js} +1 -1
  181. package/dist/assets/question-mark-Yk1OEoxM.js +1 -0
  182. package/dist/assets/queue-list-CDf4dIe8.js +1 -0
  183. package/dist/assets/{r-Ck8dtqom.js → r-BuzK-O4X.js} +1 -1
  184. package/dist/assets/radio-button-BHXtnVsK.js +1 -0
  185. package/dist/assets/radio-button-selected-Cbcd4nNT.js +1 -0
  186. package/dist/assets/{razor-w-TbBbA8.js → razor-BdPQn0FN.js} +1 -1
  187. package/dist/assets/{regexp-CEXR86Sj.js → regexp-zEw_f83a.js} +1 -1
  188. package/dist/assets/register-BoElj7Sn.js +1 -0
  189. package/dist/assets/repeat-D7Y2Sa5U.js +1 -0
  190. package/dist/assets/repeat-on-BN1EX623.js +1 -0
  191. package/dist/assets/repeat-square-CIKm5EZg.js +1 -0
  192. package/dist/assets/repeat-square-on-Bm9kAL2k.js +1 -0
  193. package/dist/assets/replay-CvqkHACU.js +1 -0
  194. package/dist/assets/rotate-DQS0vFC1.js +1 -0
  195. package/dist/assets/{rst-Car5kf30.js → rst-DKhAJU51.js} +1 -1
  196. package/dist/assets/{ruby-B-t6QsyD.js → ruby-B0E3lf9H.js} +1 -1
  197. package/dist/assets/{sas-Z6d1rhi6.js → sas-DURk68cf.js} +1 -1
  198. package/dist/assets/{scss-oo-ZAauB.js → scss-CpCId5ps.js} +1 -1
  199. package/dist/assets/search-CBnr1jD1.js +1 -0
  200. package/dist/assets/seek-backward-10-Dal7obVE.js +1 -0
  201. package/dist/assets/seek-backward-15-AD99eQGo.js +1 -0
  202. package/dist/assets/seek-backward-30-BbQ03-Ol.js +1 -0
  203. package/dist/assets/seek-backward-CCYby5n0.js +1 -0
  204. package/dist/assets/seek-forward-10-BC1NwmUo.js +1 -0
  205. package/dist/assets/seek-forward-15-mkoNS39i.js +1 -0
  206. package/dist/assets/seek-forward-30-C0SVx7IG.js +1 -0
  207. package/dist/assets/seek-forward-Dcui_2xm.js +1 -0
  208. package/dist/assets/send-psIzrYYB.js +1 -0
  209. package/dist/assets/settings-Nify7EqC.js +1 -0
  210. package/dist/assets/settings-menu-D2-gAGst.js +1 -0
  211. package/dist/assets/settings-switch-BMn7TM1n.js +1 -0
  212. package/dist/assets/{shaderlab-DhaYSNG2.js → shaderlab-F_37C8HY.js} +1 -1
  213. package/dist/assets/share-DLPac_kH.js +1 -0
  214. package/dist/assets/share-arrow-EKjK6iyY.js +1 -0
  215. package/dist/assets/{shellscript-CClMYwDv.js → shellscript-C9ppp5mf.js} +1 -1
  216. package/dist/assets/{shellsession-CkCvm7zV.js → shellsession-Bz7lU47b.js} +1 -1
  217. package/dist/assets/shuffle-BZZrchzY.js +1 -0
  218. package/dist/assets/shuffle-on-CmbwVSk9.js +1 -0
  219. package/dist/assets/{soy-Crg2Ekyt.js → soy-BhKWbuAF.js} +1 -1
  220. package/dist/assets/{sparql-CbwLv0Nv.js → sparql-C2li3eXU.js} +1 -1
  221. package/dist/assets/{sql-BzeuYDM3.js → sql-BOLSSU4F.js} +1 -1
  222. package/dist/assets/srt-parser-BGnlNAv_.js +2 -0
  223. package/dist/assets/ssa-parser-BAAtRpeE.js +5 -0
  224. package/dist/assets/{stata-aB59aUx6.js → stata-BT_KvsDz.js} +1 -1
  225. package/dist/assets/std-D4K7rQfG.js +1 -0
  226. package/dist/assets/stop-DNHv8PGN.js +1 -0
  227. package/dist/assets/subtitles-25d83-RU.js +1 -0
  228. package/dist/assets/sun-CH-KcQGq.js +1 -0
  229. package/dist/assets/{svelte-B9KhS2Xg.js → svelte-CDr7VO4q.js} +1 -1
  230. package/dist/assets/{templ-DpUl8Z5L.js → templ-nVp5md9X.js} +1 -1
  231. package/dist/assets/{tex-Dv1X6yMO.js → tex-D_8z9IZF.js} +1 -1
  232. package/dist/assets/theatre-mode-SFx-qJwc.js +1 -0
  233. package/dist/assets/theatre-mode-exit-DYtbjRZd.js +1 -0
  234. package/dist/assets/thumbs-down-CoVX0Rsq.js +1 -0
  235. package/dist/assets/thumbs-up-BGpjKY61.js +1 -0
  236. package/dist/assets/timer-B-qx-F3A.js +1 -0
  237. package/dist/assets/transcript-B9ID7SG_.js +1 -0
  238. package/dist/assets/trpc-1XzKnuJv.js +1 -0
  239. package/dist/assets/{ts-tags-DZ6TGics.js → ts-tags-B9PwlsPz.js} +1 -1
  240. package/dist/assets/{tsx-DOuiELRM.js → tsx-CsYF3fAD.js} +1 -1
  241. package/dist/assets/tv-CC87_vzg.js +1 -0
  242. package/dist/assets/{twig-Btxas3qH.js → twig-DhcsZkOG.js} +1 -1
  243. package/dist/assets/{typescript-N3s0tPxq.js → typescript-BmTNzuQ_.js} +1 -1
  244. package/dist/assets/user-redMLfx7.js +1 -0
  245. package/dist/assets/video-preview-CChWJOsP.js +1 -0
  246. package/dist/assets/volume-high-D_Nod9kV.js +1 -0
  247. package/dist/assets/volume-low-C5d45KrM.js +1 -0
  248. package/dist/assets/{vue-_OK103Ep.js → vue-9hbz3kVV.js} +1 -1
  249. package/dist/assets/{vue-html-BPOZfEpa.js → vue-html-DeYWClYd.js} +1 -1
  250. package/dist/assets/{vue-vine-BwY1fUKp.js → vue-vine-0B8BRjOA.js} +1 -1
  251. package/dist/assets/webworkerAll-CitYd6ji.js +1 -0
  252. package/dist/assets/x-mark-CK6Q9f3e.js +1 -0
  253. package/dist/assets/{xml-DG7tGi3r.js → xml-DANbtZOH.js} +1 -1
  254. package/dist/assets/{xsl-D52MvYic.js → xsl-Dxfe-dB3.js} +1 -1
  255. package/dist/assets/{yaml-8pzj-_Su.js → yaml-hgQ2rJ8K.js} +1 -1
  256. package/dist/audio-preview.html +25 -0
  257. package/dist/image-preview.html +24 -0
  258. package/dist/index.html +15 -11
  259. package/dist/pdf-preview.html +25 -0
  260. package/dist/video-preview.html +25 -0
  261. package/dist-ssg/client/.vite/ssr-manifest.json +51 -15
  262. package/dist-ssg/client/assets/CanvasRenderer-FPbXzOhu.js +1 -0
  263. package/dist-ssg/client/assets/WebGLRenderer-DTbkQ-Tc.js +1 -0
  264. package/dist-ssg/client/assets/WebGPURenderer-jYEtkBkX.js +1 -0
  265. package/dist-ssg/client/assets/browserAll-D2rErTpO.js +1 -0
  266. package/dist-ssg/client/assets/dist-03Q-XuhL.js +1 -0
  267. package/dist-ssg/client/assets/{dist-DF0-eUAB.js → dist-9ZjKnAh1.js} +1 -1
  268. package/dist-ssg/client/assets/{dist-CdlQGwSo.js → dist-BPn14NhJ.js} +1 -1
  269. package/dist-ssg/client/assets/{dist-DRwsq_6M.js → dist-BRxWvz6j.js} +1 -1
  270. package/dist-ssg/client/assets/dist-CNXuEBuZ.js +1 -0
  271. package/dist-ssg/client/assets/{dist-CUDhi1ei.js → dist-DOwxbW7B.js} +1 -1
  272. package/dist-ssg/client/assets/{dist-C2Sop3cf.js → dist-D_7Z5apg.js} +1 -1
  273. package/dist-ssg/client/assets/{dist-5pmc42qO.js → dist-Dg-rGFsy.js} +1 -1
  274. package/dist-ssg/client/assets/dist-Dj9a_D4b.js +1 -0
  275. package/dist-ssg/client/assets/{dist-COHrsH1A.js → dist-DjZdWHNx.js} +1 -1
  276. package/dist-ssg/client/assets/{dist-TgoGtlf0.js → dist-hWAvow10.js} +1 -1
  277. package/dist-ssg/client/assets/{dist-CA5DVY2w.js → dist-yriBIRgD.js} +1 -1
  278. package/dist-ssg/client/assets/{ghostty-web-B5BYD1FV.js → ghostty-web-BVM0FkWD.js} +1 -1
  279. package/dist-ssg/client/assets/index-5OettMZv.css +1 -0
  280. package/dist-ssg/client/assets/{index.ssg-CFeB0ImU.js → index.ssg-C4D0iHIp.js} +156 -148
  281. package/dist-ssg/client/assets/{init-BoLRSoMk.js → init-DBoYmUC7.js} +1 -1
  282. package/dist-ssg/client/assets/trpc-J2T_izXe.js +1 -0
  283. package/dist-ssg/client/assets/webworkerAll-CLzsuMst.js +1 -0
  284. package/dist-ssg/client/index.ssg.html +2 -2
  285. package/dist-ssg/server/entry-server.js +1767 -565
  286. package/package.json +8 -4
  287. package/dist/assets/CanvasRenderer-FPfL9ZTd.js +0 -1
  288. package/dist/assets/WebGLRenderer-MAViiHZM.js +0 -1
  289. package/dist/assets/WebGPURenderer-BTs4iUDJ.js +0 -1
  290. package/dist/assets/browserAll-BrCpXy8F.js +0 -1
  291. package/dist/assets/dist-6OABjv-w.js +0 -1
  292. package/dist/assets/dist-B6Tdxx2M.js +0 -1
  293. package/dist/assets/dist-ByROe2mk.js +0 -1
  294. package/dist/assets/dist-CL664tGJ.js +0 -1
  295. package/dist/assets/dist-CNPeR4Pz.js +0 -1
  296. package/dist/assets/dist-CUXEJ56i.js +0 -1
  297. package/dist/assets/dist-CxEKNYqH.js +0 -1
  298. package/dist/assets/dist-D_kRWvjc.js +0 -1
  299. package/dist/assets/dist-DdNBXL_R.js +0 -1
  300. package/dist/assets/dist-DoKbVA83.js +0 -1
  301. package/dist/assets/dist-EJjOo0if.js +0 -1
  302. package/dist/assets/dist-MqSTP1IH.js +0 -1
  303. package/dist/assets/ghostty-web-PwpXfIYz.js +0 -13
  304. package/dist/assets/index-6J-oF_Ui.js +0 -1654
  305. package/dist/assets/index-CSo2hsDq.css +0 -1
  306. package/dist/assets/init-DzZk7m7r.js +0 -1
  307. package/dist/assets/trpc-buLTPM4j.js +0 -1
  308. package/dist/assets/webworkerAll-D4aUBsFv.js +0 -1
  309. package/dist-ssg/client/assets/CanvasRenderer-Cl0iebcM.js +0 -1
  310. package/dist-ssg/client/assets/WebGLRenderer-D1L_66kz.js +0 -1
  311. package/dist-ssg/client/assets/WebGPURenderer-GnxaJPyT.js +0 -1
  312. package/dist-ssg/client/assets/browserAll-wfYAjP5o.js +0 -1
  313. package/dist-ssg/client/assets/dist-BAJHUZ0g.js +0 -1
  314. package/dist-ssg/client/assets/dist-BvCGGujU.js +0 -1
  315. package/dist-ssg/client/assets/dist-DCB1Hxb5.js +0 -1
  316. package/dist-ssg/client/assets/index-CrZEd8bY.css +0 -1
  317. package/dist-ssg/client/assets/trpc-CdH8LrJC.js +0 -1
  318. package/dist-ssg/client/assets/webworkerAll-CJ3LFlvS.js +0 -1
  319. /package/dist/assets/{__vite-browser-external-2447137e-BjPw0NZ_.js → __vite-browser-external-2447137e-DSmEJFXS.js} +0 -0
  320. /package/dist/assets/{abap-Bu0T6Al_.js → abap-CIVploVa.js} +0 -0
  321. /package/dist/assets/{actionscript-3-CRpSnB5s.js → actionscript-3-BOT81qbB.js} +0 -0
  322. /package/dist/assets/{ada-CFBoRA9T.js → ada-CRwAfJoy.js} +0 -0
  323. /package/dist/assets/{andromeeda-DgY5bL_s.js → andromeeda-mLkPyWfB.js} +0 -0
  324. /package/dist/assets/{apache-R7xc0G73.js → apache-DtNAck0z.js} +0 -0
  325. /package/dist/assets/{apex-DEkce9NE.js → apex-Bj7wG4q1.js} +0 -0
  326. /package/dist/assets/{apl-CJPt5sW7.js → apl-C5q1JUQ9.js} +0 -0
  327. /package/dist/assets/{applescript-C_3LmUl6.js → applescript-BQKDn04f.js} +0 -0
  328. /package/dist/assets/{ara-CV-W5Hgd.js → ara-BNT_CvyP.js} +0 -0
  329. /package/dist/assets/{asciiarmor-D0oCypDs.js → asciiarmor-BILZohWd.js} +0 -0
  330. /package/dist/assets/{asciidoc-D-6cF97z.js → asciidoc-B0485J9X.js} +0 -0
  331. /package/dist/assets/{asm-DYZMpR5h.js → asm-C2znhxd3.js} +0 -0
  332. /package/dist/assets/{asn1-8xgVfRoq.js → asn1-DI_FTWHM.js} +0 -0
  333. /package/dist/assets/{asterisk-B5kv5AQp.js → asterisk-CoYCo1jb.js} +0 -0
  334. /package/dist/assets/{aurora-x-CzNZBXLA.js → aurora-x-VoXHDv1B.js} +0 -0
  335. /package/dist/assets/{awk-CtGnqBgi.js → awk-BbTIDvOU.js} +0 -0
  336. /package/dist/assets/{ayu-dark-BEuJhx09.js → ayu-dark-BTK5Tfht.js} +0 -0
  337. /package/dist/assets/{ballerina-FF_I4_FO.js → ballerina-dRxGI8s4.js} +0 -0
  338. /package/dist/assets/{bat-BrvgUmWp.js → bat-BO6lv9SU.js} +0 -0
  339. /package/dist/assets/{beancount-BXL8T_UG.js → beancount-oq4SVsFS.js} +0 -0
  340. /package/dist/assets/{berry-CIKKfJQu.js → berry-CXRUyStP.js} +0 -0
  341. /package/dist/assets/{bibtex-Cjz3iUeg.js → bibtex-M8Wf0hPR.js} +0 -0
  342. /package/dist/assets/{bicep-BcfLCnJ8.js → bicep-DVkXDr0Y.js} +0 -0
  343. /package/dist/assets/{brainfuck-Dh7M1Ucz.js → brainfuck-CYletLv0.js} +0 -0
  344. /package/dist/assets/{cadence-C8mWZDXU.js → cadence-B0XH_PKy.js} +0 -0
  345. /package/dist/assets/{catppuccin-frappe-DenhEhc7.js → catppuccin-frappe-DhEuGbek.js} +0 -0
  346. /package/dist/assets/{catppuccin-latte-DBjZqKjK.js → catppuccin-latte-vkF8zGxA.js} +0 -0
  347. /package/dist/assets/{catppuccin-macchiato-DsXr7TPP.js → catppuccin-macchiato-Y7LgIKdI.js} +0 -0
  348. /package/dist/assets/{catppuccin-mocha-DmPmnX9r.js → catppuccin-mocha-B0udSjIm.js} +0 -0
  349. /package/dist/assets/{chunk-BEqpzyXh.js → chunk-VBW0iQ51.js} +0 -0
  350. /package/dist/assets/{clarity-CSJ2rDuE.js → clarity-DDiR-2NO.js} +0 -0
  351. /package/dist/assets/{clike-zYz_LEkw.js → clike-BJQXzji6.js} +0 -0
  352. /package/dist/assets/{clojure-CdWlIeQh.js → clojure-BTMF0bWr.js} +0 -0
  353. /package/dist/assets/{clojure-BcrkjbX1.js → clojure-snlX0Q6G.js} +0 -0
  354. /package/dist/assets/{cmake-BHzgnx8G.js → cmake-CsF3WHAq.js} +0 -0
  355. /package/dist/assets/{cmake-wWuF5ifR.js → cmake-Jt1LPs3Y.js} +0 -0
  356. /package/dist/assets/{cobol-D3WLbLVy.js → cobol-Bp7hDZyh.js} +0 -0
  357. /package/dist/assets/{codeowners-DEui52l1.js → codeowners-D0_uS0CW.js} +0 -0
  358. /package/dist/assets/{codeql-DV6BvMBu.js → codeql-BedCyGW_.js} +0 -0
  359. /package/dist/assets/{coffeescript-DRtt-5a2.js → coffeescript-CAuf1hwk.js} +0 -0
  360. /package/dist/assets/{common-lisp-xYiRwqZH.js → common-lisp-D5FvNe7i.js} +0 -0
  361. /package/dist/assets/{commonlisp-DJV75lsU.js → commonlisp-CTI5EoKD.js} +0 -0
  362. /package/dist/assets/{coq-C_yPIhZC.js → coq-8fYOFE_L.js} +0 -0
  363. /package/dist/assets/{crystal-C7mEw92C.js → crystal-C3-bEPdz.js} +0 -0
  364. /package/dist/assets/{csharp-_SaU5MOa.js → csharp-CRgWAKTP.js} +0 -0
  365. /package/dist/assets/{css-_6KgQwpu.js → css-DOOfdS_P.js} +0 -0
  366. /package/dist/assets/{csv-DkOKkcud.js → csv-BvaZ2T8c.js} +0 -0
  367. /package/dist/assets/{cue-Bc7aFG0x.js → cue-CuSO7twe.js} +0 -0
  368. /package/dist/assets/{cypher-DJ7FXmKn.js → cypher-Csc02QHL.js} +0 -0
  369. /package/dist/assets/{cypher-B3uWx7jm.js → cypher-D3PQ91Qx.js} +0 -0
  370. /package/dist/assets/{d-C_e6FFTd.js → d-CnB930ZR.js} +0 -0
  371. /package/dist/assets/{d-D3kOh3JF.js → d-Czsz-1nb.js} +0 -0
  372. /package/dist/assets/{dark-plus-CR_9xkOf.js → dark-plus-CESRMc3w.js} +0 -0
  373. /package/dist/assets/{dart-DpnlYij3.js → dart-BIgn-HM9.js} +0 -0
  374. /package/dist/assets/{dax-BGp0L71d.js → dax-pHt8u_2B.js} +0 -0
  375. /package/dist/assets/{desktop-9sZJLqKg.js → desktop-Cf3zYveK.js} +0 -0
  376. /package/dist/assets/{diff-Eg5NxGYi.js → diff-CatgE3dT.js} +0 -0
  377. /package/dist/assets/{diff-CoamybWh.js → diff-DTEjW6Ec.js} +0 -0
  378. /package/dist/assets/{dist-UN0VvTJo.js → dist-vqrjFRzf.js} +0 -0
  379. /package/dist/assets/{docker-B1k24ONt.js → docker-BxryWGFh.js} +0 -0
  380. /package/dist/assets/{dotenv-37x23HEd.js → dotenv-Ce5U7oib.js} +0 -0
  381. /package/dist/assets/{dracula-CxQ11msU.js → dracula-DAC2eyrV.js} +0 -0
  382. /package/dist/assets/{dracula-soft-DZQDoc4v.js → dracula-soft-CzyQJAj9.js} +0 -0
  383. /package/dist/assets/{dream-maker-kAD9OQQF.js → dream-maker-CnxFHZvN.js} +0 -0
  384. /package/dist/assets/{dtd-BjGQwMWL.js → dtd-DQ2nGp1I.js} +0 -0
  385. /package/dist/assets/{dylan-B9W3X2GI.js → dylan-Bje9X1q4.js} +0 -0
  386. /package/dist/assets/{ebnf-d5D0otVn.js → ebnf-DEiu6Mj6.js} +0 -0
  387. /package/dist/assets/{ecl-C5Q_IBPt.js → ecl-CcozsAMR.js} +0 -0
  388. /package/dist/assets/{eiffel-BQA_6I3b.js → eiffel-CZRTum_1.js} +0 -0
  389. /package/dist/assets/{elm-unPS17vB.js → elm-Cgd7AVBx.js} +0 -0
  390. /package/dist/assets/{emacs-lisp-VSqiU67A.js → emacs-lisp-8ncNO10u.js} +0 -0
  391. /package/dist/assets/{erlang-R8nOsUTx.js → erlang-BPW5ALQf.js} +0 -0
  392. /package/dist/assets/{everforest-dark-B5yeWra_.js → everforest-dark-WRGJyDpD.js} +0 -0
  393. /package/dist/assets/{everforest-light-B4NKIpuT.js → everforest-light-DfrVdsO0.js} +0 -0
  394. /package/dist/assets/{fcl-CVAfW9wK.js → fcl-Bv0H-MfR.js} +0 -0
  395. /package/dist/assets/{fennel-CFfxI1rI.js → fennel-Cb9koYyA.js} +0 -0
  396. /package/dist/assets/{fish-DwEMo9K0.js → fish-Bqbms_J3.js} +0 -0
  397. /package/dist/assets/{fluent-Dsn20KHK.js → fluent-BpgGq6W4.js} +0 -0
  398. /package/dist/assets/{forth-DHbsK8X8.js → forth-CFHh7lFN.js} +0 -0
  399. /package/dist/assets/{fortran-4jMwxW9-.js → fortran-CAaqh7IE.js} +0 -0
  400. /package/dist/assets/{fortran-free-form-dGWJP-PE.js → fortran-free-form-D7-gzSM8.js} +0 -0
  401. /package/dist/assets/{gas-zC_XGrQT.js → gas-BXzla7cs.js} +0 -0
  402. /package/dist/assets/{gdscript-CW6S_vBb.js → gdscript-rt9_TXru.js} +0 -0
  403. /package/dist/assets/{gdshader-BqnlaYeo.js → gdshader-crF0MxG8.js} +0 -0
  404. /package/dist/assets/{genie-DpK7PEre.js → genie-n4manvaZ.js} +0 -0
  405. /package/dist/assets/{gherkin-CPBQou3u.js → gherkin-CjaNPZBr.js} +0 -0
  406. /package/dist/assets/{gherkin-Do-rHwCg.js → gherkin-CuiH0tfp.js} +0 -0
  407. /package/dist/assets/{github-dark-BNWfKer2.js → github-dark-DLGWmEyp.js} +0 -0
  408. /package/dist/assets/{github-dark-default-Dd3JR36E.js → github-dark-default-COxVH7oN.js} +0 -0
  409. /package/dist/assets/{github-dark-dimmed-CtNE8tZH.js → github-dark-dimmed-DvctdGH5.js} +0 -0
  410. /package/dist/assets/{github-dark-high-contrast-DmAdH_w8.js → github-dark-high-contrast-B5e5f6Wv.js} +0 -0
  411. /package/dist/assets/{github-light-CUv7VR5J.js → github-light-TJTPBbm1.js} +0 -0
  412. /package/dist/assets/{github-light-default-CZlC_y8X.js → github-light-default-DC_TACoY.js} +0 -0
  413. /package/dist/assets/{github-light-high-contrast-Cpzf_dNN.js → github-light-high-contrast-DvNa2h0A.js} +0 -0
  414. /package/dist/assets/{gleam-DC5ARhDs.js → gleam-GMotk68v.js} +0 -0
  415. /package/dist/assets/{gnuplot-DSp3nTIV.js → gnuplot-PmulD7a0.js} +0 -0
  416. /package/dist/assets/{go-qASC_aC8.js → go-BD7Erf5u.js} +0 -0
  417. /package/dist/assets/{groovy-CAKGLWL8.js → groovy-BJHHaekH.js} +0 -0
  418. /package/dist/assets/{groovy-Cqopym0q.js → groovy-CQ51TE23.js} +0 -0
  419. /package/dist/assets/{gruvbox-dark-hard-Dlubl6r4.js → gruvbox-dark-hard-DMHKOM26.js} +0 -0
  420. /package/dist/assets/{gruvbox-dark-medium-Bys2crvl.js → gruvbox-dark-medium-CHM96JoK.js} +0 -0
  421. /package/dist/assets/{gruvbox-dark-soft-D5JVdD_T.js → gruvbox-dark-soft-BXZKbIog.js} +0 -0
  422. /package/dist/assets/{gruvbox-light-hard-okzwij0Q.js → gruvbox-light-hard-D6IrNyel.js} +0 -0
  423. /package/dist/assets/{gruvbox-light-medium-CKptZdRG.js → gruvbox-light-medium-BJbnlMJn.js} +0 -0
  424. /package/dist/assets/{gruvbox-light-soft-DVSSH44h.js → gruvbox-light-soft-BgH5zDdq.js} +0 -0
  425. /package/dist/assets/{haskell-imzbNPgF.js → haskell-BdLQbrXE.js} +0 -0
  426. /package/dist/assets/{haskell-BKk-Kl5_.js → haskell-YfIOUUBK.js} +0 -0
  427. /package/dist/assets/{haxe-BPFrQPtj.js → haxe-B256JjEJ.js} +0 -0
  428. /package/dist/assets/{haxe-Doh225Ku.js → haxe-BR_oGt5J.js} +0 -0
  429. /package/dist/assets/{hcl-BH96BnDR.js → hcl-z6UKeceE.js} +0 -0
  430. /package/dist/assets/{hjson-BMjtlQGM.js → hjson-B4eAwwls.js} +0 -0
  431. /package/dist/assets/{hlsl-g9gCsmqR.js → hlsl-D0l9oydz.js} +0 -0
  432. /package/dist/assets/{houston-CL5fNb0m.js → houston-B0KYClEN.js} +0 -0
  433. /package/dist/assets/{http-j4R5uEso.js → http-D4AikK5M.js} +0 -0
  434. /package/dist/assets/{hy-C4Qxxvge.js → hy-BffdPpaq.js} +0 -0
  435. /package/dist/assets/{idl-l9d1__Hj.js → idl-BhLYYWfC.js} +0 -0
  436. /package/dist/assets/{imba-BMCGEjtx.js → imba-CeA-T7p1.js} +0 -0
  437. /package/dist/assets/{ini-CiVvBUuJ.js → ini-CR4FPmWV.js} +0 -0
  438. /package/dist/assets/{javascript-BcqCeS4O.js → javascript-DoCiwYd8.js} +0 -0
  439. /package/dist/assets/{json5-CLu_sBvv.js → json5-C27Vp2xe.js} +0 -0
  440. /package/dist/assets/{jsonc-BtCrUwnt.js → jsonc-BVh3vxUv.js} +0 -0
  441. /package/dist/assets/{jsonl-DCgn6lTZ.js → jsonl-D15CZ_EL.js} +0 -0
  442. /package/dist/assets/{jsonnet-f86dBoR6.js → jsonnet-DhFVDxfq.js} +0 -0
  443. /package/dist/assets/{jssm-C9wYN-Un.js → jssm-0SEG_l0W.js} +0 -0
  444. /package/dist/assets/{julia-BU0qBb1w.js → julia-TGuXb-4v.js} +0 -0
  445. /package/dist/assets/{kanagawa-dragon-j2mqGXO-.js → kanagawa-dragon-B1itLu88.js} +0 -0
  446. /package/dist/assets/{kanagawa-lotus-DkcquZHv.js → kanagawa-lotus-Dl28Njgk.js} +0 -0
  447. /package/dist/assets/{kanagawa-wave-CC8Oc_s3.js → kanagawa-wave-BCpJajEn.js} +0 -0
  448. /package/dist/assets/{kdl-DzBG_i-5.js → kdl-B_tNS5SW.js} +0 -0
  449. /package/dist/assets/{kotlin-DIZwIusw.js → kotlin-pIweK0Tp.js} +0 -0
  450. /package/dist/assets/{kusto-DNbnBPvH.js → kusto-CqxEvpDG.js} +0 -0
  451. /package/dist/assets/{laserwave-CVoxTCdH.js → laserwave-BsFEN8Kz.js} +0 -0
  452. /package/dist/assets/{lean-Dlfurqwe.js → lean-DC7SPxbi.js} +0 -0
  453. /package/dist/assets/{less-BZZ-PLfd.js → less-Cgo6VXQL.js} +0 -0
  454. /package/dist/assets/{light-plus-BeMZ11-X.js → light-plus-DFxEhcsH.js} +0 -0
  455. /package/dist/assets/{livescript-uk34VDGK.js → livescript-C-wu00Ej.js} +0 -0
  456. /package/dist/assets/{llvm-CdR1gjlo.js → llvm-CmGPTzZ_.js} +0 -0
  457. /package/dist/assets/{log-iTn25_BO.js → log-BYyZvwT6.js} +0 -0
  458. /package/dist/assets/{logo-BcHhJD22.js → logo-RPed3OZI.js} +0 -0
  459. /package/dist/assets/{lua-ClQGOv84.js → lua-CGv6iOiJ.js} +0 -0
  460. /package/dist/assets/{luau-4FcpJ0Mb.js → luau-C6H01j1p.js} +0 -0
  461. /package/dist/assets/{make-BG0ZJ6Bw.js → make-Bp_ym9Ei.js} +0 -0
  462. /package/dist/assets/{markdown-jQZFZ3m0.js → markdown-UHPJkTEn.js} +0 -0
  463. /package/dist/assets/{material-theme-C5C8C9wY.js → material-theme-Cmydairr.js} +0 -0
  464. /package/dist/assets/{material-theme-darker-CxXF5p3u.js → material-theme-darker-focsTHXN.js} +0 -0
  465. /package/dist/assets/{material-theme-lighter-CN3_ew41.js → material-theme-lighter-BISf6XMH.js} +0 -0
  466. /package/dist/assets/{material-theme-ocean-DOr1uqH8.js → material-theme-ocean-Bzktmjor.js} +0 -0
  467. /package/dist/assets/{material-theme-palenight-BjejtMhX.js → material-theme-palenight-My1fd_35.js} +0 -0
  468. /package/dist/assets/{mathematica-BDmKpvRN.js → mathematica-C8bAvxin.js} +0 -0
  469. /package/dist/assets/{matlab-DeaiNlNF.js → matlab-CBx34vf_.js} +0 -0
  470. /package/dist/assets/{mbox-T5kA6jAQ.js → mbox-BYumpJj6.js} +0 -0
  471. /package/dist/assets/{mdx-ST4v-vi3.js → mdx-YGW2G4Uv.js} +0 -0
  472. /package/dist/assets/{mermaid-BAjGqWD-.js → mermaid-wzZJmzgK.js} +0 -0
  473. /package/dist/assets/{min-dark-DhWD_LA8.js → min-dark-Dxk-ityX.js} +0 -0
  474. /package/dist/assets/{min-light-TFk_TRdA.js → min-light-DsAIUNE7.js} +0 -0
  475. /package/dist/assets/{mipsasm-Cs1MOJEB.js → mipsasm-B8w8xWxH.js} +0 -0
  476. /package/dist/assets/{mirc-DRRKKkcJ.js → mirc-Dhg1_lkg.js} +0 -0
  477. /package/dist/assets/{mllike-iZXopbca.js → mllike-DekHTKRS.js} +0 -0
  478. /package/dist/assets/{modelica-DP8T2DKM.js → modelica-CcMbWJDy.js} +0 -0
  479. /package/dist/assets/{mojo-Dhum44Vp.js → mojo-BNCZEj9n.js} +0 -0
  480. /package/dist/assets/{monokai-zQwYTSXE.js → monokai-F_b0DFq1.js} +0 -0
  481. /package/dist/assets/{move-DDQwygay.js → move-okvFAmHH.js} +0 -0
  482. /package/dist/assets/{mscgen-DXIRw2qg.js → mscgen-D26dCiP0.js} +0 -0
  483. /package/dist/assets/{mumps-BKUS05-y.js → mumps-BJZx4oNt.js} +0 -0
  484. /package/dist/assets/{narrat-DbhadX58.js → narrat-CFbdikxO.js} +0 -0
  485. /package/dist/assets/{nextflow-Knih_yDk.js → nextflow-DzKS-iEs.js} +0 -0
  486. /package/dist/assets/{nginx-CzYOtr2G.js → nginx-PPx_WycM.js} +0 -0
  487. /package/dist/assets/{night-owl-DLGGnVs3.js → night-owl-qACT83C1.js} +0 -0
  488. /package/dist/assets/{nix-Baz5UHw4.js → nix-C9Hi1nKD.js} +0 -0
  489. /package/dist/assets/{nord-C3wm8E4I.js → nord-CH3RDbQu.js} +0 -0
  490. /package/dist/assets/{ntriples-ZgZuaYbW.js → ntriples--kmqf5za.js} +0 -0
  491. /package/dist/assets/{nushell-D5-473hD.js → nushell-DIaYF6Ou.js} +0 -0
  492. /package/dist/assets/{objective-c-BI6SNMJ5.js → objective-c-CGGdYinr.js} +0 -0
  493. /package/dist/assets/{objective-cpp-DAlvnJVe.js → objective-cpp-BjWDdNsO.js} +0 -0
  494. /package/dist/assets/{ocaml-CEGFuihZ.js → ocaml-D81Jtht8.js} +0 -0
  495. /package/dist/assets/{octave-CnOndUN3.js → octave-CAcJQTlE.js} +0 -0
  496. /package/dist/assets/{one-dark-pro-B6FJ0zvF.js → one-dark-pro-B-ww0r1B.js} +0 -0
  497. /package/dist/assets/{one-light-B2XUBJF_.js → one-light-BPbLaA51.js} +0 -0
  498. /package/dist/assets/{openscad-t-6iF15O.js → openscad-B0c464sF.js} +0 -0
  499. /package/dist/assets/{oz-DjW322Rn.js → oz-ARD1A4_T.js} +0 -0
  500. /package/dist/assets/{pascal-BdeW5uRX.js → pascal-DK7Ai13I.js} +0 -0
  501. /package/dist/assets/{pascal-BHLTdjhR.js → pascal-DT0zMytF.js} +0 -0
  502. /package/dist/assets/{perl-_CDvIe1D.js → perl-C687o_bL.js} +0 -0
  503. /package/dist/assets/{pig-inWo_B4W.js → pig-C8e4kEQV.js} +0 -0
  504. /package/dist/assets/{pkl-zHHuHn_z.js → pkl-LMui8nOx.js} +0 -0
  505. /package/dist/assets/{plastic-BRO-85T7.js → plastic-Dz26KdRC.js} +0 -0
  506. /package/dist/assets/{plsql-VRcuhvv-.js → plsql-B49Stwj8.js} +0 -0
  507. /package/dist/assets/{po-CResul3s.js → po-DJ8fyyzx.js} +0 -0
  508. /package/dist/assets/{poimandres-DCo9RR46.js → poimandres-DCUkkKHL.js} +0 -0
  509. /package/dist/assets/{polar-CakhKjn-.js → polar-2GyBpdLT.js} +0 -0
  510. /package/dist/assets/{postcss-BtHn3WbL.js → postcss-Bhprukf5.js} +0 -0
  511. /package/dist/assets/{powerquery-1rYvKCYD.js → powerquery-DfuTdzd8.js} +0 -0
  512. /package/dist/assets/{powershell-CO5KWJsy.js → powershell-C2Y_oyRr.js} +0 -0
  513. /package/dist/assets/{powershell-DE8KuUJ5.js → powershell-YtOHKxmJ.js} +0 -0
  514. /package/dist/assets/{prisma-Z141y9Vf.js → prisma-Ce3LhkhD.js} +0 -0
  515. /package/dist/assets/{prolog-Dxo_24BF.js → prolog-B2_CLi2F.js} +0 -0
  516. /package/dist/assets/{properties-CjVp4a6M.js → properties-DmYRuvnA.js} +0 -0
  517. /package/dist/assets/{proto-BFlW3M8m.js → proto-BTb-udmG.js} +0 -0
  518. /package/dist/assets/{protobuf-DybFT2KT.js → protobuf-CD6bEuFl.js} +0 -0
  519. /package/dist/assets/{puppet-CEsvHObS.js → puppet-C1Die36f.js} +0 -0
  520. /package/dist/assets/{puppet-Dw_NDgko.js → puppet-CsErpTW6.js} +0 -0
  521. /package/dist/assets/{purescript-BICOMc_6.js → purescript-DrZcHieW.js} +0 -0
  522. /package/dist/assets/{python-2pwcWoy7.js → python-DJuj1ZhC.js} +0 -0
  523. /package/dist/assets/{python-B0QK5ArY.js → python-JifBw8Pd.js} +0 -0
  524. /package/dist/assets/{q-C47l8kdS.js → q-DKzQvbt-.js} +0 -0
  525. /package/dist/assets/{qmldir-CPo3sDuO.js → qmldir-B22UuinR.js} +0 -0
  526. /package/dist/assets/{qss-D8trd40O.js → qss-CWapWRD3.js} +0 -0
  527. /package/dist/assets/{r-BmcXGVZ5.js → r-DUDpJ6Ff.js} +0 -0
  528. /package/dist/assets/{racket-BfOZs-VM.js → racket-Bf0hA9MY.js} +0 -0
  529. /package/dist/assets/{raku-lci39Tgk.js → raku-CXw4nqUw.js} +0 -0
  530. /package/dist/assets/{red-Ih7tMgXP.js → red-CzNC31na.js} +0 -0
  531. /package/dist/assets/{reg-K8cH8FkV.js → reg-CHCsNg7g.js} +0 -0
  532. /package/dist/assets/{rel-DxH5YkUl.js → rel-Ow-K5mDh.js} +0 -0
  533. /package/dist/assets/{riscv-DNTTjOwX.js → riscv-CtcsvWbN.js} +0 -0
  534. /package/dist/assets/{rose-pine-CBcSv8_z.js → rose-pine-DJ7LyBAT.js} +0 -0
  535. /package/dist/assets/{rose-pine-dawn-DsFTrjAP.js → rose-pine-dawn-C3kUPo7D.js} +0 -0
  536. /package/dist/assets/{rose-pine-moon-DSRrHXqB.js → rose-pine-moon-D5SxMAqW.js} +0 -0
  537. /package/dist/assets/{rosmsg-D94pSJ6t.js → rosmsg-a4V7Aj7O.js} +0 -0
  538. /package/dist/assets/{rpm-Cm0x5xT_.js → rpm-qoLWOnFN.js} +0 -0
  539. /package/dist/assets/{ruby-Dl-I4pxG.js → ruby-FGrV8nFX.js} +0 -0
  540. /package/dist/assets/{rust-BaX7heYs.js → rust-Cb9YKWSH.js} +0 -0
  541. /package/dist/assets/{sas-Bxkg4GVX.js → sas-BWqJ1mab.js} +0 -0
  542. /package/dist/assets/{sass-MHYUMeyd.js → sass-D7eOJrmY.js} +0 -0
  543. /package/dist/assets/{scala-0toQGra_.js → scala-DiHVSd0P.js} +0 -0
  544. /package/dist/assets/{scheme-CO3zogua.js → scheme-D9O3un-H.js} +0 -0
  545. /package/dist/assets/{scheme-B5NPj6KX.js → scheme-DqmxMK_5.js} +0 -0
  546. /package/dist/assets/{sdbl-lyJ_q2qY.js → sdbl-DcdijJCo.js} +0 -0
  547. /package/dist/assets/{shell-gYrTvBTP.js → shell-B1pKmMgB.js} +0 -0
  548. /package/dist/assets/{sieve-COX4Kn1X.js → sieve-D6RnHXa8.js} +0 -0
  549. /package/dist/assets/{simple-mode-kdHrpFjq.js → simple-mode-DW6rCJL0.js} +0 -0
  550. /package/dist/assets/{slack-dark-DJYHgMC5.js → slack-dark-q967N1Vs.js} +0 -0
  551. /package/dist/assets/{slack-ochin-DMZh8xHM.js → slack-ochin-a6A0wbgW.js} +0 -0
  552. /package/dist/assets/{smalltalk-Dma1z5eE.js → smalltalk-Bg8P7Hpz.js} +0 -0
  553. /package/dist/assets/{smalltalk-DS2N8CIT.js → smalltalk-vFEqincc.js} +0 -0
  554. /package/dist/assets/{snazzy-light-CWz9pGNQ.js → snazzy-light-CZMs_LkS.js} +0 -0
  555. /package/dist/assets/{solarized-dark-D9XpTy8q.js → solarized-dark-BGr8h_-s.js} +0 -0
  556. /package/dist/assets/{solarized-light-CbOIwuI-.js → solarized-light-BYRl8cvt.js} +0 -0
  557. /package/dist/assets/{solidity-Dt295RBh.js → solidity-CiPHtV-S.js} +0 -0
  558. /package/dist/assets/{solr-BvhcdkNH.js → solr-DCTMbxYh.js} +0 -0
  559. /package/dist/assets/{sparql-gX7W9xeh.js → sparql-D3342bJj.js} +0 -0
  560. /package/dist/assets/{splunk-DPuGGZIX.js → splunk-CnQhHYV7.js} +0 -0
  561. /package/dist/assets/{spreadsheet-BnlQRxWz.js → spreadsheet-D5vgGBWN.js} +0 -0
  562. /package/dist/assets/{sql-CwA10oIk.js → sql-C34SerfO.js} +0 -0
  563. /package/dist/assets/{ssh-config-81Puc665.js → ssh-config-DxyN4D39.js} +0 -0
  564. /package/dist/assets/{stex-DhLUylSV.js → stex-CIr7vrJc.js} +0 -0
  565. /package/dist/assets/{stylus-DBx-JbUM.js → stylus-BGkOI8rZ.js} +0 -0
  566. /package/dist/assets/{stylus-9ZGSp3KB.js → stylus-uKe9pX_z.js} +0 -0
  567. /package/dist/assets/{swift-CurfpLXH.js → swift-BwGtfoET.js} +0 -0
  568. /package/dist/assets/{swift-LIGMYdoY.js → swift-DYZLJadl.js} +0 -0
  569. /package/dist/assets/{synthwave-84-BnPKtV8a.js → synthwave-84-CwulpOa6.js} +0 -0
  570. /package/dist/assets/{system-verilog-DhhazFNi.js → system-verilog-Dp661CvP.js} +0 -0
  571. /package/dist/assets/{systemd-Cvp21r3-.js → systemd-kktSp3-B.js} +0 -0
  572. /package/dist/assets/{talonscript-Ex_ZAXWk.js → talonscript-Nc_j5bsE.js} +0 -0
  573. /package/dist/assets/{tasl-C6wcXx0u.js → tasl-C9qCYaij.js} +0 -0
  574. /package/dist/assets/{tcl-CMtw19Y3.js → tcl-7dXGLOIP.js} +0 -0
  575. /package/dist/assets/{tcl-BPvzXR-t.js → tcl-CJ_CtVRZ.js} +0 -0
  576. /package/dist/assets/{terraform-BFKovB2a.js → terraform-n2Mjymla.js} +0 -0
  577. /package/dist/assets/{textile-BUq3vgBH.js → textile-BwILayi5.js} +0 -0
  578. /package/dist/assets/{tiddlywiki-DRR6E4hS.js → tiddlywiki-CBwaBkZo.js} +0 -0
  579. /package/dist/assets/{tiki-C1XMixgx.js → tiki-DrYLgX3z.js} +0 -0
  580. /package/dist/assets/{tokyo-night-ByryBNMy.js → tokyo-night-CTu41Jiz.js} +0 -0
  581. /package/dist/assets/{toml-BQjoWSzq.js → toml-B15mRAoh.js} +0 -0
  582. /package/dist/assets/{toml-2TD737C5.js → toml-mjAKlhgf.js} +0 -0
  583. /package/dist/assets/{troff-DbgTp3Cj.js → troff-1GwZ4_kM.js} +0 -0
  584. /package/dist/assets/{tsv-B4GEmyrY.js → tsv-C9lzu5HK.js} +0 -0
  585. /package/dist/assets/{ttcn-1OxchGWH.js → ttcn-Rt4tcn5J.js} +0 -0
  586. /package/dist/assets/{ttcn-cfg-CC8OhyHu.js → ttcn-cfg-B2QycmWC.js} +0 -0
  587. /package/dist/assets/{turtle-D1WjVU4-.js → turtle-B99g2iYO.js} +0 -0
  588. /package/dist/assets/{turtle-CrO-XU5O.js → turtle-vnW9ZH2N.js} +0 -0
  589. /package/dist/assets/{typespec-BlhpafUo.js → typespec-CQo-8V96.js} +0 -0
  590. /package/dist/assets/{typst-BFytn-nF.js → typst-CcuHmJkn.js} +0 -0
  591. /package/dist/assets/{v-QsV0mqFY.js → v-B-DRpDLN.js} +0 -0
  592. /package/dist/assets/{vala-2OEMaeCr.js → vala-VuvWDMVG.js} +0 -0
  593. /package/dist/assets/{vb-Bf-XXYNJ.js → vb-BNGsVLgX.js} +0 -0
  594. /package/dist/assets/{vb-D9JlZMQx.js → vb-uGgKumq9.js} +0 -0
  595. /package/dist/assets/{vbscript-HeSyWuOi.js → vbscript-C3L-Slq1.js} +0 -0
  596. /package/dist/assets/{velocity-CUkiDsJQ.js → velocity-B5fLEzdR.js} +0 -0
  597. /package/dist/assets/{verilog-D04WYu-9.js → verilog-Cs3u3WKB.js} +0 -0
  598. /package/dist/assets/{verilog-BFxB5RAN.js → verilog-T4dM3A9w.js} +0 -0
  599. /package/dist/assets/{vesper-RapGiuFK.js → vesper-DKfkBFNi.js} +0 -0
  600. /package/dist/assets/{vhdl-BJUXQE-6.js → vhdl-Bdbtaye2.js} +0 -0
  601. /package/dist/assets/{vhdl-BmN7pPc4.js → vhdl-D8g93jeS.js} +0 -0
  602. /package/dist/assets/{viml-CgKKOlcK.js → viml-D75b9QT4.js} +0 -0
  603. /package/dist/assets/{vitesse-black-CK3sbzcK.js → vitesse-black-C8ZVPNNc.js} +0 -0
  604. /package/dist/assets/{vitesse-dark-D1-w1Fr7.js → vitesse-dark-Q3oZDeXO.js} +0 -0
  605. /package/dist/assets/{vitesse-light-D7Ky4DHb.js → vitesse-light-BU9zjuoG.js} +0 -0
  606. /package/dist/assets/{vyper-DyC3s8t1.js → vyper-I128n63H.js} +0 -0
  607. /package/dist/assets/{wasm-D0KG-h38.js → wasm-DFtcXgiA.js} +0 -0
  608. /package/dist/assets/{wasm-HmdyAy9e.js → wasm-TauBo8uk.js} +0 -0
  609. /package/dist/assets/{webidl-advQMGTP.js → webidl-BMlkVTYq.js} +0 -0
  610. /package/dist/assets/{wenyan-2PUFg5JI.js → wenyan-Tj1RZlPx.js} +0 -0
  611. /package/dist/assets/{wgsl-CN7jA0x_.js → wgsl-DuCaFBOG.js} +0 -0
  612. /package/dist/assets/{wikitext-jh9pTKmw.js → wikitext-B5Bd3rJ6.js} +0 -0
  613. /package/dist/assets/{wit-DlUr23eQ.js → wit-CK_K8sxN.js} +0 -0
  614. /package/dist/assets/{wolfram-BunKvAKE.js → wolfram-O7u88fnu.js} +0 -0
  615. /package/dist/assets/{xquery-CNzoFgd7.js → xquery-BHRymSKf.js} +0 -0
  616. /package/dist/assets/{yacas-BsmlDKac.js → yacas-B2Ltfl3H.js} +0 -0
  617. /package/dist/assets/{z80-Bnez4vZ_.js → z80-DJxBw9IF.js} +0 -0
  618. /package/dist/assets/{zenscript-NGWkhbj8.js → zenscript-B7bdmrQw.js} +0 -0
  619. /package/dist/assets/{zig-B-X7Vv3F.js → zig-CcTUrp-O.js} +0 -0
@@ -32268,7 +32268,7 @@ ZodSymbol.create;
32268
32268
  ZodUndefined.create;
32269
32269
  ZodNull.create;
32270
32270
  ZodAny.create;
32271
- ZodUnknown.create;
32271
+ var unknownType = ZodUnknown.create;
32272
32272
  ZodNever.create;
32273
32273
  ZodVoid.create;
32274
32274
  var arrayType = ZodArray.create;
@@ -32311,7 +32311,11 @@ var LocalModelDownloadStatusSchema = enumType([
32311
32311
  var TranslationDownloadFilePlanSchema = objectType({
32312
32312
  path: stringType().min(1),
32313
32313
  sizeBytes: numberType().int().nonnegative().optional(),
32314
- required: booleanType()
32314
+ required: booleanType(),
32315
+ etag: stringType().min(1).optional(),
32316
+ revision: stringType().min(1).optional(),
32317
+ sourceUrl: stringType().min(1).optional(),
32318
+ raw: unknownType().optional()
32315
32319
  });
32316
32320
  var TranslationDownloadGroupPlanSchema = objectType({
32317
32321
  id: stringType().min(1),
@@ -32320,14 +32324,97 @@ var TranslationDownloadGroupPlanSchema = objectType({
32320
32324
  profile: stringType().min(1).optional(),
32321
32325
  dtype: stringType().min(1).optional(),
32322
32326
  estimatedTotalBytes: numberType().int().nonnegative().optional(),
32327
+ baseGroupId: stringType().min(1).optional(),
32328
+ commitHash: stringType().min(1).optional(),
32329
+ shortCommitHash: stringType().min(1).optional(),
32330
+ rootDir: stringType().min(1).optional(),
32331
+ status: LocalModelDownloadStatusSchema.optional(),
32332
+ progress: numberType().min(0).max(1).optional(),
32333
+ bytesDownloaded: numberType().int().nonnegative().optional(),
32334
+ totalBytes: numberType().int().nonnegative().optional(),
32335
+ resumable: booleanType().optional(),
32336
+ error: stringType().optional(),
32323
32337
  selectable: booleanType(),
32324
32338
  selected: booleanType(),
32325
32339
  files: arrayType(TranslationDownloadFilePlanSchema)
32326
32340
  });
32341
+ var LocalModelProfileStatusSchema = enumType([
32342
+ "idle",
32343
+ "loading",
32344
+ "ready",
32345
+ "error"
32346
+ ]);
32347
+ var LocalModelProfileManifestFileSchema = objectType({
32348
+ path: stringType().min(1),
32349
+ sizeBytes: numberType().int().nonnegative().optional(),
32350
+ required: booleanType(),
32351
+ etag: stringType().min(1).optional(),
32352
+ revision: stringType().min(1).optional(),
32353
+ sourceUrl: stringType().min(1).optional(),
32354
+ raw: unknownType().optional()
32355
+ });
32356
+ var LocalModelProfileManifestGroupSchema = objectType({
32357
+ id: stringType().min(1),
32358
+ baseGroupId: stringType().min(1),
32359
+ label: stringType().min(1),
32360
+ displayLabel: stringType().min(1),
32361
+ description: stringType().optional(),
32362
+ profile: stringType().min(1).optional(),
32363
+ dtype: stringType().min(1).optional(),
32364
+ commitHash: stringType().min(1),
32365
+ shortCommitHash: stringType().min(1),
32366
+ rootDir: stringType().min(1),
32367
+ estimatedTotalBytes: numberType().int().nonnegative().optional(),
32368
+ selectable: booleanType(),
32369
+ files: arrayType(LocalModelProfileManifestFileSchema)
32370
+ });
32371
+ var LocalModelProfileManifestSchema = objectType({
32372
+ modelId: stringType().min(1),
32373
+ source: literalType("huggingface"),
32374
+ endpoint: stringType().default(""),
32375
+ revision: stringType().min(1),
32376
+ commitHash: stringType().min(1),
32377
+ shortCommitHash: stringType().min(1),
32378
+ fetchedAt: numberType().int().nonnegative(),
32379
+ updatedAt: numberType().int().nonnegative(),
32380
+ raw: unknownType().optional(),
32381
+ groups: recordType(stringType(), LocalModelProfileManifestGroupSchema).default({}),
32382
+ groupOrder: arrayType(stringType().min(1)).default([])
32383
+ });
32384
+ var LocalModelLifecycleFileStateSchema = objectType({
32385
+ path: stringType().min(1),
32386
+ sizeBytes: numberType().int().nonnegative().optional(),
32387
+ downloadedBytes: numberType().int().nonnegative().optional(),
32388
+ required: booleanType().default(true),
32389
+ status: LocalModelDownloadStatusSchema.default("not-downloaded"),
32390
+ updatedAt: numberType().int().nonnegative().optional(),
32391
+ error: stringType().optional()
32392
+ });
32393
+ var LocalModelLifecycleGroupStateSchema = objectType({
32394
+ groupId: stringType().min(1),
32395
+ baseGroupId: stringType().min(1).optional(),
32396
+ status: LocalModelDownloadStatusSchema.default("not-downloaded"),
32397
+ rootDir: stringType().min(1).optional(),
32398
+ bytesDownloaded: numberType().int().nonnegative().optional(),
32399
+ totalBytes: numberType().int().nonnegative().optional(),
32400
+ progress: numberType().min(0).max(1).optional(),
32401
+ resumable: booleanType().default(false),
32402
+ error: stringType().optional(),
32403
+ installedAt: numberType().int().nonnegative().optional(),
32404
+ updatedAt: numberType().int().nonnegative().optional(),
32405
+ files: arrayType(LocalModelLifecycleFileStateSchema).default([])
32406
+ });
32407
+ var LocalModelProfileLoadStateSchema = objectType({
32408
+ status: LocalModelProfileStatusSchema.default("idle"),
32409
+ message: stringType().optional(),
32410
+ error: stringType().optional(),
32411
+ updatedAt: numberType().int().nonnegative().optional()
32412
+ });
32327
32413
  objectType({
32328
32414
  engineId: literalType("local"),
32329
32415
  modelId: stringType().min(1),
32330
32416
  selectedGroupId: stringType().min(1).optional(),
32417
+ groupId: stringType().min(1).optional(),
32331
32418
  status: LocalModelDownloadStatusSchema,
32332
32419
  message: stringType(),
32333
32420
  progress: numberType().min(0).max(1).optional(),
@@ -32352,8 +32439,10 @@ var LocalModelAssetPlanSnapshotSchema = objectType({
32352
32439
  });
32353
32440
  objectType({
32354
32441
  modelId: stringType().min(1),
32442
+ version: literalType(2).default(2),
32355
32443
  status: LocalModelDownloadStatusSchema.default("not-downloaded"),
32356
32444
  selected: booleanType().default(false),
32445
+ selectedGroupId: stringType().min(1).optional(),
32357
32446
  installedAt: numberType().int().nonnegative().optional(),
32358
32447
  updatedAt: numberType().int().nonnegative().optional(),
32359
32448
  bytesDownloaded: numberType().int().nonnegative().optional(),
@@ -32361,6 +32450,9 @@ objectType({
32361
32450
  progress: numberType().min(0).max(1).optional(),
32362
32451
  resumable: booleanType().default(false),
32363
32452
  error: stringType().optional(),
32453
+ profileLoad: LocalModelProfileLoadStateSchema.default(LocalModelProfileLoadStateSchema.parse({})),
32454
+ profileManifest: LocalModelProfileManifestSchema.optional(),
32455
+ groupsState: recordType(stringType(), LocalModelLifecycleGroupStateSchema).default({}),
32364
32456
  plan: LocalModelAssetPlanSnapshotSchema.optional(),
32365
32457
  files: arrayType(objectType({
32366
32458
  path: stringType().min(1),
@@ -42699,6 +42791,12 @@ function useConfigSubscription() {
42699
42791
  onError: callbacks.onError
42700
42792
  }), getConfig$1, [], "config.subscribe");
42701
42793
  }
42794
+ function useGlobalSettingsSubscription() {
42795
+ return useSubscription((callbacks) => trpcClient.globalSettings.subscribe.subscribe(void 0, {
42796
+ onData: callbacks.onData,
42797
+ onError: callbacks.onError
42798
+ }), void 0, [], "globalSettings.subscribe");
42799
+ }
42702
42800
  //#endregion
42703
42801
  //#region src/lib/use-opsx.ts
42704
42802
  function getOpsxStatusSubscriptionCacheKey(input) {
@@ -43947,6 +44045,23 @@ var Copy = createLucideIcon("Copy", [["rect", {
43947
44045
  d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",
43948
44046
  key: "zix9uf"
43949
44047
  }]]);
44048
+ var Download = createLucideIcon("Download", [
44049
+ ["path", {
44050
+ d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",
44051
+ key: "ih7n3h"
44052
+ }],
44053
+ ["polyline", {
44054
+ points: "7 10 12 15 17 10",
44055
+ key: "2ggqvy"
44056
+ }],
44057
+ ["line", {
44058
+ x1: "12",
44059
+ x2: "12",
44060
+ y1: "15",
44061
+ y2: "3",
44062
+ key: "1vk2je"
44063
+ }]
44064
+ ]);
43950
44065
  var EllipsisVertical = createLucideIcon("EllipsisVertical", [
43951
44066
  ["circle", {
43952
44067
  cx: "12",
@@ -43967,6 +44082,33 @@ var EllipsisVertical = createLucideIcon("EllipsisVertical", [
43967
44082
  key: "lyex9k"
43968
44083
  }]
43969
44084
  ]);
44085
+ var Expand = createLucideIcon("Expand", [
44086
+ ["path", {
44087
+ d: "m21 21-6-6m6 6v-4.8m0 4.8h-4.8",
44088
+ key: "1c15vz"
44089
+ }],
44090
+ ["path", {
44091
+ d: "M3 16.2V21m0 0h4.8M3 21l6-6",
44092
+ key: "1fsnz2"
44093
+ }],
44094
+ ["path", {
44095
+ d: "M21 7.8V3m0 0h-4.8M21 3l-6 6",
44096
+ key: "hawz9i"
44097
+ }],
44098
+ ["path", {
44099
+ d: "M3 7.8V3m0 0h4.8M3 3l6 6",
44100
+ key: "u9ee12"
44101
+ }]
44102
+ ]);
44103
+ var Eye = createLucideIcon("Eye", [["path", {
44104
+ d: "M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0",
44105
+ key: "1nclc0"
44106
+ }], ["circle", {
44107
+ cx: "12",
44108
+ cy: "12",
44109
+ r: "3",
44110
+ key: "1v7zrd"
44111
+ }]]);
43970
44112
  var FileCode2 = createLucideIcon("FileCode2", [
43971
44113
  ["path", {
43972
44114
  d: "M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4",
@@ -43985,6 +44127,20 @@ var FileCode2 = createLucideIcon("FileCode2", [
43985
44127
  key: "112psh"
43986
44128
  }]
43987
44129
  ]);
44130
+ var FilePenLine = createLucideIcon("FilePenLine", [
44131
+ ["path", {
44132
+ d: "m18 5-2.414-2.414A2 2 0 0 0 14.172 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2",
44133
+ key: "142zxg"
44134
+ }],
44135
+ ["path", {
44136
+ d: "M21.378 12.626a1 1 0 0 0-3.004-3.004l-4.01 4.012a2 2 0 0 0-.506.854l-.837 2.87a.5.5 0 0 0 .62.62l2.87-.837a2 2 0 0 0 .854-.506z",
44137
+ key: "2t3380"
44138
+ }],
44139
+ ["path", {
44140
+ d: "M8 18h1",
44141
+ key: "13wk12"
44142
+ }]
44143
+ ]);
43988
44144
  var FilePlus = createLucideIcon("FilePlus", [
43989
44145
  ["path", {
43990
44146
  d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z",
@@ -44333,6 +44489,24 @@ var Menu = createLucideIcon("Menu", [
44333
44489
  key: "yk5zj1"
44334
44490
  }]
44335
44491
  ]);
44492
+ var Minimize = createLucideIcon("Minimize", [
44493
+ ["path", {
44494
+ d: "M8 3v3a2 2 0 0 1-2 2H3",
44495
+ key: "hohbtr"
44496
+ }],
44497
+ ["path", {
44498
+ d: "M21 8h-3a2 2 0 0 1-2-2V3",
44499
+ key: "5jw1f3"
44500
+ }],
44501
+ ["path", {
44502
+ d: "M3 16h3a2 2 0 0 1 2 2v3",
44503
+ key: "198tvr"
44504
+ }],
44505
+ ["path", {
44506
+ d: "M16 21v-3a2 2 0 0 1 2-2h3",
44507
+ key: "ph8mxp"
44508
+ }]
44509
+ ]);
44336
44510
  var Minus = createLucideIcon("Minus", [["path", {
44337
44511
  d: "M5 12h14",
44338
44512
  key: "1ays0h"
@@ -44466,6 +44640,24 @@ var Save = createLucideIcon("Save", [
44466
44640
  key: "t51u73"
44467
44641
  }]
44468
44642
  ]);
44643
+ var ScrollText = createLucideIcon("ScrollText", [
44644
+ ["path", {
44645
+ d: "M15 12h-5",
44646
+ key: "r7krc0"
44647
+ }],
44648
+ ["path", {
44649
+ d: "M15 8h-5",
44650
+ key: "1khuty"
44651
+ }],
44652
+ ["path", {
44653
+ d: "M19 17V5a2 2 0 0 0-2-2H4",
44654
+ key: "zz82l3"
44655
+ }],
44656
+ ["path", {
44657
+ d: "M8 21h12a2 2 0 0 0 2-2v-1a1 1 0 0 0-1-1H11a1 1 0 0 0-1 1v1a2 2 0 1 1-4 0V5a2 2 0 1 0-4 0v2a1 1 0 0 0 1 1h3",
44658
+ key: "1ph1d7"
44659
+ }]
44660
+ ]);
44469
44661
  var Search = createLucideIcon("Search", [["circle", {
44470
44662
  cx: "11",
44471
44663
  cy: "11",
@@ -44484,6 +44676,40 @@ var Settings = createLucideIcon("Settings", [["path", {
44484
44676
  r: "3",
44485
44677
  key: "1v7zrd"
44486
44678
  }]]);
44679
+ var Share2 = createLucideIcon("Share2", [
44680
+ ["circle", {
44681
+ cx: "18",
44682
+ cy: "5",
44683
+ r: "3",
44684
+ key: "gq8acd"
44685
+ }],
44686
+ ["circle", {
44687
+ cx: "6",
44688
+ cy: "12",
44689
+ r: "3",
44690
+ key: "w7nqdw"
44691
+ }],
44692
+ ["circle", {
44693
+ cx: "18",
44694
+ cy: "19",
44695
+ r: "3",
44696
+ key: "1xt0gg"
44697
+ }],
44698
+ ["line", {
44699
+ x1: "8.59",
44700
+ x2: "15.42",
44701
+ y1: "13.51",
44702
+ y2: "17.49",
44703
+ key: "47mynk"
44704
+ }],
44705
+ ["line", {
44706
+ x1: "15.41",
44707
+ x2: "8.59",
44708
+ y1: "6.51",
44709
+ y2: "10.49",
44710
+ key: "1n3mei"
44711
+ }]
44712
+ ]);
44487
44713
  var ShieldCheck = createLucideIcon("ShieldCheck", [["path", {
44488
44714
  d: "M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",
44489
44715
  key: "oel41y"
@@ -44689,6 +44915,13 @@ var TriangleAlert = createLucideIcon("TriangleAlert", [
44689
44915
  key: "p32p05"
44690
44916
  }]
44691
44917
  ]);
44918
+ var Undo2 = createLucideIcon("Undo2", [["path", {
44919
+ d: "M9 14 4 9l5-5",
44920
+ key: "102s5s"
44921
+ }], ["path", {
44922
+ d: "M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11",
44923
+ key: "f3b9sd"
44924
+ }]]);
44692
44925
  var Unlink2 = createLucideIcon("Unlink2", [["path", {
44693
44926
  d: "M15 7h2a5 5 0 0 1 0 10h-2m-6 0H7A5 5 0 0 1 7 7h2",
44694
44927
  key: "1re2ne"
@@ -55059,8 +55292,12 @@ function inertValue(value) {
55059
55292
  //#region src/components/tooltip.tsx
55060
55293
  function Tooltip({ content, children, delay = 180, sideOffset = 8, className }) {
55061
55294
  if (!content) return children;
55295
+ const trigger = typeof children.props === "object" && children.props !== null && "disabled" in children.props && Boolean(children.props.disabled) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
55296
+ className: "inline-flex max-w-full",
55297
+ children
55298
+ }) : children;
55062
55299
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TooltipRoot, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TooltipTrigger, {
55063
- render: children,
55300
+ render: trigger,
55064
55301
  delay
55065
55302
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TooltipPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TooltipPositioner, {
55066
55303
  sideOffset,
@@ -96471,6 +96708,77 @@ function OpsxDetailStatePanel({ message, tone = "default" }) {
96471
96708
  });
96472
96709
  }
96473
96710
  //#endregion
96711
+ //#region src/components/button.tsx
96712
+ var variantClassNames = {
96713
+ primary: "bg-primary text-primary-foreground hover:bg-primary/90",
96714
+ secondary: "border-border bg-background text-foreground border hover:bg-muted",
96715
+ ghost: "text-foreground hover:bg-muted",
96716
+ destructive: "bg-red-600 text-white hover:bg-red-700 focus-visible:ring-red-500 dark:bg-red-600 dark:hover:bg-red-700"
96717
+ };
96718
+ var activityVariantClassNames = {
96719
+ primary: "bg-primary/10 text-primary hover:bg-primary/10",
96720
+ secondary: "border-primary/40 bg-primary/10 text-primary border hover:bg-primary/10",
96721
+ ghost: "bg-primary/10 text-primary hover:bg-primary/10",
96722
+ destructive: "bg-red-600/10 text-red-600 hover:bg-red-600/10 dark:text-red-400"
96723
+ };
96724
+ var sizeClassNames = {
96725
+ sm: "gap-1.5 rounded-md px-3 py-1.5 text-xs",
96726
+ md: "gap-2 rounded-md px-4 py-2 text-sm",
96727
+ "icon-sm": "h-7 w-7 rounded-md p-0",
96728
+ "icon-md": "h-9 w-9 rounded-md p-0"
96729
+ };
96730
+ var Button = (0, import_react.forwardRef)(function Button({ variant = "primary", size = "md", activity = false, disabled = false, type = "button", className, onClick, "aria-disabled": ariaDisabled, ...props }, ref) {
96731
+ const handleClick = (event) => {
96732
+ if (activity) {
96733
+ event.preventDefault();
96734
+ event.stopPropagation();
96735
+ return;
96736
+ }
96737
+ onClick?.(event);
96738
+ };
96739
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
96740
+ ref,
96741
+ type,
96742
+ disabled,
96743
+ "aria-disabled": ariaDisabled ?? (activity ? true : void 0),
96744
+ "data-activity": activity ? "true" : void 0,
96745
+ onClick: handleClick,
96746
+ className: cn$1("inline-flex shrink-0 items-center justify-center font-medium outline-none transition-colors", "focus-visible:ring-primary focus-visible:ring-1", disabled ? "cursor-not-allowed opacity-50" : activity ? "cursor-default" : "cursor-pointer", activity ? activityVariantClassNames[variant] : variantClassNames[variant], sizeClassNames[size], className),
96747
+ ...props
96748
+ });
96749
+ });
96750
+ //#endregion
96751
+ //#region src/components/button-group.tsx
96752
+ /**
96753
+ * Compact segmented buttons with single-select behavior.
96754
+ */
96755
+ function ButtonGroup({ value, options, onChange, className = "", tone = "default", presentation = "label" }) {
96756
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
96757
+ className: `inline-flex w-fit max-w-full shrink-0 self-start overflow-hidden rounded-md border ${tone === "terminal" ? "border-terminal-foreground/25 bg-terminal/70 text-terminal-foreground" : "border-border bg-card"} ${className}`,
96758
+ children: options.map((option, index) => {
96759
+ const active = option.value === value;
96760
+ const stateClassName = active ? "bg-primary text-primary-foreground" : tone === "terminal" ? "text-terminal-foreground/72 hover:bg-terminal-foreground/10 hover:text-terminal-foreground" : "text-muted-foreground hover:bg-muted/60 hover:text-foreground";
96761
+ const accessibleLabel = option.ariaLabel ?? (typeof option.label === "string" ? option.label : void 0);
96762
+ const tooltipContent = option.tooltip ?? accessibleLabel;
96763
+ const content = presentation === "icon-only" ? option.icon ?? option.label : presentation === "icon-label" && option.icon ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [option.icon, /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: option.label })] }) : option.label;
96764
+ const button = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
96765
+ type: "button",
96766
+ disabled: option.disabled,
96767
+ onClick: () => onChange(option.value),
96768
+ "aria-pressed": active,
96769
+ "aria-label": presentation === "icon-only" ? accessibleLabel : void 0,
96770
+ title: presentation === "icon-only" && typeof accessibleLabel === "string" ? accessibleLabel : void 0,
96771
+ className: `inline-flex items-center justify-center gap-1.5 text-xs font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50 ${presentation === "icon-only" ? "h-8 w-8 p-0" : "px-3 py-1.5"} ${index > 0 ? tone === "terminal" ? "border-terminal-foreground/20 border-l" : "border-border border-l" : ""} ${stateClassName}`,
96772
+ children: content
96773
+ }, option.value);
96774
+ return tooltipContent ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Tooltip, {
96775
+ content: tooltipContent,
96776
+ children: button
96777
+ }, option.value) : button;
96778
+ })
96779
+ });
96780
+ }
96781
+ //#endregion
96474
96782
  //#region src/lib/codemirror-markdown-preview.ts
96475
96783
  /**
96476
96784
  * CodeMirror 6 Markdown Live Preview Extension
@@ -113479,11 +113787,16 @@ ReactCodeMirror.displayName = "CodeMirror";
113479
113787
  * - Markdown 文件支持实时预览(隐藏语法标记)
113480
113788
  * - 移动端友好
113481
113789
  */
113482
- /** 根据文件名推断语言类型 */
113483
- function detectLanguage(filename) {
113790
+ function isMarkdownFilename(filename) {
113791
+ if (!filename) return false;
113792
+ const lower = filename.toLowerCase();
113793
+ return lower.endsWith(".md") || lower.endsWith(".markdown") || lower.endsWith(".mdown") || lower.endsWith(".mkd");
113794
+ }
113795
+ /** 根据文件名推断常见语言类型 */
113796
+ function detectBuiltinLanguage(filename) {
113484
113797
  if (!filename) return "plain";
113485
113798
  const lower = filename.toLowerCase();
113486
- if (lower.endsWith(".md")) return "markdown";
113799
+ if (isMarkdownFilename(lower)) return "markdown";
113487
113800
  if (lower.endsWith(".ts") || lower.endsWith(".tsx")) return "typescript";
113488
113801
  if (lower.endsWith(".js") || lower.endsWith(".jsx")) return "javascript";
113489
113802
  if (lower.endsWith(".json")) return "json";
@@ -113491,7 +113804,7 @@ function detectLanguage(filename) {
113491
113804
  return "plain";
113492
113805
  }
113493
113806
  /** 根据语言类型返回 CodeMirror 扩展 */
113494
- function getLanguageExtensions(language, filename) {
113807
+ function getBuiltinLanguageExtensions(language, filename) {
113495
113808
  switch (language) {
113496
113809
  case "markdown": return [markdown({
113497
113810
  base: markdownLanguage,
@@ -113507,6 +113820,10 @@ function getLanguageExtensions(language, filename) {
113507
113820
  default: return [];
113508
113821
  }
113509
113822
  }
113823
+ function matchFilenameLanguage(filename) {
113824
+ if (!filename) return null;
113825
+ return LanguageDescription.matchFilename(languages, filename);
113826
+ }
113510
113827
  function resolveBundleTheme(theme, isDarkMode) {
113511
113828
  switch (theme) {
113512
113829
  case "github": return isDarkMode ? githubDark : githubLight;
@@ -113530,13 +113847,53 @@ function resolveBundleTheme(theme, isDarkMode) {
113530
113847
  * // 可编辑的代码编辑器
113531
113848
  * <CodeEditor value={code} onChange={setCode} language="typescript" />
113532
113849
  */
113533
- function CodeEditor({ value, onChange, readOnly = false, language, filename, lineNumbers = true, lineWrapping = true, fontSize = 13, className = "", style, placeholder, editorMinHeight = "240px" }) {
113534
- const resolvedLanguage = language ?? detectLanguage(filename);
113850
+ function CodeEditor({ value, onChange, onSaveShortcut, readOnly = false, language, filename, lineNumbers = true, lineWrapping = true, fontSize = 13, className = "", style, placeholder, editorMinHeight = "240px" }) {
113535
113851
  const isDarkMode = useDarkMode();
113536
113852
  const { data: config } = useConfigSubscription();
113537
113853
  const codeEditorTheme = config?.codeEditor?.theme ?? "github";
113854
+ const [filenameLanguageExtensions, setFilenameLanguageExtensions] = (0, import_react.useState)([]);
113855
+ (0, import_react.useEffect)(() => {
113856
+ let cancelled = false;
113857
+ if (language) {
113858
+ setFilenameLanguageExtensions([]);
113859
+ return;
113860
+ }
113861
+ const builtinLanguage = detectBuiltinLanguage(filename);
113862
+ if (builtinLanguage !== "plain") {
113863
+ setFilenameLanguageExtensions(getBuiltinLanguageExtensions(builtinLanguage, filename));
113864
+ return;
113865
+ }
113866
+ const matchedLanguage = matchFilenameLanguage(filename);
113867
+ if (!matchedLanguage) {
113868
+ setFilenameLanguageExtensions([]);
113869
+ return;
113870
+ }
113871
+ if (matchedLanguage.support) {
113872
+ setFilenameLanguageExtensions([matchedLanguage.support.extension]);
113873
+ return;
113874
+ }
113875
+ setFilenameLanguageExtensions([]);
113876
+ matchedLanguage.load().then((support) => {
113877
+ if (cancelled) return;
113878
+ setFilenameLanguageExtensions([support.extension]);
113879
+ }).catch(() => {
113880
+ if (cancelled) return;
113881
+ setFilenameLanguageExtensions([]);
113882
+ });
113883
+ return () => {
113884
+ cancelled = true;
113885
+ };
113886
+ }, [language, filename]);
113887
+ const languageExtensions = (0, import_react.useMemo)(() => {
113888
+ if (!language) return filenameLanguageExtensions;
113889
+ return getBuiltinLanguageExtensions(language, filename);
113890
+ }, [
113891
+ language,
113892
+ filename,
113893
+ filenameLanguageExtensions
113894
+ ]);
113538
113895
  const extensions = (0, import_react.useMemo)(() => {
113539
- const exts = [EditorState.readOnly.of(readOnly), ...getLanguageExtensions(resolvedLanguage, filename)];
113896
+ const exts = [EditorState.readOnly.of(readOnly), ...languageExtensions];
113540
113897
  exts.push(resolveBundleTheme(codeEditorTheme, isDarkMode));
113541
113898
  exts.push(EditorView.theme({
113542
113899
  ".cm-line": { lineHeight: "21px" },
@@ -113561,16 +113918,24 @@ function CodeEditor({ value, onChange, readOnly = false, language, filename, lin
113561
113918
  exts.push(keymap.of([{
113562
113919
  key: "Mod-a",
113563
113920
  run: selectAll
113921
+ }, {
113922
+ key: "Mod-s",
113923
+ preventDefault: true,
113924
+ run: () => {
113925
+ if (readOnly || !onSaveShortcut) return false;
113926
+ onSaveShortcut();
113927
+ return true;
113928
+ }
113564
113929
  }]));
113565
113930
  if (lineWrapping) exts.push(EditorView.lineWrapping);
113566
113931
  return exts;
113567
113932
  }, [
113568
- resolvedLanguage,
113569
- filename,
113933
+ languageExtensions,
113570
113934
  readOnly,
113571
113935
  lineWrapping,
113572
113936
  codeEditorTheme,
113573
- isDarkMode
113937
+ isDarkMode,
113938
+ onSaveShortcut
113574
113939
  ]);
113575
113940
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ReactCodeMirror, {
113576
113941
  value,
@@ -113828,6 +114193,7 @@ var layoutStyles = String.raw`
113828
114193
  display: flex;
113829
114194
  flex-direction: column;
113830
114195
  height: 100%;
114196
+ min-height: 0;
113831
114197
  gap: 0.75rem;
113832
114198
  }
113833
114199
  .fev-sidebar-tabs {
@@ -113835,6 +114201,7 @@ var layoutStyles = String.raw`
113835
114201
  }
113836
114202
  .fev-sidebar-tree {
113837
114203
  display: none;
114204
+ min-height: 0;
113838
114205
  }
113839
114206
  .fev-editor-wrapper {
113840
114207
  display: flex;
@@ -113848,8 +114215,10 @@ var layoutStyles = String.raw`
113848
114215
  .fev-layout {
113849
114216
  display: grid;
113850
114217
  grid-template-columns: minmax(0, 1fr) minmax(240px, clamp(240px, 30%, 420px));
114218
+ grid-template-rows: minmax(0, 1fr);
113851
114219
  gap: 1rem;
113852
114220
  min-height: 0;
114221
+ overflow: hidden;
113853
114222
  }
113854
114223
  .fev-sidebar-tabs {
113855
114224
  display: none;
@@ -113857,9 +114226,13 @@ var layoutStyles = String.raw`
113857
114226
  .fev-sidebar-tree {
113858
114227
  display: block;
113859
114228
  order: 2;
114229
+ height: 100%;
114230
+ min-height: 0;
114231
+ overflow: hidden;
113860
114232
  }
113861
114233
  .fev-editor-wrapper {
113862
114234
  order: 1;
114235
+ min-height: 0;
113863
114236
  }
113864
114237
  }
113865
114238
  .CodeMirror {
@@ -114037,7 +114410,8 @@ function FileTree({ entries, selectedPath, onSelect, headerLabel, headerActions,
114037
114410
  const closeMenu = () => setMenuState(null);
114038
114411
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ContextMenuWrapper, {
114039
114412
  ref: wrapperRef,
114040
- className: "border-border bg-muted/30 flex h-full flex-col rounded-md border",
114413
+ className: "border-border bg-muted/30 flex h-full min-h-0 flex-col rounded-md border",
114414
+ "data-file-explorer-tree": "",
114041
114415
  children: [
114042
114416
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
114043
114417
  className: "border-border/50 text-muted-foreground flex items-center justify-between border-b px-3 py-2 text-xs font-medium",
@@ -114047,7 +114421,8 @@ function FileTree({ entries, selectedPath, onSelect, headerLabel, headerActions,
114047
114421
  }), headerActions]
114048
114422
  }),
114049
114423
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
114050
- className: "scrollbar-thin scrollbar-track-transparent flex-1 overflow-y-auto",
114424
+ "data-file-explorer-tree-scroll": "",
114425
+ className: "scrollbar-thin scrollbar-track-transparent min-h-0 flex-1 overflow-y-auto",
114051
114426
  children: entries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
114052
114427
  className: "text-muted-foreground px-3 py-2 text-xs",
114053
114428
  children: "No files yet."
@@ -114114,7 +114489,7 @@ function FileExplorer({ entries, selectedPath, onSelect, breadcrumbRoot, headerL
114114
114489
  return sortedEntries.find((entry) => entry.path === selectedPath && entry.type === "file") ?? null;
114115
114490
  }, [sortedEntries, selectedPath]);
114116
114491
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
114117
- className: "@container-[size] h-full",
114492
+ className: "@container-[size] h-full min-h-0 overflow-hidden",
114118
114493
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: layoutStyles }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
114119
114494
  className: "fev-layout",
114120
114495
  children: [
@@ -114154,7 +114529,7 @@ function FileExplorer({ entries, selectedPath, onSelect, breadcrumbRoot, headerL
114154
114529
  })]
114155
114530
  });
114156
114531
  }
114157
- function FileExplorerCodeEditor({ file, value, readOnly = true, onChange, lineWrapping, editorMinHeight }) {
114532
+ function FileExplorerCodeEditor({ file, value, readOnly = true, onChange, onSaveShortcut, lineWrapping, editorMinHeight }) {
114158
114533
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CodeEditor, {
114159
114534
  value,
114160
114535
  filename: file.path,
@@ -114162,209 +114537,11 @@ function FileExplorerCodeEditor({ file, value, readOnly = true, onChange, lineWr
114162
114537
  lineWrapping,
114163
114538
  className: "min-h-0 flex-1",
114164
114539
  editorMinHeight,
114165
- onChange
114540
+ onChange,
114541
+ onSaveShortcut
114166
114542
  }, file.path);
114167
114543
  }
114168
114544
  //#endregion
114169
- //#region src/components/scroll-spy.ts
114170
- function hasVerticalScrollBehavior(overflowY) {
114171
- return overflowY === "auto" || overflowY === "scroll" || overflowY === "overlay";
114172
- }
114173
- function findVerticalScrollContainer(node, options = {}) {
114174
- const { allowNonScrollable = false } = options;
114175
- let current = node?.parentElement ?? null;
114176
- while (current) {
114177
- if (hasVerticalScrollBehavior(window.getComputedStyle(current).overflowY)) {
114178
- if (allowNonScrollable || current.scrollHeight > current.clientHeight) return current;
114179
- }
114180
- current = current.parentElement;
114181
- }
114182
- return null;
114183
- }
114184
- function scrollViewportBounds(root) {
114185
- if (root) {
114186
- const rect = root.getBoundingClientRect();
114187
- return {
114188
- top: rect.top,
114189
- bottom: rect.bottom
114190
- };
114191
- }
114192
- return {
114193
- top: 0,
114194
- bottom: window.innerHeight
114195
- };
114196
- }
114197
- function measureAvailableViewportHeight(node, root = findVerticalScrollContainer(node, { allowNonScrollable: true })) {
114198
- if (typeof window === "undefined" || !node) return null;
114199
- const nodeRect = node.getBoundingClientRect();
114200
- const viewport = scrollViewportBounds(root);
114201
- return Math.max(Math.floor(viewport.bottom - Math.max(nodeRect.top, viewport.top)), 0);
114202
- }
114203
- function useViewportConstrainedHeight({ target, enabled = true }) {
114204
- const [height, setHeight] = (0, import_react.useState)(null);
114205
- (0, import_react.useLayoutEffect)(() => {
114206
- if (!enabled || typeof window === "undefined") {
114207
- setHeight(null);
114208
- return;
114209
- }
114210
- if (!target) {
114211
- setHeight(null);
114212
- return;
114213
- }
114214
- let resizeObserver = null;
114215
- let scrollRoot = null;
114216
- let scrollTarget = window;
114217
- const setConstrainedHeight = (nextHeight) => {
114218
- setHeight((currentHeight) => currentHeight === nextHeight ? currentHeight : nextHeight);
114219
- };
114220
- const bindScrollRoot = (nextRoot) => {
114221
- if (scrollRoot === nextRoot) return;
114222
- scrollTarget.removeEventListener("scroll", handleUpdate);
114223
- if (resizeObserver && scrollRoot) resizeObserver.unobserve(scrollRoot);
114224
- scrollRoot = nextRoot;
114225
- scrollTarget = nextRoot ?? window;
114226
- scrollTarget.addEventListener("scroll", handleUpdate, { passive: true });
114227
- if (resizeObserver && scrollRoot) resizeObserver.observe(scrollRoot);
114228
- };
114229
- const handleUpdate = () => {
114230
- const nextRoot = findVerticalScrollContainer(target, { allowNonScrollable: true });
114231
- bindScrollRoot(nextRoot);
114232
- setConstrainedHeight(measureAvailableViewportHeight(target, nextRoot));
114233
- };
114234
- if (typeof ResizeObserver !== "undefined") {
114235
- resizeObserver = new ResizeObserver(() => {
114236
- handleUpdate();
114237
- });
114238
- resizeObserver.observe(target);
114239
- if (target.parentElement) resizeObserver.observe(target.parentElement);
114240
- }
114241
- handleUpdate();
114242
- window.addEventListener("resize", handleUpdate);
114243
- return () => {
114244
- window.removeEventListener("resize", handleUpdate);
114245
- scrollTarget.removeEventListener("scroll", handleUpdate);
114246
- resizeObserver?.disconnect();
114247
- };
114248
- }, [enabled, target]);
114249
- return height;
114250
- }
114251
- //#endregion
114252
- //#region src/components/folder-editor-viewer.tsx
114253
- function FolderEditorViewer({ changeId, archived = false, files: providedFiles }) {
114254
- const { data: files, isLoading, error } = archived ? useArchiveFilesSubscription(changeId) : useChangeFilesSubscription(changeId);
114255
- const [selectedPath, setSelectedPath] = (0, import_react.useState)(null);
114256
- const [viewportNode, setViewportNode] = (0, import_react.useState)(null);
114257
- const viewportHeight = useViewportConstrainedHeight({
114258
- target: viewportNode,
114259
- enabled: viewportNode !== null
114260
- });
114261
- const sortedEntries = (0, import_react.useMemo)(() => {
114262
- if (providedFiles) return [...providedFiles];
114263
- if (!files) return [];
114264
- return [...files];
114265
- }, [files, providedFiles]);
114266
- (0, import_react.useEffect)(() => {
114267
- if (!sortedEntries.length) {
114268
- setSelectedPath(null);
114269
- return;
114270
- }
114271
- if (!sortedEntries.find((entry) => entry.path === selectedPath && entry.type === "file")) setSelectedPath(sortedEntries.find((entry) => entry.type === "file")?.path ?? null);
114272
- }, [sortedEntries, selectedPath]);
114273
- if (!providedFiles && isLoading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
114274
- className: "border-border bg-muted/20 flex h-[400px] items-center justify-center rounded-md border",
114275
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoaderCircle, { className: "text-muted-foreground h-6 w-6 animate-spin" })
114276
- });
114277
- if (error) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
114278
- className: "border-destructive/50 bg-destructive/10 text-destructive rounded-md border p-4 text-sm",
114279
- children: ["Failed to load files: ", error.message]
114280
- });
114281
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("section", {
114282
- "data-tab-scroll-root": "true",
114283
- className: "scrollbar-thin scrollbar-track-transparent min-h-0 flex-1 overflow-auto",
114284
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
114285
- className: "pr-1",
114286
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
114287
- ref: setViewportNode,
114288
- className: "flex min-h-0 flex-col",
114289
- style: viewportHeight != null ? { height: `${viewportHeight}px` } : void 0,
114290
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileExplorer, {
114291
- entries: sortedEntries,
114292
- selectedPath,
114293
- onSelect: setSelectedPath,
114294
- emptyState: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "No files found for this change." }),
114295
- renderEditor: (activeFile) => activeFile ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileExplorerCodeEditor, {
114296
- file: activeFile,
114297
- value: activeFile.content ?? "",
114298
- readOnly: true,
114299
- editorMinHeight: "0px"
114300
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
114301
- className: "text-muted-foreground flex h-full items-center justify-center",
114302
- children: "Select a file to view"
114303
- })
114304
- })
114305
- })
114306
- })
114307
- });
114308
- }
114309
- //#endregion
114310
- //#region src/components/opsx/artifact-document-shell.tsx
114311
- var statusConfig = {
114312
- done: {
114313
- label: "Done",
114314
- className: "text-emerald-500",
114315
- icon: CircleCheck
114316
- },
114317
- ready: {
114318
- label: "Ready",
114319
- className: "text-sky-500",
114320
- icon: Circle$1
114321
- },
114322
- blocked: {
114323
- label: "Blocked",
114324
- className: "text-amber-500",
114325
- icon: TriangleAlert
114326
- }
114327
- };
114328
- function OpsxArtifactStatusBadge({ status }) {
114329
- const config = statusConfig[status];
114330
- const StatusIcon = config.icon;
114331
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
114332
- className: `inline-flex shrink-0 items-center gap-1.5 text-xs font-medium ${config.className}`,
114333
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusIcon, { className: "h-4 w-4" }), config.label]
114334
- });
114335
- }
114336
- function OpsxArtifactTabStatusIcon({ status }) {
114337
- const StatusIcon = statusConfig[status].icon;
114338
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusIcon, { className: `h-3.5 w-3.5 ${statusConfig[status].className}` });
114339
- }
114340
- function OpsxArtifactDocumentShell({ id, path, status, missingDeps, meta, children }) {
114341
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
114342
- className: "border-border bg-muted/25 mb-5 rounded-md border px-4 py-3",
114343
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
114344
- className: "flex flex-wrap items-start justify-between gap-3",
114345
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
114346
- className: "min-w-0 space-y-1",
114347
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
114348
- className: "font-medium",
114349
- children: id
114350
- }), path ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
114351
- className: "text-muted-foreground break-all text-xs",
114352
- children: path
114353
- }) : null]
114354
- }), status ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(OpsxArtifactStatusBadge, { status }) : meta]
114355
- }), status === "blocked" && missingDeps?.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
114356
- className: "mt-3 flex items-start gap-2 rounded-md border border-amber-500/50 bg-amber-500/10 px-3 py-2 text-xs text-amber-700",
114357
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, { className: "h-4 w-4 shrink-0" }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
114358
- className: "font-medium",
114359
- children: "Blocked by missing dependencies"
114360
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
114361
- className: "mt-1",
114362
- children: missingDeps.join(", ")
114363
- })] })]
114364
- }) : null]
114365
- }), children] });
114366
- }
114367
- //#endregion
114368
114545
  //#region src/components/anchor-scroll.ts
114369
114546
  /**
114370
114547
  * Utilities for hash-anchor navigation inside nested scroll containers.
@@ -114425,46 +114602,6 @@ function navigateHashAnchor(anchorElement, hash) {
114425
114602
  return true;
114426
114603
  }
114427
114604
  //#endregion
114428
- //#region src/components/button.tsx
114429
- var variantClassNames = {
114430
- primary: "bg-primary text-primary-foreground hover:bg-primary/90",
114431
- secondary: "border-border bg-background text-foreground border hover:bg-muted",
114432
- ghost: "text-foreground hover:bg-muted",
114433
- destructive: "bg-red-600 text-white hover:bg-red-700 focus-visible:ring-red-500 dark:bg-red-600 dark:hover:bg-red-700"
114434
- };
114435
- var activityVariantClassNames = {
114436
- primary: "bg-primary/10 text-primary hover:bg-primary/10",
114437
- secondary: "border-primary/40 bg-primary/10 text-primary border hover:bg-primary/10",
114438
- ghost: "bg-primary/10 text-primary hover:bg-primary/10",
114439
- destructive: "bg-red-600/10 text-red-600 hover:bg-red-600/10 dark:text-red-400"
114440
- };
114441
- var sizeClassNames = {
114442
- sm: "gap-1.5 rounded-md px-3 py-1.5 text-xs",
114443
- md: "gap-2 rounded-md px-4 py-2 text-sm",
114444
- "icon-sm": "h-7 w-7 rounded-md p-0",
114445
- "icon-md": "h-9 w-9 rounded-md p-0"
114446
- };
114447
- var Button = (0, import_react.forwardRef)(function Button({ variant = "primary", size = "md", activity = false, disabled = false, type = "button", className, onClick, "aria-disabled": ariaDisabled, ...props }, ref) {
114448
- const handleClick = (event) => {
114449
- if (activity) {
114450
- event.preventDefault();
114451
- event.stopPropagation();
114452
- return;
114453
- }
114454
- onClick?.(event);
114455
- };
114456
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
114457
- ref,
114458
- type,
114459
- disabled,
114460
- "aria-disabled": ariaDisabled ?? (activity ? true : void 0),
114461
- "data-activity": activity ? "true" : void 0,
114462
- onClick: handleClick,
114463
- className: cn$1("inline-flex shrink-0 items-center justify-center font-medium outline-none transition-colors", "focus-visible:ring-primary focus-visible:ring-1", disabled ? "cursor-not-allowed opacity-50" : activity ? "cursor-default" : "cursor-pointer", activity ? activityVariantClassNames[variant] : variantClassNames[variant], sizeClassNames[size], className),
114464
- ...props
114465
- });
114466
- });
114467
- //#endregion
114468
114605
  //#region src/lib/document-translation-session-state.ts
114469
114606
  var DOCUMENT_TRANSLATION_SESSION_STORAGE_KEY = "openspecui:document-translation:mode";
114470
114607
  var DEFAULT_ACTIVATION = "source";
@@ -114512,6 +114649,30 @@ function useDocumentTranslationActivation() {
114512
114649
  };
114513
114650
  }
114514
114651
  //#endregion
114652
+ //#region src/lib/resolve-document-translation-config.ts
114653
+ function resolveDocumentTranslationConfig(translationConfig, globalSettings) {
114654
+ if (!translationConfig) return void 0;
114655
+ const local = translationConfig.engines?.local ?? {};
114656
+ const openai = translationConfig.engines?.openai ?? {};
114657
+ const resolvedLocalModel = local.model ?? globalSettings?.translationEngines.local.model;
114658
+ const resolvedLocalSelectedGroupId = local.selectedGroupId ?? globalSettings?.translationEngines.local.selectedGroupId;
114659
+ const resolvedOpenAIModel = openai.model ?? globalSettings?.translationEngines.openai.model;
114660
+ return {
114661
+ ...translationConfig,
114662
+ engines: {
114663
+ local: {
114664
+ ...local,
114665
+ ...resolvedLocalModel ? { model: resolvedLocalModel } : {},
114666
+ ...resolvedLocalSelectedGroupId ? { selectedGroupId: resolvedLocalSelectedGroupId } : {}
114667
+ },
114668
+ openai: {
114669
+ ...openai,
114670
+ ...resolvedOpenAIModel ? { model: resolvedOpenAIModel } : {}
114671
+ }
114672
+ }
114673
+ };
114674
+ }
114675
+ //#endregion
114515
114676
  //#region ../browser-translator/dist/index.mjs
114516
114677
  async function scanBrowserTranslationSupportTable(options) {
114517
114678
  const translator = (options.win ?? window).Translator;
@@ -131195,6 +131356,55 @@ function createProjectionContext(lookup, annotations, projections) {
131195
131356
  };
131196
131357
  }
131197
131358
  //#endregion
131359
+ //#region ../core/src/translation-language-pair.ts
131360
+ var OPUS_MT_DIRECTION_PATTERN = /^opus-mt-([a-z]{2,3})-([a-z]{2,3})$/i;
131361
+ function inferLocalDirectionalModelLanguagePair(model) {
131362
+ const modelName = model?.trim().split("/").pop();
131363
+ if (!modelName) return null;
131364
+ const match = OPUS_MT_DIRECTION_PATTERN.exec(modelName);
131365
+ if (!match) return null;
131366
+ const [, sourceLanguage, targetLanguage] = match;
131367
+ if (!sourceLanguage || !targetLanguage) return null;
131368
+ return {
131369
+ sourceLanguage: normalizeLanguageCode(sourceLanguage),
131370
+ targetLanguage: normalizeLanguageCode(targetLanguage)
131371
+ };
131372
+ }
131373
+ function checkLocalDirectionalModelLanguagePair(input) {
131374
+ const expected = inferLocalDirectionalModelLanguagePair(input.model);
131375
+ if (!expected) return { supported: true };
131376
+ if (!areCompatibleLanguageTags(expected.targetLanguage, input.targetLanguage)) return {
131377
+ supported: false,
131378
+ expected,
131379
+ message: `Selected local model supports ${formatLanguagePair(expected)}, but document translation is configured for target ${input.targetLanguage}.`
131380
+ };
131381
+ if (input.sourceLanguage && !areCompatibleLanguageTags(expected.sourceLanguage, input.sourceLanguage)) return {
131382
+ supported: false,
131383
+ expected,
131384
+ message: `Selected local model supports ${formatLanguagePair(expected)}, but document segment was detected as ${input.sourceLanguage} -> ${input.targetLanguage}.`
131385
+ };
131386
+ return {
131387
+ supported: true,
131388
+ expected
131389
+ };
131390
+ }
131391
+ function areCompatibleLanguageTags(expected, actual) {
131392
+ const expectedNormalized = normalizeLanguageTag$1(expected);
131393
+ const actualNormalized = normalizeLanguageTag$1(actual);
131394
+ if (!expectedNormalized || !actualNormalized) return false;
131395
+ if (expectedNormalized === actualNormalized) return true;
131396
+ return expectedNormalized.split("-")[0] === actualNormalized.split("-")[0];
131397
+ }
131398
+ function normalizeLanguageCode(language) {
131399
+ return language.trim().toLowerCase().replace(/_/g, "-");
131400
+ }
131401
+ function normalizeLanguageTag$1(language) {
131402
+ return normalizeLanguageCode(language);
131403
+ }
131404
+ function formatLanguagePair(pair) {
131405
+ return `${pair.sourceLanguage} -> ${pair.targetLanguage}`;
131406
+ }
131407
+ //#endregion
131198
131408
  //#region ../../node_modules/.pnpm/remark-gfm@4.0.1/node_modules/remark-gfm/lib/index.js
131199
131409
  /**
131200
131410
  * @import {Root} from 'mdast'
@@ -135723,6 +135933,43 @@ function escapeAttributeValue(value) {
135723
135933
  return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;");
135724
135934
  }
135725
135935
  //#endregion
135936
+ //#region src/lib/translation-adaptive-concurrency-log.ts
135937
+ var GLOBAL_STORAGE_KEY = "__OPENSPECUI_TRANSLATION_ADAPTIVE_CONCURRENCY_LOGS__";
135938
+ var MAX_LOG_AGE_MS = 1800 * 1e3;
135939
+ var MAX_LOG_ENTRIES = 256;
135940
+ var DEFAULT_SAMPLE_SIZE = 8;
135941
+ function createTranslationAdaptiveConcurrencyScopeKey(input) {
135942
+ return JSON.stringify({
135943
+ engineId: input.engineId,
135944
+ engineVersion: input.engineVersion ?? null,
135945
+ model: input.model ?? null,
135946
+ selectedGroupId: input.selectedGroupId ?? null,
135947
+ sourceLanguage: input.sourceLanguage.trim().toLowerCase(),
135948
+ targetLanguage: input.targetLanguage.trim().toLowerCase(),
135949
+ translatorContractVersion: input.translatorContractVersion
135950
+ });
135951
+ }
135952
+ function appendTranslationAdaptiveConcurrencyLog(entry) {
135953
+ const store = getTranslationAdaptiveConcurrencyLogStore();
135954
+ store.entries.push(entry);
135955
+ cleanupTranslationAdaptiveConcurrencyLogs(store);
135956
+ }
135957
+ function readRecentTranslationAdaptiveConcurrencyLogs(input = {}) {
135958
+ const store = getTranslationAdaptiveConcurrencyLogStore();
135959
+ cleanupTranslationAdaptiveConcurrencyLogs(store);
135960
+ return (input.scopeKey ? store.entries.filter((entry) => entry.scopeKey === input.scopeKey) : store.entries).slice(-Math.max(1, input.limit ?? DEFAULT_SAMPLE_SIZE));
135961
+ }
135962
+ function getTranslationAdaptiveConcurrencyLogStore() {
135963
+ const globalScope = globalThis;
135964
+ if (!globalScope[GLOBAL_STORAGE_KEY]) globalScope[GLOBAL_STORAGE_KEY] = { entries: [] };
135965
+ return globalScope[GLOBAL_STORAGE_KEY];
135966
+ }
135967
+ function cleanupTranslationAdaptiveConcurrencyLogs(store) {
135968
+ const cutoff = Date.now() - MAX_LOG_AGE_MS;
135969
+ if (store.entries.length === 0) return;
135970
+ store.entries = store.entries.filter((entry) => entry.recordedAt >= cutoff).slice(-MAX_LOG_ENTRIES);
135971
+ }
135972
+ //#endregion
135726
135973
  //#region ../search/src/engine.ts
135727
135974
  function normalizeText(input) {
135728
135975
  return input.toLowerCase().replace(/\s+/g, " ").trim();
@@ -136182,6 +136429,7 @@ var DOCUMENT_LANGUAGE_CONFIDENCE_THRESHOLD = .45;
136182
136429
  var SEGMENT_LANGUAGE_CONFIDENCE_THRESHOLD = .62;
136183
136430
  var TRANSLATION_DISPLAY_POLICY_VERSION = 2;
136184
136431
  var BROWSER_SOURCE_LANGUAGE_ORDER = new Map(SUPPORTED_TRANSLATION_LANGUAGES.map((language, index) => [language.code, index]));
136432
+ var SUPPORTED_TRANSLATION_LANGUAGE_CODES = new Set(SUPPORTED_TRANSLATION_LANGUAGES.map((language) => language.code));
136185
136433
  function isBrowserTranslationSupported() {
136186
136434
  return typeof window !== "undefined" && !!window.Translator;
136187
136435
  }
@@ -136399,14 +136647,20 @@ function mergeBrowserSupportRows(rows, row) {
136399
136647
  }
136400
136648
  function sortBrowserSupportRows(rows) {
136401
136649
  return [...rows].sort((left, right) => {
136402
- const leftOrder = BROWSER_SOURCE_LANGUAGE_ORDER.get(left.sourceLanguage) ?? Number.MAX_SAFE_INTEGER;
136403
- const rightOrder = BROWSER_SOURCE_LANGUAGE_ORDER.get(right.sourceLanguage) ?? Number.MAX_SAFE_INTEGER;
136650
+ const leftOrder = getBrowserSourceLanguageOrder(left.sourceLanguage) ?? Number.MAX_SAFE_INTEGER;
136651
+ const rightOrder = getBrowserSourceLanguageOrder(right.sourceLanguage) ?? Number.MAX_SAFE_INTEGER;
136404
136652
  if (leftOrder !== rightOrder) return leftOrder - rightOrder;
136405
136653
  const targetDelta = left.targetLanguage.localeCompare(right.targetLanguage);
136406
136654
  if (targetDelta !== 0) return targetDelta;
136407
136655
  return left.sourceLanguage.localeCompare(right.sourceLanguage);
136408
136656
  });
136409
136657
  }
136658
+ function getBrowserSourceLanguageOrder(sourceLanguage) {
136659
+ return isSupportedTranslationLanguageCode(sourceLanguage) ? BROWSER_SOURCE_LANGUAGE_ORDER.get(sourceLanguage) : void 0;
136660
+ }
136661
+ function isSupportedTranslationLanguageCode(language) {
136662
+ return SUPPORTED_TRANSLATION_LANGUAGE_CODES.has(language);
136663
+ }
136410
136664
  async function translateMarkdownDocumentProgressively(args, onPatch) {
136411
136665
  const segments = extractTranslatableSegments(args.markdown);
136412
136666
  if (segments.length === 0) return {
@@ -136416,9 +136670,9 @@ async function translateMarkdownDocumentProgressively(args, onPatch) {
136416
136670
  };
136417
136671
  const engine = args.engine ?? createBrowserTranslationExecution();
136418
136672
  const languageDetection = await createSourceLanguageDetectionSession(args.markdown, args.signal);
136419
- const translatorBySourceLanguage = /* @__PURE__ */ new Map();
136673
+ const translatedSegments = [...segments];
136674
+ const pendingJobsBySourceLanguage = /* @__PURE__ */ new Map();
136420
136675
  try {
136421
- const translatedSegments = [];
136422
136676
  for (const [segmentIndex, segment] of segments.entries()) {
136423
136677
  throwIfAborted(args.signal);
136424
136678
  const sourceLanguage = await languageDetection.detectSegmentLanguage(segment.translatorInput, args.signal);
@@ -136432,7 +136686,7 @@ async function translateMarkdownDocumentProgressively(args, onPatch) {
136432
136686
  targetLanguage: args.targetLanguage,
136433
136687
  status: "translated"
136434
136688
  };
136435
- translatedSegments.push(translatedSegment);
136689
+ translatedSegments[segmentIndex] = translatedSegment;
136436
136690
  onPatch({
136437
136691
  segmentIndex,
136438
136692
  segment: translatedSegment
@@ -136445,33 +136699,27 @@ async function translateMarkdownDocumentProgressively(args, onPatch) {
136445
136699
  targetLanguage: args.targetLanguage
136446
136700
  }) : null;
136447
136701
  if (cachedSegment) {
136448
- translatedSegments.push(cachedSegment);
136702
+ translatedSegments[segmentIndex] = cachedSegment;
136449
136703
  onPatch({
136450
136704
  segmentIndex,
136451
136705
  segment: cachedSegment
136452
136706
  });
136453
136707
  continue;
136454
136708
  }
136455
- const translator = await getPooledTranslator(engine, translatorBySourceLanguage, sourceLanguage, args.targetLanguage, args.signal);
136456
- const protectedInput = segment.placeholderProtocol ? {
136457
- text: segment.translatorInput,
136458
- restore: (output) => output
136459
- } : protectTranslatorInput(segment.translatorInput);
136460
- const target = await raceAbort(readSingleBatchOutput(translator.batchTranslate([protectedInput.text], { signal: args.signal })), args.signal);
136461
- const restoredTarget = segment.placeholderProtocol ? restoreTranslatedPlaceholderFragment(target, segment.placeholderProtocol) : { target: protectedInput.restore(target).trim() };
136462
- const translatedSegment = {
136463
- ...segment,
136464
- ...restoredTarget,
136709
+ const pendingJob = {
136710
+ segmentIndex,
136711
+ segment,
136465
136712
  sourceLanguage,
136466
- targetLanguage: args.targetLanguage,
136467
- status: "translated"
136713
+ cacheKey,
136714
+ protectedInput: segment.placeholderProtocol ? {
136715
+ text: segment.translatorInput,
136716
+ restore: (output) => output
136717
+ } : protectTranslatorInput(segment.translatorInput),
136718
+ estimatedTokens: estimateTranslationTokens(segment.translatorInput)
136468
136719
  };
136469
- if (cacheKey) writeCachedTranslationSegment(args.cache, cacheKey, translatedSegment);
136470
- translatedSegments.push(translatedSegment);
136471
- onPatch({
136472
- segmentIndex,
136473
- segment: translatedSegment
136474
- });
136720
+ const pendingJobs = pendingJobsBySourceLanguage.get(sourceLanguage) ?? [];
136721
+ pendingJobs.push(pendingJob);
136722
+ pendingJobsBySourceLanguage.set(sourceLanguage, pendingJobs);
136475
136723
  } catch (error) {
136476
136724
  if (args.signal.aborted) throw error;
136477
136725
  const failedSegment = {
@@ -136481,13 +136729,23 @@ async function translateMarkdownDocumentProgressively(args, onPatch) {
136481
136729
  status: "error",
136482
136730
  error: getErrorMessage(error)
136483
136731
  };
136484
- translatedSegments.push(failedSegment);
136732
+ translatedSegments[segmentIndex] = failedSegment;
136485
136733
  onPatch({
136486
136734
  segmentIndex,
136487
136735
  segment: failedSegment
136488
136736
  });
136489
136737
  }
136490
136738
  }
136739
+ await Promise.all([...pendingJobsBySourceLanguage.entries()].map(([sourceLanguage, jobs]) => translatePendingJobsBySourceLanguage({
136740
+ engine,
136741
+ sourceLanguage,
136742
+ targetLanguage: args.targetLanguage,
136743
+ signal: args.signal,
136744
+ cache: args.cache,
136745
+ jobs,
136746
+ translatedSegments,
136747
+ onPatch
136748
+ })));
136491
136749
  return {
136492
136750
  segments: translatedSegments,
136493
136751
  displayMode: args.displayMode,
@@ -136495,24 +136753,247 @@ async function translateMarkdownDocumentProgressively(args, onPatch) {
136495
136753
  targetLanguage: args.targetLanguage
136496
136754
  };
136497
136755
  } finally {
136498
- translatorBySourceLanguage.forEach((translator) => translator.destroy?.());
136499
136756
  languageDetection.destroy();
136500
136757
  }
136501
136758
  }
136502
- async function getPooledTranslator(engine, translatorBySourceLanguage, sourceLanguage, targetLanguage, signal) {
136503
- const existing = translatorBySourceLanguage.get(sourceLanguage);
136504
- if (existing) return existing;
136505
- const translator = await engine.factory.create({
136506
- sourceLanguage,
136507
- targetLanguage,
136508
- signal
136759
+ async function translatePendingJobsBySourceLanguage(input) {
136760
+ const markJobsError = (jobs, message) => {
136761
+ for (const job of jobs) {
136762
+ const failedSegment = {
136763
+ ...job.segment,
136764
+ sourceLanguage: job.sourceLanguage,
136765
+ targetLanguage: input.targetLanguage,
136766
+ status: "error",
136767
+ error: message
136768
+ };
136769
+ input.translatedSegments[job.segmentIndex] = failedSegment;
136770
+ input.onPatch({
136771
+ segmentIndex: job.segmentIndex,
136772
+ segment: failedSegment
136773
+ });
136774
+ }
136775
+ };
136776
+ const unsupportedLanguagePairMessage = getUnsupportedEngineLanguagePairMessage({
136777
+ engine: input.engine,
136778
+ sourceLanguage: input.sourceLanguage,
136779
+ targetLanguage: input.targetLanguage
136509
136780
  });
136510
- translatorBySourceLanguage.set(sourceLanguage, translator);
136511
- return translator;
136781
+ if (unsupportedLanguagePairMessage) {
136782
+ markJobsError(input.jobs, unsupportedLanguagePairMessage);
136783
+ return;
136784
+ }
136785
+ const batches = packTranslationJobs(input.jobs);
136786
+ if (batches.length === 0) return;
136787
+ const maxConcurrency = Math.min(6, batches.length);
136788
+ const scopeKey = createTranslationAdaptiveConcurrencyScopeKey({
136789
+ engineId: input.engine.cacheIdentity.engineId,
136790
+ engineVersion: input.engine.cacheIdentity.engineVersion,
136791
+ model: input.engine.cacheIdentity.model,
136792
+ selectedGroupId: input.engine.cacheIdentity.selectedGroupId,
136793
+ sourceLanguage: input.sourceLanguage,
136794
+ targetLanguage: input.targetLanguage,
136795
+ translatorContractVersion: input.engine.cacheIdentity.translatorContractVersion
136796
+ });
136797
+ let desiredConcurrency = 1;
136798
+ let nextBatchIndex = 0;
136799
+ let activeWorkers = 0;
136800
+ let completedBatches = 0;
136801
+ const workerPromises = /* @__PURE__ */ new Set();
136802
+ const startWorkersToDesired = () => {
136803
+ while (activeWorkers < desiredConcurrency && nextBatchIndex < batches.length && !input.signal.aborted) startWorker();
136804
+ };
136805
+ const maybeGrowConcurrency = () => {
136806
+ if (desiredConcurrency >= maxConcurrency) return;
136807
+ const recentLogs = readRecentTranslationAdaptiveConcurrencyLogs({
136808
+ scopeKey,
136809
+ limit: Math.max(4, desiredConcurrency * 2)
136810
+ });
136811
+ if (desiredConcurrency === 1) {
136812
+ if (completedBatches >= 1 && batches.length > 1 && recentLogs.length > 0) {
136813
+ desiredConcurrency = 2;
136814
+ startWorkersToDesired();
136815
+ }
136816
+ return;
136817
+ }
136818
+ if (completedBatches < desiredConcurrency) return;
136819
+ if (recentLogs.length < desiredConcurrency * 2) return;
136820
+ const window = recentLogs.slice(-desiredConcurrency * 2);
136821
+ const split = Math.max(1, Math.floor(window.length / 2));
136822
+ const earlierThroughput = summarizeTranslationLogThroughput(window.slice(0, split));
136823
+ const laterThroughput = summarizeTranslationLogThroughput(window.slice(split));
136824
+ if (earlierThroughput > 0 && laterThroughput >= earlierThroughput * 1.08) {
136825
+ desiredConcurrency = Math.min(maxConcurrency, desiredConcurrency + 1);
136826
+ startWorkersToDesired();
136827
+ }
136828
+ };
136829
+ const applyBatchResult = async (batch, outputs) => {
136830
+ for (const [offset, job] of batch.jobs.entries()) {
136831
+ const target = outputs[offset] ?? "";
136832
+ const restoredTarget = job.segment.placeholderProtocol ? restoreTranslatedPlaceholderFragment(target, job.segment.placeholderProtocol) : { target: job.protectedInput.restore(target).trim() };
136833
+ const translatedSegment = {
136834
+ ...job.segment,
136835
+ ...restoredTarget,
136836
+ sourceLanguage: job.sourceLanguage,
136837
+ targetLanguage: input.targetLanguage,
136838
+ status: "translated"
136839
+ };
136840
+ input.translatedSegments[job.segmentIndex] = translatedSegment;
136841
+ if (job.cacheKey) writeCachedTranslationSegment(input.cache, job.cacheKey, translatedSegment);
136842
+ input.onPatch({
136843
+ segmentIndex: job.segmentIndex,
136844
+ segment: translatedSegment
136845
+ });
136846
+ }
136847
+ };
136848
+ const markBatchError = (batch, error) => {
136849
+ markJobsError(batch.jobs, getErrorMessage(error));
136850
+ };
136851
+ const startWorker = () => {
136852
+ if (input.signal.aborted || nextBatchIndex >= batches.length) return;
136853
+ activeWorkers += 1;
136854
+ let workerPromise;
136855
+ workerPromise = (async () => {
136856
+ let translator = null;
136857
+ try {
136858
+ translator = await input.engine.factory.create({
136859
+ sourceLanguage: input.sourceLanguage,
136860
+ targetLanguage: input.targetLanguage,
136861
+ signal: input.signal
136862
+ });
136863
+ while (!input.signal.aborted) {
136864
+ const batchIndex = nextBatchIndex;
136865
+ if (batchIndex >= batches.length) break;
136866
+ nextBatchIndex += 1;
136867
+ const batch = batches[batchIndex];
136868
+ const startedAt = getCurrentTimeMs();
136869
+ try {
136870
+ await applyBatchResult(batch, await collectBatchTranslationOutputs(translator.batchTranslate(batch.jobs.map((job) => job.protectedInput.text), { signal: input.signal }), batch.jobs.length));
136871
+ completedBatches += 1;
136872
+ const elapsedMs = Math.max(1, getCurrentTimeMs() - startedAt);
136873
+ appendTranslationAdaptiveConcurrencyLog({
136874
+ scopeKey,
136875
+ recordedAt: Date.now(),
136876
+ engineId: input.engine.cacheIdentity.engineId,
136877
+ engineVersion: input.engine.cacheIdentity.engineVersion,
136878
+ model: input.engine.cacheIdentity.model,
136879
+ selectedGroupId: input.engine.cacheIdentity.selectedGroupId,
136880
+ sourceLanguage: input.sourceLanguage,
136881
+ targetLanguage: input.targetLanguage,
136882
+ batchIndex,
136883
+ batchSize: batch.jobs.length,
136884
+ estimatedTokens: batch.estimatedTokens,
136885
+ elapsedMs,
136886
+ throughputTokensPerMs: batch.estimatedTokens / elapsedMs,
136887
+ desiredConcurrency,
136888
+ activeWorkers,
136889
+ maxConcurrency
136890
+ });
136891
+ maybeGrowConcurrency();
136892
+ } catch (error) {
136893
+ if (input.signal.aborted) throw error;
136894
+ markBatchError(batch, error);
136895
+ }
136896
+ }
136897
+ } finally {
136898
+ translator?.destroy?.();
136899
+ }
136900
+ })().finally(() => {
136901
+ activeWorkers -= 1;
136902
+ workerPromises.delete(workerPromise);
136903
+ startWorkersToDesired();
136904
+ });
136905
+ workerPromises.add(workerPromise);
136906
+ };
136907
+ startWorkersToDesired();
136908
+ while (workerPromises.size > 0) await Promise.race(workerPromises);
136909
+ }
136910
+ function getUnsupportedEngineLanguagePairMessage(input) {
136911
+ if (input.engine.cacheIdentity.engineId !== "local") return null;
136912
+ const directionCheck = checkLocalDirectionalModelLanguagePair({
136913
+ model: input.engine.cacheIdentity.model,
136914
+ sourceLanguage: input.sourceLanguage,
136915
+ targetLanguage: input.targetLanguage
136916
+ });
136917
+ if (directionCheck.supported) return null;
136918
+ return directionCheck.message ?? "Selected local model does not support the detected translation direction.";
136919
+ }
136920
+ function summarizeTranslationLogThroughput(logs) {
136921
+ if (logs.length === 0) return 0;
136922
+ const totalTokens = logs.reduce((total, log) => total + log.estimatedTokens, 0);
136923
+ const totalElapsedMs = logs.reduce((total, log) => total + log.elapsedMs, 0);
136924
+ if (totalTokens <= 0 || totalElapsedMs <= 0) return 0;
136925
+ return totalTokens / totalElapsedMs;
136926
+ }
136927
+ function packTranslationJobs(jobs) {
136928
+ if (jobs.length === 0) return [];
136929
+ const averageTokens = jobs.reduce((total, job) => total + job.estimatedTokens, 0) / Math.max(1, jobs.length);
136930
+ const targetTokens = Math.max(1, Math.round(averageTokens * 6));
136931
+ const batches = [];
136932
+ let currentJobs = [];
136933
+ let currentTokens = 0;
136934
+ const flush = () => {
136935
+ if (currentJobs.length === 0) return;
136936
+ batches.push({
136937
+ jobs: currentJobs,
136938
+ estimatedTokens: currentTokens
136939
+ });
136940
+ currentJobs = [];
136941
+ currentTokens = 0;
136942
+ };
136943
+ for (const job of jobs) {
136944
+ if (currentJobs.length === 0) {
136945
+ currentJobs = [job];
136946
+ currentTokens = job.estimatedTokens;
136947
+ continue;
136948
+ }
136949
+ const nextTokens = currentTokens + job.estimatedTokens;
136950
+ if (nextTokens <= targetTokens) {
136951
+ currentJobs.push(job);
136952
+ currentTokens = nextTokens;
136953
+ continue;
136954
+ }
136955
+ const withoutDelta = Math.abs(currentTokens - targetTokens);
136956
+ if (Math.abs(nextTokens - targetTokens) <= withoutDelta) {
136957
+ currentJobs.push(job);
136958
+ currentTokens = nextTokens;
136959
+ flush();
136960
+ continue;
136961
+ }
136962
+ flush();
136963
+ currentJobs = [job];
136964
+ currentTokens = job.estimatedTokens;
136965
+ }
136966
+ flush();
136967
+ return batches;
136968
+ }
136969
+ async function collectBatchTranslationOutputs(stream, expectedCount) {
136970
+ const outputs = /* @__PURE__ */ new Map();
136971
+ for await (const item of stream) {
136972
+ if (item.index < 0 || item.index >= expectedCount) throw new Error(`Translator yielded output for unexpected index ${item.index}.`);
136973
+ if (!outputs.has(item.index)) outputs.set(item.index, item.output);
136974
+ }
136975
+ if (outputs.size !== expectedCount) throw new Error(`Translator returned ${outputs.size} outputs for ${expectedCount} inputs.`);
136976
+ return Array.from({ length: expectedCount }, (_, index) => outputs.get(index) ?? "");
136977
+ }
136978
+ function estimateTranslationTokens(input) {
136979
+ const trimmed = input.trim();
136980
+ if (!trimmed) return 1;
136981
+ const segmenter = getTokenSegmenter();
136982
+ if (!segmenter) return Math.max(1, trimmed.split(/\s+/).filter(Boolean).length);
136983
+ let count = 0;
136984
+ for (const segment of segmenter.segment(trimmed)) if (segment.isWordLike ?? segment.segment.trim().length > 0) count += 1;
136985
+ return Math.max(1, count);
136986
+ }
136987
+ function getTokenSegmenter() {
136988
+ if (typeof Intl === "undefined" || typeof Intl.Segmenter !== "function") return null;
136989
+ try {
136990
+ return new Intl.Segmenter(void 0, { granularity: "word" });
136991
+ } catch {
136992
+ return null;
136993
+ }
136512
136994
  }
136513
- async function readSingleBatchOutput(stream) {
136514
- for await (const item of stream) return item.output;
136515
- throw new Error("Translator returned no batch output.");
136995
+ function getCurrentTimeMs() {
136996
+ return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
136516
136997
  }
136517
136998
  async function createSourceLanguageDetectionSession(markdown, signal) {
136518
136999
  const detectorFactory = window.LanguageDetector;
@@ -136988,87 +137469,10 @@ function getErrorMessage(error) {
136988
137469
  return error instanceof Error ? error.message : "Unknown translation error.";
136989
137470
  }
136990
137471
  //#endregion
136991
- //#region src/lib/translate-service.ts
136992
- function createTranslationEngineExecution(config) {
136993
- if (config.engineId === "browser" || isStaticMode()) return createBrowserTranslationExecution();
136994
- const model = config.engineId === "openai" ? config.engines.openai.model : config.engines.local.model;
136995
- return {
136996
- factory: new TrpcTranslatorFactory(config.engineId, model, config.engineId === "local" ? config.engines.local.selectedGroupId : void 0),
136997
- cacheIdentity: {
136998
- engineId: config.engineId,
136999
- model,
137000
- selectedGroupId: config.engineId === "local" ? config.engines.local.selectedGroupId : void 0,
137001
- translatorContractVersion: 2
137002
- }
137003
- };
137004
- }
137005
- var TrpcTranslatorFactory = class {
137006
- constructor(engineId, model, selectedGroupId) {
137007
- this.engineId = engineId;
137008
- this.model = model;
137009
- this.selectedGroupId = selectedGroupId;
137010
- }
137011
- async create(options) {
137012
- return new TrpcTranslator({
137013
- engineId: this.engineId,
137014
- sourceLanguage: options.sourceLanguage,
137015
- targetLanguage: options.targetLanguage,
137016
- model: options.model ?? this.model,
137017
- selectedGroupId: this.engineId === "local" ? this.selectedGroupId : void 0
137018
- });
137019
- }
137020
- };
137021
- var TrpcTranslator = class {
137022
- constructor(options) {
137023
- this.options = options;
137024
- }
137025
- async *batchTranslate(inputs, options) {
137026
- if (options?.signal?.aborted) throw new DOMException("Translation cancelled.", "AbortError");
137027
- const queue = [];
137028
- let completed = false;
137029
- let thrown = null;
137030
- const subscription = trpcClient.translationEngines.batchTranslate.subscribe({
137031
- engineId: this.options.engineId,
137032
- sourceLanguage: this.options.sourceLanguage,
137033
- targetLanguage: this.options.targetLanguage,
137034
- model: this.options.model,
137035
- selectedGroupId: this.options.selectedGroupId,
137036
- inputs,
137037
- instructions: options?.instructions,
137038
- context: options?.context
137039
- }, {
137040
- onData(event) {
137041
- queue.push(event);
137042
- },
137043
- onError(error) {
137044
- thrown = error instanceof Error ? error : new Error(String(error));
137045
- completed = true;
137046
- },
137047
- onComplete() {
137048
- completed = true;
137049
- }
137050
- });
137051
- try {
137052
- while (!completed || queue.length > 0) {
137053
- if (options?.signal?.aborted) throw new DOMException("Translation cancelled.", "AbortError");
137054
- const item = queue.shift();
137055
- if (item) {
137056
- yield item;
137057
- continue;
137058
- }
137059
- await new Promise((resolve) => setTimeout(resolve, 0));
137060
- }
137061
- if (thrown) throw thrown;
137062
- } finally {
137063
- subscription.unsubscribe();
137064
- }
137065
- }
137066
- };
137067
- //#endregion
137068
137472
  //#region ../core/src/local-download-profiles.ts
137069
137473
  function selectLocalDownloadGroup(plan, selectedGroupId) {
137070
137474
  if (!plan?.groups?.length) return null;
137071
- return (selectedGroupId ? plan.groups.find((group) => group.id === selectedGroupId && group.selectable) : void 0) ?? plan.groups.find((group) => group.selected) ?? selectSmallestSelectableGroup(plan.groups);
137475
+ return (selectedGroupId ? plan.groups.find((group) => group.selectable && (group.id === selectedGroupId || group.baseGroupId === selectedGroupId)) : void 0) ?? plan.groups.find((group) => group.selected) ?? selectSmallestSelectableGroup(plan.groups);
137072
137476
  }
137073
137477
  function selectSmallestSelectableGroup(groups) {
137074
137478
  return groups.filter((group) => group.selectable && group.estimatedTotalBytes !== void 0).sort((left, right) => (left.estimatedTotalBytes ?? 0) - (right.estimatedTotalBytes ?? 0))[0] ?? null;
@@ -137167,6 +137571,253 @@ function isLocalAssetReady(asset, selectedGroupId) {
137167
137571
  return allRequiredFilesReady;
137168
137572
  }
137169
137573
  //#endregion
137574
+ //#region src/lib/translate-service.ts
137575
+ async function resolveTranslateServiceState(input) {
137576
+ const config = input.config;
137577
+ if (!config?.enabled || !input.hasSource) return emitTranslateServiceState(input.onUpdate, { status: projectTranslateServiceStatus({
137578
+ enabled: config?.enabled ?? false,
137579
+ hasSource: input.hasSource,
137580
+ engineId: config?.engineId ?? "browser"
137581
+ }) });
137582
+ if (config.engineId === "local") {
137583
+ const model = config.engines.local.model?.trim();
137584
+ if (!model) return emitTranslateServiceState(input.onUpdate, { status: projectTranslateServiceStatus({
137585
+ enabled: config.enabled,
137586
+ hasSource: input.hasSource,
137587
+ engineId: "local",
137588
+ localModel: model,
137589
+ localSelectedGroupId: config.engines.local.selectedGroupId
137590
+ }) });
137591
+ const directionCheck = checkLocalDirectionalModelLanguagePair({
137592
+ model,
137593
+ targetLanguage: config.targetLanguage
137594
+ });
137595
+ if (!directionCheck.supported) return emitTranslateServiceState(input.onUpdate, { status: {
137596
+ state: "unavailable",
137597
+ engineId: "local",
137598
+ message: directionCheck.message ?? "Selected local model does not support the configured target language."
137599
+ } });
137600
+ input.onUpdate?.(createTranslateServiceState({ status: projectTranslateServiceStatus({
137601
+ enabled: config.enabled,
137602
+ hasSource: input.hasSource,
137603
+ engineId: "local",
137604
+ localModel: model,
137605
+ localSelectedGroupId: config.engines.local.selectedGroupId,
137606
+ localAssetLoading: true
137607
+ }) }));
137608
+ try {
137609
+ const panelState = await trpcClient.localModels.panelState.query({
137610
+ modelId: model,
137611
+ selectedGroupId: config.engines.local.selectedGroupId
137612
+ });
137613
+ const selectedGroupId = panelState.selectedGroupId ?? config.engines.local.selectedGroupId;
137614
+ return createTranslateServiceState({ status: projectTranslateServiceStatus({
137615
+ enabled: config.enabled,
137616
+ hasSource: input.hasSource,
137617
+ engineId: "local",
137618
+ localModel: model,
137619
+ localSelectedGroupId: selectedGroupId,
137620
+ localAsset: panelState.asset
137621
+ }) });
137622
+ } catch (assetError) {
137623
+ return createTranslateServiceState({ status: {
137624
+ state: "unavailable",
137625
+ engineId: "local",
137626
+ message: assetError instanceof Error ? assetError.message : "Unable to check local model files."
137627
+ } });
137628
+ }
137629
+ }
137630
+ if (config.engineId === "openai") return emitTranslateServiceState(input.onUpdate, { status: projectTranslateServiceStatus({
137631
+ enabled: config.enabled,
137632
+ hasSource: input.hasSource,
137633
+ engineId: "openai"
137634
+ }) });
137635
+ const cachedTable = getBrowserSupportTableState(config.targetLanguage);
137636
+ if (cachedTable) return emitTranslateServiceState(input.onUpdate, {
137637
+ browserSupportTable: cachedTable,
137638
+ status: projectTranslateServiceStatus({
137639
+ enabled: config.enabled,
137640
+ hasSource: input.hasSource,
137641
+ engineId: "browser",
137642
+ browserSupportTable: cachedTable
137643
+ })
137644
+ });
137645
+ const checkingTable = {
137646
+ state: "checking",
137647
+ table: null,
137648
+ message: "Checking browser translation pairs…"
137649
+ };
137650
+ input.onUpdate?.(createTranslateServiceState({
137651
+ browserSupportTable: checkingTable,
137652
+ status: projectTranslateServiceStatus({
137653
+ enabled: config.enabled,
137654
+ hasSource: input.hasSource,
137655
+ engineId: "browser",
137656
+ browserSupportTable: checkingTable
137657
+ })
137658
+ }));
137659
+ try {
137660
+ const nextTable = await scanBrowserTranslationPairs(config.targetLanguage, {
137661
+ signal: input.signal ?? new AbortController().signal,
137662
+ onProgress: (progressState) => {
137663
+ input.onUpdate?.(createTranslateServiceState({
137664
+ browserSupportTable: progressState,
137665
+ status: projectTranslateServiceStatus({
137666
+ enabled: config.enabled,
137667
+ hasSource: input.hasSource,
137668
+ engineId: "browser",
137669
+ browserSupportTable: progressState
137670
+ })
137671
+ }));
137672
+ }
137673
+ });
137674
+ return createTranslateServiceState({
137675
+ browserSupportTable: nextTable,
137676
+ status: projectTranslateServiceStatus({
137677
+ enabled: config.enabled,
137678
+ hasSource: input.hasSource,
137679
+ engineId: "browser",
137680
+ browserSupportTable: nextTable
137681
+ })
137682
+ });
137683
+ } catch (probeError) {
137684
+ const nextCapability = {
137685
+ availability: "error",
137686
+ message: probeError instanceof Error ? probeError.message : "Unable to check translation support."
137687
+ };
137688
+ return createTranslateServiceState({
137689
+ capability: nextCapability,
137690
+ status: projectTranslateServiceStatus({
137691
+ enabled: config.enabled,
137692
+ hasSource: input.hasSource,
137693
+ engineId: "browser",
137694
+ browserCapability: nextCapability
137695
+ })
137696
+ });
137697
+ }
137698
+ }
137699
+ function prepareTranslateServiceRun(input) {
137700
+ if (input.config.engineId !== "browser") return createTranslateServiceState({ status: projectTranslateServiceStatus({
137701
+ enabled: input.config.enabled,
137702
+ hasSource: input.hasSource,
137703
+ engineId: input.config.engineId
137704
+ }) });
137705
+ const preferredRow = input.browserSupportTable?.table?.rows.find((row) => row.availability === "available") ?? input.browserSupportTable?.table?.rows.find((row) => row.availability === "downloading") ?? input.browserSupportTable?.table?.rows.find((row) => row.availability === "downloadable") ?? null;
137706
+ if (!preferredRow) return createTranslateServiceState({
137707
+ browserSupportTable: input.browserSupportTable,
137708
+ status: projectTranslateServiceStatus({
137709
+ enabled: input.config.enabled,
137710
+ hasSource: input.hasSource,
137711
+ engineId: "browser",
137712
+ browserSupportTable: input.browserSupportTable
137713
+ })
137714
+ });
137715
+ const nextCapability = {
137716
+ availability: preferredRow.availability,
137717
+ progress: preferredRow.progress,
137718
+ message: preferredRow.message
137719
+ };
137720
+ const nextTable = patchBrowserSupportTableRow(input.config.targetLanguage, preferredRow, { message: void 0 });
137721
+ return createTranslateServiceState({
137722
+ capability: nextCapability,
137723
+ browserSupportTable: nextTable,
137724
+ status: projectTranslateServiceStatus({
137725
+ enabled: input.config.enabled,
137726
+ hasSource: input.hasSource,
137727
+ engineId: "browser",
137728
+ browserSupportTable: nextTable,
137729
+ browserCapability: nextCapability
137730
+ })
137731
+ });
137732
+ }
137733
+ function createTranslationEngineExecution(config) {
137734
+ if (config.engineId === "browser" || isStaticMode()) return createBrowserTranslationExecution();
137735
+ const model = config.engineId === "openai" ? config.engines.openai.model : config.engines.local.model;
137736
+ return {
137737
+ factory: new TrpcTranslatorFactory(config.engineId, model, config.engineId === "local" ? config.engines.local.selectedGroupId : void 0),
137738
+ cacheIdentity: {
137739
+ engineId: config.engineId,
137740
+ model,
137741
+ selectedGroupId: config.engineId === "local" ? config.engines.local.selectedGroupId : void 0,
137742
+ translatorContractVersion: 2
137743
+ }
137744
+ };
137745
+ }
137746
+ var TrpcTranslatorFactory = class {
137747
+ constructor(engineId, model, selectedGroupId) {
137748
+ this.engineId = engineId;
137749
+ this.model = model;
137750
+ this.selectedGroupId = selectedGroupId;
137751
+ }
137752
+ async create(options) {
137753
+ return new TrpcTranslator({
137754
+ engineId: this.engineId,
137755
+ sourceLanguage: options.sourceLanguage,
137756
+ targetLanguage: options.targetLanguage,
137757
+ model: options.model ?? this.model,
137758
+ selectedGroupId: this.engineId === "local" ? this.selectedGroupId : void 0
137759
+ });
137760
+ }
137761
+ };
137762
+ var TrpcTranslator = class {
137763
+ constructor(options) {
137764
+ this.options = options;
137765
+ }
137766
+ async *batchTranslate(inputs, options) {
137767
+ if (options?.signal?.aborted) throw new DOMException("Translation cancelled.", "AbortError");
137768
+ const queue = [];
137769
+ let completed = false;
137770
+ let thrown = null;
137771
+ const subscription = trpcClient.translationEngines.batchTranslate.subscribe({
137772
+ engineId: this.options.engineId,
137773
+ sourceLanguage: this.options.sourceLanguage,
137774
+ targetLanguage: this.options.targetLanguage,
137775
+ model: this.options.model,
137776
+ selectedGroupId: this.options.selectedGroupId,
137777
+ inputs,
137778
+ instructions: options?.instructions,
137779
+ context: options?.context
137780
+ }, {
137781
+ onData(event) {
137782
+ queue.push(event);
137783
+ },
137784
+ onError(error) {
137785
+ thrown = error instanceof Error ? error : new Error(String(error));
137786
+ completed = true;
137787
+ },
137788
+ onComplete() {
137789
+ completed = true;
137790
+ }
137791
+ });
137792
+ try {
137793
+ while (!completed || queue.length > 0) {
137794
+ if (options?.signal?.aborted) throw new DOMException("Translation cancelled.", "AbortError");
137795
+ const item = queue.shift();
137796
+ if (item) {
137797
+ yield item;
137798
+ continue;
137799
+ }
137800
+ await new Promise((resolve) => setTimeout(resolve, 0));
137801
+ }
137802
+ if (thrown) throw thrown;
137803
+ } finally {
137804
+ subscription.unsubscribe();
137805
+ }
137806
+ }
137807
+ };
137808
+ function createTranslateServiceState(input) {
137809
+ return {
137810
+ capability: input.capability ?? null,
137811
+ browserSupportTable: input.browserSupportTable ?? null,
137812
+ status: input.status
137813
+ };
137814
+ }
137815
+ function emitTranslateServiceState(onUpdate, input) {
137816
+ const state = createTranslateServiceState(input);
137817
+ onUpdate?.(state);
137818
+ return state;
137819
+ }
137820
+ //#endregion
137170
137821
  //#region src/lib/use-document-translation.ts
137171
137822
  function useDocumentTranslation(markdown, config) {
137172
137823
  const [status, setStatus] = (0, import_react.useState)("source");
@@ -137179,9 +137830,11 @@ function useDocumentTranslation(markdown, config) {
137179
137830
  const [error, setError] = (0, import_react.useState)(null);
137180
137831
  const [result, setResult] = (0, import_react.useState)(null);
137181
137832
  const abortRef = (0, import_react.useRef)(null);
137833
+ const generationRef = (0, import_react.useRef)(0);
137182
137834
  const latestStartRef = (0, import_react.useRef)(null);
137183
137835
  const { activation } = useDocumentTranslationActivation();
137184
137836
  const cancel = (0, import_react.useCallback)(() => {
137837
+ generationRef.current += 1;
137185
137838
  abortRef.current?.abort();
137186
137839
  abortRef.current = null;
137187
137840
  setStatus("source");
@@ -137189,6 +137842,7 @@ function useDocumentTranslation(markdown, config) {
137189
137842
  setError(null);
137190
137843
  }, []);
137191
137844
  const reset = (0, import_react.useCallback)(() => {
137845
+ generationRef.current += 1;
137192
137846
  abortRef.current?.abort();
137193
137847
  abortRef.current = null;
137194
137848
  setStatus("source");
@@ -137197,6 +137851,7 @@ function useDocumentTranslation(markdown, config) {
137197
137851
  }, []);
137198
137852
  (0, import_react.useEffect)(() => reset, [reset]);
137199
137853
  (0, import_react.useEffect)(() => {
137854
+ generationRef.current += 1;
137200
137855
  setCapability(null);
137201
137856
  setBrowserSupportTable(null);
137202
137857
  setResult(null);
@@ -137206,141 +137861,39 @@ function useDocumentTranslation(markdown, config) {
137206
137861
  markdown,
137207
137862
  config?.displayMode,
137208
137863
  config?.enabled,
137864
+ config?.engineId,
137865
+ config?.engines.local.model,
137866
+ config?.engines.local.selectedGroupId,
137867
+ config?.engines.openai.model,
137209
137868
  config?.targetLanguage
137210
137869
  ]);
137211
137870
  (0, import_react.useEffect)(() => {
137212
137871
  let disposed = false;
137213
- if (!config?.enabled || markdown.length === 0) {
137214
- setCapability(null);
137215
- setBrowserSupportTable(null);
137216
- setServiceStatus(projectTranslateServiceStatus({
137217
- enabled: config?.enabled ?? false,
137218
- hasSource: markdown.length > 0,
137219
- engineId: config?.engineId ?? "browser"
137220
- }));
137221
- return () => {
137222
- disposed = true;
137223
- };
137224
- }
137225
- if (config.engineId === "local") {
137226
- setCapability(null);
137227
- setBrowserSupportTable(null);
137228
- setServiceStatus(projectTranslateServiceStatus({
137229
- enabled: config.enabled,
137230
- hasSource: markdown.length > 0,
137231
- engineId: "local",
137232
- localModel: config.engines.local.model,
137233
- localSelectedGroupId: config.engines.local.selectedGroupId,
137234
- localAssetLoading: true
137235
- }));
137236
- const model = config.engines.local.model?.trim();
137237
- if (!model) {
137238
- setServiceStatus(projectTranslateServiceStatus({
137239
- enabled: config.enabled,
137240
- hasSource: markdown.length > 0,
137241
- engineId: "local",
137242
- localModel: model,
137243
- localSelectedGroupId: config.engines.local.selectedGroupId
137244
- }));
137245
- return () => {
137246
- disposed = true;
137247
- };
137248
- }
137249
- trpcClient.localModels.state.query({
137250
- modelId: model,
137251
- selectedGroupId: config.engines.local.selectedGroupId
137252
- }).then((localAsset) => {
137253
- if (disposed) return;
137254
- setServiceStatus(projectTranslateServiceStatus({
137255
- enabled: config.enabled,
137256
- hasSource: markdown.length > 0,
137257
- engineId: "local",
137258
- localModel: model,
137259
- localSelectedGroupId: config.engines.local.selectedGroupId,
137260
- localAsset
137261
- }));
137262
- }).catch((assetError) => {
137263
- if (disposed) return;
137264
- setServiceStatus({
137265
- state: "unavailable",
137266
- engineId: "local",
137267
- message: assetError instanceof Error ? assetError.message : "Unable to check local model files."
137268
- });
137269
- });
137270
- return () => {
137271
- disposed = true;
137272
- };
137273
- }
137274
- if (config.engineId === "openai") {
137275
- setCapability(null);
137276
- setBrowserSupportTable(null);
137277
- setServiceStatus(projectTranslateServiceStatus({
137278
- enabled: config.enabled,
137279
- hasSource: markdown.length > 0,
137280
- engineId: "openai"
137281
- }));
137282
- return () => {
137283
- disposed = true;
137284
- };
137285
- }
137286
- const cachedTable = getBrowserSupportTableState(config.targetLanguage);
137287
- if (cachedTable) {
137288
- setBrowserSupportTable(cachedTable);
137289
- setServiceStatus(projectTranslateServiceStatus({
137290
- enabled: config.enabled,
137291
- hasSource: markdown.length > 0,
137292
- engineId: "browser",
137293
- browserSupportTable: cachedTable
137294
- }));
137295
- return () => {
137296
- disposed = true;
137297
- };
137298
- }
137299
- setServiceStatus(projectTranslateServiceStatus({
137300
- enabled: config.enabled,
137301
- hasSource: markdown.length > 0,
137302
- engineId: "browser",
137303
- browserSupportTable: {
137304
- state: "checking",
137305
- table: null,
137306
- message: "Checking browser translation pairs…"
137307
- }
137308
- }));
137309
137872
  const controller = new AbortController();
137310
- scanBrowserTranslationPairs(config.targetLanguage, {
137873
+ resolveTranslateServiceState({
137874
+ config,
137875
+ hasSource: markdown.length > 0,
137311
137876
  signal: controller.signal,
137312
- onProgress: (nextState) => {
137877
+ onUpdate: (nextState) => {
137313
137878
  if (disposed) return;
137314
- setBrowserSupportTable(nextState);
137315
- setServiceStatus(projectTranslateServiceStatus({
137316
- enabled: config.enabled,
137317
- hasSource: markdown.length > 0,
137318
- engineId: "browser",
137319
- browserSupportTable: nextState
137320
- }));
137879
+ setCapability(nextState.capability);
137880
+ setBrowserSupportTable(nextState.browserSupportTable);
137881
+ setServiceStatus(nextState.status);
137321
137882
  }
137322
137883
  }).then((nextState) => {
137323
137884
  if (disposed) return;
137324
- setBrowserSupportTable(nextState);
137325
- setServiceStatus(projectTranslateServiceStatus({
137326
- enabled: config.enabled,
137327
- hasSource: markdown.length > 0,
137328
- engineId: "browser",
137329
- browserSupportTable: nextState
137330
- }));
137331
- }).catch((probeError) => {
137885
+ setCapability(nextState.capability);
137886
+ setBrowserSupportTable(nextState.browserSupportTable);
137887
+ setServiceStatus(nextState.status);
137888
+ }).catch((stateError) => {
137332
137889
  if (disposed) return;
137333
- const nextCapability = {
137334
- availability: "error",
137335
- message: probeError instanceof Error ? probeError.message : "Unable to check translation support."
137336
- };
137337
- setCapability(nextCapability);
137338
- setServiceStatus(projectTranslateServiceStatus({
137339
- enabled: config.enabled,
137340
- hasSource: markdown.length > 0,
137341
- engineId: "browser",
137342
- browserCapability: nextCapability
137343
- }));
137890
+ setCapability(null);
137891
+ setBrowserSupportTable(null);
137892
+ setServiceStatus({
137893
+ state: "unavailable",
137894
+ engineId: config?.engineId ?? "browser",
137895
+ message: stateError instanceof Error ? stateError.message : "Unable to check translation service."
137896
+ });
137344
137897
  });
137345
137898
  return () => {
137346
137899
  disposed = true;
@@ -137358,6 +137911,8 @@ function useDocumentTranslation(markdown, config) {
137358
137911
  if (!config?.enabled) return;
137359
137912
  abortRef.current?.abort();
137360
137913
  const controller = new AbortController();
137914
+ const generationId = generationRef.current + 1;
137915
+ generationRef.current = generationId;
137361
137916
  abortRef.current = controller;
137362
137917
  setError(null);
137363
137918
  setStatus("initializing");
@@ -137368,27 +137923,19 @@ function useDocumentTranslation(markdown, config) {
137368
137923
  return;
137369
137924
  }
137370
137925
  if (config.engineId === "browser") {
137371
- const preferredRow = browserSupportTable?.table?.rows.find((row) => row.availability === "available") ?? browserSupportTable?.table?.rows.find((row) => row.availability === "downloading") ?? browserSupportTable?.table?.rows.find((row) => row.availability === "downloadable") ?? null;
137372
- if (!preferredRow) {
137373
- setError(serviceStatus.message);
137926
+ const nextState = prepareTranslateServiceRun({
137927
+ config,
137928
+ hasSource: markdown.length > 0,
137929
+ browserSupportTable
137930
+ });
137931
+ setCapability(nextState.capability);
137932
+ setBrowserSupportTable(nextState.browserSupportTable);
137933
+ setServiceStatus(nextState.status);
137934
+ if (nextState.status.state !== "ready") {
137935
+ setError(nextState.status.message);
137374
137936
  setStatus("unavailable");
137375
137937
  return;
137376
137938
  }
137377
- const nextCapability = {
137378
- availability: preferredRow.availability,
137379
- progress: preferredRow.progress,
137380
- message: preferredRow.message
137381
- };
137382
- setCapability(nextCapability);
137383
- const nextTable = patchBrowserSupportTableRow(config.targetLanguage, preferredRow, { message: void 0 });
137384
- setBrowserSupportTable(nextTable);
137385
- setServiceStatus(projectTranslateServiceStatus({
137386
- enabled: config.enabled,
137387
- hasSource: markdown.length > 0,
137388
- engineId: "browser",
137389
- browserSupportTable: nextTable,
137390
- browserCapability: nextCapability
137391
- }));
137392
137939
  }
137393
137940
  setStatus("translating");
137394
137941
  setResult({
@@ -137407,21 +137954,27 @@ function useDocumentTranslation(markdown, config) {
137407
137954
  write: (input) => trpcClient.translationCache.write.mutate(input)
137408
137955
  } : void 0
137409
137956
  }, (patch) => {
137410
- if (controller.signal.aborted || abortRef.current !== controller) return;
137957
+ if (controller.signal.aborted || abortRef.current !== controller || generationRef.current !== generationId) return;
137411
137958
  setResult((current) => applyDocumentTranslationPatch(current, patch, {
137412
137959
  displayMode: config.displayMode,
137413
137960
  targetLanguage: config.targetLanguage
137414
137961
  }));
137415
137962
  });
137416
- if (controller.signal.aborted) return;
137963
+ if (controller.signal.aborted || abortRef.current !== controller || generationRef.current !== generationId) return;
137964
+ const documentFailure = getDocumentTranslationFailureMessage(nextResult);
137417
137965
  setResult(nextResult);
137966
+ if (documentFailure) {
137967
+ setError(documentFailure);
137968
+ setStatus("error");
137969
+ return;
137970
+ }
137418
137971
  setStatus("translated");
137419
137972
  } catch (translationError) {
137420
- if (controller.signal.aborted) return;
137973
+ if (controller.signal.aborted || abortRef.current !== controller || generationRef.current !== generationId) return;
137421
137974
  setError(translationError instanceof Error ? translationError.message : "Translation failed.");
137422
137975
  setStatus("error");
137423
137976
  } finally {
137424
- if (abortRef.current === controller) abortRef.current = null;
137977
+ if (abortRef.current === controller && generationRef.current === generationId) abortRef.current = null;
137425
137978
  }
137426
137979
  }, [
137427
137980
  browserSupportTable,
@@ -137462,6 +138015,14 @@ function useDocumentTranslation(markdown, config) {
137462
138015
  reset
137463
138016
  };
137464
138017
  }
138018
+ function getDocumentTranslationFailureMessage(result) {
138019
+ const segments = (Array.isArray(result.segments) ? result.segments : []).filter((segment) => segment !== void 0);
138020
+ if (segments.length === 0) return null;
138021
+ if (segments.some((segment) => segment.status !== "error" && typeof segment.target === "string")) return null;
138022
+ const errors = segments.map((segment) => segment.status === "error" ? segment.error : void 0).filter((message) => typeof message === "string" && message.length > 0);
138023
+ if (errors.length === 0) return null;
138024
+ return errors[0] ?? "Translation failed.";
138025
+ }
137465
138026
  function applyDocumentTranslationPatch(current, patch, fallback) {
137466
138027
  const segments = [...current?.segments ?? []];
137467
138028
  segments[patch.segmentIndex] = patch.segment;
@@ -148246,7 +148807,8 @@ function stripOpenSpecHeadingKindFromTextNode(node, kind, state) {
148246
148807
  //#endregion
148247
148808
  //#region src/components/document-translation-action.tsx
148248
148809
  function useDocumentTranslationRenderPlugin({ markdown, translationConfig }) {
148249
- const resolvedTranslationConfig = (0, import_react.useMemo)(() => translationConfig === void 0 ? void 0 : DocumentTranslationConfigSchema.parse(translationConfig), [translationConfig]);
148810
+ const { data: globalSettings } = useGlobalSettingsSubscription();
148811
+ const resolvedTranslationConfig = (0, import_react.useMemo)(() => translationConfig === void 0 ? void 0 : DocumentTranslationConfigSchema.parse(resolveDocumentTranslationConfig(translationConfig, globalSettings)), [globalSettings, translationConfig]);
148250
148812
  const session = useDocumentTranslation(markdown ?? "", resolvedTranslationConfig);
148251
148813
  const canTranslate = resolvedTranslationConfig !== void 0 && typeof markdown === "string" && markdown.length > 0;
148252
148814
  const translationProjection = (0, import_react.useMemo)(() => createTranslationProjection(session.result), [session.result]);
@@ -148286,6 +148848,7 @@ function DocumentTranslationAction({ enabled, session }) {
148286
148848
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DocumentTranslationButton, {
148287
148849
  capability: session.capability,
148288
148850
  enabled,
148851
+ error: session.error,
148289
148852
  serviceStatus: session.serviceStatus,
148290
148853
  status: session.status,
148291
148854
  onActivate: () => {
@@ -148319,7 +148882,8 @@ function hashString(value) {
148319
148882
  }
148320
148883
  function createTranslationProjection(result) {
148321
148884
  if (!result) return { blockAnnotations: [] };
148322
- const segmentByOffset = new Map(result.segments.filter((segment) => segment.target).map((segment) => [segment.sourceStartOffset, segment]));
148885
+ const segments = Array.isArray(result.segments) ? result.segments : [];
148886
+ const segmentByOffset = new Map(segments.filter((segment) => segment.target).map((segment) => [segment.sourceStartOffset, segment]));
148323
148887
  return {
148324
148888
  headingProcessor: {
148325
148889
  name: "document-translation",
@@ -148341,7 +148905,7 @@ function createTranslationProjection(result) {
148341
148905
  return createTranslatedHeadingTransform(input, segment, result.displayMode);
148342
148906
  }
148343
148907
  },
148344
- blockAnnotations: result.segments.filter((segment) => segment.target && segment.kind !== "heading").map((segment) => ({
148908
+ blockAnnotations: segments.filter((segment) => segment.target && segment.kind !== "heading").map((segment) => ({
148345
148909
  sourceStartOffset: segment.sourceStartOffset,
148346
148910
  sourceKind: segment.sourceKind,
148347
148911
  className: result.displayMode === "direct" ? "document-translation-direct" : "document-translation-bilingual",
@@ -148440,28 +149004,31 @@ function sanitizeTranslatedProperties(properties) {
148440
149004
  }
148441
149005
  return nextProperties;
148442
149006
  }
148443
- function DocumentTranslationButton({ capability, enabled, serviceStatus, status, onActivate }) {
149007
+ function DocumentTranslationButton({ capability, enabled, error, serviceStatus, status, onActivate }) {
148444
149008
  const isServiceChecking = serviceStatus.state === "checking";
148445
149009
  const isServiceUnavailable = serviceStatus.state === "unavailable" || status === "unavailable";
148446
149010
  const isSettingsDisabled = !enabled;
148447
149011
  const isTranslated = status === "translated";
148448
149012
  const isBusy = status === "initializing" || status === "translating";
148449
- const ariaLabel = isServiceUnavailable ? "Translation unavailable" : isSettingsDisabled ? "Configure translation" : isServiceChecking ? "Checking translation" : isBusy ? "Cancel translation" : isTranslated ? "Show source" : "Translate";
148450
- const title = isServiceUnavailable ? serviceStatus.message ?? capability?.message ?? "Translation is unavailable." : isSettingsDisabled ? "Translation is disabled in settings." : ariaLabel;
148451
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
148452
- size: "icon-sm",
148453
- variant: "secondary",
148454
- disabled: isServiceUnavailable || isServiceChecking,
148455
- "aria-disabled": isSettingsDisabled ? true : void 0,
148456
- onClick: (event) => {
148457
- event.stopPropagation();
148458
- onActivate();
148459
- },
148460
- title,
148461
- "aria-label": ariaLabel,
148462
- "data-translation-action-state": isServiceUnavailable ? "unavailable" : isServiceChecking ? "checking" : isSettingsDisabled ? "settings-disabled" : isBusy ? "busy" : isTranslated ? "translated" : "ready",
148463
- className: isServiceUnavailable || isServiceChecking ? "border-border bg-muted text-muted-foreground disabled:border-border disabled:bg-muted disabled:text-muted-foreground" : isSettingsDisabled ? "border-border bg-muted/40 text-muted-foreground opacity-70" : isTranslated ? "border-primary bg-primary text-primary-foreground hover:bg-primary/90" : "border-primary text-primary hover:bg-primary/10",
148464
- children: isBusy || isServiceChecking ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoaderCircle, { className: "h-4 w-4 animate-spin" }) : isServiceUnavailable ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, { className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Languages, { className: "h-4 w-4" })
149013
+ const isError = status === "error";
149014
+ const ariaLabel = isServiceUnavailable ? "Translation unavailable" : isSettingsDisabled ? "Configure translation" : isServiceChecking ? "Checking translation" : isError ? "Retry translation" : isBusy ? "Cancel translation" : isTranslated ? "Show source" : "Translate";
149015
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Tooltip, {
149016
+ content: isServiceUnavailable ? serviceStatus.message ?? capability?.message ?? "Translation is unavailable." : isSettingsDisabled ? "Translation is disabled in settings." : isError ? `${error ?? "Translation failed."} Click to retry.` : ariaLabel,
149017
+ delay: 0,
149018
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
149019
+ size: "icon-sm",
149020
+ variant: "secondary",
149021
+ disabled: isServiceUnavailable || isServiceChecking,
149022
+ "aria-disabled": isSettingsDisabled ? true : void 0,
149023
+ onClick: (event) => {
149024
+ event.stopPropagation();
149025
+ onActivate();
149026
+ },
149027
+ "aria-label": ariaLabel,
149028
+ "data-translation-action-state": isServiceUnavailable ? "unavailable" : isServiceChecking ? "checking" : isSettingsDisabled ? "settings-disabled" : isError ? "error" : isBusy ? "busy" : isTranslated ? "translated" : "ready",
149029
+ className: isServiceUnavailable || isServiceChecking ? "border-border bg-muted text-muted-foreground disabled:border-border disabled:bg-muted disabled:text-muted-foreground" : isSettingsDisabled ? "border-border bg-muted/40 text-muted-foreground opacity-70" : isError ? "border-amber-500/50 bg-amber-500/10 text-amber-600 hover:bg-amber-500/15 dark:text-amber-400" : isTranslated ? "border-primary bg-primary text-primary-foreground hover:bg-primary/90" : "border-primary text-primary hover:bg-primary/10",
149030
+ children: isBusy || isServiceChecking ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoaderCircle, { className: "h-4 w-4 animate-spin" }) : isServiceUnavailable || isError ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, { className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Languages, { className: "h-4 w-4" })
149031
+ })
148465
149032
  });
148466
149033
  }
148467
149034
  //#endregion
@@ -150423,6 +150990,575 @@ var viewerStyles = String.raw`
150423
150990
  /* MarkdownViewer keeps layout hooks local; shared ToC geometry lives in index.css. */
150424
150991
  `;
150425
150992
  //#endregion
150993
+ //#region src/lib/file-preview.ts
150994
+ async function prepareEntityFilePreview(input) {
150995
+ if (isStaticMode()) return null;
150996
+ const preview = await (input.archived ? trpcClient.archive.prepareFilePreview.query({
150997
+ id: input.changeId,
150998
+ path: input.path
150999
+ }) : trpcClient.change.prepareFilePreview.query({
151000
+ id: input.changeId,
151001
+ path: input.path
151002
+ }));
151003
+ const apiBaseUrl = getApiBaseUrl();
151004
+ if (!apiBaseUrl) return preview;
151005
+ const prefix = (path) => `${apiBaseUrl}${path}`;
151006
+ return {
151007
+ ...preview,
151008
+ resourcePathname: preview.resourcePathname ? prefix(preview.resourcePathname) : null,
151009
+ entryPathname: prefix(preview.entryPathname),
151010
+ urlPath: prefix(preview.urlPath)
151011
+ };
151012
+ }
151013
+ async function writeEntityFile(input) {
151014
+ if (input.archived) {
151015
+ await trpcClient.archive.writeFile.mutate({
151016
+ id: input.changeId,
151017
+ path: input.path,
151018
+ content: input.content
151019
+ });
151020
+ return;
151021
+ }
151022
+ await trpcClient.change.writeFile.mutate({
151023
+ id: input.changeId,
151024
+ path: input.path,
151025
+ content: input.content
151026
+ });
151027
+ }
151028
+ //#endregion
151029
+ //#region src/components/folder-editor-viewer.tsx
151030
+ function isFileEntry(file) {
151031
+ return file?.type === "file";
151032
+ }
151033
+ function isTextLikeFile(file) {
151034
+ return isFileEntry(file) && file.content !== void 0 && file.content !== null;
151035
+ }
151036
+ function normalizeExplorerFile(file) {
151037
+ return {
151038
+ ...file,
151039
+ content: file.content ?? void 0
151040
+ };
151041
+ }
151042
+ function canPreviewInline(file) {
151043
+ return isFileEntry(file) && file.previewKind === "markdown";
151044
+ }
151045
+ function canPreviewRemote(file) {
151046
+ return isFileEntry(file) && [
151047
+ "html",
151048
+ "image",
151049
+ "audio",
151050
+ "video",
151051
+ "pdf"
151052
+ ].includes(file.previewKind ?? "");
151053
+ }
151054
+ function canPreviewFile(file) {
151055
+ return canPreviewInline(file) || canPreviewRemote(file);
151056
+ }
151057
+ function isPreviewOnlyFile(file) {
151058
+ return isFileEntry(file) && [
151059
+ "image",
151060
+ "audio",
151061
+ "video",
151062
+ "pdf"
151063
+ ].includes(file.previewKind ?? "");
151064
+ }
151065
+ function resolveDefaultMode(file, inStaticMode) {
151066
+ if (!file) return "read";
151067
+ if (!inStaticMode && isFileEntry(file) && file.previewKind === "html") return "preview";
151068
+ if (!inStaticMode && isPreviewOnlyFile(file)) return "preview";
151069
+ return "read";
151070
+ }
151071
+ function resolveRemotePreviewFrameStyle(frameHeight) {
151072
+ if (frameHeight == null) return void 0;
151073
+ return {
151074
+ minHeight: "min(320px, 100%)",
151075
+ height: "100%",
151076
+ maxHeight: `${frameHeight}px`
151077
+ };
151078
+ }
151079
+ function canSaveDraft(file, hasDirtyDraft, savingPath) {
151080
+ return !!file && hasDirtyDraft && savingPath !== file.path;
151081
+ }
151082
+ function appendPreviewTheme(url, isDarkMode) {
151083
+ const nextUrl = new URL(url, window.location.href);
151084
+ nextUrl.searchParams.set("theme", isDarkMode ? "dark" : "light");
151085
+ return nextUrl.toString();
151086
+ }
151087
+ function resolvePreviewFrameUrl(preview, isDarkMode) {
151088
+ return preview.previewKind === "html" ? preview.urlPath : appendPreviewTheme(preview.urlPath, isDarkMode);
151089
+ }
151090
+ function triggerDownload(url, fileName) {
151091
+ const anchor = document.createElement("a");
151092
+ anchor.href = url;
151093
+ anchor.download = fileName;
151094
+ anchor.rel = "noreferrer noopener";
151095
+ anchor.click();
151096
+ }
151097
+ async function sharePreview(input) {
151098
+ if (navigator.share) {
151099
+ await navigator.share({
151100
+ title: input.title,
151101
+ url: input.url
151102
+ });
151103
+ return true;
151104
+ }
151105
+ await navigator.clipboard.writeText(input.url);
151106
+ return false;
151107
+ }
151108
+ function PreviewPane({ file, preview, loading, error, className = "", frameHeight, isDarkMode }) {
151109
+ if (file.previewKind === "markdown") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
151110
+ className: `h-full min-h-0 flex-1 overflow-hidden ${className}`,
151111
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MarkdownViewer, {
151112
+ markdown: file.content ?? "",
151113
+ path: file.path,
151114
+ className: "h-full"
151115
+ })
151116
+ });
151117
+ if (loading) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
151118
+ className: "text-muted-foreground flex h-full items-center justify-center gap-2 text-sm",
151119
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoaderCircle, { className: "h-4 w-4 animate-spin" }), "Preparing preview..."]
151120
+ });
151121
+ if (error) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
151122
+ className: "text-destructive flex h-full items-center justify-center px-4 text-sm",
151123
+ children: error
151124
+ });
151125
+ if (!preview) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
151126
+ className: "text-muted-foreground flex h-full items-center justify-center px-4 text-sm",
151127
+ children: "Preview unavailable."
151128
+ });
151129
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
151130
+ className: `bg-background h-full min-h-0 overflow-hidden ${className}`,
151131
+ style: resolveRemotePreviewFrameStyle(frameHeight),
151132
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("iframe", {
151133
+ src: resolvePreviewFrameUrl(preview, isDarkMode),
151134
+ title: `Preview ${file.path}`,
151135
+ className: "block h-full w-full border-0"
151136
+ }, `${resolvePreviewFrameUrl(preview, isDarkMode)}:${isDarkMode ? "dark" : "light"}`)
151137
+ });
151138
+ }
151139
+ function FolderEditorViewer({ changeId, archived = false, files: providedFiles }) {
151140
+ const inStaticMode = isStaticMode();
151141
+ const isDarkMode = useDarkMode();
151142
+ const { data: files, isLoading, error } = archived ? useArchiveFilesSubscription(changeId) : useChangeFilesSubscription(changeId);
151143
+ const [selectedPath, setSelectedPath] = (0, import_react.useState)(null);
151144
+ const [mode, setMode] = (0, import_react.useState)("read");
151145
+ const [draftContent, setDraftContent] = (0, import_react.useState)({});
151146
+ const [savingPath, setSavingPath] = (0, import_react.useState)(null);
151147
+ const [previewByPath, setPreviewByPath] = (0, import_react.useState)({});
151148
+ const [previewLoadingPath, setPreviewLoadingPath] = (0, import_react.useState)(null);
151149
+ const [previewErrorByPath, setPreviewErrorByPath] = (0, import_react.useState)({});
151150
+ const [previewMaximized, setPreviewMaximized] = (0, import_react.useState)(false);
151151
+ const [shareFeedback, setShareFeedback] = (0, import_react.useState)(null);
151152
+ const sortedEntries = (0, import_react.useMemo)(() => {
151153
+ if (providedFiles) return [...providedFiles];
151154
+ if (!files) return [];
151155
+ return [...files];
151156
+ }, [files, providedFiles]);
151157
+ const activeFile = (0, import_react.useMemo)(() => {
151158
+ if (!selectedPath) return null;
151159
+ const entry = sortedEntries.find((item) => item.path === selectedPath);
151160
+ return isFileEntry(entry) ? entry : null;
151161
+ }, [selectedPath, sortedEntries]);
151162
+ const activeDraft = activeFile ? draftContent[activeFile.path] ?? activeFile.content ?? "" : "";
151163
+ const editEnabled = !inStaticMode && isTextLikeFile(activeFile) && !isPreviewOnlyFile(activeFile);
151164
+ const readEnabled = !isPreviewOnlyFile(activeFile);
151165
+ const previewEnabled = !inStaticMode && canPreviewFile(activeFile);
151166
+ const hasDirtyDraft = !!activeFile && isTextLikeFile(activeFile) && activeDraft !== (activeFile.content ?? "");
151167
+ (0, import_react.useEffect)(() => {
151168
+ if (!sortedEntries.length) {
151169
+ setSelectedPath(null);
151170
+ return;
151171
+ }
151172
+ if (!sortedEntries.find((entry) => entry.path === selectedPath && entry.type === "file")) setSelectedPath(sortedEntries.find((entry) => entry.type === "file")?.path ?? null);
151173
+ }, [sortedEntries, selectedPath]);
151174
+ (0, import_react.useEffect)(() => {
151175
+ const nextDefaultMode = resolveDefaultMode(activeFile, inStaticMode);
151176
+ if (mode === "edit" && !editEnabled) {
151177
+ setMode(nextDefaultMode);
151178
+ return;
151179
+ }
151180
+ if (mode === "preview" && !previewEnabled) {
151181
+ setMode(nextDefaultMode);
151182
+ return;
151183
+ }
151184
+ if (mode === "read" && !readEnabled) setMode(nextDefaultMode);
151185
+ }, [
151186
+ activeFile,
151187
+ editEnabled,
151188
+ inStaticMode,
151189
+ mode,
151190
+ previewEnabled,
151191
+ readEnabled
151192
+ ]);
151193
+ (0, import_react.useEffect)(() => {
151194
+ const nextDefaultMode = resolveDefaultMode(activeFile, inStaticMode);
151195
+ setMode((currentMode) => {
151196
+ if (currentMode === nextDefaultMode) return currentMode;
151197
+ if (currentMode === "read" && nextDefaultMode === "preview") return nextDefaultMode;
151198
+ if (currentMode === "edit" && editEnabled) return currentMode;
151199
+ if (currentMode === "preview" && previewEnabled) return currentMode;
151200
+ if (currentMode === "read" && readEnabled) return currentMode;
151201
+ return nextDefaultMode;
151202
+ });
151203
+ }, [
151204
+ activeFile?.path,
151205
+ editEnabled,
151206
+ inStaticMode,
151207
+ previewEnabled,
151208
+ readEnabled
151209
+ ]);
151210
+ (0, import_react.useEffect)(() => {
151211
+ if (!canPreviewRemote(activeFile) || mode !== "preview") setPreviewMaximized(false);
151212
+ }, [activeFile, mode]);
151213
+ (0, import_react.useEffect)(() => {
151214
+ if (shareFeedback === null) return;
151215
+ const timer = window.setTimeout(() => {
151216
+ setShareFeedback(null);
151217
+ }, 1800);
151218
+ return () => {
151219
+ window.clearTimeout(timer);
151220
+ };
151221
+ }, [shareFeedback]);
151222
+ (0, import_react.useEffect)(() => {
151223
+ if (!activeFile || mode !== "preview" || !canPreviewRemote(activeFile)) return;
151224
+ if (previewByPath[activeFile.path] !== void 0) return;
151225
+ let cancelled = false;
151226
+ setPreviewLoadingPath(activeFile.path);
151227
+ setPreviewErrorByPath((current) => ({
151228
+ ...current,
151229
+ [activeFile.path]: null
151230
+ }));
151231
+ prepareEntityFilePreview({
151232
+ changeId,
151233
+ archived,
151234
+ path: activeFile.path
151235
+ }).then((preview) => {
151236
+ if (cancelled) return;
151237
+ setPreviewByPath((current) => ({
151238
+ ...current,
151239
+ [activeFile.path]: preview
151240
+ }));
151241
+ }).catch((cause) => {
151242
+ if (cancelled) return;
151243
+ setPreviewErrorByPath((current) => ({
151244
+ ...current,
151245
+ [activeFile.path]: cause instanceof Error ? cause.message : String(cause)
151246
+ }));
151247
+ setPreviewByPath((current) => ({
151248
+ ...current,
151249
+ [activeFile.path]: null
151250
+ }));
151251
+ }).finally(() => {
151252
+ if (cancelled) return;
151253
+ setPreviewLoadingPath((current) => current === activeFile.path ? null : current);
151254
+ });
151255
+ return () => {
151256
+ cancelled = true;
151257
+ };
151258
+ }, [
151259
+ activeFile,
151260
+ archived,
151261
+ changeId,
151262
+ mode,
151263
+ previewByPath
151264
+ ]);
151265
+ if (!providedFiles && isLoading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
151266
+ className: "bg-muted/20 flex h-[400px] items-center justify-center",
151267
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoaderCircle, { className: "text-muted-foreground h-6 w-6 animate-spin" })
151268
+ });
151269
+ if (error) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
151270
+ className: "bg-destructive/10 text-destructive p-4 text-sm",
151271
+ children: ["Failed to load files: ", error.message]
151272
+ });
151273
+ const preview = activeFile ? previewByPath[activeFile.path] ?? null : null;
151274
+ const previewError = activeFile ? previewErrorByPath[activeFile.path] ?? null : null;
151275
+ const previewDownloadUrl = activeFile && preview ? activeFile.previewKind === "html" ? preview.entryPathname : preview.resourcePathname : null;
151276
+ const previewShareUrl = activeFile && preview && canPreviewRemote(activeFile) ? resolvePreviewFrameUrl(preview, isDarkMode) : null;
151277
+ const saveActiveDraft = () => {
151278
+ if (!isTextLikeFile(activeFile)) return;
151279
+ if (!canSaveDraft(activeFile, hasDirtyDraft, savingPath)) return;
151280
+ setSavingPath(activeFile.path);
151281
+ writeEntityFile({
151282
+ changeId,
151283
+ archived,
151284
+ path: activeFile.path,
151285
+ content: activeDraft
151286
+ }).finally(() => {
151287
+ setSavingPath((current) => current === activeFile.path ? null : current);
151288
+ });
151289
+ };
151290
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
151291
+ "data-tab-scroll-root": "true",
151292
+ className: "min-h-0 flex-1 overflow-hidden",
151293
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
151294
+ className: "h-full min-h-0 pr-1",
151295
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
151296
+ "data-folder-viewport": "",
151297
+ className: "flex h-full min-h-0 flex-col overflow-hidden",
151298
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileExplorer, {
151299
+ entries: sortedEntries,
151300
+ selectedPath,
151301
+ onSelect: setSelectedPath,
151302
+ emptyState: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "No files found for this change." }),
151303
+ renderEditor: (currentFile) => {
151304
+ if (!isFileEntry(currentFile)) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
151305
+ className: "text-muted-foreground flex h-full items-center justify-center",
151306
+ children: "Select a file to view"
151307
+ });
151308
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
151309
+ className: "flex min-h-0 flex-1 flex-col",
151310
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
151311
+ "data-folder-toolbar": "",
151312
+ className: "border-border/60 bg-muted/20 flex flex-wrap items-center gap-3 border-b px-3 py-2",
151313
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ButtonGroup, {
151314
+ value: mode,
151315
+ onChange: setMode,
151316
+ presentation: "icon-only",
151317
+ className: "min-w-0",
151318
+ options: [
151319
+ {
151320
+ value: "read",
151321
+ label: "Read",
151322
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ScrollText, { className: "h-3.5 w-3.5" }),
151323
+ ariaLabel: "Read",
151324
+ tooltip: "Read",
151325
+ disabled: !readEnabled
151326
+ },
151327
+ {
151328
+ value: "edit",
151329
+ label: "Edit",
151330
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FilePenLine, { className: "h-3.5 w-3.5" }),
151331
+ ariaLabel: "Edit",
151332
+ tooltip: "Edit",
151333
+ disabled: !editEnabled
151334
+ },
151335
+ {
151336
+ value: "preview",
151337
+ label: "Preview",
151338
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Eye, { className: "h-3.5 w-3.5" }),
151339
+ ariaLabel: "Preview",
151340
+ tooltip: "Preview",
151341
+ disabled: !previewEnabled
151342
+ }
151343
+ ]
151344
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
151345
+ "data-folder-toolbar-actions": "",
151346
+ className: "ml-auto flex min-w-0 max-w-full flex-wrap items-center justify-end gap-2",
151347
+ children: mode === "edit" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Tooltip, {
151348
+ content: "Revert",
151349
+ delay: 0,
151350
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
151351
+ variant: "secondary",
151352
+ size: "icon-sm",
151353
+ "aria-label": "Revert",
151354
+ title: "Revert",
151355
+ disabled: !hasDirtyDraft,
151356
+ onClick: () => {
151357
+ if (!isTextLikeFile(activeFile)) return;
151358
+ setDraftContent((current) => ({
151359
+ ...current,
151360
+ [activeFile.path]: activeFile.content ?? ""
151361
+ }));
151362
+ },
151363
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Undo2, { className: "h-3.5 w-3.5" })
151364
+ })
151365
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Tooltip, {
151366
+ content: "Save",
151367
+ delay: 0,
151368
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
151369
+ variant: "primary",
151370
+ size: "icon-sm",
151371
+ "aria-label": "Save",
151372
+ title: "Save",
151373
+ disabled: !hasDirtyDraft || savingPath === currentFile.path,
151374
+ onClick: saveActiveDraft,
151375
+ children: savingPath === currentFile.path ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoaderCircle, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Save, { className: "h-3.5 w-3.5" })
151376
+ })
151377
+ })] }) : mode === "preview" && canPreviewRemote(activeFile) ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
151378
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Tooltip, {
151379
+ content: "Refresh",
151380
+ delay: 0,
151381
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
151382
+ variant: "secondary",
151383
+ size: "icon-sm",
151384
+ "aria-label": "Refresh",
151385
+ title: "Refresh",
151386
+ onClick: () => {
151387
+ setPreviewByPath((current) => {
151388
+ const next = { ...current };
151389
+ delete next[currentFile.path];
151390
+ return next;
151391
+ });
151392
+ },
151393
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RefreshCw, { className: "h-3.5 w-3.5" })
151394
+ })
151395
+ }),
151396
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Tooltip, {
151397
+ content: previewMaximized ? "Exit maximize" : "Maximize",
151398
+ delay: 0,
151399
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
151400
+ variant: "secondary",
151401
+ size: "icon-sm",
151402
+ "aria-label": previewMaximized ? "Exit maximize" : "Maximize",
151403
+ title: previewMaximized ? "Exit maximize" : "Maximize",
151404
+ onClick: () => {
151405
+ setPreviewMaximized((current) => !current);
151406
+ },
151407
+ children: previewMaximized ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Minimize, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Expand, { className: "h-3.5 w-3.5" })
151408
+ })
151409
+ }),
151410
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Tooltip, {
151411
+ content: "Download",
151412
+ delay: 0,
151413
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
151414
+ variant: "secondary",
151415
+ size: "icon-sm",
151416
+ "aria-label": "Download",
151417
+ title: "Download",
151418
+ disabled: !previewDownloadUrl,
151419
+ onClick: () => {
151420
+ if (!previewDownloadUrl) return;
151421
+ triggerDownload(previewDownloadUrl, currentFile.path.split("/").pop() ?? "preview");
151422
+ },
151423
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Download, { className: "h-3.5 w-3.5" })
151424
+ })
151425
+ }),
151426
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Tooltip, {
151427
+ content: shareFeedback === "shared" ? "Shared" : shareFeedback === "copied" ? "Copied" : "Share",
151428
+ delay: 0,
151429
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
151430
+ variant: "secondary",
151431
+ size: "icon-sm",
151432
+ "aria-label": shareFeedback === "shared" ? "Shared" : shareFeedback === "copied" ? "Copied" : "Share",
151433
+ title: shareFeedback === "shared" ? "Shared" : shareFeedback === "copied" ? "Copied" : "Share",
151434
+ disabled: !previewShareUrl,
151435
+ onClick: () => {
151436
+ if (!previewShareUrl) return;
151437
+ sharePreview({
151438
+ url: previewShareUrl,
151439
+ title: currentFile.path
151440
+ }).then((shared) => {
151441
+ setShareFeedback(shared ? "shared" : "copied");
151442
+ });
151443
+ },
151444
+ children: shareFeedback === "shared" || shareFeedback === "copied" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Check, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Share2, { className: "h-3.5 w-3.5" })
151445
+ })
151446
+ })
151447
+ ] }) : null
151448
+ })]
151449
+ }), !readEnabled && !editEnabled && !previewEnabled ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
151450
+ className: "text-muted-foreground flex min-h-0 flex-1 items-center justify-center px-4 text-sm",
151451
+ children: "Preview for this file type is only available in live mode."
151452
+ }) : mode === "preview" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
151453
+ className: "min-h-0 flex-1 overflow-hidden",
151454
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PreviewPane, {
151455
+ file: currentFile,
151456
+ preview,
151457
+ loading: previewLoadingPath === currentFile.path,
151458
+ error: previewError,
151459
+ isDarkMode
151460
+ })
151461
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileExplorerCodeEditor, {
151462
+ file: normalizeExplorerFile(currentFile),
151463
+ value: mode === "edit" ? activeDraft : currentFile.content ?? "",
151464
+ readOnly: mode !== "edit",
151465
+ editorMinHeight: "0px",
151466
+ onSaveShortcut: mode === "edit" ? saveActiveDraft : void 0,
151467
+ onChange: mode === "edit" ? (value) => {
151468
+ setDraftContent((current) => ({
151469
+ ...current,
151470
+ [currentFile.path]: value
151471
+ }));
151472
+ } : void 0
151473
+ })]
151474
+ });
151475
+ }
151476
+ })
151477
+ })
151478
+ }), activeFile && canPreviewRemote(activeFile) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Dialog, {
151479
+ open: previewMaximized,
151480
+ title: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
151481
+ className: "text-sm font-medium",
151482
+ children: activeFile.path
151483
+ }),
151484
+ onClose: () => setPreviewMaximized(false),
151485
+ className: "max-w-6xl rounded-none border-0 shadow-none [--openspec-dialog-radius:0px]",
151486
+ bodyClassName: "p-0",
151487
+ contentClassName: "px-3 py-3",
151488
+ maxHeight: "96vh",
151489
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
151490
+ className: "flex h-[80vh] max-h-[88vh] min-h-[420px] min-w-0 flex-col overflow-hidden",
151491
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PreviewPane, {
151492
+ file: activeFile,
151493
+ preview,
151494
+ loading: previewLoadingPath === activeFile.path,
151495
+ error: previewError,
151496
+ className: "rounded-none",
151497
+ isDarkMode
151498
+ })
151499
+ })
151500
+ })]
151501
+ });
151502
+ }
151503
+ //#endregion
151504
+ //#region src/components/opsx/artifact-document-shell.tsx
151505
+ var statusConfig = {
151506
+ done: {
151507
+ label: "Done",
151508
+ className: "text-emerald-500",
151509
+ icon: CircleCheck
151510
+ },
151511
+ ready: {
151512
+ label: "Ready",
151513
+ className: "text-sky-500",
151514
+ icon: Circle$1
151515
+ },
151516
+ blocked: {
151517
+ label: "Blocked",
151518
+ className: "text-amber-500",
151519
+ icon: TriangleAlert
151520
+ }
151521
+ };
151522
+ function OpsxArtifactStatusBadge({ status }) {
151523
+ const config = statusConfig[status];
151524
+ const StatusIcon = config.icon;
151525
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
151526
+ className: `inline-flex shrink-0 items-center gap-1.5 text-xs font-medium ${config.className}`,
151527
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusIcon, { className: "h-4 w-4" }), config.label]
151528
+ });
151529
+ }
151530
+ function OpsxArtifactTabStatusIcon({ status }) {
151531
+ const StatusIcon = statusConfig[status].icon;
151532
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusIcon, { className: `h-3.5 w-3.5 ${statusConfig[status].className}` });
151533
+ }
151534
+ function OpsxArtifactDocumentShell({ id, path, status, missingDeps, meta, children }) {
151535
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
151536
+ className: "border-border bg-muted/25 mb-5 rounded-md border px-4 py-3",
151537
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
151538
+ className: "flex flex-wrap items-start justify-between gap-3",
151539
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
151540
+ className: "min-w-0 space-y-1",
151541
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
151542
+ className: "font-medium",
151543
+ children: id
151544
+ }), path ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
151545
+ className: "text-muted-foreground break-all text-xs",
151546
+ children: path
151547
+ }) : null]
151548
+ }), status ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(OpsxArtifactStatusBadge, { status }) : meta]
151549
+ }), status === "blocked" && missingDeps?.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
151550
+ className: "mt-3 flex items-start gap-2 rounded-md border border-amber-500/50 bg-amber-500/10 px-3 py-2 text-xs text-amber-700",
151551
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, { className: "h-4 w-4 shrink-0" }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
151552
+ className: "font-medium",
151553
+ children: "Blocked by missing dependencies"
151554
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
151555
+ className: "mt-1",
151556
+ children: missingDeps.join(", ")
151557
+ })] })]
151558
+ }) : null]
151559
+ }), children] });
151560
+ }
151561
+ //#endregion
150426
151562
  //#region src/components/opsx/opsx-markdown-files-viewer.tsx
150427
151563
  function getMarkdownFiles(files) {
150428
151564
  return files.filter((file) => file.type === "file" && file.content !== void 0 && file.path.endsWith(".md"));
@@ -150576,6 +151712,8 @@ function GlobContent({ changeId, artifact, translationConfig }) {
150576
151712
  }
150577
151713
  function ArtifactOutputViewer({ changeId, artifact }) {
150578
151714
  const { data: config } = useConfigSubscription();
151715
+ const { data: globalSettings } = useGlobalSettingsSubscription();
151716
+ const translationConfig = resolveDocumentTranslationConfig(config?.translation, globalSettings);
150579
151717
  if (artifact.files) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
150580
151718
  className: "flex min-h-0 flex-1 flex-col",
150581
151719
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
@@ -150583,25 +151721,26 @@ function ArtifactOutputViewer({ changeId, artifact }) {
150583
151721
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArtifactFilesDocumentShell, {
150584
151722
  artifact,
150585
151723
  files: artifact.files,
150586
- translationConfig: config?.translation
151724
+ translationConfig
150587
151725
  })
150588
151726
  })
150589
151727
  });
150590
151728
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LiveArtifactOutputViewer, {
150591
151729
  changeId,
150592
151730
  artifact,
150593
- translationConfig: config?.translation
151731
+ translationConfig
150594
151732
  });
150595
151733
  }
150596
151734
  function ContentFallbackViewer({ fallback }) {
150597
151735
  const { data: config } = useConfigSubscription();
151736
+ const { data: globalSettings } = useGlobalSettingsSubscription();
150598
151737
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
150599
151738
  className: "flex min-h-0 flex-1 flex-col",
150600
151739
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
150601
151740
  className: "min-h-0 flex-1",
150602
151741
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FallbackDocumentShell, {
150603
151742
  fallback,
150604
- translationConfig: config?.translation
151743
+ translationConfig: resolveDocumentTranslationConfig(config?.translation, globalSettings)
150605
151744
  })
150606
151745
  })
150607
151746
  });
@@ -151134,28 +152273,6 @@ function ChangeView() {
151134
152273
  });
151135
152274
  }
151136
152275
  //#endregion
151137
- //#region src/components/button-group.tsx
151138
- /**
151139
- * Compact segmented buttons with single-select behavior.
151140
- */
151141
- function ButtonGroup({ value, options, onChange, className = "", tone = "default" }) {
151142
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
151143
- className: `inline-flex w-fit max-w-full shrink-0 self-start overflow-hidden rounded-md border ${tone === "terminal" ? "border-terminal-foreground/25 bg-terminal/70 text-terminal-foreground" : "border-border bg-card"} ${className}`,
151144
- children: options.map((option, index) => {
151145
- const active = option.value === value;
151146
- const stateClassName = active ? "bg-primary text-primary-foreground" : tone === "terminal" ? "text-terminal-foreground/72 hover:bg-terminal-foreground/10 hover:text-terminal-foreground" : "text-muted-foreground hover:bg-muted/60 hover:text-foreground";
151147
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
151148
- type: "button",
151149
- disabled: option.disabled,
151150
- onClick: () => onChange(option.value),
151151
- "aria-pressed": active,
151152
- className: `inline-flex items-center justify-center gap-1.5 px-3 py-1.5 text-xs font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50 ${index > 0 ? tone === "terminal" ? "border-terminal-foreground/20 border-l" : "border-border border-l" : ""} ${stateClassName}`,
151153
- children: option.label
151154
- }, option.value);
151155
- })
151156
- });
151157
- }
151158
- //#endregion
151159
152276
  //#region src/components/cli-terminal.tsx
151160
152277
  /**
151161
152278
  * Pure terminal renderer. Accepts ANSI-aware ASCII lines or raw ReactNode lines.
@@ -151220,6 +152337,89 @@ function renderAnsiLine(line) {
151220
152337
  return parts.length > 0 ? parts : line;
151221
152338
  }
151222
152339
  //#endregion
152340
+ //#region src/components/scroll-spy.ts
152341
+ function hasVerticalScrollBehavior(overflowY) {
152342
+ return overflowY === "auto" || overflowY === "scroll" || overflowY === "overlay";
152343
+ }
152344
+ function findVerticalScrollContainer(node, options = {}) {
152345
+ const { allowNonScrollable = false } = options;
152346
+ let current = node?.parentElement ?? null;
152347
+ while (current) {
152348
+ if (hasVerticalScrollBehavior(window.getComputedStyle(current).overflowY)) {
152349
+ if (allowNonScrollable || current.scrollHeight > current.clientHeight) return current;
152350
+ }
152351
+ current = current.parentElement;
152352
+ }
152353
+ return null;
152354
+ }
152355
+ function scrollViewportBounds(root) {
152356
+ if (root) {
152357
+ const rect = root.getBoundingClientRect();
152358
+ return {
152359
+ top: rect.top,
152360
+ bottom: rect.bottom
152361
+ };
152362
+ }
152363
+ return {
152364
+ top: 0,
152365
+ bottom: window.innerHeight
152366
+ };
152367
+ }
152368
+ function measureAvailableViewportHeight(node, root = findVerticalScrollContainer(node, { allowNonScrollable: true })) {
152369
+ if (typeof window === "undefined" || !node) return null;
152370
+ const nodeRect = node.getBoundingClientRect();
152371
+ const viewport = scrollViewportBounds(root);
152372
+ return Math.max(Math.floor(viewport.bottom - Math.max(nodeRect.top, viewport.top)), 0);
152373
+ }
152374
+ function useViewportConstrainedHeight({ target, enabled = true }) {
152375
+ const [height, setHeight] = (0, import_react.useState)(null);
152376
+ (0, import_react.useLayoutEffect)(() => {
152377
+ if (!enabled || typeof window === "undefined") {
152378
+ setHeight(null);
152379
+ return;
152380
+ }
152381
+ if (!target) {
152382
+ setHeight(null);
152383
+ return;
152384
+ }
152385
+ let resizeObserver = null;
152386
+ let scrollRoot = null;
152387
+ let scrollTarget = window;
152388
+ const setConstrainedHeight = (nextHeight) => {
152389
+ setHeight((currentHeight) => currentHeight === nextHeight ? currentHeight : nextHeight);
152390
+ };
152391
+ const bindScrollRoot = (nextRoot) => {
152392
+ if (scrollRoot === nextRoot) return;
152393
+ scrollTarget.removeEventListener("scroll", handleUpdate);
152394
+ if (resizeObserver && scrollRoot) resizeObserver.unobserve(scrollRoot);
152395
+ scrollRoot = nextRoot;
152396
+ scrollTarget = nextRoot ?? window;
152397
+ scrollTarget.addEventListener("scroll", handleUpdate, { passive: true });
152398
+ if (resizeObserver && scrollRoot) resizeObserver.observe(scrollRoot);
152399
+ };
152400
+ const handleUpdate = () => {
152401
+ const nextRoot = findVerticalScrollContainer(target, { allowNonScrollable: true });
152402
+ bindScrollRoot(nextRoot);
152403
+ setConstrainedHeight(measureAvailableViewportHeight(target, nextRoot));
152404
+ };
152405
+ if (typeof ResizeObserver !== "undefined") {
152406
+ resizeObserver = new ResizeObserver(() => {
152407
+ handleUpdate();
152408
+ });
152409
+ resizeObserver.observe(target);
152410
+ if (target.parentElement) resizeObserver.observe(target.parentElement);
152411
+ }
152412
+ handleUpdate();
152413
+ window.addEventListener("resize", handleUpdate);
152414
+ return () => {
152415
+ window.removeEventListener("resize", handleUpdate);
152416
+ scrollTarget.removeEventListener("scroll", handleUpdate);
152417
+ resizeObserver?.disconnect();
152418
+ };
152419
+ }, [enabled, target]);
152420
+ return height;
152421
+ }
152422
+ //#endregion
151223
152423
  //#region ../../node_modules/.pnpm/@base-ui+utils@0.2.6_@types+react@19.2.7_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/@base-ui/utils/esm/useControlled.js
151224
152424
  function useControlled({ controlled, default: defaultProp, name, state = "value" }) {
151225
152425
  const { current: isControlled } = import_react.useRef(controlled !== void 0);
@@ -158067,6 +159267,8 @@ function SpecView() {
158067
159267
  const { data: spec, isLoading } = useSpecSubscription(specId);
158068
159268
  const { data: rawMarkdown, isLoading: isRawLoading } = useSpecRawSubscription(specId);
158069
159269
  const { data: config } = useConfigSubscription();
159270
+ const { data: globalSettings } = useGlobalSettingsSubscription();
159271
+ const translationConfig = (0, import_react.useMemo)(() => resolveDocumentTranslationConfig(config?.translation, globalSettings), [config?.translation, globalSettings]);
158070
159272
  const validation = null;
158071
159273
  if (isLoading && !spec || isRawLoading && !rawMarkdown) {
158072
159274
  if (handoff) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
@@ -158112,7 +159314,7 @@ function SpecView() {
158112
159314
  spec,
158113
159315
  rawMarkdown: rawMarkdown ?? "",
158114
159316
  validation,
158115
- translationConfig: config?.translation
159317
+ translationConfig
158116
159318
  });
158117
159319
  }
158118
159320
  function SpecContent({ spec, rawMarkdown, validation, translationConfig }) {