dsh-vscode-mode 0.1.53 → 0.1.55

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 (210) hide show
  1. package/README.md +11 -0
  2. package/assets/vendor/pdfjs/build/pdf.mjs +26370 -0
  3. package/assets/vendor/pdfjs/build/pdf.worker.mjs +61080 -0
  4. package/assets/vendor/pdfjs/cmaps/78-EUC-H.bcmap +0 -0
  5. package/assets/vendor/pdfjs/cmaps/78-EUC-V.bcmap +0 -0
  6. package/assets/vendor/pdfjs/cmaps/78-H.bcmap +0 -0
  7. package/assets/vendor/pdfjs/cmaps/78-RKSJ-H.bcmap +0 -0
  8. package/assets/vendor/pdfjs/cmaps/78-RKSJ-V.bcmap +0 -0
  9. package/assets/vendor/pdfjs/cmaps/78-V.bcmap +0 -0
  10. package/assets/vendor/pdfjs/cmaps/78ms-RKSJ-H.bcmap +0 -0
  11. package/assets/vendor/pdfjs/cmaps/78ms-RKSJ-V.bcmap +0 -0
  12. package/assets/vendor/pdfjs/cmaps/83pv-RKSJ-H.bcmap +0 -0
  13. package/assets/vendor/pdfjs/cmaps/90ms-RKSJ-H.bcmap +0 -0
  14. package/assets/vendor/pdfjs/cmaps/90ms-RKSJ-V.bcmap +0 -0
  15. package/assets/vendor/pdfjs/cmaps/90msp-RKSJ-H.bcmap +0 -0
  16. package/assets/vendor/pdfjs/cmaps/90msp-RKSJ-V.bcmap +0 -0
  17. package/assets/vendor/pdfjs/cmaps/90pv-RKSJ-H.bcmap +0 -0
  18. package/assets/vendor/pdfjs/cmaps/90pv-RKSJ-V.bcmap +0 -0
  19. package/assets/vendor/pdfjs/cmaps/Add-H.bcmap +0 -0
  20. package/assets/vendor/pdfjs/cmaps/Add-RKSJ-H.bcmap +0 -0
  21. package/assets/vendor/pdfjs/cmaps/Add-RKSJ-V.bcmap +0 -0
  22. package/assets/vendor/pdfjs/cmaps/Add-V.bcmap +0 -0
  23. package/assets/vendor/pdfjs/cmaps/Adobe-CNS1-0.bcmap +0 -0
  24. package/assets/vendor/pdfjs/cmaps/Adobe-CNS1-1.bcmap +0 -0
  25. package/assets/vendor/pdfjs/cmaps/Adobe-CNS1-2.bcmap +0 -0
  26. package/assets/vendor/pdfjs/cmaps/Adobe-CNS1-3.bcmap +0 -0
  27. package/assets/vendor/pdfjs/cmaps/Adobe-CNS1-4.bcmap +0 -0
  28. package/assets/vendor/pdfjs/cmaps/Adobe-CNS1-5.bcmap +0 -0
  29. package/assets/vendor/pdfjs/cmaps/Adobe-CNS1-6.bcmap +0 -0
  30. package/assets/vendor/pdfjs/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
  31. package/assets/vendor/pdfjs/cmaps/Adobe-GB1-0.bcmap +0 -0
  32. package/assets/vendor/pdfjs/cmaps/Adobe-GB1-1.bcmap +0 -0
  33. package/assets/vendor/pdfjs/cmaps/Adobe-GB1-2.bcmap +0 -0
  34. package/assets/vendor/pdfjs/cmaps/Adobe-GB1-3.bcmap +0 -0
  35. package/assets/vendor/pdfjs/cmaps/Adobe-GB1-4.bcmap +0 -0
  36. package/assets/vendor/pdfjs/cmaps/Adobe-GB1-5.bcmap +0 -0
  37. package/assets/vendor/pdfjs/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
  38. package/assets/vendor/pdfjs/cmaps/Adobe-Japan1-0.bcmap +0 -0
  39. package/assets/vendor/pdfjs/cmaps/Adobe-Japan1-1.bcmap +0 -0
  40. package/assets/vendor/pdfjs/cmaps/Adobe-Japan1-2.bcmap +0 -0
  41. package/assets/vendor/pdfjs/cmaps/Adobe-Japan1-3.bcmap +0 -0
  42. package/assets/vendor/pdfjs/cmaps/Adobe-Japan1-4.bcmap +0 -0
  43. package/assets/vendor/pdfjs/cmaps/Adobe-Japan1-5.bcmap +0 -0
  44. package/assets/vendor/pdfjs/cmaps/Adobe-Japan1-6.bcmap +0 -0
  45. package/assets/vendor/pdfjs/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
  46. package/assets/vendor/pdfjs/cmaps/Adobe-Korea1-0.bcmap +0 -0
  47. package/assets/vendor/pdfjs/cmaps/Adobe-Korea1-1.bcmap +0 -0
  48. package/assets/vendor/pdfjs/cmaps/Adobe-Korea1-2.bcmap +0 -0
  49. package/assets/vendor/pdfjs/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
  50. package/assets/vendor/pdfjs/cmaps/B5-H.bcmap +0 -0
  51. package/assets/vendor/pdfjs/cmaps/B5-V.bcmap +0 -0
  52. package/assets/vendor/pdfjs/cmaps/B5pc-H.bcmap +0 -0
  53. package/assets/vendor/pdfjs/cmaps/B5pc-V.bcmap +0 -0
  54. package/assets/vendor/pdfjs/cmaps/CNS-EUC-H.bcmap +0 -0
  55. package/assets/vendor/pdfjs/cmaps/CNS-EUC-V.bcmap +0 -0
  56. package/assets/vendor/pdfjs/cmaps/CNS1-H.bcmap +0 -0
  57. package/assets/vendor/pdfjs/cmaps/CNS1-V.bcmap +0 -0
  58. package/assets/vendor/pdfjs/cmaps/CNS2-H.bcmap +0 -0
  59. package/assets/vendor/pdfjs/cmaps/CNS2-V.bcmap +3 -0
  60. package/assets/vendor/pdfjs/cmaps/ETHK-B5-H.bcmap +0 -0
  61. package/assets/vendor/pdfjs/cmaps/ETHK-B5-V.bcmap +0 -0
  62. package/assets/vendor/pdfjs/cmaps/ETen-B5-H.bcmap +0 -0
  63. package/assets/vendor/pdfjs/cmaps/ETen-B5-V.bcmap +0 -0
  64. package/assets/vendor/pdfjs/cmaps/ETenms-B5-H.bcmap +3 -0
  65. package/assets/vendor/pdfjs/cmaps/ETenms-B5-V.bcmap +0 -0
  66. package/assets/vendor/pdfjs/cmaps/EUC-H.bcmap +0 -0
  67. package/assets/vendor/pdfjs/cmaps/EUC-V.bcmap +0 -0
  68. package/assets/vendor/pdfjs/cmaps/Ext-H.bcmap +0 -0
  69. package/assets/vendor/pdfjs/cmaps/Ext-RKSJ-H.bcmap +0 -0
  70. package/assets/vendor/pdfjs/cmaps/Ext-RKSJ-V.bcmap +0 -0
  71. package/assets/vendor/pdfjs/cmaps/Ext-V.bcmap +0 -0
  72. package/assets/vendor/pdfjs/cmaps/GB-EUC-H.bcmap +0 -0
  73. package/assets/vendor/pdfjs/cmaps/GB-EUC-V.bcmap +0 -0
  74. package/assets/vendor/pdfjs/cmaps/GB-H.bcmap +4 -0
  75. package/assets/vendor/pdfjs/cmaps/GB-V.bcmap +0 -0
  76. package/assets/vendor/pdfjs/cmaps/GBK-EUC-H.bcmap +0 -0
  77. package/assets/vendor/pdfjs/cmaps/GBK-EUC-V.bcmap +0 -0
  78. package/assets/vendor/pdfjs/cmaps/GBK2K-H.bcmap +0 -0
  79. package/assets/vendor/pdfjs/cmaps/GBK2K-V.bcmap +0 -0
  80. package/assets/vendor/pdfjs/cmaps/GBKp-EUC-H.bcmap +0 -0
  81. package/assets/vendor/pdfjs/cmaps/GBKp-EUC-V.bcmap +0 -0
  82. package/assets/vendor/pdfjs/cmaps/GBT-EUC-H.bcmap +0 -0
  83. package/assets/vendor/pdfjs/cmaps/GBT-EUC-V.bcmap +0 -0
  84. package/assets/vendor/pdfjs/cmaps/GBT-H.bcmap +0 -0
  85. package/assets/vendor/pdfjs/cmaps/GBT-V.bcmap +0 -0
  86. package/assets/vendor/pdfjs/cmaps/GBTpc-EUC-H.bcmap +0 -0
  87. package/assets/vendor/pdfjs/cmaps/GBTpc-EUC-V.bcmap +0 -0
  88. package/assets/vendor/pdfjs/cmaps/GBpc-EUC-H.bcmap +0 -0
  89. package/assets/vendor/pdfjs/cmaps/GBpc-EUC-V.bcmap +0 -0
  90. package/assets/vendor/pdfjs/cmaps/H.bcmap +0 -0
  91. package/assets/vendor/pdfjs/cmaps/HKdla-B5-H.bcmap +0 -0
  92. package/assets/vendor/pdfjs/cmaps/HKdla-B5-V.bcmap +0 -0
  93. package/assets/vendor/pdfjs/cmaps/HKdlb-B5-H.bcmap +0 -0
  94. package/assets/vendor/pdfjs/cmaps/HKdlb-B5-V.bcmap +0 -0
  95. package/assets/vendor/pdfjs/cmaps/HKgccs-B5-H.bcmap +0 -0
  96. package/assets/vendor/pdfjs/cmaps/HKgccs-B5-V.bcmap +0 -0
  97. package/assets/vendor/pdfjs/cmaps/HKm314-B5-H.bcmap +0 -0
  98. package/assets/vendor/pdfjs/cmaps/HKm314-B5-V.bcmap +0 -0
  99. package/assets/vendor/pdfjs/cmaps/HKm471-B5-H.bcmap +0 -0
  100. package/assets/vendor/pdfjs/cmaps/HKm471-B5-V.bcmap +0 -0
  101. package/assets/vendor/pdfjs/cmaps/HKscs-B5-H.bcmap +0 -0
  102. package/assets/vendor/pdfjs/cmaps/HKscs-B5-V.bcmap +0 -0
  103. package/assets/vendor/pdfjs/cmaps/Hankaku.bcmap +0 -0
  104. package/assets/vendor/pdfjs/cmaps/Hiragana.bcmap +0 -0
  105. package/assets/vendor/pdfjs/cmaps/KSC-EUC-H.bcmap +0 -0
  106. package/assets/vendor/pdfjs/cmaps/KSC-EUC-V.bcmap +0 -0
  107. package/assets/vendor/pdfjs/cmaps/KSC-H.bcmap +0 -0
  108. package/assets/vendor/pdfjs/cmaps/KSC-Johab-H.bcmap +0 -0
  109. package/assets/vendor/pdfjs/cmaps/KSC-Johab-V.bcmap +0 -0
  110. package/assets/vendor/pdfjs/cmaps/KSC-V.bcmap +0 -0
  111. package/assets/vendor/pdfjs/cmaps/KSCms-UHC-H.bcmap +0 -0
  112. package/assets/vendor/pdfjs/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
  113. package/assets/vendor/pdfjs/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
  114. package/assets/vendor/pdfjs/cmaps/KSCms-UHC-V.bcmap +0 -0
  115. package/assets/vendor/pdfjs/cmaps/KSCpc-EUC-H.bcmap +0 -0
  116. package/assets/vendor/pdfjs/cmaps/KSCpc-EUC-V.bcmap +0 -0
  117. package/assets/vendor/pdfjs/cmaps/Katakana.bcmap +0 -0
  118. package/assets/vendor/pdfjs/cmaps/LICENSE +36 -0
  119. package/assets/vendor/pdfjs/cmaps/NWP-H.bcmap +0 -0
  120. package/assets/vendor/pdfjs/cmaps/NWP-V.bcmap +0 -0
  121. package/assets/vendor/pdfjs/cmaps/RKSJ-H.bcmap +0 -0
  122. package/assets/vendor/pdfjs/cmaps/RKSJ-V.bcmap +0 -0
  123. package/assets/vendor/pdfjs/cmaps/Roman.bcmap +0 -0
  124. package/assets/vendor/pdfjs/cmaps/UniCNS-UCS2-H.bcmap +0 -0
  125. package/assets/vendor/pdfjs/cmaps/UniCNS-UCS2-V.bcmap +0 -0
  126. package/assets/vendor/pdfjs/cmaps/UniCNS-UTF16-H.bcmap +0 -0
  127. package/assets/vendor/pdfjs/cmaps/UniCNS-UTF16-V.bcmap +0 -0
  128. package/assets/vendor/pdfjs/cmaps/UniCNS-UTF32-H.bcmap +0 -0
  129. package/assets/vendor/pdfjs/cmaps/UniCNS-UTF32-V.bcmap +0 -0
  130. package/assets/vendor/pdfjs/cmaps/UniCNS-UTF8-H.bcmap +0 -0
  131. package/assets/vendor/pdfjs/cmaps/UniCNS-UTF8-V.bcmap +0 -0
  132. package/assets/vendor/pdfjs/cmaps/UniGB-UCS2-H.bcmap +0 -0
  133. package/assets/vendor/pdfjs/cmaps/UniGB-UCS2-V.bcmap +0 -0
  134. package/assets/vendor/pdfjs/cmaps/UniGB-UTF16-H.bcmap +0 -0
  135. package/assets/vendor/pdfjs/cmaps/UniGB-UTF16-V.bcmap +0 -0
  136. package/assets/vendor/pdfjs/cmaps/UniGB-UTF32-H.bcmap +0 -0
  137. package/assets/vendor/pdfjs/cmaps/UniGB-UTF32-V.bcmap +0 -0
  138. package/assets/vendor/pdfjs/cmaps/UniGB-UTF8-H.bcmap +0 -0
  139. package/assets/vendor/pdfjs/cmaps/UniGB-UTF8-V.bcmap +0 -0
  140. package/assets/vendor/pdfjs/cmaps/UniJIS-UCS2-H.bcmap +0 -0
  141. package/assets/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
  142. package/assets/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
  143. package/assets/vendor/pdfjs/cmaps/UniJIS-UCS2-V.bcmap +0 -0
  144. package/assets/vendor/pdfjs/cmaps/UniJIS-UTF16-H.bcmap +0 -0
  145. package/assets/vendor/pdfjs/cmaps/UniJIS-UTF16-V.bcmap +0 -0
  146. package/assets/vendor/pdfjs/cmaps/UniJIS-UTF32-H.bcmap +0 -0
  147. package/assets/vendor/pdfjs/cmaps/UniJIS-UTF32-V.bcmap +0 -0
  148. package/assets/vendor/pdfjs/cmaps/UniJIS-UTF8-H.bcmap +0 -0
  149. package/assets/vendor/pdfjs/cmaps/UniJIS-UTF8-V.bcmap +0 -0
  150. package/assets/vendor/pdfjs/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
  151. package/assets/vendor/pdfjs/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
  152. package/assets/vendor/pdfjs/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
  153. package/assets/vendor/pdfjs/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
  154. package/assets/vendor/pdfjs/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
  155. package/assets/vendor/pdfjs/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
  156. package/assets/vendor/pdfjs/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
  157. package/assets/vendor/pdfjs/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
  158. package/assets/vendor/pdfjs/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
  159. package/assets/vendor/pdfjs/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
  160. package/assets/vendor/pdfjs/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
  161. package/assets/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
  162. package/assets/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
  163. package/assets/vendor/pdfjs/cmaps/UniKS-UCS2-H.bcmap +0 -0
  164. package/assets/vendor/pdfjs/cmaps/UniKS-UCS2-V.bcmap +0 -0
  165. package/assets/vendor/pdfjs/cmaps/UniKS-UTF16-H.bcmap +0 -0
  166. package/assets/vendor/pdfjs/cmaps/UniKS-UTF16-V.bcmap +0 -0
  167. package/assets/vendor/pdfjs/cmaps/UniKS-UTF32-H.bcmap +0 -0
  168. package/assets/vendor/pdfjs/cmaps/UniKS-UTF32-V.bcmap +0 -0
  169. package/assets/vendor/pdfjs/cmaps/UniKS-UTF8-H.bcmap +0 -0
  170. package/assets/vendor/pdfjs/cmaps/UniKS-UTF8-V.bcmap +0 -0
  171. package/assets/vendor/pdfjs/cmaps/V.bcmap +0 -0
  172. package/assets/vendor/pdfjs/cmaps/WP-Symbol.bcmap +0 -0
  173. package/assets/vendor/pdfjs/standard_fonts/FoxitDingbats.pfb +0 -0
  174. package/assets/vendor/pdfjs/standard_fonts/FoxitFixed.pfb +0 -0
  175. package/assets/vendor/pdfjs/standard_fonts/FoxitFixedBold.pfb +0 -0
  176. package/assets/vendor/pdfjs/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
  177. package/assets/vendor/pdfjs/standard_fonts/FoxitFixedItalic.pfb +0 -0
  178. package/assets/vendor/pdfjs/standard_fonts/FoxitSerif.pfb +0 -0
  179. package/assets/vendor/pdfjs/standard_fonts/FoxitSerifBold.pfb +0 -0
  180. package/assets/vendor/pdfjs/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
  181. package/assets/vendor/pdfjs/standard_fonts/FoxitSerifItalic.pfb +0 -0
  182. package/assets/vendor/pdfjs/standard_fonts/FoxitSymbol.pfb +0 -0
  183. package/assets/vendor/pdfjs/standard_fonts/LICENSE_FOXIT +27 -0
  184. package/assets/vendor/pdfjs/standard_fonts/LICENSE_LIBERATION +102 -0
  185. package/assets/vendor/pdfjs/standard_fonts/LiberationSans-Bold.ttf +0 -0
  186. package/assets/vendor/pdfjs/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
  187. package/assets/vendor/pdfjs/standard_fonts/LiberationSans-Italic.ttf +0 -0
  188. package/assets/vendor/pdfjs/standard_fonts/LiberationSans-Regular.ttf +0 -0
  189. package/assets/vendor/pdfjs/web/pdf_viewer.css +6989 -0
  190. package/assets/vendor/pdfjs/web/pdf_viewer.mjs +9459 -0
  191. package/lib/client.js +852 -13
  192. package/lib/client.js.map +1 -1
  193. package/lib/index.js +137 -17
  194. package/lib/index.js.map +1 -1
  195. package/package.json +1 -1
  196. package/src/client/compat.ts +31 -0
  197. package/src/client/imagePreview.ts +45 -0
  198. package/src/client/index.ts +46 -8
  199. package/src/client/pdf/pdfLoader.ts +82 -0
  200. package/src/client/pdf/pdfPanel.ts +239 -0
  201. package/src/client/pdfPreview.ts +48 -0
  202. package/src/client/remoteOpenRouter.ts +78 -0
  203. package/src/client/styles/editor.css +17 -0
  204. package/src/client/ui/EditorView.ts +221 -2
  205. package/src/compat.ts +1 -1
  206. package/src/dshVersion.ts +1 -0
  207. package/src/routes.ts +3 -0
  208. package/src/rpc.ts +65 -13
  209. package/src/shared/rpc.ts +50 -2
  210. package/src/store.ts +2 -0
package/lib/client.js CHANGED
@@ -31,7 +31,7 @@ window.__ModuleLoader__.load({
31
31
  let react_dom_client = require("react-dom/client");
32
32
  let react_dom = require("react-dom");
33
33
  //#region \0dsh-css:/home/runner/work/DSH_VsCodeMode/DSH_VsCodeMode/src/client/styles/editor.css.mjs
34
- const css$1 = "/* dsh-vscode-mode 编辑区样式(原 ensureEdrvStyles 字符串,落盘为真 .css,由 tsdown CSS-inline 注入) */\n/* 浅色主题(对齐参考图:#f8f8f8 近白底 + 薄荷绿药丸 + 青绿文字 + 三文鱼 undo + 浅灰边框):\n 在 [data-edrv-view] 作用域内重定义 --dsw-alias-*,级联命中组件内联样式与 CSS。 */\n[data-edrv-view] { box-sizing: border-box; --edrv-tab-h: 34px; --dsw-alias-bg-base: #f8f8f8; --dsw-alias-bg-layer-1: #ffffff; --dsw-alias-bg-layer-2: #f0f4f4; --dsw-alias-bg-overlay: #ffffff; --dsw-alias-label-primary: #1f2933; --dsw-alias-label-secondary: #52606d; --dsw-alias-label-tertiary: #9aa5b1; --dsw-alias-border-l1: #e0e6e8; --dsw-alias-border-l2: #cbd2d9; --dsw-alias-brand-primary: #0f9d58; --dsw-alias-state-success-primary: #0f9d58; --dsw-alias-state-error-primary: #d9534f; --dsw-alias-state-warn-primary: #d97706; --dsw-alias-interactive-bg-hover: rgba(15,157,88,.08); }\n\n[data-edrv-view] .edrv-tabs { display: flex; align-items: center; gap: 2px; padding: 2px 8px 0; background: var(--dsw-alias-bg-layer-1, transparent); overflow-x: auto; scrollbar-width: thin; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab { display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 8px 0 12px; border: none; border-radius: 6px 6px 0 0; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 12px; cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-tab.edrv-tab-active { background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); box-shadow: inset 0 -2px 0 var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-tab .edrv-tab-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--dsw-alias-brand-primary, #4f8cff); flex-shrink: 0; }\n[data-edrv-view] .edrv-tab .edrv-tab-x { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; border-radius: 4px; color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; }\n[data-edrv-view] .edrv-tab .edrv-tab-x:hover { background: rgba(255,255,255,.12); color: var(--dsw-alias-label-primary, #eee); }\n[data-edrv-view] .edrv-tab-add { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; margin-left: 2px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 14px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab-add:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-pathbar { display: flex; align-items: center; gap: 8px; height: 26px; padding: 0 10px; background: var(--dsw-alias-bg-layer-1, #ffffff); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 12px; flex-shrink: 0; overflow: hidden; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-name { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-full { flex: 1; min-width: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; direction: rtl; text-align: left; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-meta { flex-shrink: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-status { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-path-input { flex: 1; min-width: 140px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search-wrap { position: relative; flex-shrink: 0; display: flex; align-items: center; padding: 2px 8px 2px 4px; }\n[data-edrv-view] .edrv-search { width: 190px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-pop { position: absolute; top: calc(100% + 4px); right: 8px; width: min(460px, calc(100vw - 24px)); max-height: 300px; overflow: auto; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 10px; box-shadow: 0 6px 20px rgba(0,0,0,.4); z-index: 60; padding: 4px; }\n[data-edrv-view] .edrv-search-item { display: flex; flex-direction: column; gap: 1px; padding: 5px 8px; border-radius: 6px; cursor: pointer; }\n[data-edrv-view] .edrv-search-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.07)); }\n[data-edrv-view] .edrv-search-item .n { color: var(--dsw-alias-label-primary, #eee); font-size: 12px; word-break: break-all; }\n[data-edrv-view] .edrv-search-item .d { color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-search-empty { padding: 8px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #888); }\n[data-edrv-view] .edrv-btn-mini { font-size: 11px; padding: 2px 9px; border: none; border-radius: 999px; cursor: pointer; color: #fff; font-weight: 600; white-space: nowrap; }\n[data-edrv-view] .edrv-btn-keep { background: var(--dsw-alias-state-success-primary, #2e9e44); }\n[data-edrv-view] .edrv-btn-undo { background: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-btn-mini:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-statusbar { display: flex; align-items: center; gap: 10px; padding: 3px 10px; border-top: 1px solid var(--dsw-alias-border-l1, #333); background: var(--dsw-alias-bg-layer-1, transparent); font-size: 11px; color: var(--dsw-alias-label-tertiary, #888); flex-shrink: 0; white-space: nowrap; overflow: hidden; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-path { flex: 1; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-lsp { flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-progress-message { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-statusbar .edrv-sp-progress { flex: 0 0 auto; min-width: 36px; text-align: right; font-variant-numeric: tabular-nums; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-lsp-status-dot { width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto; background: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-lsp-status-dot.ready { background: var(--dsw-alias-state-success-primary, #0f9d58); }\n[data-edrv-view] .edrv-lsp-status-dot.busy { background: var(--dsw-alias-state-warn-primary, #d97706); animation: edrv-lsp-pulse 1.2s ease-in-out infinite; }\n@keyframes edrv-lsp-pulse { 50% { opacity: .45; } }\n/* Ctrl+hover 可导航标识符下划线提示(绑定 Monaco inlineClassName 装饰) */\n[data-edrv-view] .edrv-nav-underline { text-decoration: underline; text-decoration-color: var(--dsw-alias-interactive-primary, #4fc1ff); text-underline-offset: 1px; cursor: pointer; }\n[data-edrv-view] .edrv-diffchip { font-size: 11px; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #333); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-state-warn-primary, #b7791f); cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn { font-size: 12px; padding: 2px 6px; border: none; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; border-radius: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-chip-btn:disabled { opacity: .35; cursor: default; }\n[data-edrv-view] .edrv-chip-btn:disabled:hover { background: transparent; }\n[data-edrv-view] .edrv-mn-add-line { background: rgba(15,157,88,.10); }\n[data-edrv-view] .edrv-mn-gutter-add { color: #0f9d58 !important; font-weight: 700; display: flex !important; align-items: center; justify-content: center; }\n[data-edrv-view] .edrv-mn-gutter-add::before { content: \"+\"; }\n[data-edrv-view] .edrv-del-zone { background: #fdeaea; border-top: 1px solid rgba(217,83,79,.35); border-bottom: 1px solid rgba(217,83,79,.35); box-shadow: inset 0 0 0 1px rgba(217,83,79,.12); }\n[data-edrv-view] .edrv-del-row { white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 12.5px; line-height: 20px; color: #c0392b; }\n[data-edrv-view] .edrv-del-text { display: inline-block; white-space: pre; }\n[data-edrv-view] .edrv-minus-overlay { position: absolute; left: 0; top: 0; width: 100%; height: 100%; max-width: 100%; overflow: visible; pointer-events: none; z-index: 6; }\n[data-edrv-view] .edrv-minus-item { position: absolute; box-sizing: border-box; max-width: 100%; overflow: hidden; }\n[data-edrv-view] .edrv-minus-item::before { content: ''; position: absolute; left: 4px; top: 50%; width: 8px; height: 2px; transform: translateY(-50%); border-radius: 2px; background: #d9534f; }\n[data-edrv-view] .edrv-monaco-host { flex: 1 1 auto; min-width: 0; min-height: 0; position: relative; overflow: hidden; }\n[data-edrv-view] .edrv-monaco-host > div { position: absolute; inset: 0; min-width: 0; min-height: 0; }\n[data-edrv-view] .edrv-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; height: 100%; color: var(--dsw-alias-label-tertiary, #777); font-size: 13px; }\n[data-edrv-view] .edrv-diffbar { position: absolute; left: 0; right: 0; bottom: 10px; margin: 0 auto; z-index: 25; width: fit-content; max-width: calc(100% - 20px); border-radius: 12px; background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, #f0f4f4)); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); box-shadow: none; overflow: visible; display: flex; flex-direction: column; }\n[data-edrv-view] .edrv-editor-area > .edrv-diffbar { max-height: calc(100% - 20px); }\n[data-edrv-view] .edrv-diffbar-row { display: flex; align-items: center; gap: 6px; height: 36px; padding: 4px 5px 4px 12px; flex-wrap: nowrap; }\n[data-edrv-view] .edrv-diffbar-count { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); min-width: 42px; text-align: center; white-space: nowrap; cursor: pointer; }\n[data-edrv-view] .edrv-diffbar-count.edrv-count-file { min-width: 64px; cursor: default; }\n[data-edrv-view] .edrv-diffbar-file { flex: 1; min-width: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-pill { font-size: 11px; padding: 3px 10px; border: none; border-radius: 999px; cursor: pointer; white-space: nowrap; font-weight: 600; }\n[data-edrv-view] .edrv-pill-keep { background: #e8f8e8; color: #0f7a45; border: 1px solid rgba(15,157,88,.4); }\n[data-edrv-view] .edrv-pill-undo { background: #fdeaea; color: #c0392b; border: 1px solid rgba(217,83,79,.4); }\n[data-edrv-view] .edrv-pill-ghost { background: #ffffff; color: var(--dsw-alias-label-secondary, #52606d); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-pill:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-diffbar-menu { position: absolute; right: 8px; bottom: calc(100% + 6px); z-index: 45; min-width: 160px; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 6px 20px rgba(31,41,51,.16); padding: 4px; display: flex; flex-direction: column; gap: 2px; }\n[data-edrv-view] .edrv-diffmenu-item { display: flex; align-items: center; gap: 8px; font-size: 12px; padding: 6px 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; text-align: left; }\n[data-edrv-view] .edrv-diffmenu-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-diffmenu-item.danger { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-diffmenu-sep { height: 1px; margin: 2px 4px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n/* 编辑区 / Tab 右键菜单(添加文件/选中内容到对话) */\n[data-edrv-view] .edrv-ctxmenu { position: fixed; z-index: 71; min-width: 200px; max-width: 320px; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 8px 26px rgba(31,41,51,.2); padding: 4px; display: flex; flex-direction: column; gap: 1px; }\n[data-edrv-view] .edrv-ctxmenu-item { display: flex; align-items: center; gap: 8px; font-size: 12px; line-height: 18px; padding: 7px 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-ctxmenu-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-danger { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-ctxmenu-item:disabled,\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-disabled { color: var(--dsw-alias-label-disabled, #b0b7c0); cursor: default; background: transparent; }\n[data-edrv-view] .edrv-ctxmenu-sep { height: 1px; margin: 3px 4px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-diffbar-body { max-height: 130px; max-width: min(560px, calc(100vw - 40px)); overflow: auto; padding: 4px 8px 8px; display: flex; flex-direction: column; gap: 4px; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-diffrow { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); cursor: pointer; flex-wrap: wrap; }\n[data-edrv-view] .edrv-diffrow:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-diffrow-l { font-size: 11px; color: var(--dsw-alias-label-primary, #1f2933); min-width: 74px; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-o { font-size: 11px; color: var(--dsw-alias-state-error-primary, #d9534f); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-n { font-size: 11px; color: var(--dsw-alias-state-success-primary, #0f9d58); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-tag { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-diffrow-stale { border-color: rgba(217,119,6,.5); cursor: default; }\n[data-edrv-view] .edrv-diffbox-others { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; padding: 4px 2px 0; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); margin-top: 2px; }\n[data-edrv-view] .edrv-diffrow-file { font-size: 11px; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); cursor: pointer; white-space: nowrap; max-width: 200px; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-diffrow-file:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n/* 编辑区 hover 差异块的 Keep/Undo 浮层 */\n[data-edrv-view] .edrv-hoveract { position: absolute; z-index: 30; display: flex; align-items: center; gap: 4px; padding: 2px 6px; border-radius: 8px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 4px 14px rgba(31,41,51,.14); }\n[data-edrv-view] .edrv-launch { position: absolute; left: 12px; right: 12px; bottom: 12px; z-index: 40; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); box-shadow: 0 6px 24px rgba(0,0,0,.5); display: flex; flex-direction: column; max-height: 60%; overflow: hidden; }\n[data-edrv-view] .edrv-launch-head { display: flex; align-items: center; gap: 6px; padding: 6px 8px; border-bottom: 1px solid var(--dsw-alias-border-l1, #333); }\n[data-edrv-view] .edrv-launch-tab { font-size: 12px; padding: 3px 12px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; }\n[data-edrv-view] .edrv-launch-tab.on { background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-label-primary, #eee); font-weight: 600; }\n[data-edrv-view] .edrv-launch-body { flex: 1; min-height: 0; overflow: auto; padding: 6px 8px; display: flex; flex-direction: column; gap: 4px; }\n[data-edrv-view] .edrv-launch-row { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1, #333); border-radius: 6px; cursor: pointer; flex-wrap: wrap; }\n[data-edrv-view] .edrv-launch-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-launch-path { flex: 1; min-width: 0; font-size: 12px; color: var(--dsw-alias-label-primary, #eee); word-break: break-all; }\n[data-edrv-view] .edrv-launch-cnt { font-size: 11px; color: var(--dsw-alias-label-tertiary, #888); white-space: nowrap; }\n[data-edrv-view] .edrv-launch-arch { display: flex; flex-direction: column; gap: 6px; }\n[data-edrv-view] .monaco-editor { overflow: hidden !important; }\n[data-edrv-view] .monaco-editor .sticky-widget { z-index: 30 !important; background: var(--dsw-alias-bg-base, #f8f8f8) !important; }\n[data-edrv-view] .monaco-editor .sticky-widget .sticky-line-content,\n[data-edrv-view] .monaco-editor .sticky-widget .sticky-line-number { background: var(--dsw-alias-bg-base, #f8f8f8) !important; }\n[data-edrv-view] .monaco-editor, [data-edrv-view] .monaco-editor .margin, [data-edrv-view] .monaco-editor-background { background: transparent !important; }\n[data-edrv-view] .monaco-editor .scrollbar .slider { background: rgba(128,128,128,.3) !important; }\n[data-edrv-view] .edrv-loading { gap: 8px; padding: 20px; }\n[data-edrv-view] .edrv-loading-title { color: var(--dsw-alias-label-primary, #1f2933); font-size: 13px; }\n[data-edrv-view] .edrv-progress { width: min(360px, 72%); height: 6px; overflow: hidden; border-radius: 999px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-progress-value { height: 100%; border-radius: inherit; background: var(--dsw-alias-brand-primary, #0f9d58); transition: width .24s ease; }\n[data-edrv-view] .edrv-loading-percent { color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; font-variant-numeric: tabular-nums; }\n@media (prefers-reduced-motion: reduce) {\n [data-edrv-view] .edrv-progress-value { transition: none; }\n}\n\n/* ===== 唯一会话级差异 dock(遵循 DSH todo/queue 原生布局) ===== */\n[data-edrv-diff-dock-shell] {\n box-sizing: border-box;\n width: calc(100% - var(--dsh-composer-side-clearance) - var(--dsh-composer-side-clearance) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));\n max-width: calc(var(--dsh-composer-card-max-width) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));\n margin: 0 auto;\n padding: 0;\n flex: none;\n border: 1px solid var(--dsw-alias-border-l1, #e0e6e8);\n border-radius: 12px;\n background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, transparent));\n box-shadow: none;\n overflow: hidden;\n}\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock {\n box-sizing: border-box;\n position: relative;\n left: auto;\n right: auto;\n bottom: auto;\n z-index: auto;\n width: 100%;\n max-width: none;\n margin: 0;\n display: flex;\n flex-direction: column;\n border: none;\n border-radius: 0;\n background: transparent;\n box-shadow: none;\n overflow: visible;\n}\n[data-edrv-diff-dock-shell] .edrv-diffbar-row { min-height: 36px; padding: 6px 12px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-row { min-height: 36px; padding: 6px 12px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-body { max-height: 180px; overflow: auto; padding: 6px 12px 10px; border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-button { box-sizing: border-box; display: flex; align-items: center; justify-content: center; width: 100%; height: 24px; border: none; border-radius: 8px; padding: 0 12px; background: transparent; color: var(--dsw-alias-label-primary); font-size: 13px; font-weight: 500; line-height: 24px; text-align: center; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-button:hover { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diffbar-count { display: inline-flex; align-items: center; color: var(--dsw-alias-label-primary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 500; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-file { display: inline-flex; align-items: center; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-editor-row { display: flex; align-items: center; height: 36px; min-height: 36px; padding: 4px 12px; overflow-x: auto; scrollbar-width: thin; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-editor-content { display: flex; align-items: center; gap: 10px; width: 100%; min-width: max-content; min-height: 28px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-nav,\n[data-edrv-diff-dock-shell] .edrv-diffbar-files,\n[data-edrv-diff-dock-shell] .edrv-diffbar-actions { display: flex; align-items: center; gap: 6px; flex: none; height: 28px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-actions { margin-left: auto; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-details-toggle { display: inline-flex; align-items: center; justify-content: center; width: 28px; min-width: 28px; padding: 0; font-size: 13px; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-details-toggle svg { width: 14px; height: 14px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-files { min-width: 0; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-files .edrv-diffbar-file { min-width: 72px; max-width: 240px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-progress { min-width: 0; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; font-variant-numeric: tabular-nums; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-summary { min-width: 0; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-pill { box-sizing: border-box; height: 28px; padding: 0 9px; border: none; border-radius: 999px; cursor: pointer; white-space: nowrap; font-size: 11px; line-height: 26px; font-weight: 600; }\n[data-edrv-diff-dock-shell] .edrv-pill-keep { background: var(--dsw-alias-state-success-tertiary); color: var(--dsw-alias-state-success-primary); border: 1px solid var(--dsw-alias-state-success-secondary); }\n[data-edrv-diff-dock-shell] .edrv-pill-undo { background: var(--dsw-alias-state-error-tertiary); color: var(--dsw-alias-state-error-primary); border: 1px solid var(--dsw-alias-state-error-secondary); }\n[data-edrv-diff-dock-shell] .edrv-pill-ghost { background: transparent; color: var(--dsw-alias-label-secondary); border: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-pill:hover:not(:disabled) { background-color: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-pill:focus-visible { outline: 2px solid var(--dsw-alias-label-tertiary); outline-offset: -2px; }\n[data-edrv-diff-dock-shell] .edrv-pill:disabled { opacity: .45; cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diffrow { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; background: transparent; cursor: pointer; flex-wrap: wrap; }\n[data-edrv-diff-dock-shell] .edrv-diffrow:hover { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-l { color: var(--dsw-alias-label-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-o { color: var(--dsw-alias-state-error-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-n { color: var(--dsw-alias-state-success-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-tag { color: var(--dsw-alias-label-tertiary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-stale { border-color: var(--dsw-alias-state-warn-secondary); cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diffbox-others { border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-file { border-color: var(--dsw-alias-border-l1); background: transparent; color: var(--dsw-alias-label-secondary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-file:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }\n[data-edrv-diff-dock-shell] .edrv-diff-details { display: flex; flex-direction: column; gap: 2px; padding: 6px 12px 8px; border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item { display: flex; align-items: center; width: 100%; min-height: 28px; gap: 8px; padding: 4px 8px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary); cursor: pointer; text-align: left; font-size: 12px; line-height: 20px; }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item.danger { color: var(--dsw-alias-state-error-primary); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item:disabled { opacity: .45; cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-sep { height: 1px; margin: 2px 4px; background: var(--dsw-alias-border-l1); }\n@media (max-width: 620px) {\n [data-edrv-diff-dock-shell] .edrv-diffbar-editor-content { width: max-content; }\n [data-edrv-diff-dock-shell] .edrv-diffbar-files .edrv-diffbar-file { max-width: 160px; }\n}\n\n/* ===== 侧边栏(活动栏 + 面板区 + 文件树) ===== */\n[data-edrv-view] .edrv-editor-row { display: flex; flex: 1 1 auto; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-main-col { box-sizing: border-box; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-main-col > .edrv-pathbar,\n[data-edrv-view] .edrv-main-col > .edrv-tabs { flex: 0 0 auto; }\n[data-edrv-view] .edrv-editor-area { position: relative; display: flex; flex: 1 1 auto; flex-direction: column; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-sidebar { display: flex; flex-direction: row; flex-shrink: 1; min-width: 0; height: 100%; background: var(--dsw-alias-bg-layer-1, #ffffff); border-right: 1px solid var(--dsw-alias-border-l1, #e0e6e8); overflow: hidden; }\n[data-edrv-view] .edrv-rail { display: flex; flex-direction: column; align-items: center; width: 44px; flex-shrink: 0; padding: 6px 0; background: var(--dsw-alias-bg-layer-2, #f0f4f4); border-right: 1px solid var(--dsw-alias-border-l1, #e0e6e8); gap: 4px; }\n[data-edrv-view] .edrv-rail-btn { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border: none; border-radius: 8px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-rail-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rail-btn.edrv-rail-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-label-primary, #1f2933); box-shadow: inset 2px 0 0 var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-rail-icon { font-size: 15px; line-height: 1; }\n[data-edrv-view] .edrv-rail-badge { position: absolute; top: 2px; right: 2px; min-width: 14px; height: 14px; padding: 0 3px; border-radius: 999px; background: var(--dsw-alias-brand-primary, #0f9d58); color: #fff; font-size: 9px; font-weight: 600; line-height: 14px; text-align: center; box-sizing: border-box; }\n[data-edrv-view] .edrv-side-body { flex: 1; min-width: 0; min-height: 0; display: flex; overflow: hidden; }\n[data-edrv-view] .edrv-side-panel { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; position: relative; }\n[data-edrv-view] .edrv-side-head { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px 0 12px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); flex-shrink: 0; }\n[data-edrv-view] .edrv-side-title { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-side-root { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-side-btn { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-side-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-tree { flex: 1; min-height: 0; overflow: auto; padding: 4px 6px 12px; font-size: 12px; }\n[data-edrv-view] .edrv-tree-row { display: flex; align-items: center; gap: 4px; height: 22px; padding-right: 6px; border-radius: 5px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-tree-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-active { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-context { box-shadow: inset 0 0 0 1px var(--dsw-alias-brand-primary, #0f9d58); background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); }\n[data-edrv-view] .edrv-tree-chev { width: 12px; flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; text-align: center; }\n[data-edrv-view] .edrv-tree-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-tree-name.edrv-tree-dim { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-tree-badge { min-width: 14px; height: 14px; padding: 0 4px; border-radius: 999px; background: var(--dsw-alias-state-warn-primary, #d97706); color: #fff; font-size: 9px; font-weight: 600; line-height: 14px; text-align: center; box-sizing: border-box; flex-shrink: 0; }\n[data-edrv-view] .edrv-tree-loading { height: 22px; line-height: 22px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-tree-error { display: flex; align-items: center; gap: 8px; margin: 4px 2px 6px; padding: 6px 8px; border: 1px solid rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n/* 大纲面板:kind 字形 / detail / 行号 */\n[data-edrv-view] .edrv-outline-kind { display: inline-flex; align-items: center; justify-content: center; width: 14px; flex-shrink: 0; font-size: 12px; font-weight: 600; text-align: center; }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-func { color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-type { color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-data { color: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-ns { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-key { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-outline-detail { flex-shrink: 0; max-width: 40%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-outline-ln { flex-shrink: 0; padding-right: 2px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-side-resize { width: 5px; flex-shrink: 0; cursor: col-resize; background: transparent; }\n[data-edrv-view] .edrv-side-resize:hover { background: var(--dsw-alias-brand-primary, #0f9d58); opacity: .35; }\n[data-edrv-view] .edrv-chip-btn.edrv-chip-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-label-primary, #1f2933); }\n\n/* ===== 侧栏形态(betterSidebar 面板内编辑区) ===== */\n[data-edrv-view][data-edrv-layout='side'] { box-sizing: border-box; height: 100%; }\n\n/* ===== 侧边栏引导条(旧页签形态、未装 betterSidebar 时) ===== */\n[data-edrv-view] .edrv-side-hint { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; flex-wrap: wrap; padding: 6px 12px; font-size: 12px; color: var(--dsw-alias-label-secondary, #52606d); background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, #f0f4f4)); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-side-hint-text { white-space: nowrap; }\n[data-edrv-view] .edrv-side-hint-cmd { font-size: 11px; padding: 2px 6px; border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #ffffff); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-side-hint-close { margin-left: auto; border: none; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); cursor: pointer; font-size: 14px; line-height: 1; padding: 2px 6px; border-radius: 6px; flex-shrink: 0; }\n[data-edrv-view] .edrv-side-hint-close:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n\n/* ===== search panel (sidebar, VSCode search view) ===== */\n[data-edrv-view] .edrv-search-panel { display: flex; flex-direction: column; min-height: 0; flex: 1; padding: 6px; gap: 4px; }\n[data-edrv-view] .edrv-search-qrow { display: flex; gap: 4px; }\n[data-edrv-view] .edrv-search-input { flex: 1; min-width: 0; height: 26px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search-input:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-opts { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-search-opt { min-width: 24px; height: 22px; padding: 0 6px; border: 1px solid transparent; border-radius: 5px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 11px; font-family: var(--ds-font-family-code, ui-monospace, monospace); cursor: pointer; }\n[data-edrv-view] .edrv-search-opt:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-opt.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); border-color: var(--dsw-alias-border-l2, #d5dde3); }\n[data-edrv-view] .edrv-search-spacer { flex: 1; }\n[data-edrv-view] .edrv-search-summary { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); padding: 2px 4px; }\n[data-edrv-view] .edrv-search-results { flex: 1; min-height: 0; overflow: auto; font-size: 12px; }\n[data-edrv-view] .edrv-search-group { margin-bottom: 2px; }\n[data-edrv-view] .edrv-search-file { display: flex; align-items: center; gap: 4px; height: 22px; padding: 0 4px; border-radius: 5px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-search-file:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-chev { width: 12px; flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; text-align: center; }\n[data-edrv-view] .edrv-search-fname { font-weight: 600; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-search-fdir { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-search-fcount { flex-shrink: 0; min-width: 16px; height: 15px; padding: 0 4px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); font-size: 10px; line-height: 15px; text-align: center; }\n[data-edrv-view] .edrv-search-line { display: flex; gap: 6px; padding: 1px 4px 1px 16px; border-radius: 4px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; overflow: hidden; }\n[data-edrv-view] .edrv-search-line.alt { background: var(--dsw-alias-bg-layer-1, #ffffff); }\n[data-edrv-view] .edrv-search-line:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-ln { flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; min-width: 26px; text-align: right; user-select: none; }\n[data-edrv-view] .edrv-search-text { overflow: hidden; text-overflow: ellipsis; white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; }\n[data-edrv-view] .edrv-search-hit { background: var(--dsw-alias-state-warn-primary, #e5b93f); color: #1f2933; border-radius: 2px; padding: 0 1px; }\n[data-edrv-view] .edrv-search-empty { padding: 8px 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-search-error { padding: 6px 8px; border: 1px solid rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n[data-edrv-view] .edrv-search-warn { padding: 6px 8px; border: 1px solid rgba(240,173,78,.45); border-radius: 6px; background: #fdf6e3; color: #b8860b; font-size: 11px; word-break: break-all; }\n\n/* include/exclude filter rows (collapsible) */\n[data-edrv-view] .edrv-search-rows { display: flex; flex-direction: column; gap: 4px; padding: 2px 0 4px; }\n[data-edrv-view] .edrv-search-row { display: flex; align-items: center; gap: 4px; }\n[data-edrv-view] .edrv-search-field { flex: 1; min-width: 0; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 11px; outline: none; }\n[data-edrv-view] .edrv-search-field:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-field.dim { opacity: .45; }\n[data-edrv-view] .edrv-search-field::placeholder { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-search-toggle { min-width: 24px; height: 24px; padding: 0 5px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; line-height: 1; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-search-toggle:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-toggle.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); border-color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-search-toggle:disabled { opacity: .4; cursor: default; }\n\n/* ===== rules panel (sidebar, Codebuddy rules view) ===== */\n[data-edrv-view] .edrv-rules-panel { display: flex; flex-direction: column; min-width: 0; min-height: 0; flex: 1; padding: 6px; gap: 4px; }\n[data-edrv-view] .edrv-rules-tabs { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-tab { height: 24px; padding: 0 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; cursor: pointer; }\n[data-edrv-view] .edrv-rules-tab:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-tab.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); font-weight: 600; }\n[data-edrv-view] .edrv-rules-new { margin-left: auto; height: 24px; padding: 0 10px; border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-new:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-ws-line { font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); padding: 0 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 0 0 auto; user-select: none; }\n[data-edrv-view] .edrv-rules-hint { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); padding: 0 2px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-list { flex: 1; min-height: 0; overflow: auto; }\n[data-edrv-view] .edrv-rules-row { display: flex; align-items: center; gap: 4px; padding: 6px 4px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; }\n[data-edrv-view] .edrv-rules-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-row.off .edrv-rules-main { opacity: .5; }\n[data-edrv-view] .edrv-rules-main { flex: 1; min-width: 0; cursor: pointer; overflow: hidden; }\n[data-edrv-view] .edrv-rules-line1 { display: flex; align-items: center; gap: 6px; min-width: 0; }\n[data-edrv-view] .edrv-rules-sub { display: flex; align-items: center; gap: 5px; margin-top: 3px; min-width: 0; }\n[data-edrv-view] .edrv-rules-sublabel { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-file { font-weight: 600; font-size: 12px; color: var(--dsw-alias-label-primary, #1f2933); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-rules-path { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-rules-type { flex-shrink: 0; height: 15px; padding: 0 5px; border-radius: 999px; font-size: 10px; line-height: 15px; }\n[data-edrv-view] .edrv-rules-type-always { background: rgba(15,157,88,.15); color: #0b7c46; }\n[data-edrv-view] .edrv-rules-type-auto { background: rgba(79,140,255,.16); color: #3367c9; }\n[data-edrv-view] .edrv-rules-type-manual { background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-rules-offtag { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-desc { font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; flex: 0 1 auto; }\n[data-edrv-view] .edrv-rules-actions { display: flex; align-items: center; gap: 2px; flex-shrink: 0; margin-left: auto; }\n[data-edrv-view] .edrv-rules-act { min-width: 22px; height: 22px; padding: 0 4px; border: none; border-radius: 5px; background: transparent; font-size: 12px; line-height: 1; cursor: pointer; color: var(--dsw-alias-label-secondary, #52606d); display: inline-flex; align-items: center; justify-content: center; }\n[data-edrv-view] .edrv-rules-act:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-switch { position: relative; width: 30px; height: 16px; border-radius: 999px; border: none; background: #b9c4cc; cursor: pointer; transition: background .15s; flex-shrink: 0; padding: 0; }\n[data-edrv-view] .edrv-rules-switch.on { background: #7c5cff; }\n[data-edrv-view] .edrv-rules-knob { position: absolute; top: 2px; left: 2px; width: 12px; height: 12px; border-radius: 50%; background: #fff; transition: left .15s; }\n[data-edrv-view] .edrv-rules-switch.on .edrv-rules-knob { left: 16px; }\n[data-edrv-view] .edrv-rules-empty { padding: 10px 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); line-height: 1.6; }\n[data-edrv-view] .edrv-rules-err { padding: 6px 8px; border: 1px solid rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; word-break: break-all; }\n[data-edrv-view] .edrv-rules-editor { display: flex; flex-direction: column; min-height: 0; flex: 1; gap: 6px; }\n[data-edrv-view] .edrv-rules-editor-head { display: flex; align-items: center; justify-content: space-between; gap: 6px; font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-crumb { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-rules-editor-ctl { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-ctl-label { font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-select { height: 24px; padding: 0 4px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 11px; outline: none; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-select:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-rules-desc-input { flex: 1; min-width: 0; }\n[data-edrv-view] .edrv-rules-input { flex: 1; min-width: 0; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 11px; outline: none; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-rules-input:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-rules-body { flex: 1; min-height: 0; resize: none; padding: 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; line-height: 1.5; outline: none; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-rules-body:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-rules-editor-hint { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); line-height: 1.5; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-editor-foot { display: flex; justify-content: flex-end; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-save { height: 24px; padding: 0 14px; border: none; border-radius: 6px; background: var(--dsw-alias-brand-primary, #0f9d58); color: #fff; font-size: 12px; cursor: pointer; }\n[data-edrv-view] .edrv-rules-save:disabled { opacity: .5; cursor: default; }\n\n\n\n";
34
+ const css$1 = "/* dsh-vscode-mode 编辑区样式(原 ensureEdrvStyles 字符串,落盘为真 .css,由 tsdown CSS-inline 注入) */\n/* 浅色主题(对齐参考图:#f8f8f8 近白底 + 薄荷绿药丸 + 青绿文字 + 三文鱼 undo + 浅灰边框):\n 在 [data-edrv-view] 作用域内重定义 --dsw-alias-*,级联命中组件内联样式与 CSS。 */\n[data-edrv-view] { box-sizing: border-box; --edrv-tab-h: 34px; --dsw-alias-bg-base: #f8f8f8; --dsw-alias-bg-layer-1: #ffffff; --dsw-alias-bg-layer-2: #f0f4f4; --dsw-alias-bg-overlay: #ffffff; --dsw-alias-label-primary: #1f2933; --dsw-alias-label-secondary: #52606d; --dsw-alias-label-tertiary: #9aa5b1; --dsw-alias-border-l1: #e0e6e8; --dsw-alias-border-l2: #cbd2d9; --dsw-alias-brand-primary: #0f9d58; --dsw-alias-state-success-primary: #0f9d58; --dsw-alias-state-error-primary: #d9534f; --dsw-alias-state-warn-primary: #d97706; --dsw-alias-interactive-bg-hover: rgba(15,157,88,.08); }\n\n[data-edrv-view] .edrv-tabs { display: flex; align-items: center; gap: 2px; padding: 2px 8px 0; background: var(--dsw-alias-bg-layer-1, transparent); overflow-x: auto; scrollbar-width: thin; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab { display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 8px 0 12px; border: none; border-radius: 6px 6px 0 0; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 12px; cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-tab.edrv-tab-active { background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); box-shadow: inset 0 -2px 0 var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-tab .edrv-tab-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--dsw-alias-brand-primary, #4f8cff); flex-shrink: 0; }\n[data-edrv-view] .edrv-tab .edrv-tab-x { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; border-radius: 4px; color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; }\n[data-edrv-view] .edrv-tab .edrv-tab-x:hover { background: rgba(255,255,255,.12); color: var(--dsw-alias-label-primary, #eee); }\n[data-edrv-view] .edrv-tab-add { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; margin-left: 2px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 14px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab-add:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-pathbar { display: flex; align-items: center; gap: 8px; height: 26px; padding: 0 10px; background: var(--dsw-alias-bg-layer-1, #ffffff); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 12px; flex-shrink: 0; overflow: hidden; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-name { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-full { flex: 1; min-width: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; direction: rtl; text-align: left; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-meta { flex-shrink: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-status { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-path-input { flex: 1; min-width: 140px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search-wrap { position: relative; flex-shrink: 0; display: flex; align-items: center; padding: 2px 8px 2px 4px; }\n[data-edrv-view] .edrv-search { width: 190px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-pop { position: absolute; top: calc(100% + 4px); right: 8px; width: min(460px, calc(100vw - 24px)); max-height: 300px; overflow: auto; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 10px; box-shadow: 0 6px 20px rgba(0,0,0,.4); z-index: 60; padding: 4px; }\n[data-edrv-view] .edrv-search-item { display: flex; flex-direction: column; gap: 1px; padding: 5px 8px; border-radius: 6px; cursor: pointer; }\n[data-edrv-view] .edrv-search-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.07)); }\n[data-edrv-view] .edrv-search-item .n { color: var(--dsw-alias-label-primary, #eee); font-size: 12px; word-break: break-all; }\n[data-edrv-view] .edrv-search-item .d { color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-search-empty { padding: 8px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #888); }\n[data-edrv-view] .edrv-btn-mini { font-size: 11px; padding: 2px 9px; border: none; border-radius: 999px; cursor: pointer; color: #fff; font-weight: 600; white-space: nowrap; }\n[data-edrv-view] .edrv-btn-keep { background: var(--dsw-alias-state-success-primary, #2e9e44); }\n[data-edrv-view] .edrv-btn-undo { background: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-btn-mini:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-statusbar { display: flex; align-items: center; gap: 10px; padding: 3px 10px; border-top: 1px solid var(--dsw-alias-border-l1, #333); background: var(--dsw-alias-bg-layer-1, transparent); font-size: 11px; color: var(--dsw-alias-label-tertiary, #888); flex-shrink: 0; white-space: nowrap; overflow: hidden; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-path { flex: 1; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-lsp { flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-progress-message { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-statusbar .edrv-sp-progress { flex: 0 0 auto; min-width: 36px; text-align: right; font-variant-numeric: tabular-nums; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-lsp-status-dot { width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto; background: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-lsp-status-dot.ready { background: var(--dsw-alias-state-success-primary, #0f9d58); }\n[data-edrv-view] .edrv-lsp-status-dot.busy { background: var(--dsw-alias-state-warn-primary, #d97706); animation: edrv-lsp-pulse 1.2s ease-in-out infinite; }\n@keyframes edrv-lsp-pulse { 50% { opacity: .45; } }\n/* Ctrl+hover 可导航标识符下划线提示(绑定 Monaco inlineClassName 装饰) */\n[data-edrv-view] .edrv-nav-underline { text-decoration: underline; text-decoration-color: var(--dsw-alias-interactive-primary, #4fc1ff); text-underline-offset: 1px; cursor: pointer; }\n[data-edrv-view] .edrv-diffchip { font-size: 11px; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #333); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-state-warn-primary, #b7791f); cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn { font-size: 12px; padding: 2px 6px; border: none; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; border-radius: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-chip-btn:disabled { opacity: .35; cursor: default; }\n[data-edrv-view] .edrv-chip-btn:disabled:hover { background: transparent; }\n[data-edrv-view] .edrv-mn-add-line { background: rgba(15,157,88,.10); }\n[data-edrv-view] .edrv-mn-gutter-add { color: #0f9d58 !important; font-weight: 700; display: flex !important; align-items: center; justify-content: center; }\n[data-edrv-view] .edrv-mn-gutter-add::before { content: \"+\"; }\n[data-edrv-view] .edrv-del-zone { background: #fdeaea; border-top: 1px solid rgba(217,83,79,.35); border-bottom: 1px solid rgba(217,83,79,.35); box-shadow: inset 0 0 0 1px rgba(217,83,79,.12); }\n[data-edrv-view] .edrv-del-row { white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 12.5px; line-height: 20px; color: #c0392b; }\n[data-edrv-view] .edrv-del-text { display: inline-block; white-space: pre; }\n[data-edrv-view] .edrv-minus-overlay { position: absolute; left: 0; top: 0; width: 100%; height: 100%; max-width: 100%; overflow: visible; pointer-events: none; z-index: 6; }\n[data-edrv-view] .edrv-minus-item { position: absolute; box-sizing: border-box; max-width: 100%; overflow: hidden; }\n[data-edrv-view] .edrv-minus-item::before { content: ''; position: absolute; left: 4px; top: 50%; width: 8px; height: 2px; transform: translateY(-50%); border-radius: 2px; background: #d9534f; }\n[data-edrv-view] .edrv-monaco-host { flex: 1 1 auto; min-width: 0; min-height: 0; position: relative; overflow: hidden; }\n[data-edrv-view] .edrv-monaco-host > div { position: absolute; inset: 0; min-width: 0; min-height: 0; }\n[data-edrv-view] .edrv-imgview { flex: 1 1 auto; min-width: 0; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }\n[data-edrv-view] .edrv-imgview-bar { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px; flex-shrink: 0; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, transparent); }\n[data-edrv-view] .edrv-imgview-meta { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; }\n[data-edrv-view] .edrv-imgview-stage { flex: 1 1 auto; min-height: 0; display: flex; align-items: center; justify-content: center; overflow: auto; padding: 14px; background-color: var(--dsw-alias-bg-layer-1, #f0f4f4); background-image: conic-gradient(rgba(128,128,128,.14) 25%, transparent 0 50%, rgba(128,128,128,.14) 0 75%, transparent 0); background-size: 16px 16px; }\n[data-edrv-view] .edrv-imgview-img { max-width: 100%; max-height: 100%; object-fit: contain; border-radius: 4px; box-shadow: 0 2px 12px rgba(31,41,51,.18); }\n[data-edrv-view] .edrv-imgview-broken { display: flex; flex-direction: column; align-items: center; gap: 10px; font-size: 13px; color: var(--dsw-alias-label-tertiary, #777); }\n[data-edrv-view] .edrv-pdf-host { flex: 1 1 auto; min-width: 0; min-height: 0; position: relative; overflow: hidden; }\n[data-edrv-view] .edrv-pdf-host > .edrv-pdf { position: absolute; inset: 0; }\n[data-edrv-view] .edrv-pdf { min-width: 0; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }\n[data-edrv-view] .edrv-pdf-bar { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px; flex-shrink: 0; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, transparent); }\n[data-edrv-view] .edrv-pdf-page { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; min-width: 52px; text-align: center; }\n[data-edrv-view] .edrv-pdf-zoom { min-width: 26px; text-align: center; padding: 3px 7px; }\n[data-edrv-view] .edrv-pdf-sep { width: 1px; height: 16px; background: var(--dsw-alias-border-l1, #e0e6e8); margin: 0 2px; }\n[data-edrv-view] .edrv-pdf-mode-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-brand-primary, #0f9d58); border-color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-pdf-dirty { color: var(--dsw-alias-state-warn-primary, #d97706); border-color: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-pdf-stage { position: absolute; top: 34px; left: 0; right: 0; bottom: 0; overflow: auto; }\n[data-edrv-view] .edrv-pdf-stage .edrv-pdf-viewer { margin: 0 auto; }\n[data-edrv-view] .edrv-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; height: 100%; color: var(--dsw-alias-label-tertiary, #777); font-size: 13px; }\n[data-edrv-view] .edrv-diffbar { position: absolute; left: 0; right: 0; bottom: 10px; margin: 0 auto; z-index: 25; width: fit-content; max-width: calc(100% - 20px); border-radius: 12px; background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, #f0f4f4)); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); box-shadow: none; overflow: visible; display: flex; flex-direction: column; }\n[data-edrv-view] .edrv-editor-area > .edrv-diffbar { max-height: calc(100% - 20px); }\n[data-edrv-view] .edrv-diffbar-row { display: flex; align-items: center; gap: 6px; height: 36px; padding: 4px 5px 4px 12px; flex-wrap: nowrap; }\n[data-edrv-view] .edrv-diffbar-count { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); min-width: 42px; text-align: center; white-space: nowrap; cursor: pointer; }\n[data-edrv-view] .edrv-diffbar-count.edrv-count-file { min-width: 64px; cursor: default; }\n[data-edrv-view] .edrv-diffbar-file { flex: 1; min-width: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-pill { font-size: 11px; padding: 3px 10px; border: none; border-radius: 999px; cursor: pointer; white-space: nowrap; font-weight: 600; }\n[data-edrv-view] .edrv-pill-keep { background: #e8f8e8; color: #0f7a45; border: 1px solid rgba(15,157,88,.4); }\n[data-edrv-view] .edrv-pill-undo { background: #fdeaea; color: #c0392b; border: 1px solid rgba(217,83,79,.4); }\n[data-edrv-view] .edrv-pill-ghost { background: #ffffff; color: var(--dsw-alias-label-secondary, #52606d); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-pill:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-diffbar-menu { position: absolute; right: 8px; bottom: calc(100% + 6px); z-index: 45; min-width: 160px; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 6px 20px rgba(31,41,51,.16); padding: 4px; display: flex; flex-direction: column; gap: 2px; }\n[data-edrv-view] .edrv-diffmenu-item { display: flex; align-items: center; gap: 8px; font-size: 12px; padding: 6px 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; text-align: left; }\n[data-edrv-view] .edrv-diffmenu-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-diffmenu-item.danger { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-diffmenu-sep { height: 1px; margin: 2px 4px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n/* 编辑区 / Tab 右键菜单(添加文件/选中内容到对话) */\n[data-edrv-view] .edrv-ctxmenu { position: fixed; z-index: 71; min-width: 200px; max-width: 320px; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 8px 26px rgba(31,41,51,.2); padding: 4px; display: flex; flex-direction: column; gap: 1px; }\n[data-edrv-view] .edrv-ctxmenu-item { display: flex; align-items: center; gap: 8px; font-size: 12px; line-height: 18px; padding: 7px 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-ctxmenu-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-danger { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-ctxmenu-item:disabled,\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-disabled { color: var(--dsw-alias-label-disabled, #b0b7c0); cursor: default; background: transparent; }\n[data-edrv-view] .edrv-ctxmenu-sep { height: 1px; margin: 3px 4px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-diffbar-body { max-height: 130px; max-width: min(560px, calc(100vw - 40px)); overflow: auto; padding: 4px 8px 8px; display: flex; flex-direction: column; gap: 4px; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-diffrow { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); cursor: pointer; flex-wrap: wrap; }\n[data-edrv-view] .edrv-diffrow:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-diffrow-l { font-size: 11px; color: var(--dsw-alias-label-primary, #1f2933); min-width: 74px; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-o { font-size: 11px; color: var(--dsw-alias-state-error-primary, #d9534f); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-n { font-size: 11px; color: var(--dsw-alias-state-success-primary, #0f9d58); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-tag { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-diffrow-stale { border-color: rgba(217,119,6,.5); cursor: default; }\n[data-edrv-view] .edrv-diffbox-others { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; padding: 4px 2px 0; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); margin-top: 2px; }\n[data-edrv-view] .edrv-diffrow-file { font-size: 11px; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); cursor: pointer; white-space: nowrap; max-width: 200px; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-diffrow-file:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n/* 编辑区 hover 差异块的 Keep/Undo 浮层 */\n[data-edrv-view] .edrv-hoveract { position: absolute; z-index: 30; display: flex; align-items: center; gap: 4px; padding: 2px 6px; border-radius: 8px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 4px 14px rgba(31,41,51,.14); }\n[data-edrv-view] .edrv-launch { position: absolute; left: 12px; right: 12px; bottom: 12px; z-index: 40; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); box-shadow: 0 6px 24px rgba(0,0,0,.5); display: flex; flex-direction: column; max-height: 60%; overflow: hidden; }\n[data-edrv-view] .edrv-launch-head { display: flex; align-items: center; gap: 6px; padding: 6px 8px; border-bottom: 1px solid var(--dsw-alias-border-l1, #333); }\n[data-edrv-view] .edrv-launch-tab { font-size: 12px; padding: 3px 12px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; }\n[data-edrv-view] .edrv-launch-tab.on { background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-label-primary, #eee); font-weight: 600; }\n[data-edrv-view] .edrv-launch-body { flex: 1; min-height: 0; overflow: auto; padding: 6px 8px; display: flex; flex-direction: column; gap: 4px; }\n[data-edrv-view] .edrv-launch-row { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1, #333); border-radius: 6px; cursor: pointer; flex-wrap: wrap; }\n[data-edrv-view] .edrv-launch-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-launch-path { flex: 1; min-width: 0; font-size: 12px; color: var(--dsw-alias-label-primary, #eee); word-break: break-all; }\n[data-edrv-view] .edrv-launch-cnt { font-size: 11px; color: var(--dsw-alias-label-tertiary, #888); white-space: nowrap; }\n[data-edrv-view] .edrv-launch-arch { display: flex; flex-direction: column; gap: 6px; }\n[data-edrv-view] .monaco-editor { overflow: hidden !important; }\n[data-edrv-view] .monaco-editor .sticky-widget { z-index: 30 !important; background: var(--dsw-alias-bg-base, #f8f8f8) !important; }\n[data-edrv-view] .monaco-editor .sticky-widget .sticky-line-content,\n[data-edrv-view] .monaco-editor .sticky-widget .sticky-line-number { background: var(--dsw-alias-bg-base, #f8f8f8) !important; }\n[data-edrv-view] .monaco-editor, [data-edrv-view] .monaco-editor .margin, [data-edrv-view] .monaco-editor-background { background: transparent !important; }\n[data-edrv-view] .monaco-editor .scrollbar .slider { background: rgba(128,128,128,.3) !important; }\n[data-edrv-view] .edrv-loading { gap: 8px; padding: 20px; }\n[data-edrv-view] .edrv-loading-title { color: var(--dsw-alias-label-primary, #1f2933); font-size: 13px; }\n[data-edrv-view] .edrv-progress { width: min(360px, 72%); height: 6px; overflow: hidden; border-radius: 999px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-progress-value { height: 100%; border-radius: inherit; background: var(--dsw-alias-brand-primary, #0f9d58); transition: width .24s ease; }\n[data-edrv-view] .edrv-loading-percent { color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; font-variant-numeric: tabular-nums; }\n@media (prefers-reduced-motion: reduce) {\n [data-edrv-view] .edrv-progress-value { transition: none; }\n}\n\n/* ===== 唯一会话级差异 dock(遵循 DSH todo/queue 原生布局) ===== */\n[data-edrv-diff-dock-shell] {\n box-sizing: border-box;\n width: calc(100% - var(--dsh-composer-side-clearance) - var(--dsh-composer-side-clearance) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));\n max-width: calc(var(--dsh-composer-card-max-width) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));\n margin: 0 auto;\n padding: 0;\n flex: none;\n border: 1px solid var(--dsw-alias-border-l1, #e0e6e8);\n border-radius: 12px;\n background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, transparent));\n box-shadow: none;\n overflow: hidden;\n}\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock {\n box-sizing: border-box;\n position: relative;\n left: auto;\n right: auto;\n bottom: auto;\n z-index: auto;\n width: 100%;\n max-width: none;\n margin: 0;\n display: flex;\n flex-direction: column;\n border: none;\n border-radius: 0;\n background: transparent;\n box-shadow: none;\n overflow: visible;\n}\n[data-edrv-diff-dock-shell] .edrv-diffbar-row { min-height: 36px; padding: 6px 12px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-row { min-height: 36px; padding: 6px 12px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-body { max-height: 180px; overflow: auto; padding: 6px 12px 10px; border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-button { box-sizing: border-box; display: flex; align-items: center; justify-content: center; width: 100%; height: 24px; border: none; border-radius: 8px; padding: 0 12px; background: transparent; color: var(--dsw-alias-label-primary); font-size: 13px; font-weight: 500; line-height: 24px; text-align: center; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-button:hover { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diffbar-count { display: inline-flex; align-items: center; color: var(--dsw-alias-label-primary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 500; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-file { display: inline-flex; align-items: center; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-editor-row { display: flex; align-items: center; height: 36px; min-height: 36px; padding: 4px 12px; overflow-x: auto; scrollbar-width: thin; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-editor-content { display: flex; align-items: center; gap: 10px; width: 100%; min-width: max-content; min-height: 28px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-nav,\n[data-edrv-diff-dock-shell] .edrv-diffbar-files,\n[data-edrv-diff-dock-shell] .edrv-diffbar-actions { display: flex; align-items: center; gap: 6px; flex: none; height: 28px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-actions { margin-left: auto; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-details-toggle { display: inline-flex; align-items: center; justify-content: center; width: 28px; min-width: 28px; padding: 0; font-size: 13px; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-details-toggle svg { width: 14px; height: 14px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-files { min-width: 0; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-files .edrv-diffbar-file { min-width: 72px; max-width: 240px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-progress { min-width: 0; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; font-variant-numeric: tabular-nums; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-summary { min-width: 0; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-pill { box-sizing: border-box; height: 28px; padding: 0 9px; border: none; border-radius: 999px; cursor: pointer; white-space: nowrap; font-size: 11px; line-height: 26px; font-weight: 600; }\n[data-edrv-diff-dock-shell] .edrv-pill-keep { background: var(--dsw-alias-state-success-tertiary); color: var(--dsw-alias-state-success-primary); border: 1px solid var(--dsw-alias-state-success-secondary); }\n[data-edrv-diff-dock-shell] .edrv-pill-undo { background: var(--dsw-alias-state-error-tertiary); color: var(--dsw-alias-state-error-primary); border: 1px solid var(--dsw-alias-state-error-secondary); }\n[data-edrv-diff-dock-shell] .edrv-pill-ghost { background: transparent; color: var(--dsw-alias-label-secondary); border: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-pill:hover:not(:disabled) { background-color: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-pill:focus-visible { outline: 2px solid var(--dsw-alias-label-tertiary); outline-offset: -2px; }\n[data-edrv-diff-dock-shell] .edrv-pill:disabled { opacity: .45; cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diffrow { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; background: transparent; cursor: pointer; flex-wrap: wrap; }\n[data-edrv-diff-dock-shell] .edrv-diffrow:hover { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-l { color: var(--dsw-alias-label-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-o { color: var(--dsw-alias-state-error-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-n { color: var(--dsw-alias-state-success-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-tag { color: var(--dsw-alias-label-tertiary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-stale { border-color: var(--dsw-alias-state-warn-secondary); cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diffbox-others { border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-file { border-color: var(--dsw-alias-border-l1); background: transparent; color: var(--dsw-alias-label-secondary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-file:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }\n[data-edrv-diff-dock-shell] .edrv-diff-details { display: flex; flex-direction: column; gap: 2px; padding: 6px 12px 8px; border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item { display: flex; align-items: center; width: 100%; min-height: 28px; gap: 8px; padding: 4px 8px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary); cursor: pointer; text-align: left; font-size: 12px; line-height: 20px; }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item.danger { color: var(--dsw-alias-state-error-primary); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item:disabled { opacity: .45; cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-sep { height: 1px; margin: 2px 4px; background: var(--dsw-alias-border-l1); }\n@media (max-width: 620px) {\n [data-edrv-diff-dock-shell] .edrv-diffbar-editor-content { width: max-content; }\n [data-edrv-diff-dock-shell] .edrv-diffbar-files .edrv-diffbar-file { max-width: 160px; }\n}\n\n/* ===== 侧边栏(活动栏 + 面板区 + 文件树) ===== */\n[data-edrv-view] .edrv-editor-row { display: flex; flex: 1 1 auto; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-main-col { box-sizing: border-box; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-main-col > .edrv-pathbar,\n[data-edrv-view] .edrv-main-col > .edrv-tabs { flex: 0 0 auto; }\n[data-edrv-view] .edrv-editor-area { position: relative; display: flex; flex: 1 1 auto; flex-direction: column; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-sidebar { display: flex; flex-direction: row; flex-shrink: 1; min-width: 0; height: 100%; background: var(--dsw-alias-bg-layer-1, #ffffff); border-right: 1px solid var(--dsw-alias-border-l1, #e0e6e8); overflow: hidden; }\n[data-edrv-view] .edrv-rail { display: flex; flex-direction: column; align-items: center; width: 44px; flex-shrink: 0; padding: 6px 0; background: var(--dsw-alias-bg-layer-2, #f0f4f4); border-right: 1px solid var(--dsw-alias-border-l1, #e0e6e8); gap: 4px; }\n[data-edrv-view] .edrv-rail-btn { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border: none; border-radius: 8px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-rail-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rail-btn.edrv-rail-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-label-primary, #1f2933); box-shadow: inset 2px 0 0 var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-rail-icon { font-size: 15px; line-height: 1; }\n[data-edrv-view] .edrv-rail-badge { position: absolute; top: 2px; right: 2px; min-width: 14px; height: 14px; padding: 0 3px; border-radius: 999px; background: var(--dsw-alias-brand-primary, #0f9d58); color: #fff; font-size: 9px; font-weight: 600; line-height: 14px; text-align: center; box-sizing: border-box; }\n[data-edrv-view] .edrv-side-body { flex: 1; min-width: 0; min-height: 0; display: flex; overflow: hidden; }\n[data-edrv-view] .edrv-side-panel { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; position: relative; }\n[data-edrv-view] .edrv-side-head { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px 0 12px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); flex-shrink: 0; }\n[data-edrv-view] .edrv-side-title { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-side-root { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-side-btn { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-side-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-tree { flex: 1; min-height: 0; overflow: auto; padding: 4px 6px 12px; font-size: 12px; }\n[data-edrv-view] .edrv-tree-row { display: flex; align-items: center; gap: 4px; height: 22px; padding-right: 6px; border-radius: 5px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-tree-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-active { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-context { box-shadow: inset 0 0 0 1px var(--dsw-alias-brand-primary, #0f9d58); background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); }\n[data-edrv-view] .edrv-tree-chev { width: 12px; flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; text-align: center; }\n[data-edrv-view] .edrv-tree-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-tree-name.edrv-tree-dim { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-tree-badge { min-width: 14px; height: 14px; padding: 0 4px; border-radius: 999px; background: var(--dsw-alias-state-warn-primary, #d97706); color: #fff; font-size: 9px; font-weight: 600; line-height: 14px; text-align: center; box-sizing: border-box; flex-shrink: 0; }\n[data-edrv-view] .edrv-tree-loading { height: 22px; line-height: 22px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-tree-error { display: flex; align-items: center; gap: 8px; margin: 4px 2px 6px; padding: 6px 8px; border: 1px solid rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n/* 大纲面板:kind 字形 / detail / 行号 */\n[data-edrv-view] .edrv-outline-kind { display: inline-flex; align-items: center; justify-content: center; width: 14px; flex-shrink: 0; font-size: 12px; font-weight: 600; text-align: center; }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-func { color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-type { color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-data { color: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-ns { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-key { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-outline-detail { flex-shrink: 0; max-width: 40%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-outline-ln { flex-shrink: 0; padding-right: 2px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-side-resize { width: 5px; flex-shrink: 0; cursor: col-resize; background: transparent; }\n[data-edrv-view] .edrv-side-resize:hover { background: var(--dsw-alias-brand-primary, #0f9d58); opacity: .35; }\n[data-edrv-view] .edrv-chip-btn.edrv-chip-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-label-primary, #1f2933); }\n\n/* ===== 侧栏形态(betterSidebar 面板内编辑区) ===== */\n[data-edrv-view][data-edrv-layout='side'] { box-sizing: border-box; height: 100%; }\n\n/* ===== 侧边栏引导条(旧页签形态、未装 betterSidebar 时) ===== */\n[data-edrv-view] .edrv-side-hint { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; flex-wrap: wrap; padding: 6px 12px; font-size: 12px; color: var(--dsw-alias-label-secondary, #52606d); background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, #f0f4f4)); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-side-hint-text { white-space: nowrap; }\n[data-edrv-view] .edrv-side-hint-cmd { font-size: 11px; padding: 2px 6px; border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #ffffff); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-side-hint-close { margin-left: auto; border: none; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); cursor: pointer; font-size: 14px; line-height: 1; padding: 2px 6px; border-radius: 6px; flex-shrink: 0; }\n[data-edrv-view] .edrv-side-hint-close:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n\n/* ===== search panel (sidebar, VSCode search view) ===== */\n[data-edrv-view] .edrv-search-panel { display: flex; flex-direction: column; min-height: 0; flex: 1; padding: 6px; gap: 4px; }\n[data-edrv-view] .edrv-search-qrow { display: flex; gap: 4px; }\n[data-edrv-view] .edrv-search-input { flex: 1; min-width: 0; height: 26px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search-input:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-opts { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-search-opt { min-width: 24px; height: 22px; padding: 0 6px; border: 1px solid transparent; border-radius: 5px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 11px; font-family: var(--ds-font-family-code, ui-monospace, monospace); cursor: pointer; }\n[data-edrv-view] .edrv-search-opt:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-opt.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); border-color: var(--dsw-alias-border-l2, #d5dde3); }\n[data-edrv-view] .edrv-search-spacer { flex: 1; }\n[data-edrv-view] .edrv-search-summary { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); padding: 2px 4px; }\n[data-edrv-view] .edrv-search-results { flex: 1; min-height: 0; overflow: auto; font-size: 12px; }\n[data-edrv-view] .edrv-search-group { margin-bottom: 2px; }\n[data-edrv-view] .edrv-search-file { display: flex; align-items: center; gap: 4px; height: 22px; padding: 0 4px; border-radius: 5px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-search-file:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-chev { width: 12px; flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; text-align: center; }\n[data-edrv-view] .edrv-search-fname { font-weight: 600; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-search-fdir { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-search-fcount { flex-shrink: 0; min-width: 16px; height: 15px; padding: 0 4px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); font-size: 10px; line-height: 15px; text-align: center; }\n[data-edrv-view] .edrv-search-line { display: flex; gap: 6px; padding: 1px 4px 1px 16px; border-radius: 4px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; overflow: hidden; }\n[data-edrv-view] .edrv-search-line.alt { background: var(--dsw-alias-bg-layer-1, #ffffff); }\n[data-edrv-view] .edrv-search-line:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-ln { flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; min-width: 26px; text-align: right; user-select: none; }\n[data-edrv-view] .edrv-search-text { overflow: hidden; text-overflow: ellipsis; white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; }\n[data-edrv-view] .edrv-search-hit { background: var(--dsw-alias-state-warn-primary, #e5b93f); color: #1f2933; border-radius: 2px; padding: 0 1px; }\n[data-edrv-view] .edrv-search-empty { padding: 8px 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-search-error { padding: 6px 8px; border: 1px solid rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n[data-edrv-view] .edrv-search-warn { padding: 6px 8px; border: 1px solid rgba(240,173,78,.45); border-radius: 6px; background: #fdf6e3; color: #b8860b; font-size: 11px; word-break: break-all; }\n\n/* include/exclude filter rows (collapsible) */\n[data-edrv-view] .edrv-search-rows { display: flex; flex-direction: column; gap: 4px; padding: 2px 0 4px; }\n[data-edrv-view] .edrv-search-row { display: flex; align-items: center; gap: 4px; }\n[data-edrv-view] .edrv-search-field { flex: 1; min-width: 0; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 11px; outline: none; }\n[data-edrv-view] .edrv-search-field:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-field.dim { opacity: .45; }\n[data-edrv-view] .edrv-search-field::placeholder { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-search-toggle { min-width: 24px; height: 24px; padding: 0 5px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; line-height: 1; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-search-toggle:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-toggle.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); border-color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-search-toggle:disabled { opacity: .4; cursor: default; }\n\n/* ===== rules panel (sidebar, Codebuddy rules view) ===== */\n[data-edrv-view] .edrv-rules-panel { display: flex; flex-direction: column; min-width: 0; min-height: 0; flex: 1; padding: 6px; gap: 4px; }\n[data-edrv-view] .edrv-rules-tabs { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-tab { height: 24px; padding: 0 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; cursor: pointer; }\n[data-edrv-view] .edrv-rules-tab:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-tab.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); font-weight: 600; }\n[data-edrv-view] .edrv-rules-new { margin-left: auto; height: 24px; padding: 0 10px; border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-new:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-ws-line { font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); padding: 0 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 0 0 auto; user-select: none; }\n[data-edrv-view] .edrv-rules-hint { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); padding: 0 2px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-list { flex: 1; min-height: 0; overflow: auto; }\n[data-edrv-view] .edrv-rules-row { display: flex; align-items: center; gap: 4px; padding: 6px 4px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; }\n[data-edrv-view] .edrv-rules-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-row.off .edrv-rules-main { opacity: .5; }\n[data-edrv-view] .edrv-rules-main { flex: 1; min-width: 0; cursor: pointer; overflow: hidden; }\n[data-edrv-view] .edrv-rules-line1 { display: flex; align-items: center; gap: 6px; min-width: 0; }\n[data-edrv-view] .edrv-rules-sub { display: flex; align-items: center; gap: 5px; margin-top: 3px; min-width: 0; }\n[data-edrv-view] .edrv-rules-sublabel { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-file { font-weight: 600; font-size: 12px; color: var(--dsw-alias-label-primary, #1f2933); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-rules-path { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-rules-type { flex-shrink: 0; height: 15px; padding: 0 5px; border-radius: 999px; font-size: 10px; line-height: 15px; }\n[data-edrv-view] .edrv-rules-type-always { background: rgba(15,157,88,.15); color: #0b7c46; }\n[data-edrv-view] .edrv-rules-type-auto { background: rgba(79,140,255,.16); color: #3367c9; }\n[data-edrv-view] .edrv-rules-type-manual { background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-rules-offtag { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-desc { font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; flex: 0 1 auto; }\n[data-edrv-view] .edrv-rules-actions { display: flex; align-items: center; gap: 2px; flex-shrink: 0; margin-left: auto; }\n[data-edrv-view] .edrv-rules-act { min-width: 22px; height: 22px; padding: 0 4px; border: none; border-radius: 5px; background: transparent; font-size: 12px; line-height: 1; cursor: pointer; color: var(--dsw-alias-label-secondary, #52606d); display: inline-flex; align-items: center; justify-content: center; }\n[data-edrv-view] .edrv-rules-act:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-switch { position: relative; width: 30px; height: 16px; border-radius: 999px; border: none; background: #b9c4cc; cursor: pointer; transition: background .15s; flex-shrink: 0; padding: 0; }\n[data-edrv-view] .edrv-rules-switch.on { background: #7c5cff; }\n[data-edrv-view] .edrv-rules-knob { position: absolute; top: 2px; left: 2px; width: 12px; height: 12px; border-radius: 50%; background: #fff; transition: left .15s; }\n[data-edrv-view] .edrv-rules-switch.on .edrv-rules-knob { left: 16px; }\n[data-edrv-view] .edrv-rules-empty { padding: 10px 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); line-height: 1.6; }\n[data-edrv-view] .edrv-rules-err { padding: 6px 8px; border: 1px solid rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; word-break: break-all; }\n[data-edrv-view] .edrv-rules-editor { display: flex; flex-direction: column; min-height: 0; flex: 1; gap: 6px; }\n[data-edrv-view] .edrv-rules-editor-head { display: flex; align-items: center; justify-content: space-between; gap: 6px; font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-crumb { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-rules-editor-ctl { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-ctl-label { font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-select { height: 24px; padding: 0 4px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 11px; outline: none; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-select:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-rules-desc-input { flex: 1; min-width: 0; }\n[data-edrv-view] .edrv-rules-input { flex: 1; min-width: 0; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 11px; outline: none; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-rules-input:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-rules-body { flex: 1; min-height: 0; resize: none; padding: 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; line-height: 1.5; outline: none; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-rules-body:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-rules-editor-hint { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); line-height: 1.5; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-editor-foot { display: flex; justify-content: flex-end; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-save { height: 24px; padding: 0 14px; border: none; border-radius: 6px; background: var(--dsw-alias-brand-primary, #0f9d58); color: #fff; font-size: 12px; cursor: pointer; }\n[data-edrv-view] .edrv-rules-save:disabled { opacity: .5; cursor: default; }\n\n\n\n";
35
35
  const tagId$1 = "dsh-vscode-mode/editor.css";
36
36
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
37
37
  const tag = document.createElement("style");
@@ -44,6 +44,22 @@ window.__ModuleLoader__.load({
44
44
  //#region src/shared/rpc.ts
45
45
  /** webServer 精确路由。 */
46
46
  const RPC_PATH = "/edrv/rpc";
47
+ /**
48
+ * 图片扩展名(小写、无点)→ MIME。edrv.read base64 响应与 client 图片预览共用,
49
+ * 收敛在此避免 host/client 两处漂移。
50
+ * @author ddj 2026年09月08号
51
+ */
52
+ const IMAGE_MIME = {
53
+ png: "image/png",
54
+ jpg: "image/jpeg",
55
+ jpeg: "image/jpeg",
56
+ gif: "image/gif",
57
+ webp: "image/webp",
58
+ bmp: "image/bmp",
59
+ ico: "image/x-icon",
60
+ avif: "image/avif",
61
+ svg: "image/svg+xml"
62
+ };
47
63
  //#endregion
48
64
  //#region src/client/rpc.ts
49
65
  /**
@@ -1105,6 +1121,457 @@ window.__ModuleLoader__.load({
1105
1121
  return monacoPromise.finally(unsubscribe);
1106
1122
  }
1107
1123
  //#endregion
1124
+ //#region src/client/imagePreview.ts
1125
+ /**
1126
+ * dsh-vscode-mode client — 图片文件判定与 data URL 组装(编辑区图片预览面板用)。
1127
+ * 纯函数、无 DOM 依赖,便于单测;MIME 表收敛在 shared/rpc.ts(host base64 响应同源)。
1128
+ * @author ddj 2026年09月08号
1129
+ */
1130
+ /** 可预览的图片扩展名集合(小写、无点)。 */
1131
+ const IMAGE_EXT_SET = new Set(Object.keys(IMAGE_MIME));
1132
+ /**
1133
+ * 判断路径是否为可预览的图片文件(取 basename 扩展名,大小写不敏感)。
1134
+ * @author ddj 2026年09月08号
1135
+ * @param path 文件路径(`/` 或 `\` 分隔均可)
1136
+ * @returns 是否图片文件
1137
+ */
1138
+ function isImagePath(path) {
1139
+ const base = String(path || "").split(/[\\/]/).pop() || "";
1140
+ const dot = base.lastIndexOf(".");
1141
+ if (dot <= 0) return false;
1142
+ return IMAGE_EXT_SET.has(base.slice(dot + 1).toLowerCase());
1143
+ }
1144
+ /**
1145
+ * 判断路径是否为 SVG 文件(唯一提供「以文本打开」切换的图片格式)。
1146
+ * @author ddj 2026年09月08号
1147
+ * @param path 文件路径(`/` 或 `\` 分隔均可)
1148
+ * @returns 是否 SVG
1149
+ */
1150
+ function isSvgPath(path) {
1151
+ const base = String(path || "").split(/[\\/]/).pop() || "";
1152
+ const dot = base.lastIndexOf(".");
1153
+ return dot > 0 && base.slice(dot + 1).toLowerCase() === "svg";
1154
+ }
1155
+ /**
1156
+ * base64 文本 → 可直接赋给 `<img src>` 的 data URL。
1157
+ * @author ddj 2026年09月08号
1158
+ * @param base64 base64 文本(不含 data: 前缀)
1159
+ * @param mime MIME 类型(host edrv.read base64 响应携带)
1160
+ * @returns data URL 字符串
1161
+ */
1162
+ function dataUrlOf(base64, mime) {
1163
+ return "data:" + (mime || "application/octet-stream") + ";base64," + base64;
1164
+ }
1165
+ //#endregion
1166
+ //#region src/client/pdfPreview.ts
1167
+ /**
1168
+ * 判断路径是否为 PDF 文件(取 basename 扩展名,大小写不敏感)。
1169
+ * @author ddj 2026年09月22号
1170
+ * @param path 文件路径(`/` 或 `\` 分隔均可)
1171
+ * @returns 是否 PDF 文件
1172
+ */
1173
+ function isPdfPath(path) {
1174
+ const base = String(path || "").split(/[\\/]/).pop() || "";
1175
+ const dot = base.lastIndexOf(".");
1176
+ return dot > 0 && base.slice(dot + 1).toLowerCase() === "pdf";
1177
+ }
1178
+ /**
1179
+ * base64 文本 → 二进制字节(喂给 pdf.js getDocument 的 data 入参)。
1180
+ * @author ddj 2026年09月22号
1181
+ * @param base64 base64 文本(不含 data: 前缀,host edrv.read base64 响应携带)
1182
+ * @returns 原始字节
1183
+ */
1184
+ function base64ToBytes(base64) {
1185
+ const bin = atob(String(base64 || ""));
1186
+ const bytes = new Uint8Array(bin.length);
1187
+ for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
1188
+ return bytes;
1189
+ }
1190
+ /**
1191
+ * 二进制字节 → base64 文本(编辑保存回传 host 前的编码步骤)。
1192
+ * @author ddj 2026年09月22号
1193
+ * @param bytes 原始字节
1194
+ * @returns base64 文本
1195
+ */
1196
+ function bytesToBase64(bytes) {
1197
+ let bin = "";
1198
+ const chunk = 32768;
1199
+ for (let i = 0; i < bytes.length; i += chunk) bin += String.fromCharCode(...bytes.subarray(i, i + chunk));
1200
+ return btoa(bin);
1201
+ }
1202
+ //#endregion
1203
+ //#region src/client/pdf/pdfLoader.ts
1204
+ /**
1205
+ * dsh-vscode-mode client — pdf.js 加载器(vendor 产物离线随包,/edrv/vendor/pdfjs/*)。
1206
+ * 加载链:module script 内按序动态 import build/pdf.mjs(自挂 globalThis.pdfjsLib)→
1207
+ * web/pdf_viewer.mjs(从 globalThis.pdfjsLib 解构)→ window.__edrvPdfjs handoff。
1208
+ * 用 script 注入而非打包内 import():客户端包是 CJS,bundler 会改写动态 import 破坏 URL 语义。
1209
+ * 作者 ddj 2026-09-22
1210
+ */
1211
+ /** vendor 根(routes.ts /edrv/vendor 前缀路由分发 assets/vendor/*)。 */
1212
+ const PDFJS_BASE = "/edrv/vendor/pdfjs";
1213
+ /** pdf.js Worker 地址(GlobalWorkerOptions.workerSrc)。 */
1214
+ const PDFJS_WORKER_SRC = PDFJS_BASE + "/build/pdf.worker.mjs";
1215
+ /** CJK 字符映射目录(中文 PDF 渲染必需,尾斜杠固定)。 */
1216
+ const PDFJS_CMAP_URL = PDFJS_BASE + "/cmaps/";
1217
+ /** 标准字体目录(未嵌字体 PDF 兜底,尾斜杠固定)。 */
1218
+ const PDFJS_FONT_URL = PDFJS_BASE + "/standard_fonts/";
1219
+ /** 组件层样式(pdfViewer/textLayer/annotationEditor 布局)。 */
1220
+ const PDFJS_CSS_URL = PDFJS_BASE + "/web/pdf_viewer.css";
1221
+ let pdfjsPromise = null;
1222
+ /**
1223
+ * 注入 pdf_viewer.css(幂等;vendor 路由带 etag 协商缓存,重复挂载走 304)。
1224
+ * @author ddj 2026年09月22号
1225
+ */
1226
+ function ensurePdfCss() {
1227
+ if (typeof document === "undefined") return;
1228
+ if (document.querySelector("link[data-edrv-pdfjs-css]")) return;
1229
+ const link = document.createElement("link");
1230
+ link.rel = "stylesheet";
1231
+ link.href = PDFJS_CSS_URL;
1232
+ link.dataset.edrvPdfjsCss = "1";
1233
+ document.head.appendChild(link);
1234
+ }
1235
+ /**
1236
+ * 加载 pdf.js(core + viewer 组件层):去重 promise,失败重置允许重试(对齐 monaco loader)。
1237
+ * @author ddj 2026年09月22号
1238
+ * @returns Promise<{lib, viewer}> lib=build/pdf.mjs(getDocument/GlobalWorkerOptions/编辑器枚举等),viewer=web/pdf_viewer.mjs(PDFViewer/EventBus 等)
1239
+ */
1240
+ function loadPdfjs() {
1241
+ if (!pdfjsPromise) pdfjsPromise = new Promise((resolve, reject) => {
1242
+ ensurePdfCss();
1243
+ const boot = () => {
1244
+ const handoff = window.__edrvPdfjs;
1245
+ if (handoff && handoff.lib && handoff.viewer) {
1246
+ try {
1247
+ handoff.lib.GlobalWorkerOptions.workerSrc = PDFJS_WORKER_SRC;
1248
+ } catch (error) {}
1249
+ resolve(handoff);
1250
+ return;
1251
+ }
1252
+ reject(/* @__PURE__ */ new Error("pdf.js 模块加载失败:handoff 缺失"));
1253
+ };
1254
+ const fail = (error) => {
1255
+ pdfjsPromise = null;
1256
+ reject(error instanceof Error ? error : new Error(String(error)));
1257
+ };
1258
+ const existing = document.querySelector("script[data-edrv-pdfjs-loader]");
1259
+ if (existing) {
1260
+ existing.addEventListener("edrv-pdfjs-ready", boot, { once: true });
1261
+ if (window.__edrvPdfjs) boot();
1262
+ return;
1263
+ }
1264
+ const s = document.createElement("script");
1265
+ s.type = "module";
1266
+ s.textContent = "import * as lib from \"/edrv/vendor/pdfjs/build/pdf.mjs\";\nimport * as viewer from \"/edrv/vendor/pdfjs/web/pdf_viewer.mjs\";\nwindow.__edrvPdfjs = { lib, viewer };\ndocument.querySelector(\"script[data-edrv-pdfjs-loader]\")?.dispatchEvent(new Event(\"edrv-pdfjs-ready\"));";
1267
+ s.dataset.edrvPdfjsLoader = "1";
1268
+ s.onload = boot;
1269
+ s.onerror = () => fail(/* @__PURE__ */ new Error("pdf.js loader 脚本加载失败(检查 assets/vendor/pdfjs 完整 / /edrv/vendor 路由可达)"));
1270
+ document.head.appendChild(s);
1271
+ });
1272
+ return pdfjsPromise;
1273
+ }
1274
+ //#endregion
1275
+ //#region src/client/pdf/pdfPanel.ts
1276
+ /**
1277
+ * dsh-vscode-mode client — PDF 面板控制器(命令式 DOM,React 只渲染外壳 div)。
1278
+ * 浏览:PDFViewer 组件(虚拟化渲染 + 文本层);编辑:内置注释编辑器
1279
+ * (FreeText 文本框 / Ink 画笔 / Highlight 高亮),保存经 pdfDocument.saveDocument()
1280
+ * → base64 → edrv.saveBinary 回写原文件。接线方式对齐官方 viewer(web/app.js)。
1281
+ * 作者 ddj 2026-09-22
1282
+ */
1283
+ /** 无障碍占位 l10n:组件内 translate 为 fire-and-forget,stub 避免触发 locale 404。 */
1284
+ const L10N_STUB = {
1285
+ get: async (key) => key,
1286
+ translate: async () => {},
1287
+ getDirection: () => "ltr"
1288
+ };
1289
+ /**
1290
+ * PDF 面板控制器工厂。
1291
+ * @author ddj 2026年09月22号
1292
+ * @param deps 依赖:sessionId/path(保存回写目标)+ 状态栏回调
1293
+ * @returns 控制器:mount/destroy/savePdf/setMode/isDirty
1294
+ */
1295
+ function createPdfPanel(deps) {
1296
+ const status = (t) => {
1297
+ try {
1298
+ deps.setStatus(t);
1299
+ } catch {}
1300
+ };
1301
+ let stage = null;
1302
+ let pageLabel = null;
1303
+ let eventBus = null;
1304
+ let busAbort = null;
1305
+ let editorTypes = null;
1306
+ let pdfViewer = null;
1307
+ let pdfDocument = null;
1308
+ let loadingTask = null;
1309
+ let modeButtons = null;
1310
+ let destroyed = false;
1311
+ let dirty = false;
1312
+ let saving = false;
1313
+ /** 脏状态上抛(tab 脏点)+ 本地记忆。 */
1314
+ const setDirty = (value) => {
1315
+ dirty = value;
1316
+ if (modeButtons) modeButtons.save.classList.toggle("edrv-pdf-dirty", value);
1317
+ try {
1318
+ deps.onDirtyChange(value);
1319
+ } catch {}
1320
+ };
1321
+ /** 页码指示更新(pagechanging/pagesinit 事件)。 */
1322
+ const updatePageLabel = () => {
1323
+ if (!pageLabel || !pdfViewer) return;
1324
+ pageLabel.textContent = pdfViewer.currentPageNumber + " / " + pdfViewer.pagesCount;
1325
+ };
1326
+ /** 编辑模式按钮高亮同步(annotationeditormodechanged 事件;evt.mode 为枚举数值)。 */
1327
+ const syncModeButtons = (mode) => {
1328
+ if (!modeButtons || !editorTypes) return;
1329
+ const key = {
1330
+ [editorTypes.NONE]: "none",
1331
+ [editorTypes.FREETEXT]: "freetext",
1332
+ [editorTypes.INK]: "ink",
1333
+ [editorTypes.HIGHLIGHT]: "highlight"
1334
+ }[mode] ?? "none";
1335
+ for (const k of Object.keys(modeButtons.modes)) modeButtons.modes[k].classList.toggle("edrv-pdf-mode-on", k === key);
1336
+ };
1337
+ /** 编辑模式符号键 → AnnotationEditorType 数值(版本间枚举值有差异,禁止硬编码)。 */
1338
+ const modeValueOf = (key) => {
1339
+ if (!editorTypes) return null;
1340
+ return {
1341
+ none: editorTypes.NONE,
1342
+ freetext: editorTypes.FREETEXT,
1343
+ ink: editorTypes.INK,
1344
+ highlight: editorTypes.HIGHLIGHT
1345
+ }[key] ?? null;
1346
+ };
1347
+ /**
1348
+ * 切换编辑模式(进入注释编辑器某模式或退出回 NONE)。
1349
+ * @author ddj 2026年09月22号
1350
+ * @param key 模式符号键:none/freetext/ink/highlight
1351
+ */
1352
+ const applyMode = (key) => {
1353
+ if (!pdfViewer || !pdfDocument) {
1354
+ status("PDF 未就绪");
1355
+ return;
1356
+ }
1357
+ const mode = modeValueOf(key);
1358
+ if (mode === null) return;
1359
+ try {
1360
+ pdfViewer.annotationEditorMode = { mode };
1361
+ status(key === "none" ? "已退出编辑" : "编辑模式:" + (key === "freetext" ? "文本框" : key === "ink" ? "画笔" : "高亮"));
1362
+ } catch (error) {
1363
+ status("切换编辑模式失败:" + String(error));
1364
+ }
1365
+ };
1366
+ /**
1367
+ * 保存编辑:saveDocument 导出 → base64 → edrv.saveBinary 回写。
1368
+ * @author ddj 2026年09月22号
1369
+ * @returns Promise<boolean> 是否成功
1370
+ */
1371
+ const savePdf = async () => {
1372
+ if (saving) return false;
1373
+ if (!pdfDocument) {
1374
+ status("PDF 未就绪");
1375
+ return false;
1376
+ }
1377
+ if (!dirty) {
1378
+ status("PDF 无未保存修改");
1379
+ return true;
1380
+ }
1381
+ saving = true;
1382
+ status("正在保存 PDF…");
1383
+ try {
1384
+ const data = await pdfDocument.saveDocument();
1385
+ const res = await rpc("edrv.saveBinary", {
1386
+ sessionId: deps.sessionId,
1387
+ path: deps.path,
1388
+ content: bytesToBase64(data),
1389
+ encoding: "base64"
1390
+ });
1391
+ if (res && res.ok) {
1392
+ setDirty(false);
1393
+ try {
1394
+ pdfDocument.annotationStorage.resetModified();
1395
+ } catch {}
1396
+ status("已保存 " + (/* @__PURE__ */ new Date()).toTimeString().slice(0, 8));
1397
+ return true;
1398
+ }
1399
+ status("保存失败");
1400
+ try {
1401
+ deps.setError(res?.error ? String(res.error) : "保存失败");
1402
+ } catch {}
1403
+ return false;
1404
+ } catch (error) {
1405
+ status("保存失败");
1406
+ try {
1407
+ deps.setError("PDF 保存异常:" + String(error));
1408
+ } catch {}
1409
+ return false;
1410
+ } finally {
1411
+ saving = false;
1412
+ }
1413
+ };
1414
+ /** 工具条 DOM(页码/缩放/编辑模式/保存/刷新)。 */
1415
+ const buildToolbar = (root) => {
1416
+ const bar = document.createElement("div");
1417
+ bar.className = "edrv-pdf-bar";
1418
+ const mkBtn = (text, title, onClick, cls) => {
1419
+ const b = document.createElement("button");
1420
+ b.className = cls || "edrv-pill edrv-pill-ghost";
1421
+ b.textContent = text;
1422
+ b.title = title;
1423
+ b.addEventListener("click", onClick);
1424
+ bar.appendChild(b);
1425
+ return b;
1426
+ };
1427
+ mkBtn("◀", "上一页", () => {
1428
+ if (pdfViewer) pdfViewer.currentPageNumber = Math.max(1, pdfViewer.currentPageNumber - 1);
1429
+ });
1430
+ pageLabel = document.createElement("span");
1431
+ pageLabel.className = "edrv-pdf-page";
1432
+ pageLabel.textContent = "…";
1433
+ bar.appendChild(pageLabel);
1434
+ mkBtn("▶", "下一页", () => {
1435
+ if (pdfViewer) pdfViewer.currentPageNumber = Math.min(pdfViewer.pagesCount, pdfViewer.currentPageNumber + 1);
1436
+ });
1437
+ mkBtn("−", "缩小", () => {
1438
+ try {
1439
+ pdfViewer.decreaseScale();
1440
+ } catch {}
1441
+ }, "edrv-pill edrv-pill-ghost edrv-pdf-zoom");
1442
+ mkBtn("+", "放大", () => {
1443
+ try {
1444
+ pdfViewer.increaseScale();
1445
+ } catch {}
1446
+ }, "edrv-pill edrv-pill-ghost edrv-pdf-zoom");
1447
+ bar.appendChild(document.createElement("span")).className = "edrv-pdf-sep";
1448
+ const modes = {};
1449
+ modes.freetext = mkBtn("✎ 文本框", "插入文本框注释", () => applyMode("freetext"));
1450
+ modes.ink = mkBtn("🖌 画笔", "手绘画笔注释", () => applyMode("ink"));
1451
+ modes.highlight = mkBtn("🖍 高亮", "高亮选中文本", () => applyMode("highlight"));
1452
+ modes.none = mkBtn("☐ 选择", "退出编辑模式", () => applyMode("none"));
1453
+ modeButtons = {
1454
+ modes,
1455
+ save: null
1456
+ };
1457
+ bar.appendChild(document.createElement("span")).className = "edrv-pdf-sep";
1458
+ mkBtn("⟳", "重新加载文件", () => {
1459
+ try {
1460
+ deps.onReload();
1461
+ } catch {}
1462
+ });
1463
+ modeButtons.save = mkBtn("💾 保存", "保存修改到文件 (Ctrl+S)", () => {
1464
+ savePdf();
1465
+ });
1466
+ root.appendChild(bar);
1467
+ };
1468
+ /**
1469
+ * 挂载面板并加载 PDF 字节。
1470
+ * @author ddj 2026年09月22号
1471
+ * @param host React 渲染的外壳 div(挂载后保持引用稳定)
1472
+ * @param bytes PDF 原始字节
1473
+ * @returns Promise<void> 渲染就绪或失败(失败置 deps.setError)
1474
+ */
1475
+ const mount = async (host, bytes) => {
1476
+ try {
1477
+ const pdfjs = await loadPdfjs();
1478
+ if (destroyed) return;
1479
+ editorTypes = pdfjs.lib.AnnotationEditorType;
1480
+ busAbort = new AbortController();
1481
+ const onBus = (name, fn) => eventBus.on(name, fn, { signal: busAbort.signal });
1482
+ const root = document.createElement("div");
1483
+ root.className = "edrv-pdf";
1484
+ buildToolbar(root);
1485
+ stage = document.createElement("div");
1486
+ stage.className = "edrv-pdf-stage";
1487
+ const viewerDiv = document.createElement("div");
1488
+ viewerDiv.className = "pdfViewer edrv-pdf-viewer";
1489
+ stage.appendChild(viewerDiv);
1490
+ root.appendChild(stage);
1491
+ host.textContent = "";
1492
+ host.appendChild(root);
1493
+ eventBus = new pdfjs.viewer.EventBus();
1494
+ const linkService = new pdfjs.viewer.PDFLinkService({ eventBus });
1495
+ pdfViewer = new pdfjs.viewer.PDFViewer({
1496
+ container: stage,
1497
+ viewer: viewerDiv,
1498
+ eventBus,
1499
+ linkService,
1500
+ l10n: L10N_STUB,
1501
+ textLayerMode: 1,
1502
+ annotationEditorMode: editorTypes.NONE
1503
+ });
1504
+ linkService.setViewer(pdfViewer);
1505
+ onBus("pagechanging", updatePageLabel);
1506
+ onBus("pagesinit", () => {
1507
+ try {
1508
+ pdfViewer.currentScaleValue = "page-width";
1509
+ } catch {}
1510
+ updatePageLabel();
1511
+ });
1512
+ onBus("annotationeditormodechanged", (evt) => syncModeButtons(evt?.mode));
1513
+ loadingTask = pdfjs.lib.getDocument({
1514
+ data: bytes,
1515
+ cMapUrl: PDFJS_CMAP_URL,
1516
+ cMapPacked: true,
1517
+ standardFontDataUrl: PDFJS_FONT_URL
1518
+ });
1519
+ pdfDocument = await loadingTask.promise;
1520
+ if (destroyed) {
1521
+ loadingTask.destroy();
1522
+ return;
1523
+ }
1524
+ const storage = pdfDocument.annotationStorage;
1525
+ storage.onSetModified = () => setDirty(true);
1526
+ storage.onResetModified = () => setDirty(false);
1527
+ pdfViewer.setDocument(pdfDocument);
1528
+ linkService.setDocument(pdfDocument);
1529
+ status("PDF 已就绪(" + pdfDocument.numPages + " 页)");
1530
+ } catch (error) {
1531
+ if (destroyed) return;
1532
+ const message = String(error && (error.message || error.name) || error);
1533
+ const friendly = message.includes("password") ? "不支持加密 PDF" : "PDF 加载失败:" + message;
1534
+ status("PDF 加载失败");
1535
+ try {
1536
+ deps.setError(friendly);
1537
+ } catch {}
1538
+ }
1539
+ };
1540
+ /** 是否有未保存修改(EditorView Ctrl+S 分派用)。 */
1541
+ const isDirty = () => dirty;
1542
+ /** 销毁:解绑事件、销毁文档与 DOM(重复调用安全)。 */
1543
+ const destroy = () => {
1544
+ destroyed = true;
1545
+ try {
1546
+ busAbort?.abort();
1547
+ } catch {}
1548
+ try {
1549
+ pdfViewer?.cleanup();
1550
+ } catch {}
1551
+ try {
1552
+ loadingTask?.destroy();
1553
+ } catch {}
1554
+ try {
1555
+ pdfDocument?.destroy();
1556
+ } catch {}
1557
+ if (stage?.parentNode) stage.parentNode.removeChild(stage);
1558
+ stage = null;
1559
+ eventBus = null;
1560
+ busAbort = null;
1561
+ editorTypes = null;
1562
+ pdfViewer = null;
1563
+ pdfDocument = null;
1564
+ loadingTask = null;
1565
+ modeButtons = null;
1566
+ };
1567
+ return {
1568
+ mount,
1569
+ destroy,
1570
+ savePdf,
1571
+ isDirty
1572
+ };
1573
+ }
1574
+ //#endregion
1108
1575
  //#region src/client/monaco/diffRender.ts
1109
1576
  /**
1110
1577
  * dsh-vscode-mode client — 行内差异自绘(新增行绿底 + glyph margin '+';删除块 view zone 红底)。
@@ -3616,6 +4083,14 @@ window.__ModuleLoader__.load({
3616
4083
  const [dirtyMap, setDirtyMap] = react.default.useState({});
3617
4084
  const [content, setContent] = react.default.useState(null);
3618
4085
  const [contentPath, setContentPath] = react.default.useState(null);
4086
+ const [imageSrc, setImageSrc] = react.default.useState(null);
4087
+ const [imgSize, setImgSize] = react.default.useState(null);
4088
+ const [imgBroken, setImgBroken] = react.default.useState(false);
4089
+ const svgTextRef = react.default.useRef(/* @__PURE__ */ new Set());
4090
+ const [pdfBytes, setPdfBytes] = react.default.useState(null);
4091
+ const pdfB64CacheRef = react.default.useRef(/* @__PURE__ */ new Map());
4092
+ const pdfCtlRef = react.default.useRef(/* @__PURE__ */ new Map());
4093
+ const pdfHostRef = react.default.useRef(null);
3619
4094
  const [status, setStatus] = react.default.useState("");
3620
4095
  const [lspServers, setLspServers] = react.default.useState([]);
3621
4096
  const [error, setError] = react.default.useState(null);
@@ -3683,6 +4158,8 @@ window.__ModuleLoader__.load({
3683
4158
  return list;
3684
4159
  }, [records, active]);
3685
4160
  const contentReady = content !== null && contentPath === active;
4161
+ const isImageActive = !!active && isImagePath(active) && !svgTextRef.current.has(active);
4162
+ const isPdfActive = !!active && isPdfPath(active);
3686
4163
  const regions = react.default.useMemo(() => diffRegions(currentRecords, contentReady ? content : null).filter((r) => !r.superseded), [
3687
4164
  currentRecords,
3688
4165
  content,
@@ -3837,6 +4314,12 @@ window.__ModuleLoader__.load({
3837
4314
  saveViewState(path);
3838
4315
  recordNav();
3839
4316
  }
4317
+ const pdfCtl = pdfCtlRef.current.get(path);
4318
+ if (pdfCtl) {
4319
+ pdfCtl.destroy();
4320
+ pdfCtlRef.current.delete(path);
4321
+ }
4322
+ pdfB64CacheRef.current.delete(path);
3840
4323
  setTabs((prev) => {
3841
4324
  const idx = prev.findIndex((t) => t.path === path);
3842
4325
  if (idx < 0) return prev;
@@ -3888,6 +4371,14 @@ window.__ModuleLoader__.load({
3888
4371
  */
3889
4372
  const loadContent = (path, sid, force) => {
3890
4373
  const seq = ++loadSeqRef.current;
4374
+ if (isImagePath(path) && !svgTextRef.current.has(path)) {
4375
+ loadImage(path, sid, seq);
4376
+ return;
4377
+ }
4378
+ if (isPdfPath(path)) {
4379
+ loadPdf(path, sid, seq, force === true);
4380
+ return;
4381
+ }
3891
4382
  const cachedModel = force ? null : modelsRef.current.get(path);
3892
4383
  if (cachedModel) {
3893
4384
  setContent(cachedModel.getValue());
@@ -3943,6 +4434,113 @@ window.__ModuleLoader__.load({
3943
4434
  setStatus("读取失败");
3944
4435
  });
3945
4436
  };
4437
+ /**
4438
+ * 加载图片文件为 data URL(编辑区只读预览);失败走 loadError 面板(重试经 loadContent 分派回此)。
4439
+ * @author ddj 2026年09月08号
4440
+ * @param path 图片文件路径
4441
+ * @param sid 会话 id
4442
+ * @param seq 加载序号(过期响应丢弃)
4443
+ */
4444
+ const loadImage = (path, sid, seq) => {
4445
+ setImageSrc(null);
4446
+ setImgSize(null);
4447
+ setImgBroken(false);
4448
+ setLoadStage({
4449
+ progress: monaco ? 72 : 12,
4450
+ message: "读取图片…"
4451
+ });
4452
+ rpc("edrv.read", {
4453
+ sessionId: sid,
4454
+ path,
4455
+ encoding: "base64"
4456
+ }).then((res) => {
4457
+ if (seq !== loadSeqRef.current || path !== active) return;
4458
+ if (res && res.ok && res.encoding === "base64") {
4459
+ if (!res.mime) {
4460
+ setLoadError("host 版本过旧:图片响应缺少 mime");
4461
+ setError("host 版本过旧:图片响应缺少 mime");
4462
+ setStatus("读取失败");
4463
+ return;
4464
+ }
4465
+ setImageSrc(dataUrlOf(res.content, res.mime));
4466
+ setLoadStage({
4467
+ progress: 100,
4468
+ message: "图片已就绪"
4469
+ });
4470
+ setStatus("已加载");
4471
+ return;
4472
+ }
4473
+ const base = res?.error ? String(res.error) : "读取失败";
4474
+ const message = res?.resolvedPath ? base + ":" + String(res.resolvedPath) : base;
4475
+ setLoadError(message);
4476
+ setError(message);
4477
+ setStatus("读取失败");
4478
+ }).catch((e) => {
4479
+ if (seq !== loadSeqRef.current) return;
4480
+ const message = "read异常:" + String(e);
4481
+ setLoadError(message);
4482
+ setError(message);
4483
+ setStatus("读取失败");
4484
+ });
4485
+ };
4486
+ /**
4487
+ * 加载 PDF 文件为原始字节(编辑区 PDF 面板);命中 base64 缓存秒切,force 绕过缓存重读。
4488
+ * 面板控制器由 pdf host mount effect 产出(per-path,关闭/卸载销毁)。
4489
+ * @author ddj 2026年09月22号
4490
+ * @param path PDF 文件路径
4491
+ * @param sid 会话 id
4492
+ * @param seq 加载序号(过期响应丢弃)
4493
+ * @param force true=绕过缓存强制 RPC 重读(刷新按钮)
4494
+ */
4495
+ const loadPdf = (path, sid, seq, force) => {
4496
+ setPdfBytes(null);
4497
+ setLoadStage({
4498
+ progress: monaco ? 72 : 12,
4499
+ message: "读取 PDF…"
4500
+ });
4501
+ const cache = pdfB64CacheRef.current;
4502
+ const hit = !force ? cache.get(path) : void 0;
4503
+ if (typeof hit === "string" && hit) {
4504
+ cache.delete(path);
4505
+ cache.set(path, hit);
4506
+ setPdfBytes(base64ToBytes(hit));
4507
+ setLoadStage({
4508
+ progress: 100,
4509
+ message: "PDF 已就绪"
4510
+ });
4511
+ setStatus("已加载");
4512
+ return;
4513
+ }
4514
+ rpc("edrv.read", {
4515
+ sessionId: sid,
4516
+ path,
4517
+ encoding: "base64"
4518
+ }).then((res) => {
4519
+ if (seq !== loadSeqRef.current || path !== active) return;
4520
+ if (res && res.ok && res.encoding === "base64") {
4521
+ cache.set(path, res.content);
4522
+ while (cache.size > 6) cache.delete(cache.keys().next().value);
4523
+ setPdfBytes(base64ToBytes(res.content));
4524
+ setLoadStage({
4525
+ progress: 100,
4526
+ message: "PDF 已就绪"
4527
+ });
4528
+ setStatus("已加载");
4529
+ return;
4530
+ }
4531
+ const base = res?.error ? String(res.error) : "读取失败";
4532
+ const message = res?.resolvedPath ? base + ":" + String(res.resolvedPath) : base;
4533
+ setLoadError(message);
4534
+ setError(message);
4535
+ setStatus("读取失败");
4536
+ }).catch((e) => {
4537
+ if (seq !== loadSeqRef.current) return;
4538
+ const message = "read异常:" + String(e);
4539
+ setLoadError(message);
4540
+ setError(message);
4541
+ setStatus("读取失败");
4542
+ });
4543
+ };
3946
4544
  react.default.useEffect(() => {
3947
4545
  if (!sessionId) return;
3948
4546
  refreshRecords();
@@ -4218,6 +4816,10 @@ window.__ModuleLoader__.load({
4218
4816
  if (!active) return;
4219
4817
  setContent(null);
4220
4818
  setContentPath(null);
4819
+ setImageSrc(null);
4820
+ setImgSize(null);
4821
+ setImgBroken(false);
4822
+ setPdfBytes(null);
4221
4823
  setLoadError(null);
4222
4824
  setLoadStage({
4223
4825
  progress: 10,
@@ -4292,8 +4894,26 @@ window.__ModuleLoader__.load({
4292
4894
  }
4293
4895
  };
4294
4896
  const doSave = (silent) => {
4897
+ if (!active) return;
4898
+ if (isPdfPath(active)) {
4899
+ const ctl = pdfCtlRef.current.get(active);
4900
+ if (!ctl) {
4901
+ if (!silent) setStatus("PDF 未就绪");
4902
+ return;
4903
+ }
4904
+ if (!ctl.isDirty()) {
4905
+ if (!silent) setStatus("PDF 无未保存修改");
4906
+ return;
4907
+ }
4908
+ ctl.savePdf();
4909
+ return;
4910
+ }
4295
4911
  const ed = editorRef.current;
4296
- if (!active || !ed) return;
4912
+ if (!ed) return;
4913
+ if (isImageActive) {
4914
+ setStatus("图片只读预览");
4915
+ return;
4916
+ }
4297
4917
  const text = ed.getValue();
4298
4918
  if (!silent) setStatus("保存中…");
4299
4919
  rpc("edrv.save", {
@@ -4340,6 +4960,32 @@ window.__ModuleLoader__.load({
4340
4960
  active,
4341
4961
  content
4342
4962
  ]);
4963
+ const ensurePdfHost = (node) => {
4964
+ pdfHostRef.current = node;
4965
+ };
4966
+ react.default.useEffect(() => {
4967
+ const host = pdfHostRef.current;
4968
+ if (!isPdfActive || !pdfBytes || !host) return;
4969
+ const path = active;
4970
+ const ctl = createPdfPanel({
4971
+ sessionId,
4972
+ path,
4973
+ setStatus,
4974
+ setError,
4975
+ onDirtyChange: (d) => setDirtyMap((prev) => Object.assign({}, prev, { [path]: d })),
4976
+ onReload: () => loadContent(path, sessionId, true)
4977
+ });
4978
+ pdfCtlRef.current.set(path, ctl);
4979
+ ctl.mount(host, pdfBytes);
4980
+ return () => {
4981
+ ctl.destroy();
4982
+ if (pdfCtlRef.current.get(path) === ctl) pdfCtlRef.current.delete(path);
4983
+ };
4984
+ }, [
4985
+ isPdfActive,
4986
+ pdfBytes,
4987
+ active
4988
+ ]);
4343
4989
  react.default.useEffect(() => {
4344
4990
  if (!monaco || !editorRef.current || !active || content === null) return;
4345
4991
  diffRendererRef.current.render(monaco, editorRef.current, pendingRegions, sessionId);
@@ -4363,6 +5009,8 @@ window.__ModuleLoader__.load({
4363
5009
  }
4364
5010
  for (const m of modelsRef.current.values()) m.dispose();
4365
5011
  modelsRef.current.clear();
5012
+ for (const ctl of pdfCtlRef.current.values()) ctl.destroy();
5013
+ pdfCtlRef.current.clear();
4366
5014
  const root = editorRef.current && editorRef.current.getDomNode ? editorRef.current.getDomNode() : null;
4367
5015
  if (root) {
4368
5016
  const ov = root.querySelector(".edrv-minus-overlay");
@@ -4624,6 +5272,53 @@ window.__ModuleLoader__.load({
4624
5272
  refreshRecords(skipStale === true);
4625
5273
  };
4626
5274
  /**
5275
+ * SVG 在图片预览与文本编辑间切换(按路径记忆;重载分派随集合状态自动路由)。
5276
+ * @author ddj 2026年09月08号
5277
+ * @param path SVG 文件路径
5278
+ */
5279
+ const toggleSvgText = (path) => {
5280
+ const next = new Set(svgTextRef.current);
5281
+ if (next.has(path)) next.delete(path);
5282
+ else next.add(path);
5283
+ svgTextRef.current = next;
5284
+ setContent(null);
5285
+ setContentPath(null);
5286
+ setImageSrc(null);
5287
+ setImgSize(null);
5288
+ setImgBroken(false);
5289
+ setLoadError(null);
5290
+ setStatus(next.has(path) ? "已切换为文本模式" : "已切换为图片预览");
5291
+ loadContent(path, sessionId, true);
5292
+ };
5293
+ /**
5294
+ * 图片预览面板:工具条(尺寸 meta / SVG 文本切换 / 刷新)+ 棋盘底自适应图片。
5295
+ * @author ddj 2026年09月08号
5296
+ */
5297
+ const imagePanel = () => react.default.createElement("div", { className: "edrv-imgview" }, react.default.createElement("div", { className: "edrv-imgview-bar" }, react.default.createElement("span", { className: "edrv-imgview-meta" }, imgBroken ? "图片无法显示" : imgSize ? imgSize.w + "×" + imgSize.h : "…"), react.default.createElement("span", { style: { flex: 1 } }), isSvgPath(active) ? react.default.createElement("button", {
5298
+ className: "edrv-pill edrv-pill-ghost",
5299
+ title: "以文本方式查看/编辑(SVG 为文本格式)",
5300
+ onClick: () => toggleSvgText(active)
5301
+ }, "以文本打开") : null, react.default.createElement("button", {
5302
+ className: "edrv-pill edrv-pill-ghost",
5303
+ title: "重新加载图片",
5304
+ onClick: () => reloadFile()
5305
+ }, "⟳ 刷新")), react.default.createElement("div", { className: "edrv-imgview-stage" }, imgBroken ? react.default.createElement("div", { className: "edrv-imgview-broken" }, react.default.createElement("div", null, "图片解码失败,文件可能已损坏"), react.default.createElement("button", {
5306
+ className: "edrv-pill edrv-pill-ghost",
5307
+ onClick: () => reloadFile()
5308
+ }, "重试")) : react.default.createElement("img", {
5309
+ className: "edrv-imgview-img",
5310
+ src: imageSrc,
5311
+ alt: active || "",
5312
+ onLoad: (e) => {
5313
+ setImgBroken(false);
5314
+ setImgSize({
5315
+ w: e.target.naturalWidth,
5316
+ h: e.target.naturalHeight
5317
+ });
5318
+ },
5319
+ onError: () => setImgBroken(true)
5320
+ })));
5321
+ /**
4627
5322
  * 关闭当前差异浮窗并清理 hover 锚点。
4628
5323
  * @author ddj 2026年08月21号
4629
5324
  */
@@ -4875,6 +5570,14 @@ window.__ModuleLoader__.load({
4875
5570
  const openPath = () => {
4876
5571
  const p = (pathDraft || "").trim();
4877
5572
  if (!p) return;
5573
+ if (isImagePath(p) || isPdfPath(p)) {
5574
+ openFile(p, false);
5575
+ setOpenInput(false);
5576
+ setPathDraft("");
5577
+ setStatus("已打开");
5578
+ setError(null);
5579
+ return;
5580
+ }
4878
5581
  setStatus("打开中…");
4879
5582
  rpc("edrv.read", {
4880
5583
  sessionId,
@@ -4950,7 +5653,7 @@ window.__ModuleLoader__.load({
4950
5653
  const pathBar = react.default.createElement("div", {
4951
5654
  className: "edrv-pathbar",
4952
5655
  title: active || ""
4953
- }, react.default.createElement("span", { className: "edrv-pb-name" }, active ? String(active).split(/[\\/]/).pop() : "未打开文件"), react.default.createElement("span", { className: "edrv-pb-full" }, active || "使用右上搜索框 (" + (chordOf("edrv.quickOpen") ?? "Ctrl+P") + ") 打开文件"), active && langOf(active) ? react.default.createElement("span", { className: "edrv-pb-meta" }, langOf(active)) : null, cursor ? react.default.createElement("span", { className: "edrv-pb-meta" }, cursor) : null, status ? react.default.createElement("span", { className: "edrv-pb-meta edrv-pb-status" }, status) : null);
5656
+ }, react.default.createElement("span", { className: "edrv-pb-name" }, active ? String(active).split(/[\\/]/).pop() : "未打开文件"), react.default.createElement("span", { className: "edrv-pb-full" }, active || "使用右上搜索框 (" + (chordOf("edrv.quickOpen") ?? "Ctrl+P") + ") 打开文件"), active && !isImageActive && langOf(active) ? react.default.createElement("span", { className: "edrv-pb-meta" }, langOf(active)) : null, isImageActive && imgSize ? react.default.createElement("span", { className: "edrv-pb-meta" }, imgSize.w + "×" + imgSize.h) : null, cursor ? react.default.createElement("span", { className: "edrv-pb-meta" }, cursor) : null, status ? react.default.createElement("span", { className: "edrv-pb-meta edrv-pb-status" }, status) : null);
4954
5657
  const lspLanguage = active ? langOf(active) : "";
4955
5658
  const lspServer = lspServers.find((item) => item.languageId === lspLanguage);
4956
5659
  const lspLabel = lspServer ? "LSP " + lspLanguage + " · " + ({
@@ -5056,6 +5759,14 @@ window.__ModuleLoader__.load({
5056
5759
  });
5057
5760
  loadContent(active, sessionId);
5058
5761
  });
5762
+ else if (isImageActive && imageSrc) body = imagePanel();
5763
+ else if (isImageActive) body = loadingBody(loadStage.message || "读取图片…", loadStage.progress);
5764
+ else if (isPdfActive && pdfBytes) body = react.default.createElement("div", {
5765
+ className: "edrv-pdf-host",
5766
+ ref: ensurePdfHost,
5767
+ key: active
5768
+ });
5769
+ else if (isPdfActive) body = loadingBody(loadStage.message || "读取 PDF…", loadStage.progress);
5059
5770
  else if (content === null) body = loadingBody(loadStage.message || "读取文件内容…", loadStage.progress);
5060
5771
  else body = react.default.createElement("div", { className: "edrv-monaco-host" }, react.default.createElement("div", { ref: ensureEditor }));
5061
5772
  const hoverEl = hoverAct && !launcherOpen ? react.default.createElement("div", {
@@ -5730,6 +6441,36 @@ window.__ModuleLoader__.load({
5730
6441
  if (owner[key] === patched) owner[key] = original;
5731
6442
  };
5732
6443
  }
6444
+ /**
6445
+ * accessor 感知的链式补丁:DSH 0.1.3+ 的 remote 命名空间方法(如
6446
+ * remote.session.openWorkspacePath)是 getter-only accessor(Object.defineProperty
6447
+ * 仅定义 get,直接赋值在严格模式下抛 TypeError),须整体替换属性描述符。
6448
+ * 新 getter 每次访问现场调用原 getter 取最新一次性函数作 original,天然跟随
6449
+ * DSH 内部 methods 表变化;data 属性降级走 patchMethod;属性缺失返回 null。
6450
+ * @author ddj 2026年09月08号
6451
+ * @param owner 目标对象
6452
+ * @param key 属性名
6453
+ * @param wrapper 包装实现(original 为补丁前的实时实现)
6454
+ * @returns 恢复函数(幂等、带归属校验);属性缺失时返回 null
6455
+ */
6456
+ function patchAccessor(owner, key, wrapper) {
6457
+ const descriptor = Object.getOwnPropertyDescriptor(owner, key);
6458
+ if (!descriptor) return null;
6459
+ if (typeof descriptor.get !== "function") return patchMethod(owner, key, wrapper);
6460
+ const rawGet = descriptor.get;
6461
+ const patchedGet = function() {
6462
+ const original = (...args) => rawGet.call(owner)(...args);
6463
+ return (...args) => wrapper(original, ...args);
6464
+ };
6465
+ Object.defineProperty(owner, key, {
6466
+ configurable: true,
6467
+ enumerable: descriptor.enumerable,
6468
+ get: patchedGet
6469
+ });
6470
+ return () => {
6471
+ if (Object.getOwnPropertyDescriptor(owner, key)?.get === patchedGet) Object.defineProperty(owner, key, descriptor);
6472
+ };
6473
+ }
5733
6474
  //#endregion
5734
6475
  //#region src/client/fileOpeners.ts
5735
6476
  /**
@@ -7726,6 +8467,63 @@ window.__ModuleLoader__.load({
7726
8467
  return typeof value === "string" && value.trim() ? value.trim() : AUTO_OPEN_TOOL;
7727
8468
  }
7728
8469
  //#endregion
8470
+ //#region src/client/remoteOpenRouter.ts
8471
+ /**
8472
+ * dsh-vscode-mode client — DSH 对话文件链接的 0.1.3+ 路由(remote.session 面)。
8473
+ * 0.1.3 起 dsh-client-ui-chat 的 openFile 直接调 ctx.remote.session.openWorkspacePath
8474
+ * (浏览器→host RPC session/openWorkspacePath),不再经过 workspaces.openPath,
8475
+ * 旧路由补丁因此落空;该方法是 getter-only accessor,补丁经 compat.patchAccessor
8476
+ * 换描述符安装。行为与 openPathRouter 对齐:插件打开器优先,"."(打开工作区文件夹)、
8477
+ * 无可用打开器或打开失败时透传原实现(系统默认应用打开)。
8478
+ * 纯逻辑,node 环境可单测(不依赖 DOM / events 模块)。
8479
+ * 作者 ddj 2026年09月08号
8480
+ */
8481
+ /** 插件打开器接管成功时返回给调用方(chat 只看 ok,产物区读 value)。 */
8482
+ const OPENED_RESULT = {
8483
+ ok: true,
8484
+ value: { opened: true }
8485
+ };
8486
+ /**
8487
+ * 结构化探测 remote.session 命名空间服务及其 openWorkspacePath 方法。
8488
+ * 旧版 DSH 无该 namespace、或 api-remotes 尚未挂载时返回 undefined。
8489
+ * @author ddj 2026年09月08号
8490
+ * @param ctx 客户端服务上下文
8491
+ * @returns 命名空间服务实例;不可用返回 undefined
8492
+ */
8493
+ function probeRemoteOpen(ctx) {
8494
+ try {
8495
+ const service = ctx.get("remote.session");
8496
+ if (!service || typeof service.openWorkspacePath !== "function") return void 0;
8497
+ return service;
8498
+ } catch {
8499
+ return;
8500
+ }
8501
+ }
8502
+ /**
8503
+ * 安装可卸载的 remote.session.openWorkspacePath 路由(0.1.3+ 会话文件链接主路径)。
8504
+ * @author ddj 2026年09月08号
8505
+ * @param service probeRemoteOpen 命中的命名空间服务
8506
+ * @param options 路由依赖
8507
+ * @returns 恢复函数;目标属性缺失时返回 null(调用方停止安装并告警)
8508
+ */
8509
+ function patchRemoteOpen(service, options) {
8510
+ return patchAccessor(service, "openWorkspacePath", async (original, ...args) => {
8511
+ const fallback = original;
8512
+ const request = args[0] ?? {};
8513
+ const path = typeof request.path === "string" ? request.path : "";
8514
+ if (!path || path === ".") return fallback(request);
8515
+ const opener = selectOpener(options.registry, options.selected());
8516
+ if (!opener || !isAvailable(opener)) return fallback(request);
8517
+ try {
8518
+ await opener.open(path, options.context());
8519
+ return OPENED_RESULT;
8520
+ } catch (error) {
8521
+ options.logger?.("文件打开器 " + opener.id + " 失败,回退系统打开: " + String(error));
8522
+ return fallback(request);
8523
+ }
8524
+ });
8525
+ }
8526
+ //#endregion
7729
8527
  //#region src/shared/externalOpen.ts
7730
8528
  /**
7731
8529
  * dsh-vscode-mode shared — 外部深链 URL 契约(Windows launcher / Unity 包 / client 共用)。
@@ -10976,6 +11774,19 @@ window.__ModuleLoader__.load({
10976
11774
  const binder = pickSettingsBinder(ctx);
10977
11775
  const settings = binder.scope;
10978
11776
  let selected = autoValue("auto");
11777
+ /** 0.1.3+ 会话文件链接路由(remote.session.openWorkspacePath)是否已安装(compatSummary 展示用)。 */
11778
+ let remoteOpenInstalled = false;
11779
+ /** 两条文件链接路由共用的路由日志(openPathRouter / remoteOpenRouter)。 */
11780
+ const routeLogger = (message) => console.warn("[dsh-vscode-mode] " + message);
11781
+ /** 两条路由共用的 FileOpenContext:当前会话 id 与工作区 cwd。 */
11782
+ const openContext = () => {
11783
+ const current = sessions?.list?.getSnapshot?.();
11784
+ const sessionId = current?.current;
11785
+ return {
11786
+ sessionId,
11787
+ cwd: (sessionId ? current?.byId?.[sessionId] : void 0)?.cwd
11788
+ };
11789
+ };
10979
11790
  /** 可选探测 betterSidebar 服务(不进 inject:缺失会让插件停靠等待,杀死回退路径)。 */
10980
11791
  let sideService = detectSidebarService(ctx);
10981
11792
  /** 「添加到对话」动作集:编辑区/Tab 右键菜单注入文件引用与代码块(conversation 服务缺失时各动作安全降级)。 */
@@ -10990,7 +11801,12 @@ window.__ModuleLoader__.load({
10990
11801
  {
10991
11802
  name: "文件打开路由(workspaces.openPath)",
10992
11803
  active: Boolean(workspaces?.openPath),
10993
- note: "vscode 打开器优先,失败回退系统打开"
11804
+ note: "vscode 打开器优先,失败回退系统打开(0.1.2 及更早 DSH 的对话文件链接主路径)"
11805
+ },
11806
+ {
11807
+ name: "会话文件链接路由(remote.session.openWorkspacePath)",
11808
+ active: remoteOpenInstalled,
11809
+ note: "0.1.3+ 对话文件引用/产物打开优先走插件打开器,失败回退系统打开"
10994
11810
  },
10995
11811
  {
10996
11812
  name: "侧边栏打开器(dsh-better-sidebar)",
@@ -11055,16 +11871,39 @@ window.__ModuleLoader__.load({
11055
11871
  workspaces,
11056
11872
  registry,
11057
11873
  selected: () => selected,
11058
- context: () => {
11059
- const current = sessions?.list?.getSnapshot?.();
11060
- const sessionId = current?.current;
11061
- return {
11062
- sessionId,
11063
- cwd: (sessionId ? current?.byId?.[sessionId] : void 0)?.cwd
11064
- };
11065
- },
11066
- logger: (message) => console.warn("[dsh-vscode-mode] " + message)
11874
+ context: openContext,
11875
+ logger: routeLogger
11067
11876
  }), "vscode-mode: file link routing");
11877
+ let remoteRetries = 0;
11878
+ const retryRemoteOpen = () => {
11879
+ if (remoteOpenInstalled || remoteRetries >= 15) {
11880
+ if (!remoteOpenInstalled) console.warn("[dsh-vscode-mode] 未探测到 remote.session.openWorkspacePath,0.1.3+ 会话文件链接路由未安装");
11881
+ return;
11882
+ }
11883
+ remoteRetries += 1;
11884
+ schedule(() => {
11885
+ if (remoteOpenInstalled) return;
11886
+ const service = probeRemoteOpen(ctx);
11887
+ if (!service) {
11888
+ retryRemoteOpen();
11889
+ return;
11890
+ }
11891
+ const disposer = patchRemoteOpen(service, {
11892
+ registry,
11893
+ selected: () => selected,
11894
+ context: openContext,
11895
+ logger: routeLogger
11896
+ });
11897
+ if (!disposer) {
11898
+ console.warn("[dsh-vscode-mode] remote.session 存在但 openWorkspacePath 不可补丁,会话文件链接路由未安装");
11899
+ return;
11900
+ }
11901
+ remoteOpenInstalled = true;
11902
+ ctx.effect(() => disposer, "vscode-mode: remote file link routing");
11903
+ console.info("[dsh-vscode-mode] 已安装 0.1.3+ 会话文件链接路由(remote.session.openWorkspacePath)");
11904
+ }, 2e3);
11905
+ };
11906
+ retryRemoteOpen();
11068
11907
  const registerLegacyTab = () => {
11069
11908
  return registerSlotSafely(ctx, {
11070
11909
  name: "conversation.view",