@hienlh/ppm 0.18.4 → 0.18.5

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 (426) hide show
  1. package/.release-run.sh +5 -0
  2. package/CHANGELOG.md +11 -0
  3. package/assets/skills/ppm/SKILL.md +1 -1
  4. package/assets/skills/ppm/references/cli-reference.md +4 -4
  5. package/assets/skills/ppm/references/http-api.md +1 -1
  6. package/dist/web/assets/{ai-resource-editor-Bb-NNlp1.js → ai-resource-editor-C5GpzwXP.js} +1 -1
  7. package/dist/web/assets/{angular-html-jfMqUuRd.js → angular-html-B7ZS6cwZ.js} +1 -1
  8. package/dist/web/assets/{angular-ts-wytn9PMm.js → angular-ts-CiibjfLJ.js} +1 -1
  9. package/dist/web/assets/{apl-i-ahKx6O.js → apl-DsChgbBI.js} +1 -1
  10. package/dist/web/assets/architecture-PBZL5I3N-9f0Fi2Cw.js +1 -0
  11. package/dist/web/assets/{astro-DVBCJfG6.js → astro-CcrkAzRn.js} +1 -1
  12. package/dist/web/assets/{audio-preview-DG2Tw0cO.js → audio-preview-C0m1G-ba.js} +1 -1
  13. package/dist/web/assets/{blade-BHlL8SqU.js → blade-BW0AyHqd.js} +1 -1
  14. package/dist/web/assets/{bsl-D-UOfR1F.js → bsl-D3fsZX-N.js} +1 -1
  15. package/dist/web/assets/{cairo-Bn6rucli.js → cairo-BioL0Hpg.js} +1 -1
  16. package/dist/web/assets/chat-tab-Ca-jDA8G.js +15 -0
  17. package/dist/web/assets/click-outside-container-CbfvEfTe.js +1 -0
  18. package/dist/web/assets/{cobol-Byn9FYKu.js → cobol-SQ7BUEjA.js} +1 -1
  19. package/dist/web/assets/code-editor-Biyx46no.js +10 -0
  20. package/dist/web/assets/{coffee-DjBl4gm-.js → coffee-BwiA2ABt.js} +1 -1
  21. package/dist/web/assets/{conflict-editor-B6hVffX3.js → conflict-editor-CItgFyu9.js} +1 -1
  22. package/dist/web/assets/{cpp-CKzic-3E.js → cpp-CsiyAYfZ.js} +1 -1
  23. package/dist/web/assets/{crystal-Bkg-Ly_g.js → crystal-new71ISE.js} +1 -1
  24. package/dist/web/assets/{csv-preview-hL4Z9HS5.js → csv-preview-Dz6hI2BO.js} +1 -1
  25. package/dist/web/assets/data-grid-overlay-editor-Pq5c1EeR.js +1 -0
  26. package/dist/web/assets/database-viewer-7oDAd4kH.js +1 -0
  27. package/dist/web/assets/{diff-viewer-DZxnANY4.js → diff-viewer-B-3Byzuf.js} +1 -1
  28. package/dist/web/assets/dist-BbSJO7hs.js +11 -0
  29. package/dist/web/assets/{docx-preview-CrAc7Qjv.js → docx-preview-CM9l_r9q.js} +1 -1
  30. package/dist/web/assets/{edge-DVbZnd3Y.js → edge-CtcrJXZt.js} +1 -1
  31. package/dist/web/assets/{edit-diff-preview-HTZPC9VP.js → edit-diff-preview-yY096y6H.js} +1 -1
  32. package/dist/web/assets/{elixir-Dwi8Wu7W.js → elixir-vH8AlwfK.js} +1 -1
  33. package/dist/web/assets/{elm-DtIv-HXJ.js → elm-vhtnbbrd.js} +1 -1
  34. package/dist/web/assets/{erb-D3HEDz1x.js → erb-xsqc-5NV.js} +1 -1
  35. package/dist/web/assets/{erlang-2MjTCzGz.js → erlang-CqCTsrl7.js} +1 -1
  36. package/dist/web/assets/esm-D3_gA6XW.js +2 -0
  37. package/dist/web/assets/explorer-body-DHOiBqiL.js +2 -0
  38. package/dist/web/assets/{explorer-window-content-NS8Y0v8c.js → explorer-window-content-CTBHwDgN.js} +1 -1
  39. package/dist/web/assets/{extension-webview-D6eywKPN.js → extension-webview-D3LOkB2x.js} +1 -1
  40. package/dist/web/assets/{fortran-fixed-form-BLyAtyPM.js → fortran-fixed-form-Ctm2ZKzo.js} +1 -1
  41. package/dist/web/assets/{fsharp-Bxbn_gbr.js → fsharp-DLTMpL2s.js} +1 -1
  42. package/dist/web/assets/{gdresource-sFMY4D2Q.js → gdresource-D3G0lQVG.js} +1 -1
  43. package/dist/web/assets/{git-commit-BzB9Lio5.js → git-commit-CScOErgk.js} +1 -1
  44. package/dist/web/assets/{git-log-panel-DAogZ9QV.js → git-log-panel-Bs9ShnYL.js} +1 -1
  45. package/dist/web/assets/{git-rebase-CKSVd848.js → git-rebase-C1SMSliG.js} +1 -1
  46. package/dist/web/assets/gitGraph-HDMCJU4V-B25fnH9y.js +1 -0
  47. package/dist/web/assets/glide-data-grid-DhqJzEAm.js +138 -0
  48. package/dist/web/assets/{glimmer-js-BY8aExAJ.js → glimmer-js-DsQZnICF.js} +1 -1
  49. package/dist/web/assets/{glimmer-ts-Bak54dBX.js → glimmer-ts-DrhpAdWj.js} +1 -1
  50. package/dist/web/assets/{glsl-nR2eaJQe.js → glsl-eYL0pYVx.js} +1 -1
  51. package/dist/web/assets/{graphql-CGPPFAU6.js → graphql-DBRFyWue.js} +1 -1
  52. package/dist/web/assets/group-chat-tab-CwaKPj6c.js +1 -0
  53. package/dist/web/assets/{hack-CXIMX-Ol.js → hack-CMqVlAxr.js} +1 -1
  54. package/dist/web/assets/{haml-tPY-9Pfm.js → haml-GfSHNbBz.js} +1 -1
  55. package/dist/web/assets/{handlebars-BuW1LT7T.js → handlebars-rg_XF64o.js} +1 -1
  56. package/dist/web/assets/{html-bgVcwZ-t.js → html-BEmGwpcK.js} +1 -1
  57. package/dist/web/assets/{html-derivative-D6-IxTgn.js → html-derivative-BIu-fSXa.js} +1 -1
  58. package/dist/web/assets/{http-CJ1zyB-h.js → http-DpxX0ibD.js} +1 -1
  59. package/dist/web/assets/{hurl-CmoT7l3T.js → hurl-DUVEpqRc.js} +1 -1
  60. package/dist/web/assets/{hxml-CztOsL8o.js → hxml-BrTwgLjo.js} +1 -1
  61. package/dist/web/assets/{image-preview-Byjx8MoL.js → image-preview-BLDXptaD.js} +1 -1
  62. package/dist/web/assets/index-CtGTj9re.js +52 -0
  63. package/dist/web/assets/index-oxsyfDa0.css +2 -0
  64. package/dist/web/assets/info-3K5VOQVL-Dqg_TKq-.js +1 -0
  65. package/dist/web/assets/{jinja-B1pq3jJq.js → jinja-x3_G86rb.js} +1 -1
  66. package/dist/web/assets/{jison-D8B5pCwA.js → jison-4I0KPKa0.js} +1 -1
  67. package/dist/web/assets/{julia-D0K3bwpU.js → julia-DIztIJlK.js} +1 -1
  68. package/dist/web/assets/{just-B9Jlddu-.js → just-CIbbsxt1.js} +1 -1
  69. package/dist/web/assets/keybindings-store-BgBfamMQ.js +1 -0
  70. package/dist/web/assets/{latex-BPJSSE6j.js → latex-BSW7Iz55.js} +1 -1
  71. package/dist/web/assets/{liquid-lv10fo4U.js → liquid-DXEQy61g.js} +1 -1
  72. package/dist/web/assets/{lua-PNuaIBEF.js → lua-mPzZWOOd.js} +1 -1
  73. package/dist/web/assets/{markdown-renderer-CXlEe3ma.js → markdown-renderer-IZiQd8mi.js} +3 -3
  74. package/dist/web/assets/markdown-renderer-PTkraBMz.js +1 -0
  75. package/dist/web/assets/{marko-Du3frD6X.js → marko-DT4otfeN.js} +1 -1
  76. package/dist/web/assets/{mdc-BeDVcFRl.js → mdc-DF7GteQU.js} +1 -1
  77. package/dist/web/assets/{mobile-explorer-sheet-BuqBlP3o.js → mobile-explorer-sheet-BQ7FISPT.js} +1 -1
  78. package/dist/web/assets/{nextflow-DkcXP71s.js → nextflow-inS4q6JA.js} +1 -1
  79. package/dist/web/assets/{nginx-C5n8N_bt.js → nginx-C4sxDsIU.js} +1 -1
  80. package/dist/web/assets/{nim-CIhyfs-A.js → nim-B_KZbdbl.js} +1 -1
  81. package/dist/web/assets/notification-store-Cd1oQeCL.js +1 -0
  82. package/dist/web/assets/{number-overlay-editor-NgOsWJ7x.js → number-overlay-editor-J9_h14Jy.js} +1 -1
  83. package/dist/web/assets/packet-RMMSAZCW-91mSm_sq.js +1 -0
  84. package/dist/web/assets/{pdf-preview-F2DWVB85.js → pdf-preview-D_QDoRAJ.js} +1 -1
  85. package/dist/web/assets/{perl-Cf31sZYE.js → perl-Bzur_Tvg.js} +1 -1
  86. package/dist/web/assets/{php-Dzl_MDIW.js → php-BjcXxjIr.js} +1 -1
  87. package/dist/web/assets/pie-UPGHQEXC-D5-d4-hV.js +1 -0
  88. package/dist/web/assets/postgres-viewer-CHrw1Asz.js +3 -0
  89. package/dist/web/assets/{pug-CxSYHrB3.js → pug-DFgERppY.js} +1 -1
  90. package/dist/web/assets/{qml-DlEjGhwN.js → qml-CTl3rUgs.js} +1 -1
  91. package/dist/web/assets/radar-KQ55EAFF-D_wSb0Qz.js +1 -0
  92. package/dist/web/assets/{razor-KVt5uW14.js → razor-B8YTmkEh.js} +1 -1
  93. package/dist/web/assets/{rst-D5BwNTnw.js → rst-KkcstADZ.js} +1 -1
  94. package/dist/web/assets/{ruby-D5fejQwd.js → ruby-BkGX_9bp.js} +1 -1
  95. package/dist/web/assets/{sas-Bj7B1CB2.js → sas-CXAPcIB7.js} +1 -1
  96. package/dist/web/assets/{scss-BB0CUoCL.js → scss-BstsOLPG.js} +1 -1
  97. package/dist/web/assets/{settings-store-CY-4_U3H.js → settings-store-DQcBuCyF.js} +2 -2
  98. package/dist/web/assets/{settings-tab-Khj-w6Sr.js → settings-tab-CsevraI7.js} +1 -1
  99. package/dist/web/assets/{shaderlab-BdjEZUMc.js → shaderlab-w3VeqhHk.js} +1 -1
  100. package/dist/web/assets/{shellsession-Bp1OA1rR.js → shellsession-CM2BxxEn.js} +1 -1
  101. package/dist/web/assets/{soy-DlYz3wsC.js → soy-1-aTOd4S.js} +1 -1
  102. package/dist/web/assets/{sparql-CdfII5Jd.js → sparql-CqmJ7XJo.js} +1 -1
  103. package/dist/web/assets/{sql-query-editor-Cp0_e2P1.js → sql-query-editor-CzOTxy85.js} +1 -1
  104. package/dist/web/assets/sqlite-viewer-COHO7wsr.js +1 -0
  105. package/dist/web/assets/{stata-BvUA6GUW.js → stata-BbcHuOrm.js} +1 -1
  106. package/dist/web/assets/{surrealql--DLNbTyI.js → surrealql-DYt8SBBH.js} +1 -1
  107. package/dist/web/assets/{svelte-CBfSsG4n.js → svelte-CBrmuJZk.js} +1 -1
  108. package/dist/web/assets/{system-monitor-tab-CrssTOf4.js → system-monitor-tab-CS9DhJrA.js} +1 -1
  109. package/dist/web/assets/{team-member-window-content-D-hXax3c.js → team-member-window-content-DSlnO1ay.js} +1 -1
  110. package/dist/web/assets/{templ-Dv8zpKZW.js → templ-BWg_73eT.js} +1 -1
  111. package/dist/web/assets/{terminal-tab-BIQDG-Ti.js → terminal-tab-DCOinj6h.js} +3 -3
  112. package/dist/web/assets/{tex-CsrOiqh1.js → tex-ChwnYbaL.js} +1 -1
  113. package/dist/web/assets/tool-cards-DYQChJ7V.js +8 -0
  114. package/dist/web/assets/treemap-KZPCXAKY-DiNFF0Uo.js +1 -0
  115. package/dist/web/assets/{ts-tags-3T98k4EJ.js → ts-tags-CFZZJcMc.js} +1 -1
  116. package/dist/web/assets/{twig-u6QZ45FH.js → twig-DbRbrfbf.js} +1 -1
  117. package/dist/web/assets/{use-monaco-theme-Djp1_fKi.js → use-monaco-theme-DcRjryA0.js} +1 -1
  118. package/dist/web/assets/{use-websocket-CCYA9-a2.js → use-websocket-CX3F55gy.js} +1 -1
  119. package/dist/web/assets/{vendor-mermaid-Bg4vE8QA.js → vendor-mermaid-Dede75gn.js} +193 -193
  120. package/dist/web/assets/video-preview-DaYONH41.js +1 -0
  121. package/dist/web/assets/{vue-html-BGL5qnuH.js → vue-html-vP_PPbWw.js} +1 -1
  122. package/dist/web/assets/{vue-CxIsxtwn.js → vue-iynf6DnU.js} +1 -1
  123. package/dist/web/assets/{vue-vine-DHPh_gMr.js → vue-vine-BycfyDpl.js} +1 -1
  124. package/dist/web/assets/{xml-C-vM2m7J.js → xml-BRgRn6xu.js} +1 -1
  125. package/dist/web/assets/{xsl-DvTXNwuO.js → xsl-CWrfaC1u.js} +1 -1
  126. package/dist/web/index.html +16 -16
  127. package/dist/web/monacoeditorwork/css.worker.bundle.js +122 -122
  128. package/dist/web/monacoeditorwork/editor.worker.bundle.js +78 -78
  129. package/dist/web/monacoeditorwork/html.worker.bundle.js +110 -110
  130. package/dist/web/monacoeditorwork/json.worker.bundle.js +108 -108
  131. package/dist/web/monacoeditorwork/ts.worker.bundle.js +81 -81
  132. package/dist/web/sw.js +1 -1
  133. package/package.json +1 -1
  134. package/src/services/edge-forwarder.ts +191 -191
  135. package/src/services/windows-process-tree.ts +351 -351
  136. package/src/web/app.tsx +4 -0
  137. package/src/web/components/os-explorer/actions/collision-prompt-queue.ts +133 -0
  138. package/src/web/components/os-explorer/actions/explorer-actions-clipboard.ts +29 -3
  139. package/src/web/components/os-explorer/actions/explorer-actions-upload.ts +88 -33
  140. package/src/web/components/os-explorer/actions/use-collision-prompt.ts +56 -0
  141. package/src/web/components/os-explorer/actions/use-explorer-actions.ts +29 -44
  142. package/src/web/components/os-explorer/actions/use-permanent-overwrite-prompt.ts +47 -0
  143. package/src/web/components/os-explorer/dnd/use-drop-transfer.tsx +19 -27
  144. package/src/web/components/os-explorer/explorer-dialogs.tsx +12 -1
  145. package/src/web/components/os-explorer/upload/capture-picked-files.ts +18 -0
  146. package/src/web/components/os-explorer/upload/upload-batch-card.tsx +64 -0
  147. package/src/web/components/os-explorer/upload/upload-batch-progress.ts +34 -0
  148. package/src/web/components/os-explorer/upload/upload-batch-row.tsx +79 -0
  149. package/src/web/components/os-explorer/upload/upload-error-message.ts +19 -0
  150. package/src/web/components/os-explorer/upload/upload-progress-panel.tsx +72 -0
  151. package/src/web/components/os-explorer/upload/upload-store.ts +109 -0
  152. package/src/web/components/os-explorer/upload/use-upload-picker.tsx +7 -5
  153. package/src/web/lib/fs-upload-xhr.ts +13 -2
  154. package/dist/web/assets/architecture-PBZL5I3N-Bs7wzj-W.js +0 -1
  155. package/dist/web/assets/chat-tab-CgAv-crh.js +0 -15
  156. package/dist/web/assets/code-editor-bX4jlgMy.js +0 -10
  157. package/dist/web/assets/data-grid-overlay-editor-B1mTl3KS.js +0 -1
  158. package/dist/web/assets/data-grid-types-BXwlFMzs.js +0 -1
  159. package/dist/web/assets/database-viewer-CTK5kMaA.js +0 -1
  160. package/dist/web/assets/dist-CUPbqNnL.js +0 -11
  161. package/dist/web/assets/esm-CZ8B8Ba2.js +0 -2
  162. package/dist/web/assets/explorer-body-DykJXCTw.js +0 -2
  163. package/dist/web/assets/gitGraph-HDMCJU4V-D7i54kbM.js +0 -1
  164. package/dist/web/assets/glide-data-grid-DxfJRN-r.js +0 -138
  165. package/dist/web/assets/group-chat-tab-DkVi6qL2.js +0 -1
  166. package/dist/web/assets/index-Bucbpby-.css +0 -2
  167. package/dist/web/assets/index-CcN0TBm4.js +0 -52
  168. package/dist/web/assets/info-3K5VOQVL-BV41AzR9.js +0 -1
  169. package/dist/web/assets/keybindings-store-DJIHqbLM.js +0 -1
  170. package/dist/web/assets/markdown-renderer-pYznJDbh.js +0 -1
  171. package/dist/web/assets/notification-store-Bcl5efY2.js +0 -1
  172. package/dist/web/assets/packet-RMMSAZCW-CaJoP44m.js +0 -1
  173. package/dist/web/assets/pie-UPGHQEXC-DSGZmNw2.js +0 -1
  174. package/dist/web/assets/postgres-viewer-KZqPYfOB.js +0 -3
  175. package/dist/web/assets/radar-KQ55EAFF-Be4VUTs0.js +0 -1
  176. package/dist/web/assets/sqlite-viewer-CIv3sagZ.js +0 -1
  177. package/dist/web/assets/tool-cards-Dx-Rrpri.js +0 -8
  178. package/dist/web/assets/treemap-KZPCXAKY-Cu2zgbxU.js +0 -1
  179. package/dist/web/assets/video-preview-cvjNMjWA.js +0 -1
  180. package/packages/vscode-compat/node_modules/.bin/tsc.bunx +0 -0
  181. package/packages/vscode-compat/node_modules/.bin/tsc.exe +0 -0
  182. package/packages/vscode-compat/node_modules/.bin/tsserver.bunx +0 -0
  183. package/packages/vscode-compat/node_modules/.bin/tsserver.exe +0 -0
  184. /package/dist/web/assets/{abap-C1K0-wzc.js → abap-aW7-Jvmb.js} +0 -0
  185. /package/dist/web/assets/{actionscript-3-CJhQVjLA.js → actionscript-3-DTKrKcIk.js} +0 -0
  186. /package/dist/web/assets/{ada-Bt8r9fME.js → ada-BAPZyMF6.js} +0 -0
  187. /package/dist/web/assets/{andromeeda-DF1I8qi3.js → andromeeda-B7tKiRbo.js} +0 -0
  188. /package/dist/web/assets/{apache-CnlleE6P.js → apache-DzlxyZL6.js} +0 -0
  189. /package/dist/web/assets/{apex-j0C6Xmk6.js → apex-YMuKkRzC.js} +0 -0
  190. /package/dist/web/assets/{api-themes-CEyYK7AK.js → api-themes-BEEwU8CU.js} +0 -0
  191. /package/dist/web/assets/{applescript-DO7AnO8U.js → applescript-CA5lfLCT.js} +0 -0
  192. /package/dist/web/assets/{ara-i83AydZj.js → ara--oyOaCyG.js} +0 -0
  193. /package/dist/web/assets/{asciidoc-DbBA6-sF.js → asciidoc-DnOF36RG.js} +0 -0
  194. /package/dist/web/assets/{asm-B5S47Rgr.js → asm-BBlzivHM.js} +0 -0
  195. /package/dist/web/assets/{aurora-x-De_IaSKw.js → aurora-x-Vcb-h5c-.js} +0 -0
  196. /package/dist/web/assets/{awk-CfyLHXqS.js → awk-DIGedLLX.js} +0 -0
  197. /package/dist/web/assets/{ayu-dark-DTLdZ1Si.js → ayu-dark-CpqJlEms.js} +0 -0
  198. /package/dist/web/assets/{ayu-light-DTOfkzhu.js → ayu-light-C_Ao3JZA.js} +0 -0
  199. /package/dist/web/assets/{ayu-mirage-DsAECCMv.js → ayu-mirage-BYWxo0wh.js} +0 -0
  200. /package/dist/web/assets/{ballerina-CumGp9A7.js → ballerina-Ba65P_0B.js} +0 -0
  201. /package/dist/web/assets/{bat-Ca2SBbYN.js → bat-CsJlH9w5.js} +0 -0
  202. /package/dist/web/assets/{beancount-CqyXBwwF.js → beancount-BPC5j2kY.js} +0 -0
  203. /package/dist/web/assets/{berry-yl-kJr_H.js → berry-FDw8JA3_.js} +0 -0
  204. /package/dist/web/assets/{bibtex-DoFFszjV.js → bibtex-7QrVi7O0.js} +0 -0
  205. /package/dist/web/assets/{bicep-CWPi4nfK.js → bicep-Ch0xl3Bs.js} +0 -0
  206. /package/dist/web/assets/{bird2-DXew-ut0.js → bird2-DCEMu9Mp.js} +0 -0
  207. /package/dist/web/assets/{c-clbySDvd.js → c-CUVHE-5K.js} +0 -0
  208. /package/dist/web/assets/{c3-B65jvSM1.js → c3-DSTfto87.js} +0 -0
  209. /package/dist/web/assets/{cadence-Cm8tQTHN.js → cadence-C7hktLdb.js} +0 -0
  210. /package/dist/web/assets/{can-open-in-ppm-Cu-XYIgu.js → can-open-in-ppm-C1RSbZ7O.js} +0 -0
  211. /package/dist/web/assets/{catppuccin-frappe-DLeGslh_.js → catppuccin-frappe-DkyYFCSH.js} +0 -0
  212. /package/dist/web/assets/{catppuccin-latte-CR5GeHws.js → catppuccin-latte-BKnWZFTb.js} +0 -0
  213. /package/dist/web/assets/{catppuccin-macchiato-p-XgjxhP.js → catppuccin-macchiato-C1Ab5ZLR.js} +0 -0
  214. /package/dist/web/assets/{catppuccin-mocha-B8QOAZLl.js → catppuccin-mocha-COMc04WB.js} +0 -0
  215. /package/dist/web/assets/{clarity-DPulbvKH.js → clarity-8PE1fP_c.js} +0 -0
  216. /package/dist/web/assets/{clojure-DFuWS20u.js → clojure-Bz98WDQt.js} +0 -0
  217. /package/dist/web/assets/{cmake-DejCqcu4.js → cmake-DU6g1qMF.js} +0 -0
  218. /package/dist/web/assets/{codeowners-BwAyqWIH.js → codeowners-2Gm3RtID.js} +0 -0
  219. /package/dist/web/assets/{codeql-DgSwFjqI.js → codeql-B3FnVaRc.js} +0 -0
  220. /package/dist/web/assets/{common-lisp-CxIVJCtf.js → common-lisp-zYi9oKAF.js} +0 -0
  221. /package/dist/web/assets/{coq-DLSjSnmf.js → coq-W0vNtu9V.js} +0 -0
  222. /package/dist/web/assets/{csharp-C1HHzXBp.js → csharp-DlFGO-Bd.js} +0 -0
  223. /package/dist/web/assets/{css-VXsMY--y.js → css-BLcoafWU.js} +0 -0
  224. /package/dist/web/assets/{csv-BEbcJdHz.js → csv-BpMytiYh.js} +0 -0
  225. /package/dist/web/assets/{csv-parser-r-Nk1oHT.js → csv-parser-JohiZK_a.js} +0 -0
  226. /package/dist/web/assets/{cue-BkDnFqUD.js → cue-Ckjfj5Fx.js} +0 -0
  227. /package/dist/web/assets/{cypher-1cMqojSQ.js → cypher-D9y8enlA.js} +0 -0
  228. /package/dist/web/assets/{d-BnYjRXtH.js → d-BQt_xM-A.js} +0 -0
  229. /package/dist/web/assets/{dark-plus-XfbaH7kZ.js → dark-plus-YVOVVElU.js} +0 -0
  230. /package/dist/web/assets/{dart-Ca7s-8hK.js → dart-CbQZvIly.js} +0 -0
  231. /package/dist/web/assets/{dax-CmuOw-mY.js → dax-U83MmotH.js} +0 -0
  232. /package/dist/web/assets/{desktop-C2gJ6Ovb.js → desktop-vhxlER7T.js} +0 -0
  233. /package/dist/web/assets/{diff-BCEo1Ej7.js → diff-qIh1K-1r.js} +0 -0
  234. /package/dist/web/assets/{dist-DOlBnxFX.js → dist-k8y79TJM.js} +0 -0
  235. /package/dist/web/assets/{docker-DN2jlyAh.js → docker-CugomxC1.js} +0 -0
  236. /package/dist/web/assets/{dotenv-NExMY2kS.js → dotenv-Bjf6iJkB.js} +0 -0
  237. /package/dist/web/assets/{dracula-B9lbE01y.js → dracula-Cz9sO5UW.js} +0 -0
  238. /package/dist/web/assets/{dracula-soft-CMBBfKF_.js → dracula-soft-DY0S2NVH.js} +0 -0
  239. /package/dist/web/assets/{dream-maker-DEyDwFsd.js → dream-maker-B8LMBotO.js} +0 -0
  240. /package/dist/web/assets/{emacs-lisp-D_qP2zS6.js → emacs-lisp-DuYCGVqQ.js} +0 -0
  241. /package/dist/web/assets/{everforest-dark-DbHa2U-p.js → everforest-dark-WezKGzP_.js} +0 -0
  242. /package/dist/web/assets/{everforest-light-BISkJchP.js → everforest-light-Do7h7sGp.js} +0 -0
  243. /package/dist/web/assets/{fennel-6B22SfJR.js → fennel-DPc0PrDK.js} +0 -0
  244. /package/dist/web/assets/{fish-CubIIvJD.js → fish-Boq_hlR9.js} +0 -0
  245. /package/dist/web/assets/{fluent-DF55zQ09.js → fluent-LAzaxkrP.js} +0 -0
  246. /package/dist/web/assets/{fortran-free-form-DvOu8jAt.js → fortran-free-form-CeCg8jZE.js} +0 -0
  247. /package/dist/web/assets/{gdscript-DCPxdLpq.js → gdscript-CKnfKnN6.js} +0 -0
  248. /package/dist/web/assets/{gdshader-CTZ381FO.js → gdshader-C_ofnb9K.js} +0 -0
  249. /package/dist/web/assets/{genie-C_QDtvgU.js → genie-DhagrbXp.js} +0 -0
  250. /package/dist/web/assets/{gherkin-BcvK42tF.js → gherkin-1uujaZW0.js} +0 -0
  251. /package/dist/web/assets/{github-dark-C9afs_4w.js → github-dark-DIV5FCeV.js} +0 -0
  252. /package/dist/web/assets/{github-dark-default-CKGVrl3Z.js → github-dark-default-CcP66ogT.js} +0 -0
  253. /package/dist/web/assets/{github-dark-dimmed-C3dQZ_LC.js → github-dark-dimmed-Bj80ZBcI.js} +0 -0
  254. /package/dist/web/assets/{github-dark-high-contrast-DW78QukY.js → github-dark-high-contrast-CyI7oCCT.js} +0 -0
  255. /package/dist/web/assets/{github-light-BnP2dznS.js → github-light-CqqVK-2E.js} +0 -0
  256. /package/dist/web/assets/{github-light-default-C2fPZzPG.js → github-light-default-DEhIDABz.js} +0 -0
  257. /package/dist/web/assets/{github-light-high-contrast-BzIuUFR2.js → github-light-high-contrast-BqtUZSo1.js} +0 -0
  258. /package/dist/web/assets/{gleam-BpeKwEIO.js → gleam-Bv3z0NLi.js} +0 -0
  259. /package/dist/web/assets/{gn-nUb_Mit0.js → gn-knjS3hKu.js} +0 -0
  260. /package/dist/web/assets/{gnuplot-D7I0v20p.js → gnuplot-g56b7rpz.js} +0 -0
  261. /package/dist/web/assets/{go-D7Qqska7.js → go-DX8QO6z_.js} +0 -0
  262. /package/dist/web/assets/{groovy-DS-pne5-.js → groovy-DuYa0c1A.js} +0 -0
  263. /package/dist/web/assets/{gruvbox-dark-hard-C0W01fsq.js → gruvbox-dark-hard-D7IRkjrx.js} +0 -0
  264. /package/dist/web/assets/{gruvbox-dark-medium-Bqo6fQbg.js → gruvbox-dark-medium-UJ8YMtdx.js} +0 -0
  265. /package/dist/web/assets/{gruvbox-dark-soft-D-XSM_fu.js → gruvbox-dark-soft-I2k_O22-.js} +0 -0
  266. /package/dist/web/assets/{gruvbox-light-hard-IVAwMJRl.js → gruvbox-light-hard-CAJEeL1I.js} +0 -0
  267. /package/dist/web/assets/{gruvbox-light-medium-38ATiG7i.js → gruvbox-light-medium-BzfBTG9R.js} +0 -0
  268. /package/dist/web/assets/{gruvbox-light-soft-DnZr3c_0.js → gruvbox-light-soft-B4lq6YrU.js} +0 -0
  269. /package/dist/web/assets/{haskell-uQcywkDH.js → haskell-BG7xy9_5.js} +0 -0
  270. /package/dist/web/assets/{haxe-c6bI4_GT.js → haxe-CyusqGGx.js} +0 -0
  271. /package/dist/web/assets/{hcl-CQXTiEXq.js → hcl-BewE7tWl.js} +0 -0
  272. /package/dist/web/assets/{hjson-ChETf2bz.js → hjson-Ds8lzmRZ.js} +0 -0
  273. /package/dist/web/assets/{hlsl-BMC4JGoE.js → hlsl-ZFwRfL2h.js} +0 -0
  274. /package/dist/web/assets/{horizon-BusFlhLW.js → horizon-VAwIHbzU.js} +0 -0
  275. /package/dist/web/assets/{horizon-bright-2oD0Mz7W.js → horizon-bright-wJOIDqMt.js} +0 -0
  276. /package/dist/web/assets/{houston-DdbbjqFg.js → houston-CeohYS24.js} +0 -0
  277. /package/dist/web/assets/{hy-D_SOuqw9.js → hy-CUv6HDwS.js} +0 -0
  278. /package/dist/web/assets/{image-gallery-CrM5fHKy.js → image-gallery-CbX4JjyT.js} +0 -0
  279. /package/dist/web/assets/{imba-BxLOHO5I.js → imba-D8TAYKw4.js} +0 -0
  280. /package/dist/web/assets/{ini-ox-CFcg0.js → ini-BAKG__sb.js} +0 -0
  281. /package/dist/web/assets/{java-Bzo8yIal.js → java-CTxgEFQr.js} +0 -0
  282. /package/dist/web/assets/{javascript-DHuz9VXn.js → javascript-CyPQ_iPD.js} +0 -0
  283. /package/dist/web/assets/{json-0_y80FD5.js → json-atTPgPUT.js} +0 -0
  284. /package/dist/web/assets/{json5-CEQ50pGM.js → json5-LGxGeNhP.js} +0 -0
  285. /package/dist/web/assets/{jsonc-CfrLEAKA.js → jsonc-Bitk_sll.js} +0 -0
  286. /package/dist/web/assets/{jsonl-fKbrANC2.js → jsonl-DdyTPXqv.js} +0 -0
  287. /package/dist/web/assets/{jsonnet-DKbkPaQ2.js → jsonnet-GniiqKoY.js} +0 -0
  288. /package/dist/web/assets/{jssm-Dxxx1Hqu.js → jssm-CW6QRmkd.js} +0 -0
  289. /package/dist/web/assets/{jsx-DlJL-Oj3.js → jsx-Cr_EAVnd.js} +0 -0
  290. /package/dist/web/assets/{kanagawa-dragon-CwN4SV1c.js → kanagawa-dragon-N1CxlLFc.js} +0 -0
  291. /package/dist/web/assets/{kanagawa-lotus-BHltayiE.js → kanagawa-lotus-DuDdnVEr.js} +0 -0
  292. /package/dist/web/assets/{kanagawa-wave-D-KXPjw6.js → kanagawa-wave-BEcB8wPC.js} +0 -0
  293. /package/dist/web/assets/{kdl-DvtoJdFo.js → kdl-YdJlGKnl.js} +0 -0
  294. /package/dist/web/assets/{kotlin-CTS4MLcx.js → kotlin-D8Ou1-Vz.js} +0 -0
  295. /package/dist/web/assets/{kusto-HtSE_sKm.js → kusto-CfNzHOLh.js} +0 -0
  296. /package/dist/web/assets/{laserwave-DaXZG9ge.js → laserwave-Dw-UwgjO.js} +0 -0
  297. /package/dist/web/assets/{lean-BYtGUfWx.js → lean-Cob-4uj9.js} +0 -0
  298. /package/dist/web/assets/{less-BoxmU_Mk.js → less-D6UGsQ-F.js} +0 -0
  299. /package/dist/web/assets/{lib-BzxL1ARZ.js → lib-D6yys864.js} +0 -0
  300. /package/dist/web/assets/{libesm-ah-mr-sh.js → libesm-BNnDqFup.js} +0 -0
  301. /package/dist/web/assets/{light-plus-Bt5CyUuo.js → light-plus-g6c1YK9w.js} +0 -0
  302. /package/dist/web/assets/{llvm-CSdk9q9V.js → llvm-BCk7-7xF.js} +0 -0
  303. /package/dist/web/assets/{log-B-kp_3CL.js → log-DyyODQCQ.js} +0 -0
  304. /package/dist/web/assets/{logo-DdIsXFDO.js → logo-z3PSmZ0Q.js} +0 -0
  305. /package/dist/web/assets/{luau-DUBpLlzQ.js → luau-CuwlNMKd.js} +0 -0
  306. /package/dist/web/assets/{make-B3JVjoW_.js → make-B2ZcjXHI.js} +0 -0
  307. /package/dist/web/assets/{markdown-Seon0vHs.js → markdown-Bh7F2dEA.js} +0 -0
  308. /package/dist/web/assets/{material-theme-Nq-ChX1P.js → material-theme-DIOuD6li.js} +0 -0
  309. /package/dist/web/assets/{material-theme-darker-CPV4ayXJ.js → material-theme-darker-Cg3vOVsZ.js} +0 -0
  310. /package/dist/web/assets/{material-theme-lighter-0kyjYqEd.js → material-theme-lighter-B3plW7F5.js} +0 -0
  311. /package/dist/web/assets/{material-theme-ocean-DGpAp5co.js → material-theme-ocean-BC3W6Qbp.js} +0 -0
  312. /package/dist/web/assets/{material-theme-palenight-B0AUn0NG.js → material-theme-palenight-cn2b8irZ.js} +0 -0
  313. /package/dist/web/assets/{matlab-C2waytxs.js → matlab-CbKDDcme.js} +0 -0
  314. /package/dist/web/assets/{mdx-DAis6R6I.js → mdx-DfoNkGc0.js} +0 -0
  315. /package/dist/web/assets/{media-url-C5vA0ha9.js → media-url-FbGzzFQa.js} +0 -0
  316. /package/dist/web/assets/{mermaid-_rnT2YGD.js → mermaid-BpGcccah.js} +0 -0
  317. /package/dist/web/assets/{min-dark-BSSjchUB.js → min-dark-C-1-xt-i.js} +0 -0
  318. /package/dist/web/assets/{min-light-DomAFQsa.js → min-light-DkYGd6ZF.js} +0 -0
  319. /package/dist/web/assets/{mipsasm-bBgtvPyG.js → mipsasm-Dk87orqA.js} +0 -0
  320. /package/dist/web/assets/{mojo-Cp9BayW0.js → mojo-Ctfni3Xg.js} +0 -0
  321. /package/dist/web/assets/{monokai-CL_9gbmn.js → monokai-dRz4X-9c.js} +0 -0
  322. /package/dist/web/assets/{moonbit-BS_fcr-P.js → moonbit-BenWvd8O.js} +0 -0
  323. /package/dist/web/assets/{move-C79AH45U.js → move-CDhttBEa.js} +0 -0
  324. /package/dist/web/assets/{narrat-CJ5s3BDf.js → narrat-2qOoPAIA.js} +0 -0
  325. /package/dist/web/assets/{nextflow-groovy-ZHa4JrPJ.js → nextflow-groovy-C4CoTM6k.js} +0 -0
  326. /package/dist/web/assets/{night-owl-Jkf9zFQK.js → night-owl-CC7ba6ex.js} +0 -0
  327. /package/dist/web/assets/{night-owl-light-DRPeaG5J.js → night-owl-light-su9bVa5K.js} +0 -0
  328. /package/dist/web/assets/{nix-D2Jet9DN.js → nix-BOfpg6oF.js} +0 -0
  329. /package/dist/web/assets/{nord-CREVs22j.js → nord-Cup4UQrN.js} +0 -0
  330. /package/dist/web/assets/{nushell-CAiDi_mR.js → nushell-CV3Ed_Pd.js} +0 -0
  331. /package/dist/web/assets/{objective-c-CVkmJkC1.js → objective-c-DNKsz1d1.js} +0 -0
  332. /package/dist/web/assets/{objective-cpp-DIKDO1Ly.js → objective-cpp-BT5L7lhS.js} +0 -0
  333. /package/dist/web/assets/{ocaml-R9qtGQhs.js → ocaml-Qj-27E4B.js} +0 -0
  334. /package/dist/web/assets/{odin-DTYNQqVr.js → odin-C2scSLLk.js} +0 -0
  335. /package/dist/web/assets/{one-dark-pro-BSLWUJn5.js → one-dark-pro-C1HWasX_.js} +0 -0
  336. /package/dist/web/assets/{one-light-DbkRXG3t.js → one-light-B3bElFuJ.js} +0 -0
  337. /package/dist/web/assets/{openscad-BlPcSnmT.js → openscad-C6UAQ5Px.js} +0 -0
  338. /package/dist/web/assets/{pascal-B1Y46ZZB.js → pascal-DICllhaG.js} +0 -0
  339. /package/dist/web/assets/{pkl-BhJSJbFv.js → pkl-qghE3sfq.js} +0 -0
  340. /package/dist/web/assets/{plastic-BzxsCTpi.js → plastic-ClZHBkI2.js} +0 -0
  341. /package/dist/web/assets/{plsql-DBba7dyP.js → plsql-CKw-M6SO.js} +0 -0
  342. /package/dist/web/assets/{po-BvgLlnNo.js → po-BKro6MCB.js} +0 -0
  343. /package/dist/web/assets/{poimandres-DUaI_1JP.js → poimandres-Bdo7Kn_m.js} +0 -0
  344. /package/dist/web/assets/{polar-C7uILwJn.js → polar-B1rAV5le.js} +0 -0
  345. /package/dist/web/assets/{postcss-BgJlpFdw.js → postcss-BsA5TXYz.js} +0 -0
  346. /package/dist/web/assets/{powerquery-Dn1MIpZu.js → powerquery-hxd8aiZs.js} +0 -0
  347. /package/dist/web/assets/{powershell-Bo-DYzOS.js → powershell-D83XmNBi.js} +0 -0
  348. /package/dist/web/assets/{prisma-CTLs5IdT.js → prisma-jpc3Lfer.js} +0 -0
  349. /package/dist/web/assets/{prolog-QRGun3eG.js → prolog-By7loPcz.js} +0 -0
  350. /package/dist/web/assets/{proto-B7PI7apn.js → proto-B03P8I7L.js} +0 -0
  351. /package/dist/web/assets/{puppet-CBq0tLrP.js → puppet-BLEutFx-.js} +0 -0
  352. /package/dist/web/assets/{purescript-DFewOQb2.js → purescript-DdCIvtj7.js} +0 -0
  353. /package/dist/web/assets/{python-iWuxKXvT.js → python-DwlqCvPN.js} +0 -0
  354. /package/dist/web/assets/{qmldir-cXiW3AsF.js → qmldir-CkEpGrJr.js} +0 -0
  355. /package/dist/web/assets/{qss-DASwAbBL.js → qss-B6SOQ6U9.js} +0 -0
  356. /package/dist/web/assets/{r-TU2eaIPw.js → r-Y0KMI7Y5.js} +0 -0
  357. /package/dist/web/assets/{racket-SkRKqrLY.js → racket-BF5spJBc.js} +0 -0
  358. /package/dist/web/assets/{raku-D31lthkZ.js → raku-xNANhvUv.js} +0 -0
  359. /package/dist/web/assets/{red-CTcQZevb.js → red-DnHsBzi8.js} +0 -0
  360. /package/dist/web/assets/{reg-D8YAsTGf.js → reg-CWhYjQ7O.js} +0 -0
  361. /package/dist/web/assets/{regexp-CD2uvAWx.js → regexp-CouLuX6r.js} +0 -0
  362. /package/dist/web/assets/{rel-CAaI-1fg.js → rel-Ctf_fx-q.js} +0 -0
  363. /package/dist/web/assets/{riscv-DR-hJVIj.js → riscv-Dji9ndNu.js} +0 -0
  364. /package/dist/web/assets/{ron-CuUCJ0n4.js → ron-BgHqfYU8.js} +0 -0
  365. /package/dist/web/assets/{rose-pine-dawn-Bqz2sBRY.js → rose-pine-dawn-B5US25HC.js} +0 -0
  366. /package/dist/web/assets/{rose-pine-moon-wqyh0an4.js → rose-pine-moon-vC-4_Eb_.js} +0 -0
  367. /package/dist/web/assets/{rose-pine-aFHxW48i.js → rose-pine-rIa8chEL.js} +0 -0
  368. /package/dist/web/assets/{rosmsg-CI1ywimO.js → rosmsg-Bfxbgaxi.js} +0 -0
  369. /package/dist/web/assets/{run-in-terminal-B8TDtaM_.js → run-in-terminal-D-Q9wPF_.js} +0 -0
  370. /package/dist/web/assets/{rust-p7Imk4G_.js → rust-DSRCI-l0.js} +0 -0
  371. /package/dist/web/assets/{sass-C8JfaqCV.js → sass-BaMwafsT.js} +0 -0
  372. /package/dist/web/assets/{scala-DNxCW1By.js → scala-CnoxeIBD.js} +0 -0
  373. /package/dist/web/assets/{scheme-BYuUPJoL.js → scheme-BmSziQ83.js} +0 -0
  374. /package/dist/web/assets/{sdbl-DbPeJPUr.js → sdbl-CGDFOQ4F.js} +0 -0
  375. /package/dist/web/assets/{send-to-chat-CuBAVC8l.js → send-to-chat-BPeYO9Pv.js} +0 -0
  376. /package/dist/web/assets/{shellscript-DMiHlR3q.js → shellscript-D3_gthD5.js} +0 -0
  377. /package/dist/web/assets/{slack-dark-C4xGcQXI.js → slack-dark-Cy4dNR2g.js} +0 -0
  378. /package/dist/web/assets/{slack-ochin-BzgRt_wm.js → slack-ochin-B8hNeONl.js} +0 -0
  379. /package/dist/web/assets/{smalltalk-LDeL9PYH.js → smalltalk-B5OQnpLF.js} +0 -0
  380. /package/dist/web/assets/{snazzy-light-CXE7a5j_.js → snazzy-light-DDL1ZQgf.js} +0 -0
  381. /package/dist/web/assets/{solarized-dark-DgUhY74x.js → solarized-dark-COUdbN1J.js} +0 -0
  382. /package/dist/web/assets/{solarized-light-DD9C-H-9.js → solarized-light-CLHIejSq.js} +0 -0
  383. /package/dist/web/assets/{solidity-CAbDB4D4.js → solidity-DpQHaveQ.js} +0 -0
  384. /package/dist/web/assets/{splunk-kQREPfIc.js → splunk-BGT75_a1.js} +0 -0
  385. /package/dist/web/assets/{sql-CBzeNAD8.js → sql-ZPjZoKEG.js} +0 -0
  386. /package/dist/web/assets/{ssh-config-L1euxrsM.js → ssh-config-B6oU9nqL.js} +0 -0
  387. /package/dist/web/assets/{stylus-DvBnYniP.js → stylus-Bbgm8BDk.js} +0 -0
  388. /package/dist/web/assets/{swift-DF5NDQp6.js → swift-7OUZlXRr.js} +0 -0
  389. /package/dist/web/assets/{synthwave-84-DbBhB_Hq.js → synthwave-84-Dp7xsQqz.js} +0 -0
  390. /package/dist/web/assets/{system-verilog-D8s2ZW_k.js → system-verilog-COlHqI_R.js} +0 -0
  391. /package/dist/web/assets/{systemd-a5-XZJsG.js → systemd-DXL9nsy_.js} +0 -0
  392. /package/dist/web/assets/{talonscript-BLa0URTW.js → talonscript-Bkpiqjjy.js} +0 -0
  393. /package/dist/web/assets/{tasl-DIoV4XcC.js → tasl-Bpra97jM.js} +0 -0
  394. /package/dist/web/assets/{tcl-ztYAdXfQ.js → tcl-BcDm6PGE.js} +0 -0
  395. /package/dist/web/assets/{terraform-DvpCCiOZ.js → terraform-DGQKmd9G.js} +0 -0
  396. /package/dist/web/assets/{tokyo-night-BkHlYUv0.js → tokyo-night-CyLasBR5.js} +0 -0
  397. /package/dist/web/assets/{toml-acIrxos6.js → toml-D-01EUMm.js} +0 -0
  398. /package/dist/web/assets/{tsv-BJB5EVCT.js → tsv-DlZx-hGD.js} +0 -0
  399. /package/dist/web/assets/{tsx-B1MmXGT3.js → tsx-Bu211EOh.js} +0 -0
  400. /package/dist/web/assets/{turtle-DFceTiqd.js → turtle-CwM--Nm2.js} +0 -0
  401. /package/dist/web/assets/{typescript-Dz9wU5Y1.js → typescript-wOPax6Gk.js} +0 -0
  402. /package/dist/web/assets/{typespec-CPuYZijj.js → typespec-C5n5j5Cf.js} +0 -0
  403. /package/dist/web/assets/{typst-CfsCIYv8.js → typst-DQS-vHSj.js} +0 -0
  404. /package/dist/web/assets/{use-blob-url-BmlYYZ8L.js → use-blob-url-DdEfzVb8.js} +0 -0
  405. /package/dist/web/assets/{v-CGo0jcXA.js → v-BMQHRcJ5.js} +0 -0
  406. /package/dist/web/assets/{vala-AsSR0hrb.js → vala-By6oCVpL.js} +0 -0
  407. /package/dist/web/assets/{vb-C7tvbXv1.js → vb-BSmHxRqj.js} +0 -0
  408. /package/dist/web/assets/{vendor-xterm-BeaIjRrv.js → vendor-xterm-BHWghY3d.js} +0 -0
  409. /package/dist/web/assets/{verilog--a33ND-p.js → verilog-Bt-zbfre.js} +0 -0
  410. /package/dist/web/assets/{vesper-B_Z0h4pn.js → vesper-Bz7pxhsL.js} +0 -0
  411. /package/dist/web/assets/{vhdl-CWL5dZPN.js → vhdl-BXjhSHk-.js} +0 -0
  412. /package/dist/web/assets/{viml-BglmT14Y.js → viml-B4m7rYZk.js} +0 -0
  413. /package/dist/web/assets/{vitesse-black-RKFsSqQI.js → vitesse-black-BsmvsuHB.js} +0 -0
  414. /package/dist/web/assets/{vitesse-dark-D7zDWNmc.js → vitesse-dark-Cqnvi8YY.js} +0 -0
  415. /package/dist/web/assets/{vitesse-light-MAp87W5b.js → vitesse-light-KbYJh0ae.js} +0 -0
  416. /package/dist/web/assets/{vyper-CgCBYg1G.js → vyper-BaHPAgL_.js} +0 -0
  417. /package/dist/web/assets/{wasm-BOG7ZeTT.js → wasm-Cfq9I1o-.js} +0 -0
  418. /package/dist/web/assets/{wasm-Bwl4txwp.js → wasm-Dpw0fYUw.js} +0 -0
  419. /package/dist/web/assets/{wenyan-DpShPKXZ.js → wenyan-DZsJG8fl.js} +0 -0
  420. /package/dist/web/assets/{wgsl-BakcCblK.js → wgsl-CVc3AdMI.js} +0 -0
  421. /package/dist/web/assets/{wikitext-NroRWVAO.js → wikitext-D9TsdERw.js} +0 -0
  422. /package/dist/web/assets/{wit-B5CM2pg6.js → wit-B55b-kBe.js} +0 -0
  423. /package/dist/web/assets/{wolfram-7MTFBJpR.js → wolfram-BMCiuBhR.js} +0 -0
  424. /package/dist/web/assets/{yaml-Bwr01G2K.js → yaml-T9AUQgxg.js} +0 -0
  425. /package/dist/web/assets/{zenscript-Dj8GATvi.js → zenscript-C2NuU93Q.js} +0 -0
  426. /package/dist/web/assets/{zig-LAE-fbS-.js → zig-B4cWz8iD.js} +0 -0
package/src/web/app.tsx CHANGED
@@ -35,6 +35,7 @@ import { ExtensionQuickPick } from "@/components/extensions/extension-quickpick"
35
35
  import { ExtensionInputBox } from "@/components/extensions/extension-inputbox";
36
36
  import { useExtensionWs } from "@/hooks/use-extension-ws";
37
37
  import { useIsMobile } from "@/hooks/use-is-mobile";
38
+ import { UploadProgressPanel } from "@/components/os-explorer/upload/upload-progress-panel";
38
39
  import { cn } from "@/lib/utils";
39
40
 
40
41
  // Lazy: the explorer feature (views, actions, skins, icon map) is the same heavy bundle the
@@ -366,6 +367,9 @@ export function App() {
366
367
  {/* Connection lost overlay — shown when API unreachable for >15s */}
367
368
  <ConnectionLostOverlay />
368
369
 
370
+ {/* Explorer upload progress — bottom-right card (desktop) or pill + sheet (mobile) */}
371
+ <UploadProgressPanel />
372
+
369
373
  {/* Toast notifications. Bottom-left collides with the mobile dock's
370
374
  terminal toolbar — a toast lands directly on the buttons that raised
371
375
  it — so phones get them out of the thumb zone instead. */}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Pure serializing queue behind the collision-prompt dialog.
3
+ *
4
+ * Uploads and copy/move transfers both call `ctx.resolve()` — sometimes from several jobs
5
+ * running at once (`uploadEntries`' bounded-concurrency queue). Before this module, the
6
+ * dialog was a single React state slot: the second concurrent `resolve()` call silently
7
+ * replaced whichever request was already showing, and the first job's promise never
8
+ * settled — the queue stalled forever with a stuck "Uploading…" toast.
9
+ *
10
+ * Every request now queues here and only one shows at a time. "Apply to all" (set from the
11
+ * dialog when a choice is made) short-circuits every request still queued *in the same
12
+ * batch* without opening another prompt — see `startBatch`/`endBatch`.
13
+ *
14
+ * Pure and DOM-free on purpose, like `upload-queue.ts`: `use-collision-prompt.ts` is the
15
+ * thin React hook wrapping this for re-render notifications.
16
+ */
17
+
18
+ export interface CollisionRequest {
19
+ name: string;
20
+ destination: string;
21
+ }
22
+
23
+ export type CollisionChoice = "replace" | "keep-both" | "skip";
24
+
25
+ interface QueueItem {
26
+ request: CollisionRequest;
27
+ settle(choice: CollisionChoice): void;
28
+ }
29
+
30
+ export interface CollisionQueueSnapshot {
31
+ request: CollisionRequest;
32
+ /** How many more requests are queued behind this one — the dialog's "…and N more". */
33
+ remaining: number;
34
+ }
35
+
36
+ export interface QueueSnapshot<TRequest> {
37
+ request: TRequest;
38
+ remaining: number;
39
+ }
40
+
41
+ /**
42
+ * Generic one-at-a-time prompt queue: every `request()` call queues behind whatever is
43
+ * already showing, `snapshot()` exposes only the head, and `choose()` answers it and
44
+ * advances. Reused by anything that needs a single dialog serialized across concurrent
45
+ * callers — `CollisionPromptQueue` below layers "apply to all" sticky choices on top of one
46
+ * of these for collisions; the rarer permanent-overwrite confirm (no sticky concept needed)
47
+ * uses one directly via `use-permanent-overwrite-prompt.ts`. Both prompts used to be a bare
48
+ * `useState` slot each, with the same "second concurrent caller overwrites the first" race.
49
+ */
50
+ export class SerialPromptQueue<TRequest, TChoice> {
51
+ private queue: Array<{ request: TRequest; settle(choice: TChoice): void }> = [];
52
+
53
+ /** Called whenever the queue or the visible request changes, so a React wrapper can
54
+ * re-render. Never called synchronously from inside the constructor. */
55
+ constructor(private readonly onChange: () => void) {}
56
+
57
+ request(request: TRequest): Promise<TChoice> {
58
+ return new Promise((resolve) => {
59
+ this.queue.push({ request, settle: resolve });
60
+ this.onChange();
61
+ });
62
+ }
63
+
64
+ snapshot(): QueueSnapshot<TRequest> | null {
65
+ const head = this.queue[0];
66
+ return head ? { request: head.request, remaining: this.queue.length - 1 } : null;
67
+ }
68
+
69
+ /** Answers the head request (if any) with `choice` and advances to the next. */
70
+ choose(choice: TChoice): void {
71
+ const item = this.queue.shift();
72
+ if (!item) return;
73
+ item.settle(choice);
74
+ this.onChange();
75
+ }
76
+
77
+ /** Removes and answers every request currently queued (including the head) with the same
78
+ * `choice` — how "apply to all" resolves the rest of a batch in one step. */
79
+ drain(choice: TChoice): void {
80
+ const rest = this.queue.splice(0);
81
+ if (rest.length === 0) return;
82
+ for (const item of rest) item.settle(choice);
83
+ this.onChange();
84
+ }
85
+ }
86
+
87
+ export class CollisionPromptQueue {
88
+ private readonly core: SerialPromptQueue<CollisionRequest, CollisionChoice>;
89
+ private stickyChoice: CollisionChoice | null = null;
90
+ private activeBatches = 0;
91
+
92
+ constructor(onChange: () => void) {
93
+ this.core = new SerialPromptQueue(onChange);
94
+ }
95
+
96
+ /**
97
+ * Marks the start of one batch of parallel `resolve()` calls that should share a single
98
+ * "apply to all" choice (one drop, one paste, one drag). Batches can overlap (a paste
99
+ * started while a drag is still resolving); "apply to all" only resets once every
100
+ * overlapping batch has called `endBatch`.
101
+ */
102
+ startBatch(): void {
103
+ this.activeBatches++;
104
+ }
105
+
106
+ endBatch(): void {
107
+ this.activeBatches = Math.max(0, this.activeBatches - 1);
108
+ if (this.activeBatches === 0) this.stickyChoice = null;
109
+ }
110
+
111
+ /** Raises one collision. Resolves immediately (no dialog) if a prior "apply to all" choice
112
+ * is still sticky for the current batch; otherwise queues behind whatever is showing. */
113
+ request(request: CollisionRequest): Promise<CollisionChoice> {
114
+ if (this.stickyChoice) return Promise.resolve(this.stickyChoice);
115
+ return this.core.request(request);
116
+ }
117
+
118
+ /** The request currently on screen, or `null` when nothing is queued. */
119
+ snapshot(): CollisionQueueSnapshot | null {
120
+ return this.core.snapshot();
121
+ }
122
+
123
+ /** Answers the request on screen. When `applyToAll` is set, the choice also settles every
124
+ * request still queued right now, and sticks for any that arrive before the batch ends. */
125
+ choose(choice: CollisionChoice, applyToAll: boolean): void {
126
+ if (applyToAll) {
127
+ this.stickyChoice = choice;
128
+ this.core.drain(choice);
129
+ } else {
130
+ this.core.choose(choice);
131
+ }
132
+ }
133
+ }
@@ -33,6 +33,13 @@ export interface TransferContext {
33
33
  * delete would contradict what the user just agreed to. Returning false skips the item.
34
34
  */
35
35
  confirmPermanentOverwrite(name: string): Promise<boolean>;
36
+ /**
37
+ * Brackets one batch of parallel `resolve()` calls sharing this context's collision prompt
38
+ * (one paste, one drag, one upload), so "Apply to all" scopes to just that batch. Optional —
39
+ * a caller with no concurrent collisions (or a test building a bare context) can omit them.
40
+ */
41
+ startBatch?(): void;
42
+ endBatch?(): void;
36
43
  }
37
44
 
38
45
  export interface TransferResult {
@@ -56,6 +63,28 @@ export async function transfer(
56
63
  const result: TransferResult = { succeeded: 0, skipped: 0, failed: 0 };
57
64
  const touched = new Set<string>([dstDir]);
58
65
 
66
+ // `transfer()` itself resolves collisions one source at a time, but two *calls* to it can
67
+ // overlap (a paste fired while a drag-drop transfer is still resolving) sharing the same
68
+ // dialog — bracket this call so "Apply to all" only ever covers its own sources.
69
+ ctx.startBatch?.();
70
+ try {
71
+ await transferSources(sources, dstDir, op, ctx, result, touched);
72
+ } finally {
73
+ ctx.endBatch?.();
74
+ }
75
+
76
+ fsChanged(...touched);
77
+ return result;
78
+ }
79
+
80
+ async function transferSources(
81
+ sources: string[],
82
+ dstDir: string,
83
+ op: "copy" | "move",
84
+ ctx: TransferContext,
85
+ result: TransferResult,
86
+ touched: Set<string>,
87
+ ): Promise<void> {
59
88
  for (const source of sources) {
60
89
  const name = source.split(/[/\\]/).filter(Boolean).pop() ?? source;
61
90
  const sourceDir = dirnameOf(source, ctx.sep);
@@ -155,9 +184,6 @@ export async function transfer(
155
184
  toast.error(`${name} was removed but the replacement could not be written`, { description: errorDescription(e) });
156
185
  }
157
186
  }
158
-
159
- fsChanged(...touched);
160
- return result;
161
187
  }
162
188
 
163
189
  /** Put absolute paths on the shared clipboard. `origin` lets the tree keep its own routes. */
@@ -2,16 +2,23 @@
2
2
  * Turns a dropped/picked file batch into `PUT /api/fs/upload` calls, streamed through
3
3
  * `uploadFileXhr` with bounded concurrency. Mirrors `transfer()` in
4
4
  * `explorer-actions-clipboard.ts`: the same collision prompt (`ctx.resolve`), the same
5
- * trash-first "Replace" via the 409 `EEXIST` contract, and a `fsChanged` refresh once the
6
- * batch settles — drag-to-upload and the picker both funnel through this one function.
5
+ * trash-first "Replace" (delete via `/api/fs/delete`, then upload) and a `fsChanged` refresh
6
+ * once the batch settles — drag-to-upload and the picker both funnel through this one
7
+ * function.
8
+ *
9
+ * Per-file state lives in `upload-store.ts`, which backs the persistent progress panel that
10
+ * replaced the old "Uploading N files… NN%" toast — that toast had no room for a cancel
11
+ * button or per-file outcomes, and its single collision-dialog slot is the bug this module
12
+ * used to have (see `use-collision-prompt.ts`).
7
13
  */
8
14
 
9
- import { toast } from "sonner";
10
- import { FsError } from "@/lib/fs-api";
15
+ import { fsApi, FsError } from "@/lib/fs-api";
11
16
  import { uploadFileXhr } from "@/lib/fs-upload-xhr";
12
17
  import { dirnameOf, joinPath } from "../format-file-meta";
13
18
  import { fsChanged } from "../explorer-store";
14
19
  import type { DroppedEntry } from "../upload/collect-dropped-entries";
20
+ import { describeUploadError } from "../upload/upload-error-message";
21
+ import { useUploadStore } from "../upload/upload-store";
15
22
  import { runUploadQueue, type UploadJob } from "../upload/upload-queue";
16
23
  import type { TransferContext } from "./explorer-actions-clipboard";
17
24
  import { freeName } from "./explorer-actions-transfer-helpers";
@@ -35,34 +42,42 @@ async function uploadResolvingCollisions(
35
42
  dstDir: string,
36
43
  sep: string,
37
44
  ctx: TransferContext,
45
+ signal: AbortSignal,
38
46
  onProgress: (bytesLoaded: number) => void,
39
- ): Promise<void> {
47
+ ): Promise<"done" | "skipped"> {
40
48
  const destination = destinationFor(dstDir, entry.relativePath, sep);
41
49
  try {
42
- await uploadFileXhr(destination, entry.file, false, (p) => onProgress(p.loaded));
43
- return;
50
+ await uploadFileXhr(destination, entry.file, false, (p) => onProgress(p.loaded), signal);
51
+ return "done";
44
52
  } catch (e) {
45
53
  if (!(e instanceof FsError) || e.code !== "EEXIST") throw e;
46
54
  }
47
55
 
48
56
  const name = nameOf(entry.relativePath);
49
57
  const choice = await ctx.resolve({ name, destination });
50
- if (choice === "skip") return;
58
+ if (choice === "skip") return "skipped";
51
59
  if (choice === "keep-both") {
52
60
  const containingDir = dirnameOf(destination, sep);
53
61
  const alternative = await freeName(containingDir, name, sep);
54
62
  if (!alternative) throw new Error("No free name available");
55
- await uploadFileXhr(joinPath(containingDir, alternative, sep), entry.file, false, (p) => onProgress(p.loaded));
56
- return;
63
+ await uploadFileXhr(joinPath(containingDir, alternative, sep), entry.file, false, (p) => onProgress(p.loaded), signal);
64
+ return "done";
57
65
  }
58
- // Replace: the server upload route itself makes the overwrite atomic (tmp file + rename),
59
- // so unlike the copy/move `transfer()` there is no separate trash-then-write step here.
60
- await uploadFileXhr(destination, entry.file, true, (p) => onProgress(p.loaded));
61
- }
62
66
 
63
- function uploadLabel(entries: DroppedEntry[], fraction: number): string {
64
- const label = entries.length === 1 ? entries[0]!.file.name : `${entries.length} files`;
65
- return `Uploading ${label}… ${Math.round(fraction * 100)}%`;
67
+ // Replace: trash the existing entry first, same as copy/move's `transfer()` the dialog's
68
+ // "moves the existing item to the Trash first" copy has to hold for every caller of it.
69
+ try {
70
+ await fsApi.remove(destination, false);
71
+ } catch (e) {
72
+ if (!(e instanceof FsError) || e.code !== "NO_TRASH") throw e;
73
+ // No trash backend on this host — ask before doing something permanent instead of
74
+ // silently downgrading to it (mirrors `transfer()`'s own NO_TRASH handling).
75
+ const proceed = await ctx.confirmPermanentOverwrite(name);
76
+ if (!proceed) return "skipped";
77
+ await fsApi.remove(destination, true);
78
+ }
79
+ await uploadFileXhr(destination, entry.file, true, (p) => onProgress(p.loaded), signal);
80
+ return "done";
66
81
  }
67
82
 
68
83
  export async function uploadEntries(
@@ -73,24 +88,64 @@ export async function uploadEntries(
73
88
  ): Promise<void> {
74
89
  if (entries.length === 0) return;
75
90
 
76
- const toastId = toast.loading(uploadLabel(entries, 0));
77
- const jobs: UploadJob<void>[] = entries.map((entry, index) => ({
78
- id: String(index),
79
- size: entry.file.size,
80
- run: (onProgress) => uploadResolvingCollisions(entry, dstDir, sep, ctx, onProgress),
81
- }));
91
+ const batchId = crypto.randomUUID();
92
+ const store = useUploadStore.getState();
93
+ store.addBatch(
94
+ batchId,
95
+ dstDir,
96
+ entries.map((entry, index) => ({
97
+ id: String(index),
98
+ name: nameOf(entry.relativePath),
99
+ relativePath: entry.relativePath,
100
+ size: entry.file.size,
101
+ })),
102
+ );
82
103
 
83
- const results = await runUploadQueue(jobs, CONCURRENCY, (progress) => {
84
- const fraction = progress.bytesTotal > 0 ? progress.bytesLoaded / progress.bytesTotal : 0;
85
- toast.loading(uploadLabel(entries, fraction), { id: toastId });
104
+ const controllers = entries.map((_, index) => {
105
+ const controller = new AbortController();
106
+ store.registerCanceller(batchId, String(index), () => controller.abort());
107
+ return controller;
86
108
  });
87
109
 
88
- fsChanged(dstDir);
89
- const succeeded = results.filter((r) => r.ok).length;
90
- const failed = results.length - succeeded;
91
- if (failed === 0) {
92
- toast.success(`Uploaded ${succeeded} item${succeeded === 1 ? "" : "s"}`, { id: toastId });
93
- } else {
94
- toast.error(`Uploaded ${succeeded}, ${failed} failed`, { id: toastId });
110
+ // Serializes this batch's collision prompts through the shared queue (see
111
+ // `use-collision-prompt.ts`) and scopes "Apply to all" to just these entries.
112
+ ctx.startBatch?.();
113
+ try {
114
+ const jobs: UploadJob<void>[] = entries.map((entry, index) => {
115
+ const id = String(index);
116
+ const controller = controllers[index]!;
117
+ return {
118
+ id,
119
+ size: entry.file.size,
120
+ run: async (onProgress) => {
121
+ if (controller.signal.aborted) {
122
+ store.setItemState(batchId, id, "cancelled");
123
+ throw new DOMException("Upload aborted", "AbortError");
124
+ }
125
+ store.setItemState(batchId, id, "uploading");
126
+ try {
127
+ const outcome = await uploadResolvingCollisions(
128
+ entry, dstDir, sep, ctx, controller.signal,
129
+ (loaded) => {
130
+ onProgress(loaded);
131
+ store.setItemProgress(batchId, id, loaded);
132
+ },
133
+ );
134
+ store.setItemState(batchId, id, outcome === "skipped" ? "skipped" : "done");
135
+ } catch (e) {
136
+ const cancelled = e instanceof DOMException && e.name === "AbortError";
137
+ store.setItemState(batchId, id, cancelled ? "cancelled" : "failed", cancelled ? undefined : describeUploadError(e));
138
+ throw e;
139
+ }
140
+ },
141
+ };
142
+ });
143
+
144
+ // The aggregate progress callback is unused here — the panel reads per-item state
145
+ // straight from the store, updated above as each job settles.
146
+ await runUploadQueue(jobs, CONCURRENCY, () => {});
147
+ } finally {
148
+ ctx.endBatch?.();
149
+ fsChanged(dstDir);
95
150
  }
96
151
  }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * React wrapper around `CollisionPromptQueue`. Owns one queue instance per window/surface
3
+ * (`use-explorer-actions.ts` and `use-drop-transfer.tsx` each hold their own), exposing the
4
+ * dialog-facing state plus the `resolve`/`startBatch`/`endBatch` trio that `TransferContext`
5
+ * plugs into `transfer()` and `uploadEntries()`.
6
+ */
7
+
8
+ import { useMemo, useRef, useState } from "react";
9
+ import { CollisionPromptQueue, type CollisionChoice, type CollisionRequest } from "./collision-prompt-queue";
10
+
11
+ export interface CollisionPromptState extends CollisionRequest {
12
+ /** How many more collisions are queued behind this one. */
13
+ remaining: number;
14
+ applyToAll: boolean;
15
+ setApplyToAll(value: boolean): void;
16
+ resolve(choice: CollisionChoice): void;
17
+ }
18
+
19
+ export interface CollisionPrompt {
20
+ /** Render-ready state for the dialog, or `null` when nothing is queued. */
21
+ state: CollisionPromptState | null;
22
+ resolve(request: CollisionRequest): Promise<CollisionChoice>;
23
+ startBatch(): void;
24
+ endBatch(): void;
25
+ }
26
+
27
+ export function useCollisionPrompt(): CollisionPrompt {
28
+ const [tick, setTick] = useState(0);
29
+ const [applyToAll, setApplyToAll] = useState(false);
30
+ const queueRef = useRef<CollisionPromptQueue | null>(null);
31
+ if (!queueRef.current) {
32
+ queueRef.current = new CollisionPromptQueue(() => setTick((n) => n + 1));
33
+ }
34
+ const queue = queueRef.current;
35
+
36
+ return useMemo(() => {
37
+ const snapshot = queue.snapshot();
38
+ return {
39
+ state: snapshot && {
40
+ ...snapshot.request,
41
+ remaining: snapshot.remaining,
42
+ applyToAll,
43
+ setApplyToAll,
44
+ resolve: (choice) => {
45
+ queue.choose(choice, applyToAll);
46
+ setApplyToAll(false);
47
+ },
48
+ },
49
+ resolve: (request) => queue.request(request),
50
+ startBatch: () => queue.startBatch(),
51
+ endBatch: () => queue.endBatch(),
52
+ };
53
+ // `tick` has no direct use below — it exists purely to force this memo to recompute
54
+ // whenever the queue notifies of a change (new request queued, or one resolved).
55
+ }, [queue, applyToAll, tick]);
56
+ }
@@ -1,10 +1,8 @@
1
1
  /**
2
- * Binds the action modules to one window's slice and owns the state of the three
3
- * interruptions they need: the collision prompt, the permanent-delete confirmation and
4
- * the properties dialog.
5
- *
6
- * Prompts are modelled as promises resolved by the dialog, so the action modules stay
7
- * plain async functions with no React inside them.
2
+ * Binds the action modules to one window's slice and owns the state of its interruptions:
3
+ * the collision prompt (`use-collision-prompt.ts`), the permanent-delete confirmation and the
4
+ * properties dialog. Prompts are modelled as promises resolved by the dialog, so the action
5
+ * modules stay plain async functions with no React inside them.
8
6
  */
9
7
 
10
8
  import { useCallback, useMemo, useRef, useState, type ReactNode } from "react";
@@ -15,12 +13,11 @@ import { useExplorerPinsStore } from "../explorer-pins-store";
15
13
  import { useExplorerStore, type ExplorerSlice } from "../explorer-store";
16
14
  import type { ExplorerNavigation } from "../use-explorer-navigation";
17
15
  import { copyTextLines, downloadEntries, openEntryInPpm, openPathInNewWindow } from "./explorer-actions-open";
18
- import {
19
- pasteInto, setClipboardPaths, transfer,
20
- type CollisionChoice, type CollisionRequest,
21
- } from "./explorer-actions-clipboard";
16
+ import { pasteInto, setClipboardPaths, transfer } from "./explorer-actions-clipboard";
22
17
  import { createEntry, deleteEntries, renameEntry, validateEntryName } from "./explorer-actions-mutate";
23
18
  import { useExplorerUploadActions } from "./use-explorer-upload-actions";
19
+ import { useCollisionPrompt, type CollisionPromptState } from "./use-collision-prompt";
20
+ import { usePermanentOverwritePrompt, type PermanentOverwritePromptState } from "./use-permanent-overwrite-prompt";
24
21
  import type { DroppedEntry } from "../upload/collect-dropped-entries";
25
22
 
26
23
  export interface ExplorerActions {
@@ -52,10 +49,10 @@ export interface ExplorerActions {
52
49
  }
53
50
 
54
51
  export interface ExplorerDialogState {
55
- collision: (CollisionRequest & { resolve(choice: CollisionChoice): void }) | null;
52
+ collision: CollisionPromptState | null;
56
53
  pendingDelete: { paths: string[]; names: string[] } | null;
57
54
  /** "Replace" hit a host with no trash backend — confirm a permanent overwrite instead. */
58
- permanentOverwrite: { name: string; resolve(proceed: boolean): void } | null;
55
+ permanentOverwrite: PermanentOverwritePromptState | null;
59
56
  properties: FsEntry | null;
60
57
  inlineError: string | null;
61
58
  closeDelete(): void;
@@ -72,43 +69,31 @@ export function useExplorerActions(
72
69
  platform: string | undefined,
73
70
  ): { actions: ExplorerActions; dialogs: ExplorerDialogState } {
74
71
  const patch = useExplorerStore((s) => s.patch);
75
- const [collision, setCollision] = useState<ExplorerDialogState["collision"]>(null);
72
+ const collisionPrompt = useCollisionPrompt();
73
+ const permanentOverwritePrompt = usePermanentOverwritePrompt();
76
74
  const [pendingDelete, setPendingDelete] = useState<ExplorerDialogState["pendingDelete"]>(null);
77
- const [permanentOverwrite, setPermanentOverwrite] = useState<ExplorerDialogState["permanentOverwrite"]>(null);
78
75
  const [properties, setProperties] = useState<FsEntry | null>(null);
79
76
  const [inlineError, setInlineError] = useState<string | null>(null);
80
77
 
81
78
  const sliceRef = useRef(slice);
82
79
  sliceRef.current = slice;
83
80
 
84
- const context = useMemo(
85
- () => ({
86
- get sep() {
87
- return sliceRef.current?.sep ?? "/";
88
- },
89
- resolve: (request: CollisionRequest) =>
90
- new Promise<CollisionChoice>((resolve) => {
91
- setCollision({
92
- ...request,
93
- resolve: (choice) => {
94
- setCollision(null);
95
- resolve(choice);
96
- },
97
- });
98
- }),
99
- confirmPermanentOverwrite: (name: string) =>
100
- new Promise<boolean>((resolve) => {
101
- setPermanentOverwrite({
102
- name,
103
- resolve: (proceed) => {
104
- setPermanentOverwrite(null);
105
- resolve(proceed);
106
- },
107
- });
108
- }),
109
- }),
110
- [],
111
- );
81
+ // Read through refs so `context` keeps a stable identity ([]-deps) even though both
82
+ // prompts' own functions change identity on every queued/resolved request.
83
+ const collisionPromptRef = useRef(collisionPrompt);
84
+ collisionPromptRef.current = collisionPrompt;
85
+ const permanentOverwritePromptRef = useRef(permanentOverwritePrompt);
86
+ permanentOverwritePromptRef.current = permanentOverwritePrompt;
87
+
88
+ const context = useMemo(() => ({
89
+ get sep() {
90
+ return sliceRef.current?.sep ?? "/";
91
+ },
92
+ resolve: (request: Parameters<typeof collisionPrompt.resolve>[0]) => collisionPromptRef.current.resolve(request),
93
+ startBatch: () => collisionPromptRef.current.startBatch(),
94
+ endBatch: () => collisionPromptRef.current.endBatch(),
95
+ confirmPermanentOverwrite: (name: string) => permanentOverwritePromptRef.current.confirm(name),
96
+ }), []);
112
97
 
113
98
  const currentDir = () => sliceRef.current?.path ?? "";
114
99
  const upload = useExplorerUploadActions(context, currentDir);
@@ -212,9 +197,9 @@ export function useExplorerActions(
212
197
  return {
213
198
  actions,
214
199
  dialogs: {
215
- collision,
200
+ collision: collisionPrompt.state,
216
201
  pendingDelete,
217
- permanentOverwrite,
202
+ permanentOverwrite: permanentOverwritePrompt.state,
218
203
  properties,
219
204
  inlineError,
220
205
  closeDelete: () => setPendingDelete(null),
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Serializes the "no Trash on this host" confirm (`ctx.confirmPermanentOverwrite`) behind the
3
+ * same one-at-a-time queue as the collision prompt (`SerialPromptQueue`, see
4
+ * `collision-prompt-queue.ts`). This confirm used to be its own bare `useState` slot with the
5
+ * exact same race: a Replace that hits `NO_TRASH` on two concurrent jobs could have the second
6
+ * call silently overwrite the first's dialog, leaving the first job's promise unresolved
7
+ * forever. No "apply to all" here — it is a much rarer prompt than a name collision, so a
8
+ * plain FIFO queue is all it needs.
9
+ */
10
+
11
+ import { useMemo, useRef, useState } from "react";
12
+ import { SerialPromptQueue } from "./collision-prompt-queue";
13
+
14
+ export interface PermanentOverwritePromptState {
15
+ name: string;
16
+ /** How many more confirms are queued behind this one. */
17
+ remaining: number;
18
+ resolve(proceed: boolean): void;
19
+ }
20
+
21
+ export interface PermanentOverwritePrompt {
22
+ state: PermanentOverwritePromptState | null;
23
+ confirm(name: string): Promise<boolean>;
24
+ }
25
+
26
+ export function usePermanentOverwritePrompt(): PermanentOverwritePrompt {
27
+ const [tick, setTick] = useState(0);
28
+ const queueRef = useRef<SerialPromptQueue<string, boolean> | null>(null);
29
+ if (!queueRef.current) {
30
+ queueRef.current = new SerialPromptQueue(() => setTick((n) => n + 1));
31
+ }
32
+ const queue = queueRef.current;
33
+
34
+ return useMemo(() => {
35
+ const snapshot = queue.snapshot();
36
+ return {
37
+ state: snapshot && {
38
+ name: snapshot.request,
39
+ remaining: snapshot.remaining,
40
+ resolve: (proceed) => queue.choose(proceed),
41
+ },
42
+ confirm: (name) => queue.request(name),
43
+ };
44
+ // `tick` has no direct use below — it forces this memo to recompute whenever the queue
45
+ // notifies of a change (new confirm queued, or one resolved).
46
+ }, [queue, tick]);
47
+ }