dsh-vscode-mode 0.1.62 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -28,10 +28,11 @@ window.__ModuleLoader__.load({
28
28
  //#endregion
29
29
  let react = require("react");
30
30
  react = __toESM(react, 1);
31
- let react_dom_client = require("react-dom/client");
32
31
  let react_dom = require("react-dom");
32
+ let react_dom_client = require("react-dom/client");
33
+ let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
33
34
  //#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-star { color: var(--dsw-alias-brand-primary, #4f8cff); font-size: 13px; font-weight: 700; line-height: 1; flex-shrink: 0; } /* 未保存修改星号 @author ddj 2026年09月09号 */\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
+ const css$1 = "/* dsh-vscode-mode 编辑区样式(原 ensureEdrvStyles 字符串,落盘为真 .css,由 tsdown CSS-inline 注入) */\n/* 主题:跟随官方 --dsw-alias-* 令牌(DSH 明暗与第三方皮肤生效)。\n 本作用域不再重定义官方令牌(旧实现曾在此硬覆盖浅色盘,导致插件不跟随 DSH 主题);\n 旧环境/缺令牌场景由每条声明的 var(--dsw-alias-*, 回落值) 兜底。\n @author ddj 2026-09-10 */\n[data-edrv-view] { box-sizing: border-box; --edrv-tab-h: 34px; }\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-star { color: var(--dsw-alias-brand-primary, #4f8cff); font-size: 13px; font-weight: 700; line-height: 1; flex-shrink: 0; } /* 未保存修改星号 @author ddj 2026年09月09号 */\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: var(--dsw-alias-interactive-bg-hover, 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: var(--dsw-alias-label-primary-inverted, #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: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.10)); }\n[data-edrv-view] .edrv-mn-gutter-add { color: var(--dsw-alias-state-success-primary, #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: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.14)); border-top: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.35)); border-bottom: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.35)); box-shadow: inset 0 0 0 1px var(--dsw-alias-interactive-bg-hover-danger, 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: var(--dsw-alias-state-error-primary, #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: var(--dsw-alias-state-error-primary, #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: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-state-success-primary, #0f7a45); border: 1px solid var(--dsw-alias-state-success-primary, rgba(15,157,88,.4)); }\n[data-edrv-view] .edrv-pill-undo { background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.14)); color: var(--dsw-alias-state-error-primary, #c0392b); border: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); }\n[data-edrv-view] .edrv-pill-ghost { background: var(--dsw-alias-bg-layer-1, #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: var(--dsw-alias-state-warn-primary, 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; display: inline-flex; align-items: center; justify-content: center; }\n/* 树行图标:官方原语(文件夹/文件类型),尺寸与行高对齐 @author ddj 2026-09-10 */\n[data-edrv-view] .edrv-tree-icon { flex-shrink: 0; display: inline-flex; align-items: center; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-active .edrv-tree-icon { color: var(--dsw-alias-label-secondary, #52606d); }\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: var(--dsw-alias-label-primary-inverted, #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: var(--dsw-alias-label-primary-inverted, #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 var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); 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: var(--dsw-alias-label-primary-inverted, #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 var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n[data-edrv-view] .edrv-search-warn { padding: 6px 8px; border: 1px solid var(--dsw-alias-state-warn-primary, rgba(240,173,78,.45)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover, rgba(240,173,78,.12)); color: var(--dsw-alias-state-warn-primary, #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: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.15)); color: var(--dsw-alias-state-success-primary, #0b7c46); }\n[data-edrv-view] .edrv-rules-type-auto { background: var(--dsw-alias-interactive-bg-hover-accent, rgba(79,140,255,.16)); color: var(--dsw-alias-link, #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: var(--dsw-alias-border-l2, #b9c4cc); cursor: pointer; transition: background .15s; flex-shrink: 0; padding: 0; }\n[data-edrv-view] .edrv-rules-switch.on { background: var(--dsw-alias-brand-primary, #7c5cff); }\n[data-edrv-view] .edrv-rules-knob { position: absolute; top: 2px; left: 2px; width: 12px; height: 12px; border-radius: 50%; background: var(--dsw-alias-bg-layer-1, #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 var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); 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: var(--dsw-alias-label-primary-inverted, #fff); font-size: 12px; cursor: pointer; }\n[data-edrv-view] .edrv-rules-save:disabled { opacity: .5; cursor: default; }\n\n/* 命令栏(Ctrl+Shift+P / F1):body 级 portal 浮层,故不依赖编辑区几何 */\n[data-edrv-view] .edrv-palette-mask { position: fixed; inset: 0; z-index: 190; background: rgba(0, 0, 0, .28); }\n[data-edrv-view] .edrv-palette { position: fixed; top: 12vh; left: 50%; transform: translateX(-50%); z-index: 191; width: min(580px, calc(100vw - 32px)); max-height: 64vh; display: flex; flex-direction: column; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 12px 34px rgba(31, 41, 51, .24); overflow: hidden; }\n[data-edrv-view] .edrv-palette-input { height: 38px; flex: 0 0 auto; padding: 0 12px; border: none; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: transparent; color: var(--dsw-alias-label-primary, #1f2933); font-size: 13px; outline: none; }\n[data-edrv-view] .edrv-palette-list { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 4px; }\n[data-edrv-view] .edrv-palette-row { display: flex; align-items: center; gap: 8px; padding: 6px 10px; border-radius: 6px; font-size: 12px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; }\n[data-edrv-view] .edrv-palette-row.edrv-palette-sel { background: var(--dsw-alias-interactive-bg-hover, rgba(15, 157, 88, .10)); }\n[data-edrv-view] .edrv-palette-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-palette-cat { flex: 0 0 auto; font-size: 10px; padding: 1px 7px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-tertiary, #7b8794); }\n[data-edrv-view] .edrv-palette-key { flex: 0 0 auto; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 10px; padding: 1px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 5px; background: var(--dsw-alias-bg-layer-1, #f7f9fa); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-palette-empty { padding: 14px 10px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #7b8794); text-align: center; }\n[data-edrv-view] .edrv-palette-notice { flex: 0 0 auto; padding: 6px 10px; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 11px; color: var(--dsw-alias-state-warn-primary, #b7791f); }\n\n\n\n\n";
35
36
  const tagId$1 = "dsh-vscode-mode/editor.css";
36
37
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
37
38
  const tag = document.createElement("style");
@@ -504,11 +505,11 @@ window.__ModuleLoader__.load({
504
505
  //#endregion
505
506
  //#region src/client/monaco/theme.ts
506
507
  /**
507
- * dsh-vscode-mode client — Monaco 语法分色主题(rich token 配色)。
508
- * 编辑器原先硬编码 'vs'(内置基础主题),token 分色层次少;
509
- * 这里定义 edrv-dark / edrv-light 两套完整 token 配色(对齐 VSCode Dark+ 语义分层),
510
- * 并随 DSH 明暗主题自动切换(跟随文档根 data 主题属性 / prefers-color-scheme)。
511
- * 作者 ddj 2026-08-28
508
+ * dsh-vscode-mode client — Monaco 主题:官方令牌跟随 + 现役双套回落。
509
+ * 优先级:官方代码/UI 令牌(--shiki-* / --dsw-alias-*,DSH 0.1.5+ 主题体系,
510
+ * 含第三方皮肤)→ edrv-dark / edrv-light 两套内置配色(旧版 DSH 或令牌缺失)。
511
+ * 明暗判定:body[data-ds-dark-theme](官方)→ data-theme(旧皮肤)→ prefers-color-scheme
512
+ * 作者 ddj 2026-08-28 / 2026-09-10
512
513
  */
513
514
  const EDRV_DARK = "edrv-dark";
514
515
  const EDRV_LIGHT = "edrv-light";
@@ -985,12 +986,14 @@ window.__ModuleLoader__.load({
985
986
  } catch (error) {}
986
987
  }
987
988
  /**
988
- * 探测当前 DSH 明暗(文档根 data 主题属性 → prefers-color-scheme → 暗)。
989
- * @author ddj 2026年08月28号
989
+ * 探测当前 DSH 明暗(官方 data-ds-dark-theme 旧皮肤 data-theme → prefers-color-scheme → 暗)。
990
+ * @author ddj 2026年08月28号 / 2026年09月10号
990
991
  * @returns 'dark' | 'light'
991
992
  */
992
993
  function detectColorScheme() {
993
994
  try {
995
+ const official = document.body?.getAttribute?.("data-ds-dark-theme");
996
+ if (official !== null && official !== void 0 && official !== "false") return "dark";
994
997
  const attr = document.documentElement?.getAttribute?.("data-theme") ?? document.body?.getAttribute?.("data-theme");
995
998
  const value = String(attr ?? "").toLowerCase();
996
999
  if (value.includes("light") || value.includes("catppuccin-latte")) return "light";
@@ -1018,6 +1021,337 @@ window.__ModuleLoader__.load({
1018
1021
  monaco.editor.setTheme(themeNameOf());
1019
1022
  } catch (error) {}
1020
1023
  }
1024
+ /** 官方代码配色令牌 → Monaco 规则 token 前缀(粗粒度;未覆盖的规则保留现役语义分层)。 */
1025
+ const RULE_TOKEN_MAP = [
1026
+ ["--shiki-token-comment", ["comment"]],
1027
+ ["--shiki-token-keyword", ["keyword"]],
1028
+ ["--shiki-token-string", ["string"]],
1029
+ ["--shiki-token-string-expression", ["string.escape"]],
1030
+ ["--shiki-token-constant", ["number", "constant"]],
1031
+ ["--shiki-token-function", [
1032
+ "function",
1033
+ "method",
1034
+ "member"
1035
+ ]],
1036
+ ["--shiki-token-parameter", ["parameter", "variable.parameter"]],
1037
+ ["--shiki-token-punctuation", [
1038
+ "delimiter",
1039
+ "operator",
1040
+ "punctuation"
1041
+ ]],
1042
+ ["--shiki-token-link", ["annotation", "metatag"]]
1043
+ ];
1044
+ /**
1045
+ * 官方 UI 令牌 → Monaco 颜色键(每键给候选令牌,按序取首个可解析值)。
1046
+ * 依据运行态实测:--dsw-alias-* 定义在 body 上;--shiki-background/-foreground 未定义,
1047
+ * 故代码面底色用 markdown-code-block 近似;selection 不覆盖(沿用现役可见选框)。
1048
+ */
1049
+ const COLOR_TOKEN_MAP = [
1050
+ [["--dsw-alias-markdown-code-block", "--dsw-alias-bg-layer-2"], [
1051
+ "editor.background",
1052
+ "editorGutter.background",
1053
+ "minimap.background"
1054
+ ]],
1055
+ [["--dsw-alias-label-primary", "--shiki-foreground"], ["editor.foreground"]],
1056
+ [["--dsw-alias-bg-layer-1", "--dsw-alias-bg-layer-3"], ["editorWidget.background", "editorHoverWidget.background"]],
1057
+ [["--dsw-alias-label-tertiary"], ["editorLineNumber.foreground"]],
1058
+ [["--dsw-alias-label-secondary"], ["editorLineNumber.activeForeground"]],
1059
+ [["--dsw-alias-interactive-bg-hover"], ["editor.lineHighlightBackground", "editor.inactiveSelectionBackground"]]
1060
+ ];
1061
+ /** 已应用的官方主题序号(模块级计数,保证主题 id 每次唯一)。 */
1062
+ let officialSeq = 0;
1063
+ /**
1064
+ * 读官方 CSS 变量(先 body 后文档根;未定义/空值/未解析 var() 返回 undefined)。
1065
+ * 依据运行态实测:DSH 的 --dsw-alias-* 定义在 body 上,仅 --shiki-token-* 在根。
1066
+ * @author ddj 2026年09月10号
1067
+ * @param name CSS 变量名(含 -- 前缀)
1068
+ * @returns 计算样式值,或 undefined
1069
+ */
1070
+ function readCssVar(name) {
1071
+ try {
1072
+ if (typeof window?.getComputedStyle !== "function") return void 0;
1073
+ const hosts = [document?.body, document?.documentElement];
1074
+ for (const host of hosts) {
1075
+ if (!host) continue;
1076
+ const raw = window.getComputedStyle(host).getPropertyValue(name);
1077
+ const value = String(raw ?? "").trim();
1078
+ if (value && !value.startsWith("var(")) return value;
1079
+ }
1080
+ return;
1081
+ } catch (error) {
1082
+ return;
1083
+ }
1084
+ }
1085
+ /**
1086
+ * 数值 → 两位十六进制(0-255 夹取)。
1087
+ * @author ddj 2026年09月10号
1088
+ * @param value 通道值
1089
+ * @returns 两位小写十六进制
1090
+ */
1091
+ function hex2(value) {
1092
+ const text = Math.max(0, Math.min(255, Math.round(Number(value) || 0))).toString(16);
1093
+ return text.length === 1 ? "0" + text : text;
1094
+ }
1095
+ /**
1096
+ * CSS 颜色归一为 Monaco 可用值(#rgb/#rrggbb/#rrggbbaa 原样,rgb()/hsl() 转 hex,其余 undefined)。
1097
+ * @author ddj 2026年09月10号
1098
+ * @param value CSS 计算样式颜色值
1099
+ * @returns Monaco 颜色字符串,或 undefined(不可识别)
1100
+ */
1101
+ function toMonacoColor(value) {
1102
+ const text = String(value ?? "").trim().toLowerCase();
1103
+ if (!text || text.startsWith("var(")) return void 0;
1104
+ if (/^#[0-9a-f]{3}$/.test(text)) return "#" + text.slice(1).split("").map((c) => c + c).join("");
1105
+ if (/^#[0-9a-f]{6}$/.test(text) || /^#[0-9a-f]{8}$/.test(text)) return text;
1106
+ return channelColor(text);
1107
+ }
1108
+ /**
1109
+ * rgb()/rgba()/hsl()/hsla() → Monaco 颜色(兼容逗号与空格/斜杠两种参数语法)。
1110
+ * @author ddj 2026年09月10号
1111
+ * @param text 小写颜色文本
1112
+ * @returns Monaco 颜色,或 undefined(不可识别)
1113
+ */
1114
+ function channelColor(text) {
1115
+ const body = /^(?:rgba?|hsla?)\(([^)]+)\)$/.exec(text)?.[1];
1116
+ if (!body) return void 0;
1117
+ const parts = body.split(/[\s,/]+/).filter(Boolean);
1118
+ if (parts.length < 3) return void 0;
1119
+ let channels;
1120
+ if (text.startsWith("hsl")) {
1121
+ const h = Number(parts[0]);
1122
+ const s = percentOf(parts[1]);
1123
+ const l = percentOf(parts[2]);
1124
+ if (![
1125
+ h,
1126
+ s,
1127
+ l
1128
+ ].every(Number.isFinite)) return void 0;
1129
+ channels = hslToRgb(h, s, l);
1130
+ } else channels = parts.slice(0, 3).map(Number);
1131
+ if (channels.some((n) => !Number.isFinite(n))) return void 0;
1132
+ const alpha = parts.length > 3 ? alphaOf(parts[3]) : 1;
1133
+ const tail = Number.isFinite(alpha) && alpha < 1 ? hex2(alpha * 255) : "";
1134
+ return "#" + channels.map(hex2).join("") + tail;
1135
+ }
1136
+ /**
1137
+ * 百分数文本 → 数值('5%' → 5,'0.5' → 0.5)。
1138
+ * @author ddj 2026年09月10号
1139
+ * @param value 参数文本
1140
+ * @returns 数值(非数字为 NaN)
1141
+ */
1142
+ function percentOf(value) {
1143
+ const text = String(value ?? "");
1144
+ return text.endsWith("%") ? Number(text.slice(0, -1)) : Number(text);
1145
+ }
1146
+ /**
1147
+ * alpha 参数归一('5%' → 0.05,'0.5' → 0.5)。
1148
+ * @author ddj 2026年09月10号
1149
+ * @param value 参数文本
1150
+ * @returns 0-1 的 alpha(非数字为 NaN)
1151
+ */
1152
+ function alphaOf(value) {
1153
+ const text = String(value ?? "");
1154
+ return text.endsWith("%") ? Number(text.slice(0, -1)) / 100 : Number(text);
1155
+ }
1156
+ /**
1157
+ * HSL → RGB 通道(h 度、s/l 为 0-100 百分数)。
1158
+ * @author ddj 2026年09月10号
1159
+ * @param h 色相(度)
1160
+ * @param s 饱和度(0-100)
1161
+ * @param l 亮度(0-100)
1162
+ * @returns [r, g, b](0-255)
1163
+ */
1164
+ function hslToRgb(h, s, l) {
1165
+ const hue = (h % 360 + 360) % 360;
1166
+ const sat = Math.max(0, Math.min(100, s)) / 100;
1167
+ const lum = Math.max(0, Math.min(100, l)) / 100;
1168
+ const c = (1 - Math.abs(2 * lum - 1)) * sat;
1169
+ const x = c * (1 - Math.abs(hue / 60 % 2 - 1));
1170
+ const m = lum - c / 2;
1171
+ return [
1172
+ [
1173
+ c,
1174
+ x,
1175
+ 0
1176
+ ],
1177
+ [
1178
+ x,
1179
+ c,
1180
+ 0
1181
+ ],
1182
+ [
1183
+ 0,
1184
+ c,
1185
+ x
1186
+ ],
1187
+ [
1188
+ 0,
1189
+ x,
1190
+ c
1191
+ ],
1192
+ [
1193
+ x,
1194
+ 0,
1195
+ c
1196
+ ],
1197
+ [
1198
+ c,
1199
+ 0,
1200
+ x
1201
+ ]
1202
+ ][Math.min(5, Math.floor(hue / 60))].map((v) => (v + m) * 255);
1203
+ }
1204
+ /**
1205
+ * 官方令牌 → Monaco 颜色键覆盖表(候选令牌按序取首个可解析值;全缺则不写入,保持现役回落)。
1206
+ * @author ddj 2026年09月10号
1207
+ * @returns 颜色键 → 颜色值
1208
+ */
1209
+ function tokenColors() {
1210
+ const out = {};
1211
+ for (const entry of COLOR_TOKEN_MAP) {
1212
+ const color = firstColor(entry[0]);
1213
+ if (color === void 0) continue;
1214
+ for (const key of entry[1]) out[key] = color;
1215
+ }
1216
+ return out;
1217
+ }
1218
+ /**
1219
+ * 候选令牌中首个可解析为 Monaco 颜色的值。
1220
+ * @author ddj 2026年09月10号
1221
+ * @param names CSS 变量名候选(按优先级)
1222
+ * @returns Monaco 颜色,或 undefined(全部缺失/不可解析)
1223
+ */
1224
+ function firstColor(names) {
1225
+ for (const name of names) {
1226
+ const color = toMonacoColor(readCssVar(name));
1227
+ if (color !== void 0) return color;
1228
+ }
1229
+ }
1230
+ /**
1231
+ * 官方令牌 → Monaco 规则前缀覆盖表(值去掉 # 前缀,Monaco rules 约定)。
1232
+ * @author ddj 2026年09月10号
1233
+ * @returns token 前缀 → 十六进制色(无 #)
1234
+ */
1235
+ function tokenRules() {
1236
+ const out = {};
1237
+ for (const entry of RULE_TOKEN_MAP) {
1238
+ const color = toMonacoColor(readCssVar(entry[0]));
1239
+ if (color === void 0) continue;
1240
+ for (const prefix of entry[1]) out[prefix] = color.replace("#", "");
1241
+ }
1242
+ return out;
1243
+ }
1244
+ /**
1245
+ * 现役规则叠加令牌覆盖(前缀命中即换色,未命中保持语义分层)。
1246
+ * @author ddj 2026年09月10号
1247
+ * @param baseRules 现役规则表(edrv-dark / edrv-light)
1248
+ * @param overrides token 前缀 → 颜色
1249
+ * @returns 覆盖后的规则表(无覆盖时原样返回)
1250
+ */
1251
+ function withOverrides(baseRules, overrides) {
1252
+ const prefixes = Object.keys(overrides);
1253
+ if (!prefixes.length) return baseRules;
1254
+ return baseRules.map((rule) => {
1255
+ const hit = prefixes.find((p) => rule.token === p || rule.token.startsWith(p + "."));
1256
+ return hit === void 0 ? rule : Object.assign({}, rule, { foreground: overrides[hit] });
1257
+ });
1258
+ }
1259
+ /**
1260
+ * 基础规则(token 为空串)前景色跟随官方 editor.foreground。
1261
+ * Monaco 的 '' 规则匹配所有未被更具体规则命中的 token,不改它则内置 #1e1e1e 会盖住
1262
+ * editor.foreground 令牌色(实测 .mtk1 仍为内置值的原因)。
1263
+ * @author ddj 2026年09月10号
1264
+ * @param rules 现役规则表
1265
+ * @param color 已解析的 editor.foreground(含 #,缺省则不覆盖)
1266
+ * @returns 基础规则换色后的规则表
1267
+ */
1268
+ function withBaseForeground(rules, color) {
1269
+ if (!color) return rules;
1270
+ const foreground = String(color).replace("#", "");
1271
+ return rules.map((rule) => rule.token === "" ? Object.assign({}, rule, { foreground }) : rule);
1272
+ }
1273
+ /**
1274
+ * 构建跟随官方的 Monaco 主题(令牌全缺时 hasTokens=false,调用方回落现役双套)。
1275
+ * @author ddj 2026年09月10号
1276
+ * @param scheme 明暗('light' 之外一律按暗色)
1277
+ * @returns 主题定义(base/rules/colors/hasTokens)
1278
+ */
1279
+ function officialThemeOf(scheme) {
1280
+ const dark = scheme !== "light";
1281
+ const colors = tokenColors();
1282
+ const rules = tokenRules();
1283
+ const layered = withOverrides(dark ? DARK_RULES : LIGHT_RULES, rules);
1284
+ return {
1285
+ base: dark ? "vs-dark" : "vs",
1286
+ rules: withBaseForeground(layered, colors["editor.foreground"]),
1287
+ colors: Object.assign({}, dark ? DARK_COLORS : LIGHT_COLORS, colors),
1288
+ hasTokens: Object.keys(colors).length > 0 || Object.keys(rules).length > 0
1289
+ };
1290
+ }
1291
+ /**
1292
+ * 应用跟随官方的主题;令牌读不到或定义失败时回落现役双套。
1293
+ * @author ddj 2026年09月10号
1294
+ * @param monaco Monaco 实例
1295
+ * @returns 实际应用的 Monaco 主题 id
1296
+ */
1297
+ function applyOfficial(monaco) {
1298
+ if (!monaco?.editor?.setTheme || !monaco?.editor?.defineTheme) return themeNameOf();
1299
+ const theme = officialThemeOf(detectColorScheme());
1300
+ if (!theme.hasTokens) {
1301
+ applyTheme(monaco);
1302
+ return themeNameOf();
1303
+ }
1304
+ officialSeq += 1;
1305
+ const id = "edrv-official-" + officialSeq;
1306
+ try {
1307
+ monaco.editor.defineTheme(id, {
1308
+ base: theme.base,
1309
+ inherit: true,
1310
+ rules: theme.rules,
1311
+ colors: theme.colors
1312
+ });
1313
+ monaco.editor.setTheme(id);
1314
+ return id;
1315
+ } catch (error) {
1316
+ applyTheme(monaco);
1317
+ return themeNameOf();
1318
+ }
1319
+ }
1320
+ /**
1321
+ * 观察官方明暗标记变化(body / 根节点的 data-ds-dark-theme 与 data-theme)。
1322
+ * @author ddj 2026年09月10号
1323
+ * @param onChange 标记变化回调
1324
+ * @returns 停止观察函数(非浏览器环境返回空函数)
1325
+ */
1326
+ function observeScheme(onChange) {
1327
+ try {
1328
+ if (typeof MutationObserver !== "function" || !document?.body) return () => {};
1329
+ const observer = new MutationObserver(() => onChange());
1330
+ const filter = ["data-ds-dark-theme", "data-theme"];
1331
+ observer.observe(document.body, {
1332
+ attributes: true,
1333
+ attributeFilter: filter
1334
+ });
1335
+ if (document.documentElement) observer.observe(document.documentElement, {
1336
+ attributes: true,
1337
+ attributeFilter: filter
1338
+ });
1339
+ return () => observer.disconnect();
1340
+ } catch (error) {
1341
+ return () => {};
1342
+ }
1343
+ }
1344
+ /**
1345
+ * 官方主题快照 → 明暗(ThemeRuntime.getTheme() 快照;字段缺失/未知返回 undefined)。
1346
+ * @author ddj 2026年09月10号
1347
+ * @param snapshot 官方主题快照
1348
+ * @returns 'light' | 'dark' | undefined
1349
+ */
1350
+ function schemeOfSnapshot(snapshot) {
1351
+ const value = snapshot ?? {};
1352
+ const scheme = value.active?.colorScheme ?? value.colorScheme;
1353
+ return scheme === "light" || scheme === "dark" ? scheme : void 0;
1354
+ }
1021
1355
  //#endregion
1022
1356
  //#region src/client/monaco/loader.ts
1023
1357
  /**
@@ -1185,7 +1519,7 @@ window.__ModuleLoader__.load({
1185
1519
  publishStage("ready", MONACO_STAGES.ready.progress, MONACO_STAGES.ready.message);
1186
1520
  try {
1187
1521
  registerThemes(window.monaco);
1188
- applyTheme(window.monaco);
1522
+ applyOfficial(window.monaco);
1189
1523
  } catch (error) {}
1190
1524
  resolve(window.monaco);
1191
1525
  }, (err) => fail(/* @__PURE__ */ new Error("Monaco 模块加载失败:" + String(err))));
@@ -2153,7 +2487,9 @@ window.__ModuleLoader__.load({
2153
2487
  * 纯数据模块:host(settings schema 默认值)与 client(执行匹配/设置页)共用。
2154
2488
  * 键位格式:修饰符 + 主键,`+` 连接,如 `Ctrl+Shift+F`;空串 = 未绑定;
2155
2489
  * `|` 连接多个候选(任一命中即触发),如 `Alt+ArrowLeft|Ctrl+Alt+-`。
2156
- * 作者 ddj 2026年08月26号
2490
+ * 约束:本模块被 host 与 client 两半共用,**禁止 import client 侧模块**(React/浏览器 API)。
2491
+ * 与 client/ui/commandCatalog 的一致性由 tests/commands.test.ts 断言兜底。
2492
+ * 作者 ddj 2026年08月26号 / 2026年09月10号
2157
2493
  */
2158
2494
  /** 命令 id → 默认键位(可为多候选)。命令目录以此为准,新增命令只需加一项。 */
2159
2495
  const KEYBINDING_DEFAULTS = {
@@ -2162,7 +2498,12 @@ window.__ModuleLoader__.load({
2162
2498
  "edrv.toggleSidebar": "Ctrl+B",
2163
2499
  "edrv.searchInFiles": "Ctrl+Shift+F",
2164
2500
  "edrv.navigateBack": "Alt+ArrowLeft|Ctrl+Alt+-",
2165
- "edrv.navigateForward": "Alt+ArrowRight|Ctrl+Shift+-"
2501
+ "edrv.navigateForward": "Alt+ArrowRight|Ctrl+Shift+-",
2502
+ "edrv.nextTab": "Ctrl+Alt+ArrowRight|Ctrl+PageDown",
2503
+ "edrv.prevTab": "Ctrl+Alt+ArrowLeft|Ctrl+PageUp",
2504
+ "edrv.showCommands": "Ctrl+Shift+P|F1",
2505
+ "edrv.nextEditorRow": "Ctrl+Alt+ArrowDown",
2506
+ "edrv.prevEditorRow": "Ctrl+Alt+ArrowUp"
2166
2507
  };
2167
2508
  /**
2168
2509
  * 返回默认键位的独立副本(调用方修改不污染目录)。
@@ -2186,41 +2527,261 @@ window.__ModuleLoader__.load({
2186
2527
  return out;
2187
2528
  }
2188
2529
  //#endregion
2189
- //#region src/client/keybindings.ts
2530
+ //#region src/client/editorModelState.ts
2190
2531
  /**
2191
- * dsh-vscode-mode client — 快捷键配置模块(解析/匹配/状态同步)。
2192
- * 纯逻辑(parseChord/parseChords/formatChord/matchEvent/chordFromEvent/normalizeKey)不依赖 DOM,可单测;
2193
- * 模块状态由 settings 订阅驱动(client/index.ts 调 keybindingsApply)。
2194
- * 键位语义:Ctrl 与 Cmd 互认(延续现有 Ctrl+P/Ctrl+B 捕获行为)。
2195
- * 作者 ddj 2026年08月26号
2532
+ * 当前文档是否已有 Monaco 活动模型(编辑器打开着文件而非空态)。
2533
+ * @author ddj 2026年09月10号
2534
+ * @returns 是否存在活动模型
2196
2535
  */
2197
- /** 命令目录(设置页展示标签;执行按目录序先匹配先执行,冲突键位确定性)。 */
2198
- const COMMANDS = [
2536
+ function hasEditorModel() {
2537
+ if (typeof document === "undefined") return false;
2538
+ return document.querySelector(".monaco-editor textarea.inputarea") !== null;
2539
+ }
2540
+ //#endregion
2541
+ //#region src/client/ui/commandCatalog.ts
2542
+ /**
2543
+ * dsh-vscode-mode client — 编辑器指令目录(纯元数据)。
2544
+ * 「一条命令 = 一条注册数据」:命令栏、快捷键设置页、快捷键监听与 Monaco 右键菜单
2545
+ * 全部从本表读取;新增一条能力只需在 EDITOR_COMMANDS 追加一项(可选 keybinding)。
2546
+ * run 只派发 `edrv.command.*` 窗口事件,不直接触碰 React/Monaco(`edrv.command.` 前缀
2547
+ * 与既有 `edrv:` 刷新/主题事件分属不同命名空间,互不干扰)。
2548
+ * 作者 ddj 2026年09月10号
2549
+ */
2550
+ /**
2551
+ * 派发编辑器命令事件(`edrv.command.<action>`)。
2552
+ * 无 window 的运行环境(纯 Node 单测)静默跳过,命令本身不因此失败。
2553
+ * @author ddj 2026年09月10号
2554
+ * @param action 动作名(不含前缀)
2555
+ */
2556
+ function emit(action) {
2557
+ if (typeof window === "undefined") return;
2558
+ window.dispatchEvent(new CustomEvent("edrv.command." + action));
2559
+ }
2560
+ /** 需要活动编辑器模型才可用的命令(命令栏隐藏并拒绝执行)。 */
2561
+ function needsModel() {
2562
+ return hasEditorModel();
2563
+ }
2564
+ /** 面板区显隐切换始终可用(未挂载编辑器时 run 为空操作)。 */
2565
+ function alwaysAvailable() {
2566
+ return true;
2567
+ }
2568
+ /**
2569
+ * 光标整行下移(编辑行导航)。
2570
+ * @author ddj 2026年09月10号
2571
+ * @returns 命令定义
2572
+ */
2573
+ function nextEditorRowDef() {
2574
+ return {
2575
+ id: "edrv.nextEditorRow",
2576
+ label: "下一编辑行(光标整行下移)",
2577
+ category: "导航",
2578
+ order: 50,
2579
+ keybinding: "Ctrl+Alt+ArrowDown",
2580
+ available: needsModel,
2581
+ run: () => emit("nextEditorRow")
2582
+ };
2583
+ }
2584
+ /**
2585
+ * 光标整行上移(编辑行导航)。
2586
+ * @author ddj 2026年09月10号
2587
+ * @returns 命令定义
2588
+ */
2589
+ function prevEditorRowDef() {
2590
+ return {
2591
+ id: "edrv.prevEditorRow",
2592
+ label: "上一编辑行(光标整行上移)",
2593
+ category: "导航",
2594
+ order: 60,
2595
+ keybinding: "Ctrl+Alt+ArrowUp",
2596
+ available: needsModel,
2597
+ run: () => emit("prevEditorRow")
2598
+ };
2599
+ }
2600
+ /**
2601
+ * 编辑器内置指令目录(顺序 = 快捷键设置页展示顺序)。
2602
+ * 前置 8 条的键位由 EditorView / QuickOpen 自行 capture 监听(历史实现),
2603
+ * 故不进 BRIDGE_COMMANDS,避免同一按键双执行。
2604
+ * @author ddj 2026年09月10号
2605
+ */
2606
+ const EDITOR_COMMANDS = [
2199
2607
  {
2200
2608
  id: "edrv.save",
2201
- label: "保存文件"
2609
+ label: "保存文件",
2610
+ category: "文件",
2611
+ order: 10,
2612
+ keybinding: "Ctrl+S",
2613
+ available: needsModel,
2614
+ run: () => emit("save")
2202
2615
  },
2203
2616
  {
2204
2617
  id: "edrv.quickOpen",
2205
- label: "快速打开文件"
2618
+ label: "快速打开文件",
2619
+ category: "文件",
2620
+ order: 20,
2621
+ keybinding: "Ctrl+P",
2622
+ available: alwaysAvailable,
2623
+ run: () => emit("quickOpen")
2206
2624
  },
2207
2625
  {
2208
2626
  id: "edrv.toggleSidebar",
2209
- label: "切换侧边栏"
2627
+ label: "切换侧边栏",
2628
+ category: "视图",
2629
+ order: 10,
2630
+ keybinding: "Ctrl+B",
2631
+ available: alwaysAvailable,
2632
+ run: () => emit("toggleSidebar")
2210
2633
  },
2211
2634
  {
2212
2635
  id: "edrv.searchInFiles",
2213
- label: "在工作区中搜索"
2636
+ label: "在工作区中搜索",
2637
+ category: "视图",
2638
+ order: 20,
2639
+ keybinding: "Ctrl+Shift+F",
2640
+ available: alwaysAvailable,
2641
+ run: () => emit("searchInFiles")
2214
2642
  },
2215
2643
  {
2216
2644
  id: "edrv.navigateBack",
2217
- label: "后退(导航历史)"
2645
+ label: "后退(导航历史)",
2646
+ category: "导航",
2647
+ order: 10,
2648
+ keybinding: "Alt+ArrowLeft|Ctrl+Alt+-",
2649
+ available: needsModel,
2650
+ run: () => emit("navigateBack")
2218
2651
  },
2219
2652
  {
2220
2653
  id: "edrv.navigateForward",
2221
- label: "前进(导航历史)"
2654
+ label: "前进(导航历史)",
2655
+ category: "导航",
2656
+ order: 20,
2657
+ keybinding: "Alt+ArrowRight|Ctrl+Shift+-",
2658
+ available: needsModel,
2659
+ run: () => emit("navigateForward")
2660
+ },
2661
+ {
2662
+ id: "edrv.nextTab",
2663
+ label: "下一个页签",
2664
+ category: "导航",
2665
+ order: 30,
2666
+ keybinding: "Ctrl+Alt+ArrowRight|Ctrl+PageDown",
2667
+ available: needsModel,
2668
+ run: () => emit("nextTab")
2669
+ },
2670
+ {
2671
+ id: "edrv.prevTab",
2672
+ label: "上一个页签",
2673
+ category: "导航",
2674
+ order: 40,
2675
+ keybinding: "Ctrl+Alt+ArrowLeft|Ctrl+PageUp",
2676
+ available: needsModel,
2677
+ run: () => emit("prevTab")
2678
+ },
2679
+ {
2680
+ id: "edrv.goToDefinition",
2681
+ label: "转到定义",
2682
+ category: "语言智能",
2683
+ order: 10,
2684
+ available: needsModel,
2685
+ run: () => emit("goToDefinition")
2686
+ },
2687
+ {
2688
+ id: "edrv.findReferences",
2689
+ label: "查找所有引用",
2690
+ category: "语言智能",
2691
+ order: 20,
2692
+ available: needsModel,
2693
+ run: () => emit("findReferences")
2694
+ },
2695
+ {
2696
+ id: "edrv.triggerAi",
2697
+ label: "触发 AI 内联补全",
2698
+ category: "语言智能",
2699
+ order: 30,
2700
+ available: needsModel,
2701
+ run: () => emit("triggerAi")
2702
+ },
2703
+ {
2704
+ id: "edrv.openInExplorer",
2705
+ label: "在文件浏览器中打开",
2706
+ category: "文件",
2707
+ order: 30,
2708
+ available: needsModel,
2709
+ run: () => emit("openInExplorer")
2222
2710
  }
2223
2711
  ];
2712
+ /**
2713
+ * 桥接派发指令(无原生监听,键位由 commandBridge 统一 capture 处理)。
2714
+ * 新增「只填目录、不写监听」的编辑器指令一律放这里:键位、命令栏、设置页自动可用。
2715
+ * @author ddj 2026年09月10号
2716
+ */
2717
+ const BRIDGE_COMMANDS = [nextEditorRowDef(), prevEditorRowDef()];
2718
+ /**
2719
+ * 命令栏自身的命令(避免循环依赖,由 commandBridge 注入 run 后注册)。
2720
+ * @author ddj 2026年09月10号
2721
+ * @param run 打开命令栏
2722
+ * @returns 命令定义
2723
+ */
2724
+ function showCommandsDef(run) {
2725
+ return {
2726
+ id: "edrv.showCommands",
2727
+ label: "显示所有命令",
2728
+ category: "视图",
2729
+ order: 1,
2730
+ keybinding: "Ctrl+Shift+P|F1",
2731
+ available: alwaysAvailable,
2732
+ run
2733
+ };
2734
+ }
2735
+ /**
2736
+ * 需要全局键位派发的指令(桥接类 + 命令栏自身;不含 EditorView/QuickOpen 原生监听的那些)。
2737
+ * @author ddj 2026年09月10号
2738
+ * @param showCommands 命令栏命令定义
2739
+ * @returns 派发集合
2740
+ */
2741
+ function dispatchedCommands(showCommands) {
2742
+ return [...BRIDGE_COMMANDS, showCommands];
2743
+ }
2744
+ //#endregion
2745
+ //#region src/client/keybindings.ts
2746
+ /**
2747
+ * dsh-vscode-mode client — 快捷键配置模块(解析/匹配/状态同步)。
2748
+ * 纯逻辑(parseChord/parseChords/formatChord/matchEvent/chordFromEvent/normalizeKey)不依赖 DOM,可单测;
2749
+ * 模块状态由 settings 订阅驱动(client/index.ts 调 keybindingsApply)。
2750
+ * 键位语义:Ctrl 与 Cmd 互认(延续 Ctrl+P/Ctrl+B 捕获行为)。
2751
+ * 命令目录(COMMANDS)派生自指令目录 commandCatalog(指令 = 单一数据源,设置页自动跟随);
2752
+ * 另支持运行时键位表(第三方命令 register 时声明,不落设置 schema,注销即失效)。
2753
+ * 作者 ddj 2026年08月26号 / 2026年09月10号
2754
+ */
2755
+ /** 命令目录(设置页展示标签;执行按目录序先匹配先执行,冲突键位确定性)。 */
2756
+ const COMMANDS = [
2757
+ ...EDITOR_COMMANDS.map((command) => ({
2758
+ id: command.id,
2759
+ label: command.label
2760
+ })),
2761
+ {
2762
+ id: "edrv.showCommands",
2763
+ label: "显示所有命令"
2764
+ },
2765
+ ...BRIDGE_COMMANDS.map((command) => ({
2766
+ id: command.id,
2767
+ label: command.label
2768
+ }))
2769
+ ];
2770
+ /** 命令栏命令定义(键位自检与目录展示共用;run 不参与键位逻辑)。 */
2771
+ function paletteCommand() {
2772
+ return showCommandsDef(() => {});
2773
+ }
2774
+ /**
2775
+ * 目录与默认键位表一致性自检(仅告警不中断):新指令漏写共享表时第一时间可见。
2776
+ * @author ddj 2026年09月10号
2777
+ */
2778
+ function checkDefaultsDrift() {
2779
+ for (const command of [...EDITOR_COMMANDS, paletteCommand()]) {
2780
+ if (!command.keybinding) continue;
2781
+ if (KEYBINDING_DEFAULTS[command.id] === command.keybinding) continue;
2782
+ log.warn("指令默认键位与共享表不一致:" + command.id + " 目录=" + command.keybinding + " 共享表=" + String(KEYBINDING_DEFAULTS[command.id]));
2783
+ }
2784
+ }
2224
2785
  const MODIFIERS = {
2225
2786
  ctrl: "ctrl",
2226
2787
  cmd: "meta",
@@ -2229,8 +2790,9 @@ window.__ModuleLoader__.load({
2229
2790
  alt: "alt"
2230
2791
  };
2231
2792
  let current = { ...KEYBINDING_DEFAULTS };
2232
- let parsed = {};
2233
- const listeners$1 = /* @__PURE__ */ new Set();
2793
+ const runtime = /* @__PURE__ */ new Map();
2794
+ const listeners$2 = /* @__PURE__ */ new Set();
2795
+ checkDefaultsDrift();
2234
2796
  /**
2235
2797
  * 应用设置快照(与默认值合并;未知 id 丢弃;空对象 = 全部默认)。
2236
2798
  * 每个命令可含多候选键位(`|` 分隔),任一命中即触发。
@@ -2242,9 +2804,7 @@ window.__ModuleLoader__.load({
2242
2804
  ...KEYBINDING_DEFAULTS,
2243
2805
  ...normalizeKeybindings(raw)
2244
2806
  };
2245
- parsed = {};
2246
- for (const id of Object.keys(current)) parsed[id] = parseChords(current[id]);
2247
- for (const listener of listeners$1) try {
2807
+ for (const listener of listeners$2) try {
2248
2808
  listener();
2249
2809
  } catch {}
2250
2810
  }
@@ -2255,27 +2815,34 @@ window.__ModuleLoader__.load({
2255
2815
  * @returns 取消订阅函数
2256
2816
  */
2257
2817
  function subscribeKeybindings(listener) {
2258
- listeners$1.add(listener);
2259
- return () => listeners$1.delete(listener);
2818
+ listeners$2.add(listener);
2819
+ return () => listeners$2.delete(listener);
2260
2820
  }
2261
2821
  /**
2262
- * 当前键位弦(未绑定/空 → null)。
2263
- * @author ddj 2026年08月26号
2822
+ * 当前命令的键位弦(运行时键位优先;未绑定/空 → null)。
2823
+ * @author ddj 2026年08月26号 / 2026年09月10号
2264
2824
  * @param id 命令 id
2265
2825
  * @returns 键位弦或 null
2266
2826
  */
2267
2827
  function chordOf(id) {
2828
+ if (runtime.has(id)) {
2829
+ const chords = runtime.get(id) ?? [];
2830
+ return chords.length ? chords.map(formatChord).join("|") : null;
2831
+ }
2268
2832
  const chord = current[id];
2269
2833
  return typeof chord === "string" && chord.trim() !== "" ? chord : null;
2270
2834
  }
2271
2835
  /**
2272
2836
  * 当前命令的解析键位集合(未绑定/非法 → 空数组;含多候选)。
2273
- * @author ddj 2026年08月26号
2837
+ * @author ddj 2026年08月26号 / 2026年09月10号
2274
2838
  * @param id 命令 id
2275
2839
  * @returns 解析键位数组(可能为空)
2276
2840
  */
2277
2841
  function bindingsOf(id) {
2278
- return parsed[id] ?? [];
2842
+ const override = runtime.get(id);
2843
+ if (override) return override;
2844
+ const chord = current[id];
2845
+ return typeof chord === "string" ? parseChords(chord) : [];
2279
2846
  }
2280
2847
  /**
2281
2848
  * 主键规范化:小写字母大写、空格归一为 Space,其余原样(与事件 e.key 对照)。
@@ -2449,19 +3016,26 @@ window.__ModuleLoader__.load({
2449
3016
  inputRef.current?.blur?.();
2450
3017
  };
2451
3018
  react.default.useEffect(() => {
3019
+ const openBox = () => {
3020
+ inputRef.current?.focus?.();
3021
+ setOpen(true);
3022
+ };
2452
3023
  const onKey = (e) => {
2453
3024
  if (matchEvent(e, bindingsOf("edrv.quickOpen"))) {
2454
3025
  e.preventDefault();
2455
3026
  e.stopPropagation();
2456
- inputRef.current?.focus?.();
2457
- setOpen(true);
3027
+ openBox();
2458
3028
  } else if (e.key === "Escape") {
2459
3029
  setOpen(false);
2460
3030
  inputRef.current?.blur?.();
2461
3031
  }
2462
3032
  };
2463
3033
  window.addEventListener("keydown", onKey, true);
2464
- return () => window.removeEventListener("keydown", onKey, true);
3034
+ window.addEventListener("edrv.command.quickOpen", openBox);
3035
+ return () => {
3036
+ window.removeEventListener("keydown", onKey, true);
3037
+ window.removeEventListener("edrv.command.quickOpen", openBox);
3038
+ };
2465
3039
  }, []);
2466
3040
  const dirText = (p) => {
2467
3041
  const base = String(p).split(/[\\/]/).pop() || String(p);
@@ -2494,6 +3068,460 @@ window.__ModuleLoader__.load({
2494
3068
  }), pop);
2495
3069
  }
2496
3070
  //#endregion
3071
+ //#region src/client/commandGlobals.ts
3072
+ /**
3073
+ * dsh-vscode-mode client — 指令系统的全局挂点名约定。
3074
+ * 单独成模块:装配层(client/index.ts)与读取方(命令栏/第三方)都要用,
3075
+ * 放这里可避免 CommandPalette ↔ index 的循环依赖。
3076
+ *
3077
+ * ⚠️ 必须挂在 window 自身(双下划线 + edrv 前缀,与既有 __edrvExtPoll 同风格)。
3078
+ * 旧实现写 window.dsh.edrvCommands——DSH 从不创建 window.dsh 命名空间(全仓库无赋值),
3079
+ * 该路径恒为死代码并导致命令栏读到空表;不要再改回气泡式挂点。
3080
+ * 作者 ddj 2026年09月10号
3081
+ */
3082
+ /** 指令注册表的全局挂点名:window[REGISTRY_GLOBAL](第三方注册与调试读取;命令栏首选模块引用)。 */
3083
+ const REGISTRY_GLOBAL = "__edrvCommands__";
3084
+ //#endregion
3085
+ //#region src/client/commandSearch.ts
3086
+ /** 排序用基础序(未声明 order 的命令排在已声明之后)。 */
3087
+ const DEFAULT_ORDER = 100;
3088
+ /** 命中字段权重(数值越小越优先)。 */
3089
+ const FIELD_WEIGHT = {
3090
+ label: 0,
3091
+ id: 1,
3092
+ category: 2
3093
+ };
3094
+ /** 小写化(非字符串按空串处理,容错外部脏数据)。 */
3095
+ function lower(text) {
3096
+ return typeof text === "string" ? text.toLocaleLowerCase("en-US") : "";
3097
+ }
3098
+ /** 建立一条命令的索引文本。 */
3099
+ function indexOf(command) {
3100
+ return {
3101
+ label: lower(command.label),
3102
+ id: lower(command.id),
3103
+ category: lower(command.category)
3104
+ };
3105
+ }
3106
+ /**
3107
+ * 命令是否命中全部 token;命中时返回最优(最小)字段权重。
3108
+ * @author ddj 2026年09月10号
3109
+ * @param fields 命令索引文本
3110
+ * @param tokens 小写查询 token
3111
+ * @returns 字段权重;未命中返回 null
3112
+ */
3113
+ function hitWeight(fields, tokens) {
3114
+ let best = null;
3115
+ for (const token of tokens) {
3116
+ let tokenWeight = null;
3117
+ for (const field of [
3118
+ "label",
3119
+ "id",
3120
+ "category"
3121
+ ]) {
3122
+ if (!fields[field].includes(token)) continue;
3123
+ const weight = FIELD_WEIGHT[field];
3124
+ if (tokenWeight === null || weight < tokenWeight) tokenWeight = weight;
3125
+ if (weight === 0) break;
3126
+ }
3127
+ if (tokenWeight === null) return null;
3128
+ if (best === null || tokenWeight < best) best = tokenWeight;
3129
+ }
3130
+ return best;
3131
+ }
3132
+ /** 目录序(order 缺省 100;非有限值同样按 100)。 */
3133
+ function orderOf$1(command) {
3134
+ const order = command.order;
3135
+ return typeof order === "number" && Number.isFinite(order) ? order : DEFAULT_ORDER;
3136
+ }
3137
+ /**
3138
+ * 过滤并按相关度排序命令(空查询返回全部,仅按目录序排序)。
3139
+ * @author ddj 2026年09月10号
3140
+ * @param commands 候选命令(调用方通常已按可用性过滤)
3141
+ * @param query 用户输入
3142
+ * @returns 命中命令数组
3143
+ */
3144
+ function filterCommands(commands, query) {
3145
+ const tokens = lower(query).split(/\s+/).filter(Boolean);
3146
+ const hits = [];
3147
+ for (const command of commands) {
3148
+ const weight = tokens.length ? hitWeight(indexOf(command), tokens) : 0;
3149
+ if (weight !== null) hits.push({
3150
+ command,
3151
+ weight
3152
+ });
3153
+ }
3154
+ return hits.map((hit, index) => ({
3155
+ hit,
3156
+ index
3157
+ })).sort((a, b) => a.hit.weight - b.hit.weight || orderOf$1(a.hit.command) - orderOf$1(b.hit.command) || a.index - b.index).map((entry) => entry.hit.command);
3158
+ }
3159
+ //#endregion
3160
+ //#region src/client/commandRegistry.ts
3161
+ /**
3162
+ * dsh-vscode-mode client — 指令注册表(命令栏与快捷键系统的唯一数据源)。
3163
+ * 镜像 sidebar/registry.ts 的注册表模式:register 返回注销器、list/subscribe 可订阅;
3164
+ * 额外提供 run(id):先做可用性判定再执行,运行体异常一律捕获上报,绝不让命令抛出到事件循环。
3165
+ * 重复 id 按「后注册者生效」覆盖,旧注销器带身份校验(不会误删新实例,见 releaseRegistry)。
3166
+ * 作者 ddj 2026年09月10号
3167
+ */
3168
+ const registryLog = log.child("commands");
3169
+ /** 校验命令定义(缺 id/label/run 抛 TypeError,早失败优于静默无效)。 */
3170
+ function assertCommand(command) {
3171
+ if (!command || typeof command.id !== "string" || !command.id) throw new TypeError("命令必须提供 id");
3172
+ if (typeof command.label !== "string" || !command.label) throw new TypeError("命令必须提供 label:" + command.id);
3173
+ if (typeof command.run !== "function") throw new TypeError("命令必须提供 run:" + command.id);
3174
+ }
3175
+ /** 目录序(order 缺省 100;非有限值同样按 100)。 */
3176
+ function orderOf(command) {
3177
+ return typeof command.order === "number" && Number.isFinite(command.order) ? command.order : 100;
3178
+ }
3179
+ /** 命令是否可用(available 缺省视为可用;判定异常按不可用处理)。 */
3180
+ function isAvailable$1(command) {
3181
+ if (typeof command.available !== "function") return true;
3182
+ try {
3183
+ return command.available() === true;
3184
+ } catch (error) {
3185
+ registryLog.warn("可用性判定异常(按不可用处理):" + command.id + " · " + String(error));
3186
+ return false;
3187
+ }
3188
+ }
3189
+ /**
3190
+ * 注销命令(仅当表中仍是本次注册的定义时移除,避免旧实例误删新实例)。
3191
+ * @author ddj 2026年09月10号
3192
+ * @param entries 命令表
3193
+ * @param notify 变化通知
3194
+ * @param command 注册时的定义
3195
+ * @returns 注销函数
3196
+ */
3197
+ function releaseRegistry(entries, notify, command) {
3198
+ let released = false;
3199
+ return () => {
3200
+ if (released) return;
3201
+ released = true;
3202
+ if (entries.get(command.id) !== command) return;
3203
+ entries.delete(command.id);
3204
+ notify();
3205
+ };
3206
+ }
3207
+ /**
3208
+ * 执行已注册命令(可用性判定 → 运行体 → 异常上报)。
3209
+ * @author ddj 2026年09月10号
3210
+ * @param command 命令定义
3211
+ * @returns 是否真正执行
3212
+ */
3213
+ function runCommand(command) {
3214
+ if (!isAvailable$1(command)) {
3215
+ registryLog.debug("命令不可用,已跳过:" + command.id);
3216
+ return false;
3217
+ }
3218
+ try {
3219
+ command.run();
3220
+ registryLog.debug("命令已执行:" + command.id);
3221
+ return true;
3222
+ } catch (error) {
3223
+ registryLog.error("命令执行失败:" + command.id + " · " + String(error));
3224
+ return false;
3225
+ }
3226
+ }
3227
+ /**
3228
+ * 创建指令注册表。
3229
+ * @author ddj 2026年09月10号
3230
+ * @returns 指令注册表
3231
+ */
3232
+ function createCommandRegistry() {
3233
+ const entries = /* @__PURE__ */ new Map();
3234
+ const listeners = /* @__PURE__ */ new Set();
3235
+ const notify = () => {
3236
+ for (const listener of listeners) try {
3237
+ listener();
3238
+ } catch (error) {
3239
+ registryLog.warn("注册表订阅回调异常:" + String(error));
3240
+ }
3241
+ };
3242
+ const list = () => [...entries.values()].sort((a, b) => orderOf(a) - orderOf(b));
3243
+ const available = () => list().filter(isAvailable$1);
3244
+ return {
3245
+ register(command) {
3246
+ assertCommand(command);
3247
+ if (entries.get(command.id) !== void 0) registryLog.warn("命令 id 重复注册(后者生效):" + command.id);
3248
+ entries.set(command.id, command);
3249
+ notify();
3250
+ return releaseRegistry(entries, notify, command);
3251
+ },
3252
+ has: (id) => entries.has(id),
3253
+ get: (id) => entries.get(id),
3254
+ list,
3255
+ available,
3256
+ match: (query) => filterCommands(available(), query),
3257
+ run(id) {
3258
+ const command = entries.get(id);
3259
+ if (!command) {
3260
+ registryLog.warn("命令未注册:" + id);
3261
+ return false;
3262
+ }
3263
+ return runCommand(command);
3264
+ },
3265
+ subscribe(listener) {
3266
+ listeners.add(listener);
3267
+ return () => listeners.delete(listener);
3268
+ }
3269
+ };
3270
+ }
3271
+ /** 装配期存入的指令注册表(命令栏读取候选的唯一真源)。 */
3272
+ let registryTable = null;
3273
+ /** 命令栏是否展开。 */
3274
+ let opened = false;
3275
+ /** 当前真正渲染浮层的宿主令牌(null = 无宿主)。 */
3276
+ let hostToken = null;
3277
+ /** 注入的命令执行器(commandBridge 装配时写入)。 */
3278
+ let runner = null;
3279
+ /** 打开命令栏前的焦点元素(关闭后归还焦点,键盘操作不中断)。 */
3280
+ let focusBack = null;
3281
+ const listeners$1 = /* @__PURE__ */ new Set();
3282
+ /** 通知全部订阅者(回调异常不影响其他订阅)。 */
3283
+ function notifyPalette() {
3284
+ for (const listener of listeners$1) try {
3285
+ listener();
3286
+ } catch {}
3287
+ }
3288
+ /**
3289
+ * 注入命令执行器(命令栏执行选中命令时调用)。
3290
+ * @author ddj 2026年09月10号
3291
+ * @param next 执行器(返回是否执行成功)
3292
+ */
3293
+ function setPaletteRunner(next) {
3294
+ runner = next;
3295
+ }
3296
+ /**
3297
+ * 执行命令栏选中的命令。
3298
+ * @author ddj 2026年09月10号
3299
+ * @param id 命令 id
3300
+ * @returns 是否执行成功(执行器未注入/命令不可用/抛异常均为 false)
3301
+ */
3302
+ function runPaletteCommand(id) {
3303
+ if (!runner) return false;
3304
+ return runner(id) === true;
3305
+ }
3306
+ /**
3307
+ * 存入指令注册表(commandBridge 装配期调用;命令栏据此读取候选)。
3308
+ * @author ddj 2026年09月10号
3309
+ * @param next 指令注册表(null = 卸载)
3310
+ */
3311
+ function setRegistryRef(next) {
3312
+ registryTable = next;
3313
+ }
3314
+ /**
3315
+ * 读取指令注册表(未装配返回 null;浮层据此回退全局/空表)。
3316
+ * @author ddj 2026年09月10号
3317
+ * @returns 指令注册表或 null
3318
+ */
3319
+ function registryRef() {
3320
+ return registryTable;
3321
+ }
3322
+ /**
3323
+ * 订阅命令栏开关变化。
3324
+ * @author ddj 2026年09月10号
3325
+ * @param listener 变化回调
3326
+ * @returns 取消订阅函数
3327
+ */
3328
+ function subscribePalette(listener) {
3329
+ listeners$1.add(listener);
3330
+ return () => listeners$1.delete(listener);
3331
+ }
3332
+ /**
3333
+ * 命令栏是否展开(useSyncExternalStore 快照)。
3334
+ * @author ddj 2026年09月10号
3335
+ * @returns 是否展开
3336
+ */
3337
+ function isPaletteOpen() {
3338
+ return opened;
3339
+ }
3340
+ /** 记录打开前的焦点元素(只在真正需要归还时记录)。 */
3341
+ function rememberFocus() {
3342
+ if (typeof document === "undefined") return;
3343
+ const active = document.activeElement;
3344
+ focusBack = active instanceof HTMLElement ? active : null;
3345
+ }
3346
+ /**
3347
+ * 打开命令栏(已打开时为空操作;记录当前焦点供关闭后归还)。
3348
+ * @author ddj 2026年09月10号
3349
+ * @param reason 唤起来源(键盘/命令/外部 API)
3350
+ */
3351
+ function openCommandPalette(reason = "keybinding") {
3352
+ if (opened) return;
3353
+ rememberFocus();
3354
+ opened = true;
3355
+ notifyPalette();
3356
+ }
3357
+ /**
3358
+ * 关闭命令栏并归还焦点。
3359
+ * @author ddj 2026年09月10号
3360
+ */
3361
+ function closeCommandPalette() {
3362
+ if (!opened) return;
3363
+ opened = false;
3364
+ notifyPalette();
3365
+ const target = focusBack;
3366
+ focusBack = null;
3367
+ if (!target || typeof target.focus !== "function") return;
3368
+ try {
3369
+ target.focus();
3370
+ } catch {}
3371
+ }
3372
+ /**
3373
+ * 认领命令栏宿主(返回 true 表示由本宿主渲染浮层)。
3374
+ * @author ddj 2026年09月10号
3375
+ * @returns 是否为当前宿主
3376
+ */
3377
+ function claimPaletteHost() {
3378
+ if (hostToken !== null) return false;
3379
+ hostToken = {};
3380
+ return true;
3381
+ }
3382
+ /**
3383
+ * 释放宿主认领(仅持有者可释放,卸载顺序错乱不会顶掉新宿主)。
3384
+ * @author ddj 2026年09月10号
3385
+ * @param token 认领令牌(null 表示本宿主未认领)
3386
+ */
3387
+ function releasePaletteHost(token) {
3388
+ if (token === null || hostToken !== token) return;
3389
+ hostToken = null;
3390
+ }
3391
+ //#endregion
3392
+ //#region src/client/ui/CommandPalette.ts
3393
+ /**
3394
+ * dsh-vscode-mode client — 命令栏浮层(Ctrl+Shift+P / F1)。
3395
+ * 订阅 commandPaletteStore 的开关状态;候选来自注入的指令注册表(window.dsh.edrvCommands),
3396
+ * 过滤/排序复用 commandSearch 纯函数;↑↓ 选择、Enter 执行、Esc 或点击遮罩关闭。
3397
+ * 浮层经 createPortal 渲染到 body,故不受编辑区三种形态(官方侧栏/better-sidebar/中央页签)影响;
3398
+ * 宿主单实例由 store 的 claimPaletteHost 保证(另一个宿主自动返回 null)。
3399
+ * 作者 ddj 2026年09月10号
3400
+ */
3401
+ /** 空注册表(宿主未注入时的安全降级:命令栏可开但无候选)。 */
3402
+ let fallbackRegistry = null;
3403
+ /**
3404
+ * 读取指令注册表:① 装配期存入的模块引用(首选,不依赖全局)
3405
+ * ② window[REGISTRY_GLOBAL] 镜像(第三方/调试场景)③ 空表降级(仅装配异常时)。
3406
+ * @author ddj 2026年09月10号
3407
+ * @returns 指令注册表
3408
+ */
3409
+ function useRegistry() {
3410
+ const injected = registryRef();
3411
+ if (injected) return injected;
3412
+ const mirrored = typeof window === "undefined" ? void 0 : window[REGISTRY_GLOBAL];
3413
+ if (mirrored) return mirrored;
3414
+ if (!fallbackRegistry) fallbackRegistry = createCommandRegistry();
3415
+ return fallbackRegistry;
3416
+ }
3417
+ /**
3418
+ * 组装候选行(先按可用性过滤,再按查询排序)。
3419
+ * @author ddj 2026年09月10号
3420
+ * @param registry 指令注册表
3421
+ * @param query 用户输入
3422
+ * @returns 候选行
3423
+ */
3424
+ function rowsOf(registry, query) {
3425
+ return filterCommands(registry.available(), query).map((command) => ({
3426
+ command,
3427
+ chord: chordOf(command.id)
3428
+ }));
3429
+ }
3430
+ /**
3431
+ * 命令栏浮层(未展开/非宿主时渲染 null)。
3432
+ * @author ddj 2026年09月10号
3433
+ * @returns 浮层 React 元素或 null
3434
+ */
3435
+ function CommandPalette() {
3436
+ const open = react.default.useSyncExternalStore(subscribePalette, isPaletteOpen);
3437
+ const registry = useRegistry();
3438
+ const [token] = react.default.useState(() => claimPaletteHost() ? {} : null);
3439
+ const [query, setQuery] = react.default.useState("");
3440
+ const [selected, setSelected] = react.default.useState(0);
3441
+ const [notice, setNotice] = react.default.useState("");
3442
+ const inputRef = react.default.useRef(null);
3443
+ const host = token !== null;
3444
+ react.default.useEffect(() => () => releasePaletteHost(token), [token]);
3445
+ react.default.useEffect(() => {
3446
+ if (!open) return void 0;
3447
+ setQuery("");
3448
+ setSelected(0);
3449
+ setNotice("");
3450
+ const timer = setTimeout(() => inputRef.current?.focus(), 0);
3451
+ return () => clearTimeout(timer);
3452
+ }, [open]);
3453
+ const rows = react.default.useMemo(() => open && host ? rowsOf(registry, query) : [], [
3454
+ open,
3455
+ host,
3456
+ registry,
3457
+ query
3458
+ ]);
3459
+ const active = rows.length ? Math.min(selected, rows.length - 1) : 0;
3460
+ react.default.useEffect(() => {
3461
+ if (!open) return;
3462
+ const node = document.querySelector(".edrv-palette-row.edrv-palette-sel");
3463
+ const scroll = node?.scrollIntoView;
3464
+ if (typeof scroll === "function") scroll.call(node, { block: "nearest" });
3465
+ }, [
3466
+ open,
3467
+ active,
3468
+ rows.length
3469
+ ]);
3470
+ /** 执行候选行(执行器内部会做可用性校验与异常上报)。 */
3471
+ const execute = (row) => {
3472
+ if (!row) return;
3473
+ closeCommandPalette();
3474
+ if (!runPaletteCommand(row.command.id)) setNotice("命令未执行:" + row.command.label);
3475
+ };
3476
+ const onKeyDown = (event) => {
3477
+ event.stopPropagation();
3478
+ if (event.key === "Escape") {
3479
+ event.preventDefault();
3480
+ closeCommandPalette();
3481
+ return;
3482
+ }
3483
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
3484
+ event.preventDefault();
3485
+ if (!rows.length) return;
3486
+ const step = event.key === "ArrowDown" ? 1 : rows.length - 1;
3487
+ setSelected((value) => (Math.min(value, rows.length - 1) + step) % rows.length);
3488
+ return;
3489
+ }
3490
+ if (event.key === "Enter") {
3491
+ event.preventDefault();
3492
+ execute(rows[active]);
3493
+ }
3494
+ };
3495
+ if (!open || !host || typeof document === "undefined") return null;
3496
+ const list = rows.length ? rows.map((row, index) => react.default.createElement("div", {
3497
+ key: row.command.id,
3498
+ className: "edrv-palette-row" + (index === active ? " edrv-palette-sel" : ""),
3499
+ onMouseEnter: () => setSelected(index),
3500
+ onClick: () => execute(row)
3501
+ }, react.default.createElement("span", { className: "edrv-palette-label" }, row.command.label), react.default.createElement("span", { className: "edrv-palette-cat" }, row.command.category), row.chord ? react.default.createElement("kbd", { className: "edrv-palette-key" }, row.chord) : null)) : react.default.createElement("div", { className: "edrv-palette-empty" }, "无匹配命令");
3502
+ const panel = react.default.createElement("div", {
3503
+ className: "edrv-palette",
3504
+ "data-edrv-palette": "1",
3505
+ onKeyDown
3506
+ }, react.default.createElement("input", {
3507
+ ref: inputRef,
3508
+ className: "edrv-palette-input",
3509
+ value: query,
3510
+ placeholder: "输入命令名称…(↑↓ 选择 · Enter 执行 · Esc 关闭)",
3511
+ spellCheck: false,
3512
+ onChange: (event) => {
3513
+ setQuery(event.target.value);
3514
+ setSelected(0);
3515
+ setNotice("");
3516
+ }
3517
+ }), react.default.createElement("div", { className: "edrv-palette-list" }, list), notice ? react.default.createElement("div", { className: "edrv-palette-notice" }, notice) : null);
3518
+ const overlay = react.default.createElement("div", { "data-edrv-view": "1" }, react.default.createElement("div", {
3519
+ className: "edrv-palette-mask",
3520
+ onClick: () => closeCommandPalette()
3521
+ }), panel);
3522
+ return (0, react_dom.createPortal)(overlay, document.body);
3523
+ }
3524
+ //#endregion
2497
3525
  //#region src/client/ui/shared.ts
2498
3526
  /**
2499
3527
  * dsh-vscode-mode client — UI 共用小工具(按钮样式/状态文案/等宽字体)。
@@ -2768,6 +3796,20 @@ window.__ModuleLoader__.load({
2768
3796
  /** 隐藏态拖出面板区的触发阈值(px,拖过即展开并继续实时调宽)。 */
2769
3797
  const PULL_OUT_THRESHOLD = 12;
2770
3798
  /**
3799
+ * 活动栏图标内容:面板可给官方图标组件(跟随官方主题),也可给文本/emoji(回落)。
3800
+ * @author ddj 2026年09月10号
3801
+ * @param icon 面板定义的 icon 字段(组件或文本)
3802
+ * @returns 图标元素或文本;组件渲染异常返回 null
3803
+ */
3804
+ function railIconEl(icon) {
3805
+ if (typeof icon !== "function") return icon;
3806
+ try {
3807
+ return react.default.createElement(icon, { size: 16 });
3808
+ } catch (error) {
3809
+ return null;
3810
+ }
3811
+ }
3812
+ /**
2771
3813
  * 侧边栏容器。
2772
3814
  * @param props.registry 面板注册表(list() 提供面板顺序)
2773
3815
  * @param props.ctx 面板共享上下文
@@ -2856,7 +3898,7 @@ window.__ModuleLoader__.load({
2856
3898
  onActive(p.id);
2857
3899
  if (!visible && typeof onShow === "function") onShow();
2858
3900
  }
2859
- }, react.default.createElement("span", { className: "edrv-rail-icon" }, p.icon), count > 0 ? react.default.createElement("span", { className: "edrv-rail-badge" }, String(count)) : null);
3901
+ }, react.default.createElement("span", { className: "edrv-rail-icon" }, railIconEl(p.icon)), count > 0 ? react.default.createElement("span", { className: "edrv-rail-badge" }, String(count)) : null);
2860
3902
  })), react.default.createElement("button", {
2861
3903
  className: "edrv-rail-btn",
2862
3904
  title: (visible ? "隐藏面板区" : "展开面板区") + " (Ctrl+B)",
@@ -4658,6 +5700,12 @@ window.__ModuleLoader__.load({
4658
5700
  const navCursorTimerRef = react.default.useRef(null);
4659
5701
  const navBackRef = react.default.useRef(null);
4660
5702
  const navForwardRef = react.default.useRef(null);
5703
+ const cycleTabRef = react.default.useRef(null);
5704
+ const rowNavColRef = react.default.useRef(null);
5705
+ const rowNavMoveRef = react.default.useRef(false);
5706
+ const activeRef = react.default.useRef(null);
5707
+ activeRef.current = active;
5708
+ const tabsHostRef = react.default.useRef(null);
4661
5709
  const [navTick, setNavTick] = react.default.useState(0);
4662
5710
  const hoverRegionsRef = react.default.useRef([]);
4663
5711
  const lineRegionMapRef = react.default.useRef(/* @__PURE__ */ new Map());
@@ -4854,6 +5902,22 @@ window.__ModuleLoader__.load({
4854
5902
  });
4855
5903
  };
4856
5904
  /**
5905
+ * 在已打开页签间循环切换(文件分页归编辑器自带页签栏)。
5906
+ * @author ddj 2026年09月10号
5907
+ * @param step 步进(+1 下一个 / -1 上一个)
5908
+ */
5909
+ const cycleTab = (step) => {
5910
+ if (tabs.length < 2) return;
5911
+ const idx = tabs.findIndex((t) => t.path === active);
5912
+ const next = tabs[(idx + step + tabs.length) % tabs.length];
5913
+ if (!next || next.path === active) return;
5914
+ flushSave();
5915
+ saveViewState(active);
5916
+ recordNav();
5917
+ setActive(next.path);
5918
+ };
5919
+ cycleTabRef.current = cycleTab;
5920
+ /**
4857
5921
  * 轮询去重:前后记录内容一致时返回原引用,React 跳过重渲染,
4858
5922
  * 阻断 5s 轮询 → memo 链 → diff 重渲染/日志 的空转。
4859
5923
  * @author ddj 2026年08月26号
@@ -5347,6 +6411,104 @@ window.__ModuleLoader__.load({
5347
6411
  window.addEventListener("keydown", onKey, true);
5348
6412
  return () => window.removeEventListener("keydown", onKey, true);
5349
6413
  }, []);
6414
+ react.default.useEffect(() => {
6415
+ const onKey = (e) => {
6416
+ const step = matchEvent(e, bindingsOf("edrv.nextTab")) ? 1 : matchEvent(e, bindingsOf("edrv.prevTab")) ? -1 : 0;
6417
+ if (step === 0) return;
6418
+ e.preventDefault();
6419
+ e.stopPropagation();
6420
+ if (cycleTabRef.current) cycleTabRef.current(step);
6421
+ };
6422
+ window.addEventListener("keydown", onKey, true);
6423
+ return () => window.removeEventListener("keydown", onKey, true);
6424
+ }, []);
6425
+ /**
6426
+ * 指令系统接线:命令栏/键位/第三方派发的 `edrv.command.*` 事件落到编辑器动作。
6427
+ * 全部动作经最新闭包执行(与窗口级键位监听同源);事件名逐条字面书写,
6428
+ * 便于与指令目录(ui/commandCatalog)静态对照(tests/commands.test.ts 有断言)。
6429
+ * @author ddj 2026年09月10号
6430
+ */
6431
+ react.default.useEffect(() => {
6432
+ /** 整行上下移动:Monaco 内置 cursorUp/Down 会丢列位,故按期望列自行定位(连续移动保持同列)。 */
6433
+ const moveRow = (step) => {
6434
+ const ed = editorRef.current;
6435
+ const model = ed?.getModel?.();
6436
+ const pos = ed?.getPosition?.();
6437
+ if (!ed || !model || !pos) return;
6438
+ const col = rowNavColRef.current ?? pos.column;
6439
+ const line = Math.max(1, Math.min(model.getLineCount(), pos.lineNumber + step));
6440
+ if (line === pos.lineNumber) return;
6441
+ const maxCol = model.getLineMaxColumn(line);
6442
+ rowNavColRef.current = col;
6443
+ rowNavMoveRef.current = true;
6444
+ ed.setPosition({
6445
+ lineNumber: line,
6446
+ column: Math.max(1, Math.min(col, maxCol))
6447
+ });
6448
+ ed.revealLineInCenterIfOutsideViewport?.(line);
6449
+ };
6450
+ const handlers = [
6451
+ ["edrv.command.save", () => {
6452
+ if (editorRef.current?.getModel?.()) {
6453
+ flushSave();
6454
+ doSaveRef.current?.(false);
6455
+ }
6456
+ }],
6457
+ ["edrv.command.toggleSidebar", () => setSidebarOn((v) => !v)],
6458
+ ["edrv.command.searchInFiles", () => {
6459
+ setSidebarOn(true);
6460
+ setActivePanel("search");
6461
+ setTimeout(() => window.dispatchEvent(new CustomEvent("edrv:search-focus")), 0);
6462
+ }],
6463
+ ["edrv.command.navigateBack", () => navBackRef.current?.()],
6464
+ ["edrv.command.navigateForward", () => navForwardRef.current?.()],
6465
+ ["edrv.command.nextTab", () => cycleTabRef.current?.(1)],
6466
+ ["edrv.command.prevTab", () => cycleTabRef.current?.(-1)],
6467
+ ["edrv.command.nextEditorRow", () => moveRow(1)],
6468
+ ["edrv.command.prevEditorRow", () => moveRow(-1)],
6469
+ ["edrv.command.goToDefinition", () => {
6470
+ const ed = editorRef.current;
6471
+ if (ed) runGoToDefinition(ed);
6472
+ }],
6473
+ ["edrv.command.findReferences", () => {
6474
+ const ed = editorRef.current;
6475
+ if (ed) runFindReferences(ed);
6476
+ }],
6477
+ ["edrv.command.triggerAi", () => editorRef.current?.trigger?.("edrv-ai", "editor.action.inlineSuggest.trigger", null)],
6478
+ ["edrv.command.openInExplorer", () => {
6479
+ const path = activeRef.current;
6480
+ if (!path) {
6481
+ setStatus("无活动文件");
6482
+ return;
6483
+ }
6484
+ menuHandlersRef.current?.openInExplorer?.(path);
6485
+ }]
6486
+ ];
6487
+ const byName = new Map(handlers);
6488
+ const onCommand = (event) => {
6489
+ const action = byName.get(event.type);
6490
+ if (!action) return;
6491
+ try {
6492
+ action();
6493
+ } catch (error) {
6494
+ dbg(sessionId, "指令 " + event.type + " 失败:" + String(error));
6495
+ }
6496
+ };
6497
+ for (const [eventName] of handlers) window.addEventListener(eventName, onCommand);
6498
+ return () => {
6499
+ for (const [eventName] of handlers) window.removeEventListener(eventName, onCommand);
6500
+ };
6501
+ }, [sessionId]);
6502
+ react.default.useEffect(() => {
6503
+ const host = tabsHostRef.current;
6504
+ if (!host) return;
6505
+ const el = host.querySelector?.(".edrv-tab-active");
6506
+ if (!el) return;
6507
+ const left = el.offsetLeft;
6508
+ const right = left + el.offsetWidth;
6509
+ if (left < host.scrollLeft) host.scrollLeft = left;
6510
+ else if (right > host.scrollLeft + host.clientWidth) host.scrollLeft = right - host.clientWidth;
6511
+ }, [active, tabs.length]);
5350
6512
  react.default.useEffect(() => {
5351
6513
  const onPointer = (e) => {
5352
6514
  if (e?.button !== 3 && e?.button !== 4) return;
@@ -5424,16 +6586,20 @@ window.__ModuleLoader__.load({
5424
6586
  react.default.useEffect(() => {
5425
6587
  if (!monaco) return;
5426
6588
  registerThemes(monaco);
5427
- applyTheme(monaco);
5428
- if (typeof window.matchMedia !== "function") return;
5429
- const query = window.matchMedia("(prefers-color-scheme: dark)");
5430
- const onChange = () => applyTheme(monaco);
5431
- if (typeof query.addEventListener === "function") {
5432
- query.addEventListener("change", onChange);
5433
- return () => query.removeEventListener("change", onChange);
5434
- }
5435
- query.addListener(onChange);
5436
- return () => query.removeListener(onChange);
6589
+ const apply = () => applyOfficial(monaco);
6590
+ apply();
6591
+ window.addEventListener("edrv:theme-change", apply);
6592
+ const query = typeof window.matchMedia === "function" ? window.matchMedia("(prefers-color-scheme: dark)") : null;
6593
+ if (query) {
6594
+ if (typeof query.addEventListener === "function") query.addEventListener("change", apply);
6595
+ else query.addListener(apply);
6596
+ }
6597
+ return () => {
6598
+ window.removeEventListener("edrv:theme-change", apply);
6599
+ if (!query) return;
6600
+ if (typeof query.removeEventListener === "function") query.removeEventListener("change", apply);
6601
+ else query.removeListener(apply);
6602
+ };
5437
6603
  }, [monaco]);
5438
6604
  monacoRef.current = monaco;
5439
6605
  const getModel = (path, text) => {
@@ -5620,6 +6786,8 @@ window.__ModuleLoader__.load({
5620
6786
  });
5621
6787
  ed.onDidChangeCursorPosition((e) => {
5622
6788
  setCursor("Ln " + e.position.lineNumber + ", Col " + e.position.column);
6789
+ if (rowNavMoveRef.current) rowNavMoveRef.current = false;
6790
+ else rowNavColRef.current = null;
5623
6791
  if (navCursorTimerRef.current) clearTimeout(navCursorTimerRef.current);
5624
6792
  navCursorTimerRef.current = setTimeout(() => {
5625
6793
  navCursorTimerRef.current = null;
@@ -5696,6 +6864,24 @@ window.__ModuleLoader__.load({
5696
6864
  ed.addCommand(m.KeyCode.F12, () => {
5697
6865
  runGoToDefinition(ed);
5698
6866
  });
6867
+ ed.addAction({
6868
+ id: "edrv.prevEditorRow",
6869
+ label: "上一编辑行",
6870
+ contextMenuGroupId: "1_edrv",
6871
+ run: () => window.dispatchEvent(new CustomEvent("edrv.command.prevEditorRow"))
6872
+ });
6873
+ ed.addAction({
6874
+ id: "edrv.nextEditorRow",
6875
+ label: "下一编辑行",
6876
+ contextMenuGroupId: "1_edrv",
6877
+ run: () => window.dispatchEvent(new CustomEvent("edrv.command.nextEditorRow"))
6878
+ });
6879
+ ed.addAction({
6880
+ id: "edrv.showCommands",
6881
+ label: "显示所有命令",
6882
+ contextMenuGroupId: "1_edrv",
6883
+ run: () => window.dispatchEvent(new CustomEvent("edrv.command.showCommands"))
6884
+ });
5699
6885
  bindLspEditor(ed);
5700
6886
  bindLspUnderline(ed, m);
5701
6887
  trackAiEditor(ed);
@@ -6168,6 +7354,7 @@ window.__ModuleLoader__.load({
6168
7354
  };
6169
7355
  const tabsEl = react.default.createElement("div", {
6170
7356
  className: "edrv-tabs",
7357
+ ref: tabsHostRef,
6171
7358
  style: {
6172
7359
  flex: "1 1 auto",
6173
7360
  minWidth: 0
@@ -6344,7 +7531,7 @@ window.__ModuleLoader__.load({
6344
7531
  });
6345
7532
  }
6346
7533
  }, "重试"));
6347
- else if (!active) body = react.default.createElement("div", { className: "edrv-empty" }, react.default.createElement("div", null, "暂无打开的文件"), react.default.createElement("div", { style: { fontSize: 12 } }, "使用右上搜索框 (" + (chordOf("edrv.quickOpen") ?? "Ctrl+P") + ") 打开工作区文件;agent 修改文件后顶部会出现差异角标"));
7534
+ else if (!active) body = react.default.createElement("div", { className: "edrv-empty" }, react.default.createElement("div", null, "暂无打开的文件"), react.default.createElement("div", { style: { fontSize: 12 } }, "使用右上搜索框 (" + (chordOf("edrv.quickOpen") ?? "Ctrl+P") + ") 打开工作区文件;" + (chordOf("edrv.showCommands") ?? "Ctrl+Shift+P") + " 打开命令栏;agent 修改文件后顶部会出现差异角标"));
6348
7535
  else if (content === null && loadError) body = loadingBody("文件加载失败:" + loadError, 0, () => {
6349
7536
  setLoadError(null);
6350
7537
  setContent(null);
@@ -6569,20 +7756,24 @@ window.__ModuleLoader__.load({
6569
7756
  background: "var(--dsw-alias-bg-base,transparent)",
6570
7757
  overflow: "hidden"
6571
7758
  };
7759
+ const paletteEl = react.default.createElement(CommandPalette, {
7760
+ key: "edrv-palette",
7761
+ sessionId
7762
+ });
6572
7763
  return layout === "side" ? react.default.createElement("div", {
6573
7764
  ref: viewRootRef,
6574
7765
  "data-edrv-view": "1",
6575
7766
  "data-edrv-layout": "side",
6576
7767
  className: "edrv-view-side",
6577
7768
  style: Object.assign({}, baseStyle, { height: "100%" })
6578
- }, editorRow, menuBackdrop, tabMenuEl) : react.default.createElement("div", {
7769
+ }, editorRow, menuBackdrop, tabMenuEl, paletteEl) : react.default.createElement("div", {
6579
7770
  ref: viewRootRef,
6580
7771
  "data-edrv-view": "1",
6581
7772
  style: Object.assign({}, baseStyle, {
6582
7773
  height: "var(--edrv-editor-height, 100%)",
6583
7774
  maxHeight: "var(--edrv-editor-height, 100%)"
6584
7775
  })
6585
- }, editorRow, menuBackdrop, tabMenuEl);
7776
+ }, editorRow, menuBackdrop, tabMenuEl, paletteEl);
6586
7777
  }
6587
7778
  //#endregion
6588
7779
  //#region src/client/ui/DiffBadge.ts
@@ -6935,11 +8126,15 @@ window.__ModuleLoader__.load({
6935
8126
  "data-edrv-diff-dock-shell": "1"
6936
8127
  }, content);
6937
8128
  const editorSnapshot = readDiffDock(sessionId);
8129
+ const palette = react.default.createElement(CommandPalette, {
8130
+ key: "edrv-palette",
8131
+ sessionId
8132
+ });
6938
8133
  if (editorSnapshot) {
6939
- if (editorSnapshot.mode === "editor-empty" && !editorSnapshot.fileTotal) return null;
6940
- return renderDock(react.default.createElement(DiffBox, Object.assign({}, editorSnapshot, { dock: true })), sessionId);
8134
+ if (editorSnapshot.mode === "editor-empty" && !editorSnapshot.fileTotal) return palette;
8135
+ return react.default.createElement(react.default.Fragment, null, renderDock(react.default.createElement(DiffBox, Object.assign({}, editorSnapshot, { dock: true })), sessionId), palette);
6941
8136
  }
6942
- if (!sessionId || !summary?.pendingFiles?.length) return null;
8137
+ if (!sessionId || !summary?.pendingFiles?.length) return palette;
6943
8138
  const paths = summary.pendingFiles.map((file) => file.path);
6944
8139
  const click = () => {
6945
8140
  const current = nextIndexBySession.get(sessionId) ?? 0;
@@ -6947,12 +8142,12 @@ window.__ModuleLoader__.load({
6947
8142
  nextIndexBySession.set(sessionId, next.index);
6948
8143
  if (next.path) openDiffView(next.path);
6949
8144
  };
6950
- return renderDock(react.default.createElement(DiffBox, {
8145
+ return react.default.createElement(react.default.Fragment, null, renderDock(react.default.createElement(DiffBox, {
6951
8146
  mode: "chat",
6952
8147
  dock: true,
6953
8148
  fileTotal: paths.length,
6954
8149
  onOpenNextFile: click
6955
- }), sessionId || "chat");
8150
+ }), sessionId || "chat"), palette);
6956
8151
  }
6957
8152
  //#endregion
6958
8153
  //#region \0dsh-css:/home/runner/work/DSH_VsCodeMode/DSH_VsCodeMode/src/client/styles/mcp.css.mjs
@@ -7132,6 +8327,17 @@ window.__ModuleLoader__.load({
7132
8327
  focusDiff: value?.focusDiff === true
7133
8328
  };
7134
8329
  }
8330
+ /**
8331
+ * 从官方导航参数安全解析行号(缺字段/坏类型/非正数一律视为未指定)。
8332
+ * @author ddj 2026年09月10号
8333
+ * @param params openTab/openResource 传入的 params(正文经 navigation.params 读回)
8334
+ * @returns 正整数行号,或 undefined
8335
+ */
8336
+ function resolveNavLine(params) {
8337
+ const line = (params ?? {})?.line;
8338
+ if (typeof line !== "number" || !Number.isFinite(line) || line <= 0) return void 0;
8339
+ return Math.floor(line);
8340
+ }
7135
8341
  /** 逐段 component 解码(失败返回 null,对齐官方 parseFileAddress 的容错语义)。 */
7136
8342
  function decodeSegment(raw) {
7137
8343
  if (raw === void 0) return null;
@@ -7211,6 +8417,27 @@ window.__ModuleLoader__.load({
7211
8417
  return "dsh-resource://file/session/" + encodeSegment(sessionId) + "/" + relative.split("/").map(encodeSegment).join("/");
7212
8418
  }
7213
8419
  /**
8420
+ * 把 file 打开请求转发进单一编辑器页签(文件分页由编辑器自带页签栏接管,
8421
+ * 官方侧栏不再按文件分裂出多套编辑器实例)。
8422
+ * @author ddj 2026年09月10号
8423
+ * @param service 官方 sidebarRight 服务(缺失/缺 openTab 返回 false)
8424
+ * @param path 目标文件路径(空值返回 false)
8425
+ * @param line 可选行号(透传给编辑器页签导航参数)
8426
+ * @returns 转发是否成功(openTab 抛错返回 false,由调用方决定重试或兜底)
8427
+ */
8428
+ function forwardToEditor(service, path, line) {
8429
+ if (!service || typeof service.openTab !== "function" || !path) return false;
8430
+ const params = { openPath: path };
8431
+ if (line !== void 0) params.line = line;
8432
+ try {
8433
+ service.openTab(OFFICIAL_TAB_KIND, { params });
8434
+ return true;
8435
+ } catch (error) {
8436
+ log.warn("file 认领转发进编辑器页签失败(" + String(error) + ")");
8437
+ return false;
8438
+ }
8439
+ }
8440
+ /**
7214
8441
  * 注册官方 Tab 正文(keyed slot,key=定义 id;slots.inject 等待 rightbar seat 声明)。
7215
8442
  * @author ddj 2026年09月09号
7216
8443
  * @param slots slots 服务
@@ -7696,7 +8923,7 @@ window.__ModuleLoader__.load({
7696
8923
  onClick: () => resetRow(command.id)
7697
8924
  }, "恢复"))));
7698
8925
  });
7699
- return react.default.createElement("section", { className: "vsm-general-page" }, react.default.createElement("h2", null, "快捷键"), react.default.createElement("p", null, "配置编辑器视图的快捷键(保存 / 快速打开 / 侧边栏 / 搜索 / 后退 / 前进)。修改即时写入配置,重新聚焦编辑器后生效。"), unavailable && react.default.createElement("div", { className: "vsm-mcp-error vsm-mcp-banner" }, "设置服务暂不可用,当前使用默认键位。"), error && react.default.createElement("div", { className: "vsm-mcp-error vsm-mcp-banner" }, error), message && react.default.createElement("div", { className: "vsm-kb-message" }, message), react.default.createElement("section", { className: "vsm-panel" }, react.default.createElement("h3", { className: "vsm-panel-title" }, "编辑器键位"), react.default.createElement("div", { className: "vsm-panel-body" }, react.default.createElement("div", { className: "vsm-kb-list" }, rows)), react.default.createElement("div", { className: "vsm-panel-body vsm-kb-actionsbar" }, react.default.createElement("span", { className: "vsm-kb-dirty" }, dirty ? "有未保存的修改" : ""), react.default.createElement("button", {
8926
+ return react.default.createElement("section", { className: "vsm-general-page" }, react.default.createElement("h2", null, "快捷键"), react.default.createElement("p", null, "配置编辑器视图的快捷键(命令栏 / 保存 / 快速打开 / 侧边栏 / 搜索 / 后退前进 / 页签与编辑行导航)。修改即时写入配置,重新聚焦编辑器后生效;命令栏(默认 Ctrl+Shift+P 或 F1)可搜索并执行下列全部命令。"), unavailable && react.default.createElement("div", { className: "vsm-mcp-error vsm-mcp-banner" }, "设置服务暂不可用,当前使用默认键位。"), error && react.default.createElement("div", { className: "vsm-mcp-error vsm-mcp-banner" }, error), message && react.default.createElement("div", { className: "vsm-kb-message" }, message), react.default.createElement("section", { className: "vsm-panel" }, react.default.createElement("h3", { className: "vsm-panel-title" }, "编辑器键位"), react.default.createElement("div", { className: "vsm-panel-body" }, react.default.createElement("div", { className: "vsm-kb-list" }, rows)), react.default.createElement("div", { className: "vsm-panel-body vsm-kb-actionsbar" }, react.default.createElement("span", { className: "vsm-kb-dirty" }, dirty ? "有未保存的修改" : ""), react.default.createElement("button", {
7700
8927
  className: "vsm-primary vsm-small",
7701
8928
  disabled: unavailable || notReady || busy || snapshot?.writable === false || !dirty,
7702
8929
  onClick: save
@@ -10089,13 +11316,12 @@ window.__ModuleLoader__.load({
10089
11316
  //#endregion
10090
11317
  //#region src/client/ui/OfficialSideTab.ts
10091
11318
  /**
10092
- * dsh-vscode-mode client — OfficialSideTab:DSH 官方右侧 Sidebar「文件编辑」Tab 正文包装。
10093
- * 双用途:页类型 Tab(edrvEditor)经 navigation.params(openPath/focusDiff)打开;
10094
- * file 资源类型 Tab(edrvEditorFile,认领 dsh-resource://file/**)经 navigation.address
10095
- * 解码出真实路径并透传 params.line 行号定位。派发既有 edrv:open-editor 事件复用
10096
- * EditorView 打开流;按会话 key 保证切会话干净重建。
11319
+ * dsh-vscode-mode client — OfficialSideTab:DSH 官方右侧 Sidebar「文件编辑」页签正文包装。
11320
+ * 用途:页类型 Tab(edrvEditor)经 navigation.params(openPath/focusDiff/line)打开;
11321
+ * 兼作 file 认领转发(ClaimRouter)失败时的兜底正文(就地挂编辑器,旧行为)。
11322
+ * 派发既有 edrv:open-editor 事件复用 EditorView 打开流;按会话 key 保证切会话干净重建。
10097
11323
  * Tab 正文切换后重挂载时按最新导航恢复打开(对齐 better-sidebar 形态的种子行为)。
10098
- * 作者 ddj 2026年09月09号
11324
+ * 作者 ddj 2026年09月09号 / 2026年09月10号
10099
11325
  */
10100
11326
  /**
10101
11327
  * 官方侧边栏 Tab 正文组件(keyed slot sidebar.right.pane.tab 装配)。
@@ -10148,7 +11374,8 @@ window.__ModuleLoader__.load({
10148
11374
  const request = resolveNavOpen(navigation?.params);
10149
11375
  window.dispatchEvent(new CustomEvent("edrv:open-editor", { detail: {
10150
11376
  path: request.path,
10151
- focusDiff: request.focusDiff
11377
+ focusDiff: request.focusDiff,
11378
+ line: resolveNavLine(navigation?.params)
10152
11379
  } }));
10153
11380
  });
10154
11381
  return react.default.createElement(EditorView, {
@@ -10164,6 +11391,93 @@ window.__ModuleLoader__.load({
10164
11391
  });
10165
11392
  }
10166
11393
  //#endregion
11394
+ //#region src/client/ui/ClaimRouter.ts
11395
+ /**
11396
+ * dsh-vscode-mode client — ClaimRouter:官方 file 认领页签的中转正文。
11397
+ * 官方为每个 `dsh-resource://file/**` 地址开一个认领页签;本组件只做转发:
11398
+ * 解析地址 → 送进单一编辑器页签(文件分页由编辑器自带页签栏接管)→ 关闭本中转页签。
11399
+ * 转发失败(seat 未就绪等瞬时态)按 3 次 ×150ms 重试;仍失败则就地渲染兜底正文
11400
+ * (旧行为:每文件一套编辑器),保证退化路径不白屏。本组件自身不创建 Monaco 实例。
11401
+ * 作者 ddj 2026年09月10号
11402
+ */
11403
+ /** 转发尝试次数(含首次)与重试间隔。 */
11404
+ const FORWARD_ATTEMPTS = 3;
11405
+ const FORWARD_DELAY_MS = 150;
11406
+ /**
11407
+ * 读 slot 框架注入的 tab 记录(hook 缺失或抛错时返回 undefined)。
11408
+ * @author ddj 2026年09月10号
11409
+ * @param props slot 框架注入的组件 props
11410
+ * @returns tab 记录(含 navigation 与 actions),或 undefined
11411
+ */
11412
+ function readTab(props) {
11413
+ const useTabInfo = props?.useTabInfo;
11414
+ if (typeof useTabInfo !== "function") return void 0;
11415
+ try {
11416
+ return useTabInfo()?.tab;
11417
+ } catch {
11418
+ return;
11419
+ }
11420
+ }
11421
+ /**
11422
+ * 关闭本中转页签(失败仅告警:目标文件已在编辑器打开,残留页签不阻塞功能)。
11423
+ * @author ddj 2026年09月10号
11424
+ * @param tab slot 框架注入的 tab 记录
11425
+ */
11426
+ function closeTab(tab) {
11427
+ try {
11428
+ tab?.actions?.close?.();
11429
+ } catch (error) {
11430
+ log.warn("中转页签关闭失败(" + String(error) + ")");
11431
+ }
11432
+ }
11433
+ /**
11434
+ * 组装 file 认领转发正文。
11435
+ * @author ddj 2026年09月10号
11436
+ * @param spec 装配依赖(service 官方导航服务 / schedule 延时调度 / fallback 兜底正文)
11437
+ * @returns 正文组件(注册进 keyed slot sidebar.right.pane.tab)
11438
+ */
11439
+ function createClaimRouter(spec) {
11440
+ const service = spec?.service;
11441
+ const schedule = spec?.schedule;
11442
+ const fallback = spec?.fallback;
11443
+ /**
11444
+ * 中转正文:转发成功即关闭自身;重试耗尽后渲染兜底正文。
11445
+ * @param props slot 框架注入(useTabInfo)+ 装配依赖
11446
+ * @returns 兜底正文元素,或 null(转发中 / 已转发)
11447
+ */
11448
+ function ClaimRouter(props) {
11449
+ const tab = readTab(props);
11450
+ const navigation = tab?.navigation;
11451
+ const revision = typeof navigation?.revision === "number" ? navigation.revision : -1;
11452
+ const [failed, setFailed] = react.default.useState(false);
11453
+ const doneRef = react.default.useRef(-1);
11454
+ react.default.useEffect(() => {
11455
+ if (revision === doneRef.current) return;
11456
+ doneRef.current = revision;
11457
+ const parsed = parseOfficialFileAddress(navigation?.address);
11458
+ if (!parsed) {
11459
+ setFailed(true);
11460
+ return;
11461
+ }
11462
+ const line = resolveNavLine(navigation?.params);
11463
+ let left = FORWARD_ATTEMPTS;
11464
+ const attempt = () => {
11465
+ if (forwardToEditor(service, parsed.path, line)) {
11466
+ closeTab(tab);
11467
+ return;
11468
+ }
11469
+ left -= 1;
11470
+ if (left > 0 && typeof schedule === "function") schedule(attempt, FORWARD_DELAY_MS);
11471
+ else setFailed(true);
11472
+ };
11473
+ attempt();
11474
+ }, [revision]);
11475
+ if (!failed || typeof fallback !== "function") return null;
11476
+ return react.default.createElement(fallback, props);
11477
+ }
11478
+ return ClaimRouter;
11479
+ }
11480
+ //#endregion
10167
11481
  //#region src/client/sidebar/registry.ts
10168
11482
  /** 校验面板定义并写入注册表(缺 id/render 抛 TypeError)。 */
10169
11483
  function panelRegister(entries, notify, panel) {
@@ -10611,8 +11925,8 @@ window.__ModuleLoader__.load({
10611
11925
  * host 树索引,命中近乎零成本);挂载/切会话从缓存即时恢复展开树;⟳/edrv:refresh
10612
11926
  * 保留旧条目强制后台重列(force);每次用户发起加载后预取 ≤4 个子目录(排除重型
10613
11927
  * 目录、缓存新鲜跳过、不级联);10s 轻量跟随已展开目录(命中索引,RPC 近零成本)。
10614
- * 差异角标/右键菜单/展开状态持久化行为不变。
10615
- * 作者 ddj 2026-08-26 / 2026-08-27 / 2026-08-31
11928
+ * 差异角标/右键菜单/展开状态持久化行为不变;行图标用官方原语(文件夹图标 + 文件类型图标)。
11929
+ * 作者 ddj 2026-08-26 / 2026-08-27 / 2026-08-31 / 2026-09-10
10616
11930
  */
10617
11931
  const DIR_CAP = 4e3;
10618
11932
  const SAVE_DEBOUNCE_MS = 300;
@@ -10627,6 +11941,58 @@ window.__ModuleLoader__.load({
10627
11941
  ".pnpm-store"
10628
11942
  ]);
10629
11943
  /**
11944
+ * 目录图标元素(官方 IconFolderOpen16/Close16)。
11945
+ * @author ddj 2026年09月10号
11946
+ * @param isOpen 目录是否展开
11947
+ * @returns 图标元素;原语缺失返回 null
11948
+ */
11949
+ function dirIconEl(isOpen) {
11950
+ const Icon = isOpen ? _deepseek_ai_dsh_client_ui_primitives.IconFolderOpen16 : _deepseek_ai_dsh_client_ui_primitives.IconFolderClose16;
11951
+ if (typeof Icon !== "function") return null;
11952
+ return react.default.createElement(Icon, {
11953
+ size: 16,
11954
+ className: "edrv-tree-icon"
11955
+ });
11956
+ }
11957
+ /**
11958
+ * 文件图标元素(官方 FileTypeIcon + classifyFileType 分类,未知类型为 other)。
11959
+ * @author ddj 2026年09月10号
11960
+ * @param name 文件名(含扩展名)
11961
+ * @returns 图标元素;原语缺失或分类异常返回 null
11962
+ */
11963
+ function fileIconEl(name) {
11964
+ if (typeof _deepseek_ai_dsh_client_ui_primitives.FileTypeIcon !== "function" || typeof _deepseek_ai_dsh_client_ui_primitives.classifyFileType !== "function") return null;
11965
+ try {
11966
+ return react.default.createElement(_deepseek_ai_dsh_client_ui_primitives.FileTypeIcon, {
11967
+ kind: (0, _deepseek_ai_dsh_client_ui_primitives.classifyFileType)(String(name ?? "")),
11968
+ size: 16,
11969
+ className: "edrv-tree-icon"
11970
+ });
11971
+ } catch (error) {
11972
+ return null;
11973
+ }
11974
+ }
11975
+ /**
11976
+ * 行图标分派:目录 → 文件夹图标,文件 → 官方类型图标。
11977
+ * @author ddj 2026年09月10号
11978
+ * @param e 目录条目(name/type)
11979
+ * @param isDir 是否目录
11980
+ * @param isOpen 目录是否展开
11981
+ * @returns 图标元素或 null
11982
+ */
11983
+ function rowIconEl(e, isDir, isOpen) {
11984
+ return isDir ? dirIconEl(isOpen) : fileIconEl(e?.name);
11985
+ }
11986
+ /**
11987
+ * 刷新按钮图标(官方 IconRefreshOutline16;原语缺失回落文本 ⟳)。
11988
+ * @author ddj 2026年09月10号
11989
+ * @returns 图标元素或回落文本
11990
+ */
11991
+ function refreshIconEl() {
11992
+ if (typeof _deepseek_ai_dsh_client_ui_primitives.IconRefreshOutline16 !== "function") return "⟳";
11993
+ return react.default.createElement(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutline16, { size: 14 });
11994
+ }
11995
+ /**
10630
11996
  * 目录树面板主体(SWR:有缓存先渲染,无缓存才显示加载态;加载总在后台)。
10631
11997
  * @param props.ctx 面板共享上下文(sessionId/openFile/activePath/pendingByPath/fileMenuItems/notify)
10632
11998
  */
@@ -10824,7 +12190,7 @@ window.__ModuleLoader__.load({
10824
12190
  }
10825
12191
  });
10826
12192
  }
10827
- }, react.default.createElement("span", { className: "edrv-tree-chev" }, isDir ? isOpen ? "▾" : "▸" : ""), react.default.createElement("span", { className: "edrv-tree-name" + (dim ? " edrv-tree-dim" : "") }, isDir ? isOpen ? "📂" : "📁" : "📄", " ", e.name), pending > 0 ? react.default.createElement("span", { className: "edrv-tree-badge" }, String(pending)) : null);
12193
+ }, react.default.createElement("span", { className: "edrv-tree-chev" }, isDir ? isOpen ? "▾" : "▸" : ""), rowIconEl(e, isDir, isOpen), react.default.createElement("span", { className: "edrv-tree-name" + (dim ? " edrv-tree-dim" : "") }, e.name), pending > 0 ? react.default.createElement("span", { className: "edrv-tree-badge" }, String(pending)) : null);
10828
12194
  };
10829
12195
  const rowsOf = (rel, depth) => {
10830
12196
  const entries = entriesOf(rel);
@@ -10882,7 +12248,7 @@ window.__ModuleLoader__.load({
10882
12248
  className: "edrv-side-btn",
10883
12249
  title: "刷新目录树",
10884
12250
  onClick: refresh
10885
- }, "⟳")), react.default.createElement("div", { className: "edrv-tree" }, errorText ? react.default.createElement("div", { className: "edrv-tree-error" }, react.default.createElement("span", null, String(errorText)), react.default.createElement("button", {
12251
+ }, refreshIconEl())), react.default.createElement("div", { className: "edrv-tree" }, errorText ? react.default.createElement("div", { className: "edrv-tree-error" }, react.default.createElement("span", null, String(errorText)), react.default.createElement("button", {
10886
12252
  className: "edrv-side-btn",
10887
12253
  onClick: () => refresh()
10888
12254
  }, "重试")) : null, rowsOf("", 0)), menu && menuEntries.length ? react.default.createElement(ContextMenu, {
@@ -11935,18 +13301,19 @@ window.__ModuleLoader__.load({
11935
13301
  //#region src/client/sidebar/panels/index.ts
11936
13302
  /**
11937
13303
  * dsh-vscode-mode client — 侧边栏面板定义(文件管理 + 搜索 + 规则)。
11938
- * 作者 ddj 2026-08-26 / 2026-09-03
13304
+ * 活动栏图标用官方 UI 原语(跟随 DSH 主题与皮肤);原语缺失时由 SidebarView 回落文本渲染。
13305
+ * 作者 ddj 2026-08-26 / 2026-09-03 / 2026-09-10
11939
13306
  */
11940
13307
  /**
11941
13308
  * 构造文件管理面板定义。
11942
- * @author ddj 2026年08月26号
11943
- * @returns 面板定义(含活动栏徽标 = 差异文件总数)
13309
+ * @author ddj 2026年08月26号 / 2026年09月10号
13310
+ * @returns 面板定义(含活动栏徽标 = 差异文件总数;图标 = 官方 IconFolderOpenOutline16)
11944
13311
  */
11945
13312
  function createFilePanel() {
11946
13313
  return {
11947
13314
  id: "explorer",
11948
13315
  title: "文件管理",
11949
- icon: "📁",
13316
+ icon: _deepseek_ai_dsh_client_ui_primitives.IconFolderOpenOutline16,
11950
13317
  order: 10,
11951
13318
  badge: (ctx) => ctx.sum && ctx.sum.totalFiles > 0 ? ctx.sum.totalFiles : null,
11952
13319
  render: (ctx) => react.default.createElement(FileExplorer, { ctx })
@@ -11954,28 +13321,28 @@ window.__ModuleLoader__.load({
11954
13321
  }
11955
13322
  /**
11956
13323
  * 构造搜索面板定义。
11957
- * @author ddj 2026年08月30号
11958
- * @returns 面板定义(无徽标;活动栏图标 🔍)
13324
+ * @author ddj 2026年08月30号 / 2026年09月10号
13325
+ * @returns 面板定义(无徽标;图标 = 官方 IconSearchOutline16)
11959
13326
  */
11960
13327
  function createSearchPanel() {
11961
13328
  return {
11962
13329
  id: "search",
11963
13330
  title: "搜索",
11964
- icon: "🔍",
13331
+ icon: _deepseek_ai_dsh_client_ui_primitives.IconSearchOutline16,
11965
13332
  order: 15,
11966
13333
  render: (ctx) => react.default.createElement(SearchPanel, { ctx })
11967
13334
  };
11968
13335
  }
11969
13336
  /**
11970
13337
  * 构造规则管理面板定义(Codebuddy 规则形态:用户规则/项目规则双 Tab + 开关)。
11971
- * @author ddj 2026年09月03号
11972
- * @returns 面板定义(无徽标;活动栏图标 📏,与大纲 📜 区分)
13338
+ * @author ddj 2026年09月03号 / 2026年09月10号
13339
+ * @returns 面板定义(无徽标;图标 = 官方 IconListPenOutline16)
11973
13340
  */
11974
13341
  function createRulesPanel() {
11975
13342
  return {
11976
13343
  id: "rules",
11977
13344
  title: "规则",
11978
- icon: "📏",
13345
+ icon: _deepseek_ai_dsh_client_ui_primitives.IconListPenOutline16,
11979
13346
  order: 20,
11980
13347
  render: (ctx) => react.default.createElement(RulesPanel, { ctx })
11981
13348
  };
@@ -12767,14 +14134,14 @@ window.__ModuleLoader__.load({
12767
14134
  */
12768
14135
  /**
12769
14136
  * 构造大纲面板定义。
12770
- * @author ddj 2026年08月27号
12771
- * @returns 面板定义(无徽标;活动栏图标 📜)
14137
+ * @author ddj 2026年08月27号 / 2026年09月10号
14138
+ * @returns 面板定义(无徽标;活动栏图标 = 官方 IconCodeOutline16)
12772
14139
  */
12773
14140
  function createOutlinePanel() {
12774
14141
  return {
12775
14142
  id: "outline",
12776
14143
  title: "大纲",
12777
- icon: "📜",
14144
+ icon: _deepseek_ai_dsh_client_ui_primitives.IconCodeOutline16,
12778
14145
  order: 20,
12779
14146
  render: (ctx) => react.default.createElement(OutlinePanel, { ctx })
12780
14147
  };
@@ -12817,6 +14184,64 @@ window.__ModuleLoader__.load({
12817
14184
  return out;
12818
14185
  }
12819
14186
  //#endregion
14187
+ //#region src/client/commandBridge.ts
14188
+ /**
14189
+ * dsh-vscode-mode client — 指令执行桥(装配层)。
14190
+ * 职责三件:① 把内置指令目录注册进注册表;② 为「桥接派发」类指令挂窗口 capture 键位监听
14191
+ * (EditorView 原生监听的 8 条不进这里,避免双执行);③ 注入命令栏执行器。
14192
+ * 编辑器动作本身由 EditorView / QuickOpen 监听 `edrv.command.<action>` 窗口事件完成——桥不持有
14193
+ * React 状态,因此指令系统可在编辑器挂载前装配、卸载后仍安全。
14194
+ * 作者 ddj 2026年09月10号
14195
+ */
14196
+ const bridgeLog = log.child("commands");
14197
+ /** 解析事件目标(缺省 window;无 window 返回 null)。 */
14198
+ function resolveTarget(options) {
14199
+ if (options.target) return options.target;
14200
+ if (typeof window === "undefined") return null;
14201
+ return window;
14202
+ }
14203
+ /**
14204
+ * 创建指令执行桥:注册内置指令 + 桥接类指令的全局键位监听。
14205
+ * @author ddj 2026年09月10号
14206
+ * @param options 装配选项(事件目标注入)
14207
+ * @returns 指令执行桥句柄
14208
+ */
14209
+ function createCommandBridge(options = {}) {
14210
+ const registry = createCommandRegistry();
14211
+ const disposers = [];
14212
+ const palette = showCommandsDef(() => openCommandPalette("command"));
14213
+ for (const command of [...EDITOR_COMMANDS, ...BRIDGE_COMMANDS]) disposers.push(registry.register(command));
14214
+ disposers.push(registry.register(palette));
14215
+ setPaletteRunner((id) => registry.run(id));
14216
+ setRegistryRef(registry);
14217
+ const dispatched = dispatchedCommands(palette);
14218
+ const onKey = (event) => {
14219
+ for (const command of dispatched) {
14220
+ if (!matchEvent(event, bindingsOf(command.id))) continue;
14221
+ event.preventDefault();
14222
+ event.stopPropagation();
14223
+ registry.run(command.id);
14224
+ return;
14225
+ }
14226
+ };
14227
+ const target = resolveTarget(options);
14228
+ if (target) target.addEventListener("keydown", onKey, true);
14229
+ const dispose = () => {
14230
+ if (target) target.removeEventListener("keydown", onKey, true);
14231
+ while (disposers.length) {
14232
+ const release = disposers.pop();
14233
+ if (release) release();
14234
+ }
14235
+ setPaletteRunner(null);
14236
+ setRegistryRef(null);
14237
+ };
14238
+ bridgeLog.info("指令注册表已装配(" + registry.list().length + " 条指令,桥接键位 " + dispatched.length + " 条)");
14239
+ return {
14240
+ registry,
14241
+ dispose
14242
+ };
14243
+ }
14244
+ //#endregion
12820
14245
  //#region src/client/index.ts
12821
14246
  /**
12822
14247
  * dsh-vscode-mode client — 浏览器半入口:slot 注册 + 装配。
@@ -12844,6 +14269,30 @@ window.__ModuleLoader__.load({
12844
14269
  "conversation",
12845
14270
  "settingsScope"
12846
14271
  ];
14272
+ /** 指令桥装配幂等标记(同一 document 重复 apply 只装配一次,避免重复键位监听)。 */
14273
+ let commandsMounted = false;
14274
+ /**
14275
+ * 装配指令注册表(指令桥 + 命令栏)。
14276
+ * 指令桥不依赖已挂载编辑器(run 只派发窗口事件),故可在启动期装配;
14277
+ * 命令栏浮层的宿主由 CommandPalette 自己在编辑区树内认领。
14278
+ * @author ddj 2026年09月10号
14279
+ * @param ctx 客户端根上下文
14280
+ * @returns void
14281
+ */
14282
+ function setupCommands(ctx) {
14283
+ if (commandsMounted) return;
14284
+ commandsMounted = true;
14285
+ const bridge = createCommandBridge();
14286
+ ctx.provide(REGISTRY_GLOBAL, bridge.registry);
14287
+ const host = window;
14288
+ host[REGISTRY_GLOBAL] = bridge.registry;
14289
+ ctx.effect(() => () => {
14290
+ bridge.dispose();
14291
+ commandsMounted = false;
14292
+ if (host["__edrvCommands__"] === bridge.registry) delete host[REGISTRY_GLOBAL];
14293
+ }, "vscode-mode: command registry");
14294
+ log.info("指令系统已装配:" + bridge.registry.list().length + " 条指令,Ctrl+Shift+P 打开命令栏");
14295
+ }
12847
14296
  /**
12848
14297
  * 装配客户端:注册中央编辑区视图与 header 差异角标。
12849
14298
  * @author ddj 2026年08月20号
@@ -12851,6 +14300,7 @@ window.__ModuleLoader__.load({
12851
14300
  */
12852
14301
  function apply(ctx) {
12853
14302
  const schedule = (fn, ms) => ctx.timeout(fn, ms);
14303
+ setupCommands(ctx);
12854
14304
  const registry = createFileOpenerRegistry();
12855
14305
  const workspaces = ctx.get("workspaces");
12856
14306
  const sessions = ctx.get("sessions");
@@ -12955,7 +14405,7 @@ window.__ModuleLoader__.load({
12955
14405
  {
12956
14406
  name: "文件链接官方认领(dsh-resource://file)",
12957
14407
  active: claimDisposer !== null,
12958
- note: claimDisposer !== null ? "聊天文件链接由本插件编辑器接管(官方侧边栏内打开)" : "链接走官方查看器或旧版路由(未认领)"
14408
+ note: claimDisposer !== null ? "聊天文件链接转发进单一编辑器页签(文件分页归编辑器自带页签栏)" : "链接走官方查看器或旧版路由(未认领)"
12959
14409
  }
12960
14410
  ];
12961
14411
  ctx.provide("fileOpeners", registry);
@@ -12991,15 +14441,20 @@ window.__ModuleLoader__.load({
12991
14441
  fileMenuItems,
12992
14442
  sessions
12993
14443
  }));
12994
- /** 官方 file 地址认领同步:自动/VSCodeMode 档认领(链接进本插件编辑器),其余交官方查看器。 */
14444
+ /** 官方 file 地址认领同步:自动/VSCodeMode 档认领(转发进单一编辑器页签),其余交官方查看器。 */
12995
14445
  const syncFileClaim = () => {
12996
14446
  const official = officialService;
12997
14447
  const want = official !== void 0 && shouldClaimFiles(selected);
12998
14448
  if (want && claimDisposer === null && official) {
14449
+ const renderTab = createClaimRouter({
14450
+ service: official.service,
14451
+ schedule,
14452
+ fallback: officialRenderTab
14453
+ });
12999
14454
  const disposer = registerOfficialFileClaim({
13000
14455
  tabs: official.tabs,
13001
14456
  slots: ctx.slots,
13002
- renderTab: officialRenderTab
14457
+ renderTab
13003
14458
  });
13004
14459
  if (disposer !== null) claimDisposer = ctx.effect(() => disposer, "vscode-mode: official file claim");
13005
14460
  return;
@@ -13070,6 +14525,18 @@ window.__ModuleLoader__.load({
13070
14525
  }, 2e3);
13071
14526
  };
13072
14527
  retryRemoteOpen();
14528
+ const themeService = ctx.get("theme");
14529
+ const emitTheme = () => {
14530
+ const snapshot = typeof themeService?.getTheme === "function" ? themeService.getTheme() : void 0;
14531
+ window.dispatchEvent(new CustomEvent("edrv:theme-change", { detail: { scheme: schemeOfSnapshot(snapshot) } }));
14532
+ };
14533
+ ctx.effect(() => {
14534
+ if (!themeService || typeof ctx.on !== "function") return void 0;
14535
+ const disposer = ctx.on("theme/change", emitTheme);
14536
+ return typeof disposer === "function" ? disposer : void 0;
14537
+ }, "vscode-mode: official theme event");
14538
+ ctx.effect(() => observeScheme(emitTheme), "vscode-mode: theme attribute watch");
14539
+ emitTheme();
13073
14540
  const registerLegacyTab = () => {
13074
14541
  return registerSlotSafely(ctx, {
13075
14542
  name: "conversation.view",