dsh-vscode-mode 0.1.48 → 0.1.50

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
@@ -30,7 +30,7 @@ window.__ModuleLoader__.load({
30
30
  react = __toESM(react, 1);
31
31
  let react_dom = require("react-dom");
32
32
  //#region \0dsh-css:/home/runner/work/DSH_VsCodeMode/DSH_VsCodeMode/src/client/styles/editor.css.mjs
33
- const css$1 = "/* dsh-vscode-mode 编辑区样式(原 ensureEdrvStyles 字符串,落盘为真 .css,由 tsdown CSS-inline 注入) */\n/* 浅色主题(对齐参考图:#f8f8f8 近白底 + 薄荷绿药丸 + 青绿文字 + 三文鱼 undo + 浅灰边框):\n 在 [data-edrv-view] 作用域内重定义 --dsw-alias-*,级联命中组件内联样式与 CSS。 */\n[data-edrv-view] { box-sizing: border-box; --edrv-tab-h: 34px; --dsw-alias-bg-base: #f8f8f8; --dsw-alias-bg-layer-1: #ffffff; --dsw-alias-bg-layer-2: #f0f4f4; --dsw-alias-bg-overlay: #ffffff; --dsw-alias-label-primary: #1f2933; --dsw-alias-label-secondary: #52606d; --dsw-alias-label-tertiary: #9aa5b1; --dsw-alias-border-l1: #e0e6e8; --dsw-alias-border-l2: #cbd2d9; --dsw-alias-brand-primary: #0f9d58; --dsw-alias-state-success-primary: #0f9d58; --dsw-alias-state-error-primary: #d9534f; --dsw-alias-state-warn-primary: #d97706; --dsw-alias-interactive-bg-hover: rgba(15,157,88,.08); }\n\n[data-edrv-view] .edrv-tabs { display: flex; align-items: center; gap: 2px; padding: 2px 8px 0; background: var(--dsw-alias-bg-layer-1, transparent); overflow-x: auto; scrollbar-width: thin; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab { display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 8px 0 12px; border: none; border-radius: 6px 6px 0 0; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 12px; cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-tab.edrv-tab-active { background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); box-shadow: inset 0 -2px 0 var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-tab .edrv-tab-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--dsw-alias-brand-primary, #4f8cff); flex-shrink: 0; }\n[data-edrv-view] .edrv-tab .edrv-tab-x { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; border-radius: 4px; color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; }\n[data-edrv-view] .edrv-tab .edrv-tab-x:hover { background: rgba(255,255,255,.12); color: var(--dsw-alias-label-primary, #eee); }\n[data-edrv-view] .edrv-tab-add { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; margin-left: 2px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 14px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab-add:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-pathbar { display: flex; align-items: center; gap: 8px; height: 26px; padding: 0 10px; background: var(--dsw-alias-bg-layer-1, #ffffff); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 12px; flex-shrink: 0; overflow: hidden; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-name { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-full { flex: 1; min-width: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; direction: rtl; text-align: left; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-meta { flex-shrink: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-status { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-path-input { flex: 1; min-width: 140px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search-wrap { position: relative; flex-shrink: 0; display: flex; align-items: center; padding: 2px 8px 2px 4px; }\n[data-edrv-view] .edrv-search { width: 190px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-pop { position: absolute; top: calc(100% + 4px); right: 8px; width: min(460px, calc(100vw - 24px)); max-height: 300px; overflow: auto; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 10px; box-shadow: 0 6px 20px rgba(0,0,0,.4); z-index: 60; padding: 4px; }\n[data-edrv-view] .edrv-search-item { display: flex; flex-direction: column; gap: 1px; padding: 5px 8px; border-radius: 6px; cursor: pointer; }\n[data-edrv-view] .edrv-search-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.07)); }\n[data-edrv-view] .edrv-search-item .n { color: var(--dsw-alias-label-primary, #eee); font-size: 12px; word-break: break-all; }\n[data-edrv-view] .edrv-search-item .d { color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-search-empty { padding: 8px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #888); }\n[data-edrv-view] .edrv-btn-mini { font-size: 11px; padding: 2px 9px; border: none; border-radius: 999px; cursor: pointer; color: #fff; font-weight: 600; white-space: nowrap; }\n[data-edrv-view] .edrv-btn-keep { background: var(--dsw-alias-state-success-primary, #2e9e44); }\n[data-edrv-view] .edrv-btn-undo { background: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-btn-mini:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-statusbar { display: flex; align-items: center; gap: 10px; padding: 3px 10px; border-top: 1px solid var(--dsw-alias-border-l1, #333); background: var(--dsw-alias-bg-layer-1, transparent); font-size: 11px; color: var(--dsw-alias-label-tertiary, #888); flex-shrink: 0; white-space: nowrap; overflow: hidden; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-path { flex: 1; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-lsp { flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-progress-message { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-statusbar .edrv-sp-progress { flex: 0 0 auto; min-width: 36px; text-align: right; font-variant-numeric: tabular-nums; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-lsp-status-dot { width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto; background: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-lsp-status-dot.ready { background: var(--dsw-alias-state-success-primary, #0f9d58); }\n[data-edrv-view] .edrv-lsp-status-dot.busy { background: var(--dsw-alias-state-warn-primary, #d97706); animation: edrv-lsp-pulse 1.2s ease-in-out infinite; }\n@keyframes edrv-lsp-pulse { 50% { opacity: .45; } }\n/* Ctrl+hover 可导航标识符下划线提示(绑定 Monaco inlineClassName 装饰) */\n[data-edrv-view] .edrv-nav-underline { text-decoration: underline; text-decoration-color: var(--dsw-alias-interactive-primary, #4fc1ff); text-underline-offset: 1px; cursor: pointer; }\n[data-edrv-view] .edrv-diffchip { font-size: 11px; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #333); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-state-warn-primary, #b7791f); cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn { font-size: 12px; padding: 2px 6px; border: none; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; border-radius: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-chip-btn:disabled { opacity: .35; cursor: default; }\n[data-edrv-view] .edrv-chip-btn:disabled:hover { background: transparent; }\n[data-edrv-view] .edrv-mn-add-line { background: rgba(15,157,88,.10); }\n[data-edrv-view] .edrv-mn-gutter-add { color: #0f9d58 !important; font-weight: 700; display: flex !important; align-items: center; justify-content: center; }\n[data-edrv-view] .edrv-mn-gutter-add::before { content: \"+\"; }\n[data-edrv-view] .edrv-del-zone { background: #fdeaea; border-top: 1px solid rgba(217,83,79,.35); border-bottom: 1px solid rgba(217,83,79,.35); box-shadow: inset 0 0 0 1px rgba(217,83,79,.12); }\n[data-edrv-view] .edrv-del-row { white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 12.5px; line-height: 20px; color: #c0392b; }\n[data-edrv-view] .edrv-del-text { display: inline-block; white-space: pre; }\n[data-edrv-view] .edrv-minus-overlay { position: absolute; left: 0; top: 0; width: 100%; height: 100%; max-width: 100%; overflow: visible; pointer-events: none; z-index: 6; }\n[data-edrv-view] .edrv-minus-item { position: absolute; box-sizing: border-box; max-width: 100%; overflow: hidden; }\n[data-edrv-view] .edrv-minus-item::before { content: ''; position: absolute; left: 4px; top: 50%; width: 8px; height: 2px; transform: translateY(-50%); border-radius: 2px; background: #d9534f; }\n[data-edrv-view] .edrv-monaco-host { flex: 1 1 auto; min-width: 0; min-height: 0; position: relative; overflow: hidden; }\n[data-edrv-view] .edrv-monaco-host > div { position: absolute; inset: 0; min-width: 0; min-height: 0; }\n[data-edrv-view] .edrv-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; height: 100%; color: var(--dsw-alias-label-tertiary, #777); font-size: 13px; }\n[data-edrv-view] .edrv-diffbar { position: absolute; left: 0; right: 0; bottom: 10px; margin: 0 auto; z-index: 25; width: fit-content; max-width: calc(100% - 20px); border-radius: 12px; background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, #f0f4f4)); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); box-shadow: none; overflow: visible; display: flex; flex-direction: column; }\n[data-edrv-view] .edrv-editor-area > .edrv-diffbar { max-height: calc(100% - 20px); }\n[data-edrv-view] .edrv-diffbar-row { display: flex; align-items: center; gap: 6px; height: 36px; padding: 4px 5px 4px 12px; flex-wrap: nowrap; }\n[data-edrv-view] .edrv-diffbar-count { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); min-width: 42px; text-align: center; white-space: nowrap; cursor: pointer; }\n[data-edrv-view] .edrv-diffbar-count.edrv-count-file { min-width: 64px; cursor: default; }\n[data-edrv-view] .edrv-diffbar-file { flex: 1; min-width: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-pill { font-size: 11px; padding: 3px 10px; border: none; border-radius: 999px; cursor: pointer; white-space: nowrap; font-weight: 600; }\n[data-edrv-view] .edrv-pill-keep { background: #e8f8e8; color: #0f7a45; border: 1px solid rgba(15,157,88,.4); }\n[data-edrv-view] .edrv-pill-undo { background: #fdeaea; color: #c0392b; border: 1px solid rgba(217,83,79,.4); }\n[data-edrv-view] .edrv-pill-ghost { background: #ffffff; color: var(--dsw-alias-label-secondary, #52606d); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-pill:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-diffbar-menu { position: absolute; right: 8px; bottom: calc(100% + 6px); z-index: 45; min-width: 160px; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 6px 20px rgba(31,41,51,.16); padding: 4px; display: flex; flex-direction: column; gap: 2px; }\n[data-edrv-view] .edrv-diffmenu-item { display: flex; align-items: center; gap: 8px; font-size: 12px; padding: 6px 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; text-align: left; }\n[data-edrv-view] .edrv-diffmenu-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-diffmenu-item.danger { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-diffmenu-sep { height: 1px; margin: 2px 4px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n/* 编辑区 / Tab 右键菜单(添加文件/选中内容到对话) */\n[data-edrv-view] .edrv-ctxmenu { position: fixed; z-index: 71; min-width: 200px; max-width: 320px; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 8px 26px rgba(31,41,51,.2); padding: 4px; display: flex; flex-direction: column; gap: 1px; }\n[data-edrv-view] .edrv-ctxmenu-item { display: flex; align-items: center; gap: 8px; font-size: 12px; line-height: 18px; padding: 7px 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-ctxmenu-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-danger { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-ctxmenu-item:disabled,\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-disabled { color: var(--dsw-alias-label-disabled, #b0b7c0); cursor: default; background: transparent; }\n[data-edrv-view] .edrv-ctxmenu-sep { height: 1px; margin: 3px 4px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-diffbar-body { max-height: 130px; max-width: min(560px, calc(100vw - 40px)); overflow: auto; padding: 4px 8px 8px; display: flex; flex-direction: column; gap: 4px; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-diffrow { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); cursor: pointer; flex-wrap: wrap; }\n[data-edrv-view] .edrv-diffrow:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-diffrow-l { font-size: 11px; color: var(--dsw-alias-label-primary, #1f2933); min-width: 74px; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-o { font-size: 11px; color: var(--dsw-alias-state-error-primary, #d9534f); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-n { font-size: 11px; color: var(--dsw-alias-state-success-primary, #0f9d58); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-tag { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-diffrow-stale { border-color: rgba(217,119,6,.5); cursor: default; }\n[data-edrv-view] .edrv-diffbox-others { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; padding: 4px 2px 0; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); margin-top: 2px; }\n[data-edrv-view] .edrv-diffrow-file { font-size: 11px; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); cursor: pointer; white-space: nowrap; max-width: 200px; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-diffrow-file:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n/* 编辑区 hover 差异块的 Keep/Undo 浮层 */\n[data-edrv-view] .edrv-hoveract { position: absolute; z-index: 30; display: flex; align-items: center; gap: 4px; padding: 2px 6px; border-radius: 8px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 4px 14px rgba(31,41,51,.14); }\n[data-edrv-view] .edrv-launch { position: absolute; left: 12px; right: 12px; bottom: 12px; z-index: 40; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); box-shadow: 0 6px 24px rgba(0,0,0,.5); display: flex; flex-direction: column; max-height: 60%; overflow: hidden; }\n[data-edrv-view] .edrv-launch-head { display: flex; align-items: center; gap: 6px; padding: 6px 8px; border-bottom: 1px solid var(--dsw-alias-border-l1, #333); }\n[data-edrv-view] .edrv-launch-tab { font-size: 12px; padding: 3px 12px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; }\n[data-edrv-view] .edrv-launch-tab.on { background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-label-primary, #eee); font-weight: 600; }\n[data-edrv-view] .edrv-launch-body { flex: 1; min-height: 0; overflow: auto; padding: 6px 8px; display: flex; flex-direction: column; gap: 4px; }\n[data-edrv-view] .edrv-launch-row { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1, #333); border-radius: 6px; cursor: pointer; flex-wrap: wrap; }\n[data-edrv-view] .edrv-launch-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-launch-path { flex: 1; min-width: 0; font-size: 12px; color: var(--dsw-alias-label-primary, #eee); word-break: break-all; }\n[data-edrv-view] .edrv-launch-cnt { font-size: 11px; color: var(--dsw-alias-label-tertiary, #888); white-space: nowrap; }\n[data-edrv-view] .edrv-launch-arch { display: flex; flex-direction: column; gap: 6px; }\n[data-edrv-view] .monaco-editor { overflow: hidden !important; }\n[data-edrv-view] .monaco-editor .sticky-widget { z-index: 30 !important; background: var(--dsw-alias-bg-base, #f8f8f8) !important; }\n[data-edrv-view] .monaco-editor .sticky-widget .sticky-line-content,\n[data-edrv-view] .monaco-editor .sticky-widget .sticky-line-number { background: var(--dsw-alias-bg-base, #f8f8f8) !important; }\n[data-edrv-view] .monaco-editor, [data-edrv-view] .monaco-editor .margin, [data-edrv-view] .monaco-editor-background { background: transparent !important; }\n[data-edrv-view] .monaco-editor .scrollbar .slider { background: rgba(128,128,128,.3) !important; }\n[data-edrv-view] .edrv-loading { gap: 8px; padding: 20px; }\n[data-edrv-view] .edrv-loading-title { color: var(--dsw-alias-label-primary, #1f2933); font-size: 13px; }\n[data-edrv-view] .edrv-progress { width: min(360px, 72%); height: 6px; overflow: hidden; border-radius: 999px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-progress-value { height: 100%; border-radius: inherit; background: var(--dsw-alias-brand-primary, #0f9d58); transition: width .24s ease; }\n[data-edrv-view] .edrv-loading-percent { color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; font-variant-numeric: tabular-nums; }\n@media (prefers-reduced-motion: reduce) {\n [data-edrv-view] .edrv-progress-value { transition: none; }\n}\n\n/* ===== 唯一会话级差异 dock(遵循 DSH todo/queue 原生布局) ===== */\n[data-edrv-diff-dock-shell] {\n box-sizing: border-box;\n width: calc(100% - var(--dsh-composer-side-clearance) - var(--dsh-composer-side-clearance) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));\n max-width: calc(var(--dsh-composer-card-max-width) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));\n margin: 0 auto;\n padding: 0;\n flex: none;\n border: 1px solid var(--dsw-alias-border-l1, #e0e6e8);\n border-radius: 12px;\n background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, transparent));\n box-shadow: none;\n overflow: hidden;\n}\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock {\n box-sizing: border-box;\n position: relative;\n left: auto;\n right: auto;\n bottom: auto;\n z-index: auto;\n width: 100%;\n max-width: none;\n margin: 0;\n display: flex;\n flex-direction: column;\n border: none;\n border-radius: 0;\n background: transparent;\n box-shadow: none;\n overflow: visible;\n}\n[data-edrv-diff-dock-shell] .edrv-diffbar-row { min-height: 36px; padding: 6px 12px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-row { min-height: 36px; padding: 6px 12px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-body { max-height: 180px; overflow: auto; padding: 6px 12px 10px; border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-button { box-sizing: border-box; display: flex; align-items: center; justify-content: center; width: 100%; height: 24px; border: none; border-radius: 8px; padding: 0 12px; background: transparent; color: var(--dsw-alias-label-primary); font-size: 13px; font-weight: 500; line-height: 24px; text-align: center; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-button:hover { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diffbar-count { display: inline-flex; align-items: center; color: var(--dsw-alias-label-primary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 500; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-file { display: inline-flex; align-items: center; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-editor-row { display: flex; align-items: center; height: 36px; min-height: 36px; padding: 4px 12px; overflow-x: auto; scrollbar-width: thin; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-editor-content { display: flex; align-items: center; gap: 10px; width: 100%; min-width: max-content; min-height: 28px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-nav,\n[data-edrv-diff-dock-shell] .edrv-diffbar-files,\n[data-edrv-diff-dock-shell] .edrv-diffbar-actions { display: flex; align-items: center; gap: 6px; flex: none; height: 28px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-actions { margin-left: auto; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-details-toggle { display: inline-flex; align-items: center; justify-content: center; width: 28px; min-width: 28px; padding: 0; font-size: 13px; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-details-toggle svg { width: 14px; height: 14px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-files { min-width: 0; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-files .edrv-diffbar-file { min-width: 72px; max-width: 240px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-progress { min-width: 0; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; font-variant-numeric: tabular-nums; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-summary { min-width: 0; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-pill { box-sizing: border-box; height: 28px; padding: 0 9px; border: none; border-radius: 999px; cursor: pointer; white-space: nowrap; font-size: 11px; line-height: 26px; font-weight: 600; }\n[data-edrv-diff-dock-shell] .edrv-pill-keep { background: var(--dsw-alias-state-success-tertiary); color: var(--dsw-alias-state-success-primary); border: 1px solid var(--dsw-alias-state-success-secondary); }\n[data-edrv-diff-dock-shell] .edrv-pill-undo { background: var(--dsw-alias-state-error-tertiary); color: var(--dsw-alias-state-error-primary); border: 1px solid var(--dsw-alias-state-error-secondary); }\n[data-edrv-diff-dock-shell] .edrv-pill-ghost { background: transparent; color: var(--dsw-alias-label-secondary); border: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-pill:hover:not(:disabled) { background-color: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-pill:focus-visible { outline: 2px solid var(--dsw-alias-label-tertiary); outline-offset: -2px; }\n[data-edrv-diff-dock-shell] .edrv-pill:disabled { opacity: .45; cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diffrow { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; background: transparent; cursor: pointer; flex-wrap: wrap; }\n[data-edrv-diff-dock-shell] .edrv-diffrow:hover { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-l { color: var(--dsw-alias-label-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-o { color: var(--dsw-alias-state-error-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-n { color: var(--dsw-alias-state-success-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-tag { color: var(--dsw-alias-label-tertiary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-stale { border-color: var(--dsw-alias-state-warn-secondary); cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diffbox-others { border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-file { border-color: var(--dsw-alias-border-l1); background: transparent; color: var(--dsw-alias-label-secondary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-file:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }\n[data-edrv-diff-dock-shell] .edrv-diff-details { display: flex; flex-direction: column; gap: 2px; padding: 6px 12px 8px; border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item { display: flex; align-items: center; width: 100%; min-height: 28px; gap: 8px; padding: 4px 8px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary); cursor: pointer; text-align: left; font-size: 12px; line-height: 20px; }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item.danger { color: var(--dsw-alias-state-error-primary); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item:disabled { opacity: .45; cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-sep { height: 1px; margin: 2px 4px; background: var(--dsw-alias-border-l1); }\n@media (max-width: 620px) {\n [data-edrv-diff-dock-shell] .edrv-diffbar-editor-content { width: max-content; }\n [data-edrv-diff-dock-shell] .edrv-diffbar-files .edrv-diffbar-file { max-width: 160px; }\n}\n\n/* ===== 侧边栏(活动栏 + 面板区 + 文件树) ===== */\n[data-edrv-view] .edrv-editor-row { display: flex; flex: 1 1 auto; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-main-col { box-sizing: border-box; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-main-col > .edrv-pathbar,\n[data-edrv-view] .edrv-main-col > .edrv-tabs { flex: 0 0 auto; }\n[data-edrv-view] .edrv-editor-area { position: relative; display: flex; flex: 1 1 auto; flex-direction: column; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-sidebar { display: flex; flex-direction: row; flex-shrink: 0; 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\n\n";
33
+ const css$1 = "/* dsh-vscode-mode 编辑区样式(原 ensureEdrvStyles 字符串,落盘为真 .css,由 tsdown CSS-inline 注入) */\n/* 浅色主题(对齐参考图:#f8f8f8 近白底 + 薄荷绿药丸 + 青绿文字 + 三文鱼 undo + 浅灰边框):\n 在 [data-edrv-view] 作用域内重定义 --dsw-alias-*,级联命中组件内联样式与 CSS。 */\n[data-edrv-view] { box-sizing: border-box; --edrv-tab-h: 34px; --dsw-alias-bg-base: #f8f8f8; --dsw-alias-bg-layer-1: #ffffff; --dsw-alias-bg-layer-2: #f0f4f4; --dsw-alias-bg-overlay: #ffffff; --dsw-alias-label-primary: #1f2933; --dsw-alias-label-secondary: #52606d; --dsw-alias-label-tertiary: #9aa5b1; --dsw-alias-border-l1: #e0e6e8; --dsw-alias-border-l2: #cbd2d9; --dsw-alias-brand-primary: #0f9d58; --dsw-alias-state-success-primary: #0f9d58; --dsw-alias-state-error-primary: #d9534f; --dsw-alias-state-warn-primary: #d97706; --dsw-alias-interactive-bg-hover: rgba(15,157,88,.08); }\n\n[data-edrv-view] .edrv-tabs { display: flex; align-items: center; gap: 2px; padding: 2px 8px 0; background: var(--dsw-alias-bg-layer-1, transparent); overflow-x: auto; scrollbar-width: thin; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab { display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 8px 0 12px; border: none; border-radius: 6px 6px 0 0; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 12px; cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-tab.edrv-tab-active { background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); box-shadow: inset 0 -2px 0 var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-tab .edrv-tab-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--dsw-alias-brand-primary, #4f8cff); flex-shrink: 0; }\n[data-edrv-view] .edrv-tab .edrv-tab-x { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; border-radius: 4px; color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; }\n[data-edrv-view] .edrv-tab .edrv-tab-x:hover { background: rgba(255,255,255,.12); color: var(--dsw-alias-label-primary, #eee); }\n[data-edrv-view] .edrv-tab-add { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; margin-left: 2px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 14px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab-add:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-pathbar { display: flex; align-items: center; gap: 8px; height: 26px; padding: 0 10px; background: var(--dsw-alias-bg-layer-1, #ffffff); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 12px; flex-shrink: 0; overflow: hidden; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-name { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-full { flex: 1; min-width: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; direction: rtl; text-align: left; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-meta { flex-shrink: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-status { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-path-input { flex: 1; min-width: 140px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search-wrap { position: relative; flex-shrink: 0; display: flex; align-items: center; padding: 2px 8px 2px 4px; }\n[data-edrv-view] .edrv-search { width: 190px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-pop { position: absolute; top: calc(100% + 4px); right: 8px; width: min(460px, calc(100vw - 24px)); max-height: 300px; overflow: auto; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 10px; box-shadow: 0 6px 20px rgba(0,0,0,.4); z-index: 60; padding: 4px; }\n[data-edrv-view] .edrv-search-item { display: flex; flex-direction: column; gap: 1px; padding: 5px 8px; border-radius: 6px; cursor: pointer; }\n[data-edrv-view] .edrv-search-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.07)); }\n[data-edrv-view] .edrv-search-item .n { color: var(--dsw-alias-label-primary, #eee); font-size: 12px; word-break: break-all; }\n[data-edrv-view] .edrv-search-item .d { color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-search-empty { padding: 8px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #888); }\n[data-edrv-view] .edrv-btn-mini { font-size: 11px; padding: 2px 9px; border: none; border-radius: 999px; cursor: pointer; color: #fff; font-weight: 600; white-space: nowrap; }\n[data-edrv-view] .edrv-btn-keep { background: var(--dsw-alias-state-success-primary, #2e9e44); }\n[data-edrv-view] .edrv-btn-undo { background: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-btn-mini:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-statusbar { display: flex; align-items: center; gap: 10px; padding: 3px 10px; border-top: 1px solid var(--dsw-alias-border-l1, #333); background: var(--dsw-alias-bg-layer-1, transparent); font-size: 11px; color: var(--dsw-alias-label-tertiary, #888); flex-shrink: 0; white-space: nowrap; overflow: hidden; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-path { flex: 1; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-lsp { flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-progress-message { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-statusbar .edrv-sp-progress { flex: 0 0 auto; min-width: 36px; text-align: right; font-variant-numeric: tabular-nums; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-lsp-status-dot { width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto; background: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-lsp-status-dot.ready { background: var(--dsw-alias-state-success-primary, #0f9d58); }\n[data-edrv-view] .edrv-lsp-status-dot.busy { background: var(--dsw-alias-state-warn-primary, #d97706); animation: edrv-lsp-pulse 1.2s ease-in-out infinite; }\n@keyframes edrv-lsp-pulse { 50% { opacity: .45; } }\n/* Ctrl+hover 可导航标识符下划线提示(绑定 Monaco inlineClassName 装饰) */\n[data-edrv-view] .edrv-nav-underline { text-decoration: underline; text-decoration-color: var(--dsw-alias-interactive-primary, #4fc1ff); text-underline-offset: 1px; cursor: pointer; }\n[data-edrv-view] .edrv-diffchip { font-size: 11px; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #333); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-state-warn-primary, #b7791f); cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn { font-size: 12px; padding: 2px 6px; border: none; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; border-radius: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-chip-btn:disabled { opacity: .35; cursor: default; }\n[data-edrv-view] .edrv-chip-btn:disabled:hover { background: transparent; }\n[data-edrv-view] .edrv-mn-add-line { background: rgba(15,157,88,.10); }\n[data-edrv-view] .edrv-mn-gutter-add { color: #0f9d58 !important; font-weight: 700; display: flex !important; align-items: center; justify-content: center; }\n[data-edrv-view] .edrv-mn-gutter-add::before { content: \"+\"; }\n[data-edrv-view] .edrv-del-zone { background: #fdeaea; border-top: 1px solid rgba(217,83,79,.35); border-bottom: 1px solid rgba(217,83,79,.35); box-shadow: inset 0 0 0 1px rgba(217,83,79,.12); }\n[data-edrv-view] .edrv-del-row { white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 12.5px; line-height: 20px; color: #c0392b; }\n[data-edrv-view] .edrv-del-text { display: inline-block; white-space: pre; }\n[data-edrv-view] .edrv-minus-overlay { position: absolute; left: 0; top: 0; width: 100%; height: 100%; max-width: 100%; overflow: visible; pointer-events: none; z-index: 6; }\n[data-edrv-view] .edrv-minus-item { position: absolute; box-sizing: border-box; max-width: 100%; overflow: hidden; }\n[data-edrv-view] .edrv-minus-item::before { content: ''; position: absolute; left: 4px; top: 50%; width: 8px; height: 2px; transform: translateY(-50%); border-radius: 2px; background: #d9534f; }\n[data-edrv-view] .edrv-monaco-host { flex: 1 1 auto; min-width: 0; min-height: 0; position: relative; overflow: hidden; }\n[data-edrv-view] .edrv-monaco-host > div { position: absolute; inset: 0; min-width: 0; min-height: 0; }\n[data-edrv-view] .edrv-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; height: 100%; color: var(--dsw-alias-label-tertiary, #777); font-size: 13px; }\n[data-edrv-view] .edrv-diffbar { position: absolute; left: 0; right: 0; bottom: 10px; margin: 0 auto; z-index: 25; width: fit-content; max-width: calc(100% - 20px); border-radius: 12px; background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, #f0f4f4)); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); box-shadow: none; overflow: visible; display: flex; flex-direction: column; }\n[data-edrv-view] .edrv-editor-area > .edrv-diffbar { max-height: calc(100% - 20px); }\n[data-edrv-view] .edrv-diffbar-row { display: flex; align-items: center; gap: 6px; height: 36px; padding: 4px 5px 4px 12px; flex-wrap: nowrap; }\n[data-edrv-view] .edrv-diffbar-count { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); min-width: 42px; text-align: center; white-space: nowrap; cursor: pointer; }\n[data-edrv-view] .edrv-diffbar-count.edrv-count-file { min-width: 64px; cursor: default; }\n[data-edrv-view] .edrv-diffbar-file { flex: 1; min-width: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-pill { font-size: 11px; padding: 3px 10px; border: none; border-radius: 999px; cursor: pointer; white-space: nowrap; font-weight: 600; }\n[data-edrv-view] .edrv-pill-keep { background: #e8f8e8; color: #0f7a45; border: 1px solid rgba(15,157,88,.4); }\n[data-edrv-view] .edrv-pill-undo { background: #fdeaea; color: #c0392b; border: 1px solid rgba(217,83,79,.4); }\n[data-edrv-view] .edrv-pill-ghost { background: #ffffff; color: var(--dsw-alias-label-secondary, #52606d); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-pill:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-diffbar-menu { position: absolute; right: 8px; bottom: calc(100% + 6px); z-index: 45; min-width: 160px; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 6px 20px rgba(31,41,51,.16); padding: 4px; display: flex; flex-direction: column; gap: 2px; }\n[data-edrv-view] .edrv-diffmenu-item { display: flex; align-items: center; gap: 8px; font-size: 12px; padding: 6px 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; text-align: left; }\n[data-edrv-view] .edrv-diffmenu-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-diffmenu-item.danger { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-diffmenu-sep { height: 1px; margin: 2px 4px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n/* 编辑区 / Tab 右键菜单(添加文件/选中内容到对话) */\n[data-edrv-view] .edrv-ctxmenu { position: fixed; z-index: 71; min-width: 200px; max-width: 320px; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 8px 26px rgba(31,41,51,.2); padding: 4px; display: flex; flex-direction: column; gap: 1px; }\n[data-edrv-view] .edrv-ctxmenu-item { display: flex; align-items: center; gap: 8px; font-size: 12px; line-height: 18px; padding: 7px 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-ctxmenu-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-danger { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-ctxmenu-item:disabled,\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-disabled { color: var(--dsw-alias-label-disabled, #b0b7c0); cursor: default; background: transparent; }\n[data-edrv-view] .edrv-ctxmenu-sep { height: 1px; margin: 3px 4px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-diffbar-body { max-height: 130px; max-width: min(560px, calc(100vw - 40px)); overflow: auto; padding: 4px 8px 8px; display: flex; flex-direction: column; gap: 4px; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-diffrow { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); cursor: pointer; flex-wrap: wrap; }\n[data-edrv-view] .edrv-diffrow:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-diffrow-l { font-size: 11px; color: var(--dsw-alias-label-primary, #1f2933); min-width: 74px; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-o { font-size: 11px; color: var(--dsw-alias-state-error-primary, #d9534f); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-n { font-size: 11px; color: var(--dsw-alias-state-success-primary, #0f9d58); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-tag { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-diffrow-stale { border-color: rgba(217,119,6,.5); cursor: default; }\n[data-edrv-view] .edrv-diffbox-others { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; padding: 4px 2px 0; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); margin-top: 2px; }\n[data-edrv-view] .edrv-diffrow-file { font-size: 11px; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); cursor: pointer; white-space: nowrap; max-width: 200px; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-diffrow-file:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n/* 编辑区 hover 差异块的 Keep/Undo 浮层 */\n[data-edrv-view] .edrv-hoveract { position: absolute; z-index: 30; display: flex; align-items: center; gap: 4px; padding: 2px 6px; border-radius: 8px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 4px 14px rgba(31,41,51,.14); }\n[data-edrv-view] .edrv-launch { position: absolute; left: 12px; right: 12px; bottom: 12px; z-index: 40; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); box-shadow: 0 6px 24px rgba(0,0,0,.5); display: flex; flex-direction: column; max-height: 60%; overflow: hidden; }\n[data-edrv-view] .edrv-launch-head { display: flex; align-items: center; gap: 6px; padding: 6px 8px; border-bottom: 1px solid var(--dsw-alias-border-l1, #333); }\n[data-edrv-view] .edrv-launch-tab { font-size: 12px; padding: 3px 12px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; }\n[data-edrv-view] .edrv-launch-tab.on { background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-label-primary, #eee); font-weight: 600; }\n[data-edrv-view] .edrv-launch-body { flex: 1; min-height: 0; overflow: auto; padding: 6px 8px; display: flex; flex-direction: column; gap: 4px; }\n[data-edrv-view] .edrv-launch-row { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1, #333); border-radius: 6px; cursor: pointer; flex-wrap: wrap; }\n[data-edrv-view] .edrv-launch-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-launch-path { flex: 1; min-width: 0; font-size: 12px; color: var(--dsw-alias-label-primary, #eee); word-break: break-all; }\n[data-edrv-view] .edrv-launch-cnt { font-size: 11px; color: var(--dsw-alias-label-tertiary, #888); white-space: nowrap; }\n[data-edrv-view] .edrv-launch-arch { display: flex; flex-direction: column; gap: 6px; }\n[data-edrv-view] .monaco-editor { overflow: hidden !important; }\n[data-edrv-view] .monaco-editor .sticky-widget { z-index: 30 !important; background: var(--dsw-alias-bg-base, #f8f8f8) !important; }\n[data-edrv-view] .monaco-editor .sticky-widget .sticky-line-content,\n[data-edrv-view] .monaco-editor .sticky-widget .sticky-line-number { background: var(--dsw-alias-bg-base, #f8f8f8) !important; }\n[data-edrv-view] .monaco-editor, [data-edrv-view] .monaco-editor .margin, [data-edrv-view] .monaco-editor-background { background: transparent !important; }\n[data-edrv-view] .monaco-editor .scrollbar .slider { background: rgba(128,128,128,.3) !important; }\n[data-edrv-view] .edrv-loading { gap: 8px; padding: 20px; }\n[data-edrv-view] .edrv-loading-title { color: var(--dsw-alias-label-primary, #1f2933); font-size: 13px; }\n[data-edrv-view] .edrv-progress { width: min(360px, 72%); height: 6px; overflow: hidden; border-radius: 999px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-progress-value { height: 100%; border-radius: inherit; background: var(--dsw-alias-brand-primary, #0f9d58); transition: width .24s ease; }\n[data-edrv-view] .edrv-loading-percent { color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; font-variant-numeric: tabular-nums; }\n@media (prefers-reduced-motion: reduce) {\n [data-edrv-view] .edrv-progress-value { transition: none; }\n}\n\n/* ===== 唯一会话级差异 dock(遵循 DSH todo/queue 原生布局) ===== */\n[data-edrv-diff-dock-shell] {\n box-sizing: border-box;\n width: calc(100% - var(--dsh-composer-side-clearance) - var(--dsh-composer-side-clearance) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));\n max-width: calc(var(--dsh-composer-card-max-width) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));\n margin: 0 auto;\n padding: 0;\n flex: none;\n border: 1px solid var(--dsw-alias-border-l1, #e0e6e8);\n border-radius: 12px;\n background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, transparent));\n box-shadow: none;\n overflow: hidden;\n}\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock {\n box-sizing: border-box;\n position: relative;\n left: auto;\n right: auto;\n bottom: auto;\n z-index: auto;\n width: 100%;\n max-width: none;\n margin: 0;\n display: flex;\n flex-direction: column;\n border: none;\n border-radius: 0;\n background: transparent;\n box-shadow: none;\n overflow: visible;\n}\n[data-edrv-diff-dock-shell] .edrv-diffbar-row { min-height: 36px; padding: 6px 12px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-row { min-height: 36px; padding: 6px 12px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-body { max-height: 180px; overflow: auto; padding: 6px 12px 10px; border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-button { box-sizing: border-box; display: flex; align-items: center; justify-content: center; width: 100%; height: 24px; border: none; border-radius: 8px; padding: 0 12px; background: transparent; color: var(--dsw-alias-label-primary); font-size: 13px; font-weight: 500; line-height: 24px; text-align: center; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-button:hover { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diffbar-count { display: inline-flex; align-items: center; color: var(--dsw-alias-label-primary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 500; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-file { display: inline-flex; align-items: center; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-editor-row { display: flex; align-items: center; height: 36px; min-height: 36px; padding: 4px 12px; overflow-x: auto; scrollbar-width: thin; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-editor-content { display: flex; align-items: center; gap: 10px; width: 100%; min-width: max-content; min-height: 28px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-nav,\n[data-edrv-diff-dock-shell] .edrv-diffbar-files,\n[data-edrv-diff-dock-shell] .edrv-diffbar-actions { display: flex; align-items: center; gap: 6px; flex: none; height: 28px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-actions { margin-left: auto; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-details-toggle { display: inline-flex; align-items: center; justify-content: center; width: 28px; min-width: 28px; padding: 0; font-size: 13px; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-details-toggle svg { width: 14px; height: 14px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-files { min-width: 0; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-files .edrv-diffbar-file { min-width: 72px; max-width: 240px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-progress { min-width: 0; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; font-variant-numeric: tabular-nums; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-summary { min-width: 0; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-pill { box-sizing: border-box; height: 28px; padding: 0 9px; border: none; border-radius: 999px; cursor: pointer; white-space: nowrap; font-size: 11px; line-height: 26px; font-weight: 600; }\n[data-edrv-diff-dock-shell] .edrv-pill-keep { background: var(--dsw-alias-state-success-tertiary); color: var(--dsw-alias-state-success-primary); border: 1px solid var(--dsw-alias-state-success-secondary); }\n[data-edrv-diff-dock-shell] .edrv-pill-undo { background: var(--dsw-alias-state-error-tertiary); color: var(--dsw-alias-state-error-primary); border: 1px solid var(--dsw-alias-state-error-secondary); }\n[data-edrv-diff-dock-shell] .edrv-pill-ghost { background: transparent; color: var(--dsw-alias-label-secondary); border: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-pill:hover:not(:disabled) { background-color: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-pill:focus-visible { outline: 2px solid var(--dsw-alias-label-tertiary); outline-offset: -2px; }\n[data-edrv-diff-dock-shell] .edrv-pill:disabled { opacity: .45; cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diffrow { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; background: transparent; cursor: pointer; flex-wrap: wrap; }\n[data-edrv-diff-dock-shell] .edrv-diffrow:hover { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-l { color: var(--dsw-alias-label-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-o { color: var(--dsw-alias-state-error-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-n { color: var(--dsw-alias-state-success-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-tag { color: var(--dsw-alias-label-tertiary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-stale { border-color: var(--dsw-alias-state-warn-secondary); cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diffbox-others { border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-file { border-color: var(--dsw-alias-border-l1); background: transparent; color: var(--dsw-alias-label-secondary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-file:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }\n[data-edrv-diff-dock-shell] .edrv-diff-details { display: flex; flex-direction: column; gap: 2px; padding: 6px 12px 8px; border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item { display: flex; align-items: center; width: 100%; min-height: 28px; gap: 8px; padding: 4px 8px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary); cursor: pointer; text-align: left; font-size: 12px; line-height: 20px; }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item.danger { color: var(--dsw-alias-state-error-primary); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item:disabled { opacity: .45; cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-sep { height: 1px; margin: 2px 4px; background: var(--dsw-alias-border-l1); }\n@media (max-width: 620px) {\n [data-edrv-diff-dock-shell] .edrv-diffbar-editor-content { width: max-content; }\n [data-edrv-diff-dock-shell] .edrv-diffbar-files .edrv-diffbar-file { max-width: 160px; }\n}\n\n/* ===== 侧边栏(活动栏 + 面板区 + 文件树) ===== */\n[data-edrv-view] .edrv-editor-row { display: flex; flex: 1 1 auto; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-main-col { box-sizing: border-box; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-main-col > .edrv-pathbar,\n[data-edrv-view] .edrv-main-col > .edrv-tabs { flex: 0 0 auto; }\n[data-edrv-view] .edrv-editor-area { position: relative; display: flex; flex: 1 1 auto; flex-direction: column; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-sidebar { display: flex; flex-direction: row; flex-shrink: 1; min-width: 0; height: 100%; background: var(--dsw-alias-bg-layer-1, #ffffff); border-right: 1px solid var(--dsw-alias-border-l1, #e0e6e8); overflow: hidden; }\n[data-edrv-view] .edrv-rail { display: flex; flex-direction: column; align-items: center; width: 44px; flex-shrink: 0; padding: 6px 0; background: var(--dsw-alias-bg-layer-2, #f0f4f4); border-right: 1px solid var(--dsw-alias-border-l1, #e0e6e8); gap: 4px; }\n[data-edrv-view] .edrv-rail-btn { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border: none; border-radius: 8px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-rail-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rail-btn.edrv-rail-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-label-primary, #1f2933); box-shadow: inset 2px 0 0 var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-rail-icon { font-size: 15px; line-height: 1; }\n[data-edrv-view] .edrv-rail-badge { position: absolute; top: 2px; right: 2px; min-width: 14px; height: 14px; padding: 0 3px; border-radius: 999px; background: var(--dsw-alias-brand-primary, #0f9d58); color: #fff; font-size: 9px; font-weight: 600; line-height: 14px; text-align: center; box-sizing: border-box; }\n[data-edrv-view] .edrv-side-body { flex: 1; min-width: 0; min-height: 0; display: flex; overflow: hidden; }\n[data-edrv-view] .edrv-side-panel { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; position: relative; }\n[data-edrv-view] .edrv-side-head { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px 0 12px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); flex-shrink: 0; }\n[data-edrv-view] .edrv-side-title { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-side-root { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-side-btn { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-side-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-tree { flex: 1; min-height: 0; overflow: auto; padding: 4px 6px 12px; font-size: 12px; }\n[data-edrv-view] .edrv-tree-row { display: flex; align-items: center; gap: 4px; height: 22px; padding-right: 6px; border-radius: 5px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-tree-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-active { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-context { box-shadow: inset 0 0 0 1px var(--dsw-alias-brand-primary, #0f9d58); background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); }\n[data-edrv-view] .edrv-tree-chev { width: 12px; flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; text-align: center; }\n[data-edrv-view] .edrv-tree-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-tree-name.edrv-tree-dim { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-tree-badge { min-width: 14px; height: 14px; padding: 0 4px; border-radius: 999px; background: var(--dsw-alias-state-warn-primary, #d97706); color: #fff; font-size: 9px; font-weight: 600; line-height: 14px; text-align: center; box-sizing: border-box; flex-shrink: 0; }\n[data-edrv-view] .edrv-tree-loading { height: 22px; line-height: 22px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-tree-error { display: flex; align-items: center; gap: 8px; margin: 4px 2px 6px; padding: 6px 8px; border: 1px solid rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n/* 大纲面板:kind 字形 / detail / 行号 */\n[data-edrv-view] .edrv-outline-kind { display: inline-flex; align-items: center; justify-content: center; width: 14px; flex-shrink: 0; font-size: 12px; font-weight: 600; text-align: center; }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-func { color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-type { color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-data { color: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-ns { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-key { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-outline-detail { flex-shrink: 0; max-width: 40%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-outline-ln { flex-shrink: 0; padding-right: 2px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-side-resize { width: 5px; flex-shrink: 0; cursor: col-resize; background: transparent; }\n[data-edrv-view] .edrv-side-resize:hover { background: var(--dsw-alias-brand-primary, #0f9d58); opacity: .35; }\n[data-edrv-view] .edrv-chip-btn.edrv-chip-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-label-primary, #1f2933); }\n\n/* ===== 侧栏形态(betterSidebar 面板内编辑区) ===== */\n[data-edrv-view][data-edrv-layout='side'] { box-sizing: border-box; height: 100%; }\n\n/* ===== 侧边栏引导条(旧页签形态、未装 betterSidebar 时) ===== */\n[data-edrv-view] .edrv-side-hint { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; flex-wrap: wrap; padding: 6px 12px; font-size: 12px; color: var(--dsw-alias-label-secondary, #52606d); background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, #f0f4f4)); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-side-hint-text { white-space: nowrap; }\n[data-edrv-view] .edrv-side-hint-cmd { font-size: 11px; padding: 2px 6px; border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #ffffff); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-side-hint-close { margin-left: auto; border: none; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); cursor: pointer; font-size: 14px; line-height: 1; padding: 2px 6px; border-radius: 6px; flex-shrink: 0; }\n[data-edrv-view] .edrv-side-hint-close:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n\n/* ===== search panel (sidebar, VSCode search view) ===== */\n[data-edrv-view] .edrv-search-panel { display: flex; flex-direction: column; min-height: 0; flex: 1; padding: 6px; gap: 4px; }\n[data-edrv-view] .edrv-search-qrow { display: flex; gap: 4px; }\n[data-edrv-view] .edrv-search-input { flex: 1; min-width: 0; height: 26px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search-input:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-opts { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-search-opt { min-width: 24px; height: 22px; padding: 0 6px; border: 1px solid transparent; border-radius: 5px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 11px; font-family: var(--ds-font-family-code, ui-monospace, monospace); cursor: pointer; }\n[data-edrv-view] .edrv-search-opt:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-opt.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); border-color: var(--dsw-alias-border-l2, #d5dde3); }\n[data-edrv-view] .edrv-search-spacer { flex: 1; }\n[data-edrv-view] .edrv-search-summary { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); padding: 2px 4px; }\n[data-edrv-view] .edrv-search-results { flex: 1; min-height: 0; overflow: auto; font-size: 12px; }\n[data-edrv-view] .edrv-search-group { margin-bottom: 2px; }\n[data-edrv-view] .edrv-search-file { display: flex; align-items: center; gap: 4px; height: 22px; padding: 0 4px; border-radius: 5px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-search-file:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-chev { width: 12px; flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; text-align: center; }\n[data-edrv-view] .edrv-search-fname { font-weight: 600; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-search-fdir { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-search-fcount { flex-shrink: 0; min-width: 16px; height: 15px; padding: 0 4px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); font-size: 10px; line-height: 15px; text-align: center; }\n[data-edrv-view] .edrv-search-line { display: flex; gap: 6px; padding: 1px 4px 1px 16px; border-radius: 4px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; overflow: hidden; }\n[data-edrv-view] .edrv-search-line.alt { background: var(--dsw-alias-bg-layer-1, #ffffff); }\n[data-edrv-view] .edrv-search-line:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-ln { flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; min-width: 26px; text-align: right; user-select: none; }\n[data-edrv-view] .edrv-search-text { overflow: hidden; text-overflow: ellipsis; white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; }\n[data-edrv-view] .edrv-search-hit { background: var(--dsw-alias-state-warn-primary, #e5b93f); color: #1f2933; border-radius: 2px; padding: 0 1px; }\n[data-edrv-view] .edrv-search-empty { padding: 8px 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-search-error { padding: 6px 8px; border: 1px solid rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n[data-edrv-view] .edrv-search-warn { padding: 6px 8px; border: 1px solid rgba(240,173,78,.45); border-radius: 6px; background: #fdf6e3; color: #b8860b; font-size: 11px; word-break: break-all; }\n\n/* include/exclude filter rows (collapsible) */\n[data-edrv-view] .edrv-search-rows { display: flex; flex-direction: column; gap: 4px; padding: 2px 0 4px; }\n[data-edrv-view] .edrv-search-row { display: flex; align-items: center; gap: 4px; }\n[data-edrv-view] .edrv-search-field { flex: 1; min-width: 0; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 11px; outline: none; }\n[data-edrv-view] .edrv-search-field:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-field.dim { opacity: .45; }\n[data-edrv-view] .edrv-search-field::placeholder { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-search-toggle { min-width: 24px; height: 24px; padding: 0 5px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; line-height: 1; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-search-toggle:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-toggle.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); border-color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-search-toggle:disabled { opacity: .4; cursor: default; }\n\n/* ===== rules panel (sidebar, Codebuddy rules view) ===== */\n[data-edrv-view] .edrv-rules-panel { display: flex; flex-direction: column; min-width: 0; min-height: 0; flex: 1; padding: 6px; gap: 4px; }\n[data-edrv-view] .edrv-rules-tabs { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-tab { height: 24px; padding: 0 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; cursor: pointer; }\n[data-edrv-view] .edrv-rules-tab:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-tab.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); font-weight: 600; }\n[data-edrv-view] .edrv-rules-new { margin-left: auto; height: 24px; padding: 0 10px; border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-new:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-ws-line { font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); padding: 0 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 0 0 auto; user-select: none; }\n[data-edrv-view] .edrv-rules-hint { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); padding: 0 2px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-list { flex: 1; min-height: 0; overflow: auto; }\n[data-edrv-view] .edrv-rules-row { display: flex; align-items: center; gap: 4px; padding: 6px 4px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; }\n[data-edrv-view] .edrv-rules-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-row.off .edrv-rules-main { opacity: .5; }\n[data-edrv-view] .edrv-rules-main { flex: 1; min-width: 0; cursor: pointer; overflow: hidden; }\n[data-edrv-view] .edrv-rules-line1 { display: flex; align-items: center; gap: 6px; min-width: 0; }\n[data-edrv-view] .edrv-rules-sub { display: flex; align-items: center; gap: 5px; margin-top: 3px; min-width: 0; }\n[data-edrv-view] .edrv-rules-sublabel { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-file { font-weight: 600; font-size: 12px; color: var(--dsw-alias-label-primary, #1f2933); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-rules-path { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-rules-type { flex-shrink: 0; height: 15px; padding: 0 5px; border-radius: 999px; font-size: 10px; line-height: 15px; }\n[data-edrv-view] .edrv-rules-type-always { background: rgba(15,157,88,.15); color: #0b7c46; }\n[data-edrv-view] .edrv-rules-type-auto { background: rgba(79,140,255,.16); color: #3367c9; }\n[data-edrv-view] .edrv-rules-type-manual { background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-rules-offtag { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-desc { font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; flex: 0 1 auto; }\n[data-edrv-view] .edrv-rules-actions { display: flex; align-items: center; gap: 2px; flex-shrink: 0; margin-left: auto; }\n[data-edrv-view] .edrv-rules-act { min-width: 22px; height: 22px; padding: 0 4px; border: none; border-radius: 5px; background: transparent; font-size: 12px; line-height: 1; cursor: pointer; color: var(--dsw-alias-label-secondary, #52606d); display: inline-flex; align-items: center; justify-content: center; }\n[data-edrv-view] .edrv-rules-act:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-switch { position: relative; width: 30px; height: 16px; border-radius: 999px; border: none; background: #b9c4cc; cursor: pointer; transition: background .15s; flex-shrink: 0; padding: 0; }\n[data-edrv-view] .edrv-rules-switch.on { background: #7c5cff; }\n[data-edrv-view] .edrv-rules-knob { position: absolute; top: 2px; left: 2px; width: 12px; height: 12px; border-radius: 50%; background: #fff; transition: left .15s; }\n[data-edrv-view] .edrv-rules-switch.on .edrv-rules-knob { left: 16px; }\n[data-edrv-view] .edrv-rules-empty { padding: 10px 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); line-height: 1.6; }\n[data-edrv-view] .edrv-rules-err { padding: 6px 8px; border: 1px solid rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; word-break: break-all; }\n[data-edrv-view] .edrv-rules-editor { display: flex; flex-direction: column; min-height: 0; flex: 1; gap: 6px; }\n[data-edrv-view] .edrv-rules-editor-head { display: flex; align-items: center; justify-content: space-between; gap: 6px; font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-crumb { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-rules-editor-ctl { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-ctl-label { font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-select { height: 24px; padding: 0 4px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 11px; outline: none; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-select:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-rules-desc-input { flex: 1; min-width: 0; }\n[data-edrv-view] .edrv-rules-input { flex: 1; min-width: 0; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 11px; outline: none; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-rules-input:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-rules-body { flex: 1; min-height: 0; resize: none; padding: 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; line-height: 1.5; outline: none; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-rules-body:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-rules-editor-hint { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); line-height: 1.5; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-editor-foot { display: flex; justify-content: flex-end; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-save { height: 24px; padding: 0 14px; border: none; border-radius: 6px; background: var(--dsw-alias-brand-primary, #0f9d58); color: #fff; font-size: 12px; cursor: pointer; }\n[data-edrv-view] .edrv-rules-save:disabled { opacity: .5; cursor: default; }\n\n\n\n";
34
34
  const tagId$1 = "dsh-vscode-mode/editor.css";
35
35
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
36
36
  const tag = document.createElement("style");
@@ -2166,44 +2166,87 @@ window.__ModuleLoader__.load({
2166
2166
  //#endregion
2167
2167
  //#region src/client/sidebar/SidebarView.ts
2168
2168
  /**
2169
- * dsh-vscode-mode client — 侧边栏容器(活动栏 + 面板区 + 拖拽调宽)。
2170
- * 面板列表来自注册表(活动栏图标/徽标/激活态),渲染当前激活面板的 render(ctx);
2171
- * 右侧手柄拖拽调宽(clamp 180–560),底部按钮收起侧边栏。
2172
- * 作者 ddj 2026-08-26
2169
+ * dsh-vscode-mode client — 侧边栏容器(活动栏常显 + 可隐藏面板区 + 拖拽调宽)。
2170
+ * 面板列表来自注册表(活动栏图标/徽标/激活态);最左侧图标列(活动栏)常显,
2171
+ * 右侧详情面板区可拖拽调宽/隐藏:visible=false 时仅保留图标列(宽 = 图标列宽),
2172
+ * 点击任一图标重新展开面板(onShow),底部按钮在 ◀ 收起 / ▶ 展开间切换。
2173
+ * 拖拽调宽下限 = minWidth prop(通用设置 sidebarMinWidth,默认 300),低于下限直接收起面板区。
2174
+ * 作者 ddj 2026-08-26 / 2026-09-04
2173
2175
  */
2174
- const W_MIN = 180;
2175
2176
  const W_MAX = 560;
2177
+ /** 隐藏态拖出面板区的触发阈值(px,拖过即展开并继续实时调宽)。 */
2178
+ const PULL_OUT_THRESHOLD = 12;
2176
2179
  /**
2177
2180
  * 侧边栏容器。
2178
2181
  * @param props.registry 面板注册表(list() 提供面板顺序)
2179
2182
  * @param props.ctx 面板共享上下文
2180
2183
  * @param props.activePanel 当前激活面板 id
2181
2184
  * @param props.onActive 激活面板变化回调
2185
+ * @param props.visible 面板区是否可见(false = 只显示活动栏)
2186
+ * @param props.onShow 重新展开面板区回调(活动栏图标点击/底部按钮)
2182
2187
  * @param props.width 面板区宽度
2183
2188
  * @param props.onWidth 宽度变化回调
2184
- * @param props.onHide 收起侧边栏回调
2189
+ * @param props.onHide 收起面板区回调
2190
+ * @param props.minWidth 最小宽度(通用设置 sidebarMinWidth;拖拽低于它触发隐藏)
2185
2191
  */
2186
2192
  function SidebarView(props) {
2187
2193
  const panels = props.registry?.list?.() ?? [];
2188
2194
  const ctx = props.ctx;
2189
2195
  const activePanel = props.activePanel;
2190
2196
  const onActive = props.onActive;
2197
+ const visible = props.visible !== false;
2198
+ const onShow = props.onShow;
2191
2199
  const width = props.width;
2192
2200
  const onWidth = props.onWidth;
2193
2201
  const onHide = props.onHide;
2202
+ const wMin = Math.max(120, Math.min(W_MAX, Math.round(Number(props.minWidth) || 300)));
2194
2203
  const active = panels.find((p) => p.id === activePanel) || panels[0];
2195
2204
  const onPointerDown = (e) => {
2196
2205
  e.preventDefault();
2197
2206
  const startX = e.clientX;
2198
2207
  const startW = width;
2208
+ const cleanup = () => {
2209
+ window.removeEventListener("pointermove", onMove);
2210
+ window.removeEventListener("pointerup", onUp);
2211
+ };
2212
+ const onUp = () => cleanup();
2199
2213
  const onMove = (ev) => {
2200
- const w = Math.max(W_MIN, Math.min(W_MAX, startW + (ev.clientX - startX)));
2201
- onWidth(w);
2214
+ const raw = startW + (ev.clientX - startX);
2215
+ if (raw < wMin) {
2216
+ cleanup();
2217
+ onHide();
2218
+ return;
2219
+ }
2220
+ onWidth(Math.min(W_MAX, raw));
2202
2221
  };
2203
- const onUp = () => {
2222
+ window.addEventListener("pointermove", onMove);
2223
+ window.addEventListener("pointerup", onUp);
2224
+ };
2225
+ /**
2226
+ * 隐藏态接缝拖拽:向右拖过阈值把面板区拉出来(以记忆宽度展开),继续拖动实时调宽。
2227
+ * @param e pointerdown 事件
2228
+ */
2229
+ const onSeamPointerDown = (e) => {
2230
+ e.preventDefault();
2231
+ const startX = e.clientX;
2232
+ const baseW = Math.max(wMin, Math.min(W_MAX, Math.round(Number(width) || wMin)));
2233
+ let expanded = false;
2234
+ let expandStartX = 0;
2235
+ const cleanup = () => {
2204
2236
  window.removeEventListener("pointermove", onMove);
2205
2237
  window.removeEventListener("pointerup", onUp);
2206
2238
  };
2239
+ const onUp = () => cleanup();
2240
+ const onMove = (ev) => {
2241
+ if (!expanded) {
2242
+ if (ev.clientX - startX < PULL_OUT_THRESHOLD) return;
2243
+ expanded = true;
2244
+ expandStartX = ev.clientX;
2245
+ onShow();
2246
+ return;
2247
+ }
2248
+ onWidth(Math.max(wMin, Math.min(W_MAX, baseW + (ev.clientX - expandStartX))));
2249
+ };
2207
2250
  window.addEventListener("pointermove", onMove);
2208
2251
  window.addEventListener("pointerup", onUp);
2209
2252
  };
@@ -2216,21 +2259,31 @@ window.__ModuleLoader__.load({
2216
2259
  const count = typeof p.badge === "function" ? p.badge(ctx) : null;
2217
2260
  return react.default.createElement("button", {
2218
2261
  key: p.id,
2219
- className: "edrv-rail-btn" + (active && p.id === active.id ? " edrv-rail-on" : ""),
2262
+ className: "edrv-rail-btn" + (visible && active && p.id === active.id ? " edrv-rail-on" : ""),
2220
2263
  title: p.title,
2221
- onClick: () => onActive(p.id)
2264
+ onClick: () => {
2265
+ onActive(p.id);
2266
+ if (!visible && typeof onShow === "function") onShow();
2267
+ }
2222
2268
  }, react.default.createElement("span", { className: "edrv-rail-icon" }, p.icon), count > 0 ? react.default.createElement("span", { className: "edrv-rail-badge" }, String(count)) : null);
2223
2269
  })), react.default.createElement("button", {
2224
2270
  className: "edrv-rail-btn",
2225
- title: "隐藏侧边栏 (Ctrl+B)",
2226
- onClick: onHide
2227
- }, "◀"));
2271
+ title: (visible ? "隐藏面板区" : "展开面板区") + " (Ctrl+B)",
2272
+ onClick: () => visible ? onHide() : onShow?.()
2273
+ }, visible ? "◀" : "▶"));
2228
2274
  return react.default.createElement("div", {
2229
- className: "edrv-sidebar",
2230
- style: { width }
2231
- }, rail, react.default.createElement("div", { className: "edrv-side-body" }, active ? active.render(ctx) : null), react.default.createElement("div", {
2275
+ className: "edrv-sidebar" + (visible ? "" : " edrv-sidebar-rail-only"),
2276
+ style: {
2277
+ width: visible ? width : 49,
2278
+ maxWidth: "100%"
2279
+ }
2280
+ }, rail, visible ? react.default.createElement("div", { className: "edrv-side-body" }, active ? active.render(ctx) : null) : null, visible ? react.default.createElement("div", {
2232
2281
  className: "edrv-side-resize",
2233
2282
  onPointerDown
2283
+ }) : react.default.createElement("div", {
2284
+ className: "edrv-side-resize",
2285
+ title: "拖拽展开面板区",
2286
+ onPointerDown: onSeamPointerDown
2234
2287
  }));
2235
2288
  }
2236
2289
  //#endregion
@@ -2431,7 +2484,9 @@ window.__ModuleLoader__.load({
2431
2484
  /** 侧边栏提示已关闭标记(全局,无会话)。 */
2432
2485
  sideHint: "edrv.side-hint-dismissed",
2433
2486
  /** 「性能优化」页工作区栏目展开状态(workspaceFoldCache v1,全局不按会话)。 */
2434
- workspaceFold: "edrv.ws-fold.v1."
2487
+ workspaceFold: "edrv.ws-fold.v1.",
2488
+ /** 规则面板 UI 状态(RulesPanel v1:Tab 与项目工作区选择,全局不按会话)。 */
2489
+ rules: "edrv.rules.v1."
2435
2490
  };
2436
2491
  //#endregion
2437
2492
  //#region src/client/state/viewStateCache.ts
@@ -2537,6 +2592,36 @@ window.__ModuleLoader__.load({
2537
2592
  window.localStorage.setItem(KEY_PREFIX$2 + String(sessionId), serializeViewStates(states));
2538
2593
  } catch (error) {}
2539
2594
  }
2595
+ let currentMin = 300;
2596
+ /**
2597
+ * 归一化最小宽度:非法(NaN/非有限/负数)回退默认,越界夹取到 [180, 560]。
2598
+ * @author ddj 2026年09月04号
2599
+ * @param value 原始值(设置文档来的任意 JSON 值)
2600
+ * @returns 合法最小宽度
2601
+ */
2602
+ function normalizeSidebarMinWidth(value) {
2603
+ const n = typeof value === "number" ? value : Number(value);
2604
+ if (!Number.isFinite(n) || n <= 0) return 300;
2605
+ return Math.max(180, Math.min(560, Math.round(n)));
2606
+ }
2607
+ /**
2608
+ * 应用设置值(client/index.ts 设置订阅同步调用)。
2609
+ * @author ddj 2026年09月04号
2610
+ * @param value 设置文档中的 sidebarMinWidth
2611
+ * @returns 归一化后的生效值
2612
+ */
2613
+ function sidebarMinApply(value) {
2614
+ currentMin = normalizeSidebarMinWidth(value);
2615
+ return currentMin;
2616
+ }
2617
+ /**
2618
+ * 读取当前生效的最小宽度(编辑器初始/恢复/拖拽夹取共用)。
2619
+ * @author ddj 2026年09月04号
2620
+ * @returns 当前最小宽度
2621
+ */
2622
+ function getSidebarMinWidth() {
2623
+ return currentMin;
2624
+ }
2540
2625
  /** 路径一致(容忍相对路径大小写差异,对齐既有 sameFile 语义常用写法)。 */
2541
2626
  function samePath(a, b) {
2542
2627
  if (a === b) return true;
@@ -3534,7 +3619,7 @@ window.__ModuleLoader__.load({
3534
3619
  const [fileIdx, setFileIdx] = react.default.useState(0);
3535
3620
  const [tabMenu, setTabMenu] = react.default.useState(null);
3536
3621
  const [sidebarOn, setSidebarOn] = react.default.useState(layout !== "side");
3537
- const [sidebarW, setSidebarW] = react.default.useState(240);
3622
+ const [sidebarW, setSidebarW] = react.default.useState(() => getSidebarMinWidth());
3538
3623
  const [activePanel, setActivePanel] = react.default.useState("explorer");
3539
3624
  const [focusRequest, setFocusRequest] = react.default.useState(0);
3540
3625
  useKeybindingsVersion();
@@ -4005,11 +4090,20 @@ window.__ModuleLoader__.load({
4005
4090
  if (raw) {
4006
4091
  const saved = JSON.parse(raw);
4007
4092
  if (typeof saved.on === "boolean") setSidebarOn(saved.on);
4008
- if (typeof saved.width === "number") setSidebarW(Math.max(180, Math.min(560, saved.width)));
4093
+ if (typeof saved.width === "number") setSidebarW(Math.max(getSidebarMinWidth(), Math.min(560, saved.width)));
4009
4094
  if (typeof saved.panel === "string") setActivePanel(saved.panel);
4010
4095
  }
4011
4096
  } catch (e) {}
4012
4097
  }, [sessionId, sidebarKey]);
4098
+ const [sidebarMinW, setSidebarMinW] = react.default.useState(() => getSidebarMinWidth());
4099
+ react.default.useEffect(() => {
4100
+ const onMinChange = () => {
4101
+ setSidebarMinW(getSidebarMinWidth());
4102
+ setSidebarW((w) => Math.max(getSidebarMinWidth(), w));
4103
+ };
4104
+ window.addEventListener("edrv:sidebar-min-width", onMinChange);
4105
+ return () => window.removeEventListener("edrv:sidebar-min-width", onMinChange);
4106
+ }, []);
4013
4107
  react.default.useEffect(() => {
4014
4108
  if (!sessionId) return;
4015
4109
  try {
@@ -4888,7 +4982,7 @@ window.__ModuleLoader__.load({
4888
4982
  onClick: navForward
4889
4983
  }, "→"), react.default.createElement("button", {
4890
4984
  className: "edrv-chip-btn" + (sidebarOn ? " edrv-chip-on" : ""),
4891
- title: "切换侧边栏 (" + (chordOf("edrv.toggleSidebar") ?? "Ctrl+B") + ")",
4985
+ title: "切换面板区 (" + (chordOf("edrv.toggleSidebar") ?? "Ctrl+B") + "),图标列常显",
4892
4986
  onClick: () => setSidebarOn((v) => !v)
4893
4987
  }, "☰"), react.default.createElement("button", {
4894
4988
  className: "edrv-chip-btn",
@@ -5086,6 +5180,7 @@ window.__ModuleLoader__.load({
5086
5180
  const sidebarPanels = props.sidebarPanels;
5087
5181
  const sidebarCtx = {
5088
5182
  sessionId,
5183
+ cwd: props.sessions?.list?.getSnapshot?.()?.byId?.[sessionId]?.cwd ?? null,
5089
5184
  openFile: (p) => openFile(p, false),
5090
5185
  openFileAt,
5091
5186
  activePath: active,
@@ -5132,14 +5227,17 @@ window.__ModuleLoader__.load({
5132
5227
  overflow: "hidden"
5133
5228
  }
5134
5229
  }, pathBar, tabRow, sideHintEl, editorArea, lspFooter);
5135
- const editorRow = react.default.createElement("div", { className: "edrv-editor-row" }, sidebarOn && sidebarPanels ? react.default.createElement(SidebarView, {
5230
+ const editorRow = react.default.createElement("div", { className: "edrv-editor-row" }, sidebarPanels ? react.default.createElement(SidebarView, {
5136
5231
  registry: sidebarPanels,
5137
5232
  ctx: sidebarCtx,
5138
5233
  activePanel,
5139
5234
  onActive: setActivePanel,
5235
+ visible: sidebarOn,
5236
+ onShow: () => setSidebarOn(true),
5140
5237
  width: sidebarW,
5141
5238
  onWidth: setSidebarW,
5142
- onHide: () => setSidebarOn(false)
5239
+ onHide: () => setSidebarOn(false),
5240
+ minWidth: sidebarMinW
5143
5241
  }) : null, mainCol);
5144
5242
  const baseStyle = {
5145
5243
  minHeight: 0,
@@ -6909,7 +7007,7 @@ window.__ModuleLoader__.load({
6909
7007
  }));
6910
7008
  return react.default.createElement("section", { className: "vsm-project" }, head, body);
6911
7009
  }
6912
- /** 通用设置:选择当前对话文件链接的打开器 + 开发形态开关。 */
7010
+ /** 通用设置:选择当前对话文件链接的打开器 + 开发形态开关 + 编辑器布局(侧边栏最小宽度)。 */
6913
7011
  function GeneralSettings({ registry }) {
6914
7012
  const [tool, setTool] = react.default.useState(AUTO_OPEN_TOOL);
6915
7013
  const [busy, setBusy] = react.default.useState(false);
@@ -6917,6 +7015,8 @@ window.__ModuleLoader__.load({
6917
7015
  const [devForm, setDevForm] = react.default.useState(null);
6918
7016
  const [devBusy, setDevBusy] = react.default.useState(false);
6919
7017
  const [devMessage, setDevMessage] = react.default.useState("");
7018
+ const [minW, setMinW] = react.default.useState(300);
7019
+ const [minDraft, setMinDraft] = react.default.useState(null);
6920
7020
  const settings = react.default.useContext(SettingsContext);
6921
7021
  const snapshot = settings?.getSnapshot?.();
6922
7022
  const loading = !snapshot || snapshot.status === "loading";
@@ -6924,8 +7024,10 @@ window.__ModuleLoader__.load({
6924
7024
  const notReady = snapshot?.status !== "ready";
6925
7025
  react.default.useEffect(() => {
6926
7026
  const onChange = () => {
6927
- const next = settings?.getSnapshot?.().value?.fileOpenTool;
7027
+ const snap = settings?.getSnapshot?.();
7028
+ const next = snap?.value?.fileOpenTool;
6928
7029
  if (typeof next === "string") setTool(next);
7030
+ setMinW(normalizeSidebarMinWidth(snap?.value?.sidebarMinWidth));
6929
7031
  };
6930
7032
  onChange();
6931
7033
  return settings?.subscribe?.(onChange);
@@ -6946,6 +7048,25 @@ window.__ModuleLoader__.load({
6946
7048
  }
6947
7049
  settings.set("fileOpenTool", value).catch((e) => setError(String(e))).finally(() => setBusy(false));
6948
7050
  };
7051
+ /** 提交侧边栏最小宽度(归一化夹取 180–560 后持久化)。 */
7052
+ const saveMinW = (raw) => {
7053
+ const next = normalizeSidebarMinWidth(raw);
7054
+ setMinW(next);
7055
+ setBusy(true);
7056
+ setError("");
7057
+ if (!settings?.set) {
7058
+ setError("设置服务不可用");
7059
+ setBusy(false);
7060
+ return;
7061
+ }
7062
+ settings.set("sidebarMinWidth", next).catch((e) => setError(String(e))).finally(() => setBusy(false));
7063
+ };
7064
+ /** 结束输入(blur/Enter)时提交草稿。 */
7065
+ const commitMinW = () => {
7066
+ if (minDraft === null) return;
7067
+ setMinDraft(null);
7068
+ saveMinW(minDraft);
7069
+ };
6949
7070
  const closeDevForm = () => {
6950
7071
  if (!window.confirm("关闭开发形态:插件将切换为正式版安装(版本依赖 + 删除工作区链接),pnpm 装配后需重启 DSH 生效。确认关闭?")) return;
6951
7072
  setDevBusy(true);
@@ -6981,7 +7102,20 @@ window.__ModuleLoader__.load({
6981
7102
  }, options.map((item) => react.default.createElement("option", {
6982
7103
  key: item.id,
6983
7104
  value: item.id
6984
- }, item.label))), loading && react.default.createElement("small", null, "读取中…")), devFormRow)));
7105
+ }, item.label))), loading && react.default.createElement("small", null, "读取中…")), devFormRow)), 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("label", { className: "vsm-general-row" }, react.default.createElement("span", null, "侧边栏最小宽度"), react.default.createElement("input", {
7106
+ type: "number",
7107
+ min: 180,
7108
+ max: 560,
7109
+ step: 10,
7110
+ value: minDraft ?? minW,
7111
+ disabled: loading || unavailable || notReady || busy || snapshot?.writable === false,
7112
+ title: "180–560 px;拖拽侧边栏低于该宽度时自动隐藏",
7113
+ onChange: (event) => setMinDraft(event.target.value),
7114
+ onBlur: commitMinW,
7115
+ onKeyDown: (event) => {
7116
+ if (event.key === "Enter") commitMinW();
7117
+ }
7118
+ }), react.default.createElement("small", null, "180–560 px;拖拽低于该宽度自动隐藏")))));
6985
7119
  }
6986
7120
  /** 兼容性小节:host 报告(RPC compat)+ 客户端本地适配项。 */
6987
7121
  function CompatSection({ getSummary }) {
@@ -7368,7 +7502,8 @@ window.__ModuleLoader__.load({
7368
7502
  addToConversation: props?.addToConversation,
7369
7503
  sidebarPanels: props?.sidebarPanels,
7370
7504
  outlineSources: props?.outlineSources,
7371
- fileMenuItems: props?.fileMenuItems
7505
+ fileMenuItems: props?.fileMenuItems,
7506
+ sessions: props?.sessions
7372
7507
  });
7373
7508
  }
7374
7509
  //#endregion
@@ -8439,10 +8574,709 @@ window.__ModuleLoader__.load({
8439
8574
  })), optsBar, filterRows, summary, warnBanner, body);
8440
8575
  }
8441
8576
  //#endregion
8577
+ //#region src/client/rulesMdc.ts
8578
+ /**
8579
+ * 去除值两侧成对引号(与 host stripQuotes 一致)。
8580
+ * @author ddj 2026年09月07号
8581
+ * @param raw 原始值
8582
+ * @returns 去引号后的值
8583
+ */
8584
+ function stripQuotes(raw) {
8585
+ const value = raw.trim();
8586
+ if (value.length >= 2 && (value.startsWith("\"") && value.endsWith("\"") || value.startsWith("'") && value.endsWith("'"))) return value.slice(1, -1);
8587
+ return value;
8588
+ }
8589
+ /**
8590
+ * 解析 .mdc 全文:首行 --- 且 100 行内有闭合 --- 才视为 frontmatter;
8591
+ * 已知键 description/alwaysApply/globs/enabled,其余原行进 fmExtra;永不抛错。
8592
+ * @author ddj 2026年09月07号
8593
+ * @param text 文件全文
8594
+ * @returns 解析结果
8595
+ */
8596
+ function parseRuleFm(text) {
8597
+ const bom = text.startsWith("");
8598
+ const lines = text.replace(/^\uFEFF/, "").split(/\r?\n/);
8599
+ const none = {
8600
+ type: "manual",
8601
+ description: "",
8602
+ alwaysApply: false,
8603
+ globs: [],
8604
+ enabled: true,
8605
+ hasFm: false,
8606
+ body: text.replace(/^\uFEFF/, ""),
8607
+ fmExtra: [],
8608
+ bom,
8609
+ hasEnabledLine: false
8610
+ };
8611
+ if (lines[0]?.trim() !== "---") return none;
8612
+ let close = -1;
8613
+ for (let i = 1; i < lines.length && i <= 101; i++) if (lines[i].trim() === "---") {
8614
+ close = i;
8615
+ break;
8616
+ }
8617
+ if (close < 0) return none;
8618
+ const parsed = {
8619
+ type: "manual",
8620
+ description: "",
8621
+ alwaysApply: false,
8622
+ globs: [],
8623
+ enabled: true,
8624
+ hasFm: true,
8625
+ body: lines.slice(close + 1).join("\n"),
8626
+ fmExtra: [],
8627
+ bom,
8628
+ hasEnabledLine: false
8629
+ };
8630
+ for (let i = 1; i < close; i++) {
8631
+ const match = /^([A-Za-z_-]+)[ \t]*:[ \t]?(.*)$/.exec(lines[i]);
8632
+ if (!match) {
8633
+ parsed.fmExtra.push(lines[i]);
8634
+ continue;
8635
+ }
8636
+ const [, key, raw] = match;
8637
+ if (key === "description") parsed.description = stripQuotes(raw);
8638
+ else if (key === "alwaysApply") parsed.alwaysApply = stripQuotes(raw).toLowerCase() === "true";
8639
+ else if (key === "enabled") {
8640
+ parsed.enabled = stripQuotes(raw).toLowerCase() !== "false";
8641
+ parsed.hasEnabledLine = true;
8642
+ } else if (key === "globs") parsed.globs = parseGlobsValue(raw, lines, i, close);
8643
+ else parsed.fmExtra.push(lines[i]);
8644
+ }
8645
+ parsed.type = fmTypeOf(parsed);
8646
+ return parsed;
8647
+ }
8648
+ /**
8649
+ * 解析 globs 值:内联逗号分隔串,或空值后接 YAML 短横列表(与 host parseGlobs 一致)。
8650
+ * @author ddj 2026年09月07号
8651
+ * @param value 内联值
8652
+ * @param lines 全文行
8653
+ * @param start globs 行下标
8654
+ * @param close 闭合 --- 下标
8655
+ * @returns glob 数组
8656
+ */
8657
+ function parseGlobsValue(value, lines, start, close) {
8658
+ const inline = stripQuotes(value);
8659
+ if (inline) return inline.split(",").map((item) => stripQuotes(item)).filter(Boolean);
8660
+ const list = [];
8661
+ for (let j = start + 1; j < close; j++) {
8662
+ const item = /^[ \t]*-[ \t]*(.+)$/.exec(lines[j]);
8663
+ if (!item) break;
8664
+ list.push(stripQuotes(item[1]));
8665
+ }
8666
+ return list;
8667
+ }
8668
+ /**
8669
+ * 由 frontmatter 推导类型:alwaysApply=true → 总是;有 globs → 自动;否则手动。
8670
+ * @author ddj 2026年09月07号
8671
+ * @param parsed 解析结果
8672
+ * @returns 规则类型
8673
+ */
8674
+ function fmTypeOf(parsed) {
8675
+ if (parsed.alwaysApply) return "always";
8676
+ if (parsed.globs.length) return "auto";
8677
+ return "manual";
8678
+ }
8679
+ /**
8680
+ * 按最新控件值重写 frontmatter:known 键固定顺序 + fmExtra + 闭合 --- + 原 body;
8681
+ * 无 frontmatter 且目标为手动时:有描述则新建仅含描述的 frontmatter,否则原文返回。
8682
+ * @author ddj 2026年09月07号
8683
+ * @param parsed parseRuleFm 的结果(必须来自同一文本)
8684
+ * @param next 控件最新值
8685
+ * @returns 重写后的全文
8686
+ */
8687
+ function applyRuleMeta(parsed, next) {
8688
+ if (!parsed.hasFm && next.type === "manual") {
8689
+ if (!next.description.trim()) return (parsed.bom ? "" : "") + parsed.body;
8690
+ return (parsed.bom ? "" : "") + [
8691
+ "---",
8692
+ "description: " + next.description.trim(),
8693
+ "---"
8694
+ ].join("\n") + "\n" + parsed.body;
8695
+ }
8696
+ const lines = ["---"];
8697
+ lines.push("description: " + next.description.trim());
8698
+ if (next.type === "always") lines.push("alwaysApply: true");
8699
+ if (next.type === "auto") lines.push("globs: " + next.globs.join(", "));
8700
+ if (parsed.hasEnabledLine) lines.push("enabled: " + (parsed.enabled ? "true" : "false"));
8701
+ lines.push(...parsed.fmExtra);
8702
+ lines.push("---");
8703
+ return (parsed.bom ? "" : "") + lines.join("\n") + "\n" + parsed.body;
8704
+ }
8705
+ //#endregion
8706
+ //#region src/client/sidebar/panels/RulesPanel.ts
8707
+ /**
8708
+ * dsh-vscode-mode client — 侧边栏「规则」面板(Codebuddy 规则管理形态)。
8709
+ * 双 Tab:用户规则(~/.dsh/rules/)与项目规则(<工作区>/.dsh/rules/);
8710
+ * 列表行 = 文件名 + 相对提示,第二行类型徽标与描述,右侧 编辑/删除 图标 + 滑动启用开关;
8711
+ * 新建/编辑 = 顶部面包屑 + 规则类型下拉(总是/自动/手动)+ 描述/globs 控件,与原始 .mdc
8712
+ * 文本域双向同步(控件改写 frontmatter,文本域回读控件),保存走 rules.save。
8713
+ * 作者 ddj 2026年09月03号(2026年09月07号 交互性调整)
8714
+ */
8715
+ /** 新建规则模板(frontmatter 字段与 host parseRuleMdc 对齐)。 */
8716
+ const NEW_TEMPLATE = "---\ndescription: \nalwaysApply: true\n---\n\n";
8717
+ const TYPE_LABEL = {
8718
+ always: "总是",
8719
+ auto: "自动",
8720
+ manual: "手动"
8721
+ };
8722
+ /** 列表行描述的基础显示上限(字符数;宽面板下的封顶值,超出省略号)。 */
8723
+ const DESC_MAX = 24;
8724
+ /** 动态字数下限(极窄面板的保底可见字符数)。 */
8725
+ const DESC_CAP_MIN = 8;
8726
+ /** 动态字数估算:描述之外的行内固定占用 px(动作区/类型标签/徽标/间距/省略余量)。 */
8727
+ const DESC_RESERVE_PX = 210;
8728
+ /** 动态字数估算:单字符平均宽度 px(11px 字号,中英混排)。 */
8729
+ const DESC_CHAR_PX = 10;
8730
+ /** 窄面板阈值:低于此宽度隐藏路径提示(编辑界面面包屑与悬停仍有完整路径)。 */
8731
+ const NARROW_W = 420;
8732
+ /**
8733
+ * 读 localStorage(损坏/不可用安全)。
8734
+ * @author ddj 2026年09月03号
8735
+ * @param key 键
8736
+ * @returns 值或 null
8737
+ */
8738
+ function readLocal(key) {
8739
+ try {
8740
+ return localStorage.getItem(key);
8741
+ } catch (e) {
8742
+ return null;
8743
+ }
8744
+ }
8745
+ /**
8746
+ * 写 localStorage(不可用安全)。
8747
+ * @author ddj 2026年09月03号
8748
+ * @param key 键
8749
+ * @param value 值
8750
+ */
8751
+ function writeLocal(key, value) {
8752
+ try {
8753
+ localStorage.setItem(key, value);
8754
+ } catch (e) {}
8755
+ }
8756
+ /**
8757
+ * 类型徽标(总是=绿 / 自动=蓝 / 手动=灰)。
8758
+ * @author ddj 2026年09月03号
8759
+ * @param type 规则类型
8760
+ * @returns 徽标元素
8761
+ */
8762
+ function typeBadge(type) {
8763
+ return react.default.createElement("span", { className: "edrv-rules-type edrv-rules-type-" + type }, TYPE_LABEL[type] ?? type);
8764
+ }
8765
+ /**
8766
+ * 按字符上限截断列表行描述,超出以省略号收尾(上限随面板宽度动态变化;
8767
+ * 窄面板下 CSS 省略号仍会按像素提前截断,二者取更小)。
8768
+ * @author ddj 2026年09月07号
8769
+ * @param text 完整描述
8770
+ * @param cap 本帧字符上限
8771
+ * @returns 截断后的展示文本
8772
+ */
8773
+ function clampDesc(text, cap) {
8774
+ const chars = Array.from(String(text ?? ""));
8775
+ const limit = Math.max(4, Number(cap) || DESC_MAX);
8776
+ return chars.length > limit ? chars.slice(0, limit).join("") + "…" : chars.join("");
8777
+ }
8778
+ /**
8779
+ * 由面板宽度估算描述可用字符数:随宽度动态变化,并与基础上限取小、极窄时保底。
8780
+ * @author ddj 2026年09月07号
8781
+ * @param panelWidth 面板内容宽度(px)
8782
+ * @returns 本帧描述字符上限
8783
+ */
8784
+ function descCapOf(panelWidth) {
8785
+ const byWidth = Math.floor((Number(panelWidth) - DESC_RESERVE_PX) / DESC_CHAR_PX);
8786
+ return Math.max(DESC_CAP_MIN, Math.min(DESC_MAX, byWidth));
8787
+ }
8788
+ /**
8789
+ * 编辑图标(线性铅笔,与 DiffBox chevron 同风格:currentColor 描边装饰图)。
8790
+ * @author ddj 2026年09月07号
8791
+ * @returns 13×13 装饰性 SVG
8792
+ */
8793
+ function pencilIcon() {
8794
+ return react.default.createElement("svg", {
8795
+ width: 13,
8796
+ height: 13,
8797
+ viewBox: "0 0 24 24",
8798
+ fill: "none",
8799
+ "aria-hidden": true,
8800
+ focusable: false
8801
+ }, react.default.createElement("path", {
8802
+ d: "M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z",
8803
+ stroke: "currentColor",
8804
+ strokeWidth: 2,
8805
+ strokeLinecap: "round",
8806
+ strokeLinejoin: "round"
8807
+ }));
8808
+ }
8809
+ /**
8810
+ * 删除图标(线性垃圾桶,风格同 pencilIcon)。
8811
+ * @author ddj 2026年09月07号
8812
+ * @returns 13×13 装饰性 SVG
8813
+ */
8814
+ function trashIcon() {
8815
+ return react.default.createElement("svg", {
8816
+ width: 13,
8817
+ height: 13,
8818
+ viewBox: "0 0 24 24",
8819
+ fill: "none",
8820
+ "aria-hidden": true,
8821
+ focusable: false
8822
+ }, react.default.createElement("path", {
8823
+ d: "M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2m3 0v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6h14zM10 11v6M14 11v6",
8824
+ stroke: "currentColor",
8825
+ strokeWidth: 2,
8826
+ strokeLinecap: "round",
8827
+ strokeLinejoin: "round"
8828
+ }));
8829
+ }
8830
+ /**
8831
+ * 逗号分隔的 globs 输入串 → 数组(去空项)。
8832
+ * @author ddj 2026年09月07号
8833
+ * @param text 输入串
8834
+ * @returns glob 数组
8835
+ */
8836
+ function globList(text) {
8837
+ return String(text ?? "").split(",").map((item) => item.trim()).filter(Boolean);
8838
+ }
8839
+ /**
8840
+ * 由控件值重建 .mdc 全文:frontmatter 按类型/描述/globs 重写,正文与其余键不动。
8841
+ * @author ddj 2026年09月07号
8842
+ * @param base 当前全文
8843
+ * @param fmType 目标类型(always/auto/manual)
8844
+ * @param desc 描述文本
8845
+ * @param globsText globs 输入串
8846
+ * @returns 重写后的全文
8847
+ */
8848
+ function rebuildContent(base, fmType, desc, globsText) {
8849
+ return applyRuleMeta(parseRuleFm(base), {
8850
+ type: fmType,
8851
+ description: desc,
8852
+ globs: globList(globsText)
8853
+ });
8854
+ }
8855
+ /**
8856
+ * 渲染一条规则行:左侧两行(文件名+相对提示 / 类型徽标+描述),右侧 编辑/删除 图标 + 滑动开关。
8857
+ * @author ddj 2026年09月03号
8858
+ * @param props.rule 规则元信息
8859
+ * @param props.onEdit 编辑回调
8860
+ * @param props.onRemove 删除回调
8861
+ * @param props.onToggle 开关回调
8862
+ * @returns 行元素
8863
+ */
8864
+ function RuleRow(props) {
8865
+ const rule = props.rule;
8866
+ const desc = [rule.error ? "解析失败:" + rule.error : null, rule.description || (rule.type === "auto" ? "globs: " + rule.globs.join(", ") : "")].filter(Boolean).join(" · ");
8867
+ return react.default.createElement("div", { className: "edrv-rules-row" + (rule.enabled ? "" : " off") }, react.default.createElement("div", {
8868
+ className: "edrv-rules-main",
8869
+ onClick: () => props.onEdit(rule),
8870
+ title: rule.absPath
8871
+ }, react.default.createElement("div", { className: "edrv-rules-line1" }, react.default.createElement("span", { className: "edrv-rules-file" }, rule.file), !props.narrow ? react.default.createElement("span", { className: "edrv-rules-path" }, "[" + rule.relHint + rule.file + "]") : null, !rule.enabled ? react.default.createElement("span", { className: "edrv-rules-offtag" }, "已停用") : null), react.default.createElement("div", { className: "edrv-rules-sub" }, react.default.createElement("span", { className: "edrv-rules-sublabel" }, "类型:"), typeBadge(rule.type), desc ? react.default.createElement("span", {
8872
+ className: "edrv-rules-desc",
8873
+ title: desc
8874
+ }, clampDesc(desc, props.descCap)) : null)), react.default.createElement("div", { className: "edrv-rules-actions" }, react.default.createElement("button", {
8875
+ className: "edrv-rules-act",
8876
+ title: "编辑",
8877
+ onClick: () => props.onEdit(rule)
8878
+ }, pencilIcon()), react.default.createElement("button", {
8879
+ className: "edrv-rules-act",
8880
+ title: "删除",
8881
+ onClick: () => props.onRemove(rule)
8882
+ }, trashIcon()), react.default.createElement("button", {
8883
+ className: "edrv-rules-switch" + (rule.enabled ? " on" : ""),
8884
+ role: "switch",
8885
+ "aria-checked": rule.enabled,
8886
+ title: rule.enabled ? "已启用(点击停用)" : "已停用(点击启用)",
8887
+ onClick: () => props.onToggle(rule)
8888
+ }, react.default.createElement("span", { className: "edrv-rules-knob" }))));
8889
+ }
8890
+ /**
8891
+ * 新建/编辑表单:面包屑头部 + 规则类型下拉/描述/globs 控件行 + 原始 .mdc 文本域 + 保存/取消。
8892
+ * @author ddj 2026年09月03号
8893
+ * @param props.form 表单状态(mode/scope/workspacePath/relHint/file/content/fmType/desc/globs/error/saving)
8894
+ * @param props.onType 类型下拉变更回调
8895
+ * @param props.onDesc 描述输入回调
8896
+ * @param props.onGlobs globs 输入回调
8897
+ * @param props.onBody 文本域编辑回调
8898
+ * @param props.onSave 保存回调
8899
+ * @param props.onCancel 取消回调
8900
+ * @returns 表单元素
8901
+ */
8902
+ function RuleEditor(props) {
8903
+ const form = props.form;
8904
+ const isNew = form.mode === "new";
8905
+ const crumb = (form.scope === "project" ? "项目规则" : "用户规则") + " > " + form.relHint + " > " + (form.file || "新建规则.mdc");
8906
+ return react.default.createElement("div", { className: "edrv-rules-editor" }, react.default.createElement("div", { className: "edrv-rules-editor-head" }, react.default.createElement("span", {
8907
+ className: "edrv-rules-crumb",
8908
+ title: crumb
8909
+ }, crumb), react.default.createElement("button", {
8910
+ className: "edrv-rules-act",
8911
+ title: "取消",
8912
+ onClick: props.onCancel
8913
+ }, "✕")), react.default.createElement("div", { className: "edrv-rules-editor-ctl" }, react.default.createElement("label", { className: "edrv-rules-ctl-label" }, "规则类型"), react.default.createElement("select", {
8914
+ className: "edrv-rules-select",
8915
+ value: form.fmType,
8916
+ onChange: props.onType
8917
+ }, Object.keys(TYPE_LABEL).map((key) => react.default.createElement("option", {
8918
+ key,
8919
+ value: key
8920
+ }, TYPE_LABEL[key]))), react.default.createElement("label", { className: "edrv-rules-ctl-label" }, "描述"), react.default.createElement("input", {
8921
+ className: "edrv-rules-input edrv-rules-desc-input",
8922
+ value: form.desc,
8923
+ spellCheck: false,
8924
+ placeholder: isNew ? "规则用途说明(写入 frontmatter description)" : "规则用途说明",
8925
+ onChange: props.onDesc
8926
+ })), form.fmType === "auto" ? react.default.createElement("div", { className: "edrv-rules-editor-ctl" }, react.default.createElement("label", { className: "edrv-rules-ctl-label" }, "globs"), react.default.createElement("input", {
8927
+ className: "edrv-rules-input",
8928
+ value: form.globs,
8929
+ spellCheck: false,
8930
+ placeholder: "src/**/*.ts, *.md(逗号分隔,命中才注入)",
8931
+ onChange: props.onGlobs
8932
+ })) : null, react.default.createElement("textarea", {
8933
+ className: "edrv-rules-body",
8934
+ spellCheck: false,
8935
+ value: form.content,
8936
+ onChange: props.onBody
8937
+ }), react.default.createElement("div", { className: "edrv-rules-editor-hint" }, "类型/描述/globs 与 frontmatter 双向同步;enabled 与其余键原样保留;无 frontmatter 的纯 markdown 视为「手动」规则"), form.error ? react.default.createElement("div", { className: "edrv-rules-err" }, form.error) : null, react.default.createElement("div", { className: "edrv-rules-editor-foot" }, react.default.createElement("button", {
8938
+ className: "edrv-rules-save",
8939
+ disabled: form.saving,
8940
+ onClick: props.onSave
8941
+ }, form.saving ? "保存中…" : "保存")));
8942
+ }
8943
+ /**
8944
+ * 规则面板主体。
8945
+ * @param props.ctx 面板共享上下文(notify 可选)
8946
+ */
8947
+ function RulesPanel(props) {
8948
+ const ctx = props?.ctx;
8949
+ const notify = ctx?.notify ?? ((message) => {});
8950
+ const cwd = ctx?.cwd ?? null;
8951
+ const [tab, setTab] = react.default.useState(() => readLocal(CACHE_KEY.rules + "tab") === "project" ? "project" : "user");
8952
+ const [data, setData] = react.default.useState(null);
8953
+ const [error, setError] = react.default.useState("");
8954
+ const panelRef = react.default.useRef(null);
8955
+ const [panelW, setPanelW] = react.default.useState(0);
8956
+ const [form, setForm] = react.default.useState(null);
8957
+ const mountedRef = react.default.useRef(true);
8958
+ /**
8959
+ * 当前工作区对应的项目聚合(按 ctx.cwd 自动匹配;无会话/未注册返回 null)。
8960
+ * @returns RuleProject 或 null
8961
+ */
8962
+ const activeProject = () => {
8963
+ if (!cwd) return null;
8964
+ return (data?.projects ?? []).find((p) => p.workspacePath === cwd) ?? null;
8965
+ };
8966
+ /** 拉取规则总列表(rules.list)。 */
8967
+ const load = () => {
8968
+ rpc("rules.list", {}).then((res) => {
8969
+ if (!mountedRef.current) return;
8970
+ if (res && res.ok) {
8971
+ setData(res);
8972
+ setError("");
8973
+ } else setError(res?.error ?? "读取规则失败");
8974
+ }).catch((e) => {
8975
+ if (mountedRef.current) setError("读取规则异常: " + String(e));
8976
+ });
8977
+ };
8978
+ react.default.useEffect(() => {
8979
+ mountedRef.current = true;
8980
+ load();
8981
+ return () => {
8982
+ mountedRef.current = false;
8983
+ };
8984
+ }, []);
8985
+ react.default.useEffect(() => {
8986
+ const el = panelRef.current;
8987
+ if (!el || typeof ResizeObserver === "undefined") return void 0;
8988
+ const observer = new ResizeObserver(() => setPanelW(el.clientWidth));
8989
+ observer.observe(el);
8990
+ setPanelW(el.clientWidth);
8991
+ return () => observer.disconnect();
8992
+ }, []);
8993
+ const descCap = panelW > 0 ? descCapOf(panelW) : DESC_MAX;
8994
+ const narrow = panelW > 0 && panelW < NARROW_W;
8995
+ /**
8996
+ * 切换 Tab(记忆到 localStorage)。
8997
+ * @param next 目标 Tab
8998
+ */
8999
+ const switchTab = (next) => {
9000
+ setTab(next);
9001
+ writeLocal(CACHE_KEY.rules + "tab", next);
9002
+ };
9003
+ /**
9004
+ * 打开新建表单(按当前 Tab 决定作用域;项目规则跟随当前会话工作区)。
9005
+ */
9006
+ const openNew = () => {
9007
+ const scope = tab === "project" ? "project" : "user";
9008
+ if (scope === "project" && !cwd) {
9009
+ notify("当前会话没有工作区,无法新建项目规则");
9010
+ return;
9011
+ }
9012
+ const parsed = parseRuleFm(NEW_TEMPLATE);
9013
+ setForm({
9014
+ mode: "new",
9015
+ scope,
9016
+ workspacePath: scope === "project" ? cwd : void 0,
9017
+ relHint: scope === "project" ? ".dsh/rules/" : "rules/",
9018
+ file: "",
9019
+ content: NEW_TEMPLATE,
9020
+ fmType: parsed.type,
9021
+ desc: parsed.description,
9022
+ globs: parsed.globs.join(", "),
9023
+ error: "",
9024
+ saving: false
9025
+ });
9026
+ };
9027
+ /**
9028
+ * 打开编辑表单:先拉全文,再解析 frontmatter 回填类型/描述/globs 控件。
9029
+ * @param rule 目标规则
9030
+ */
9031
+ const openEdit = (rule) => {
9032
+ rpc("rules.read", {
9033
+ scope: rule.scope,
9034
+ workspacePath: rule.scope === "project" ? rule.workspacePath : void 0,
9035
+ file: rule.file
9036
+ }).then((res) => {
9037
+ if (!res || !res.ok) {
9038
+ notify(res?.error ?? "读取规则失败");
9039
+ return;
9040
+ }
9041
+ const parsed = parseRuleFm(res.content);
9042
+ setForm({
9043
+ mode: "edit",
9044
+ scope: rule.scope,
9045
+ workspacePath: rule.workspacePath,
9046
+ relHint: rule.relHint,
9047
+ file: rule.file,
9048
+ content: res.content,
9049
+ fmType: parsed.type,
9050
+ desc: parsed.description,
9051
+ globs: parsed.globs.join(", "),
9052
+ error: "",
9053
+ saving: false
9054
+ });
9055
+ }).catch((e) => notify("读取规则异常: " + String(e)));
9056
+ };
9057
+ /** 类型下拉变更:frontmatter 按新类型重写,控件同步。 */
9058
+ const onTypeChange = (e) => {
9059
+ const nextType = e.target.value;
9060
+ setForm((prev) => ({
9061
+ ...prev,
9062
+ fmType: nextType,
9063
+ content: rebuildContent(prev.content, nextType, prev.desc, prev.globs),
9064
+ error: ""
9065
+ }));
9066
+ };
9067
+ /** 描述输入变更:同步 frontmatter description 行。 */
9068
+ const onDescChange = (e) => {
9069
+ const nextDesc = e.target.value;
9070
+ setForm((prev) => ({
9071
+ ...prev,
9072
+ desc: nextDesc,
9073
+ content: rebuildContent(prev.content, prev.fmType, nextDesc, prev.globs),
9074
+ error: ""
9075
+ }));
9076
+ };
9077
+ /** globs 输入变更(自动规则):同步 frontmatter globs 行。 */
9078
+ const onGlobsChange = (e) => {
9079
+ const nextGlobs = e.target.value;
9080
+ setForm((prev) => ({
9081
+ ...prev,
9082
+ globs: nextGlobs,
9083
+ content: rebuildContent(prev.content, prev.fmType, prev.desc, nextGlobs),
9084
+ error: ""
9085
+ }));
9086
+ };
9087
+ /** 文本域直接编辑:回读 frontmatter,同步类型/描述/globs 控件(文本域是唯一真源)。 */
9088
+ const onBodyChange = (e) => {
9089
+ const parsed = parseRuleFm(e.target.value);
9090
+ setForm((prev) => ({
9091
+ ...prev,
9092
+ content: e.target.value,
9093
+ fmType: parsed.type,
9094
+ desc: parsed.description,
9095
+ globs: parsed.globs.join(", ")
9096
+ }));
9097
+ };
9098
+ /** 保存表单(rules.save;文件名非空 + 自动规则必须有 globs)。 */
9099
+ const saveForm = () => {
9100
+ const next = {
9101
+ ...form,
9102
+ saving: true,
9103
+ error: ""
9104
+ };
9105
+ const file = String(form.file ?? "").trim();
9106
+ if (!file) {
9107
+ setForm({
9108
+ ...next,
9109
+ saving: false,
9110
+ error: "文件名不能为空"
9111
+ });
9112
+ return;
9113
+ }
9114
+ if (form.fmType === "auto" && globList(form.globs).length === 0) {
9115
+ setForm({
9116
+ ...next,
9117
+ saving: false,
9118
+ error: "自动规则需要至少一个 glob(逗号分隔)"
9119
+ });
9120
+ return;
9121
+ }
9122
+ setForm(next);
9123
+ rpc("rules.save", {
9124
+ scope: form.scope,
9125
+ workspacePath: form.workspacePath,
9126
+ file,
9127
+ content: form.content
9128
+ }).then((res) => {
9129
+ if (res && res.ok) {
9130
+ setForm(null);
9131
+ notify("规则已保存:" + file);
9132
+ load();
9133
+ } else setForm((prev) => ({
9134
+ ...prev,
9135
+ saving: false,
9136
+ error: res?.error ?? "保存失败"
9137
+ }));
9138
+ }).catch((e) => setForm((prev) => ({
9139
+ ...prev,
9140
+ saving: false,
9141
+ error: "保存异常: " + String(e)
9142
+ })));
9143
+ };
9144
+ /**
9145
+ * 删除规则(confirm 后走 rules.remove)。
9146
+ * @param rule 目标规则
9147
+ */
9148
+ const removeRule = (rule) => {
9149
+ if (!window.confirm("删除规则 " + rule.file + "?(不可恢复)")) return;
9150
+ rpc("rules.remove", {
9151
+ scope: rule.scope,
9152
+ workspacePath: rule.workspacePath,
9153
+ file: rule.file
9154
+ }).then((res) => {
9155
+ if (res && res.ok) {
9156
+ notify("已删除:" + rule.file);
9157
+ load();
9158
+ } else notify(res?.error ?? "删除失败");
9159
+ }).catch((e) => notify("删除异常: " + String(e)));
9160
+ };
9161
+ /**
9162
+ * 切换启用开关:本地乐观翻转(按 workspacePath+file 定位,失败回滚)。
9163
+ * @param rule 目标规则(project 已注入 workspacePath)
9164
+ */
9165
+ const toggleRule = (rule) => {
9166
+ const enabled = !rule.enabled;
9167
+ const applyLocal = (on) => setData((prev) => prev ? {
9168
+ ...prev,
9169
+ user: prev.user.map((r) => r.scope === "user" && r.file === rule.file ? {
9170
+ ...r,
9171
+ enabled: on
9172
+ } : r),
9173
+ projects: prev.projects.map((p) => p.workspacePath === rule.workspacePath ? {
9174
+ ...p,
9175
+ rules: p.rules.map((r) => r.file === rule.file ? {
9176
+ ...r,
9177
+ enabled: on
9178
+ } : r)
9179
+ } : p)
9180
+ } : prev);
9181
+ applyLocal(enabled);
9182
+ rpc("rules.toggle", {
9183
+ scope: rule.scope,
9184
+ workspacePath: rule.workspacePath,
9185
+ file: rule.file,
9186
+ enabled
9187
+ }).then((res) => {
9188
+ if (res && res.ok) {
9189
+ applyLocal(res.rule?.enabled === true);
9190
+ notify(res.rule?.enabled === false ? "已停用:" + rule.file : "已启用:" + rule.file);
9191
+ } else {
9192
+ applyLocal(!enabled);
9193
+ notify(res?.error ?? "切换失败");
9194
+ }
9195
+ }).catch((e) => {
9196
+ applyLocal(!enabled);
9197
+ notify("切换异常: " + String(e));
9198
+ });
9199
+ };
9200
+ /** 当前列表数据(按 Tab 取用户规则或当前工作区的项目规则)。 */
9201
+ const rowsOf = () => {
9202
+ if (!data) return [];
9203
+ if (tab === "user") return data.user;
9204
+ return activeProject()?.rules ?? [];
9205
+ };
9206
+ const renderTabs = () => react.default.createElement("div", { className: "edrv-rules-tabs" }, react.default.createElement("button", {
9207
+ className: "edrv-rules-tab" + (tab === "user" ? " on" : ""),
9208
+ onClick: () => switchTab("user")
9209
+ }, "用户规则"), react.default.createElement("button", {
9210
+ className: "edrv-rules-tab" + (tab === "project" ? " on" : ""),
9211
+ onClick: () => switchTab("project")
9212
+ }, "项目规则"), react.default.createElement("button", {
9213
+ className: "edrv-rules-new",
9214
+ title: "新建规则",
9215
+ onClick: openNew
9216
+ }, "+ 新建规则"));
9217
+ /** 项目 Tab 的工作区展示(不可编辑,自动跟随当前会话)。 */
9218
+ const renderWsLine = () => {
9219
+ if (tab !== "project") return null;
9220
+ return react.default.createElement("div", {
9221
+ className: "edrv-rules-ws-line",
9222
+ title: cwd ?? ""
9223
+ }, "工作区:" + (cwd ?? "当前会话未打开工作区"));
9224
+ };
9225
+ const renderEmpty = () => {
9226
+ if (tab === "project") {
9227
+ if (!cwd) return "当前会话没有工作区,项目规则不可用(项目规则跟随会话所在工作区)";
9228
+ if (!data?.projects?.length) return "当前 DSH 没有已注册的工作区;在目标工作区打开一次会话后再来管理";
9229
+ if (!activeProject()) return "当前工作区未注册为 DSH workspace,暂不能管理其项目规则";
9230
+ return "<工作区>/.dsh/rules/ 还没有规则,点击「+ 新建规则」创建";
9231
+ }
9232
+ return "还没有用户规则(~/.dsh/rules/),点击「+ 新建规则」创建";
9233
+ };
9234
+ const renderBody = () => {
9235
+ if (form) return react.default.createElement(RuleEditor, {
9236
+ form,
9237
+ onType: onTypeChange,
9238
+ onDesc: onDescChange,
9239
+ onGlobs: onGlobsChange,
9240
+ onBody: onBodyChange,
9241
+ onSave: saveForm,
9242
+ onCancel: () => setForm(null)
9243
+ });
9244
+ if (!data) return react.default.createElement("div", { className: "edrv-rules-empty" }, "加载中…");
9245
+ if (error) return react.default.createElement("div", { className: "edrv-rules-err" }, error);
9246
+ const rows = rowsOf();
9247
+ if (!rows.length) return react.default.createElement("div", { className: "edrv-rules-empty" }, renderEmpty());
9248
+ const common = {
9249
+ descCap,
9250
+ narrow,
9251
+ onEdit: (rule) => openEdit({
9252
+ ...rule,
9253
+ workspacePath: rule.scope === "project" ? cwd : void 0
9254
+ }),
9255
+ onRemove: (rule) => removeRule({
9256
+ ...rule,
9257
+ workspacePath: rule.scope === "project" ? cwd : void 0
9258
+ }),
9259
+ onToggle: (rule) => toggleRule({
9260
+ ...rule,
9261
+ workspacePath: rule.scope === "project" ? cwd : void 0
9262
+ })
9263
+ };
9264
+ return react.default.createElement("div", { className: "edrv-rules-list" }, rows.map((rule) => react.default.createElement(RuleRow, {
9265
+ key: rule.scope + ":" + rule.file,
9266
+ rule,
9267
+ ...common
9268
+ })));
9269
+ };
9270
+ return react.default.createElement("div", {
9271
+ className: "edrv-rules-panel",
9272
+ ref: panelRef
9273
+ }, renderTabs(), renderWsLine(), react.default.createElement("div", { className: "edrv-rules-hint" }, tab === "user" ? "用户规则对所有会话生效(存放于 ~/.dsh/rules/)" : "项目规则仅对所在工作区的会话生效(存放于 <工作区>/.dsh/rules/)"), renderBody());
9274
+ }
9275
+ //#endregion
8442
9276
  //#region src/client/sidebar/panels/index.ts
8443
9277
  /**
8444
- * dsh-vscode-mode client — 侧边栏面板定义(文件管理 + 搜索)。
8445
- * 作者 ddj 2026-08-26 / 2026-08-26
9278
+ * dsh-vscode-mode client — 侧边栏面板定义(文件管理 + 搜索 + 规则)。
9279
+ * 作者 ddj 2026-08-26 / 2026-09-03
8446
9280
  */
8447
9281
  /**
8448
9282
  * 构造文件管理面板定义。
@@ -8473,6 +9307,20 @@ window.__ModuleLoader__.load({
8473
9307
  render: (ctx) => react.default.createElement(SearchPanel, { ctx })
8474
9308
  };
8475
9309
  }
9310
+ /**
9311
+ * 构造规则管理面板定义(Codebuddy 规则形态:用户规则/项目规则双 Tab + 开关)。
9312
+ * @author ddj 2026年09月03号
9313
+ * @returns 面板定义(无徽标;活动栏图标 📏,与大纲 📜 区分)
9314
+ */
9315
+ function createRulesPanel() {
9316
+ return {
9317
+ id: "rules",
9318
+ title: "规则",
9319
+ icon: "📏",
9320
+ order: 20,
9321
+ render: (ctx) => react.default.createElement(RulesPanel, { ctx })
9322
+ };
9323
+ }
8476
9324
  //#endregion
8477
9325
  //#region src/client/sidebar/menuItems.ts
8478
9326
  /**
@@ -9407,6 +10255,7 @@ window.__ModuleLoader__.load({
9407
10255
  ctx.provide("edrvSidebarPanels", sidebarPanels);
9408
10256
  ctx.effect(() => sidebarPanels.register(createFilePanel()), "vscode-mode: sidebar panel");
9409
10257
  ctx.effect(() => sidebarPanels.register(createSearchPanel()), "vscode-mode: sidebar panel search");
10258
+ ctx.effect(() => sidebarPanels.register(createRulesPanel()), "vscode-mode: sidebar panel rules");
9410
10259
  const fileMenuItems = createTreeMenuRegistry();
9411
10260
  ctx.provide("edrvFileContextMenuItems", fileMenuItems);
9412
10261
  for (const item of createDefaultFileMenuItems()) ctx.effect(() => fileMenuItems.register(item), "vscode-mode: file context menu item " + item.id);
@@ -9442,6 +10291,8 @@ window.__ModuleLoader__.load({
9442
10291
  const snapshot = settings.getSnapshot();
9443
10292
  if (snapshot.status === "loading") return;
9444
10293
  keybindingsApply(snapshot.value?.keybindings);
10294
+ const minW = sidebarMinApply(snapshot.value?.sidebarMinWidth);
10295
+ window.dispatchEvent(new CustomEvent("edrv:sidebar-min-width", { detail: { value: minW } }));
9445
10296
  };
9446
10297
  sync();
9447
10298
  return settings.subscribe(sync);
@@ -9474,7 +10325,8 @@ window.__ModuleLoader__.load({
9474
10325
  addToConversation,
9475
10326
  sidebarPanels,
9476
10327
  outlineSources,
9477
- fileMenuItems
10328
+ fileMenuItems,
10329
+ sessions
9478
10330
  })));
9479
10331
  };
9480
10332
  let sideDisposer = null;
@@ -9493,7 +10345,8 @@ window.__ModuleLoader__.load({
9493
10345
  addToConversation,
9494
10346
  sidebarPanels,
9495
10347
  outlineSources,
9496
- fileMenuItems
10348
+ fileMenuItems,
10349
+ sessions
9497
10350
  })),
9498
10351
  activeSession: () => {
9499
10352
  const snapshot = sessions?.list?.getSnapshot?.();