dsh-vscode-mode 0.1.22 → 0.1.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -28,8 +28,9 @@ window.__ModuleLoader__.load({
28
28
  //#endregion
29
29
  let react = require("react");
30
30
  react = __toESM(react, 1);
31
+ let react_dom = require("react-dom");
31
32
  //#region \0dsh-css:/home/runner/work/DSH_VsCodeMode/DSH_VsCodeMode/src/client/styles/editor.css.mjs
32
- 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-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";
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";
33
34
  const tagId$1 = "dsh-vscode-mode/editor.css";
34
35
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
35
36
  const tag = document.createElement("style");
@@ -75,14 +76,251 @@ window.__ModuleLoader__.load({
75
76
  } catch (e) {}
76
77
  }
77
78
  //#endregion
79
+ //#region src/client/sidebarBridge.ts
80
+ /**
81
+ * dsh-vscode-mode client — 侧边栏编辑区桥:可选探测 dsh-better-sidebar 的
82
+ * ctx.betterSidebar 服务,并注册「文件编辑」Tab(单实例)。
83
+ * 可选依赖模式:服务缺失时调用方回退到中央页签形态;本模块不注册任何东西。
84
+ * 纯逻辑(探测/初始打开解析/角标计数)可单测,DOM/事件仅存在于 install 路径。
85
+ * 作者 ddj 2026年08月25号
86
+ */
87
+ /** betterSidebar 服务名(ctx.get 用;不要加进 inject——缺失会让插件停靠等待)。 */
88
+ const BETTER_SIDEBAR_SERVICE = "betterSidebar";
89
+ /** 本插件在侧边栏注册的 Tab 类型 id(亦是 SidebarTab.type)。 */
90
+ const SIDE_TAB_ID = "edrv-editor";
91
+ /** 侧边栏 Tab 标题。 */
92
+ const SIDE_TAB_TITLE = "文件编辑";
93
+ /** 推荐安装命令(提示条/兼容性报告共用)。 */
94
+ const SIDEBAR_INSTALL_CMD = "dsh plugin --profile web add dsh-better-sidebar";
95
+ /**
96
+ * 解析 Tab 挂载时的初始打开请求(创建路径读 tab.path/meta,聚焦路径走窗口事件)。
97
+ * @author ddj 2026年08月25号
98
+ * @param tab 侧边栏 Tab(path/meta 为可选字段)
99
+ * @returns 待打开路径与是否聚焦差异
100
+ */
101
+ function resolveInitialOpen(tab) {
102
+ const meta = tab?.meta ?? {};
103
+ return {
104
+ path: (typeof tab?.path === "string" && tab.path ? tab.path : typeof meta?.openPath === "string" ? meta.openPath : null) || null,
105
+ focusDiff: meta?.focusDiff === true
106
+ };
107
+ }
108
+ /** 会话级待处理差异文件数缓存(Tab 角标同步读取;EditorView 侧栏形态写入)。 */
109
+ const sidePending = /* @__PURE__ */ new Map();
110
+ /**
111
+ * 写入会话的待处理差异文件数(0 视为清除,不显示角标)。
112
+ * @author ddj 2026年08月25号
113
+ * @param sessionId 会话 id
114
+ * @param count 待处理差异文件数
115
+ */
116
+ function setSidePending(sessionId, count) {
117
+ if (!sessionId) return;
118
+ const value = Number.isFinite(count) ? Math.max(0, Math.floor(count)) : 0;
119
+ if (value > 0) sidePending.set(sessionId, value);
120
+ else sidePending.delete(sessionId);
121
+ }
122
+ /**
123
+ * 读取会话的待处理差异文件数(角标用)。
124
+ * @author ddj 2026年08月25号
125
+ * @param sessionId 会话 id
126
+ * @returns 非负计数
127
+ */
128
+ function getSidePending(sessionId) {
129
+ if (!sessionId) return 0;
130
+ return sidePending.get(sessionId) ?? 0;
131
+ }
132
+ /** 模块级侧栏打开路由(events.ts 优先走它;未注册 = 旧页签形态)。 */
133
+ let ensureSideEditor = null;
134
+ /** 待消费的初始打开(Tab 组件尚未挂载时暂存;按会话匹配,挂载时取走)。 */
135
+ let pendingOpen = null;
136
+ /** Tab 组件当前是否有挂载实例(有则直接投递窗口事件,无则暂存待消费)。 */
137
+ let sideEditorMounted = false;
138
+ /**
139
+ * 注册/撤销侧栏打开路由。
140
+ * @author ddj 2026年08月25号
141
+ * @param fn 路由函数或 null
142
+ */
143
+ function setEnsureSideEditor(fn) {
144
+ ensureSideEditor = fn;
145
+ }
146
+ /**
147
+ * 标记侧栏编辑器组件挂载状态(SideEditorTab 挂载/卸载时调用)。
148
+ * @author ddj 2026年08月25号
149
+ * @param mounted 是否已挂载
150
+ */
151
+ function setSideEditorMounted(mounted) {
152
+ sideEditorMounted = mounted;
153
+ }
154
+ /**
155
+ * 暂存指定会话的待消费初始打开(Tab 组件未挂载时由 install 路径调用)。
156
+ * @author ddj 2026年08月25号
157
+ * @param sessionId 会话 id
158
+ * @param path 待打开路径(可空)
159
+ * @param focusDiff 是否聚焦首个差异
160
+ */
161
+ function stagePendingSideOpen(sessionId, path, focusDiff) {
162
+ if (!sessionId) return;
163
+ pendingOpen = {
164
+ sessionId,
165
+ path: path || null,
166
+ focusDiff: focusDiff === true
167
+ };
168
+ }
169
+ /**
170
+ * 取走指定会话的待消费初始打开(SideEditorTab 挂载时读取;不存在返回 null)。
171
+ * @author ddj 2026年08月25号
172
+ * @param sessionId 会话 id
173
+ * @returns 待打开请求或 null
174
+ */
175
+ function takePendingSideOpen(sessionId) {
176
+ if (!pendingOpen || !sessionId || pendingOpen.sessionId !== sessionId) return null;
177
+ const value = {
178
+ path: pendingOpen.path,
179
+ focusDiff: pendingOpen.focusDiff
180
+ };
181
+ pendingOpen = null;
182
+ return value;
183
+ }
184
+ /**
185
+ * 打开/聚焦侧栏编辑器(打开路径可选;返回是否已被侧栏形态接管)。
186
+ * @author ddj 2026年08月25号
187
+ * @param path 待打开路径(可空)
188
+ * @param focusDiff 是否聚焦首个差异
189
+ * @returns 是否路由成功
190
+ */
191
+ function routeSideEditor(path, focusDiff) {
192
+ if (typeof ensureSideEditor !== "function") return false;
193
+ try {
194
+ return ensureSideEditor(path, focusDiff) === true;
195
+ } catch (error) {
196
+ console.warn("[dsh-vscode-mode] 侧栏编辑器打开失败(" + String(error) + "),已回退");
197
+ return false;
198
+ }
199
+ }
200
+ /**
201
+ * 结构化探测 betterSidebar 服务(可选依赖:缺失/降级返回 undefined)。
202
+ * @author ddj 2026年08月25号
203
+ * @param ctx 客户端服务上下文
204
+ * @returns 服务结构面或 undefined
205
+ */
206
+ function detectSidebarService(ctx) {
207
+ try {
208
+ const service = ctx.get(BETTER_SIDEBAR_SERVICE);
209
+ if (!service || typeof service.registerTab !== "function" || typeof service.openTab !== "function") return void 0;
210
+ return service;
211
+ } catch {
212
+ return;
213
+ }
214
+ }
215
+ /**
216
+ * 注册侧边栏「文件编辑」Tab 并接管打开路由。
217
+ * Tab 被用户在 better-sidebar 设置里禁用时,打开路由降级为回退回调(中央页签)。
218
+ * @author ddj 2026年08月25号
219
+ * @param options 装配参数(组件依赖 + 活动会话解析 + 回退注册)
220
+ * @returns 卸载器(反注册 Tab + 撤销路由)
221
+ */
222
+ function installSideEditor(options) {
223
+ const { service, renderTab, activeSession, registerLegacyFallback } = options;
224
+ let fallbackInstalled = false;
225
+ const open = (path, focusDiff) => {
226
+ if (typeof service.isTabEnabled === "function" && !service.isTabEnabled("edrv-editor")) {
227
+ if (!fallbackInstalled) {
228
+ fallbackInstalled = true;
229
+ try {
230
+ registerLegacyFallback();
231
+ } catch (error) {
232
+ console.warn("[dsh-vscode-mode] 回退注册失败(" + String(error) + ")");
233
+ }
234
+ }
235
+ return false;
236
+ }
237
+ const scope = activeSession();
238
+ const sessionId = scope?.sessionId;
239
+ if (!sessionId) return false;
240
+ try {
241
+ service.openTab({
242
+ type: SIDE_TAB_ID,
243
+ title: SIDE_TAB_TITLE,
244
+ ...path ? { path } : {},
245
+ meta: {
246
+ openPath: path || void 0,
247
+ focusDiff
248
+ }
249
+ }, {
250
+ sessionId,
251
+ cwd: scope?.cwd
252
+ });
253
+ } catch (error) {
254
+ console.warn("[dsh-vscode-mode] openTab 失败(" + String(error) + ")");
255
+ return false;
256
+ }
257
+ if (sideEditorMounted) window.dispatchEvent(new CustomEvent("edrv:open-editor", { detail: {
258
+ path,
259
+ focusDiff
260
+ } }));
261
+ else stagePendingSideOpen(sessionId, path, focusDiff);
262
+ return true;
263
+ };
264
+ let tabDisposer = null;
265
+ try {
266
+ tabDisposer = service.registerTab({
267
+ id: SIDE_TAB_ID,
268
+ title: SIDE_TAB_TITLE,
269
+ icon: codeIcon,
270
+ single: true,
271
+ badge: (_ctx, scope) => getSidePending(scope?.sessionId) || null,
272
+ component: renderTab
273
+ });
274
+ } catch (error) {
275
+ console.warn("[dsh-vscode-mode] 侧边栏 Tab 注册失败(" + String(error) + ")");
276
+ if (!fallbackInstalled) {
277
+ fallbackInstalled = true;
278
+ try {
279
+ registerLegacyFallback();
280
+ } catch (inner) {
281
+ console.warn("[dsh-vscode-mode] 回退注册失败(" + String(inner) + ")");
282
+ }
283
+ }
284
+ return () => {};
285
+ }
286
+ setEnsureSideEditor(open);
287
+ return () => {
288
+ if (typeof tabDisposer === "function") tabDisposer();
289
+ setEnsureSideEditor(null);
290
+ };
291
+ }
292
+ /**
293
+ * 侧边栏 Tab 图标(内联 SVG 代码括号,不依赖图标包)。
294
+ * @author ddj 2026年08月25号
295
+ * @param size 边长(px)
296
+ * @returns 图标元素
297
+ */
298
+ function codeIcon(size) {
299
+ return react.default.createElement("svg", {
300
+ width: size,
301
+ height: size,
302
+ viewBox: "0 0 16 16",
303
+ fill: "none",
304
+ "aria-hidden": true,
305
+ focusable: false
306
+ }, react.default.createElement("path", {
307
+ d: "M5.5 4.5 2.5 8l3 3.5M10.5 4.5 13.5 8l-3 3.5",
308
+ stroke: "currentColor",
309
+ strokeWidth: 1.4,
310
+ strokeLinecap: "round",
311
+ strokeLinejoin: "round"
312
+ }));
313
+ }
314
+ //#endregion
78
315
  //#region src/client/events.ts
79
316
  /**
80
317
  * dsh-vscode-mode client — 跨组件/跨 slot 的窗口事件助手。
81
- * 迁移自原 src/client/index.ts 的 openEditorView 与事件派发,语义不改。
318
+ * 迁移自原 src/client/index.ts 的 openEditorView 与事件派发,语义不改;
319
+ * 侧边栏形态(sidebarBridge 已注册路由)优先,否则回退 DOM 页签点击。
82
320
  * 作者 ddj 2026-08-20
83
321
  */
84
322
  /**
85
- * 选择中央「文件编辑」页签(DOM 级,无需 store actions)。
323
+ * 选择中央「文件编辑」页签(DOM 级,无需 store actions)。仅旧页签形态使用。
86
324
  * @author ddj 2026年08月26号
87
325
  */
88
326
  function selectEditorTab() {
@@ -93,11 +331,12 @@ window.__ModuleLoader__.load({
93
331
  }
94
332
  }
95
333
  /**
96
- * 打开中央「文件编辑」页签。
334
+ * 打开「文件编辑」:侧边栏形态路由优先,旧形态回退中央页签。
97
335
  * @author ddj 2026年08月26号
98
336
  * @param path 要打开的路径(可空)
99
337
  */
100
338
  function openEditorView(path) {
339
+ if (routeSideEditor(path ?? null, false)) return;
101
340
  selectEditorTab();
102
341
  const target = path ?? null;
103
342
  setTimeout(() => {
@@ -105,11 +344,12 @@ window.__ModuleLoader__.load({
105
344
  }, 80);
106
345
  }
107
346
  /**
108
- * 打开文件编辑页并聚焦指定文件的首个差异。
347
+ * 打开文件编辑页并聚焦指定文件的首个差异(侧边栏形态自动展开面板)。
109
348
  * @author ddj 2026年08月26号
110
349
  * @param path 待聚焦的差异文件路径
111
350
  */
112
351
  function openDiffView(path) {
352
+ if (routeSideEditor(path, true)) return;
113
353
  selectEditorTab();
114
354
  setTimeout(() => {
115
355
  window.dispatchEvent(new CustomEvent("edrv:open-editor", { detail: {
@@ -291,7 +531,7 @@ window.__ModuleLoader__.load({
291
531
  if (document.querySelector("script[data-edrv-monaco-loader]")) boot();
292
532
  else {
293
533
  const s = document.createElement("script");
294
- s.src = "/edrv/vendor/monaco/vs/loader.js";
534
+ s.src = MONACO_BASE + "/loader.js";
295
535
  s.dataset.edrvMonacoLoader = "1";
296
536
  s.onload = boot;
297
537
  s.onerror = () => fail(/* @__PURE__ */ new Error("Monaco loader 加载失败"));
@@ -323,6 +563,7 @@ window.__ModuleLoader__.load({
323
563
  * @param sessionId 会话 id
324
564
  */
325
565
  const render = (monaco, editor, pendingRegions, sessionId) => {
566
+ if (!pendingRegions.length && viewZoneIds.length === 0 && decorations.length === 0) return;
326
567
  const renderT0 = Date.now();
327
568
  const callIdAttr = (callId, idx) => String(callId) + ":" + String(idx);
328
569
  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("|"));
@@ -1374,11 +1615,15 @@ window.__ModuleLoader__.load({
1374
1615
  * 底部差异条(DiffBox/空态)+ 全局差异下拉(DiffLauncher)+ 状态栏。
1375
1616
  * @param props.sessionId 会话 id
1376
1617
  * @param props.schedule 延时调度(ctx.timeout)
1618
+ * @param props.layout 布局形态:'tab'(中央页签,默认)| 'side'(侧边栏面板)
1619
+ * @param props.sideHint 旧页签形态下显示侧边栏引导(安装命令)
1377
1620
  */
1378
1621
  function EditorView(props) {
1379
1622
  const sessionId = props?.sessionId;
1380
1623
  const schedule = props.schedule;
1381
1624
  const addToConversation = props.addToConversation;
1625
+ const layout = props?.layout === "side" ? "side" : "tab";
1626
+ const sideHint = props?.sideHint;
1382
1627
  const [monaco, setMonaco] = react.default.useState(null);
1383
1628
  const [monacoErr, setMonacoErr] = react.default.useState(null);
1384
1629
  const [records, setRecords] = react.default.useState({});
@@ -1403,10 +1648,17 @@ window.__ModuleLoader__.load({
1403
1648
  const [diffIdx, setDiffIdx] = react.default.useState(0);
1404
1649
  const [fileIdx, setFileIdx] = react.default.useState(0);
1405
1650
  const [tabMenu, setTabMenu] = react.default.useState(null);
1406
- const [sidebarOn, setSidebarOn] = react.default.useState(true);
1651
+ const [sidebarOn, setSidebarOn] = react.default.useState(layout !== "side");
1407
1652
  const [sidebarW, setSidebarW] = react.default.useState(240);
1408
1653
  const [activePanel, setActivePanel] = react.default.useState("explorer");
1409
1654
  const [focusRequest, setFocusRequest] = react.default.useState(0);
1655
+ const [hintDismissed, setHintDismissed] = react.default.useState(() => {
1656
+ try {
1657
+ return localStorage.getItem("edrv.side-hint-dismissed") === "1";
1658
+ } catch {
1659
+ return false;
1660
+ }
1661
+ });
1410
1662
  const editorRef = react.default.useRef(null);
1411
1663
  const viewRootRef = react.default.useRef(null);
1412
1664
  const monacoRef = react.default.useRef(null);
@@ -1427,6 +1679,8 @@ window.__ModuleLoader__.load({
1427
1679
  const batchBusyRef = react.default.useRef(false);
1428
1680
  const menuHandlersRef = react.default.useRef(null);
1429
1681
  const diffRendererRef = react.default.useRef(null);
1682
+ const layoutRef = react.default.useRef(layout);
1683
+ layoutRef.current = layout;
1430
1684
  if (!diffRendererRef.current) diffRendererRef.current = createDiffRenderer((sid, t) => dbg(sid, t));
1431
1685
  const currentRecords = react.default.useMemo(() => {
1432
1686
  const list = [];
@@ -1470,6 +1724,24 @@ window.__ModuleLoader__.load({
1470
1724
  return next;
1471
1725
  });
1472
1726
  };
1727
+ /**
1728
+ * 轮询去重:前后记录内容一致时返回原引用,React 跳过重渲染,
1729
+ * 阻断 5s 轮询 → memo 链 → diff 重渲染/日志 的空转。
1730
+ * @author ddj 2026年08月26号
1731
+ * @param prev 当前 records
1732
+ * @param next 轮询新结果
1733
+ * @returns 内容一致返回 true
1734
+ */
1735
+ const sameRecords = (prev, next) => {
1736
+ const pk = Object.keys(prev);
1737
+ const nk = Object.keys(next);
1738
+ if (pk.length !== nk.length) return false;
1739
+ for (const k of pk) {
1740
+ if (!(k in next)) return false;
1741
+ if (JSON.stringify(prev[k]) !== JSON.stringify(next[k])) return false;
1742
+ }
1743
+ return true;
1744
+ };
1473
1745
  const refreshRecords = (skipStale) => {
1474
1746
  if (!sessionId) return;
1475
1747
  rpc("edrv.list", {
@@ -1482,7 +1754,7 @@ window.__ModuleLoader__.load({
1482
1754
  if (r.archived === true) continue;
1483
1755
  map[r.callId] = r;
1484
1756
  }
1485
- setRecords(map);
1757
+ setRecords((prev) => sameRecords(prev, map) ? prev : map);
1486
1758
  }).catch((e) => setError("list异常:" + String(e)));
1487
1759
  };
1488
1760
  const loadContent = (path, sid) => {
@@ -1556,8 +1828,12 @@ window.__ModuleLoader__.load({
1556
1828
  };
1557
1829
  }, [sessionId]);
1558
1830
  const dockSourceRef = react.default.useRef({});
1559
- react.default.useEffect(() => () => clearDiffDock(sessionId, dockSourceRef.current), [sessionId]);
1831
+ react.default.useEffect(() => () => {
1832
+ clearDiffDock(sessionId, dockSourceRef.current);
1833
+ if (layout === "side") setSidePending(sessionId, 0);
1834
+ }, [sessionId]);
1560
1835
  react.default.useLayoutEffect(() => {
1836
+ if (layout === "side") return;
1561
1837
  const root = viewRootRef.current;
1562
1838
  const scroll = root?.closest?.("[data-conversation-scroll]");
1563
1839
  if (!root || !scroll) return;
@@ -1606,7 +1882,7 @@ window.__ModuleLoader__.load({
1606
1882
  window.removeEventListener("resize", scheduleUpdate);
1607
1883
  root.style.removeProperty("--edrv-editor-height");
1608
1884
  };
1609
- }, [sessionId]);
1885
+ }, [sessionId, layout]);
1610
1886
  react.default.useEffect(() => {
1611
1887
  if (bootRef.current || !sessionId) return;
1612
1888
  bootRef.current = true;
@@ -1634,10 +1910,11 @@ window.__ModuleLoader__.load({
1634
1910
  active,
1635
1911
  sessionId
1636
1912
  ]);
1913
+ const sidebarKey = "edrv.sidebar." + (layout === "side" ? "side." : "") + String(sessionId);
1637
1914
  react.default.useEffect(() => {
1638
1915
  if (!sessionId) return;
1639
1916
  try {
1640
- const raw = localStorage.getItem("edrv.sidebar." + String(sessionId));
1917
+ const raw = localStorage.getItem(sidebarKey);
1641
1918
  if (raw) {
1642
1919
  const saved = JSON.parse(raw);
1643
1920
  if (typeof saved.on === "boolean") setSidebarOn(saved.on);
@@ -1645,11 +1922,11 @@ window.__ModuleLoader__.load({
1645
1922
  if (typeof saved.panel === "string") setActivePanel(saved.panel);
1646
1923
  }
1647
1924
  } catch (e) {}
1648
- }, [sessionId]);
1925
+ }, [sessionId, sidebarKey]);
1649
1926
  react.default.useEffect(() => {
1650
1927
  if (!sessionId) return;
1651
1928
  try {
1652
- localStorage.setItem("edrv.sidebar." + String(sessionId), JSON.stringify({
1929
+ localStorage.setItem(sidebarKey, JSON.stringify({
1653
1930
  on: sidebarOn,
1654
1931
  width: sidebarW,
1655
1932
  panel: activePanel
@@ -1659,7 +1936,8 @@ window.__ModuleLoader__.load({
1659
1936
  sidebarOn,
1660
1937
  sidebarW,
1661
1938
  activePanel,
1662
- sessionId
1939
+ sessionId,
1940
+ sidebarKey
1663
1941
  ]);
1664
1942
  react.default.useEffect(() => {
1665
1943
  const onKey = (e) => {
@@ -1825,6 +2103,7 @@ window.__ModuleLoader__.load({
1825
2103
  }
1826
2104
  if (editorRef.current || !monacoRef.current) return;
1827
2105
  const m = monacoRef.current;
2106
+ const side = layoutRef.current === "side";
1828
2107
  const ed = m.editor.create(node, {
1829
2108
  value: "",
1830
2109
  language: "plaintext",
@@ -1833,7 +2112,7 @@ window.__ModuleLoader__.load({
1833
2112
  fontSize: 13,
1834
2113
  lineHeight: 20,
1835
2114
  minimap: {
1836
- enabled: true,
2115
+ enabled: !side,
1837
2116
  scale: 1
1838
2117
  },
1839
2118
  glyphMargin: true,
@@ -1845,7 +2124,7 @@ window.__ModuleLoader__.load({
1845
2124
  renderWhitespace: "selection",
1846
2125
  smoothScrolling: true,
1847
2126
  cursorBlinking: "smooth",
1848
- padding: { top: 8 }
2127
+ padding: { top: side ? 6 : 8 }
1849
2128
  });
1850
2129
  ed.addCommand(m.KeyMod.CtrlCmd | m.KeyCode.KeyS, () => {
1851
2130
  flushSave();
@@ -2434,39 +2713,42 @@ window.__ModuleLoader__.load({
2434
2713
  actHunk(hoverAct.region, true);
2435
2714
  }
2436
2715
  }, "↩ Undo")) : null;
2716
+ /** 组装差异 dock 快照(发布给 conversation.input.dock 的唯一 DiffBox 实例)。 */
2717
+ const buildDockSnapshot = () => ({
2718
+ mode: editorDockMode(active),
2719
+ pendingRegions,
2720
+ staleRegions,
2721
+ onAct: actHunk,
2722
+ onAcceptFile: acceptFile,
2723
+ onUndoFile: undoFile,
2724
+ onAcceptAllFiles: acceptAllFiles,
2725
+ onUndoAllFiles: undoAllFiles,
2726
+ allPendingCount: allPending.length,
2727
+ onRollback: rollbackFile,
2728
+ onJump: jumpTo,
2729
+ otherFiles,
2730
+ onOpenOther: (path) => openFile(path, true),
2731
+ onOpenLauncher: (tab) => {
2732
+ setLauncherTab(tab || "pending");
2733
+ setLauncherOpen(true);
2734
+ },
2735
+ onRefresh: reloadFile,
2736
+ activePath: active,
2737
+ diffIdx: contentReady ? diffIdx : 0,
2738
+ diffTotal: displayDiffTotal(contentReady, pendingRegions.length, sum.files.find((file) => file.path === active)?.pending ?? 0),
2739
+ fileIdx,
2740
+ fileTotal: sum.pendingFiles.length,
2741
+ onPrevDiff: () => gotoDiff(-1),
2742
+ onNextDiff: () => gotoDiff(1),
2743
+ onPrevFile: () => gotoFile(-1),
2744
+ onNextFile: () => gotoFile(1),
2745
+ onOpenNextFile: openNextFile
2746
+ });
2437
2747
  react.default.useEffect(() => {
2438
2748
  if (!sessionId) return;
2439
- const mode = editorDockMode(active);
2440
- publishDiffDock(sessionId, {
2441
- mode,
2442
- pendingRegions,
2443
- staleRegions,
2444
- onAct: actHunk,
2445
- onAcceptFile: acceptFile,
2446
- onUndoFile: undoFile,
2447
- onAcceptAllFiles: acceptAllFiles,
2448
- onUndoAllFiles: undoAllFiles,
2449
- allPendingCount: allPending.length,
2450
- onRollback: rollbackFile,
2451
- onJump: jumpTo,
2452
- otherFiles,
2453
- onOpenOther: (path) => openFile(path, true),
2454
- onOpenLauncher: (tab) => {
2455
- setLauncherTab(tab || "pending");
2456
- setLauncherOpen(true);
2457
- },
2458
- onRefresh: reloadFile,
2459
- activePath: active,
2460
- diffIdx: contentReady ? diffIdx : 0,
2461
- diffTotal: displayDiffTotal(contentReady, pendingRegions.length, sum.files.find((file) => file.path === active)?.pending ?? 0),
2462
- fileIdx,
2463
- fileTotal: sum.pendingFiles.length,
2464
- onPrevDiff: () => gotoDiff(-1),
2465
- onNextDiff: () => gotoDiff(1),
2466
- onPrevFile: () => gotoFile(-1),
2467
- onNextFile: () => gotoFile(1),
2468
- onOpenNextFile: openNextFile
2469
- }, dockSourceRef.current);
2749
+ publishDiffDock(sessionId, buildDockSnapshot(), dockSourceRef.current);
2750
+ if (layout === "side") setSidePending(sessionId, sum.totalFiles);
2751
+ else setSidePending(sessionId, 0);
2470
2752
  });
2471
2753
  const overlay = launcherOpen ? react.default.createElement(react.default.Fragment, null, react.default.createElement("div", {
2472
2754
  style: {
@@ -2538,6 +2820,25 @@ window.__ModuleLoader__.load({
2538
2820
  notify: (message) => setStatus(message)
2539
2821
  };
2540
2822
  const editorArea = react.default.createElement("div", { className: "edrv-editor-area" }, body, hoverEl, overlay);
2823
+ const dismissHint = () => {
2824
+ setHintDismissed(true);
2825
+ try {
2826
+ localStorage.setItem("edrv.side-hint-dismissed", "1");
2827
+ } catch (e) {}
2828
+ };
2829
+ const copyInstallCmd = () => {
2830
+ if (navigator.clipboard?.writeText) navigator.clipboard.writeText(SIDEBAR_INSTALL_CMD).catch(() => {});
2831
+ };
2832
+ const sideHintEl = layout === "tab" && sideHint && !hintDismissed ? react.default.createElement("div", { className: "edrv-side-hint" }, react.default.createElement("span", { className: "edrv-side-hint-text" }, "安装 dsh-better-sidebar 后可启用侧边栏编辑(对话+编辑同屏):"), react.default.createElement("code", { className: "edrv-side-hint-cmd" }, SIDEBAR_INSTALL_CMD), react.default.createElement("button", {
2833
+ className: "edrv-pill edrv-pill-ghost",
2834
+ title: "复制安装命令",
2835
+ onClick: copyInstallCmd
2836
+ }, "复制命令"), react.default.createElement("button", {
2837
+ className: "edrv-side-hint-close",
2838
+ title: "关闭提示",
2839
+ "aria-label": "关闭提示",
2840
+ onClick: dismissHint
2841
+ }, "×")) : null;
2541
2842
  const mainCol = react.default.createElement("div", {
2542
2843
  className: "edrv-main-col",
2543
2844
  style: {
@@ -2548,7 +2849,7 @@ window.__ModuleLoader__.load({
2548
2849
  flexDirection: "column",
2549
2850
  overflow: "hidden"
2550
2851
  }
2551
- }, pathBar, tabRow, editorArea);
2852
+ }, pathBar, tabRow, sideHintEl, editorArea);
2552
2853
  const editorRow = react.default.createElement("div", { className: "edrv-editor-row" }, sidebarOn && sidebarPanels ? react.default.createElement(SidebarView, {
2553
2854
  registry: sidebarPanels,
2554
2855
  ctx: sidebarCtx,
@@ -2558,18 +2859,26 @@ window.__ModuleLoader__.load({
2558
2859
  onWidth: setSidebarW,
2559
2860
  onHide: () => setSidebarOn(false)
2560
2861
  }) : null, mainCol);
2561
- return react.default.createElement("div", {
2862
+ const baseStyle = {
2863
+ minHeight: 0,
2864
+ display: "flex",
2865
+ flexDirection: "column",
2866
+ background: "var(--dsw-alias-bg-base,transparent)",
2867
+ overflow: "hidden"
2868
+ };
2869
+ return layout === "side" ? react.default.createElement("div", {
2562
2870
  ref: viewRootRef,
2563
2871
  "data-edrv-view": "1",
2564
- style: {
2872
+ "data-edrv-layout": "side",
2873
+ className: "edrv-view-side",
2874
+ style: Object.assign({}, baseStyle, { height: "100%" })
2875
+ }, editorRow, menuBackdrop, tabMenuEl) : react.default.createElement("div", {
2876
+ ref: viewRootRef,
2877
+ "data-edrv-view": "1",
2878
+ style: Object.assign({}, baseStyle, {
2565
2879
  height: "var(--edrv-editor-height, 100%)",
2566
- maxHeight: "var(--edrv-editor-height, 100%)",
2567
- minHeight: 0,
2568
- display: "flex",
2569
- flexDirection: "column",
2570
- background: "var(--dsw-alias-bg-base,transparent)",
2571
- overflow: "hidden"
2572
- }
2880
+ maxHeight: "var(--edrv-editor-height, 100%)"
2881
+ })
2573
2882
  }, editorRow, menuBackdrop, tabMenuEl);
2574
2883
  }
2575
2884
  //#endregion
@@ -2584,14 +2893,14 @@ window.__ModuleLoader__.load({
2584
2893
  */
2585
2894
  function DiffBadge(props) {
2586
2895
  const sessionId = props?.sessionId;
2587
- const [n, setN] = react.default.useState(0);
2896
+ const [summary, setSummary] = react.default.useState(null);
2588
2897
  const seq = react.default.useRef(0);
2589
2898
  const load = react.default.useCallback(() => {
2590
2899
  if (!sessionId) return;
2591
2900
  const s = ++seq.current;
2592
2901
  rpc("edrv.list", { sessionId }).then((res) => {
2593
2902
  if (s !== seq.current || !res || !res.ok || !Array.isArray(res.records)) return;
2594
- setN(summarize(res.records).totalFiles);
2903
+ setSummary(summarize(res.records));
2595
2904
  }).catch(() => {});
2596
2905
  }, [sessionId]);
2597
2906
  react.default.useEffect(() => {
@@ -2604,9 +2913,10 @@ window.__ModuleLoader__.load({
2604
2913
  window.removeEventListener("edrv:refresh", onRefresh);
2605
2914
  };
2606
2915
  }, [load]);
2916
+ const n = summary?.totalFiles ?? 0;
2607
2917
  if (!n) return null;
2608
2918
  const click = () => {
2609
- openEditorView(null);
2919
+ openEditorView(summary?.pendingFiles?.[0]?.path ?? null);
2610
2920
  setTimeout(() => {
2611
2921
  emitShowLauncher();
2612
2922
  }, 120);
@@ -3597,6 +3907,51 @@ window.__ModuleLoader__.load({
3597
3907
  return typeof value === "string" && value.trim() ? value.trim() : AUTO_OPEN_TOOL;
3598
3908
  }
3599
3909
  //#endregion
3910
+ //#region src/client/ui/SideEditorTab.ts
3911
+ /**
3912
+ * dsh-vscode-mode client — SideEditorTab:betterSidebar「文件编辑」Tab 的组件包装。
3913
+ * 把 TabComponentProps(scope/tab/visible)映射为 EditorView 侧栏形态 props,
3914
+ * 并按会话 key 保证切会话状态干净重建;创建种子的初始打开在挂载后投递一次。
3915
+ * 作者 ddj 2026年08月25号
3916
+ */
3917
+ /**
3918
+ * 侧边栏 Tab 组件(TabDescriptor.component 装配)。
3919
+ * @param props TabComponentProps(scope.sessionId、tab.path/meta 等)
3920
+ * @returns EditorView 侧栏形态
3921
+ */
3922
+ function SideEditorTab(props) {
3923
+ const sessionId = props?.scope?.sessionId;
3924
+ const initial = react.default.useMemo(() => resolveInitialOpen(props?.tab), [props?.tab]);
3925
+ const dispatchedRef = react.default.useRef(false);
3926
+ react.default.useEffect(() => {
3927
+ setSideEditorMounted(true);
3928
+ return () => setSideEditorMounted(false);
3929
+ }, []);
3930
+ react.default.useEffect(() => {
3931
+ if (dispatchedRef.current) return;
3932
+ dispatchedRef.current = true;
3933
+ const request = takePendingSideOpen(sessionId) ?? initial;
3934
+ window.dispatchEvent(new CustomEvent("edrv:open-editor", { detail: {
3935
+ path: request?.path ?? null,
3936
+ focusDiff: request?.focusDiff === true
3937
+ } }));
3938
+ }, [
3939
+ initial.path,
3940
+ initial.focusDiff,
3941
+ sessionId
3942
+ ]);
3943
+ return react.default.createElement(EditorView, {
3944
+ key: sessionId,
3945
+ sessionId,
3946
+ layout: "side",
3947
+ schedule: props?.schedule,
3948
+ addToConversation: props?.addToConversation,
3949
+ sidebarPanels: props?.sidebarPanels,
3950
+ outlineSources: props?.outlineSources,
3951
+ fileMenuItems: props?.fileMenuItems
3952
+ });
3953
+ }
3954
+ //#endregion
3600
3955
  //#region src/client/addToConversation.ts
3601
3956
  /** DSH reference source 名(dsh-client-ui-reference 注册的 @file/@session 统一源)。 */
3602
3957
  const REF_SOURCE = "reference";
@@ -3775,10 +4130,50 @@ window.__ModuleLoader__.load({
3775
4130
  };
3776
4131
  }
3777
4132
  //#endregion
4133
+ //#region src/client/ui/menuPosition.ts
4134
+ /**
4135
+ * 将菜单坐标限制在 viewport 内。
4136
+ * @author ddj 2026年08月28号
4137
+ * @param x 期望的 viewport x 坐标
4138
+ * @param y 期望的 viewport y 坐标
4139
+ * @param viewportWidth viewport 宽度
4140
+ * @param viewportHeight viewport 高度
4141
+ * @param menuWidth 菜单估算宽度
4142
+ * @param menuHeight 菜单估算高度
4143
+ * @returns 限制后的菜单位置
4144
+ */
4145
+ function clampMenuPosition(x, y, viewportWidth, viewportHeight, menuWidth, menuHeight) {
4146
+ const maxLeft = Math.max(4, viewportWidth - menuWidth);
4147
+ const maxTop = Math.max(4, viewportHeight - menuHeight);
4148
+ return {
4149
+ left: Math.max(4, Math.min(x, maxLeft)),
4150
+ top: Math.max(4, Math.min(y, maxTop))
4151
+ };
4152
+ }
4153
+ /**
4154
+ * 将文件树行右键菜单锚定到目标行右侧;无法测量时回退到鼠标坐标。
4155
+ * @author ddj 2026年08月28号
4156
+ * @param rect 目标行的布局矩形
4157
+ * @param fallbackX 鼠标 viewport x 坐标
4158
+ * @param fallbackY 鼠标 viewport y 坐标
4159
+ * @returns 菜单初始位置
4160
+ */
4161
+ function rowMenuPosition(rect, fallbackX, fallbackY) {
4162
+ if (!rect || rect.width <= 0 || rect.height <= 0) return {
4163
+ left: fallbackX,
4164
+ top: fallbackY
4165
+ };
4166
+ return {
4167
+ left: rect.right + 4,
4168
+ top: rect.top
4169
+ };
4170
+ }
4171
+ //#endregion
3778
4172
  //#region src/client/ui/ContextMenu.ts
3779
4173
  /**
3780
4174
  * dsh-vscode-mode client — 通用浮动右键菜单(createElement 风格、类型化)。
3781
- * 全屏 backdrop(点击/右键/Esc 关闭)+ 固定定位(viewport clamp 防越界),
4175
+ * 非阻塞式关闭:window capture 监听(点击菜单外/右键菜单外/Esc 关闭),
4176
+ * 不拦截菜单外事件,允许同一事件内由发起方切换/重开菜单。
3782
4177
  * 条目支持 danger/disabled/separator,复用既有 edrv-ctxmenu* 样式类。
3783
4178
  * 作者 ddj 2026-08-27
3784
4179
  */
@@ -3794,15 +4189,30 @@ window.__ModuleLoader__.load({
3794
4189
  */
3795
4190
  function ContextMenu(props) {
3796
4191
  const { x, y, entries, onClose } = props;
4192
+ const menuRef = react.default.useRef(null);
3797
4193
  react.default.useEffect(() => {
3798
4194
  const onKey = (e) => {
3799
4195
  if (e.key === "Escape") onClose();
3800
4196
  };
4197
+ const onPointerDown = (e) => {
4198
+ if (e.button !== 0) return;
4199
+ if (menuRef.current && menuRef.current.contains(e.target)) return;
4200
+ onClose();
4201
+ };
4202
+ const onContextMenu = (e) => {
4203
+ if (menuRef.current && menuRef.current.contains(e.target)) e.preventDefault();
4204
+ onClose();
4205
+ };
3801
4206
  window.addEventListener("keydown", onKey, true);
3802
- return () => window.removeEventListener("keydown", onKey, true);
4207
+ window.addEventListener("pointerdown", onPointerDown, true);
4208
+ window.addEventListener("contextmenu", onContextMenu, true);
4209
+ return () => {
4210
+ window.removeEventListener("keydown", onKey, true);
4211
+ window.removeEventListener("pointerdown", onPointerDown, true);
4212
+ window.removeEventListener("contextmenu", onContextMenu, true);
4213
+ };
3803
4214
  }, [onClose]);
3804
- const left = Math.max(4, Math.min(x, (window.innerWidth || 800) - MENU_W));
3805
- const top = Math.max(4, Math.min(y, (window.innerHeight || 600) - MENU_H));
4215
+ const position = clampMenuPosition(Number.isFinite(x) ? x : 4, Number.isFinite(y) ? y : 4, window.innerWidth || 800, window.innerHeight || 600, MENU_W, MENU_H);
3806
4216
  const children = [];
3807
4217
  for (const entry of entries) {
3808
4218
  if (entry.separator) {
@@ -3825,25 +4235,12 @@ window.__ModuleLoader__.load({
3825
4235
  }
3826
4236
  }, entry.label));
3827
4237
  }
3828
- return react.default.createElement(react.default.Fragment, null, react.default.createElement("div", {
3829
- className: "edrv-ctxmenu-backdrop",
3830
- style: {
3831
- position: "fixed",
3832
- inset: 0,
3833
- zIndex: 70
3834
- },
3835
- onClick: onClose,
3836
- onContextMenu: (e) => {
3837
- e.preventDefault();
3838
- onClose();
3839
- }
3840
- }), react.default.createElement("div", {
4238
+ const overlay = react.default.createElement("div", { "data-edrv-view": "1" }, react.default.createElement("div", {
3841
4239
  className: "edrv-ctxmenu",
3842
- style: {
3843
- left,
3844
- top
3845
- }
4240
+ ref: menuRef,
4241
+ style: position
3846
4242
  }, ...children));
4243
+ return typeof document === "undefined" ? overlay : (0, react_dom.createPortal)(overlay, document.body);
3847
4244
  }
3848
4245
  //#endregion
3849
4246
  //#region src/client/sidebar/contextMenu.ts
@@ -3966,6 +4363,7 @@ window.__ModuleLoader__.load({
3966
4363
  const refresh = () => {
3967
4364
  const keep = Object.keys(expandedRef.current).filter((k) => expandedRef.current[k] === true);
3968
4365
  tokensRef.current = {};
4366
+ setMenu(null);
3969
4367
  setDirs({});
3970
4368
  setLoading({});
3971
4369
  setError(null);
@@ -3983,6 +4381,7 @@ window.__ModuleLoader__.load({
3983
4381
  setExpanded({});
3984
4382
  setLoading({});
3985
4383
  setError(null);
4384
+ setMenu(null);
3986
4385
  setRoot(null);
3987
4386
  loadDir("");
3988
4387
  }, [sessionId]);
@@ -3995,10 +4394,11 @@ window.__ModuleLoader__.load({
3995
4394
  const rowEl = (e, depth, isDir, isOpen) => {
3996
4395
  const pending = isDir ? 0 : pendingByPath[e.path] ?? 0;
3997
4396
  const active = !isDir && e.path === activePath;
4397
+ const contextTarget = Boolean(menu && menuEntries.length && menu.target.path === e.path);
3998
4398
  const dim = e.type === "other";
3999
4399
  return react.default.createElement("div", {
4000
4400
  key: e.path,
4001
- className: "edrv-tree-row" + (active ? " edrv-tree-active" : ""),
4401
+ className: "edrv-tree-row" + (active ? " edrv-tree-active" : "") + (contextTarget ? " edrv-tree-context" : ""),
4002
4402
  title: e.path,
4003
4403
  style: { paddingLeft: 6 + depth * 14 },
4004
4404
  onClick: () => {
@@ -4008,9 +4408,11 @@ window.__ModuleLoader__.load({
4008
4408
  onContextMenu: (ev) => {
4009
4409
  ev.preventDefault();
4010
4410
  ev.stopPropagation();
4411
+ const rect = ev.currentTarget?.getBoundingClientRect?.();
4412
+ const position = rowMenuPosition(rect, ev.clientX, ev.clientY);
4011
4413
  setMenu({
4012
- x: ev.clientX,
4013
- y: ev.clientY,
4414
+ x: position.left,
4415
+ y: position.top,
4014
4416
  target: {
4015
4417
  path: e.path,
4016
4418
  type: e.type
@@ -4044,6 +4446,8 @@ window.__ModuleLoader__.load({
4044
4446
  };
4045
4447
  const onPanelContext = (ev) => {
4046
4448
  ev.preventDefault();
4449
+ ev.stopPropagation();
4450
+ if (!ev.currentTarget.contains(ev.target)) return;
4047
4451
  setMenu({
4048
4452
  x: ev.clientX,
4049
4453
  y: ev.clientY,
@@ -4862,7 +5266,8 @@ window.__ModuleLoader__.load({
4862
5266
  //#region src/client/index.ts
4863
5267
  /**
4864
5268
  * dsh-vscode-mode client — 浏览器半入口:slot 注册 + 装配。
4865
- * 挂点:conversation.view「文件编辑」页签(中央 Monaco 编辑器)+ conversation.input.dock 差异条 + header 差异角标。
5269
+ * 挂点:betterSidebar「文件编辑」Tab(侧边栏形态,对话+编辑同屏;未装 dsh-better-sidebar 时
5270
+ * 回退 conversation.view 中央页签)+ conversation.input.dock 差异条 + header 差异角标。
4866
5271
  * 与 Host 通信:同源 fetch('/edrv/rpc')(shared/rpc 契约)。
4867
5272
  *
4868
5273
  * ⚠️ 跨版本 slot 装配(2026-08-21):新版 DSH 的 slots 系统要求 slot 必须由父 entry
@@ -4915,6 +5320,8 @@ window.__ModuleLoader__.load({
4915
5320
  const binder = pickSettingsBinder(ctx);
4916
5321
  const settings = binder.scope;
4917
5322
  let selected = autoValue("auto");
5323
+ /** 可选探测 betterSidebar 服务(不进 inject:缺失会让插件停靠等待,杀死回退路径)。 */
5324
+ const sideService = detectSidebarService(ctx);
4918
5325
  /** 「添加到对话」动作集:编辑区/Tab 右键菜单注入文件引用与代码块(conversation 服务缺失时各动作安全降级)。 */
4919
5326
  const addToConversation = createAddToConversation(ctx);
4920
5327
  /** 客户端侧兼容摘要(与 host 报告合并展示;惰性求值保证 HMR 后仍新鲜)。 */
@@ -4933,6 +5340,11 @@ window.__ModuleLoader__.load({
4933
5340
  name: "侧边栏打开器(dsh-better-sidebar)",
4934
5341
  active: registry.get(SIDEBAR_PLUGIN) !== void 0,
4935
5342
  note: registry.get("dsh-better-sidebar") !== void 0 ? "已注册(优先级 80)" : "未检测到侧边栏打开能力"
5343
+ },
5344
+ {
5345
+ name: "侧边栏编辑区(dsh-better-sidebar)",
5346
+ active: sideService !== void 0,
5347
+ note: sideService !== void 0 ? "编辑区=侧边栏 Tab(对话+编辑同屏)" : "未检测到;安装 dsh-better-sidebar 后刷新启用侧边栏形态(" + SIDEBAR_INSTALL_CMD + ")"
4936
5348
  }
4937
5349
  ];
4938
5350
  ctx.provide("fileOpeners", registry);
@@ -4982,19 +5394,47 @@ window.__ModuleLoader__.load({
4982
5394
  },
4983
5395
  logger: (message) => console.warn("[dsh-vscode-mode] " + message)
4984
5396
  }), "vscode-mode: file link routing");
4985
- registerSlotSafely(ctx, {
4986
- name: "conversation.view",
4987
- id: "edrv-editor",
4988
- order: 5,
4989
- label: "文件编辑",
4990
- inject: (sessionId) => ({ sessionId })
4991
- }, (props) => react.default.createElement(EditorView, Object.assign({}, props, {
4992
- schedule,
4993
- addToConversation,
4994
- sidebarPanels,
4995
- outlineSources,
4996
- fileMenuItems
4997
- })));
5397
+ const registerLegacyTab = () => {
5398
+ registerSlotSafely(ctx, {
5399
+ name: "conversation.view",
5400
+ id: "edrv-editor",
5401
+ order: 5,
5402
+ label: "文件编辑",
5403
+ inject: (sessionId) => ({ sessionId })
5404
+ }, (props) => react.default.createElement(EditorView, Object.assign({}, props, {
5405
+ layout: "tab",
5406
+ sideHint: SIDEBAR_INSTALL_CMD,
5407
+ schedule,
5408
+ addToConversation,
5409
+ sidebarPanels,
5410
+ outlineSources,
5411
+ fileMenuItems
5412
+ })));
5413
+ };
5414
+ if (sideService) ctx.effect(() => installSideEditor({
5415
+ service: sideService,
5416
+ renderTab: (props) => react.default.createElement(SideEditorTab, Object.assign({}, props, {
5417
+ schedule,
5418
+ addToConversation,
5419
+ sidebarPanels,
5420
+ outlineSources,
5421
+ fileMenuItems
5422
+ })),
5423
+ activeSession: () => {
5424
+ const snapshot = sessions?.list?.getSnapshot?.();
5425
+ const sessionId = snapshot?.current;
5426
+ if (!sessionId) return void 0;
5427
+ return {
5428
+ sessionId,
5429
+ cwd: snapshot?.byId?.[sessionId]?.cwd
5430
+ };
5431
+ },
5432
+ registerLegacyFallback: registerLegacyTab
5433
+ }), "vscode-mode: sidebar editor tab");
5434
+ else {
5435
+ setEnsureSideEditor(null);
5436
+ registerLegacyTab();
5437
+ }
4998
5438
  registerSlotSafely(ctx, {
4999
5439
  name: "conversation.input.dock",
5000
5440
  id: "edrv-diff-dock",