dsh-vscode-mode 0.1.29 → 0.1.32

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-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-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\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";
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-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-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";
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");
@@ -50,6 +50,19 @@ window.__ModuleLoader__.load({
50
50
  * 迁移自原 src/client/index.ts 的 rpc/dbg,语义不改。
51
51
  * 作者 ddj 2026-08-20
52
52
  */
53
+ /**
54
+ * 诊断日志开关(默认关):diff 渲染热路径每条日志 = 1 次 RPC 往返 +
55
+ * host 端 debug 文件全量读改写(上限 512KB),高频渲染下开销可观。
56
+ * 排查问题时在浏览器控制台执行 localStorage.setItem('edrv.debug','1') 后刷新开启。
57
+ * @author ddj 2026年08月26号
58
+ */
59
+ const DEBUG = (() => {
60
+ try {
61
+ return localStorage.getItem("edrv.debug") === "1";
62
+ } catch (e) {
63
+ return false;
64
+ }
65
+ })();
53
66
  /** 同源 RPC 调用(host /edrv/rpc 精确路由)。 */
54
67
  function rpc(method, args) {
55
68
  return fetch(RPC_PATH, {
@@ -62,12 +75,13 @@ window.__ModuleLoader__.load({
62
75
  }).then((res) => res.json());
63
76
  }
64
77
  /**
65
- * 诊断日志:统一走 host edrv.debug 落盘,避免 console 刷屏。
66
- * @author ddj 2026年08月20号
78
+ * 诊断日志:开关关闭时直接返回(零 RPC 零落盘);开启时走 host edrv.debug 落盘。
79
+ * @author ddj 2026年08月26号
67
80
  * @param sessionId 会话 id
68
81
  * @param text 日志文本
69
82
  */
70
83
  function dbg(sessionId, text) {
84
+ if (!DEBUG) return;
71
85
  try {
72
86
  rpc("edrv.debug", {
73
87
  sessionId,
@@ -555,6 +569,8 @@ window.__ModuleLoader__.load({
555
569
  function createDiffRenderer(log) {
556
570
  let viewZoneIds = [];
557
571
  let decorations = [];
572
+ /** 上次已渲染的差异指纹(callId:idx@start-end:oldLen/newLen 串):内容未变时跳过重建。 */
573
+ let lastKey = null;
558
574
  /**
559
575
  * 渲染当前 pending 差异:绿底 decoration + 删除块 view zones + '-' 号 overlay(滚动同步)。
560
576
  * @param monaco window.monaco
@@ -566,6 +582,9 @@ window.__ModuleLoader__.load({
566
582
  if (!pendingRegions.length && viewZoneIds.length === 0 && decorations.length === 0) return;
567
583
  const renderT0 = Date.now();
568
584
  const callIdAttr = (callId, idx) => String(callId) + ":" + String(idx);
585
+ const key = pendingRegions.map((r) => callIdAttr(r.callId, r.idx) + "@" + (r.start ?? "?") + "-" + (r.end ?? "?") + ":" + (r.oldLines ? r.oldLines.length : 0) + "/" + (r.newLines ? r.newLines.length : 0)).join("|");
586
+ if (key === lastKey) return;
587
+ lastKey = key;
569
588
  log(sessionId, "[diff-render] begin regs=" + pendingRegions.length + " " + pendingRegions.map((r) => callIdAttr(r.callId, r.idx) + "@" + (r.start ?? "?") + "-" + (r.end ?? "?") + "(-" + (r.oldLines ? r.oldLines.length : 0) + "/+" + (r.newLines ? r.newLines.length : 0) + ")").join("|"));
570
589
  const decos = [];
571
590
  for (const r of pendingRegions) {
@@ -1819,15 +1838,42 @@ window.__ModuleLoader__.load({
1819
1838
  }
1820
1839
  }
1821
1840
  //#endregion
1841
+ //#region src/client/paths.ts
1842
+ /**
1843
+ * dsh-vscode-mode client — 浏览器端缓存键/路径统一出口(PathConst)。
1844
+ * 统一 localStorage 键前缀(各缓存模块/编辑区/搜索面板共用),避免内联散落;
1845
+ * 键带 schema 版本号,未来版本递增时经 sweepLegacyKeys 自动清旧。
1846
+ * 浏览器不涉 ~/.dsh 文件系统,这里只管键名 + shared 路由常量。
1847
+ * 作者 ddj 2026-09-01
1848
+ */
1849
+ /** localStorage 键前缀表(按功能隔离;均按会话拼接)。 */
1850
+ const CACHE_KEY = {
1851
+ /** 展开状态(explorerCache v1,当前使用)。 */
1852
+ expanded: "edrv.cache.explorer.v1.",
1853
+ /** 目录条目 SWR 缓存(explorerEntriesCache v2,当前使用)。 */
1854
+ entries: "edrv.cache.entries.v2.",
1855
+ /** 编辑区视图状态(viewStateCache v1)。 */
1856
+ viewstate: "edrv.cache.viewstate.v1.",
1857
+ /** 编辑器页签/活动文件(EditorView v2)。 */
1858
+ editor: "edrv.editor.v2.",
1859
+ /** 侧边栏状态(EditorView;按布局 side/central 追加段)。 */
1860
+ sidebar: "edrv.sidebar.",
1861
+ /** 搜索面板条件(SearchPanel v1)。 */
1862
+ search: "edrv.search.v1.",
1863
+ /** 侧边栏提示已关闭标记(全局,无会话)。 */
1864
+ sideHint: "edrv.side-hint-dismissed"
1865
+ };
1866
+ //#endregion
1822
1867
  //#region src/client/state/viewStateCache.ts
1823
1868
  /**
1824
1869
  * dsh-vscode-mode client — 编辑器视图状态持久化(纯函数,可单测)。
1825
1870
  * 对齐 VSCode workbench.editor.restoreViewState:恢复每个文件的光标/滚动/折叠位置。
1826
1871
  * 视图状态 = Monaco editor.saveViewState() 返回值(JSON 可序列化),按 path 存储。
1872
+ * 键前缀统一走 paths.ts PathConst(CACHE_KEY.viewstate)。
1827
1873
  * 作者 ddj 2026-08-28
1828
1874
  */
1829
1875
  /** localStorage 键前缀(按会话隔离)。 */
1830
- const KEY_PREFIX$1 = "edrv.cache.viewstate.v1.";
1876
+ const KEY_PREFIX$2 = CACHE_KEY.viewstate;
1831
1877
  /**
1832
1878
  * 判断对象是否为合法的 Monaco view state(保守形状校验,非深校验)。
1833
1879
  * @author ddj 2026年08月28号
@@ -1905,7 +1951,7 @@ window.__ModuleLoader__.load({
1905
1951
  */
1906
1952
  function viewStatesLoad(sessionId) {
1907
1953
  try {
1908
- return parseViewStates(window.localStorage.getItem(KEY_PREFIX$1 + String(sessionId))) ?? {};
1954
+ return parseViewStates(window.localStorage.getItem(KEY_PREFIX$2 + String(sessionId))) ?? {};
1909
1955
  } catch (error) {
1910
1956
  return {};
1911
1957
  }
@@ -1918,7 +1964,7 @@ window.__ModuleLoader__.load({
1918
1964
  */
1919
1965
  function viewStatesSave(sessionId, states) {
1920
1966
  try {
1921
- window.localStorage.setItem(KEY_PREFIX$1 + String(sessionId), serializeViewStates(states));
1967
+ window.localStorage.setItem(KEY_PREFIX$2 + String(sessionId), serializeViewStates(states));
1922
1968
  } catch (error) {}
1923
1969
  }
1924
1970
  //#endregion
@@ -1974,7 +2020,7 @@ window.__ModuleLoader__.load({
1974
2020
  useKeybindingsVersion();
1975
2021
  const [hintDismissed, setHintDismissed] = react.default.useState(() => {
1976
2022
  try {
1977
- return localStorage.getItem("edrv.side-hint-dismissed") === "1";
2023
+ return localStorage.getItem(CACHE_KEY.sideHint) === "1";
1978
2024
  } catch {
1979
2025
  return false;
1980
2026
  }
@@ -2274,7 +2320,7 @@ window.__ModuleLoader__.load({
2274
2320
  bootRef.current = true;
2275
2321
  viewStatesRef.current = viewStatesLoad(sessionId);
2276
2322
  try {
2277
- const raw = localStorage.getItem("edrv.editor.v2." + String(sessionId));
2323
+ const raw = localStorage.getItem(CACHE_KEY.editor + String(sessionId));
2278
2324
  if (raw) {
2279
2325
  const saved = JSON.parse(raw);
2280
2326
  if (Array.isArray(saved.tabs) && saved.tabs.length) {
@@ -2287,7 +2333,7 @@ window.__ModuleLoader__.load({
2287
2333
  react.default.useEffect(() => {
2288
2334
  if (!sessionId) return;
2289
2335
  try {
2290
- localStorage.setItem("edrv.editor.v2." + String(sessionId), JSON.stringify({
2336
+ localStorage.setItem(CACHE_KEY.editor + String(sessionId), JSON.stringify({
2291
2337
  tabs: tabs.map((t) => t.path),
2292
2338
  active
2293
2339
  }));
@@ -2297,7 +2343,7 @@ window.__ModuleLoader__.load({
2297
2343
  active,
2298
2344
  sessionId
2299
2345
  ]);
2300
- const sidebarKey = "edrv.sidebar." + (layout === "side" ? "side." : "") + String(sessionId);
2346
+ const sidebarKey = CACHE_KEY.sidebar + (layout === "side" ? "side." : "") + String(sessionId);
2301
2347
  react.default.useEffect(() => {
2302
2348
  if (!sessionId) return;
2303
2349
  try {
@@ -2790,7 +2836,7 @@ window.__ModuleLoader__.load({
2790
2836
  ok++;
2791
2837
  if (item.record) next[item.callId] = item.record;
2792
2838
  } else fail++;
2793
- setRecords((prev) => Object.assign({}, prev, next));
2839
+ if (Object.keys(next).length) setRecords((prev) => Object.assign({}, prev, next));
2794
2840
  return {
2795
2841
  ok,
2796
2842
  fail
@@ -2817,19 +2863,29 @@ window.__ModuleLoader__.load({
2817
2863
  decision: reject ? "rejected" : "accepted"
2818
2864
  });
2819
2865
  const acceptFile = () => {
2866
+ if (batchBusyRef.current || !pendingRegions.length) return;
2867
+ batchBusyRef.current = true;
2820
2868
  actMany(pendingRegions.map((r) => itemOf(r, false))).then(({ ok, fail }) => {
2869
+ batchBusyRef.current = false;
2821
2870
  reloadFile(true);
2822
2871
  emitRefresh();
2823
2872
  setStatus("已采纳 " + ok + " 处差异" + (fail ? "," + fail + " 处失败" : ""));
2824
2873
  if (fail) setError(fail + " 处差异处理失败(可能已被后续修改影响),可刷新后重试");
2874
+ }).catch(() => {
2875
+ batchBusyRef.current = false;
2825
2876
  });
2826
2877
  };
2827
2878
  const undoFile = () => {
2879
+ if (batchBusyRef.current || !pendingRegions.length) return;
2880
+ batchBusyRef.current = true;
2828
2881
  actMany([...pendingRegions].reverse().map((r) => itemOf(r, true))).then(({ ok, fail }) => {
2882
+ batchBusyRef.current = false;
2829
2883
  reloadFile(true);
2830
2884
  emitRefresh();
2831
2885
  setStatus("已不采纳 " + ok + " 处差异" + (fail ? "," + fail + " 处失败" : ""));
2832
2886
  if (fail) setError(fail + " 处差异处理失败(可能已被后续修改影响),可刷新后重试");
2887
+ }).catch(() => {
2888
+ batchBusyRef.current = false;
2833
2889
  });
2834
2890
  };
2835
2891
  const allPending = react.default.useMemo(() => {
@@ -3263,7 +3319,7 @@ window.__ModuleLoader__.load({
3263
3319
  const dismissHint = () => {
3264
3320
  setHintDismissed(true);
3265
3321
  try {
3266
- localStorage.setItem("edrv.side-hint-dismissed", "1");
3322
+ localStorage.setItem(CACHE_KEY.sideHint, "1");
3267
3323
  } catch (e) {}
3268
3324
  };
3269
3325
  const copyInstallCmd = () => {
@@ -3403,6 +3459,71 @@ window.__ModuleLoader__.load({
3403
3459
  } }, String(n)));
3404
3460
  }
3405
3461
  //#endregion
3462
+ //#region src/client/ui/PerfSizeBadge.ts
3463
+ /**
3464
+ * dsh-vscode-mode client — PerfSizeBadge:对话 header 会话体积指示器。
3465
+ * 5s 轮询当前会话持久化体积(host 仅 stat,近零成本),≥1MB 显示、超阈值变色,
3466
+ * 引导"一次任务一个短会话":会话过大时建议 /compact 或新开会话。
3467
+ * 作者 ddj 2026-09-02
3468
+ */
3469
+ /** 软阈值:≥ 此值琥珀色(默认 2MB)。 */
3470
+ const SOFT = 2097152;
3471
+ /** 硬阈值:≥ 此值红色(默认 8MB)。 */
3472
+ const HARD = 8388608;
3473
+ /** 显示下限:≥ 1MB 才显示(太小无提示价值)。 */
3474
+ const SHOW_MIN = 1048576;
3475
+ /**
3476
+ * 会话 header 体积徽章(挂 conversation.session.header.utilities)。
3477
+ * @author ddj 2026年09月02号
3478
+ * @param props { sessionId, sessions }(sessions 供 cwd 解析)
3479
+ */
3480
+ function PerfSizeBadge(props) {
3481
+ const sessionId = props?.sessionId;
3482
+ const sessions = props?.sessions;
3483
+ const [size, setSize] = react.default.useState(null);
3484
+ const seq = react.default.useRef(0);
3485
+ const load = react.default.useCallback(() => {
3486
+ if (!sessionId) return;
3487
+ const cwd = sessions?.list?.getSnapshot?.()?.byId?.[sessionId]?.cwd;
3488
+ if (!cwd) return;
3489
+ const s = ++seq.current;
3490
+ rpc("edrv.perf.sessionSize", {
3491
+ sessionId,
3492
+ cwd
3493
+ }).then((res) => {
3494
+ if (s !== seq.current || !res || !res.ok) return;
3495
+ setSize(res.exists ? res.bytes : 0);
3496
+ }).catch(() => {});
3497
+ }, [sessionId, sessions]);
3498
+ react.default.useEffect(() => {
3499
+ load();
3500
+ const t = setInterval(load, 5e3);
3501
+ return () => {
3502
+ clearInterval(t);
3503
+ };
3504
+ }, [load]);
3505
+ if (!size || size < SHOW_MIN) return null;
3506
+ const label = size >= 1048576 ? (size / 1048576).toFixed(1) + "MB" : Math.round(size / 1024) + "KB";
3507
+ const color = size >= HARD ? "#dc2626" : size >= SOFT ? "#d97706" : "var(--dsw-text-3,#6b7280)";
3508
+ const tip = "当前会话已持久化 " + label + "(启动回放约放大 10×,占内存)。过大建议 /compact 或新开会话。";
3509
+ return react.default.createElement("span", {
3510
+ style: {
3511
+ display: "inline-flex",
3512
+ alignItems: "center",
3513
+ height: 30,
3514
+ padding: "0 8px",
3515
+ fontSize: 11,
3516
+ color,
3517
+ borderRadius: 6,
3518
+ cursor: "default",
3519
+ whiteSpace: "nowrap",
3520
+ gap: 4,
3521
+ lineHeight: "30px"
3522
+ },
3523
+ title: tip
3524
+ }, "会话 " + label);
3525
+ }
3526
+ //#endregion
3406
3527
  //#region src/client/ui/DiffBox.ts
3407
3528
  /**
3408
3529
  * dsh-vscode-mode client — DiffBox:每个文件底部紧凑差异条(per-file hunk + ⋮ 二级菜单)。
@@ -3628,7 +3749,7 @@ window.__ModuleLoader__.load({
3628
3749
  }
3629
3750
  //#endregion
3630
3751
  //#region \0dsh-css:/home/runner/work/DSH_VsCodeMode/DSH_VsCodeMode/src/client/styles/mcp.css.mjs
3631
- const css = "/* dsh-vscode-mode MCP 管理界面样式。\n 全部使用 DSH 真实主题变量(--dsw-alias-*),不再用不存在的 fg-* 变量。 */\n.vsm-mcp-page{display:flex;flex-direction:column;gap:18px;width:100%;max-width:920px;box-sizing:border-box;color:var(--dsw-alias-label-primary,#e6e6e6);padding-bottom:32px}\n\n/* 顶部:标题 + 副标题 + 添加按钮 */\n.vsm-mcp-header{display:flex;align-items:flex-start;justify-content:space-between;gap:20px}\n.vsm-mcp-header h2{margin:0 0 4px;font-size:20px;font-weight:600;line-height:1.35;color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-mcp-header p{margin:0;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:13px;line-height:1.5}\n.vsm-primary{border:0;border-radius:6px;padding:8px 16px;background:var(--dsw-alias-button-primary-fill,#6d55ff);color:var(--dsw-alias-button-contrast-fill,#fff);font-size:13px;font-weight:500;cursor:pointer;white-space:nowrap}\n.vsm-primary:hover{background:var(--dsw-alias-button-primary-hover,#5a46e6)}\n.vsm-primary:disabled{opacity:.55;cursor:default}\n\n/* 子 Tab:我的 MCP / MCP 市场 */\n.vsm-mcp-tabs{display:flex;gap:24px;border-bottom:1px solid var(--dsw-alias-border-l2,#3a3a3a)}\n.vsm-mcp-tabs button{border:0;background:none;color:var(--dsw-alias-label-tertiary,#9aa5b1);padding:9px 2px 11px;cursor:pointer;font-size:14px;position:relative}\n.vsm-mcp-tabs button:hover{color:var(--dsw-alias-label-secondary,#c8c8c8)}\n.vsm-mcp-tabs button.active{color:var(--dsw-alias-label-primary,#fff);font-weight:500}\n.vsm-mcp-tabs button.active::after{content:\"\";position:absolute;left:0;right:0;bottom:-1px;height:2px;background:var(--dsw-alias-brand-primary,#6d55ff);border-radius:2px}\n\n/* 通用设置 */\n.vsm-general-page{display:flex;flex-direction:column;gap:10px;max-width:720px}\n.vsm-general-page h2{margin:0;font-size:20px;color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-general-page p{margin:0 0 8px;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:13px}\n.vsm-general-row{display:flex;align-items:center;justify-content:space-between;gap:20px;padding:14px 0;border-bottom:1px solid var(--dsw-alias-border-l1,#333);color:var(--dsw-alias-label-primary,#eee);font-size:14px}\n.vsm-general-row select{min-width:220px;padding:8px 10px;border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;background:var(--dsw-alias-bg-layer-1,#2b2b2b);color:var(--dsw-alias-label-primary,#eee);font:inherit}\n.vsm-general-row small{color:var(--dsw-alias-label-tertiary,#9aa5b1)}\n\n/* 服务卡片 */\n.vsm-mcp-card{border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:10px;padding:14px 16px;margin-bottom:10px;background:var(--dsw-alias-bg-layer-2,transparent);transition:border-color .15s}\n.vsm-mcp-card:hover{border-color:var(--dsw-alias-border-l3,#555)}\n.vsm-mcp-card-head{display:flex;justify-content:space-between;align-items:center;gap:12px}\n.vsm-mcp-title{display:flex;align-items:center;gap:9px;font-weight:600;font-size:14px;color:var(--dsw-alias-label-primary,#e6e6e6);min-width:0}\n.vsm-mcp-source{font-size:11px;font-weight:400;padding:2px 7px;border-radius:4px;background:var(--dsw-alias-bg-mask-2,#ffffff22);color:var(--dsw-alias-label-tertiary,#9aa5b1);flex-shrink:0}\n.vsm-mcp-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0;background:var(--dsw-alias-state-error-primary,#e05252)}\n.vsm-mcp-dot.connected{background:var(--dsw-alias-state-success-primary,#38bd75)}\n.vsm-mcp-dot.connecting{background:var(--dsw-alias-state-warn-primary,#e5b93f)}\n.vsm-mcp-dot.disabled{background:var(--dsw-alias-label-tertiary,#9aa5b1)}\n.vsm-mcp-actions{display:flex;align-items:center;gap:4px;flex-shrink:0}\n.vsm-mcp-actions button{border:0;background:none;color:var(--dsw-alias-label-tertiary,#9aa5b1);cursor:pointer;font-size:15px;width:28px;height:28px;border-radius:6px;line-height:1}\n.vsm-mcp-actions button:hover{color:var(--dsw-alias-label-primary,#fff);background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n.vsm-mcp-actions button.vsm-danger:hover{color:var(--dsw-alias-state-error-primary,#f07878);background:var(--dsw-alias-interactive-bg-hover-danger,#ff000014)}\n.vsm-switch{font-size:14px !important}\n.vsm-switch.on{color:var(--dsw-alias-state-success-primary,#38bd75)}\n.vsm-mcp-meta{font-size:12px;color:var(--dsw-alias-label-tertiary,#9aa5b1);margin:9px 0}\n.vsm-mcp-error{color:var(--dsw-alias-state-error-primary,#f07878);font-size:12px;margin:8px 0}\n.vsm-mcp-banner{padding:9px 12px;border:1px solid var(--dsw-alias-state-error-secondary,#d9534f55);border-radius:6px;background:var(--dsw-alias-state-error-secondary,#d9534f1a);margin-bottom:10px}\n\n/* 工具 chips */\n.vsm-mcp-tools{display:flex;flex-wrap:wrap;gap:6px}\n.vsm-mcp-chip{font:12px var(--ds-font-family-code,ui-monospace,monospace);padding:4px 8px;border-radius:5px;background:var(--dsw-alias-bg-mask-2,#ffffff14);color:var(--dsw-alias-label-secondary,#c8c8c8);border:1px solid var(--dsw-alias-border-l1,#333)}\n\n/* 空态 / 加载态 */\n.vsm-mcp-empty{text-align:center;padding:56px 20px;color:var(--dsw-alias-label-tertiary,#9aa5b1);border:1px dashed var(--dsw-alias-border-l2,#3a3a3a);border-radius:8px;font-size:13px}\n\n/* 项目搜索下拉框 */\n.vsm-project-picker{position:relative;width:100%;z-index:4}\n.vsm-project-picker-trigger{width:100%;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 12px;border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:8px;background:var(--dsw-alias-bg-layer-1,transparent);color:var(--dsw-alias-label-primary,#e6e6e6);cursor:pointer;text-align:left}\n.vsm-project-picker-trigger:hover{border-color:var(--dsw-alias-brand-primary,#6d55ff)}\n.vsm-project-picker-label{display:flex;flex-direction:column;min-width:0;font-size:13px;font-weight:500}\n.vsm-project-picker-label small{margin-top:3px;color:var(--dsw-alias-label-tertiary,#9aa5b1);font:11px var(--ds-font-family-code,ui-monospace,monospace);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.vsm-project-picker-arrow{color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:16px}\n.vsm-project-picker-menu{position:absolute;top:calc(100% + 6px);left:0;right:0;padding:8px;border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:9px;background:var(--dsw-alias-bg-overlay,#202020);box-shadow:0 12px 36px #0008}\n.vsm-project-picker-search{width:100%;box-sizing:border-box;padding:8px 10px;border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;background:var(--dsw-alias-bg-layer-1,#2b2b2b);color:var(--dsw-alias-label-primary,#eee);outline:none}\n.vsm-project-picker-search:focus{border-color:var(--dsw-alias-brand-primary,#6d55ff)}\n.vsm-project-picker-options{max-height:260px;overflow:auto;margin-top:6px}\n.vsm-project-option{display:flex;width:100%;flex-direction:column;gap:3px;padding:8px 9px;border:0;border-radius:6px;background:none;color:var(--dsw-alias-label-primary,#eee);cursor:pointer;text-align:left}\n.vsm-project-option:hover,.vsm-project-option.highlight{background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n.vsm-project-option.selected{color:var(--dsw-alias-brand-primary,#6d55ff)}\n.vsm-project-option small{overflow:hidden;color:var(--dsw-alias-label-tertiary,#9aa5b1);font:11px var(--ds-font-family-code,ui-monospace,monospace);text-overflow:ellipsis;white-space:nowrap}\n.vsm-project-picker-empty{padding:18px 8px;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:12px;text-align:center}\n\n/* 项目级 MCP 分组 */\n.vsm-project{border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:12px;margin-bottom:14px;overflow:hidden;background:var(--dsw-alias-bg-layer-1,transparent)}\n.vsm-project-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 16px;border-bottom:1px solid var(--dsw-alias-border-l1,#333);background:var(--dsw-alias-bg-mask-1,#ffffff0a)}\n.vsm-project-title{display:flex;align-items:center;gap:10px;min-width:0}\n.vsm-project-icon{color:var(--dsw-alias-brand-primary,#6d55ff);font-size:15px;flex-shrink:0}\n.vsm-project-name{font-size:14px;font-weight:600;color:var(--dsw-alias-label-primary,#e6e6e6);display:block}\n.vsm-project-path{font-size:11px;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-family:var(--ds-font-family-code,ui-monospace,monospace);display:block;margin-top:2px;word-break:break-all}\n.vsm-primary.vsm-small{padding:5px 12px;font-size:12px}\n.vsm-project-empty{text-align:center;padding:26px 16px;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:12px}\n.vsm-project .vsm-mcp-card{border:0;border-radius:0;margin:0;border-bottom:1px solid var(--dsw-alias-border-l1,#333);background:transparent}\n.vsm-project .vsm-mcp-card:last-child{border-bottom:0}\n.vsm-project .vsm-mcp-banner{border-radius:0;margin:0}\n\n/* 新增 MCP 弹窗 */\n.vsm-mcp-modal{position:fixed;inset:0;background:var(--dsw-alias-bg-mask-drop,#000000aa);display:flex;align-items:center;justify-content:center;z-index:50}\n.vsm-mcp-dialog{width:min(560px,calc(100vw - 40px));max-height:88vh;overflow:auto;padding:22px 24px;border-radius:12px;background:var(--dsw-alias-bg-overlay,#202020);border:1px solid var(--dsw-alias-border-l2,#444);box-shadow:0 16px 60px #000c;color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-mcp-dialog h3{margin:0 0 14px;font-size:16px;font-weight:600}\n.vsm-mcp-dialog label{display:flex;flex-direction:column;gap:6px;margin:12px 0;font-size:12px;color:var(--dsw-alias-label-secondary,#aaa)}\n.vsm-mcp-dialog input,.vsm-mcp-dialog select,.vsm-mcp-dialog textarea{font:inherit;color:var(--dsw-alias-label-primary,#eee);background:var(--dsw-alias-bg-layer-1,#2b2b2b);border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;padding:8px 10px}\n.vsm-mcp-dialog input:focus,.vsm-mcp-dialog select:focus,.vsm-mcp-dialog textarea:focus{outline:none;border-color:var(--dsw-alias-brand-primary,#6d55ff)}\n.vsm-mcp-dialog textarea{min-height:64px;resize:vertical;font-family:var(--ds-font-family-code,ui-monospace,monospace)}\n.vsm-mcp-dialog-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:20px}\n.vsm-mcp-dialog-actions button{padding:8px 14px;border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;background:none;color:var(--dsw-alias-label-primary,#eee);cursor:pointer;font-size:13px}\n.vsm-mcp-dialog-actions button:hover{background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n\n/* 兼容性小节 */\n.vsm-compat-h3{margin:16px 0 2px;font-size:14px;font-weight:600;color:var(--dsw-alias-label-secondary,#c8c8c8)}\n.vsm-compat-item{display:flex;align-items:baseline;justify-content:space-between;gap:16px;padding:10px 0;border-bottom:1px solid var(--dsw-alias-border-l1,#333);font-size:13px;color:var(--dsw-alias-label-primary,#eee)}\n.vsm-compat-item.ok .vsm-compat-name::before{content:\"● \";color:var(--dsw-alias-state-success-primary,#38bd75)}\n.vsm-compat-item.warn .vsm-compat-name::before{content:\"● \";color:var(--dsw-alias-state-warn-primary,#e5b93f)}\n.vsm-compat-name{font-weight:500;min-width:0}\n.vsm-compat-note{color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:12px;text-align:right;min-width:0}\n\n/* 开发形态开关 */\n.vsm-devform-note{display:block;margin-top:4px;font-size:11px;color:var(--dsw-alias-label-tertiary,#9aa5b1);word-break:break-all}\n.vsm-devform-actions{display:flex;flex-direction:column;align-items:flex-end;gap:6px;min-width:0}\n.vsm-devform-msg{color:var(--dsw-alias-state-warn-primary,#e5b93f);font-size:11px;text-align:right}\n.vsm-general-row button{border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;padding:6px 12px;background:none;color:var(--dsw-alias-label-primary,#eee);cursor:pointer;font-size:12px;white-space:nowrap}\n.vsm-general-row button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n.vsm-general-row button:disabled{opacity:.55;cursor:default}\n.vsm-general-row button.vsm-devform-close{color:var(--dsw-alias-state-error-primary,#f07878);border-color:var(--dsw-alias-state-error-secondary,#d9534f55)}\n\n/* keyboard shortcuts page */\n.vsm-kb-list{display:flex;flex-direction:column;gap:6px;margin-top:8px}\n.vsm-kb-row{display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid var(--dsw-alias-border-l2,#555);border-radius:8px;background:var(--dsw-alias-bg-layer-1,#161616)}\n.vsm-kb-row.rec{border-color:var(--dsw-alias-brand-primary,#4f8cff)}\n.vsm-kb-label{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;color:var(--dsw-alias-label-primary,#eee);font-size:13px}\n.vsm-kb-warn{color:var(--dsw-alias-state-warn-primary,#e5b93f);font-size:11px}\n.vsm-kb-key{min-width:96px;text-align:center;padding:3px 10px;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;font-family:var(--ds-font-family-code,ui-monospace,monospace)}\n.vsm-kb-key.warn{border-color:var(--dsw-alias-state-warn-primary,#e5b93f);color:var(--dsw-alias-state-warn-primary,#e5b93f)}\n.vsm-kb-key.invalid{border-color:var(--dsw-alias-state-error-primary,#d9534f);color:var(--dsw-alias-state-error-primary,#d9534f)}\n.vsm-kb-rec{font-size:12px;color:var(--dsw-alias-label-secondary,#9aa5b1)}\n.vsm-kb-actions{display:flex;gap:6px}\n.vsm-kb-actions button{border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;padding:4px 10px;background:none;color:var(--dsw-alias-label-primary,#eee);cursor:pointer;font-size:12px;white-space:nowrap}\n.vsm-kb-actions button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n.vsm-kb-actions button:disabled{opacity:.55;cursor:default}\n.vsm-kb-actionsbar{display:flex;align-items:center;gap:10px;margin-top:12px}\n.vsm-kb-dirty{flex:1;font-size:12px;color:var(--dsw-alias-state-warn-primary,#e5b93f)}\n.vsm-kb-message{font-size:12px;color:var(--dsw-alias-brand-primary,#4f8cff);margin-top:8px}\n";
3752
+ const css = "/* dsh-vscode-mode MCP 管理界面样式。\n 全部使用 DSH 真实主题变量(--dsw-alias-*),不再用不存在的 fg-* 变量。 */\n.vsm-mcp-page{display:flex;flex-direction:column;gap:18px;width:100%;max-width:920px;box-sizing:border-box;color:var(--dsw-alias-label-primary,#e6e6e6);padding-bottom:32px}\n\n/* 顶部:标题 + 副标题 + 添加按钮 */\n.vsm-mcp-header{display:flex;align-items:flex-start;justify-content:space-between;gap:20px}\n.vsm-mcp-header h2{margin:0 0 4px;font-size:20px;font-weight:600;line-height:1.35;color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-mcp-header p{margin:0;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:13px;line-height:1.5}\n.vsm-primary{border:0;border-radius:6px;padding:8px 16px;background:var(--dsw-alias-button-primary-fill,#6d55ff);color:var(--dsw-alias-button-contrast-fill,#fff);font-size:13px;font-weight:500;cursor:pointer;white-space:nowrap}\n.vsm-primary:hover{background:var(--dsw-alias-button-primary-hover,#5a46e6)}\n.vsm-primary:disabled{opacity:.55;cursor:default}\n\n/* 子 Tab:我的 MCP / MCP 市场 */\n.vsm-mcp-tabs{display:flex;gap:24px;border-bottom:1px solid var(--dsw-alias-border-l2,#3a3a3a)}\n.vsm-mcp-tabs button{border:0;background:none;color:var(--dsw-alias-label-tertiary,#9aa5b1);padding:9px 2px 11px;cursor:pointer;font-size:14px;position:relative}\n.vsm-mcp-tabs button:hover{color:var(--dsw-alias-label-secondary,#c8c8c8)}\n.vsm-mcp-tabs button.active{color:var(--dsw-alias-label-primary,#fff);font-weight:500}\n.vsm-mcp-tabs button.active::after{content:\"\";position:absolute;left:0;right:0;bottom:-1px;height:2px;background:var(--dsw-alias-brand-primary,#6d55ff);border-radius:2px}\n\n/* 通用设置 */\n.vsm-general-page{display:flex;flex-direction:column;gap:10px;max-width:720px}\n.vsm-general-page h2{margin:0;font-size:20px;color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-general-page p{margin:0 0 8px;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:13px}\n.vsm-general-row{display:flex;align-items:center;justify-content:space-between;gap:20px;padding:14px 0;border-bottom:1px solid var(--dsw-alias-border-l1,#333);color:var(--dsw-alias-label-primary,#eee);font-size:14px}\n.vsm-general-row select{min-width:220px;padding:8px 10px;border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;background:var(--dsw-alias-bg-layer-1,#2b2b2b);color:var(--dsw-alias-label-primary,#eee);font:inherit}\n.vsm-general-row small{color:var(--dsw-alias-label-tertiary,#9aa5b1)}\n\n/* 服务卡片 */\n.vsm-mcp-card{border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:10px;padding:14px 16px;margin-bottom:10px;background:var(--dsw-alias-bg-layer-2,transparent);transition:border-color .15s}\n.vsm-mcp-card:hover{border-color:var(--dsw-alias-border-l3,#555)}\n.vsm-mcp-card-head{display:flex;justify-content:space-between;align-items:center;gap:12px}\n.vsm-mcp-title{display:flex;align-items:center;gap:9px;font-weight:600;font-size:14px;color:var(--dsw-alias-label-primary,#e6e6e6);min-width:0}\n.vsm-mcp-source{font-size:11px;font-weight:400;padding:2px 7px;border-radius:4px;background:var(--dsw-alias-bg-mask-2,#ffffff22);color:var(--dsw-alias-label-tertiary,#9aa5b1);flex-shrink:0}\n.vsm-mcp-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0;background:var(--dsw-alias-state-error-primary,#e05252)}\n.vsm-mcp-dot.connected{background:var(--dsw-alias-state-success-primary,#38bd75)}\n.vsm-mcp-dot.connecting{background:var(--dsw-alias-state-warn-primary,#e5b93f)}\n.vsm-mcp-dot.disabled{background:var(--dsw-alias-label-tertiary,#9aa5b1)}\n.vsm-mcp-actions{display:flex;align-items:center;gap:4px;flex-shrink:0}\n.vsm-mcp-actions button{border:0;background:none;color:var(--dsw-alias-label-tertiary,#9aa5b1);cursor:pointer;font-size:15px;width:28px;height:28px;border-radius:6px;line-height:1}\n.vsm-mcp-actions button:hover{color:var(--dsw-alias-label-primary,#fff);background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n.vsm-mcp-actions button.vsm-danger:hover{color:var(--dsw-alias-state-error-primary,#f07878);background:var(--dsw-alias-interactive-bg-hover-danger,#ff000014)}\n.vsm-switch{font-size:14px !important}\n.vsm-switch.on{color:var(--dsw-alias-state-success-primary,#38bd75)}\n.vsm-mcp-meta{font-size:12px;color:var(--dsw-alias-label-tertiary,#9aa5b1);margin:9px 0}\n.vsm-mcp-error{color:var(--dsw-alias-state-error-primary,#f07878);font-size:12px;margin:8px 0}\n.vsm-mcp-banner{padding:9px 12px;border:1px solid var(--dsw-alias-state-error-secondary,#d9534f55);border-radius:6px;background:var(--dsw-alias-state-error-secondary,#d9534f1a);margin-bottom:10px}\n\n/* 工具 chips */\n.vsm-mcp-tools{display:flex;flex-wrap:wrap;gap:6px}\n.vsm-mcp-chip{font:12px var(--ds-font-family-code,ui-monospace,monospace);padding:4px 8px;border-radius:5px;background:var(--dsw-alias-bg-mask-2,#ffffff14);color:var(--dsw-alias-label-secondary,#c8c8c8);border:1px solid var(--dsw-alias-border-l1,#333)}\n\n/* 空态 / 加载态 */\n.vsm-mcp-empty{text-align:center;padding:56px 20px;color:var(--dsw-alias-label-tertiary,#9aa5b1);border:1px dashed var(--dsw-alias-border-l2,#3a3a3a);border-radius:8px;font-size:13px}\n\n/* 项目搜索下拉框 */\n.vsm-project-picker{position:relative;width:100%;z-index:4}\n.vsm-project-picker-trigger{width:100%;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 12px;border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:8px;background:var(--dsw-alias-bg-layer-1,transparent);color:var(--dsw-alias-label-primary,#e6e6e6);cursor:pointer;text-align:left}\n.vsm-project-picker-trigger:hover{border-color:var(--dsw-alias-brand-primary,#6d55ff)}\n.vsm-project-picker-label{display:flex;flex-direction:column;min-width:0;font-size:13px;font-weight:500}\n.vsm-project-picker-label small{margin-top:3px;color:var(--dsw-alias-label-tertiary,#9aa5b1);font:11px var(--ds-font-family-code,ui-monospace,monospace);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.vsm-project-picker-arrow{color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:16px}\n.vsm-project-picker-menu{position:absolute;top:calc(100% + 6px);left:0;right:0;padding:8px;border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:9px;background:var(--dsw-alias-bg-overlay,#202020);box-shadow:0 12px 36px #0008}\n.vsm-project-picker-search{width:100%;box-sizing:border-box;padding:8px 10px;border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;background:var(--dsw-alias-bg-layer-1,#2b2b2b);color:var(--dsw-alias-label-primary,#eee);outline:none}\n.vsm-project-picker-search:focus{border-color:var(--dsw-alias-brand-primary,#6d55ff)}\n.vsm-project-picker-options{max-height:260px;overflow:auto;margin-top:6px}\n.vsm-project-option{display:flex;width:100%;flex-direction:column;gap:3px;padding:8px 9px;border:0;border-radius:6px;background:none;color:var(--dsw-alias-label-primary,#eee);cursor:pointer;text-align:left}\n.vsm-project-option:hover,.vsm-project-option.highlight{background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n.vsm-project-option.selected{color:var(--dsw-alias-brand-primary,#6d55ff)}\n.vsm-project-option small{overflow:hidden;color:var(--dsw-alias-label-tertiary,#9aa5b1);font:11px var(--ds-font-family-code,ui-monospace,monospace);text-overflow:ellipsis;white-space:nowrap}\n.vsm-project-picker-empty{padding:18px 8px;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:12px;text-align:center}\n\n/* 项目级 MCP 分组 */\n.vsm-project{border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:12px;margin-bottom:14px;overflow:hidden;background:var(--dsw-alias-bg-layer-1,transparent)}\n.vsm-project-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 16px;border-bottom:1px solid var(--dsw-alias-border-l1,#333);background:var(--dsw-alias-bg-mask-1,#ffffff0a)}\n.vsm-project-title{display:flex;align-items:center;gap:10px;min-width:0}\n.vsm-project-icon{color:var(--dsw-alias-brand-primary,#6d55ff);font-size:15px;flex-shrink:0}\n.vsm-project-name{font-size:14px;font-weight:600;color:var(--dsw-alias-label-primary,#e6e6e6);display:block}\n.vsm-project-path{font-size:11px;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-family:var(--ds-font-family-code,ui-monospace,monospace);display:block;margin-top:2px;word-break:break-all}\n.vsm-primary.vsm-small{padding:5px 12px;font-size:12px}\n.vsm-project-empty{text-align:center;padding:26px 16px;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:12px}\n.vsm-project .vsm-mcp-card{border:0;border-radius:0;margin:0;border-bottom:1px solid var(--dsw-alias-border-l1,#333);background:transparent}\n.vsm-project .vsm-mcp-card:last-child{border-bottom:0}\n.vsm-project .vsm-mcp-banner{border-radius:0;margin:0}\n\n/* 新增 MCP 弹窗 */\n.vsm-mcp-modal{position:fixed;inset:0;background:var(--dsw-alias-bg-mask-drop,#000000aa);display:flex;align-items:center;justify-content:center;z-index:50}\n.vsm-mcp-dialog{width:min(560px,calc(100vw - 40px));max-height:88vh;overflow:auto;padding:22px 24px;border-radius:12px;background:var(--dsw-alias-bg-overlay,#202020);border:1px solid var(--dsw-alias-border-l2,#444);box-shadow:0 16px 60px #000c;color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-mcp-dialog h3{margin:0 0 14px;font-size:16px;font-weight:600}\n.vsm-mcp-dialog label{display:flex;flex-direction:column;gap:6px;margin:12px 0;font-size:12px;color:var(--dsw-alias-label-secondary,#aaa)}\n.vsm-mcp-dialog input,.vsm-mcp-dialog select,.vsm-mcp-dialog textarea{font:inherit;color:var(--dsw-alias-label-primary,#eee);background:var(--dsw-alias-bg-layer-1,#2b2b2b);border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;padding:8px 10px}\n.vsm-mcp-dialog input:focus,.vsm-mcp-dialog select:focus,.vsm-mcp-dialog textarea:focus{outline:none;border-color:var(--dsw-alias-brand-primary,#6d55ff)}\n.vsm-mcp-dialog textarea{min-height:64px;resize:vertical;font-family:var(--ds-font-family-code,ui-monospace,monospace)}\n.vsm-mcp-dialog-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:20px}\n.vsm-mcp-dialog-actions button{padding:8px 14px;border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;background:none;color:var(--dsw-alias-label-primary,#eee);cursor:pointer;font-size:13px}\n.vsm-mcp-dialog-actions button:hover{background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n\n/* 兼容性小节 */\n.vsm-compat-h3{margin:16px 0 2px;font-size:14px;font-weight:600;color:var(--dsw-alias-label-secondary,#c8c8c8)}\n.vsm-compat-item{display:flex;align-items:baseline;justify-content:space-between;gap:16px;padding:10px 0;border-bottom:1px solid var(--dsw-alias-border-l1,#333);font-size:13px;color:var(--dsw-alias-label-primary,#eee)}\n.vsm-compat-item.ok .vsm-compat-name::before{content:\"● \";color:var(--dsw-alias-state-success-primary,#38bd75)}\n.vsm-compat-item.warn .vsm-compat-name::before{content:\"● \";color:var(--dsw-alias-state-warn-primary,#e5b93f)}\n.vsm-compat-name{font-weight:500;min-width:0}\n.vsm-compat-note{color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:12px;text-align:right;min-width:0}\n\n/* 开发形态开关 */\n.vsm-devform-note{display:block;margin-top:4px;font-size:11px;color:var(--dsw-alias-label-tertiary,#9aa5b1);word-break:break-all}\n.vsm-devform-actions{display:flex;flex-direction:column;align-items:flex-end;gap:6px;min-width:0}\n.vsm-devform-msg{color:var(--dsw-alias-state-warn-primary,#e5b93f);font-size:11px;text-align:right}\n.vsm-general-row button{border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;padding:6px 12px;background:none;color:var(--dsw-alias-label-primary,#eee);cursor:pointer;font-size:12px;white-space:nowrap}\n.vsm-general-row button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n.vsm-general-row button:disabled{opacity:.55;cursor:default}\n.vsm-general-row button.vsm-devform-close{color:var(--dsw-alias-state-error-primary,#f07878);border-color:var(--dsw-alias-state-error-secondary,#d9534f55)}\n\n/* keyboard shortcuts page */\n.vsm-kb-list{display:flex;flex-direction:column;gap:6px;margin-top:8px}\n.vsm-kb-row{display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid var(--dsw-alias-border-l2,#555);border-radius:8px;background:var(--dsw-alias-bg-layer-1,#161616)}\n.vsm-kb-row.rec{border-color:var(--dsw-alias-brand-primary,#4f8cff)}\n.vsm-kb-label{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;color:var(--dsw-alias-label-primary,#eee);font-size:13px}\n.vsm-kb-warn{color:var(--dsw-alias-state-warn-primary,#e5b93f);font-size:11px}\n.vsm-kb-key{min-width:96px;text-align:center;padding:3px 10px;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;font-family:var(--ds-font-family-code,ui-monospace,monospace)}\n.vsm-kb-key.warn{border-color:var(--dsw-alias-state-warn-primary,#e5b93f);color:var(--dsw-alias-state-warn-primary,#e5b93f)}\n.vsm-kb-key.invalid{border-color:var(--dsw-alias-state-error-primary,#d9534f);color:var(--dsw-alias-state-error-primary,#d9534f)}\n.vsm-kb-rec{font-size:12px;color:var(--dsw-alias-label-secondary,#9aa5b1)}\n.vsm-kb-actions{display:flex;gap:6px}\n.vsm-kb-actions button{border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;padding:4px 10px;background:none;color:var(--dsw-alias-label-primary,#eee);cursor:pointer;font-size:12px;white-space:nowrap}\n.vsm-kb-actions button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n.vsm-kb-actions button:disabled{opacity:.55;cursor:default}\n.vsm-kb-actionsbar{display:flex;align-items:center;gap:10px;margin-top:12px}\n.vsm-kb-dirty{flex:1;font-size:12px;color:var(--dsw-alias-state-warn-primary,#e5b93f)}\n.vsm-kb-message{font-size:12px;color:var(--dsw-alias-brand-primary,#4f8cff);margin-top:8px}\n\n/* 会话性能(PerfSettings 子 Tab) */\n.vsm-perf-page{display:flex;flex-direction:column;gap:14px;max-width:920px}\n.vsm-perf-page h2{margin:0;font-size:20px;color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-perf-page p{margin:0;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:13px;line-height:1.5}\n.vsm-perf-cards{display:flex;gap:12px;flex-wrap:wrap}\n.vsm-perf-card{display:flex;flex-direction:column;gap:4px;min-width:120px;padding:12px 16px;border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:10px;background:var(--dsw-alias-bg-layer-2,transparent)}\n.vsm-perf-card span{font-size:12px;color:var(--dsw-alias-label-tertiary,#9aa5b1)}\n.vsm-perf-card b{font-size:20px;color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-perf-card b.big{color:var(--dsw-alias-state-error-primary,#e05252)}\n.vsm-perf-toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap}\n.vsm-perf-selcount{font-size:12px;color:var(--dsw-alias-label-tertiary,#9aa5b1);margin:0 4px}\n.vsm-perf-ws{border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:10px;overflow:hidden}\n.vsm-perf-ws-head{display:flex;justify-content:space-between;align-items:center;gap:12px;padding:10px 14px;background:var(--dsw-alias-bg-layer-1,#262626);border-bottom:1px solid var(--dsw-alias-border-l2,#3a3a3a)}\n.vsm-perf-ws-name{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary,#e6e6e6);font-family:var(--ds-font-family-code,ui-monospace,monospace);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.vsm-perf-ws-meta{font-size:12px;color:var(--dsw-alias-label-tertiary,#9aa5b1);flex-shrink:0}\n.vsm-perf-rows{display:flex;flex-direction:column}\n.vsm-perf-row{display:flex;align-items:center;gap:10px;padding:7px 14px;border-bottom:1px solid var(--dsw-alias-border-l1,#333);font-size:12px;color:var(--dsw-alias-label-secondary,#c8c8c8)}\n.vsm-perf-row:last-child{border-bottom:0}\n.vsm-perf-row:hover{background:var(--dsw-alias-interactive-bg-hover,#ffffff0d)}\n.vsm-perf-row input[type=checkbox]{accent-color:var(--dsw-alias-brand-primary,#6d55ff);cursor:pointer}\n.vsm-perf-cell{min-width:0}\n.vsm-perf-id{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--ds-font-family-code,ui-monospace,monospace);color:var(--dsw-alias-label-primary,#eee)}\n.vsm-perf-size{width:70px;text-align:right;flex-shrink:0;color:var(--dsw-alias-label-secondary,#c8c8c8)}\n.vsm-perf-size.big{color:var(--dsw-alias-state-error-primary,#e05252);font-weight:600}\n.vsm-perf-mtime{width:44px;flex-shrink:0;color:var(--dsw-alias-label-tertiary,#9aa5b1)}\n.vsm-perf-active{width:44px;flex-shrink:0;font-size:11px;color:var(--dsw-alias-state-warn-primary,#e5b93f);text-align:right}\n.vsm-perf-moved{border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:10px;padding:12px 14px;background:var(--dsw-alias-bg-layer-2,transparent)}\n.vsm-perf-moved h3{margin:0 0 8px;font-size:14px;color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-perf-config{border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:10px;padding:12px 14px;background:var(--dsw-alias-bg-layer-2,transparent)}\n.vsm-perf-config h3{margin:0 0 8px;font-size:14px;color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-perf-config-state{display:flex;align-items:center;gap:12px;margin:10px 0}\n.vsm-perf-note{font-size:12px;color:var(--dsw-alias-state-warn-primary,#e5b93f)}\n.vsm-perf-block{margin:8px 0 0;padding:10px 12px;border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:8px;background:var(--dsw-alias-bg-base,#111);color:var(--dsw-alias-label-secondary,#c8c8c8);font-size:11px;line-height:1.5;font-family:var(--ds-font-family-code,ui-monospace,monospace);white-space:pre-wrap;overflow-x:auto;max-width:100%}\n.vsm-perf-guide{border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:10px;padding:12px 14px;background:var(--dsw-alias-bg-layer-2,transparent)}\n.vsm-perf-guide h3{margin:0 0 8px;font-size:14px;color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-perf-modal{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:var(--dsw-alias-bg-mask-1,#000000aa);z-index:1000;padding:20px}\n.vsm-perf-modal-card{width:min(560px,92vw);max-height:72vh;display:flex;flex-direction:column;gap:12px;padding:18px 20px;border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:12px;background:var(--dsw-alias-bg-layer-2,#1f1f1f);color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-perf-modal-card h3{margin:0;font-size:16px}\n.vsm-perf-modal-note{font-size:12px}\n.vsm-perf-modal-list{list-style:none;margin:0;padding:0;overflow-y:auto;font-size:12px;color:var(--dsw-alias-label-secondary,#c8c8c8);display:flex;flex-direction:column;gap:4px}\n.vsm-perf-modal-list li{padding:4px 6px;border-radius:6px;background:var(--dsw-alias-bg-layer-1,#262626);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.vsm-perf-modal-more{font-size:12px;color:var(--dsw-alias-label-tertiary,#9aa5b1)}\n.vsm-perf-modal-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:4px}\n.vsm-secondary{border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;padding:8px 16px;background:none;color:var(--dsw-alias-label-primary,#eee);font-size:13px;cursor:pointer;white-space:nowrap}\n.vsm-secondary:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n.vsm-secondary:disabled{opacity:.55;cursor:default}\n.vsm-small{padding:4px 10px;font-size:12px}\n";
3632
3753
  const tagId = "dsh-vscode-mode/mcp.css";
3633
3754
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
3634
3755
  const tag = document.createElement("style");
@@ -4026,6 +4147,229 @@ window.__ModuleLoader__.load({
4026
4147
  }, "恢复默认")));
4027
4148
  }
4028
4149
  //#endregion
4150
+ //#region src/client/ui/PerfSettings.ts
4151
+ /**
4152
+ * dsh-vscode-mode client — PerfSettings:「性能优化」设置子页(会话卫生 + 压缩调优)。
4153
+ * - 会话盘点:全工作区/每会话体积、活跃标记,按体积排序;
4154
+ * - 移出到归档(先规划→确认→执行→可恢复)与归档清除;
4155
+ * - DSH 内置压缩调优:写 profile patch(compaction-basic / tool-result-pruner 更低阈值,
4156
+ * 带备份与撤销,需重启生效);
4157
+ * - 侧车摘要用法提示(agent/脚本取关键字段,不整份读 .dsh-edit-review.json)。
4158
+ * 作者 ddj 2026-09-02
4159
+ */
4160
+ /** 字节数人类可读。 */
4161
+ function formatBytes(n) {
4162
+ if (!n) return "0B";
4163
+ if (n >= 1048576) return (n / 1048576).toFixed(1) + "MB";
4164
+ if (n >= 1024) return (n / 1024).toFixed(0) + "KB";
4165
+ return n + "B";
4166
+ }
4167
+ /** 会话行 key:workspaceKey \u0000 sessionId。 */
4168
+ const keyOf = (ws, id) => ws + "\0" + id;
4169
+ /** 单行会话。 */
4170
+ function SessionRow({ row, checked, disabled, onToggle }) {
4171
+ const age = Math.max(0, (Date.now() - row.mtime) / 864e5);
4172
+ const when = age < 1 ? Math.round(age * 24) + "h" : Math.round(age) + "d";
4173
+ return react.default.createElement("label", { className: "vsm-perf-row" }, react.default.createElement("input", {
4174
+ type: "checkbox",
4175
+ checked,
4176
+ disabled,
4177
+ onChange: onToggle
4178
+ }), react.default.createElement("span", {
4179
+ className: "vsm-perf-cell vsm-perf-id",
4180
+ title: row.sessionId
4181
+ }, row.sessionId), react.default.createElement("span", { className: "vsm-perf-cell vsm-perf-size " + (row.bytes >= 1048576 ? "big" : "") }, formatBytes(row.bytes)), react.default.createElement("span", {
4182
+ className: "vsm-perf-cell vsm-perf-mtime",
4183
+ title: new Date(row.mtime).toLocaleString()
4184
+ }, when), row.active ? react.default.createElement("span", { className: "vsm-perf-cell vsm-perf-active" }, "活跃") : null);
4185
+ }
4186
+ /**
4187
+ * 会话卫生 + 压缩调优设置子页。
4188
+ * @author ddj 2026年09月02号
4189
+ */
4190
+ function PerfSettings() {
4191
+ const [inv, setInv] = react.default.useState(null);
4192
+ const [error, setError] = react.default.useState("");
4193
+ const [busy, setBusy] = react.default.useState("");
4194
+ const [selected, setSelected] = react.default.useState({});
4195
+ const [confirm, setConfirm] = react.default.useState(null);
4196
+ const [moved, setMoved] = react.default.useState(null);
4197
+ const [config, setConfig] = react.default.useState(null);
4198
+ const load = react.default.useCallback(() => {
4199
+ setError("");
4200
+ Promise.all([rpc("edrv.perf.inventory", {}), rpc("edrv.perf.configGet", {})]).then(([i, c]) => {
4201
+ if (!i.ok) throw new Error(i.error);
4202
+ if (!c.ok) throw new Error(c.error);
4203
+ setInv(i);
4204
+ setConfig(c);
4205
+ }).catch((e) => setError(String(e)));
4206
+ }, []);
4207
+ react.default.useEffect(load, [load]);
4208
+ const action = (id, method, args, patch) => {
4209
+ setBusy(id);
4210
+ setError("");
4211
+ return rpc(method, args).then((res) => {
4212
+ if (!res.ok) throw new Error(res.error);
4213
+ if (patch) patch(res);
4214
+ return res;
4215
+ }).catch((e) => setError(String(e))).finally(() => setBusy(""));
4216
+ };
4217
+ /** 圈选 ≥ 1MB 的非活跃会话。 */
4218
+ const selectBig = () => {
4219
+ if (!inv) return;
4220
+ const next = {};
4221
+ for (const s of inv.sessions) if (s.bytes >= 1048576 && !s.active) next[keyOf(s.workspaceKey, s.sessionId)] = true;
4222
+ setSelected(next);
4223
+ };
4224
+ /** 清空选择。 */
4225
+ const clearSel = () => setSelected({});
4226
+ /** 规划移出所选(跨工作区按 sessionIds 一次规划)。 */
4227
+ const planMove = () => {
4228
+ const sessionIds = Object.keys(selected).map((k) => k.slice(k.indexOf("\0") + 1));
4229
+ if (!sessionIds.length) return;
4230
+ action("plan", "edrv.perf.movePlan", { sessionIds }).then((res) => {
4231
+ if (res.items?.length) setConfirm(res);
4232
+ else setError("所选会话没有可移出的项(活跃会话已排除)");
4233
+ });
4234
+ };
4235
+ /** 确认移出:按工作区分组逐组执行,成功后刷新并记录可恢复项。 */
4236
+ const doMove = () => {
4237
+ const grouped = {};
4238
+ for (const item of confirm.items) (grouped[item.workspaceKey] ?? (grouped[item.workspaceKey] = [])).push(item.sessionId);
4239
+ const jobs = Object.entries(grouped).map(([ws, sessionIds]) => rpc("edrv.perf.moveOut", {
4240
+ workspaceKey: ws,
4241
+ sessionIds
4242
+ }));
4243
+ Promise.all(jobs).then((results) => {
4244
+ const allMoved = [];
4245
+ const failures = [];
4246
+ for (const res of results) {
4247
+ if (!res.ok) {
4248
+ failures.push(res.error);
4249
+ continue;
4250
+ }
4251
+ allMoved.push(...res.moved ?? []);
4252
+ failures.push(...(res.failures ?? []).map((f) => f.sessionId + ": " + f.error));
4253
+ }
4254
+ setMoved({
4255
+ moved: allMoved,
4256
+ failures,
4257
+ reclaimedBytes: allMoved.reduce((s, i) => s + i.bytes, 0)
4258
+ });
4259
+ setConfirm(null);
4260
+ setSelected({});
4261
+ load();
4262
+ }).catch((e) => setError(String(e)));
4263
+ };
4264
+ /** 恢复单个已移出会话。 */
4265
+ const doRestore = (item) => {
4266
+ action("restore", "edrv.perf.restore", {
4267
+ workspaceKey: item.workspaceKey,
4268
+ sessionId: item.sessionId
4269
+ }).then(() => {
4270
+ setMoved((old) => old ? {
4271
+ ...old,
4272
+ moved: old.moved.filter((m) => !(m.workspaceKey === item.workspaceKey && m.sessionId === item.sessionId))
4273
+ } : old);
4274
+ load();
4275
+ });
4276
+ };
4277
+ /** 清除归档区早于 N 天的会话(破坏性)。 */
4278
+ const doPurge = () => {
4279
+ if (!window.confirm("确认永久删除归档区中 30 天前的会话?此操作不可恢复(仅归档区,不影响当前 sessions)。")) return;
4280
+ action("purge", "edrv.perf.purgeArchive", { olderThanDays: 30 }).then((res) => {
4281
+ setError("已清除 " + (res.removed ?? 0) + " 个归档会话,释放 " + formatBytes(res.reclaimedBytes ?? 0));
4282
+ });
4283
+ };
4284
+ /** 应用压缩调优到 profile patch。 */
4285
+ const applyConfig = () => {
4286
+ action("apply", "edrv.perf.configApply", {}).then((res) => {
4287
+ setError("已写入压缩调优配置(备份 " + res.backup + "),重启 DSH 后生效");
4288
+ load();
4289
+ });
4290
+ };
4291
+ /** 撤销压缩调优。 */
4292
+ const undoConfig = () => {
4293
+ action("undo", "edrv.perf.configUndo", {}).then(() => {
4294
+ setError("已撤销压缩调优配置(恢复备份)");
4295
+ load();
4296
+ });
4297
+ };
4298
+ const totals = inv?.totals;
4299
+ const summaryCards = totals ? react.default.createElement("div", { className: "vsm-perf-cards" }, react.default.createElement("div", { className: "vsm-perf-card" }, react.default.createElement("span", null, "工作区"), react.default.createElement("b", null, String(totals.workspaces))), react.default.createElement("div", { className: "vsm-perf-card" }, react.default.createElement("span", null, "会话数"), react.default.createElement("b", null, String(totals.sessions))), react.default.createElement("div", { className: "vsm-perf-card" }, react.default.createElement("span", null, "压缩态总体积"), react.default.createElement("b", { className: totals.totalBytes >= 52428800 ? "big" : "" }, formatBytes(totals.totalBytes)))) : null;
4300
+ const workspaceBlocks = inv?.workspaces ? inv.workspaces.map((ws) => {
4301
+ const rows = inv.sessions.filter((s) => s.workspaceKey === ws.workspaceKey);
4302
+ return react.default.createElement("div", {
4303
+ key: ws.workspaceKey,
4304
+ className: "vsm-perf-ws"
4305
+ }, react.default.createElement("div", { className: "vsm-perf-ws-head" }, react.default.createElement("span", {
4306
+ className: "vsm-perf-ws-name",
4307
+ title: ws.workspaceKey
4308
+ }, ws.workspaceKey), react.default.createElement("span", { className: "vsm-perf-ws-meta" }, rows.length + " 会话 · " + formatBytes(ws.totalBytes))), react.default.createElement("div", { className: "vsm-perf-rows" }, rows.length ? rows.map((row) => react.default.createElement(SessionRow, {
4309
+ key: keyOf(row.workspaceKey, row.sessionId),
4310
+ row,
4311
+ checked: !!selected[keyOf(row.workspaceKey, row.sessionId)],
4312
+ disabled: row.active || busy === "move",
4313
+ onToggle: () => {
4314
+ const k = keyOf(row.workspaceKey, row.sessionId);
4315
+ setSelected((old) => {
4316
+ const next = { ...old };
4317
+ if (next[k]) delete next[k];
4318
+ else next[k] = true;
4319
+ return next;
4320
+ });
4321
+ }
4322
+ })) : react.default.createElement("div", { className: "vsm-mcp-empty" }, "无会话")));
4323
+ }) : null;
4324
+ const selCount = Object.keys(selected).length;
4325
+ const confirmBody = confirm ? react.default.createElement("div", { className: "vsm-perf-modal" }, react.default.createElement("div", { className: "vsm-perf-modal-card" }, react.default.createElement("h3", null, "确认移出 " + confirm.items.length + " 个会话?"), react.default.createElement("p", { className: "vsm-perf-modal-note" }, "将从 ~/.dsh/sessions 移出到 ~/.dsh/sessions-archive(可逆,重启后不再回放,释放 " + formatBytes(confirm.reclaimedBytes) + ")。活跃会话已排除。"), react.default.createElement("ul", { className: "vsm-perf-modal-list" }, confirm.items.slice(0, 20).map((item) => react.default.createElement("li", { key: item.workspaceKey + item.sessionId }, item.workspaceKey + " / " + item.sessionId + "(" + formatBytes(item.bytes) + ")"))), confirm.items.length > 20 ? react.default.createElement("div", { className: "vsm-perf-modal-more" }, "…等 " + confirm.items.length + " 个") : null, react.default.createElement("div", { className: "vsm-perf-modal-actions" }, react.default.createElement("button", {
4326
+ className: "vsm-primary",
4327
+ onClick: doMove,
4328
+ disabled: busy === "move"
4329
+ }, busy === "move" ? "执行中…" : "确认移出"), react.default.createElement("button", {
4330
+ className: "vsm-secondary",
4331
+ onClick: () => setConfirm(null)
4332
+ }, "取消")))) : null;
4333
+ const movedBody = moved?.moved?.length ? react.default.createElement("div", { className: "vsm-perf-moved" }, react.default.createElement("h3", null, "已移出 " + moved.moved.length + " 个会话(释放 " + formatBytes(moved.reclaimedBytes) + ")"), react.default.createElement("div", { className: "vsm-perf-rows" }, moved.moved.map((item) => react.default.createElement("div", {
4334
+ key: item.workspaceKey + item.sessionId,
4335
+ className: "vsm-perf-row"
4336
+ }, react.default.createElement("span", { className: "vsm-perf-cell vsm-perf-id" }, item.sessionId), react.default.createElement("span", { className: "vsm-perf-cell vsm-perf-size" }, formatBytes(item.bytes)), react.default.createElement("button", {
4337
+ className: "vsm-secondary vsm-small",
4338
+ onClick: () => doRestore(item),
4339
+ disabled: busy === "restore"
4340
+ }, "恢复")))), moved.failures?.length ? react.default.createElement("div", { className: "vsm-mcp-error vsm-mcp-banner" }, "失败:" + moved.failures.join(";")) : null) : null;
4341
+ const configBody = config ? react.default.createElement("div", { className: "vsm-perf-config" }, react.default.createElement("h3", null, "DSH 内置压缩调优"), react.default.createElement("p", null, "调低 compaction-basic / tool-result-pruner 触发阈值,让长循环会话更早压缩,降低模型可见上下文压力(减少 token 与防 context overflow)。"), react.default.createElement("p", { className: "vsm-perf-note" }, "注意:压缩只追加 compaction 事件,不重写已持久化会话日志(append-only),因此不会缩小已存在的会话文件——存量瘦身请用上方「移出到归档」。packChunks 已默认开启,无需配置。"), react.default.createElement("div", { className: "vsm-perf-config-state" }, react.default.createElement("span", { className: "vsm-perf-cell" }, "状态:" + (config.applied ? "已应用" : "未应用")), config.applied ? react.default.createElement("button", {
4342
+ className: "vsm-secondary vsm-small",
4343
+ onClick: undoConfig,
4344
+ disabled: busy === "undo"
4345
+ }, "撤销") : react.default.createElement("button", {
4346
+ className: "vsm-primary vsm-small",
4347
+ onClick: applyConfig,
4348
+ disabled: busy === "apply"
4349
+ }, "应用建议配置(需重启)")), react.default.createElement("pre", { className: "vsm-perf-block" }, config.block)) : null;
4350
+ const guideBody = react.default.createElement("div", { className: "vsm-perf-guide" }, react.default.createElement("h3", null, "侧车摘要(agent/脚本取关键字段,不整份读 sidecar)"), react.default.createElement("p", null, "工作区根目录的 .dsh-edit-review.json(可能数 MB)只应通过摘要接口读取,禁止 agent 整份 read/write 进对话:"), react.default.createElement("pre", { className: "vsm-perf-block" }, "curl -s -X POST http://127.0.0.1:3080/edrv/rpc -H 'content-type: application/json' -d '{\"method\":\"edrv.perf.sidecarSummary\",\"args\":{}}'\n# 差异记录列表(含每文件 pending 摘要):edrv.list\n# 历史归档:edrv.archiveList / edrv.archiveRead"));
4351
+ return react.default.createElement("section", { className: "vsm-perf-page" }, react.default.createElement("h2", null, "会话性能"), react.default.createElement("p", null, "DSH 启动会回放 ~/.dsh/sessions 全部会话(V8 展开约 10×),体积越大内存越吃紧。定期把巨型/旧会话移出到归档可显著降低启动内存。"), error ? react.default.createElement("div", { className: "vsm-mcp-error vsm-mcp-banner" }, error) : null, summaryCards, react.default.createElement("div", { className: "vsm-perf-toolbar" }, react.default.createElement("button", {
4352
+ className: "vsm-secondary vsm-small",
4353
+ onClick: selectBig
4354
+ }, "圈选 ≥1MB 非活跃"), react.default.createElement("button", {
4355
+ className: "vsm-secondary vsm-small",
4356
+ onClick: clearSel,
4357
+ disabled: !selCount
4358
+ }, "清空选择"), react.default.createElement("span", { className: "vsm-perf-selcount" }, "已选 " + selCount + " 个"), react.default.createElement("button", {
4359
+ className: "vsm-primary vsm-small",
4360
+ onClick: planMove,
4361
+ disabled: !selCount || busy === "plan"
4362
+ }, busy === "plan" ? "规划中…" : "移出所选"), react.default.createElement("button", {
4363
+ className: "vsm-secondary vsm-small",
4364
+ onClick: doPurge,
4365
+ disabled: busy === "purge"
4366
+ }, "清除归档(>30天)"), react.default.createElement("button", {
4367
+ className: "vsm-secondary vsm-small",
4368
+ onClick: load,
4369
+ disabled: busy === "load"
4370
+ }, "⟳ 刷新")), workspaceBlocks, movedBody, configBody, guideBody, confirmBody);
4371
+ }
4372
+ //#endregion
4029
4373
  //#region src/client/ui/McpSettings.ts
4030
4374
  /**
4031
4375
  * dsh-vscode-mode client — VSCodeMode 设置区:通用 / 快捷键 / MCP 管理。
@@ -4412,6 +4756,7 @@ window.__ModuleLoader__.load({
4412
4756
  })) : react.default.createElement("div", { className: "vsm-mcp-empty" }, "还没有配置全局 MCP"));
4413
4757
  else if (tab === "projects") body = projectBody;
4414
4758
  else if (tab === "compat") body = react.default.createElement(CompatSection, { getSummary: compatSummary });
4759
+ else if (tab === "perf") body = react.default.createElement(PerfSettings, null);
4415
4760
  else body = marketBody;
4416
4761
  const form = showForm ? react.default.createElement(McpForm, {
4417
4762
  title: "添加全局 MCP",
@@ -4447,6 +4792,9 @@ window.__ModuleLoader__.load({
4447
4792
  className: tab === "projects" ? "active" : "",
4448
4793
  onClick: () => setTab("projects")
4449
4794
  }, "项目 MCP"), react.default.createElement("button", {
4795
+ className: tab === "perf" ? "active" : "",
4796
+ onClick: () => setTab("perf")
4797
+ }, "性能优化"), react.default.createElement("button", {
4450
4798
  className: tab === "market" ? "active" : "",
4451
4799
  onClick: () => setTab("market")
4452
4800
  }, "MCP 市场"), react.default.createElement("button", {
@@ -4922,10 +5270,11 @@ window.__ModuleLoader__.load({
4922
5270
  /**
4923
5271
  * dsh-vscode-mode client — 资源管理栏展开状态持久化(纯函数,可单测)。
4924
5272
  * 对齐 VSCode:只持久化展开路径集合,不缓存目录条目数据(条目实时 listDir)。
5273
+ * 键前缀统一走 paths.ts PathConst(CACHE_KEY.expanded)。
4925
5274
  * 作者 ddj 2026-08-28
4926
5275
  */
4927
5276
  /** localStorage 键前缀(按会话隔离)。 */
4928
- const KEY_PREFIX = "edrv.cache.explorer.v1.";
5277
+ const KEY_PREFIX$1 = CACHE_KEY.expanded;
4929
5278
  /**
4930
5279
  * 归一化展开路径:去空白、反斜杠→斜杠、去首尾斜杠,`..` 段拒绝。
4931
5280
  * @author ddj 2026年08月28号
@@ -5003,7 +5352,7 @@ window.__ModuleLoader__.load({
5003
5352
  */
5004
5353
  function explorerLoad(sessionId) {
5005
5354
  try {
5006
- return parseExplorer(window.localStorage.getItem(KEY_PREFIX + String(sessionId)));
5355
+ return parseExplorer(window.localStorage.getItem(KEY_PREFIX$1 + String(sessionId)));
5007
5356
  } catch (error) {
5008
5357
  return null;
5009
5358
  }
@@ -5016,23 +5365,185 @@ window.__ModuleLoader__.load({
5016
5365
  */
5017
5366
  function explorerSave(sessionId, data) {
5018
5367
  try {
5019
- window.localStorage.setItem(KEY_PREFIX + String(sessionId), serializeExplorer(data));
5368
+ window.localStorage.setItem(KEY_PREFIX$1 + String(sessionId), serializeExplorer(data));
5020
5369
  } catch (error) {}
5021
5370
  }
5022
5371
  //#endregion
5372
+ //#region src/client/state/explorerEntriesCache.ts
5373
+ const KEY_PREFIX = CACHE_KEY.entries;
5374
+ /** 裁剪到上限(目录按 ts 逐出最旧;单目录条目截断)。 */
5375
+ function entriesTrim(data, maxDirs = 300, maxEntries = 500) {
5376
+ const dirs = {};
5377
+ const sorted = Object.entries(data.dirs).sort((a, b) => b[1].ts - a[1].ts);
5378
+ for (const [rel, dir] of sorted) {
5379
+ if (Object.keys(dirs).length >= maxDirs) break;
5380
+ dirs[rel] = {
5381
+ ts: dir.ts,
5382
+ entries: dir.entries.length > maxEntries ? dir.entries.slice(0, maxEntries) : dir.entries
5383
+ };
5384
+ }
5385
+ return {
5386
+ v: 2,
5387
+ root: data.root,
5388
+ dirs
5389
+ };
5390
+ }
5391
+ /** 序列化缓存数据。 */
5392
+ function entriesSerialize(data) {
5393
+ return JSON.stringify(data);
5394
+ }
5395
+ /** 解析缓存文本;损坏/格式不符 → null。 */
5396
+ function entriesParse(text) {
5397
+ if (!text) return null;
5398
+ try {
5399
+ const raw = JSON.parse(text);
5400
+ if (!raw || raw.v !== 2 || !raw.dirs || typeof raw.dirs !== "object") return null;
5401
+ const dirs = {};
5402
+ for (const [rel, d] of Object.entries(raw.dirs)) {
5403
+ if (!d || typeof d !== "object") continue;
5404
+ const dir = d;
5405
+ if (!Array.isArray(dir.entries)) continue;
5406
+ const entries = [];
5407
+ for (const e of dir.entries) {
5408
+ if (!e || typeof e !== "object") continue;
5409
+ const item = e;
5410
+ if (typeof item.name !== "string" || typeof item.path !== "string") continue;
5411
+ const type = item.type === "directory" ? "directory" : item.type === "file" ? "file" : "other";
5412
+ entries.push({
5413
+ name: item.name,
5414
+ path: item.path,
5415
+ type
5416
+ });
5417
+ }
5418
+ if (!entries.length) continue;
5419
+ dirs[rel] = {
5420
+ ts: typeof dir.ts === "number" ? dir.ts : 0,
5421
+ entries
5422
+ };
5423
+ }
5424
+ return {
5425
+ v: 2,
5426
+ root: typeof raw.root === "string" ? raw.root : null,
5427
+ dirs
5428
+ };
5429
+ } catch (error) {
5430
+ return null;
5431
+ }
5432
+ }
5433
+ /** sessionId → 缓存镜像(同步读,避免每次渲染 parse)。 */
5434
+ const mirrors = /* @__PURE__ */ new Map();
5435
+ /** sessionId → 落盘防抖计时器。 */
5436
+ const saveTimers = /* @__PURE__ */ new Map();
5437
+ /** 单调时钟:连续 put 的 ts 严格递增(同毫秒不并列,逐出顺序可预期)。 */
5438
+ let clock = 0;
5439
+ /** 取下一时间戳(不小于真实时间且严格递增)。 */
5440
+ function nextTs() {
5441
+ clock = Math.max(Date.now(), clock + 1);
5442
+ return clock;
5443
+ }
5444
+ /** localStorage 读取(不可用 → null)。 */
5445
+ function readRaw(sessionId) {
5446
+ try {
5447
+ return window.localStorage.getItem(KEY_PREFIX + sessionId);
5448
+ } catch (error) {
5449
+ return null;
5450
+ }
5451
+ }
5452
+ /** localStorage 写入(配额/隐私模式失败静默)。 */
5453
+ function writeRaw(sessionId, text) {
5454
+ try {
5455
+ window.localStorage.setItem(KEY_PREFIX + sessionId, text);
5456
+ } catch (error) {}
5457
+ }
5458
+ /** 取(或建)会话缓存镜像。 */
5459
+ function mirrorOf(sessionId) {
5460
+ const existing = mirrors.get(sessionId);
5461
+ if (existing) return existing;
5462
+ const data = entriesParse(readRaw(sessionId)) ?? {
5463
+ v: 2,
5464
+ root: null,
5465
+ dirs: {}
5466
+ };
5467
+ mirrors.set(sessionId, data);
5468
+ return data;
5469
+ }
5470
+ /** 调度防抖落盘(重置已有计时器)。 */
5471
+ function scheduleSave(sessionId) {
5472
+ const prev = saveTimers.get(sessionId);
5473
+ if (prev) clearTimeout(prev);
5474
+ saveTimers.set(sessionId, setTimeout(() => {
5475
+ saveTimers.delete(sessionId);
5476
+ const data = mirrors.get(sessionId);
5477
+ if (data) writeRaw(sessionId, entriesSerialize(entriesTrim(data)));
5478
+ }, 300));
5479
+ }
5480
+ /**
5481
+ * 读某目录缓存条目(无 → null;展示不受新鲜度限制)。
5482
+ * @author ddj 2026年08月31号
5483
+ * @param sessionId 会话 id
5484
+ * @param rel 目录相对路径('' = 根)
5485
+ * @returns 缓存条目或 null
5486
+ */
5487
+ function entriesCacheGet(sessionId, rel) {
5488
+ if (!sessionId) return null;
5489
+ const dir = mirrorOf(sessionId).dirs[rel];
5490
+ if (!dir || !dir.entries.length) return null;
5491
+ return dir.entries;
5492
+ }
5493
+ /**
5494
+ * 某目录缓存是否新鲜(预取去重用)。
5495
+ * @author ddj 2026年08月31号
5496
+ * @param sessionId 会话 id
5497
+ * @param rel 目录相对路径
5498
+ * @returns 新鲜返回 true
5499
+ */
5500
+ function entriesCacheIsFresh(sessionId, rel) {
5501
+ if (!sessionId) return false;
5502
+ const dir = mirrorOf(sessionId).dirs[rel];
5503
+ return Boolean(dir && Date.now() - dir.ts < 3e4);
5504
+ }
5505
+ /**
5506
+ * 写入某目录缓存条目(内存镜像 + 防抖落盘;单目录条目截断)。
5507
+ * @author ddj 2026年08月31号
5508
+ * @param sessionId 会话 id
5509
+ * @param rel 目录相对路径
5510
+ * @param entries 目录条目
5511
+ */
5512
+ function entriesCachePut(sessionId, rel, entries) {
5513
+ if (!sessionId) return;
5514
+ const data = mirrorOf(sessionId);
5515
+ data.dirs[rel] = {
5516
+ ts: nextTs(),
5517
+ entries: entries.slice(0, 500)
5518
+ };
5519
+ data.dirs = entriesTrim(data).dirs;
5520
+ scheduleSave(sessionId);
5521
+ }
5522
+ //#endregion
5023
5523
  //#region src/client/sidebar/panels/FileExplorer.ts
5024
5524
  /**
5025
- * dsh-vscode-mode client — 侧边栏「文件管理」面板(懒加载目录树)。
5026
- * 点目录展开/收起(首次经 edrv.listDir 拉取并缓存),点文件经 ctx.openFile 打开;
5027
- * 差异角标取 pendingByPath,活动文件高亮;edrv:refresh 事件与手动刷新重载树。
5028
- * 右键行/空白弹出菜单:项来自 ctx.fileMenuItems 注册表(可拓展),
5029
- * 内置「在文件浏览器中打开」经 edrv.revealInExplorer 定位/打开。
5030
- * 作者 ddj 2026-08-26 / 2026-08-27
5525
+ * dsh-vscode-mode client — 侧边栏「文件管理」面板(懒加载目录树 + SWR 缓存)。
5526
+ * 展开目录立即渲染(dirs 内存态 → 本地条目缓存兜底),后台刷新(edrv.listDir 走
5527
+ * host 树索引,命中近乎零成本);挂载/切会话从缓存即时恢复展开树;⟳/edrv:refresh
5528
+ * 保留旧条目强制后台重列(force);每次用户发起加载后预取 ≤4 个子目录(排除重型
5529
+ * 目录、缓存新鲜跳过、不级联);10s 轻量跟随已展开目录(命中索引,RPC 近零成本)。
5530
+ * 差异角标/右键菜单/展开状态持久化行为不变。
5531
+ * 作者 ddj 2026-08-26 / 2026-08-27 / 2026-08-31
5031
5532
  */
5032
5533
  const DIR_CAP = 4e3;
5033
5534
  const SAVE_DEBOUNCE_MS = 300;
5535
+ const FOLLOW_INTERVAL_MS = 1e4;
5536
+ const PREFETCH_MAX = 4;
5537
+ const PREFETCH_EXCLUDED = /* @__PURE__ */ new Set([
5538
+ "node_modules",
5539
+ ".git",
5540
+ ".hg",
5541
+ ".svn",
5542
+ ".pnpm",
5543
+ ".pnpm-store"
5544
+ ]);
5034
5545
  /**
5035
- * 目录树面板主体。
5546
+ * 目录树面板主体(SWR:有缓存先渲染,无缓存才显示加载态;加载总在后台)。
5036
5547
  * @param props.ctx 面板共享上下文(sessionId/openFile/activePath/pendingByPath/fileMenuItems/notify)
5037
5548
  */
5038
5549
  function FileExplorer(props) {
@@ -5045,29 +5556,65 @@ window.__ModuleLoader__.load({
5045
5556
  const [dirs, setDirs] = react.default.useState({});
5046
5557
  const [expanded, setExpanded] = react.default.useState({});
5047
5558
  const [loading, setLoading] = react.default.useState({});
5048
- const [error, setError] = react.default.useState(null);
5559
+ const [errors, setErrors] = react.default.useState({});
5049
5560
  const [menu, setMenu] = react.default.useState(null);
5050
5561
  const tokensRef = react.default.useRef({});
5051
5562
  const expandedRef = react.default.useRef({});
5052
5563
  expandedRef.current = expanded;
5564
+ const loadingRef = react.default.useRef({});
5565
+ loadingRef.current = loading;
5566
+ const dirsRef = react.default.useRef({});
5567
+ dirsRef.current = dirs;
5053
5568
  const saveTimerRef = react.default.useRef(null);
5054
- const loadDir = (rel) => {
5569
+ const loadDirRef = react.default.useRef(null);
5570
+ const refreshRef = react.default.useRef(null);
5571
+ /** 渲染取数:内存态 → 本地条目缓存 → null(显示加载态)。 */
5572
+ const entriesOf = (rel) => dirsRef.current[rel] ?? entriesCacheGet(sessionId, rel) ?? null;
5573
+ /** 预取子目录:≤4 个、排除重型目录、缓存新鲜跳过、已加载跳过、不级联。 */
5574
+ const prefetchDirs = (rel, entries) => {
5575
+ const want = [];
5576
+ for (const e of entries) {
5577
+ if (e.type !== "directory") continue;
5578
+ if (PREFETCH_EXCLUDED.has(e.name)) continue;
5579
+ if (entriesCacheIsFresh(sessionId, e.path)) continue;
5580
+ if (dirsRef.current[e.path] !== void 0) continue;
5581
+ want.push(e.path);
5582
+ if (want.length >= PREFETCH_MAX) break;
5583
+ }
5584
+ for (const sub of want) loadDir(sub, {});
5585
+ };
5586
+ /**
5587
+ * 后台加载目录:token 守卫防乱序;force 跳过索引命中强制实列;
5588
+ * 非 force 且已在途时跳过(避免轮询打断用户展开的响应)。
5589
+ */
5590
+ const loadDir = (rel, opts) => {
5591
+ const force = opts?.force === true;
5592
+ const doPrefetch = opts?.prefetch === true;
5593
+ if (!force && loadingRef.current[rel]) return;
5055
5594
  const token = (tokensRef.current[rel] || 0) + 1;
5056
5595
  tokensRef.current[rel] = token;
5057
5596
  setLoading((prev) => Object.assign({}, prev, { [rel]: true }));
5058
- setError(null);
5059
- rpc("edrv.listDir", {
5597
+ setErrors((prev) => {
5598
+ const next = Object.assign({}, prev);
5599
+ delete next[rel];
5600
+ return next;
5601
+ });
5602
+ const args = {
5060
5603
  sessionId,
5061
5604
  path: rel
5062
- }).then((res) => {
5605
+ };
5606
+ if (force) args.force = true;
5607
+ rpc("edrv.listDir", args).then((res) => {
5063
5608
  if (tokensRef.current[rel] !== token) return;
5064
5609
  if (res && res.ok && Array.isArray(res.entries)) {
5065
5610
  setDirs((prev) => Object.assign({}, prev, { [rel]: res.entries }));
5066
- if (res.root && !root) setRoot(res.root);
5067
- } else setError(res?.error ? String(res.error) : "读取目录失败");
5611
+ if (res.root) setRoot((prev) => prev || res.root);
5612
+ entriesCachePut(sessionId, rel, res.entries);
5613
+ if (doPrefetch) prefetchDirs(rel, res.entries);
5614
+ } else if (!entriesOf(rel)) setErrors((prev) => Object.assign({}, prev, { [rel]: res?.error ? String(res.error) : "读取目录失败" }));
5068
5615
  }).catch((e) => {
5069
5616
  if (tokensRef.current[rel] !== token) return;
5070
- setError("读取目录异常:" + String(e));
5617
+ if (!entriesOf(rel)) setErrors((prev) => Object.assign({}, prev, { [rel]: "读取目录异常:" + String(e) }));
5071
5618
  }).finally(() => {
5072
5619
  if (tokensRef.current[rel] !== token) return;
5073
5620
  setLoading((prev) => {
@@ -5077,35 +5624,42 @@ window.__ModuleLoader__.load({
5077
5624
  });
5078
5625
  });
5079
5626
  };
5627
+ loadDirRef.current = loadDir;
5080
5628
  const toggle = (rel) => {
5081
5629
  if (expanded[rel] === true) {
5082
5630
  setExpanded((prev) => Object.assign({}, prev, { [rel]: false }));
5083
5631
  return;
5084
5632
  }
5085
- if (!dirs[rel]) loadDir(rel);
5086
5633
  setExpanded((prev) => Object.assign({}, prev, { [rel]: true }));
5634
+ loadDir(rel, { prefetch: true });
5087
5635
  };
5088
5636
  const refresh = () => {
5089
5637
  const keep = Object.keys(expandedRef.current).filter((k) => expandedRef.current[k] === true);
5090
5638
  tokensRef.current = {};
5091
5639
  setMenu(null);
5092
- setDirs({});
5640
+ setErrors({});
5093
5641
  setLoading({});
5094
- setError(null);
5095
5642
  if (keep.length) {
5096
5643
  const next = {};
5097
5644
  for (const rel of keep) next[rel] = true;
5098
5645
  setExpanded(next);
5099
- for (const rel of keep) loadDir(rel);
5646
+ for (const rel of keep) loadDir(rel, {
5647
+ force: true,
5648
+ prefetch: true
5649
+ });
5100
5650
  } else setExpanded({});
5101
- loadDir("");
5651
+ loadDir("", {
5652
+ force: true,
5653
+ prefetch: true
5654
+ });
5102
5655
  };
5656
+ refreshRef.current = refresh;
5103
5657
  react.default.useEffect(() => {
5104
5658
  tokensRef.current = {};
5105
5659
  setDirs({});
5106
5660
  setExpanded({});
5107
5661
  setLoading({});
5108
- setError(null);
5662
+ setErrors({});
5109
5663
  setMenu(null);
5110
5664
  setRoot(null);
5111
5665
  const cached = sessionId ? explorerLoad(sessionId) : null;
@@ -5116,8 +5670,8 @@ window.__ModuleLoader__.load({
5116
5670
  for (const rel of restored) next[rel] = true;
5117
5671
  setExpanded(next);
5118
5672
  }
5119
- loadDir("");
5120
- for (const rel of restored) if (rel) loadDir(rel);
5673
+ loadDir("", { prefetch: true });
5674
+ for (const rel of restored) if (rel) loadDir(rel, { prefetch: true });
5121
5675
  }, [sessionId]);
5122
5676
  react.default.useEffect(() => {
5123
5677
  if (saveTimerRef.current) {
@@ -5145,10 +5699,19 @@ window.__ModuleLoader__.load({
5145
5699
  sessionId
5146
5700
  ]);
5147
5701
  react.default.useEffect(() => {
5148
- const onRefresh = () => refresh();
5702
+ const onRefresh = () => refreshRef.current?.();
5149
5703
  window.addEventListener("edrv:refresh", onRefresh);
5150
5704
  return () => window.removeEventListener("edrv:refresh", onRefresh);
5151
5705
  }, []);
5706
+ react.default.useEffect(() => {
5707
+ if (!sessionId) return;
5708
+ const timer = setInterval(() => {
5709
+ const open = Object.keys(expandedRef.current).filter((k) => expandedRef.current[k] === true);
5710
+ if (!open.length) return;
5711
+ for (const rel of open) loadDirRef.current?.(rel, {});
5712
+ }, FOLLOW_INTERVAL_MS);
5713
+ return () => clearInterval(timer);
5714
+ }, [sessionId]);
5152
5715
  const rootName = root ? String(root).split(/[\\/]/).pop() || root : "";
5153
5716
  const rowEl = (e, depth, isDir, isOpen) => {
5154
5717
  const pending = isDir ? 0 : pendingByPath[e.path] ?? 0;
@@ -5181,7 +5744,7 @@ window.__ModuleLoader__.load({
5181
5744
  }, react.default.createElement("span", { className: "edrv-tree-chev" }, isDir ? isOpen ? "▾" : "▸" : ""), react.default.createElement("span", { className: "edrv-tree-name" + (dim ? " edrv-tree-dim" : "") }, isDir ? isOpen ? "📂" : "📁" : "📄", " ", e.name), pending > 0 ? react.default.createElement("span", { className: "edrv-tree-badge" }, String(pending)) : null);
5182
5745
  };
5183
5746
  const rowsOf = (rel, depth) => {
5184
- const entries = dirs[rel];
5747
+ const entries = entriesOf(rel);
5185
5748
  if (!entries) return [react.default.createElement("div", {
5186
5749
  key: rel + ":loading",
5187
5750
  className: "edrv-tree-loading",
@@ -5224,6 +5787,8 @@ window.__ModuleLoader__.load({
5224
5787
  separator: item.separator,
5225
5788
  onClick: () => item.run(menu.target, ctx)
5226
5789
  })) : [];
5790
+ const errorList = Object.entries(errors);
5791
+ const errorText = errorList.length ? errorList[0][1] : null;
5227
5792
  return react.default.createElement("div", {
5228
5793
  className: "edrv-side-panel",
5229
5794
  onContextMenu: onPanelContext
@@ -5234,7 +5799,7 @@ window.__ModuleLoader__.load({
5234
5799
  className: "edrv-side-btn",
5235
5800
  title: "刷新目录树",
5236
5801
  onClick: refresh
5237
- }, "⟳")), react.default.createElement("div", { className: "edrv-tree" }, error ? react.default.createElement("div", { className: "edrv-tree-error" }, react.default.createElement("span", null, String(error)), react.default.createElement("button", {
5802
+ }, "⟳")), react.default.createElement("div", { className: "edrv-tree" }, errorText ? react.default.createElement("div", { className: "edrv-tree-error" }, react.default.createElement("span", null, String(errorText)), react.default.createElement("button", {
5238
5803
  className: "edrv-side-btn",
5239
5804
  onClick: () => refresh()
5240
5805
  }, "重试")) : null, rowsOf("", 0)), menu && menuEntries.length ? react.default.createElement(ContextMenu, {
@@ -5300,6 +5865,7 @@ window.__ModuleLoader__.load({
5300
5865
  const [sectionOpen, setSectionOpen] = react.default.useState(false);
5301
5866
  const [status, setStatus] = react.default.useState("idle");
5302
5867
  const [error, setError] = react.default.useState("");
5868
+ const [warning, setWarning] = react.default.useState("");
5303
5869
  const [matches, setMatches] = react.default.useState(null);
5304
5870
  const [truncated, setTruncated] = react.default.useState(false);
5305
5871
  const [collapsed, setCollapsed] = react.default.useState({});
@@ -5327,7 +5893,7 @@ window.__ModuleLoader__.load({
5327
5893
  react.default.useEffect(() => {
5328
5894
  if (!sessionId) return;
5329
5895
  try {
5330
- const saved = JSON.parse(localStorage.getItem("edrv.search.v1." + String(sessionId)) || "null");
5896
+ const saved = JSON.parse(localStorage.getItem(CACHE_KEY.search + String(sessionId)) || "null");
5331
5897
  if (saved && typeof saved === "object") {
5332
5898
  if (typeof saved.query === "string") setQuery(saved.query);
5333
5899
  if (typeof saved.matchCase === "boolean") setMatchCase(saved.matchCase);
@@ -5344,7 +5910,7 @@ window.__ModuleLoader__.load({
5344
5910
  react.default.useEffect(() => {
5345
5911
  if (!sessionId) return;
5346
5912
  try {
5347
- localStorage.setItem("edrv.search.v1." + String(sessionId), JSON.stringify({
5913
+ localStorage.setItem(CACHE_KEY.search + String(sessionId), JSON.stringify({
5348
5914
  query,
5349
5915
  matchCase,
5350
5916
  wholeWord,
@@ -5383,6 +5949,7 @@ window.__ModuleLoader__.load({
5383
5949
  const req = requestRef.current;
5384
5950
  setStatus("searching");
5385
5951
  setError("");
5952
+ setWarning("");
5386
5953
  rpc("edrv.searchContent", {
5387
5954
  sessionId,
5388
5955
  query: clean,
@@ -5396,6 +5963,7 @@ window.__ModuleLoader__.load({
5396
5963
  if (res && res.ok) {
5397
5964
  setMatches(Array.isArray(res.matches) ? res.matches : []);
5398
5965
  setTruncated(res.truncated === true);
5966
+ setWarning(res?.warning ? String(res.warning) : "");
5399
5967
  setStatus("done");
5400
5968
  } else {
5401
5969
  setError(res?.error ? String(res.error) : "搜索失败");
@@ -5533,6 +6101,10 @@ window.__ModuleLoader__.load({
5533
6101
  onClick: () => toggleOpt("excludeOn", !excludeOn)
5534
6102
  }, "⚙"))) : null;
5535
6103
  const summary = status === "done" ? react.default.createElement("div", { className: "edrv-search-summary" }, totalFiles > 0 ? totalFiles + " 个文件 · " + totalMatches + " 处匹配" + (truncated ? "(已截断)" : "") : "无匹配结果") : null;
6104
+ const warnBanner = warning ? react.default.createElement("div", {
6105
+ className: "edrv-search-warn",
6106
+ title: warning
6107
+ }, warning) : null;
5536
6108
  const body = (() => {
5537
6109
  if (status === "searching") return react.default.createElement("div", { className: "edrv-search-empty" }, "搜索中…");
5538
6110
  if (status === "error") return react.default.createElement("div", { className: "edrv-search-error" }, error);
@@ -5574,7 +6146,7 @@ window.__ModuleLoader__.load({
5574
6146
  }
5575
6147
  if (e.key === "Escape") inputRef.current?.blur?.();
5576
6148
  }
5577
- })), optsBar, filterRows, summary, body);
6149
+ })), optsBar, filterRows, summary, warnBanner, body);
5578
6150
  }
5579
6151
  //#endregion
5580
6152
  //#region src/client/sidebar/panels/index.ts
@@ -6593,6 +7165,12 @@ window.__ModuleLoader__.load({
6593
7165
  order: 90,
6594
7166
  label: "差异"
6595
7167
  }, (props) => react.default.createElement(DiffBadge, Object.assign({}, props)));
7168
+ registerSlotSafely(ctx, {
7169
+ name: "conversation.session.header.utilities",
7170
+ id: "edrv-perf-size",
7171
+ order: 89,
7172
+ label: "会话体积"
7173
+ }, (props) => react.default.createElement(PerfSizeBadge, Object.assign({}, props, { sessions })));
6596
7174
  registerSlotSafely(ctx, {
6597
7175
  name: "settings.section",
6598
7176
  id: "vscode-mode",