@linxin666/dsh-remote-web-ui 0.1.20 → 0.2.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 (126) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +56 -26
  3. package/README.zh.md +20 -15
  4. package/assets/mobile-icon-192.png +0 -0
  5. package/assets/mobile-icon-512.png +0 -0
  6. package/assets/mobile-service-worker.js +64 -0
  7. package/lib/client.js +272 -47
  8. package/lib/client.js.map +1 -1
  9. package/lib/index.js +316 -60
  10. package/lib/mobile.js +487 -56
  11. package/lib/mobile.js.map +1 -1
  12. package/lib/types/client/PluginSettingsCard.d.ts +28 -0
  13. package/lib/types/client/PluginSettingsCard.d.ts.map +1 -1
  14. package/lib/types/client/PluginSettingsCard.js +147 -6
  15. package/lib/types/client/RemoteEntry.d.ts.map +1 -1
  16. package/lib/types/client/RemoteEntry.js +13 -2
  17. package/lib/types/client/RemoteSettingsCard.d.ts +2 -2
  18. package/lib/types/client/RemoteSettingsCard.d.ts.map +1 -1
  19. package/lib/types/client/RemoteSettingsCard.js +1 -1
  20. package/lib/types/client/UpdateEntry.d.ts.map +1 -1
  21. package/lib/types/client/UpdateEntry.js +36 -3
  22. package/lib/types/client/UpdatePanel.d.ts.map +1 -1
  23. package/lib/types/client/UpdatePanel.js +2 -2
  24. package/lib/types/client/deep-link.js +1 -1
  25. package/lib/types/client/locales.d.ts +4 -0
  26. package/lib/types/client/locales.d.ts.map +1 -1
  27. package/lib/types/client/locales.js +4 -0
  28. package/lib/types/gate.d.ts +9 -0
  29. package/lib/types/gate.d.ts.map +1 -1
  30. package/lib/types/gate.js +17 -4
  31. package/lib/types/index.d.ts +25 -0
  32. package/lib/types/index.d.ts.map +1 -1
  33. package/lib/types/index.js +30 -13
  34. package/lib/types/mobile/PairRequiredView.d.ts +7 -0
  35. package/lib/types/mobile/PairRequiredView.d.ts.map +1 -0
  36. package/lib/types/mobile/PairRequiredView.js +28 -0
  37. package/lib/types/mobile/PairRequiredView.test.d.ts +2 -0
  38. package/lib/types/mobile/PairRequiredView.test.d.ts.map +1 -0
  39. package/lib/types/mobile/PairRequiredView.test.js +24 -0
  40. package/lib/types/mobile/api.d.ts +10 -0
  41. package/lib/types/mobile/api.d.ts.map +1 -1
  42. package/lib/types/mobile/api.js +4 -0
  43. package/lib/types/mobile/index.js +14 -1
  44. package/lib/types/mobile/messages.d.ts +24 -0
  45. package/lib/types/mobile/messages.d.ts.map +1 -1
  46. package/lib/types/mobile/messages.js +60 -23
  47. package/lib/types/mobile/messages.test.js +49 -1
  48. package/lib/types/mobile/mobile-styles.d.ts +1 -1
  49. package/lib/types/mobile/mobile-styles.d.ts.map +1 -1
  50. package/lib/types/mobile/mobile-styles.js +86 -0
  51. package/lib/types/mobile/pairing.d.ts +31 -0
  52. package/lib/types/mobile/pairing.d.ts.map +1 -0
  53. package/lib/types/mobile/pairing.js +62 -0
  54. package/lib/types/mobile/views/App.d.ts +12 -5
  55. package/lib/types/mobile/views/App.d.ts.map +1 -1
  56. package/lib/types/mobile/views/App.js +34 -7
  57. package/lib/types/mobile/views/App.test.d.ts +2 -0
  58. package/lib/types/mobile/views/App.test.d.ts.map +1 -0
  59. package/lib/types/mobile/views/App.test.js +52 -0
  60. package/lib/types/mobile/views/ChatView.d.ts.map +1 -1
  61. package/lib/types/mobile/views/ChatView.js +34 -11
  62. package/lib/types/mobile/views/SessionListView.d.ts.map +1 -1
  63. package/lib/types/mobile/views/SessionListView.js +30 -4
  64. package/lib/types/mobile/views/SessionListView.test.js +58 -1
  65. package/lib/types/mobile/views/WorkspaceView.d.ts.map +1 -1
  66. package/lib/types/mobile/views/WorkspaceView.js +4 -2
  67. package/lib/types/mobile-api.d.ts.map +1 -1
  68. package/lib/types/mobile-api.js +10 -1
  69. package/lib/types/mobile-pwa.d.ts +6 -0
  70. package/lib/types/mobile-pwa.d.ts.map +1 -0
  71. package/lib/types/mobile-pwa.js +17 -0
  72. package/lib/types/mobile-routes.d.ts +5 -8
  73. package/lib/types/mobile-routes.d.ts.map +1 -1
  74. package/lib/types/mobile-routes.js +115 -30
  75. package/lib/types/pairing-access.d.ts +28 -0
  76. package/lib/types/pairing-access.d.ts.map +1 -0
  77. package/lib/types/pairing-access.js +26 -0
  78. package/lib/types/pairing.d.ts +27 -0
  79. package/lib/types/pairing.d.ts.map +1 -1
  80. package/lib/types/pairing.js +68 -0
  81. package/lib/types/pairing.persist.test.d.ts +2 -0
  82. package/lib/types/pairing.persist.test.d.ts.map +1 -0
  83. package/lib/types/pairing.persist.test.js +128 -0
  84. package/lib/types/routes.d.ts.map +1 -1
  85. package/lib/types/routes.js +23 -3
  86. package/lib/types/tunnel.d.ts +1 -0
  87. package/lib/types/tunnel.d.ts.map +1 -1
  88. package/lib/types/tunnel.js +7 -2
  89. package/lib/types/update.d.ts +4 -4
  90. package/lib/types/update.d.ts.map +1 -1
  91. package/lib/types/update.js +35 -12
  92. package/package.json +12 -12
  93. package/src/client/PluginSettingsCard.tsx +229 -18
  94. package/src/client/RemoteEntry.tsx +12 -2
  95. package/src/client/RemoteSettingsCard.tsx +3 -2
  96. package/src/client/UpdateEntry.tsx +36 -4
  97. package/src/client/UpdatePanel.tsx +2 -0
  98. package/src/client/deep-link.ts +1 -1
  99. package/src/client/locales.ts +4 -0
  100. package/src/client/remote.module.css +26 -0
  101. package/src/client/settings-card.module.css +90 -1
  102. package/src/gate.ts +17 -3
  103. package/src/index.ts +46 -15
  104. package/src/mobile/PairRequiredView.test.tsx +28 -0
  105. package/src/mobile/PairRequiredView.tsx +58 -0
  106. package/src/mobile/api.ts +14 -1
  107. package/src/mobile/index.tsx +15 -1
  108. package/src/mobile/messages.test.ts +52 -1
  109. package/src/mobile/messages.ts +65 -22
  110. package/src/mobile/mobile-styles.ts +86 -0
  111. package/src/mobile/pairing.ts +77 -0
  112. package/src/mobile/views/App.test.tsx +62 -0
  113. package/src/mobile/views/App.tsx +53 -6
  114. package/src/mobile/views/ChatView.tsx +33 -10
  115. package/src/mobile/views/SessionListView.test.tsx +69 -1
  116. package/src/mobile/views/SessionListView.tsx +58 -5
  117. package/src/mobile/views/WorkspaceView.tsx +4 -2
  118. package/src/mobile-api.ts +9 -1
  119. package/src/mobile-pwa.ts +19 -0
  120. package/src/mobile-routes.ts +123 -30
  121. package/src/pairing-access.ts +36 -0
  122. package/src/pairing.persist.test.ts +145 -0
  123. package/src/pairing.ts +70 -1
  124. package/src/routes.ts +23 -3
  125. package/src/tunnel.ts +7 -2
  126. package/src/update.ts +42 -14
package/lib/client.js CHANGED
@@ -1343,7 +1343,7 @@ window.__ModuleLoader__.load({
1343
1343
  }
1344
1344
  //#endregion
1345
1345
  //#region \0dsh-css:packages/dsh-remote-web-ui/src/client/remote.module.css.mjs
1346
- const css$1 = ".fThDlq_overlay{z-index:1000;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.fThDlq_mask{background:var(--dsw-alias-bg-mask-1);backdrop-filter:var(--dsw-mask-blur);position:absolute;inset:0}.fThDlq_trigger{width:36px;height:36px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:50%;flex:none;justify-content:center;align-items:center;padding:0;transition:background-color .12s,color .12s,box-shadow .12s;display:inline-flex}.fThDlq_trigger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.fThDlq_trigger:active:not(:disabled){background:var(--dsw-alias-interactive-bg-active)}.fThDlq_trigger:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-bg-layer-2), 0 0 0 4px var(--dsw-alias-brand-primary);outline:none}.fThDlq_trigger:disabled{opacity:.5;cursor:default}.fThDlq_panel{z-index:1;box-sizing:border-box;background:var(--dsw-alias-bg-layer-2);width:560px;max-width:calc(100vw - 48px);max-height:calc(100vh - 48px);box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);border-radius:24px;flex-direction:column;gap:14px;padding:24px;font-size:14px;line-height:22px;display:flex;position:relative;overflow:auto}.fThDlq_header{align-items:flex-start;gap:12px;display:flex}.fThDlq_heading{flex:1;min-width:0}.fThDlq_title{margin:0;font-size:18px;font-weight:600;line-height:26px}.fThDlq_subtitle{color:var(--dsw-alias-label-secondary);margin:4px 0 0;font-size:13px}.fThDlq_close{width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:50%;flex:none;justify-content:center;align-items:center;padding:0;transition:background-color .12s,color .12s,box-shadow .12s;display:inline-flex}.fThDlq_close:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.fThDlq_close:active:not(:disabled){background:var(--dsw-alias-interactive-bg-active)}.fThDlq_close:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-bg-layer-2), 0 0 0 4px var(--dsw-alias-brand-primary);outline:none}.fThDlq_close:disabled{opacity:.5;cursor:default}.fThDlq_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:16px;flex-direction:column;align-items:center;gap:12px;padding:16px;display:flex}.fThDlq_cardHeader{justify-content:space-between;align-items:center;gap:12px;width:100%;display:flex}.fThDlq_cardTitle{font-weight:500}.fThDlq_badge{white-space:nowrap;border-radius:999px;flex:none;align-items:center;gap:6px;min-width:0;padding:2px 10px;font-size:12px;line-height:18px;display:inline-flex}.fThDlq_badge:before{content:\"\";background:currentColor;border-radius:50%;width:8px;height:8px}.fThDlq_badge-waiting{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover)}.fThDlq_badge-connected{color:var(--dsw-alias-state-success-primary);background:var(--dsw-alias-interactive-bg-hover)}.fThDlq_badge-disconnected{color:var(--dsw-alias-state-warn-primary);background:var(--dsw-alias-interactive-bg-hover)}.fThDlq_badge-stopped{color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-interactive-bg-hover)}.fThDlq_badgePublic{color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-interactive-bg-hover)}.fThDlq_badges{flex:none;align-items:center;gap:6px;display:inline-flex}.fThDlq_qrWrap{background:var(--dsw-alias-bg-base);border-radius:12px;justify-content:center;align-items:center;padding:12px;display:flex}.fThDlq_qr{display:block}.fThDlq_expired{color:var(--dsw-alias-state-error-primary);margin:0;font-size:13px}.fThDlq_expiry{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px}.fThDlq_hint{color:var(--dsw-alias-label-secondary);margin:0;font-size:13px}.fThDlq_link{text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-caption);font-family:var(--dsw-font-mono,ui-monospace, monospace);margin:0;font-size:12px;overflow:hidden}.fThDlq_stoppedHint{color:var(--dsw-alias-state-error-primary);margin:0;font-size:13px}.fThDlq_tunnelNote{color:var(--dsw-alias-label-secondary);margin:0;font-size:13px}.fThDlq_tunnelFailed{color:var(--dsw-alias-state-error-primary);margin:0;font-size:13px}.fThDlq_actions{gap:8px;display:flex}.fThDlq_action{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-button-elevated-fill);height:34px;color:var(--dsw-alias-label-primary);cursor:pointer;white-space:nowrap;border-radius:10px;justify-content:center;align-items:center;gap:6px;padding:0 14px;font-size:13px;transition:background-color .12s,border-color .12s,box-shadow .12s;display:inline-flex}.fThDlq_action:hover:not(:disabled){background:var(--dsw-alias-button-floating-hover)}.fThDlq_action:active:not(:disabled){background:var(--dsw-alias-interactive-bg-active)}.fThDlq_action:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-bg-layer-2), 0 0 0 4px var(--dsw-alias-brand-primary);outline:none}.fThDlq_action:disabled{opacity:.5;cursor:default}.fThDlq_banner{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:16px;padding:16px}.fThDlq_bannerTitle{color:var(--dsw-alias-state-warn-primary);margin:0;font-weight:500}.fThDlq_bannerHint{color:var(--dsw-alias-label-secondary);margin:6px 0 0;font-size:13px}.fThDlq_notice{z-index:2000;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);max-width:min(420px,100vw - 32px);box-shadow:var(--dsw-shadow-lv3);border-radius:12px;padding:12px 16px;position:fixed;top:16px;left:50%;transform:translate(-50%)}.fThDlq_noticeTitle{color:var(--dsw-alias-state-error-primary);margin:0;font-weight:500}.fThDlq_noticeDetail{color:var(--dsw-alias-label-secondary);margin:4px 0 0;font-size:13px}.fThDlq_addresses{border:none;margin:12px 0 0;padding:0}.fThDlq_addresses legend{color:var(--dsw-alias-label-secondary);padding:0;font-size:13px}.fThDlq_address{color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;cursor:pointer;border-radius:6px;align-items:center;gap:8px;margin-top:6px;padding:4px 6px;font-size:13px;transition:background-color .12s;display:flex}.fThDlq_address:hover{background:var(--dsw-alias-interactive-bg-hover)}.fThDlq_address input:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-bg-layer-2), 0 0 0 4px var(--dsw-alias-brand-primary);border-radius:50%;outline:none}.fThDlq_addressValue{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-secondary);flex:1;font-size:12px;overflow:hidden}.fThDlq_addressHint{color:var(--dsw-alias-label-tertiary);margin:6px 0 0;font-size:12px}@media (prefers-reduced-motion:reduce){.fThDlq_trigger,.fThDlq_close,.fThDlq_action,.fThDlq_address{transition:none}}.fThDlq_entryRow{flex:none;align-items:center;gap:6px;display:flex}.fThDlq_entryRow[data-rail=rail]{flex-direction:column-reverse;gap:4px}.fThDlq_updateStatus{margin:0;font-weight:600}.fThDlq_updateDetail{color:var(--dsw-alias-label-secondary);margin:6px 0 0;font-size:13px}.fThDlq_updateError{color:var(--dsw-alias-text-danger,var(--dsw-alias-label-primary));margin:0;font-weight:600}.fThDlq_updateOutput{background:var(--dsw-alias-bg-layer-1);max-height:180px;color:var(--dsw-alias-label-secondary);white-space:pre-wrap;word-break:break-all;border-radius:10px;margin:10px 0 0;padding:10px 12px;font-size:12px;line-height:18px;overflow:auto}.fThDlq_updateList{flex-direction:column;gap:6px;margin:12px 0 0;padding:0;list-style:none;display:flex}.fThDlq_updateListItem{justify-content:space-between;align-items:baseline;gap:12px;font-size:13px;display:flex}.fThDlq_updateListName{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);overflow:hidden}.fThDlq_updateListVersions{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none}.fThDlq_updateActions{justify-content:flex-end;margin-top:16px;display:flex}.fThDlq_updateRetry{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:10px;align-items:center;gap:6px;padding:8px 14px;font-size:13px;transition:background-color .12s,color .12s;display:inline-flex}.fThDlq_updateRetry:hover{background:var(--dsw-alias-interactive-bg-active)}@media (prefers-reduced-motion:reduce){.fThDlq_updateRetry{transition:none}}";
1346
+ const css$1 = ".fThDlq_overlay{z-index:1000;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.fThDlq_mask{background:var(--dsw-alias-bg-mask-1);backdrop-filter:var(--dsw-mask-blur);position:absolute;inset:0}.fThDlq_trigger{width:36px;height:36px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:50%;flex:none;justify-content:center;align-items:center;padding:0;transition:background-color .12s,color .12s,box-shadow .12s;display:inline-flex;position:relative}.fThDlq_trigger[data-update-available]:after{box-sizing:border-box;border:2px solid var(--dsw-alias-bg-layer-1);background:var(--dsw-alias-brand-primary);content:\"\";pointer-events:none;border-radius:50%;width:8px;height:8px;position:absolute;top:4px;right:4px}.fThDlq_trigger[data-wide=wide]{border-radius:8px;flex:auto;justify-content:flex-start;gap:8px;width:auto;min-width:0;padding:0 10px}.fThDlq_trigger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.fThDlq_trigger:active:not(:disabled){background:var(--dsw-alias-interactive-bg-active)}.fThDlq_trigger:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-bg-layer-2), 0 0 0 4px var(--dsw-alias-brand-primary);outline:none}.fThDlq_trigger:disabled{opacity:.5;cursor:default}.fThDlq_panel{z-index:1;box-sizing:border-box;background:var(--dsw-alias-bg-layer-2);width:560px;max-width:calc(100vw - 48px);max-height:calc(100vh - 48px);box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);border-radius:24px;flex-direction:column;gap:14px;padding:24px;font-size:14px;line-height:22px;display:flex;position:relative;overflow:auto}.fThDlq_header{align-items:flex-start;gap:12px;display:flex}.fThDlq_heading{flex:1;min-width:0}.fThDlq_title{margin:0;font-size:18px;font-weight:600;line-height:26px}.fThDlq_subtitle{color:var(--dsw-alias-label-secondary);margin:4px 0 0;font-size:13px}.fThDlq_close{width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:50%;flex:none;justify-content:center;align-items:center;padding:0;transition:background-color .12s,color .12s,box-shadow .12s;display:inline-flex}.fThDlq_close:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.fThDlq_close:active:not(:disabled){background:var(--dsw-alias-interactive-bg-active)}.fThDlq_close:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-bg-layer-2), 0 0 0 4px var(--dsw-alias-brand-primary);outline:none}.fThDlq_close:disabled{opacity:.5;cursor:default}.fThDlq_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:16px;flex-direction:column;align-items:center;gap:12px;padding:16px;display:flex}.fThDlq_cardHeader{justify-content:space-between;align-items:center;gap:12px;width:100%;display:flex}.fThDlq_cardTitle{font-weight:500}.fThDlq_badge{white-space:nowrap;border-radius:999px;flex:none;align-items:center;gap:6px;min-width:0;padding:2px 10px;font-size:12px;line-height:18px;display:inline-flex}.fThDlq_badge:before{content:\"\";background:currentColor;border-radius:50%;width:8px;height:8px}.fThDlq_badge-waiting{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover)}.fThDlq_badge-connected{color:var(--dsw-alias-state-success-primary);background:var(--dsw-alias-interactive-bg-hover)}.fThDlq_badge-disconnected{color:var(--dsw-alias-state-warn-primary);background:var(--dsw-alias-interactive-bg-hover)}.fThDlq_badge-stopped{color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-interactive-bg-hover)}.fThDlq_badgePublic{color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-interactive-bg-hover)}.fThDlq_badges{flex:none;align-items:center;gap:6px;display:inline-flex}.fThDlq_qrWrap{background:var(--dsw-alias-bg-base);border-radius:12px;justify-content:center;align-items:center;padding:12px;display:flex}.fThDlq_qr{display:block}.fThDlq_expired{color:var(--dsw-alias-state-error-primary);margin:0;font-size:13px}.fThDlq_expiry{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px}.fThDlq_hint{color:var(--dsw-alias-label-secondary);margin:0;font-size:13px}.fThDlq_link{text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-caption);font-family:var(--dsw-font-mono,ui-monospace, monospace);margin:0;font-size:12px;overflow:hidden}.fThDlq_stoppedHint{color:var(--dsw-alias-state-error-primary);margin:0;font-size:13px}.fThDlq_tunnelNote{color:var(--dsw-alias-label-secondary);margin:0;font-size:13px}.fThDlq_tunnelFailed{color:var(--dsw-alias-state-error-primary);margin:0;font-size:13px}.fThDlq_actions{gap:8px;display:flex}.fThDlq_action{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-button-elevated-fill);height:34px;color:var(--dsw-alias-label-primary);cursor:pointer;white-space:nowrap;border-radius:10px;justify-content:center;align-items:center;gap:6px;padding:0 14px;font-size:13px;transition:background-color .12s,border-color .12s,box-shadow .12s;display:inline-flex}.fThDlq_action:hover:not(:disabled){background:var(--dsw-alias-button-floating-hover)}.fThDlq_action:active:not(:disabled){background:var(--dsw-alias-interactive-bg-active)}.fThDlq_action:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-bg-layer-2), 0 0 0 4px var(--dsw-alias-brand-primary);outline:none}.fThDlq_action:disabled{opacity:.5;cursor:default}.fThDlq_banner{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:16px;padding:16px}.fThDlq_bannerTitle{color:var(--dsw-alias-state-warn-primary);margin:0;font-weight:500}.fThDlq_bannerHint{color:var(--dsw-alias-label-secondary);margin:6px 0 0;font-size:13px}.fThDlq_notice{z-index:2000;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);max-width:min(420px,100vw - 32px);box-shadow:var(--dsw-shadow-lv3);border-radius:12px;padding:12px 16px;position:fixed;top:16px;left:50%;transform:translate(-50%)}.fThDlq_noticeTitle{color:var(--dsw-alias-state-error-primary);margin:0;font-weight:500}.fThDlq_noticeDetail{color:var(--dsw-alias-label-secondary);margin:4px 0 0;font-size:13px}.fThDlq_addresses{border:none;margin:12px 0 0;padding:0}.fThDlq_addresses legend{color:var(--dsw-alias-label-secondary);padding:0;font-size:13px}.fThDlq_address{color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;cursor:pointer;border-radius:6px;align-items:center;gap:8px;margin-top:6px;padding:4px 6px;font-size:13px;transition:background-color .12s;display:flex}.fThDlq_address:hover{background:var(--dsw-alias-interactive-bg-hover)}.fThDlq_address input:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-bg-layer-2), 0 0 0 4px var(--dsw-alias-brand-primary);border-radius:50%;outline:none}.fThDlq_addressValue{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-secondary);flex:1;font-size:12px;overflow:hidden}.fThDlq_addressHint{color:var(--dsw-alias-label-tertiary);margin:6px 0 0;font-size:12px}@media (prefers-reduced-motion:reduce){.fThDlq_trigger,.fThDlq_close,.fThDlq_action,.fThDlq_address{transition:none}}.fThDlq_entryRow{flex:none;align-items:center;gap:6px;min-width:0;display:flex}.fThDlq_entryRow[data-rail=rail]{flex-direction:column-reverse;gap:4px}.fThDlq_updateStatus{margin:0;font-weight:600}.fThDlq_updateDetail{color:var(--dsw-alias-label-secondary);margin:6px 0 0;font-size:13px}.fThDlq_updateError{color:var(--dsw-alias-text-danger,var(--dsw-alias-label-primary));margin:0;font-weight:600}.fThDlq_updateOutput{background:var(--dsw-alias-bg-layer-1);max-height:180px;color:var(--dsw-alias-label-secondary);white-space:pre-wrap;word-break:break-all;border-radius:10px;margin:10px 0 0;padding:10px 12px;font-size:12px;line-height:18px;overflow:auto}.fThDlq_updateList{flex-direction:column;gap:6px;margin:12px 0 0;padding:0;list-style:none;display:flex}.fThDlq_updateListItem{justify-content:space-between;align-items:baseline;gap:12px;font-size:13px;display:flex}.fThDlq_updateListName{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);overflow:hidden}.fThDlq_updateListVersions{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none}.fThDlq_updateActions{justify-content:flex-end;margin-top:16px;display:flex}.fThDlq_updateRetry{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:10px;align-items:center;gap:6px;padding:8px 14px;font-size:13px;transition:background-color .12s,color .12s;display:inline-flex}.fThDlq_updateRetry:hover{background:var(--dsw-alias-interactive-bg-active)}@media (prefers-reduced-motion:reduce){.fThDlq_updateRetry{transition:none}}";
1347
1347
  const tagId$1 = "@linxin666/dsh-remote-web-ui/remote.module.css";
1348
1348
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
1349
1349
  const tag = document.createElement("style");
@@ -1740,13 +1740,20 @@ window.__ModuleLoader__.load({
1740
1740
  t,
1741
1741
  status
1742
1742
  }),
1743
- view.kind === "updating" && status !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1744
- className: remote_module_css_default.updateStatus,
1745
- children: t("update.updating", {
1746
- name: anchorName(status) ?? "",
1747
- version: anchorLatest(status) ?? ""
1748
- })
1749
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PackageList, { status })] }),
1743
+ view.kind === "updating" && status !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
1744
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1745
+ className: remote_module_css_default.updateStatus,
1746
+ children: t("update.updating", {
1747
+ name: anchorName(status) ?? "",
1748
+ version: anchorLatest(status) ?? ""
1749
+ })
1750
+ }),
1751
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1752
+ className: remote_module_css_default.updateDetail,
1753
+ children: t("update.cooldownNotice")
1754
+ }),
1755
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PackageList, { status })
1756
+ ] }),
1750
1757
  view.kind === "done" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DoneBody, {
1751
1758
  t,
1752
1759
  result: view.result
@@ -1809,16 +1816,23 @@ window.__ModuleLoader__.load({
1809
1816
  className: remote_module_css_default.updateDetail,
1810
1817
  children: t("update.offlineDetail")
1811
1818
  })] });
1812
- if (status.outdated) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1813
- className: remote_module_css_default.updateStatus,
1814
- children: t("update.found")
1815
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1816
- className: remote_module_css_default.updateDetail,
1817
- children: anchor !== void 0 ? t("update.foundDetail", {
1818
- name: anchor,
1819
- version: latest ?? ""
1820
- }) : ""
1821
- })] });
1819
+ if (status.outdated) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
1820
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1821
+ className: remote_module_css_default.updateStatus,
1822
+ children: t("update.found")
1823
+ }),
1824
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1825
+ className: remote_module_css_default.updateDetail,
1826
+ children: anchor !== void 0 ? t("update.foundDetail", {
1827
+ name: anchor,
1828
+ version: latest ?? ""
1829
+ }) : ""
1830
+ }),
1831
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1832
+ className: remote_module_css_default.updateDetail,
1833
+ children: t("update.cooldownNotice")
1834
+ })
1835
+ ] });
1822
1836
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
1823
1837
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1824
1838
  className: remote_module_css_default.updateStatus,
@@ -1899,13 +1913,27 @@ window.__ModuleLoader__.load({
1899
1913
  function UpdateEntry({ wide, t }) {
1900
1914
  const [open, setOpen] = (0, react.useState)(false);
1901
1915
  const [view, setView] = (0, react.useState)({ kind: "checking" });
1916
+ const [updateAvailable, setUpdateAvailable] = (0, react.useState)(false);
1902
1917
  const runToken = (0, react.useRef)(0);
1918
+ const availabilityToken = (0, react.useRef)(0);
1919
+ const mounted = (0, react.useRef)(false);
1920
+ const probeAvailability = (0, react.useCallback)(async () => {
1921
+ const token = ++availabilityToken.current;
1922
+ try {
1923
+ const status = await fetchUpdateStatus();
1924
+ if (token === availabilityToken.current) setUpdateAvailable(status.mode === "npm" && status.outdated);
1925
+ } catch {
1926
+ if (token === availabilityToken.current) setUpdateAvailable(false);
1927
+ }
1928
+ }, []);
1903
1929
  const check = (0, react.useCallback)(async () => {
1930
+ const availabilityCheck = ++availabilityToken.current;
1904
1931
  setView({ kind: "checking" });
1905
1932
  let status;
1906
1933
  try {
1907
1934
  status = await fetchUpdateStatus();
1908
1935
  } catch (error) {
1936
+ if (availabilityCheck === availabilityToken.current) setUpdateAvailable(false);
1909
1937
  if (error instanceof UpdateStatusError && error.status === 404) {
1910
1938
  setView({
1911
1939
  kind: "error",
@@ -1921,6 +1949,7 @@ window.__ModuleLoader__.load({
1921
1949
  });
1922
1950
  return;
1923
1951
  }
1952
+ if (availabilityCheck === availabilityToken.current) setUpdateAvailable(status.mode === "npm" && status.outdated);
1924
1953
  if (status.error === "registry-unreachable") {
1925
1954
  setView({
1926
1955
  kind: "result",
@@ -1940,6 +1969,7 @@ window.__ModuleLoader__.load({
1940
1969
  const token = ++runToken.current;
1941
1970
  try {
1942
1971
  const result = await runUpdate();
1972
+ if (result.ok && mounted.current) setUpdateAvailable(false);
1943
1973
  if (token !== runToken.current) return;
1944
1974
  setView({
1945
1975
  kind: "done",
@@ -1962,15 +1992,23 @@ window.__ModuleLoader__.load({
1962
1992
  runToken.current++;
1963
1993
  setOpen(false);
1964
1994
  }, []);
1965
- (0, react.useEffect)(() => () => {
1966
- runToken.current++;
1967
- }, []);
1995
+ (0, react.useEffect)(() => {
1996
+ mounted.current = true;
1997
+ probeAvailability();
1998
+ return () => {
1999
+ mounted.current = false;
2000
+ runToken.current++;
2001
+ availabilityToken.current++;
2002
+ };
2003
+ }, [probeAvailability]);
2004
+ const updateLabel = updateAvailable ? t("update.availableLabel") : t("update.label");
1968
2005
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1969
2006
  type: "button",
1970
2007
  className: remote_module_css_default.trigger,
1971
2008
  "data-wide": wide ? void 0 : "rail",
1972
- "aria-label": t("update.label"),
1973
- title: t("update.label"),
2009
+ "data-update-available": updateAvailable ? "true" : void 0,
2010
+ "aria-label": updateLabel,
2011
+ title: updateLabel,
1974
2012
  onClick: openPanel,
1975
2013
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconDownloadOutline16, { size: wide ? 16 : 18 })
1976
2014
  }), open && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -2034,6 +2072,7 @@ window.__ModuleLoader__.load({
2034
2072
  }, [state]);
2035
2073
  const [copied, setCopied] = (0, react.useState)(false);
2036
2074
  const eventSource = (0, react.useRef)(void 0);
2075
+ const openSeq = (0, react.useRef)(0);
2037
2076
  const workspaceId = useWorkspaces((s) => s.recentWorkspaceId);
2038
2077
  const closeEventSource = (0, react.useCallback)(() => {
2039
2078
  eventSource.current?.close();
@@ -2067,8 +2106,10 @@ window.__ModuleLoader__.load({
2067
2106
  };
2068
2107
  }, [workspaceId]);
2069
2108
  const openPanel = (0, react.useCallback)(async () => {
2109
+ const seq = ++openSeq.current;
2070
2110
  setOpen(true);
2071
2111
  const next = await mint();
2112
+ if (seq !== openSeq.current) return;
2072
2113
  setState(next);
2073
2114
  if (next.kind !== "ready" && next.kind !== "lan-required") return;
2074
2115
  const source = new EventSource("/api/pair/events");
@@ -2087,6 +2128,7 @@ window.__ModuleLoader__.load({
2087
2128
  };
2088
2129
  }, [mint]);
2089
2130
  const closePanel = (0, react.useCallback)(() => {
2131
+ openSeq.current += 1;
2090
2132
  closeEventSource();
2091
2133
  setOpen(false);
2092
2134
  }, [closeEventSource]);
@@ -2171,12 +2213,12 @@ window.__ModuleLoader__.load({
2171
2213
  })]
2172
2214
  }), document.body)] });
2173
2215
  }
2174
- /** The trigger: an icon button matching the settings rail/row geometry. */
2216
+ /** The trigger: an icon-only control with a persistent accessible label. */
2175
2217
  function TooltipAnchor({ wide, label, onClick }) {
2176
2218
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2177
2219
  type: "button",
2178
2220
  className: remote_module_css_default.trigger,
2179
- "data-wide": wide ? void 0 : "rail",
2221
+ "data-wide": wide ? "wide" : "rail",
2180
2222
  "aria-label": label,
2181
2223
  title: label,
2182
2224
  onClick,
@@ -2236,7 +2278,7 @@ window.__ModuleLoader__.load({
2236
2278
  }
2237
2279
  //#endregion
2238
2280
  //#region \0dsh-css:packages/dsh-remote-web-ui/src/client/settings-card.module.css.mjs
2239
- const css = ".Kwoi6G_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.Kwoi6G_card:hover{border-color:var(--dsw-alias-label-dimmed)}.Kwoi6G_cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.Kwoi6G_header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.Kwoi6G_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.Kwoi6G_headerStatic{border-radius:12px;align-items:center;gap:12px;width:100%;padding:14px 16px;display:flex}.Kwoi6G_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.Kwoi6G_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.Kwoi6G_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.Kwoi6G_pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.Kwoi6G_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.Kwoi6G_chevronOpen{transform:rotate(180deg)}.Kwoi6G_body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.Kwoi6G_readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.Kwoi6G_notExposed{color:var(--dsw-alias-state-warn-primary);margin:12px 0 0;font-size:12px;line-height:1.5}.Kwoi6G_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.Kwoi6G_failed{min-width:0;color:var(--dsw-alias-label-error);text-overflow:ellipsis;white-space:nowrap;flex:1;margin:0;font-size:12px;line-height:1.5;overflow:hidden}.Kwoi6G_discard,.Kwoi6G_save{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.Kwoi6G_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.Kwoi6G_discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.Kwoi6G_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.Kwoi6G_discard:disabled,.Kwoi6G_save:disabled{opacity:.4;cursor:default}.Kwoi6G_discard:focus-visible,.Kwoi6G_save:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.Kwoi6G_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.Kwoi6G_field+.Kwoi6G_field{border-top:1px solid var(--dsw-alias-border-l2)}.Kwoi6G_head{align-items:center;gap:8px;display:flex}.Kwoi6G_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.Kwoi6G_badges{align-items:center;gap:8px;display:inline-flex}.Kwoi6G_badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.Kwoi6G_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.Kwoi6G_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.Kwoi6G_reset:disabled{cursor:default}.Kwoi6G_reset:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px;outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.Kwoi6G_input,.Kwoi6G_select{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.Kwoi6G_input:focus-visible,.Kwoi6G_select:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.Kwoi6G_input:disabled,.Kwoi6G_select:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.Kwoi6G_inputInvalid{border:1px solid var(--dsw-alias-label-error);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.Kwoi6G_inputInvalid:focus-visible{outline:2px solid var(--dsw-alias-label-error);outline-offset:1px;border-color:var(--dsw-alias-label-error)}.Kwoi6G_invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.Kwoi6G_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}@media (prefers-reduced-motion:reduce){.Kwoi6G_card,.Kwoi6G_header,.Kwoi6G_chevron,.Kwoi6G_chevronOpen,.Kwoi6G_discard,.Kwoi6G_save{transition:none}}";
2281
+ const css = ".Kwoi6G_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.Kwoi6G_card:hover{border-color:var(--dsw-alias-label-dimmed)}.Kwoi6G_cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.Kwoi6G_header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.Kwoi6G_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.Kwoi6G_headerStatic{border-radius:12px;align-items:center;gap:12px;width:100%;padding:14px 16px;display:flex}.Kwoi6G_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.Kwoi6G_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.Kwoi6G_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.Kwoi6G_pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.Kwoi6G_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.Kwoi6G_chevronOpen{transform:rotate(180deg)}.Kwoi6G_body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.Kwoi6G_readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.Kwoi6G_notExposed{color:var(--dsw-alias-state-warn-primary);margin:12px 0 0;font-size:12px;line-height:1.5}.Kwoi6G_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.Kwoi6G_failed{min-width:0;color:var(--dsw-alias-label-error);text-overflow:ellipsis;white-space:nowrap;flex:1;margin:0;font-size:12px;line-height:1.5;overflow:hidden}.Kwoi6G_discard,.Kwoi6G_save{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.Kwoi6G_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.Kwoi6G_discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.Kwoi6G_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.Kwoi6G_discard:disabled,.Kwoi6G_save:disabled{opacity:.4;cursor:default}.Kwoi6G_discard:focus-visible,.Kwoi6G_save:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.Kwoi6G_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.Kwoi6G_field+.Kwoi6G_field{border-top:1px solid var(--dsw-alias-border-l2)}.Kwoi6G_head{align-items:center;gap:8px;display:flex}.Kwoi6G_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.Kwoi6G_badges{align-items:center;gap:8px;display:inline-flex}.Kwoi6G_badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.Kwoi6G_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.Kwoi6G_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.Kwoi6G_reset:disabled{cursor:default}.Kwoi6G_reset:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px;outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.Kwoi6G_input,.Kwoi6G_select{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.Kwoi6G_input:focus-visible,.Kwoi6G_select:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.Kwoi6G_input:disabled,.Kwoi6G_select:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.Kwoi6G_inputInvalid{border:1px solid var(--dsw-alias-label-error);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.Kwoi6G_inputInvalid:focus-visible{outline:2px solid var(--dsw-alias-label-error);outline-offset:1px;border-color:var(--dsw-alias-label-error)}.Kwoi6G_selectWrap{position:relative}.Kwoi6G_selectButton{appearance:none;text-align:left;cursor:pointer;justify-content:space-between;align-items:center;gap:8px;width:100%;display:flex}.Kwoi6G_selectLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.Kwoi6G_selectChevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.Kwoi6G_selectChevronOpen{transform:rotate(180deg)}.Kwoi6G_selectPopup{z-index:40;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);max-height:240px;box-shadow:0 8px 24px var(--dsw-alias-bg-mask-2);opacity:0;border-radius:8px;flex-direction:column;padding:4px;transition:opacity .1s,transform .1s;display:flex;position:absolute;top:calc(100% + 4px);left:0;right:0;overflow-y:auto;transform:translateY(-4px)}.Kwoi6G_selectPopupOpen{opacity:1;transform:none}.Kwoi6G_selectPopupClose{opacity:0;pointer-events:none;transform:translateY(-4px)}.Kwoi6G_selectOption{color:var(--dsw-alias-label-primary);cursor:pointer;white-space:nowrap;text-overflow:ellipsis;border-radius:6px;padding:6px 10px;font-size:13px;line-height:1.5;overflow:hidden}.Kwoi6G_selectOption:hover,.Kwoi6G_selectOptionActive{background:var(--dsw-alias-interactive-bg-hover)}.Kwoi6G_selectOptionSelected{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 10%, transparent);font-weight:500}.Kwoi6G_invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.Kwoi6G_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}@media (prefers-reduced-motion:reduce){.Kwoi6G_card,.Kwoi6G_header,.Kwoi6G_chevron,.Kwoi6G_chevronOpen,.Kwoi6G_discard,.Kwoi6G_save,.Kwoi6G_selectChevron,.Kwoi6G_selectChevronOpen,.Kwoi6G_selectPopup{transition:none}}";
2240
2282
  const tagId = "@linxin666/dsh-remote-web-ui/settings-card.module.css";
2241
2283
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
2242
2284
  const tag = document.createElement("style");
@@ -2273,7 +2315,18 @@ window.__ModuleLoader__.load({
2273
2315
  "readOnly": "Kwoi6G_readOnly",
2274
2316
  "reset": "Kwoi6G_reset",
2275
2317
  "save": "Kwoi6G_save",
2276
- "select": "Kwoi6G_select"
2318
+ "select": "Kwoi6G_select",
2319
+ "selectButton": "Kwoi6G_selectButton",
2320
+ "selectChevron": "Kwoi6G_selectChevron",
2321
+ "selectChevronOpen": "Kwoi6G_selectChevronOpen",
2322
+ "selectLabel": "Kwoi6G_selectLabel",
2323
+ "selectOption": "Kwoi6G_selectOption",
2324
+ "selectOptionActive": "Kwoi6G_selectOptionActive",
2325
+ "selectOptionSelected": "Kwoi6G_selectOptionSelected",
2326
+ "selectPopup": "Kwoi6G_selectPopup",
2327
+ "selectPopupClose": "Kwoi6G_selectPopupClose",
2328
+ "selectPopupOpen": "Kwoi6G_selectPopupOpen",
2329
+ "selectWrap": "Kwoi6G_selectWrap"
2277
2330
  };
2278
2331
  //#endregion
2279
2332
  //#region src/client/PluginSettingsCard.tsx
@@ -2379,7 +2432,7 @@ window.__ModuleLoader__.load({
2379
2432
  children: props.t("settings.readOnly")
2380
2433
  }) : null,
2381
2434
  props.children,
2382
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2435
+ props.hideFooter === true ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2383
2436
  className: settings_card_module_css_default.footer,
2384
2437
  children: [
2385
2438
  state.failed ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
@@ -2452,6 +2505,175 @@ window.__ModuleLoader__.load({
2452
2505
  ]
2453
2506
  });
2454
2507
  }
2508
+ const NON_SKIN_BODY_MARKERS = /* @__PURE__ */ new Set(["dshSkinCenter", "dshSidebarCollapsed"]);
2509
+ function isSkinActive() {
2510
+ return Object.keys(document.body.dataset).some((key) => key.startsWith("dsh") && !NON_SKIN_BODY_MARKERS.has(key));
2511
+ }
2512
+ const SELECT_CLOSE_MS = 100;
2513
+ /**
2514
+ * The shared dual-mode select control. While an appearance skin is active it
2515
+ * renders the legacy native `<select>` untouched, so element-level skin
2516
+ * selectors keep working; under the default appearance it renders a
2517
+ * self-drawn `role="listbox"` popup whose open/close is transition-animated.
2518
+ * Staged cards reach it through BooleanField/ChoiceField; immediate-apply
2519
+ * editors (the side-card prefs) bind it directly through onEdit.
2520
+ * 双模式下拉框:皮肤激活时用原生 select,默认外观用自绘动画弹层。
2521
+ */
2522
+ function SelectField(props) {
2523
+ const { id, options, value } = props;
2524
+ const [open, setOpen] = (0, react.useState)(false);
2525
+ const [closing, setClosing] = (0, react.useState)(false);
2526
+ const [phase, setPhase] = (0, react.useState)("initial");
2527
+ const [activeIndex, setActiveIndex] = (0, react.useState)(0);
2528
+ const closeTimer = (0, react.useRef)(void 0);
2529
+ const wrapRef = (0, react.useRef)(null);
2530
+ const popupRef = (0, react.useRef)(null);
2531
+ const currentIndex = () => {
2532
+ const index = options.findIndex((option) => option.value === value);
2533
+ return index >= 0 ? index : 0;
2534
+ };
2535
+ const close = (0, react.useCallback)(() => {
2536
+ if (closeTimer.current !== void 0) clearTimeout(closeTimer.current);
2537
+ setClosing(true);
2538
+ closeTimer.current = setTimeout(() => {
2539
+ setClosing(false);
2540
+ setOpen(false);
2541
+ }, SELECT_CLOSE_MS);
2542
+ }, []);
2543
+ const openPopup = () => {
2544
+ if (closeTimer.current !== void 0) clearTimeout(closeTimer.current);
2545
+ setActiveIndex(currentIndex());
2546
+ setPhase("initial");
2547
+ setClosing(false);
2548
+ setOpen(true);
2549
+ };
2550
+ const commit = (index) => {
2551
+ const option = options[index];
2552
+ if (option) props.onEdit(option.value);
2553
+ close();
2554
+ };
2555
+ const onTriggerClick = () => {
2556
+ if (props.disabled) return;
2557
+ if (open && !closing) close();
2558
+ else openPopup();
2559
+ };
2560
+ const onKeyDown = (event) => {
2561
+ if (props.disabled) return;
2562
+ const count = options.length;
2563
+ switch (event.key) {
2564
+ case "ArrowDown":
2565
+ case "ArrowUp":
2566
+ case "Enter":
2567
+ case " ":
2568
+ event.preventDefault();
2569
+ if (!open) openPopup();
2570
+ else if (!closing) if (event.key === "ArrowDown") setActiveIndex((index) => (index + 1) % count);
2571
+ else if (event.key === "ArrowUp") setActiveIndex((index) => (index - 1 + count) % count);
2572
+ else commit(activeIndex);
2573
+ break;
2574
+ case "Escape":
2575
+ if (open) {
2576
+ event.preventDefault();
2577
+ event.stopPropagation();
2578
+ close();
2579
+ }
2580
+ break;
2581
+ case "Tab":
2582
+ if (open) close();
2583
+ break;
2584
+ }
2585
+ };
2586
+ (0, react.useEffect)(() => () => {
2587
+ if (closeTimer.current !== void 0) clearTimeout(closeTimer.current);
2588
+ }, []);
2589
+ (0, react.useLayoutEffect)(() => {
2590
+ if (open && !closing && phase === "initial") {
2591
+ popupRef.current?.offsetHeight;
2592
+ setPhase("open");
2593
+ }
2594
+ }, [
2595
+ open,
2596
+ closing,
2597
+ phase
2598
+ ]);
2599
+ (0, react.useEffect)(() => {
2600
+ if (!open) return;
2601
+ const onPointerDown = (event) => {
2602
+ const target = event.target;
2603
+ if (target instanceof Node && !wrapRef.current?.contains(target)) close();
2604
+ };
2605
+ document.addEventListener("pointerdown", onPointerDown);
2606
+ return () => document.removeEventListener("pointerdown", onPointerDown);
2607
+ }, [open, close]);
2608
+ (0, react.useEffect)(() => {
2609
+ if (props.disabled && open) close();
2610
+ }, [
2611
+ props.disabled,
2612
+ open,
2613
+ close
2614
+ ]);
2615
+ if (isSkinActive()) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
2616
+ id,
2617
+ className: settings_card_module_css_default.select,
2618
+ value,
2619
+ disabled: props.disabled,
2620
+ onChange: (event) => {
2621
+ props.onEdit(event.target.value);
2622
+ },
2623
+ children: options.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2624
+ value: option.value,
2625
+ children: option.label
2626
+ }, option.value))
2627
+ });
2628
+ const label = options.find((option) => option.value === value)?.label ?? "";
2629
+ const popupClass = closing ? `${settings_card_module_css_default.selectPopup} ${settings_card_module_css_default.selectPopupClose}` : phase === "open" ? `${settings_card_module_css_default.selectPopup} ${settings_card_module_css_default.selectPopupOpen}` : settings_card_module_css_default.selectPopup;
2630
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2631
+ className: settings_card_module_css_default.selectWrap,
2632
+ ref: wrapRef,
2633
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2634
+ type: "button",
2635
+ id,
2636
+ className: `${settings_card_module_css_default.select} ${settings_card_module_css_default.selectButton}`,
2637
+ disabled: props.disabled,
2638
+ "aria-haspopup": "listbox",
2639
+ "aria-expanded": open,
2640
+ "aria-activedescendant": open ? `${id}-o${activeIndex}` : void 0,
2641
+ "aria-invalid": props.invalid || void 0,
2642
+ onClick: onTriggerClick,
2643
+ onKeyDown,
2644
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2645
+ className: settings_card_module_css_default.selectLabel,
2646
+ children: label
2647
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
2648
+ width: "14",
2649
+ height: "14",
2650
+ viewBox: "0 0 14 14",
2651
+ fill: "none",
2652
+ xmlns: "http://www.w3.org/2000/svg",
2653
+ className: open ? `${settings_card_module_css_default.selectChevron} ${settings_card_module_css_default.selectChevronOpen}` : settings_card_module_css_default.selectChevron,
2654
+ "aria-hidden": "true",
2655
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
2656
+ d: "M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z",
2657
+ fill: "currentColor"
2658
+ })
2659
+ })]
2660
+ }), open ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2661
+ className: popupClass,
2662
+ role: "listbox",
2663
+ ref: popupRef,
2664
+ children: options.map((option, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2665
+ id: `${id}-o${index}`,
2666
+ role: "option",
2667
+ "aria-selected": option.value === value,
2668
+ className: `${settings_card_module_css_default.selectOption}${option.value === value ? ` ${settings_card_module_css_default.selectOptionSelected}` : ""}${index === activeIndex && !closing ? ` ${settings_card_module_css_default.selectOptionActive}` : ""}`,
2669
+ onClick: () => {
2670
+ commit(index);
2671
+ },
2672
+ children: option.label
2673
+ }, option.value))
2674
+ }) : null]
2675
+ });
2676
+ }
2455
2677
  /** A staged boolean field: 继承 / 开 / 关. */
2456
2678
  function BooleanField(props) {
2457
2679
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -2477,28 +2699,26 @@ window.__ModuleLoader__.load({
2477
2699
  })]
2478
2700
  }) : null]
2479
2701
  }),
2480
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
2702
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectField, {
2481
2703
  id: props.id,
2482
- className: settings_card_module_css_default.select,
2483
- value: props.text,
2484
- disabled: props.disabled,
2485
- onChange: (event) => {
2486
- props.onEdit(event.target.value);
2487
- },
2488
- children: [
2489
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2704
+ options: [
2705
+ {
2490
2706
  value: "",
2491
- children: props.inheritLabel
2492
- }),
2493
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2707
+ label: props.inheritLabel
2708
+ },
2709
+ {
2494
2710
  value: "true",
2495
- children: props.onLabel
2496
- }),
2497
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2711
+ label: props.onLabel
2712
+ },
2713
+ {
2498
2714
  value: "false",
2499
- children: props.offLabel
2500
- })
2501
- ]
2715
+ label: props.offLabel
2716
+ }
2717
+ ],
2718
+ value: props.text,
2719
+ disabled: props.disabled,
2720
+ invalid: props.invalid,
2721
+ onEdit: props.onEdit
2502
2722
  }),
2503
2723
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2504
2724
  className: settings_card_module_css_default.hint,
@@ -2868,6 +3088,7 @@ window.__ModuleLoader__.load({
2868
3088
  t,
2869
3089
  titleKey: "settings.title",
2870
3090
  descriptionKey: "settings.description",
3091
+ defaultOpen: false,
2871
3092
  state,
2872
3093
  onSave: props.save,
2873
3094
  onDiscard: props.discard,
@@ -3083,6 +3304,7 @@ window.__ModuleLoader__.load({
3083
3304
  "settings.saveFailed": "部署未接受这些值,已保留供你修改。",
3084
3305
  "settings.invalidNumber": "请输入数字,留空则使用默认值。",
3085
3306
  "update.label": "检查更新",
3307
+ "update.availableLabel": "发现新版本,检查更新",
3086
3308
  "update.title": "检查更新",
3087
3309
  "update.checking": "正在检查远程仓库中的新版本…",
3088
3310
  "update.upToDate": "当前已是最新版本",
@@ -3090,6 +3312,7 @@ window.__ModuleLoader__.load({
3090
3312
  "update.found": "发现新版本",
3091
3313
  "update.foundDetail": "{name} 有新版本 v{version},正在自动更新…",
3092
3314
  "update.updating": "正在更新 {name} 至 v{version},可能需要 1-2 分钟…",
3315
+ "update.cooldownNotice": "本次更新由你主动触发,将跳过 pnpm 的 24 小时发布冷却期(供应链保护)直接安装所选版本。",
3093
3316
  "update.updatingTitle": "正在自动更新…",
3094
3317
  "update.done": "更新完成",
3095
3318
  "update.doneDetail": "所有组件已更新到最新版本。",
@@ -3187,6 +3410,7 @@ window.__ModuleLoader__.load({
3187
3410
  "settings.saveFailed": "The deployment did not accept these values; they were left for you to correct.",
3188
3411
  "settings.invalidNumber": "Enter a number, or leave blank to use the default.",
3189
3412
  "update.label": "Check for updates",
3413
+ "update.availableLabel": "New version available. Check for updates",
3190
3414
  "update.title": "Check for updates",
3191
3415
  "update.checking": "Checking the remote repository for newer releases…",
3192
3416
  "update.upToDate": "Everything is up to date",
@@ -3194,6 +3418,7 @@ window.__ModuleLoader__.load({
3194
3418
  "update.found": "A new version is available",
3195
3419
  "update.foundDetail": "{name} has a newer release v{version}; updating automatically…",
3196
3420
  "update.updating": "Updating {name} to v{version}; this may take 1-2 minutes…",
3421
+ "update.cooldownNotice": "This user-initiated update bypasses pnpm's 24-hour release cooldown (supply-chain protection) and installs the selected version immediately.",
3197
3422
  "update.updatingTitle": "Updating automatically…",
3198
3423
  "update.done": "Update complete",
3199
3424
  "update.doneDetail": "All components are up to date.",
@@ -3272,7 +3497,7 @@ window.__ModuleLoader__.load({
3272
3497
  url.searchParams.delete("pair");
3273
3498
  page.replaceState(`${url.pathname}${url.search}${url.hash}`);
3274
3499
  if (ok) if (isMobileSurface()) {
3275
- url.pathname = "/m";
3500
+ url.pathname = "/m/";
3276
3501
  page.navigate(`${url.pathname}${url.search}${url.hash}`);
3277
3502
  } else page.reload();
3278
3503
  }