dsh-vscode-mode 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -33,7 +33,7 @@ window.__ModuleLoader__.load({
33
33
  let react_dom = require("react-dom");
34
34
  let react_dom_client = require("react-dom/client");
35
35
  //#region \0dsh-css:/home/runner/work/DSH_VsCodeMode/DSH_VsCodeMode/src/client/styles/editor.css.mjs
36
- const css$1 = "/* dsh-vscode-mode 编辑区样式(原 ensureEdrvStyles 字符串,落盘为真 .css,由 tsdown CSS-inline 注入) */\n/* 主题:跟随官方 --dsw-alias-* 令牌(DSH 明暗与第三方皮肤生效)。\n 本作用域不再重定义官方令牌(旧实现曾在此硬覆盖浅色盘,导致插件不跟随 DSH 主题);\n 旧环境/缺令牌场景由每条声明的 var(--dsw-alias-*, 回落值) 兜底。\n @author ddj 2026-09-10 */\n[data-edrv-view] { box-sizing: border-box; --edrv-tab-h: 34px; }\n\n[data-edrv-view] .edrv-tabs { display: flex; align-items: center; gap: 2px; padding: 2px 8px 0; background: var(--dsw-alias-bg-layer-1, transparent); overflow-x: auto; overflow-y: hidden; scrollbar-width: thin; flex-shrink: 0; overscroll-behavior-x: contain; } /* overscroll-behavior-x: 横滚到边界不把滚动链传给页面(滚轮横滚接管更可控)@author ddj 2026年09月18号 */\n[data-edrv-view] .edrv-tab { display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 8px 0 12px; border: none; border-radius: 6px 6px 0 0; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 12px; cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-tab.edrv-tab-active { background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); box-shadow: inset 0 -2px 0 var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-tab .edrv-tab-star { color: var(--dsw-alias-brand-primary, #4f8cff); font-size: 13px; font-weight: 700; line-height: 1; flex-shrink: 0; } /* 未保存修改星号 @author ddj 2026年09月09号 */\n[data-edrv-view] .edrv-tab .edrv-tab-x { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; border-radius: 4px; color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; }\n[data-edrv-view] .edrv-tab .edrv-tab-x:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.12)); color: var(--dsw-alias-label-primary, #eee); }\n/* 固定页签:📌 标记 + 免关闭按钮(固定页签不渲染 ×,仅可经右键菜单取消固定) */\n[data-edrv-view] .edrv-tab .edrv-tab-pin { flex-shrink: 0; font-size: 10px; line-height: 1; opacity: .85; }\n[data-edrv-view] .edrv-tab.edrv-tab-pinned { background: var(--dsw-alias-bg-layer-2, rgba(255,255,255,.04)); }\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/* 键盘高亮项(↑↓ 选择):与 hover 同特异性但声明在后,故选中态稳定可辨 @author ddj 2026年09月11号 */\n[data-edrv-view] .edrv-search-item.edrv-search-sel { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.14)); }\n[data-edrv-view] .edrv-search-item .n { color: var(--dsw-alias-label-primary, #eee); font-size: 12px; word-break: break-all; }\n[data-edrv-view] .edrv-search-item .d { color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-search-empty { padding: 8px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #888); }\n[data-edrv-view] .edrv-btn-mini { font-size: 11px; padding: 2px 9px; border: none; border-radius: 999px; cursor: pointer; color: var(--dsw-alias-label-primary-inverted, #fff); font-weight: 600; white-space: nowrap; }\n[data-edrv-view] .edrv-btn-keep { background: var(--dsw-alias-state-success-primary, #2e9e44); }\n[data-edrv-view] .edrv-btn-undo { background: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-btn-mini:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-statusbar { display: flex; align-items: center; gap: 10px; padding: 3px 10px; border-top: 1px solid var(--dsw-alias-border-l1, #333); background: var(--dsw-alias-bg-layer-1, transparent); font-size: 11px; color: var(--dsw-alias-label-tertiary, #888); flex-shrink: 0; white-space: nowrap; overflow: hidden; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-path { flex: 1; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-lsp { flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-progress-message { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-statusbar .edrv-sp-progress { flex: 0 0 auto; min-width: 36px; text-align: right; font-variant-numeric: tabular-nums; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-lsp-status-dot { width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto; background: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-lsp-status-dot.ready { background: var(--dsw-alias-state-success-primary, #0f9d58); }\n[data-edrv-view] .edrv-lsp-status-dot.busy { background: var(--dsw-alias-state-warn-primary, #d97706); animation: edrv-lsp-pulse 1.2s ease-in-out infinite; }\n@keyframes edrv-lsp-pulse { 50% { opacity: .45; } }\n/* Ctrl+hover 可导航标识符下划线提示(绑定 Monaco inlineClassName 装饰) */\n[data-edrv-view] .edrv-nav-underline { text-decoration: underline; text-decoration-color: var(--dsw-alias-interactive-primary, #4fc1ff); text-underline-offset: 1px; cursor: pointer; }\n/* 跳转目标区域高亮(LSP 定义/引用、搜索命中落点):落点一眼可见,约 1.2s 后由 EditorView 自动清除。\n 用官方令牌并带回落值,不在插件作用域重定义 --dsw-* (否则永久脱离官方主题)。 */\n[data-edrv-view] .edrv-nav-target { background: var(--dsw-alias-interactive-bg-hover, rgba(79,193,255,.28)); border-radius: 2px; box-shadow: 0 0 0 1px var(--dsw-alias-interactive-primary, rgba(79,193,255,.55)); }\n[data-edrv-view] .edrv-diffchip { font-size: 11px; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #333); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-state-warn-primary, #b7791f); cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn { font-size: 12px; padding: 2px 6px; border: none; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; border-radius: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-chip-btn:disabled { opacity: .35; cursor: default; }\n[data-edrv-view] .edrv-chip-btn:disabled:hover { background: transparent; }\n[data-edrv-view] .edrv-mn-add-line { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.10)); }\n[data-edrv-view] .edrv-mn-gutter-add { color: var(--dsw-alias-state-success-primary, #0f9d58) !important; font-weight: 700; display: flex !important; align-items: center; justify-content: center; }\n[data-edrv-view] .edrv-mn-gutter-add::before { content: \"+\"; }\n[data-edrv-view] .edrv-del-zone { background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.14)); border-top: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.35)); border-bottom: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.35)); box-shadow: inset 0 0 0 1px var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); }\n[data-edrv-view] .edrv-del-row { white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 12.5px; line-height: 20px; color: var(--dsw-alias-state-error-primary, #c0392b); }\n[data-edrv-view] .edrv-del-text { display: inline-block; white-space: pre; }\n[data-edrv-view] .edrv-minus-overlay { position: absolute; left: 0; top: 0; width: 100%; height: 100%; max-width: 100%; overflow: visible; pointer-events: none; z-index: 6; }\n[data-edrv-view] .edrv-minus-item { position: absolute; box-sizing: border-box; max-width: 100%; overflow: hidden; }\n[data-edrv-view] .edrv-minus-item::before { content: ''; position: absolute; left: 4px; top: 50%; width: 8px; height: 2px; transform: translateY(-50%); border-radius: 2px; background: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-monaco-host { flex: 1 1 auto; min-width: 0; min-height: 0; position: relative; overflow: hidden; }\n[data-edrv-view] .edrv-monaco-host > div { position: absolute; inset: 0; min-width: 0; min-height: 0; }\n[data-edrv-view] .edrv-imgview { flex: 1 1 auto; min-width: 0; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }\n[data-edrv-view] .edrv-imgview-bar { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px; flex-shrink: 0; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, transparent); }\n[data-edrv-view] .edrv-imgview-meta { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; }\n/* 图片预览:居中交给子项 margin:auto(auto 外边距优先吃正向空闲空间;溢出时空闲为负 → 外边距归 0、\n flex-start 起点对齐 → 放大后四边均可滚动到达,规避 justify-content:center 双侧溢出不可达问题) */\n[data-edrv-view] .edrv-imgview-stage { flex: 1 1 auto; min-height: 0; display: flex; overflow: auto; padding: 14px; background-color: var(--dsw-alias-bg-layer-1, #f0f4f4); background-image: conic-gradient(rgba(128,128,128,.14) 25%, transparent 0 50%, rgba(128,128,128,.14) 0 75%, transparent 0); background-size: 16px 16px; }\n[data-edrv-view] .edrv-imgview-img { max-width: 100%; max-height: 100%; flex-shrink: 0; margin: auto; align-self: flex-start; object-fit: contain; border-radius: 4px; box-shadow: 0 2px 12px rgba(31,41,51,.18); }\n[data-edrv-view] .edrv-imgview-broken { display: flex; flex-direction: column; align-items: center; gap: 10px; font-size: 13px; color: var(--dsw-alias-label-tertiary, #777); margin: auto; }\n[data-edrv-view] .edrv-pdf-host { flex: 1 1 auto; min-width: 0; min-height: 0; position: relative; overflow: hidden; }\n[data-edrv-view] .edrv-pdf-host > .edrv-pdf { position: absolute; inset: 0; }\n[data-edrv-view] .edrv-pdf { min-width: 0; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }\n[data-edrv-view] .edrv-pdf-bar { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px; flex-shrink: 0; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, transparent); }\n[data-edrv-view] .edrv-pdf-page { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; min-width: 52px; text-align: center; }\n[data-edrv-view] .edrv-pdf-zoom { min-width: 26px; text-align: center; padding: 3px 7px; }\n[data-edrv-view] .edrv-pdf-sep { width: 1px; height: 16px; background: var(--dsw-alias-border-l1, #e0e6e8); margin: 0 2px; }\n[data-edrv-view] .edrv-pdf-mode-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-brand-primary, #0f9d58); border-color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-pdf-dirty { color: var(--dsw-alias-state-warn-primary, #d97706); border-color: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-pdf-stage { position: absolute; top: 34px; left: 0; right: 0; bottom: 0; overflow: auto; }\n/* Markdown 预览(需求 4):工具条 + 居中阅读栏;正文排版由官方 MarkdownText 自带的 --dsw-* 样式负责 */\n[data-edrv-view] .edrv-mdview { flex: 1 1 auto; min-width: 0; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }\n[data-edrv-view] .edrv-mdview-bar { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px; flex-shrink: 0; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, transparent); }\n[data-edrv-view] .edrv-mdview-meta { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; }\n[data-edrv-view] .edrv-mdview-stage { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 14px 20px 28px; }\n[data-edrv-view] .edrv-mdview-doc { max-width: 880px; margin: 0 auto; width: 100%; }\n[data-edrv-view] .edrv-mdview-fallback { font-size: 12px; line-height: 1.7; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-mdview-pre { margin: 8px 0 0; padding: 10px 12px; border-radius: 8px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-primary, #1f2933); font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; line-height: 1.6; white-space: pre-wrap; word-break: break-word; }\n[data-edrv-view] .edrv-pb-mdbtn { height: 20px; padding: 0 8px; font-size: 11px; flex-shrink: 0; }\n[data-edrv-view] .edrv-pdf-stage .edrv-pdf-viewer { margin: 0 auto; }\n[data-edrv-view] .edrv-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; height: 100%; color: var(--dsw-alias-label-tertiary, #777); font-size: 13px; }\n[data-edrv-view] .edrv-diffbar { position: absolute; left: 0; right: 0; bottom: 10px; margin: 0 auto; z-index: 25; width: fit-content; max-width: calc(100% - 20px); border-radius: 12px; background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, #f0f4f4)); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); box-shadow: none; overflow: visible; display: flex; flex-direction: column; }\n[data-edrv-view] .edrv-editor-area > .edrv-diffbar { max-height: calc(100% - 20px); }\n[data-edrv-view] .edrv-diffbar-row { display: flex; align-items: center; gap: 6px; height: 36px; padding: 4px 5px 4px 12px; flex-wrap: nowrap; }\n[data-edrv-view] .edrv-diffbar-count { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); min-width: 42px; text-align: center; white-space: nowrap; cursor: pointer; }\n[data-edrv-view] .edrv-diffbar-count.edrv-count-file { min-width: 64px; cursor: default; }\n[data-edrv-view] .edrv-diffbar-file { flex: 1; min-width: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-pill { font-size: 11px; padding: 3px 10px; border: none; border-radius: 999px; cursor: pointer; white-space: nowrap; font-weight: 600; }\n[data-edrv-view] .edrv-pill-keep { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-state-success-primary, #0f7a45); border: 1px solid var(--dsw-alias-state-success-primary, rgba(15,157,88,.4)); }\n[data-edrv-view] .edrv-pill-undo { background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.14)); color: var(--dsw-alias-state-error-primary, #c0392b); border: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); }\n[data-edrv-view] .edrv-pill-ghost { background: var(--dsw-alias-bg-layer-1, #ffffff); color: var(--dsw-alias-label-secondary, #52606d); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-pill:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-diffbar-menu { position: absolute; right: 8px; bottom: calc(100% + 6px); z-index: 45; min-width: 160px; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 6px 20px rgba(31,41,51,.16); padding: 4px; display: flex; flex-direction: column; gap: 2px; }\n[data-edrv-view] .edrv-diffmenu-item { display: flex; align-items: center; gap: 8px; font-size: 12px; padding: 6px 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; text-align: left; }\n[data-edrv-view] .edrv-diffmenu-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-diffmenu-item.danger { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-diffmenu-sep { height: 1px; margin: 2px 4px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n/* 编辑区 / Tab 右键菜单(页签右键菜单 + 文件树右键菜单共用)。\n 页签菜单 11 条 + 键位提示,故限高可滚(ContextMenu 以实测尺寸做 viewport clamp)。\n ⚠️ z-index 71 在既有浮层阶梯内(见文件末尾命令栏注释),不得上调越过命令栏/片段浮窗。 */\n[data-edrv-view] .edrv-ctxmenu { position: fixed; z-index: 71; min-width: 220px; max-width: 360px; max-height: min(70vh, 520px); overflow-y: auto; 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/* 菜单项文案(弹性占宽,超出省略)与右侧键位提示(不缩放,等宽字体) */\n[data-edrv-view] .edrv-ctxmenu-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-ctxmenu-hint { flex: 0 0 auto; padding-left: 18px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; }\n[data-edrv-view] .edrv-ctxmenu-item:disabled .edrv-ctxmenu-hint,\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-disabled .edrv-ctxmenu-hint { color: var(--dsw-alias-label-disabled, #b0b7c0); }\n[data-edrv-view] .edrv-diffbar-body { max-height: 130px; max-width: min(560px, calc(100vw - 40px)); overflow: auto; padding: 4px 8px 8px; display: flex; flex-direction: column; gap: 4px; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-diffrow { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); cursor: pointer; flex-wrap: wrap; }\n[data-edrv-view] .edrv-diffrow:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-diffrow-l { font-size: 11px; color: var(--dsw-alias-label-primary, #1f2933); min-width: 74px; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-o { font-size: 11px; color: var(--dsw-alias-state-error-primary, #d9534f); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-n { font-size: 11px; color: var(--dsw-alias-state-success-primary, #0f9d58); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-tag { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-diffrow-stale { border-color: var(--dsw-alias-state-warn-primary, rgba(217,119,6,.5)); cursor: default; }\n[data-edrv-view] .edrv-diffbox-others { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; padding: 4px 2px 0; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); margin-top: 2px; }\n[data-edrv-view] .edrv-diffrow-file { font-size: 11px; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); cursor: pointer; white-space: nowrap; max-width: 200px; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-diffrow-file:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n/* 编辑区 hover 差异块的 Keep/Undo 浮层 */\n[data-edrv-view] .edrv-hoveract { position: absolute; z-index: 30; display: flex; align-items: center; gap: 4px; padding: 2px 6px; border-radius: 8px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 4px 14px rgba(31,41,51,.14); }\n[data-edrv-view] .edrv-launch { position: absolute; left: 12px; right: 12px; bottom: 12px; z-index: 40; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); box-shadow: 0 6px 24px rgba(0,0,0,.5); display: flex; flex-direction: column; max-height: 60%; overflow: hidden; }\n[data-edrv-view] .edrv-launch-head { display: flex; align-items: center; gap: 6px; padding: 6px 8px; border-bottom: 1px solid var(--dsw-alias-border-l1, #333); }\n[data-edrv-view] .edrv-launch-tab { font-size: 12px; padding: 3px 12px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; }\n[data-edrv-view] .edrv-launch-tab.on { background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-label-primary, #eee); font-weight: 600; }\n[data-edrv-view] .edrv-launch-body { flex: 1; min-height: 0; overflow: auto; padding: 6px 8px; display: flex; flex-direction: column; gap: 4px; }\n[data-edrv-view] .edrv-launch-row { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1, #333); border-radius: 6px; cursor: pointer; flex-wrap: wrap; }\n[data-edrv-view] .edrv-launch-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-launch-path { flex: 1; min-width: 0; font-size: 12px; color: var(--dsw-alias-label-primary, #eee); word-break: break-all; }\n[data-edrv-view] .edrv-launch-cnt { font-size: 11px; color: var(--dsw-alias-label-tertiary, #888); white-space: nowrap; }\n[data-edrv-view] .edrv-launch-arch { display: flex; flex-direction: column; gap: 6px; }\n[data-edrv-view] .monaco-editor { overflow: hidden !important; }\n[data-edrv-view] .monaco-editor .sticky-widget { z-index: 30 !important; background: var(--dsw-alias-bg-base, #f8f8f8) !important; }\n[data-edrv-view] .monaco-editor .sticky-widget .sticky-line-content,\n[data-edrv-view] .monaco-editor .sticky-widget .sticky-line-number { background: var(--dsw-alias-bg-base, #f8f8f8) !important; }\n[data-edrv-view] .monaco-editor, [data-edrv-view] .monaco-editor .margin, [data-edrv-view] .monaco-editor-background { background: transparent !important; }\n[data-edrv-view] .monaco-editor .scrollbar .slider { background: rgba(128,128,128,.3) !important; }\n[data-edrv-view] .edrv-loading { gap: 8px; padding: 20px; }\n[data-edrv-view] .edrv-loading-title { color: var(--dsw-alias-label-primary, #1f2933); font-size: 13px; }\n[data-edrv-view] .edrv-progress { width: min(360px, 72%); height: 6px; overflow: hidden; border-radius: 999px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-progress-value { height: 100%; border-radius: inherit; background: var(--dsw-alias-brand-primary, #0f9d58); transition: width .24s ease; }\n[data-edrv-view] .edrv-loading-percent { color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; font-variant-numeric: tabular-nums; }\n@media (prefers-reduced-motion: reduce) {\n [data-edrv-view] .edrv-progress-value { transition: none; }\n}\n\n/* ===== 唯一会话级差异 dock(遵循 DSH todo/queue 原生布局) ===== */\n[data-edrv-diff-dock-shell] {\n box-sizing: border-box;\n width: calc(100% - var(--dsh-composer-side-clearance) - var(--dsh-composer-side-clearance) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));\n max-width: calc(var(--dsh-composer-card-max-width) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));\n margin: 0 auto;\n padding: 0;\n flex: none;\n border: 1px solid var(--dsw-alias-border-l1, #e0e6e8);\n border-radius: 12px;\n background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, transparent));\n box-shadow: none;\n overflow: hidden;\n}\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock {\n box-sizing: border-box;\n position: relative;\n left: auto;\n right: auto;\n bottom: auto;\n z-index: auto;\n width: 100%;\n max-width: none;\n margin: 0;\n display: flex;\n flex-direction: column;\n border: none;\n border-radius: 0;\n background: transparent;\n box-shadow: none;\n overflow: visible;\n}\n[data-edrv-diff-dock-shell] .edrv-diffbar-row { min-height: 36px; padding: 6px 12px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-row { min-height: 36px; padding: 6px 12px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-body { max-height: 180px; overflow: auto; padding: 6px 12px 10px; border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-button { box-sizing: border-box; display: flex; align-items: center; justify-content: center; width: 100%; height: 24px; border: none; border-radius: 8px; padding: 0 12px; background: transparent; color: var(--dsw-alias-label-primary); font-size: 13px; font-weight: 500; line-height: 24px; text-align: center; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-button:hover { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diffbar-count { display: inline-flex; align-items: center; color: var(--dsw-alias-label-primary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 500; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-file { display: inline-flex; align-items: center; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-editor-row { display: flex; align-items: center; height: 36px; min-height: 36px; padding: 4px 12px; overflow-x: auto; scrollbar-width: thin; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-editor-content { display: flex; align-items: center; gap: 10px; width: 100%; min-width: max-content; min-height: 28px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-nav,\n[data-edrv-diff-dock-shell] .edrv-diffbar-files,\n[data-edrv-diff-dock-shell] .edrv-diffbar-actions { display: flex; align-items: center; gap: 6px; flex: none; height: 28px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-actions { margin-left: auto; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-details-toggle { display: inline-flex; align-items: center; justify-content: center; width: 28px; min-width: 28px; padding: 0; font-size: 13px; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-details-toggle svg { width: 14px; height: 14px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-files { min-width: 0; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-files .edrv-diffbar-file { min-width: 72px; max-width: 240px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-progress { min-width: 0; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; font-variant-numeric: tabular-nums; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-summary { min-width: 0; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-pill { box-sizing: border-box; height: 28px; padding: 0 9px; border: none; border-radius: 999px; cursor: pointer; white-space: nowrap; font-size: 11px; line-height: 26px; font-weight: 600; }\n[data-edrv-diff-dock-shell] .edrv-pill-keep { background: var(--dsw-alias-state-success-tertiary); color: var(--dsw-alias-state-success-primary); border: 1px solid var(--dsw-alias-state-success-secondary); }\n[data-edrv-diff-dock-shell] .edrv-pill-undo { background: var(--dsw-alias-state-error-tertiary); color: var(--dsw-alias-state-error-primary); border: 1px solid var(--dsw-alias-state-error-secondary); }\n[data-edrv-diff-dock-shell] .edrv-pill-ghost { background: transparent; color: var(--dsw-alias-label-secondary); border: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-pill:hover:not(:disabled) { background-color: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-pill:focus-visible { outline: 2px solid var(--dsw-alias-label-tertiary); outline-offset: -2px; }\n[data-edrv-diff-dock-shell] .edrv-pill:disabled { opacity: .45; cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diffrow { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; background: transparent; cursor: pointer; flex-wrap: wrap; }\n[data-edrv-diff-dock-shell] .edrv-diffrow:hover { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-l { color: var(--dsw-alias-label-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-o { color: var(--dsw-alias-state-error-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-n { color: var(--dsw-alias-state-success-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-tag { color: var(--dsw-alias-label-tertiary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-stale { border-color: var(--dsw-alias-state-warn-secondary); cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diffbox-others { border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-file { border-color: var(--dsw-alias-border-l1); background: transparent; color: var(--dsw-alias-label-secondary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-file:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }\n[data-edrv-diff-dock-shell] .edrv-diff-details { display: flex; flex-direction: column; gap: 2px; padding: 6px 12px 8px; border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item { display: flex; align-items: center; width: 100%; min-height: 28px; gap: 8px; padding: 4px 8px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary); cursor: pointer; text-align: left; font-size: 12px; line-height: 20px; }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item.danger { color: var(--dsw-alias-state-error-primary); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item:disabled { opacity: .45; cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-sep { height: 1px; margin: 2px 4px; background: var(--dsw-alias-border-l1); }\n@media (max-width: 620px) {\n [data-edrv-diff-dock-shell] .edrv-diffbar-editor-content { width: max-content; }\n [data-edrv-diff-dock-shell] .edrv-diffbar-files .edrv-diffbar-file { max-width: 160px; }\n}\n\n/* ===== 侧边栏(活动栏 + 面板区 + 文件树) ===== */\n[data-edrv-view] .edrv-editor-row { display: flex; flex: 1 1 auto; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-main-col { box-sizing: border-box; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-main-col > .edrv-pathbar,\n[data-edrv-view] .edrv-main-col > .edrv-tabs { flex: 0 0 auto; }\n[data-edrv-view] .edrv-editor-area { position: relative; display: flex; flex: 1 1 auto; flex-direction: column; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-sidebar { display: flex; flex-direction: row; flex-shrink: 1; min-width: 0; height: 100%; background: var(--dsw-alias-bg-layer-1, #ffffff); border-right: 1px solid var(--dsw-alias-border-l1, #e0e6e8); overflow: hidden; }\n[data-edrv-view] .edrv-rail { display: flex; flex-direction: column; align-items: center; width: 44px; flex-shrink: 0; padding: 6px 0; background: var(--dsw-alias-bg-layer-2, #f0f4f4); border-right: 1px solid var(--dsw-alias-border-l1, #e0e6e8); gap: 4px; }\n[data-edrv-view] .edrv-rail-btn { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border: none; border-radius: 8px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-rail-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rail-btn.edrv-rail-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-label-primary, #1f2933); box-shadow: inset 2px 0 0 var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-rail-icon { font-size: 15px; line-height: 1; display: inline-flex; align-items: center; justify-content: center; }\n/* 树行图标:官方原语(文件夹/文件类型),尺寸与行高对齐 @author ddj 2026-09-10 */\n[data-edrv-view] .edrv-tree-icon { flex-shrink: 0; display: inline-flex; align-items: center; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-active .edrv-tree-icon { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-rail-badge { position: absolute; top: 2px; right: 2px; min-width: 14px; height: 14px; padding: 0 3px; border-radius: 999px; background: var(--dsw-alias-brand-primary, #0f9d58); color: var(--dsw-alias-label-primary-inverted, #fff); font-size: 9px; font-weight: 600; line-height: 14px; text-align: center; box-sizing: border-box; }\n[data-edrv-view] .edrv-side-body { flex: 1; min-width: 0; min-height: 0; display: flex; overflow: hidden; }\n[data-edrv-view] .edrv-side-panel { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; position: relative; }\n[data-edrv-view] .edrv-side-head { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px 0 12px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); flex-shrink: 0; }\n[data-edrv-view] .edrv-side-title { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-side-root { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-side-btn { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-side-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-tree { flex: 1; min-height: 0; overflow: auto; padding: 4px 6px 12px; font-size: 12px; }\n[data-edrv-view] .edrv-tree-row { display: flex; align-items: center; gap: 4px; height: 22px; padding-right: 6px; border-radius: 5px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-tree-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-active { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-context { box-shadow: inset 0 0 0 1px var(--dsw-alias-brand-primary, #0f9d58); background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); }\n/* 「在资源管理器视图中显示」的定位高亮(短时淡出,区别于常驻的 active 态) */\n[data-edrv-view] .edrv-tree-row.edrv-tree-reveal { box-shadow: inset 0 0 0 1px var(--dsw-alias-brand-primary, #0f9d58); background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.18)); animation: edrv-tree-reveal-fade 2s ease-out; }\n@keyframes edrv-tree-reveal-fade { from { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.32)); } to { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.18)); } }\n[data-edrv-view] .edrv-tree-chev { width: 12px; flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; text-align: center; }\n[data-edrv-view] .edrv-tree-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-tree-name.edrv-tree-dim { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-tree-badge { min-width: 14px; height: 14px; padding: 0 4px; border-radius: 999px; background: var(--dsw-alias-state-warn-primary, #d97706); color: var(--dsw-alias-label-primary-inverted, #fff); font-size: 9px; font-weight: 600; line-height: 14px; text-align: center; box-sizing: border-box; flex-shrink: 0; }\n[data-edrv-view] .edrv-tree-loading { height: 22px; line-height: 22px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-tree-error { display: flex; align-items: center; gap: 8px; margin: 4px 2px 6px; padding: 6px 8px; border: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n/* 大纲面板:kind 字形 / detail / 行号 */\n[data-edrv-view] .edrv-outline-kind { display: inline-flex; align-items: center; justify-content: center; width: 14px; flex-shrink: 0; font-size: 12px; font-weight: 600; text-align: center; }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-func { color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-type { color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-data { color: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-ns { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-key { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-outline-detail { flex-shrink: 0; max-width: 40%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-outline-ln { flex-shrink: 0; padding-right: 2px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-side-resize { width: 5px; flex-shrink: 0; cursor: col-resize; background: transparent; }\n[data-edrv-view] .edrv-side-resize:hover { background: var(--dsw-alias-brand-primary, #0f9d58); opacity: .35; }\n[data-edrv-view] .edrv-chip-btn.edrv-chip-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-label-primary, #1f2933); }\n\n/* ===== SVN 变更面板(工作副本状态列表;颜色分级对齐 TortoiseSVN 口径) @author ddj 2026-09-16 ===== */\n[data-edrv-view] .edrv-svn-toolbar { display: flex; align-items: center; gap: 12px; padding: 4px 10px 6px 12px; flex-shrink: 0; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-svn-check { display: inline-flex; align-items: center; gap: 4px; cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-svn-check input { margin: 0; cursor: pointer; }\n[data-edrv-view] .edrv-svn-bulk { display: flex; align-items: center; gap: 6px; padding: 0 10px 6px 12px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svn-count { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svn-list { flex: 1; min-height: 0; overflow: auto; padding: 2px 6px 12px; font-size: 12px; }\n[data-edrv-view] .edrv-svn-group { display: flex; align-items: center; gap: 6px; height: 22px; padding: 0 6px; margin: 2px 0; border-radius: 5px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); font-size: 10px; font-weight: 600; }\n[data-edrv-view] .edrv-svn-group-n { margin-left: auto; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-weight: 400; }\n[data-edrv-view] .edrv-svn-row { display: flex; align-items: center; gap: 6px; height: 22px; padding: 0 6px; border-radius: 5px; cursor: default; white-space: nowrap; }\n[data-edrv-view] .edrv-svn-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-svn-path { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svn-acts { display: none; align-items: center; gap: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svn-row:hover .edrv-svn-acts { display: inline-flex; }\n[data-edrv-view] .edrv-svn-act { border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 5px; padding: 1px 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-secondary, #52606d); font-size: 10px; line-height: 14px; cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-svn-act:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svn-act:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-svn-act-danger { color: var(--dsw-alias-state-error-primary, #d9534f); border-color: var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); }\n[data-edrv-view] .edrv-svn-ch { display: inline-flex; align-items: center; justify-content: center; width: 14px; flex-shrink: 0; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; font-weight: 700; }\n[data-edrv-view] .edrv-svn-ch-modified { color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svn-ch-added { color: var(--dsw-alias-state-warn-primary, #7c3aed); }\n[data-edrv-view] .edrv-svn-ch-deleted { color: var(--dsw-alias-label-secondary, #b91c1c); }\n[data-edrv-view] .edrv-svn-ch-conflict { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-svn-ch-plain { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n/* 文件树行尾 SVN 状态徽标(与差异角标并列;方形字母,区别圆形差异计数) */\n[data-edrv-view] .edrv-tree-svn { min-width: 14px; height: 14px; padding: 0 4px; border-radius: 4px; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 9px; font-weight: 700; line-height: 14px; text-align: center; box-sizing: border-box; flex-shrink: 0; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-tree-svn.edrv-svn-ch-modified { color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-tree-svn.edrv-svn-ch-added { color: var(--dsw-alias-state-warn-primary, #7c3aed); }\n[data-edrv-view] .edrv-tree-svn.edrv-svn-ch-deleted { color: var(--dsw-alias-label-secondary, #b91c1c); }\n[data-edrv-view] .edrv-tree-svn.edrv-svn-ch-conflict { color: var(--dsw-alias-state-error-primary, #d9534f); }\n/* ===== SVN 基线差异视图(BASE 左 / 工作区右,只读并排) @author ddj 2026-09-16 ===== */\n[data-edrv-view] .edrv-svndiff { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-svndiff-bar { display: flex; align-items: center; gap: 8px; height: 30px; padding: 0 10px; flex-shrink: 0; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-svndiff-title { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-svndiff-tag { padding: 1px 6px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svndiff-host { flex: 1 1 auto; min-height: 0; }\n[data-edrv-view] .edrv-svndiff-empty { display: flex; flex: 1 1 auto; align-items: center; justify-content: center; padding: 24px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 12px; text-align: center; }\n/* 差异整行色块与行首 +/- 指示符:vendored Monaco(diffEditorWidget2)静态 CSS 无\n .line-insert/.line-delete 背景规则,整行色块靠主题键 + 此处固定色兜底保证可见。\n 注意不要用 --dsw-alias-interactive-bg-hover 类 token:实测为 92% 透明中性色,肉眼不可见。\n 固定色取自研差异 UI 同色相(绿 #0f9d58 / 红 #d9534f),alpha 提到肉眼可辨。 */\n[data-edrv-view] .monaco-editor .line-insert { background: rgba(15, 157, 88, 0.18); }\n[data-edrv-view] .monaco-editor .line-delete { background: rgba(217, 83, 79, 0.16); }\n[data-edrv-view] .monaco-editor .gutter-insert { background: rgba(15, 157, 88, 0.35); }\n[data-edrv-view] .monaco-editor .gutter-delete { background: rgba(217, 83, 79, 0.35); }\n[data-edrv-view] .monaco-editor .insert-sign { color: var(--dsw-alias-state-success-primary, #0f9d58); }\n[data-edrv-view] .monaco-editor .delete-sign { color: var(--dsw-alias-state-error-primary, #d9534f); }\n/* 差异条快速跳转簇(对齐自研审查条 ↑ i/N ↓ 的形态) */\n[data-edrv-view] .edrv-svndiff-nav { display: flex; align-items: center; gap: 2px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svndiff-nav-count { min-width: 36px; text-align: center; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); }\n/* W1-3 差异统计徽标(+新增/修改 −删除/修改;色相与行块绿红一致) @author ddj 2026-09-20 */\n[data-edrv-view] .edrv-svndiff-stat { display: inline-flex; align-items: center; gap: 4px; flex-shrink: 0; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-svndiff-stat-add { color: var(--dsw-alias-state-success-primary, #0f9d58); }\n[data-edrv-view] .edrv-svndiff-stat-del { color: var(--dsw-alias-state-error-primary, #d9534f); }\n/* W1-1 差异视图选项条(右端开关组;复用 .edrv-svn-check 的 label 形态) */\n[data-edrv-view] .edrv-svndiff-opts { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }\n/* W1-2 变更面板名称过滤输入框(工具条行内,紧凑) @author ddj 2026-09-20 */\n[data-edrv-view] .edrv-svn-name-filter { width: 168px; padding: 1px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 5px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; line-height: 14px; }\n[data-edrv-view] .edrv-svn-name-filter:focus { outline: none; border-color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-svn-name-filter::placeholder { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n/* W2-3 远端更新提示条(工具条上方;warn = 失败降级) @author ddj 2026-09-20 */\n[data-edrv-view] .edrv-svn-hintbar { display: flex; align-items: center; gap: 6px; margin: 0 10px 4px 12px; padding: 3px 8px; border-radius: 5px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); font-size: 11px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svn-hintbar-warn { background: rgba(217, 83, 79, 0.12); color: var(--dsw-alias-state-error-primary, #d9534f); }\n/* W2-5 疑似改名标记(行内 ⇄;hover 见 tooltip) */\n[data-edrv-view] .edrv-svn-pair-mark { flex-shrink: 0; color: var(--dsw-alias-state-warn-primary, #7c3aed); font-size: 11px; cursor: help; }\n/* W2-1 补丁对话框 / W2-2 目录对比对话框 @author ddj 2026-09-20 */\n[data-edrv-view] .edrv-svn-patch-dialog { max-width: calc(100vw - 48px); }\n[data-edrv-view] .edrv-svn-patch-head { display: flex; align-items: center; gap: 8px; padding-bottom: 8px; }\n[data-edrv-view] .edrv-svn-patch-notes { display: flex; flex-direction: column; gap: 4px; padding-bottom: 6px; }\n[data-edrv-view] .edrv-svn-patch-warn { color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n[data-edrv-view] .edrv-svn-patch-pre { max-height: 46vh; overflow: auto; margin: 0 0 8px; padding: 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f7f9f9); color: var(--dsw-alias-label-primary, #1f2933); font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; line-height: 1.5; white-space: pre; user-select: text; }\n[data-edrv-view] .edrv-svn-patch-foot { display: flex; align-items: center; gap: 8px; }\n[data-edrv-view] .edrv-svn-sum-form { display: flex; align-items: center; gap: 10px; padding-bottom: 8px; }\n[data-edrv-view] .edrv-svn-sum-list { max-height: 44vh; overflow: auto; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; padding: 2px; margin-bottom: 8px; }\n[data-edrv-view] .edrv-svnlog-path-kind { flex-shrink: 0; padding: 0 5px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; }\n\n/* ===== 通用弹窗外壳(ModalShell)+ SVN 日志弹窗 @author ddj 2026-09-16 ===== */\n/* z-index 190:落在既有阶梯内(命令栏 200 > 片段二级 197 > 片段一级 195 > 190),\n 不遮挡命令栏;既有浮层数值不受影响(见 tests/overlayZOrder.test.ts)。 */\n[data-edrv-view] .edrv-modal-mask { position: fixed; inset: 0; z-index: 190; display: flex; align-items: center; justify-content: center; padding: 24px; box-sizing: border-box; background: var(--dsw-alias-bg-mask-drop, #000000aa); }\n[data-edrv-view] .edrv-svnlog-dialog { position: relative; display: flex; flex-direction: column; gap: 8px; }\n[data-edrv-view] .edrv-svnlog-head { display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; }\n[data-edrv-view] .edrv-svnlog-title { margin: 0; font-size: 15px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-svnlog-target { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-svnlog-filter { display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; }\n[data-edrv-view] .edrv-svnlog-field { flex: 0 0 auto; padding: 4px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-svnlog-search { min-width: 160px; flex: 1 1 220px; padding: 4px 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-svnlog-date { padding: 2px 4px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-svnlog-check { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); white-space: nowrap; cursor: pointer; }\n[data-edrv-view] .edrv-svnlog-error { padding: 4px 8px; border: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n/* P0-14 上中下三段全宽:body 纵向铺满弹窗(外框高度由拖拽受控) */\n[data-edrv-view] .edrv-svnlog-body { display: flex; flex-direction: column; gap: 6px; flex: 1 1 auto; min-height: 0; }\n/* 上段修订列表:列头行 + 单行五列(版本/动作/作者/日期/信息),列宽由 cell 类与 nth-child 对齐(P0-12/D30) */\n[data-edrv-view] .edrv-svnlog-list { flex: 0 0 auto; display: flex; flex-direction: column; overflow: auto; border: 2px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 8px; padding: 4px; }\n[data-edrv-view] .edrv-svnlog-cols { display: flex; align-items: center; gap: 6px; padding: 2px 6px; border-bottom: 2px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-secondary, #52606d); flex-shrink: 0; }\n[data-edrv-view] .edrv-svnlog-cols .edrv-svnlog-col:nth-child(1) { width: 52px; flex: none; }\n[data-edrv-view] .edrv-svnlog-cols .edrv-svnlog-col:nth-child(2) { width: 52px; flex: none; }\n[data-edrv-view] .edrv-svnlog-cols .edrv-svnlog-col:nth-child(3) { width: 88px; flex: none; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-svnlog-cols .edrv-svnlog-col:nth-child(4) { width: 82px; flex: none; }\n[data-edrv-view] .edrv-svnlog-cols .edrv-svnlog-col:nth-child(5) { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-svnlog-col-sortable { cursor: pointer; }\n[data-edrv-view] .edrv-svnlog-col-sortable:hover { color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svnlog-col-on { color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svnlog-sort-reset { flex: none; }\n[data-edrv-view] .edrv-svnlog-item { display: flex; align-items: center; gap: 6px; padding: 2px 6px; border-radius: 6px; cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-svnlog-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-svnlog-item.edrv-svnlog-item-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); }\n[data-edrv-view] .edrv-svnlog-item-copied .edrv-svnlog-cell-msg,\n[data-edrv-view] .edrv-svnlog-item-copied .edrv-svnlog-rev { color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svnlog-cell { overflow: hidden; text-overflow: ellipsis; font-size: 11px; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svnlog-cell-rev { width: 52px; flex: none; }\n[data-edrv-view] .edrv-svnlog-cell-act { width: 52px; flex: none; display: inline-flex; gap: 3px; }\n[data-edrv-view] .edrv-svnlog-cell-author { width: 88px; flex: none; }\n[data-edrv-view] .edrv-svnlog-cell-date { width: 82px; flex: none; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-cell-msg { flex: 1 1 auto; }\n[data-edrv-view] .edrv-svnlog-rev { font-family: var(--ds-font-family-code, ui-monospace, monospace); font-weight: 700; color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svnlog-badge { display: inline-flex; align-items: center; justify-content: center; width: 12px; height: 12px; border-radius: 3px; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 9px; font-weight: 700; }\n[data-edrv-view] .edrv-svnlog-badge-modified { color: var(--dsw-alias-brand-primary, #2563eb); background: rgba(37,99,235,.12); }\n[data-edrv-view] .edrv-svnlog-badge-added { color: var(--dsw-alias-state-warn-primary, #7c3aed); background: rgba(124,58,237,.12); }\n[data-edrv-view] .edrv-svnlog-badge-deleted { color: #b91c1c; background: rgba(185,28,28,.12); }\n[data-edrv-view] .edrv-svnlog-badge-plain { color: var(--dsw-alias-label-tertiary, #9aa5b1); background: var(--dsw-alias-bg-layer-2, #f0f4f4); }\n[data-edrv-view] .edrv-svnlog-more { padding: 6px 4px 2px; text-align: center; }\n/* P0-14 三段 pane 公共外观(上段列表自带 .edrv-svnlog-list 边框) */\n[data-edrv-view] .edrv-svnlog-pane { border: 2px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 8px; padding: 8px 10px; overflow: hidden; }\n[data-edrv-view] .edrv-svnlog-msgpane { flex: 0 0 auto; display: flex; flex-direction: column; }\n[data-edrv-view] .edrv-svnlog-pathspane { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }\n/* P0-13/P0-14:分段横向拖拽分隔条 + 变更路径独立滚动容器 */\n[data-edrv-view] .edrv-svnlog-hsplit { flex: 0 0 6px; cursor: row-resize; margin: 2px 0; border-radius: 3px; touch-action: none; }\n[data-edrv-view] .edrv-svnlog-hsplit:hover, [data-edrv-view] .edrv-svnlog-hsplit:active { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.28)); }\n[data-edrv-view] .edrv-svnlog-paths-wrap { flex: 1 1 auto; min-height: 0; overflow: auto; display: flex; flex-direction: column; }\n[data-edrv-view] .edrv-svnlog-meta { display: flex; align-items: center; gap: 10px; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); flex-wrap: wrap; }\n[data-edrv-view] .edrv-svnlog-date { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-msgpane pre.edrv-svnlog-body { margin: 6px 0 0; padding: 6px 8px; border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; line-height: 1.6; white-space: pre-wrap; word-break: break-word; overflow: auto; flex: 1 1 auto; min-height: 0; }\n/* P0-14 外框尺寸手柄(右缘调宽 / 底缘调高 / 右下角双向) */\n[data-edrv-view] .edrv-svnlog-grip { position: absolute; z-index: 2; touch-action: none; }\n[data-edrv-view] .edrv-svnlog-grip-r { top: 12px; bottom: 12px; right: 0; width: 8px; cursor: ew-resize; }\n[data-edrv-view] .edrv-svnlog-grip-b { left: 12px; right: 12px; bottom: 0; height: 8px; cursor: ns-resize; }\n[data-edrv-view] .edrv-svnlog-grip-c { right: 0; bottom: 0; width: 14px; height: 14px; cursor: nwse-resize; border-radius: 3px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); }\n[data-edrv-view] .edrv-svnlog-grip:hover, [data-edrv-view] .edrv-svnlog-grip:active { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.35)); }\n[data-edrv-view] .edrv-svnlog-paths-head { display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-secondary, #52606d); margin-bottom: 4px; }\n[data-edrv-view] .edrv-svnlog-hint { font-weight: 400; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-paths { display: flex; flex-direction: column; gap: 1px; }\n[data-edrv-view] .edrv-svnlog-path { display: flex; align-items: center; gap: 6px; height: 22px; padding: 0 6px; border-radius: 5px; cursor: default; white-space: nowrap; }\n[data-edrv-view] .edrv-svnlog-path:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-svnlog-path-dim .edrv-svnlog-pathtext,\n[data-edrv-view] .edrv-svnlog-path-dim .edrv-svnlog-copyfrom { opacity: .45; }\n[data-edrv-view] .edrv-svnlog-pathtext { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; font-size: 11px; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svnlog-copyfrom { flex: 0 1 160px; overflow: hidden; text-overflow: ellipsis; font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-svnlog-kind { font-size: 10px; padding: 0 5px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-acts { display: none; align-items: center; gap: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svnlog-path:hover .edrv-svnlog-acts { display: inline-flex; }\n[data-edrv-view] .edrv-svnlog-footwrap { display: flex; flex-direction: column; gap: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svnlog-foot { display: flex; align-items: center; gap: 10px; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-btns { display: flex; align-items: center; gap: 6px; }\n/* ===== SVN 日志统计窗(P1-10)@author ddj 2026-09-17 ===== */\n[data-edrv-view] .edrv-svnlog-stats { display: flex; flex-direction: column; max-height: 82vh; }\n[data-edrv-view] .edrv-svnlog-stats-head { display: flex; align-items: center; gap: 8px; padding: 12px 16px 0; }\n[data-edrv-view] .edrv-svnlog-stats-body { display: flex; flex-direction: column; gap: 14px; padding: 10px 16px 16px; overflow: auto; }\n[data-edrv-view] .edrv-svnlog-stat-line { display: flex; gap: 16px; flex-wrap: wrap; font-size: 12px; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svnlog-stat-block { display: flex; flex-direction: column; gap: 8px; }\n[data-edrv-view] .edrv-svnlog-stat-label { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svnlog-stat-duo { display: flex; gap: 18px; align-items: flex-start; flex-wrap: wrap; }\n[data-edrv-view] .edrv-svnlog-stat-hist { flex: 1 1 260px; display: flex; flex-direction: column; gap: 4px; min-width: 220px; }\n[data-edrv-view] .edrv-svnlog-stat-row { display: flex; align-items: center; gap: 8px; font-size: 11px; }\n[data-edrv-view] .edrv-svnlog-stat-name { width: 110px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-svnlog-stat-barwrap { flex: 1; height: 12px; border-radius: 6px; background: rgba(127,127,127,.15); overflow: hidden; }\n[data-edrv-view] .edrv-svnlog-stat-bar { display: block; height: 100%; border-radius: 6px; }\n[data-edrv-view] .edrv-svnlog-stat-count { width: 36px; text-align: right; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-svnlog-stat-pie { width: 120px; height: 120px; flex-shrink: 0; border-radius: 50%; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-svnlog-stat-days { display: flex; align-items: flex-end; gap: 2px; height: 120px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); overflow-x: auto; }\n[data-edrv-view] .edrv-svnlog-stat-day { flex: 1 0 6px; min-width: 6px; height: 100%; display: flex; flex-direction: column; justify-content: flex-end; }\n[data-edrv-view] .edrv-svnlog-stat-seg { display: block; width: 100%; }\n/* ===== SVN 日志区间弹窗(P1-6)@author ddj 2026-09-17 ===== */\n[data-edrv-view] .edrv-svnlog-range-body { display: flex; flex-direction: column; gap: 12px; padding: 14px 16px 16px; }\n[data-edrv-view] .edrv-svnlog-range-row { display: flex; gap: 14px; flex-wrap: wrap; }\n[data-edrv-view] .edrv-svnlog-range-input { width: 110px; padding: 4px 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-svnlog-range-btns { display: flex; gap: 8px; justify-content: flex-end; }\n/* SVN 日志 WC 版号行加粗(P1-9) */\n[data-edrv-view] .edrv-svnlog-item-wc { font-weight: 700; }\n/* SVN 日志 merged 行(P1-5):灰字 + 缩进(缩进量按层级内联),前置「↳」标记 */\n[data-edrv-view] .edrv-svnlog-item-merged { color: var(--dsw-alias-label-tertiary, #7b8794); }\n[data-edrv-view] .edrv-svnlog-item-merged .edrv-svnlog-merge-mark { flex: 0 0 auto; color: var(--dsw-alias-label-tertiary, #7b8794); }\n[data-edrv-view] .edrv-svnlog-item-merged .edrv-svnlog-cell-msg { font-style: italic; }\n/* ===== 诊断日志弹窗(LogDialog)@author ddj 2026-09-17 ===== */\n[data-edrv-view] .edrv-dlog-dialog { display: flex; flex-direction: column; gap: 8px; max-height: 88vh; }\n[data-edrv-view] .edrv-dlog-head { display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; }\n[data-edrv-view] .edrv-dlog-title { margin: 0; font-size: 15px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-dlog-file { max-width: 200px; padding: 4px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-dlog-level { padding: 4px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-dlog-search { min-width: 120px; flex: 0 1 200px; padding: 4px 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-dlog-auto { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); white-space: nowrap; cursor: pointer; }\n[data-edrv-view] .edrv-dlog-error { padding: 4px 8px; border: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n[data-edrv-view] .edrv-dlog-scroll { flex: 1 1 auto; min-height: 240px; overflow: auto; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 8px; padding: 4px 0; background: var(--dsw-alias-bg-layer-1, #fff); }\n[data-edrv-view] .edrv-dlog-row { display: flex; align-items: baseline; gap: 8px; padding: 1px 8px; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; line-height: 1.55; }\n[data-edrv-view] .edrv-dlog-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.06)); }\n[data-edrv-view] .edrv-dlog-at { flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-dlog-lvl { flex-shrink: 0; width: 26px; text-align: center; font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-dlog-text { flex: 1; min-width: 0; white-space: pre-wrap; word-break: break-word; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-dlog-row-error .edrv-dlog-text { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-dlog-row-warn .edrv-dlog-text { color: var(--dsw-alias-state-warning-primary, #b45309); }\n[data-edrv-view] .edrv-dlog-row-debug .edrv-dlog-text { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-dlog-foot { display: flex; align-items: center; gap: 10px; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex-shrink: 0; }\n[data-edrv-view] .edrv-dlog-path { font-family: var(--ds-font-family-code, ui-monospace, monospace); max-width: 46%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-dlog-stat { white-space: nowrap; }\n[data-edrv-view] .edrv-dlog-switch { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); white-space: nowrap; cursor: pointer; flex-shrink: 0; }\n/* SVN 更新结果条(P3:update 条目级明细,可关闭) */\n[data-edrv-view] .edrv-svnres { display: flex; align-items: flex-start; gap: 8px; flex-shrink: 0; padding: 5px 10px; font-size: 11px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, rgba(15,157,88,.06)); }\n[data-edrv-view] .edrv-svnres-head { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-svnres-list { display: flex; flex-wrap: wrap; gap: 4px 10px; min-width: 0; }\n[data-edrv-view] .edrv-svnres-item { display: inline-flex; align-items: center; gap: 3px; font-family: var(--ds-font-family-code, ui-monospace, monospace); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-svnres-item.edrv-svnres-conflict { color: var(--dsw-alias-state-error-primary, #d9534f); font-weight: 700; }\n\n/* ===== 侧栏形态(betterSidebar 面板内编辑区) ===== */\n[data-edrv-view][data-edrv-layout='side'] { box-sizing: border-box; height: 100%; }\n\n/* ===== 侧边栏引导条(旧页签形态、未装 betterSidebar 时) ===== */\n[data-edrv-view] .edrv-side-hint { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; flex-wrap: wrap; padding: 6px 12px; font-size: 12px; color: var(--dsw-alias-label-secondary, #52606d); background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, #f0f4f4)); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-side-hint-text { white-space: nowrap; }\n[data-edrv-view] .edrv-side-hint-cmd { font-size: 11px; padding: 2px 6px; border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #ffffff); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-side-hint-close { margin-left: auto; border: none; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); cursor: pointer; font-size: 14px; line-height: 1; padding: 2px 6px; border-radius: 6px; flex-shrink: 0; }\n[data-edrv-view] .edrv-side-hint-close:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n\n/* ===== search panel (sidebar, VSCode search view) ===== */\n[data-edrv-view] .edrv-search-panel { display: flex; flex-direction: column; min-height: 0; flex: 1; padding: 6px; gap: 4px; }\n[data-edrv-view] .edrv-search-qrow { display: flex; gap: 4px; }\n[data-edrv-view] .edrv-search-input { flex: 1; min-width: 0; height: 26px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search-input:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-opts { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-search-opt { min-width: 24px; height: 22px; padding: 0 6px; border: 1px solid transparent; border-radius: 5px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 11px; font-family: var(--ds-font-family-code, ui-monospace, monospace); cursor: pointer; }\n[data-edrv-view] .edrv-search-opt:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-opt.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); border-color: var(--dsw-alias-border-l2, #d5dde3); }\n[data-edrv-view] .edrv-search-spacer { flex: 1; }\n[data-edrv-view] .edrv-search-summary { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); padding: 2px 4px; }\n[data-edrv-view] .edrv-search-results { flex: 1; min-height: 0; overflow: auto; font-size: 12px; }\n[data-edrv-view] .edrv-search-group { margin-bottom: 2px; }\n[data-edrv-view] .edrv-search-file { display: flex; align-items: center; gap: 4px; height: 22px; padding: 0 4px; border-radius: 5px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-search-file:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-chev { width: 12px; flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; text-align: center; }\n[data-edrv-view] .edrv-search-fname { font-weight: 600; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-search-fdir { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-search-fcount { flex-shrink: 0; min-width: 16px; height: 15px; padding: 0 4px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); font-size: 10px; line-height: 15px; text-align: center; }\n[data-edrv-view] .edrv-search-line { display: flex; gap: 6px; padding: 1px 4px 1px 16px; border-radius: 4px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; overflow: hidden; }\n[data-edrv-view] .edrv-search-line.alt { background: var(--dsw-alias-bg-layer-1, #ffffff); }\n[data-edrv-view] .edrv-search-line:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-ln { flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; min-width: 26px; text-align: right; user-select: none; }\n[data-edrv-view] .edrv-search-text { overflow: hidden; text-overflow: ellipsis; white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; }\n[data-edrv-view] .edrv-search-hit { background: var(--dsw-alias-state-warn-primary, #e5b93f); color: var(--dsw-alias-label-primary-inverted, #1f2933); border-radius: 2px; padding: 0 1px; }\n[data-edrv-view] .edrv-search-empty { padding: 8px 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-search-error { padding: 6px 8px; border: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n[data-edrv-view] .edrv-search-warn { padding: 6px 8px; border: 1px solid var(--dsw-alias-state-warn-primary, rgba(240,173,78,.45)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover, rgba(240,173,78,.12)); color: var(--dsw-alias-state-warn-primary, #b8860b); font-size: 11px; word-break: break-all; }\n\n/* include/exclude filter rows (collapsible) */\n[data-edrv-view] .edrv-search-rows { display: flex; flex-direction: column; gap: 4px; padding: 2px 0 4px; }\n[data-edrv-view] .edrv-search-row { display: flex; align-items: center; gap: 4px; }\n[data-edrv-view] .edrv-search-field { flex: 1; min-width: 0; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 11px; outline: none; }\n[data-edrv-view] .edrv-search-field:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-field.dim { opacity: .45; }\n[data-edrv-view] .edrv-search-field::placeholder { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-search-toggle { min-width: 24px; height: 24px; padding: 0 5px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; line-height: 1; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-search-toggle:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-toggle.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); border-color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-search-toggle:disabled { opacity: .4; cursor: default; }\n\n/* ===== rules panel (sidebar, Codebuddy rules view) ===== */\n[data-edrv-view] .edrv-rules-panel { display: flex; flex-direction: column; min-width: 0; min-height: 0; flex: 1; padding: 6px; gap: 4px; }\n[data-edrv-view] .edrv-rules-tabs { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-tab { height: 24px; padding: 0 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; cursor: pointer; }\n[data-edrv-view] .edrv-rules-tab:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-tab.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); font-weight: 600; }\n[data-edrv-view] .edrv-rules-new { margin-left: auto; height: 24px; padding: 0 10px; border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-new:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-ws-line { font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); padding: 0 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 0 0 auto; user-select: none; }\n[data-edrv-view] .edrv-rules-hint { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); padding: 0 2px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-list { flex: 1; min-height: 0; overflow: auto; }\n[data-edrv-view] .edrv-rules-row { display: flex; align-items: center; gap: 4px; padding: 6px 4px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; }\n[data-edrv-view] .edrv-rules-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-row.off .edrv-rules-main { opacity: .5; }\n[data-edrv-view] .edrv-rules-main { flex: 1; min-width: 0; cursor: pointer; overflow: hidden; }\n[data-edrv-view] .edrv-rules-line1 { display: flex; align-items: center; gap: 6px; min-width: 0; }\n[data-edrv-view] .edrv-rules-sub { display: flex; align-items: center; gap: 5px; margin-top: 3px; min-width: 0; }\n[data-edrv-view] .edrv-rules-sublabel { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-file { font-weight: 600; font-size: 12px; color: var(--dsw-alias-label-primary, #1f2933); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-rules-path { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-rules-type { flex-shrink: 0; height: 15px; padding: 0 5px; border-radius: 999px; font-size: 10px; line-height: 15px; }\n[data-edrv-view] .edrv-rules-type-always { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.15)); color: var(--dsw-alias-state-success-primary, #0b7c46); }\n[data-edrv-view] .edrv-rules-type-auto { background: var(--dsw-alias-interactive-bg-hover-accent, rgba(79,140,255,.16)); color: var(--dsw-alias-link, #3367c9); }\n[data-edrv-view] .edrv-rules-type-manual { background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-rules-offtag { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-desc { font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; flex: 0 1 auto; }\n[data-edrv-view] .edrv-rules-actions { display: flex; align-items: center; gap: 2px; flex-shrink: 0; margin-left: auto; }\n[data-edrv-view] .edrv-rules-act { min-width: 22px; height: 22px; padding: 0 4px; border: none; border-radius: 5px; background: transparent; font-size: 12px; line-height: 1; cursor: pointer; color: var(--dsw-alias-label-secondary, #52606d); display: inline-flex; align-items: center; justify-content: center; }\n[data-edrv-view] .edrv-rules-act:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-switch { position: relative; width: 30px; height: 16px; border-radius: 999px; border: none; background: var(--dsw-alias-border-l2, #b9c4cc); cursor: pointer; transition: background .15s; flex-shrink: 0; padding: 0; }\n[data-edrv-view] .edrv-rules-switch.on { background: var(--dsw-alias-brand-primary, #7c5cff); }\n[data-edrv-view] .edrv-rules-knob { position: absolute; top: 2px; left: 2px; width: 12px; height: 12px; border-radius: 50%; background: var(--dsw-alias-bg-layer-1, #fff); transition: left .15s; }\n[data-edrv-view] .edrv-rules-switch.on .edrv-rules-knob { left: 16px; }\n[data-edrv-view] .edrv-rules-empty { padding: 10px 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); line-height: 1.6; }\n[data-edrv-view] .edrv-rules-err { padding: 6px 8px; border: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; word-break: break-all; }\n[data-edrv-view] .edrv-rules-editor { display: flex; flex-direction: column; min-height: 0; flex: 1; gap: 6px; }\n[data-edrv-view] .edrv-rules-editor-head { display: flex; align-items: center; justify-content: space-between; gap: 6px; font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-crumb { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-rules-editor-ctl { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-ctl-label { font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-select { height: 24px; padding: 0 4px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 11px; outline: none; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-select:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-rules-desc-input { flex: 1; min-width: 0; }\n[data-edrv-view] .edrv-rules-input { flex: 1; min-width: 0; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 11px; outline: none; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-rules-input:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-rules-body { flex: 1; min-height: 0; resize: none; padding: 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; line-height: 1.5; outline: none; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-rules-body:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-rules-editor-hint { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); line-height: 1.5; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-editor-foot { display: flex; justify-content: flex-end; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-save { height: 24px; padding: 0 14px; border: none; border-radius: 6px; background: var(--dsw-alias-brand-primary, #0f9d58); color: var(--dsw-alias-label-primary-inverted, #fff); font-size: 12px; cursor: pointer; }\n[data-edrv-view] .edrv-rules-save:disabled { opacity: .5; cursor: default; }\n\n/* 命令栏(Ctrl+Shift+P / F1):body 级 portal 浮层,故不依赖编辑区几何。\n ⚠️ 浮层 z-index 阶梯(自下而上;改动务必保持顺序,tests/overlayZOrder.test.ts 守约):\n 编辑器内浮层 60(.edrv-search-pop) / 71(.edrv-ctxmenu)\n < 190 命令栏遮罩 < 200 命令栏\n < 195 片段浮窗遮罩 < 197 片段二级弹窗遮罩\n 命令栏必须**高于**片段浮窗:曾因片段遮罩(192) 压过命令栏(191),导致片段浮窗打开时\n 命令栏被整体盖住,按 Ctrl+Shift+P 因「已打开即早退」而毫无反应(表现为快捷键失效)。 */\n[data-edrv-view] .edrv-palette-mask { position: fixed; inset: 0; z-index: 190; background: rgba(0, 0, 0, .28); }\n[data-edrv-view] .edrv-palette { position: fixed; top: 12vh; left: 50%; transform: translateX(-50%); z-index: 200; width: min(580px, calc(100vw - 32px)); max-height: 64vh; display: flex; flex-direction: column; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 12px 34px rgba(31, 41, 51, .24); overflow: hidden; }\n[data-edrv-view] .edrv-palette-input { height: 38px; flex: 0 0 auto; padding: 0 12px; border: none; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: transparent; color: var(--dsw-alias-label-primary, #1f2933); font-size: 13px; outline: none; }\n[data-edrv-view] .edrv-palette-list { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 4px; }\n[data-edrv-view] .edrv-palette-row { display: flex; align-items: center; gap: 8px; padding: 6px 10px; border-radius: 6px; font-size: 12px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; }\n[data-edrv-view] .edrv-palette-row.edrv-palette-sel { background: var(--dsw-alias-interactive-bg-hover, rgba(15, 157, 88, .10)); }\n[data-edrv-view] .edrv-palette-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-palette-cat { flex: 0 0 auto; font-size: 10px; padding: 1px 7px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-tertiary, #7b8794); }\n[data-edrv-view] .edrv-palette-key { flex: 0 0 auto; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 10px; padding: 1px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 5px; background: var(--dsw-alias-bg-layer-1, #f7f9fa); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-palette-empty { padding: 14px 10px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #7b8794); text-align: center; }\n[data-edrv-view] .edrv-palette-notice { flex: 0 0 auto; padding: 6px 10px; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 11px; color: var(--dsw-alias-state-warn-primary, #b7791f); }\n\n/* 代码片段选择器(配置 / 插入):居中浮窗 + 新建二级弹窗。\n 卡片复用 mcp.css 的 .vsm-mcp-dialog(与「添加 MCP」「工作区选择」同一视觉语言),\n 此处只补遮罩、尺寸与列表布局。⚠️ 根节点须带 data-edrv-view,否则这些规则全部失配。 */\n[data-edrv-view] .edrv-snip-mask { position: fixed; inset: 0; z-index: 195; display: flex; align-items: center; justify-content: center; padding: 24px; box-sizing: border-box; background: var(--dsw-alias-bg-mask-drop, rgba(0, 0, 0, .55)); }\n/* 二级弹窗叠在一级浮窗之上(仍在命令栏之下,见上方阶梯说明) */\n[data-edrv-view] .edrv-snip-mask-top { z-index: 197; }\n[data-edrv-view] .edrv-snip-dialog { display: flex; flex-direction: column; overflow: hidden; width: min(620px, calc(100vw - 48px)); }\n[data-edrv-view] .edrv-snip-hint { margin: 0 0 12px; font-size: 12px; line-height: 1.6; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-snip-list { display: flex; flex-direction: column; gap: 1px; min-height: 0; max-height: 46vh; overflow: auto; }\n[data-edrv-view] .edrv-snip-group { padding: 12px 2px 4px; font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-secondary, #aaa); }\n[data-edrv-view] .edrv-snip-row { display: flex; align-items: center; gap: 4px; width: 100%; box-sizing: border-box; padding: 2px; border: none; border-radius: 8px; background: transparent; text-align: left; color: var(--dsw-alias-label-primary, #e6e6e6); font: inherit; }\n[data-edrv-view] .edrv-snip-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255, 255, 255, .06)); }\n[data-edrv-view] button.edrv-snip-row { cursor: pointer; }\n[data-edrv-view] .edrv-snip-row-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; padding: 8px 10px; border: none; border-radius: 6px; background: transparent; text-align: left; cursor: pointer; color: inherit; font: inherit; }\n[data-edrv-view] .edrv-snip-label { font-size: 13px; font-weight: 600; color: var(--dsw-alias-label-primary, #e6e6e6); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-snip-desc { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-snip-src { flex: 0 0 auto; padding-right: 6px; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-snip-warn { flex: 0 0 auto; font-size: 11px; padding: 2px 7px; border-radius: 999px; background: var(--dsw-alias-state-warn-tertiary, rgba(229, 185, 63, .16)); color: var(--dsw-alias-state-warn-primary, #e5b93f); white-space: nowrap; }\n[data-edrv-view] .edrv-snip-act { flex: 0 0 auto; width: 26px; height: 26px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 13px; line-height: 1; cursor: pointer; }\n[data-edrv-view] .edrv-snip-act:hover { background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217, 83, 79, .16)); color: var(--dsw-alias-state-error-primary, #f07878); }\n[data-edrv-view] .edrv-snip-empty { padding: 12px 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); line-height: 1.6; }\n/* 当前文件语言提示条(片段按语言绑定,明确告知生效范围) */\n[data-edrv-view] .edrv-snip-langbar { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; margin: 0 0 10px; padding: 8px 10px; border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #2b2b2b); font-size: 12px; color: var(--dsw-alias-label-secondary, #aaa); }\n[data-edrv-view] .edrv-snip-langbar b { color: var(--dsw-alias-label-primary, #e6e6e6); }\n/* 二级弹窗的动作按钮(原生 .vsm-mcp-dialog-actions 已提供排版与按钮样式) */\n[data-edrv-view] .edrv-snip-dialog .vsm-mcp-dialog-actions { flex-wrap: wrap; }\n/* 删除图标按钮:.vsm-danger 的规则全部限定在 .vsm-mcp-actions button 之下,裸用无样式,此处补自有类 */\n[data-edrv-view] .edrv-snip-act.edrv-snip-danger:hover { background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217, 83, 79, .16)); color: var(--dsw-alias-state-error-primary, #f07878); }\n/* 浮窗内的原生空态(.vsm-mcp-empty 默认为整页尺寸)压缩为对话框尺寸 */\n[data-edrv-view] .edrv-snip-dialog .vsm-mcp-empty { padding: 26px 16px; border: 0; }\n\n\n\n\n\n/* 调试(DAP):断点圆点 / 停帧行 / 浮动调试工具条。\n 圆点挂在 Monaco glyphMargin(glyphMarginClassName),行背景为 isWholeLine className;\n 工具条绝对定位于编辑区右上(editorArea relative 由 .edrv-editor-area 自身定位)。 */\n/* 断点圆点:装饰类占满整行,圆点经 ::before 在本行盒子内居中(行归属明确、不跨行界) */\n[data-edrv-view] .edrv-dap-bp { cursor: pointer; }\n[data-edrv-view] .edrv-dap-bp::before { content: ''; display: block; width: 7px; height: 7px; margin: 6px auto 0; border-radius: 50%; background: var(--dsw-alias-state-error-primary, #e51400); }\n[data-edrv-view] .edrv-dap-bp-off { cursor: pointer; }\n[data-edrv-view] .edrv-dap-bp-off::before { content: ''; display: block; box-sizing: border-box; width: 7px; height: 7px; margin: 6px auto 0; border-radius: 50%; border: 1px solid var(--dsw-alias-label-tertiary, #9aa5b1); opacity: .6; }\n/* 未验证断点(适配器真实回执 verified:false):空心红圈,对齐 VS Code 空心圆语义 */\n[data-edrv-view] .edrv-dap-bp-unverified { cursor: pointer; }\n[data-edrv-view] .edrv-dap-bp-unverified::before { content: ''; display: block; box-sizing: border-box; width: 7px; height: 7px; margin: 6px auto 0; border-radius: 50%; border: 1px solid var(--dsw-alias-state-error-primary, #e51400); opacity: .75; }\n[data-edrv-view] .edrv-dap-paused-line { background: var(--dsw-alias-state-warn-tertiary, rgba(229, 185, 63, .22)); }\n[data-edrv-view] .edrv-dap-paused-glyph { cursor: pointer; }\n[data-edrv-view] .edrv-dap-paused-glyph::before { content: ''; display: block; width: 5px; height: 12px; margin: 4px auto 0; border-radius: 2px; background: var(--dsw-alias-state-warn-primary, #e5b93f); }\n[data-edrv-view] .edrv-editor-area { position: relative; }\n/* launch.json 右下角「添加配置」按钮(VSCode 同款形态):仅 launch.json 打开时渲染 */\n[data-edrv-view] .edrv-addcfg { position: absolute; right: 14px; bottom: 10px; z-index: 13; padding: 4px 12px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #f7f9fa); color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; line-height: 18px; cursor: pointer; box-shadow: 0 1px 4px rgba(0, 0, 0, .1); }\n[data-edrv-view] .edrv-addcfg:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .15)); color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-dapbar { position: absolute; top: 6px; right: 14px; z-index: 12; display: none; align-items: center; gap: 3px; padding: 3px 5px; border-radius: 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, #f7f9fa); box-shadow: 0 2px 8px rgba(0, 0, 0, .12); }\n[data-edrv-view] .edrv-dapbar.on { display: flex; border-color: var(--dsw-alias-border-l2, #cdd6da); }\n[data-edrv-view] .edrv-dapbar-grip { flex: 0 0 auto; width: 16px; height: 22px; display: inline-flex; align-items: center; justify-content: center; cursor: grab; user-select: none; color: var(--dsw-alias-label-tertiary, #7b8794); font-size: 12px; }\n[data-edrv-view] .edrv-dapbar-grip:active, [data-edrv-view] .edrv-dapbar.dragging .edrv-dapbar-grip { cursor: grabbing; }\n[data-edrv-view] .edrv-dapbar.dragging { user-select: none; }\n[data-edrv-view] .edrv-dapbar-cfg { max-width: 220px; height: 22px; font-size: 11px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); }\n[data-edrv-view] .edrv-dapbar-btn { min-width: 24px; height: 22px; padding: 0 6px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, inherit); font-size: 12px; line-height: 1; cursor: pointer; }\n[data-edrv-view] .edrv-dapbar-btn:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .15)); }\n[data-edrv-view] .edrv-dapbar-btn:disabled { opacity: .35; cursor: default; }\n[data-edrv-view] .edrv-dapbar-phase { padding: 0 4px; font-size: 11px; white-space: nowrap; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-dapbar-phase.paused { color: var(--dsw-alias-state-warn-primary, #b7791f); font-weight: 600; }\n[data-edrv-view] .edrv-dapbar-err { max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; color: var(--dsw-alias-state-error-primary, #e05252); }\n\n/* 调试面板(活动栏「调试」页签):四段折叠区 + 断点列表 + REPL。 */\n[data-edrv-view] .edrv-dappanel { display: flex; flex-direction: column; gap: 10px; height: 100%; min-height: 0; overflow: auto; padding: 2px 2px 8px; }\n[data-edrv-view] .edrv-dappanel-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; row-gap: 4px; font-size: 12px; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-dappanel-phase { padding: 2px 8px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); }\n[data-edrv-view] .edrv-dappanel-phase.paused { background: var(--dsw-alias-state-warn-tertiary, rgba(229, 185, 63, .18)); color: var(--dsw-alias-state-warn-primary, #b7791f); font-weight: 600; }\n[data-edrv-view] .edrv-dappanel-cfg { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-dappanel-pid { font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; }\n[data-edrv-view] .edrv-dappanel-err { color: var(--dsw-alias-state-error-primary, #e05252); }\n[data-edrv-view] .edrv-dapseg { display: flex; flex-direction: column; gap: 2px; min-height: 0; }\n[data-edrv-view] .edrv-dapseg-body { min-height: 0; overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain; }\n/* 段间分隔条(splitview sash):拖动调整相邻两段高度占比;各段高度由 DebugPanel 内联接管。 */\n[data-edrv-view] .edrv-dapseg-sash { flex: 0 0 auto; height: 4px; margin: 2px 0; border-radius: 2px; background: transparent; cursor: row-resize; }\n[data-edrv-view] .edrv-dapseg-sash:hover, [data-edrv-view] .edrv-dapseg-sash.dragging { background: var(--dsw-alias-border-l2, #cdd6da); }\n/* 折叠段头:chevron + 标题 + 悬浮动作区(动作 hover 显隐;REPL 头不参与折叠)。 */\n[data-edrv-view] .edrv-dapseg-head { display: flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-tertiary, #7b8794); padding: 2px 2px; cursor: pointer; border-radius: 4px; }\n[data-edrv-view] .edrv-dapseg-head:hover { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-daprepl .edrv-dapseg-head { cursor: default; padding: 2px 0; }\n[data-edrv-view] .edrv-dapseg-chevron { flex: 0 0 auto; width: 14px; text-align: center; font-size: 10px; }\n[data-edrv-view] .edrv-dapseg-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-dapseg-act { flex: 0 0 auto; min-width: 20px; height: 18px; padding: 0 4px; border: none; border-radius: 4px; background: transparent; color: var(--dsw-alias-label-tertiary, #7b8794); font-size: 11px; line-height: 1; cursor: pointer; opacity: 0; }\n[data-edrv-view] .edrv-dapseg-head:hover .edrv-dapseg-act { opacity: 1; }\n[data-edrv-view] .edrv-dapseg-act:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .15)); color: var(--dsw-alias-label-primary, inherit); }\n[data-edrv-view] .edrv-dapempty { font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); padding: 4px 2px; }\n[data-edrv-view] .edrv-dapframe { display: flex; align-items: baseline; gap: 8px; padding: 3px 4px; border-radius: 6px; cursor: pointer; font-size: 12px; }\n[data-edrv-view] .edrv-dapframe:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .12)); }\n[data-edrv-view] .edrv-dapframe-name { color: var(--dsw-alias-label-primary, inherit); font-weight: 600; }\n[data-edrv-view] .edrv-dapframe-loc { color: var(--dsw-alias-label-tertiary, #9aa5b1); font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-dapscope { font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-secondary, #52606d); padding: 4px 2px 1px; }\n[data-edrv-view] .edrv-dapvar { display: flex; align-items: baseline; gap: 6px; width: 100%; box-sizing: border-box; font-size: 12px; padding: 1px 2px; min-width: 0; }\n[data-edrv-view] .edrv-dapvar-tw { flex: 0 0 auto; width: 14px; border: none; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); cursor: pointer; font-size: 10px; padding: 0; }\n[data-edrv-view] span.edrv-dapvar-tw { cursor: default; }\n[data-edrv-view] .edrv-dapvar-name { flex: 0 1 34%; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-primary, inherit); font-family: var(--ds-font-family-code, ui-monospace, monospace); white-space: nowrap; }\n[data-edrv-view] .edrv-dapvar-val { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-dapvar-type { flex: 0 0 auto; font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-dapframe.selected { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .16)); outline: 1px solid var(--dsw-alias-border-l2, #cdd6da); }\n[data-edrv-view] .edrv-dapwatch { display: flex; align-items: baseline; gap: 6px; width: 100%; box-sizing: border-box; min-width: 0; font-size: 12px; padding: 1px 2px; }\n[data-edrv-view] .edrv-dapwatch-x { border: none; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); cursor: pointer; width: 14px; }\n[data-edrv-view] .edrv-dapwatch-x:hover { color: var(--dsw-alias-state-error-primary, #e05252); }\n[data-edrv-view] .edrv-dapwatch-add { padding: 2px 0; }\n[data-edrv-view] .edrv-dapbp { display: flex; align-items: center; gap: 6px; font-size: 12px; padding: 2px 2px; border-radius: 6px; cursor: pointer; }\n[data-edrv-view] .edrv-dapbp:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .12)); }\n[data-edrv-view] .edrv-dapbp:active { background: var(--dsw-alias-interactive-bg-pressed, rgba(127, 127, 127, .2)); }\n[data-edrv-view] .edrv-dapbp-dot { flex: 0 0 auto; width: 9px; height: 9px; border-radius: 50%; background: var(--dsw-alias-state-error-primary, #e51400); }\n[data-edrv-view] .edrv-dapbp-dot.off { background: transparent; border: 1.5px solid var(--dsw-alias-label-tertiary, #9aa5b1); opacity: .6; }\n[data-edrv-view] .edrv-dapbp-file { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; border: none; background: transparent; color: var(--dsw-alias-label-primary, inherit); cursor: pointer; padding: 0; font-size: 12px; }\n[data-edrv-view] .edrv-dapbp-dir { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; text-align: right; }\n[data-edrv-view] .edrv-dapbp-line { flex: 0 0 auto; font-size: 10px; padding: 1px 6px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-dapbp-x { flex: 0 0 auto; border: none; background: transparent; color: transparent; cursor: pointer; width: 14px; }\n[data-edrv-view] .edrv-dapbp:hover .edrv-dapbp-x { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-dapbp-x:hover { color: var(--dsw-alias-state-error-primary, #e05252) !important; }\n[data-edrv-view] .edrv-daprepl { display: flex; flex-direction: column; gap: 4px; }\n[data-edrv-view] .edrv-daprepl-log { display: flex; flex-direction: column; gap: 1px; max-height: 180px; overflow: auto; }\n[data-edrv-view] .edrv-daprepl-line { font-size: 11px; font-family: var(--ds-font-family-code, ui-monospace, monospace); color: var(--dsw-alias-label-secondary, #52606d); white-space: pre-wrap; word-break: break-all; display: flex; gap: 6px; }\n[data-edrv-view] .edrv-daprepl-line.out { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-daprepl-in { width: 100%; box-sizing: border-box; height: 26px; padding: 0 8px; font-size: 12px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); }\n[data-edrv-view] .edrv-dappanel-run { flex: 0 0 auto; width: 24px; height: 24px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, inherit); font-size: 13px; line-height: 1; cursor: pointer; }\n[data-edrv-view] .edrv-dappanel-run:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .15)); }\n[data-edrv-view] .edrv-dappanel-run:disabled { opacity: .35; cursor: default; background: transparent; }\n/* 面板顶部配置下拉(与编辑器浮动条 .edrv-dapbar-cfg 同视觉)。 */\n[data-edrv-view] .edrv-dappanel-cfg-select { max-width: 190px; height: 24px; padding: 0 4px; font-size: 11px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); }\n/* 断点行内编辑行(面板内展开编辑,控件复用 .edrv-bpwidget-* 视觉;左缩进对齐断点行文字列)。 */\n[data-edrv-view] .edrv-dapbp-edit { display: flex; align-items: center; gap: 6px; padding: 3px 2px 3px 20px; border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); }\n[data-edrv-view] .edrv-dapbp-edit .edrv-bpwidget-mode { height: 20px; }\n[data-edrv-view] .edrv-dapbp-edit .edrv-bpwidget-input { height: 20px; }\n/* 断点回执:未验证空心红圈(须排在 .off 之后,禁用态优先展示灰圈语义)。 */\n[data-edrv-view] .edrv-dapbp-dot.unverified { background: transparent; border: 1.5px solid var(--dsw-alias-state-error-primary, #e51400); opacity: .75; }\n/* 断点行内编辑浮层(Monaco content widget,锚定断点行上方;对齐 VS Code breakpointWidget 形态)。 */\n/* View Zone 浮层:宽度/左移由 BpWidget.syncWidth 按 layout 内联设置\n (Monaco .view-zones 仅内容区宽,需补偿 contentLeft 与滚动条),此处只管视觉。 */\n[data-edrv-view] .edrv-bpwidget { position: relative; box-sizing: border-box; display: flex; align-items: center; gap: 6px; padding: 3px 8px; border-top: 1px solid var(--dsw-alias-border-l2, #cdd6da); border-bottom: 1px solid var(--dsw-alias-border-l2, #cdd6da); background: var(--dsw-alias-bg-layer-1, #f7f9fa); }\n/* 断点编辑中的目标行高亮(浮层打开期间) */\n[data-edrv-view] .edrv-dap-editing-line { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .12)); }\n[data-edrv-view] .edrv-bpwidget-mode { flex: 0 0 auto; height: 22px; padding: 0 4px; font-size: 12px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 3px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); cursor: pointer; }\n[data-edrv-view] .edrv-bpwidget-input { flex: 1 1 auto !important; min-width: 0; width: auto !important; box-sizing: border-box; height: 22px; padding: 0 6px; font-size: 12px; font-family: var(--ds-font-family-code, ui-monospace, monospace); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 3px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); }\n[data-edrv-view] .edrv-bpwidget-input:focus { outline: 1px solid var(--dsw-alias-border-l2, #cdd6da); }\n\n/* 断点 hover 预览(glyph 区):半透明小红点 + pointer 光标(对齐 VS Code .codicon-debug-hint)。 */\n[data-edrv-view] .edrv-dap-bp-hint { cursor: pointer; }\n[data-edrv-view] .edrv-dap-bp-hint::before { content: ''; display: block; width: 7px; height: 7px; margin: 6px auto 0; border-radius: 50%; background: var(--dsw-alias-state-error-primary, #e51400); opacity: .4; }\n/* 行号区也给出可点提示(与 VS Code 一致:glyph 区与行号区都可点/可 hover);\n 不拦截折叠箭头等自有控件的光标。 */\n[data-edrv-view] .edrv-editor-row .monaco-editor .margin-view-overlays .line-numbers:hover { cursor: pointer; }\n\n/* 暂停态 hover 调试块 + 变量树(成员全量直显 + table 成员折叠展开)。\n ⚠️ 选择器一律用 data-*:本仓 vendored Monaco 的 markdown→DOM 管线会剥掉我们 HTML 里的\n class(supportHtml/isTrusted 都不豁免),只有 data-* 存活;用 class 会静默失效。 */\n[data-edrv-view] [data-edrv-dap] { display: block; min-width: 0; }\n[data-edrv-view] [data-edrv-head] { display: flex; align-items: baseline; gap: 2px; }\n[data-edrv-view] [data-edrv-head] [data-edrv-expr] { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] [data-edrv-head] [data-edrv-val] { font-family: var(--ds-font-family-code, ui-monospace, monospace); word-break: break-all; }\n[data-edrv-view] [data-edrv-type] { margin-top: 2px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #8a949b); }\n[data-edrv-view] [data-edrv-tree] { margin: 2px 0 0; padding: 0; list-style: none; font-variant-numeric: tabular-nums; }\n[data-edrv-view] [data-edrv-line] { display: flex; align-items: baseline; gap: 4px; padding: 1px 2px; border-radius: 3px; white-space: nowrap; }\n[data-edrv-view] [data-edrv-line]:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .12)); }\n/* 折叠按钮(对齐 CodeBuddy 调试浮窗变量树的 twist):热区 14px + hover 反馈,未可展开时留空占位 */\n[data-edrv-view] [data-edrv-twist] { flex: 0 0 auto; box-sizing: border-box; width: 14px; height: 14px; line-height: 13px; text-align: center; border-radius: 3px; color: var(--dsw-alias-label-tertiary, #8a949b); }\n[data-edrv-view] [data-edrv-twist]:not(:empty) { cursor: pointer; user-select: none; }\n[data-edrv-view] [data-edrv-twist]:not(:empty):hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .2)); color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] [data-edrv-name] { flex: 0 0 auto; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] [data-edrv-line] [data-edrv-eq] { flex: 0 0 auto; color: var(--dsw-alias-label-tertiary, #8a949b); }\n[data-edrv-view] [data-edrv-line] [data-edrv-val] { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] [data-edrv-note] { color: var(--dsw-alias-label-tertiary, #8a949b); font-style: italic; }\n/* Alt 提示层:由 hoverTree 注入到 .monaco-hover(滚动区之外)贴底常驻;容器预留同高内边距避免遮挡末行。\n 不再用 sticky / `:has()`:滚动链在 .monaco-hover-content 上,sticky 会被滚走。 */\n[data-edrv-view] .monaco-hover[data-edrv-hint-host=\"1\"] { padding-bottom: 22px; }\n[data-edrv-view] [data-edrv-hint=\"1\"] { position: absolute; left: 0; right: 0; bottom: 0; box-sizing: border-box; height: 22px; padding: 2px 8px; font-size: 11px; line-height: 18px; color: var(--dsw-alias-label-tertiary, #8a949b); background: var(--dsw-alias-bg-overlay, #ffffff); border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }";
36
+ const css$1 = "/* dsh-vscode-mode 编辑区样式(原 ensureEdrvStyles 字符串,落盘为真 .css,由 tsdown CSS-inline 注入) */\n/* 主题:跟随官方 --dsw-alias-* 令牌(DSH 明暗与第三方皮肤生效)。\n 本作用域不再重定义官方令牌(旧实现曾在此硬覆盖浅色盘,导致插件不跟随 DSH 主题);\n 旧环境/缺令牌场景由每条声明的 var(--dsw-alias-*, 回落值) 兜底。\n @author ddj 2026-09-10 */\n[data-edrv-view] { box-sizing: border-box; --edrv-tab-h: 34px; }\n\n[data-edrv-view] .edrv-tabs { display: flex; align-items: center; gap: 2px; padding: 2px 8px 0; background: var(--dsw-alias-bg-layer-1, transparent); overflow-x: auto; overflow-y: hidden; scrollbar-width: thin; flex-shrink: 0; overscroll-behavior-x: contain; } /* overscroll-behavior-x: 横滚到边界不把滚动链传给页面(滚轮横滚接管更可控)@author ddj 2026年09月18号 */\n[data-edrv-view] .edrv-tab { display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 8px 0 12px; border: none; border-radius: 6px 6px 0 0; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 12px; cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-tab.edrv-tab-active { background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); box-shadow: inset 0 -2px 0 var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-tab .edrv-tab-star { color: var(--dsw-alias-brand-primary, #4f8cff); font-size: 13px; font-weight: 700; line-height: 1; flex-shrink: 0; } /* 未保存修改星号 @author ddj 2026年09月09号 */\n[data-edrv-view] .edrv-tab .edrv-tab-x { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; border-radius: 4px; color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; }\n[data-edrv-view] .edrv-tab .edrv-tab-x:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.12)); color: var(--dsw-alias-label-primary, #eee); }\n/* 固定页签:📌 标记 + 免关闭按钮(固定页签不渲染 ×,仅可经右键菜单取消固定) */\n[data-edrv-view] .edrv-tab .edrv-tab-pin { flex-shrink: 0; font-size: 10px; line-height: 1; opacity: .85; }\n[data-edrv-view] .edrv-tab.edrv-tab-pinned { background: var(--dsw-alias-bg-layer-2, rgba(255,255,255,.04)); }\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/* 键盘高亮项(↑↓ 选择):与 hover 同特异性但声明在后,故选中态稳定可辨 @author ddj 2026年09月11号 */\n[data-edrv-view] .edrv-search-item.edrv-search-sel { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.14)); }\n[data-edrv-view] .edrv-search-item .n { color: var(--dsw-alias-label-primary, #eee); font-size: 12px; word-break: break-all; }\n[data-edrv-view] .edrv-search-item .d { color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-search-empty { padding: 8px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #888); }\n[data-edrv-view] .edrv-btn-mini { font-size: 11px; padding: 2px 9px; border: none; border-radius: 999px; cursor: pointer; color: var(--dsw-alias-label-primary-inverted, #fff); font-weight: 600; white-space: nowrap; }\n[data-edrv-view] .edrv-btn-keep { background: var(--dsw-alias-state-success-primary, #2e9e44); }\n[data-edrv-view] .edrv-btn-undo { background: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-btn-mini:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-statusbar { display: flex; align-items: center; gap: 10px; padding: 3px 10px; border-top: 1px solid var(--dsw-alias-border-l1, #333); background: var(--dsw-alias-bg-layer-1, transparent); font-size: 11px; color: var(--dsw-alias-label-tertiary, #888); flex-shrink: 0; white-space: nowrap; overflow: hidden; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-path { flex: 1; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-lsp { flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-progress-message { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-statusbar .edrv-sp-progress { flex: 0 0 auto; min-width: 36px; text-align: right; font-variant-numeric: tabular-nums; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-lsp-status-dot { width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto; background: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-lsp-status-dot.ready { background: var(--dsw-alias-state-success-primary, #0f9d58); }\n[data-edrv-view] .edrv-lsp-status-dot.busy { background: var(--dsw-alias-state-warn-primary, #d97706); animation: edrv-lsp-pulse 1.2s ease-in-out infinite; }\n@keyframes edrv-lsp-pulse { 50% { opacity: .45; } }\n/* Ctrl+hover 可导航标识符下划线提示(绑定 Monaco inlineClassName 装饰) */\n[data-edrv-view] .edrv-nav-underline { text-decoration: underline; text-decoration-color: var(--dsw-alias-interactive-primary, #4fc1ff); text-underline-offset: 1px; cursor: pointer; }\n/* 跳转目标区域高亮(LSP 定义/引用、搜索命中落点):落点一眼可见,约 1.2s 后由 EditorView 自动清除。\n 用官方令牌并带回落值,不在插件作用域重定义 --dsw-* (否则永久脱离官方主题)。 */\n[data-edrv-view] .edrv-nav-target { background: var(--dsw-alias-interactive-bg-hover, rgba(79,193,255,.28)); border-radius: 2px; box-shadow: 0 0 0 1px var(--dsw-alias-interactive-primary, rgba(79,193,255,.55)); }\n[data-edrv-view] .edrv-diffchip { font-size: 11px; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #333); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-state-warn-primary, #b7791f); cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn { font-size: 12px; padding: 2px 6px; border: none; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; border-radius: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-chip-btn:disabled { opacity: .35; cursor: default; }\n[data-edrv-view] .edrv-chip-btn:disabled:hover { background: transparent; }\n[data-edrv-view] .edrv-mn-add-line { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.10)); }\n[data-edrv-view] .edrv-mn-gutter-add { color: var(--dsw-alias-state-success-primary, #0f9d58) !important; font-weight: 700; display: flex !important; align-items: center; justify-content: center; }\n[data-edrv-view] .edrv-mn-gutter-add::before { content: \"+\"; }\n[data-edrv-view] .edrv-del-zone { background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.14)); border-top: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.35)); border-bottom: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.35)); box-shadow: inset 0 0 0 1px var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); }\n[data-edrv-view] .edrv-del-row { white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 12.5px; line-height: 20px; color: var(--dsw-alias-state-error-primary, #c0392b); }\n[data-edrv-view] .edrv-del-text { display: inline-block; white-space: pre; }\n[data-edrv-view] .edrv-minus-overlay { position: absolute; left: 0; top: 0; width: 100%; height: 100%; max-width: 100%; overflow: visible; pointer-events: none; z-index: 6; }\n[data-edrv-view] .edrv-minus-item { position: absolute; box-sizing: border-box; max-width: 100%; overflow: hidden; }\n[data-edrv-view] .edrv-minus-item::before { content: ''; position: absolute; left: 4px; top: 50%; width: 8px; height: 2px; transform: translateY(-50%); border-radius: 2px; background: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-monaco-host { flex: 1 1 auto; min-width: 0; min-height: 0; position: relative; overflow: hidden; }\n[data-edrv-view] .edrv-monaco-host > div { position: absolute; inset: 0; min-width: 0; min-height: 0; }\n[data-edrv-view] .edrv-imgview { flex: 1 1 auto; min-width: 0; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }\n[data-edrv-view] .edrv-imgview-bar { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px; flex-shrink: 0; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, transparent); }\n[data-edrv-view] .edrv-imgview-meta { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; }\n/* 图片预览:居中交给子项 margin:auto(auto 外边距优先吃正向空闲空间;溢出时空闲为负 → 外边距归 0、\n flex-start 起点对齐 → 放大后四边均可滚动到达,规避 justify-content:center 双侧溢出不可达问题) */\n[data-edrv-view] .edrv-imgview-stage { flex: 1 1 auto; min-height: 0; display: flex; overflow: auto; padding: 14px; background-color: var(--dsw-alias-bg-layer-1, #f0f4f4); background-image: conic-gradient(rgba(128,128,128,.14) 25%, transparent 0 50%, rgba(128,128,128,.14) 0 75%, transparent 0); background-size: 16px 16px; }\n[data-edrv-view] .edrv-imgview-img { max-width: 100%; max-height: 100%; flex-shrink: 0; margin: auto; align-self: flex-start; object-fit: contain; border-radius: 4px; box-shadow: 0 2px 12px rgba(31,41,51,.18); }\n[data-edrv-view] .edrv-imgview-broken { display: flex; flex-direction: column; align-items: center; gap: 10px; font-size: 13px; color: var(--dsw-alias-label-tertiary, #777); margin: auto; }\n[data-edrv-view] .edrv-pdf-host { flex: 1 1 auto; min-width: 0; min-height: 0; position: relative; overflow: hidden; }\n[data-edrv-view] .edrv-pdf-host > .edrv-pdf { position: absolute; inset: 0; }\n[data-edrv-view] .edrv-pdf { min-width: 0; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }\n[data-edrv-view] .edrv-pdf-bar { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px; flex-shrink: 0; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, transparent); }\n[data-edrv-view] .edrv-pdf-page { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; min-width: 52px; text-align: center; }\n[data-edrv-view] .edrv-pdf-zoom { min-width: 26px; text-align: center; padding: 3px 7px; }\n[data-edrv-view] .edrv-pdf-sep { width: 1px; height: 16px; background: var(--dsw-alias-border-l1, #e0e6e8); margin: 0 2px; }\n[data-edrv-view] .edrv-pdf-mode-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-brand-primary, #0f9d58); border-color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-pdf-dirty { color: var(--dsw-alias-state-warn-primary, #d97706); border-color: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-pdf-stage { position: absolute; top: 34px; left: 0; right: 0; bottom: 0; overflow: auto; }\n/* Markdown 预览(需求 4):工具条 + 居中阅读栏;正文排版由官方 MarkdownText 自带的 --dsw-* 样式负责 */\n[data-edrv-view] .edrv-mdview { flex: 1 1 auto; min-width: 0; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }\n[data-edrv-view] .edrv-mdview-bar { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px; flex-shrink: 0; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, transparent); }\n[data-edrv-view] .edrv-mdview-meta { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; }\n[data-edrv-view] .edrv-mdview-stage { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 14px 20px 28px; }\n[data-edrv-view] .edrv-mdview-doc { max-width: 880px; margin: 0 auto; width: 100%; }\n[data-edrv-view] .edrv-mdview-fallback { font-size: 12px; line-height: 1.7; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-mdview-pre { margin: 8px 0 0; padding: 10px 12px; border-radius: 8px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-primary, #1f2933); font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; line-height: 1.6; white-space: pre-wrap; word-break: break-word; }\n[data-edrv-view] .edrv-pb-mdbtn { height: 20px; padding: 0 8px; font-size: 11px; flex-shrink: 0; }\n[data-edrv-view] .edrv-pdf-stage .edrv-pdf-viewer { margin: 0 auto; }\n[data-edrv-view] .edrv-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; height: 100%; color: var(--dsw-alias-label-tertiary, #777); font-size: 13px; }\n[data-edrv-view] .edrv-diffbar { position: absolute; left: 0; right: 0; bottom: 10px; margin: 0 auto; z-index: 25; width: fit-content; max-width: calc(100% - 20px); border-radius: 12px; background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, #f0f4f4)); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); box-shadow: none; overflow: visible; display: flex; flex-direction: column; }\n[data-edrv-view] .edrv-editor-area > .edrv-diffbar { max-height: calc(100% - 20px); }\n[data-edrv-view] .edrv-diffbar-row { display: flex; align-items: center; gap: 6px; height: 36px; padding: 4px 5px 4px 12px; flex-wrap: nowrap; }\n[data-edrv-view] .edrv-diffbar-count { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); min-width: 42px; text-align: center; white-space: nowrap; cursor: pointer; }\n[data-edrv-view] .edrv-diffbar-count.edrv-count-file { min-width: 64px; cursor: default; }\n[data-edrv-view] .edrv-diffbar-file { flex: 1; min-width: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-pill { font-size: 11px; padding: 3px 10px; border: none; border-radius: 999px; cursor: pointer; white-space: nowrap; font-weight: 600; }\n[data-edrv-view] .edrv-pill-keep { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-state-success-primary, #0f7a45); border: 1px solid var(--dsw-alias-state-success-primary, rgba(15,157,88,.4)); }\n[data-edrv-view] .edrv-pill-undo { background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.14)); color: var(--dsw-alias-state-error-primary, #c0392b); border: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); }\n[data-edrv-view] .edrv-pill-ghost { background: var(--dsw-alias-bg-layer-1, #ffffff); color: var(--dsw-alias-label-secondary, #52606d); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-pill:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-diffbar-menu { position: absolute; right: 8px; bottom: calc(100% + 6px); z-index: 45; min-width: 160px; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 6px 20px rgba(31,41,51,.16); padding: 4px; display: flex; flex-direction: column; gap: 2px; }\n[data-edrv-view] .edrv-diffmenu-item { display: flex; align-items: center; gap: 8px; font-size: 12px; padding: 6px 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; text-align: left; }\n[data-edrv-view] .edrv-diffmenu-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-diffmenu-item.danger { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-diffmenu-sep { height: 1px; margin: 2px 4px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n/* 编辑区 / Tab 右键菜单(页签右键菜单 + 文件树右键菜单共用)。\n 页签菜单 11 条 + 键位提示,故限高可滚(ContextMenu 以实测尺寸做 viewport clamp)。\n ⚠️ z-index 71 在既有浮层阶梯内(见文件末尾命令栏注释),不得上调越过命令栏/片段浮窗。 */\n[data-edrv-view] .edrv-ctxmenu { position: fixed; z-index: 71; min-width: 220px; max-width: 360px; max-height: min(70vh, 520px); overflow-y: auto; 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/* 菜单项文案(弹性占宽,超出省略)与右侧键位提示(不缩放,等宽字体) */\n[data-edrv-view] .edrv-ctxmenu-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-ctxmenu-hint { flex: 0 0 auto; padding-left: 18px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; }\n[data-edrv-view] .edrv-ctxmenu-item:disabled .edrv-ctxmenu-hint,\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-disabled .edrv-ctxmenu-hint { color: var(--dsw-alias-label-disabled, #b0b7c0); }\n[data-edrv-view] .edrv-diffbar-body { max-height: 130px; max-width: min(560px, calc(100vw - 40px)); overflow: auto; padding: 4px 8px 8px; display: flex; flex-direction: column; gap: 4px; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-diffrow { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); cursor: pointer; flex-wrap: wrap; }\n[data-edrv-view] .edrv-diffrow:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-diffrow-l { font-size: 11px; color: var(--dsw-alias-label-primary, #1f2933); min-width: 74px; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-o { font-size: 11px; color: var(--dsw-alias-state-error-primary, #d9534f); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-n { font-size: 11px; color: var(--dsw-alias-state-success-primary, #0f9d58); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-tag { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-diffrow-stale { border-color: var(--dsw-alias-state-warn-primary, rgba(217,119,6,.5)); cursor: default; }\n[data-edrv-view] .edrv-diffbox-others { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; padding: 4px 2px 0; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); margin-top: 2px; }\n[data-edrv-view] .edrv-diffrow-file { font-size: 11px; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); cursor: pointer; white-space: nowrap; max-width: 200px; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-diffrow-file:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n/* 编辑区 hover 差异块的 Keep/Undo 浮层 */\n[data-edrv-view] .edrv-hoveract { position: absolute; z-index: 30; display: flex; align-items: center; gap: 4px; padding: 2px 6px; border-radius: 8px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 4px 14px rgba(31,41,51,.14); }\n[data-edrv-view] .edrv-launch { position: absolute; left: 12px; right: 12px; bottom: 12px; z-index: 40; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); box-shadow: 0 6px 24px rgba(0,0,0,.5); display: flex; flex-direction: column; max-height: 60%; overflow: hidden; }\n[data-edrv-view] .edrv-launch-head { display: flex; align-items: center; gap: 6px; padding: 6px 8px; border-bottom: 1px solid var(--dsw-alias-border-l1, #333); }\n[data-edrv-view] .edrv-launch-tab { font-size: 12px; padding: 3px 12px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; }\n[data-edrv-view] .edrv-launch-tab.on { background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-label-primary, #eee); font-weight: 600; }\n[data-edrv-view] .edrv-launch-body { flex: 1; min-height: 0; overflow: auto; padding: 6px 8px; display: flex; flex-direction: column; gap: 4px; }\n[data-edrv-view] .edrv-launch-row { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1, #333); border-radius: 6px; cursor: pointer; flex-wrap: wrap; }\n[data-edrv-view] .edrv-launch-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-launch-path { flex: 1; min-width: 0; font-size: 12px; color: var(--dsw-alias-label-primary, #eee); word-break: break-all; }\n[data-edrv-view] .edrv-launch-cnt { font-size: 11px; color: var(--dsw-alias-label-tertiary, #888); white-space: nowrap; }\n[data-edrv-view] .edrv-launch-arch { display: flex; flex-direction: column; gap: 6px; }\n[data-edrv-view] .monaco-editor { overflow: hidden !important; }\n[data-edrv-view] .monaco-editor .sticky-widget { z-index: 30 !important; background: var(--dsw-alias-bg-base, #f8f8f8) !important; }\n[data-edrv-view] .monaco-editor .sticky-widget .sticky-line-content,\n[data-edrv-view] .monaco-editor .sticky-widget .sticky-line-number { background: var(--dsw-alias-bg-base, #f8f8f8) !important; }\n[data-edrv-view] .monaco-editor, [data-edrv-view] .monaco-editor .margin, [data-edrv-view] .monaco-editor-background { background: transparent !important; }\n[data-edrv-view] .monaco-editor .scrollbar .slider { background: rgba(128,128,128,.3) !important; }\n[data-edrv-view] .edrv-loading { gap: 8px; padding: 20px; }\n[data-edrv-view] .edrv-loading-title { color: var(--dsw-alias-label-primary, #1f2933); font-size: 13px; }\n[data-edrv-view] .edrv-progress { width: min(360px, 72%); height: 6px; overflow: hidden; border-radius: 999px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-progress-value { height: 100%; border-radius: inherit; background: var(--dsw-alias-brand-primary, #0f9d58); transition: width .24s ease; }\n[data-edrv-view] .edrv-loading-percent { color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; font-variant-numeric: tabular-nums; }\n@media (prefers-reduced-motion: reduce) {\n [data-edrv-view] .edrv-progress-value { transition: none; }\n}\n\n/* ===== 唯一会话级差异 dock(遵循 DSH todo/queue 原生布局) ===== */\n[data-edrv-diff-dock-shell] {\n box-sizing: border-box;\n width: calc(100% - var(--dsh-composer-side-clearance) - var(--dsh-composer-side-clearance) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));\n max-width: calc(var(--dsh-composer-card-max-width) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));\n margin: 0 auto;\n padding: 0;\n flex: none;\n border: 1px solid var(--dsw-alias-border-l1, #e0e6e8);\n border-radius: 12px;\n background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, transparent));\n box-shadow: none;\n overflow: hidden;\n}\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock {\n box-sizing: border-box;\n position: relative;\n left: auto;\n right: auto;\n bottom: auto;\n z-index: auto;\n width: 100%;\n max-width: none;\n margin: 0;\n display: flex;\n flex-direction: column;\n border: none;\n border-radius: 0;\n background: transparent;\n box-shadow: none;\n overflow: visible;\n}\n[data-edrv-diff-dock-shell] .edrv-diffbar-row { min-height: 36px; padding: 6px 12px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-row { min-height: 36px; padding: 6px 12px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-body { max-height: 180px; overflow: auto; padding: 6px 12px 10px; border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-button { box-sizing: border-box; display: flex; align-items: center; justify-content: center; width: 100%; height: 24px; border: none; border-radius: 8px; padding: 0 12px; background: transparent; color: var(--dsw-alias-label-primary); font-size: 13px; font-weight: 500; line-height: 24px; text-align: center; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-button:hover { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diffbar-count { display: inline-flex; align-items: center; color: var(--dsw-alias-label-primary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 500; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-file { display: inline-flex; align-items: center; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-editor-row { display: flex; align-items: center; height: 36px; min-height: 36px; padding: 4px 12px; overflow-x: auto; scrollbar-width: thin; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-editor-content { display: flex; align-items: center; gap: 10px; width: 100%; min-width: max-content; min-height: 28px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-nav,\n[data-edrv-diff-dock-shell] .edrv-diffbar-files,\n[data-edrv-diff-dock-shell] .edrv-diffbar-actions { display: flex; align-items: center; gap: 6px; flex: none; height: 28px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-actions { margin-left: auto; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-details-toggle { display: inline-flex; align-items: center; justify-content: center; width: 28px; min-width: 28px; padding: 0; font-size: 13px; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-details-toggle svg { width: 14px; height: 14px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-files { min-width: 0; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-files .edrv-diffbar-file { min-width: 72px; max-width: 240px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-progress { min-width: 0; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; font-variant-numeric: tabular-nums; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-summary { min-width: 0; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-pill { box-sizing: border-box; height: 28px; padding: 0 9px; border: none; border-radius: 999px; cursor: pointer; white-space: nowrap; font-size: 11px; line-height: 26px; font-weight: 600; }\n[data-edrv-diff-dock-shell] .edrv-pill-keep { background: var(--dsw-alias-state-success-tertiary); color: var(--dsw-alias-state-success-primary); border: 1px solid var(--dsw-alias-state-success-secondary); }\n[data-edrv-diff-dock-shell] .edrv-pill-undo { background: var(--dsw-alias-state-error-tertiary); color: var(--dsw-alias-state-error-primary); border: 1px solid var(--dsw-alias-state-error-secondary); }\n[data-edrv-diff-dock-shell] .edrv-pill-ghost { background: transparent; color: var(--dsw-alias-label-secondary); border: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-pill:hover:not(:disabled) { background-color: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-pill:focus-visible { outline: 2px solid var(--dsw-alias-label-tertiary); outline-offset: -2px; }\n[data-edrv-diff-dock-shell] .edrv-pill:disabled { opacity: .45; cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diffrow { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; background: transparent; cursor: pointer; flex-wrap: wrap; }\n[data-edrv-diff-dock-shell] .edrv-diffrow:hover { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-l { color: var(--dsw-alias-label-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-o { color: var(--dsw-alias-state-error-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-n { color: var(--dsw-alias-state-success-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-tag { color: var(--dsw-alias-label-tertiary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-stale { border-color: var(--dsw-alias-state-warn-secondary); cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diffbox-others { border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-file { border-color: var(--dsw-alias-border-l1); background: transparent; color: var(--dsw-alias-label-secondary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-file:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }\n[data-edrv-diff-dock-shell] .edrv-diff-details { display: flex; flex-direction: column; gap: 2px; padding: 6px 12px 8px; border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item { display: flex; align-items: center; width: 100%; min-height: 28px; gap: 8px; padding: 4px 8px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary); cursor: pointer; text-align: left; font-size: 12px; line-height: 20px; }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item.danger { color: var(--dsw-alias-state-error-primary); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item:disabled { opacity: .45; cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-sep { height: 1px; margin: 2px 4px; background: var(--dsw-alias-border-l1); }\n@media (max-width: 620px) {\n [data-edrv-diff-dock-shell] .edrv-diffbar-editor-content { width: max-content; }\n [data-edrv-diff-dock-shell] .edrv-diffbar-files .edrv-diffbar-file { max-width: 160px; }\n}\n\n/* ===== 侧边栏(活动栏 + 面板区 + 文件树) ===== */\n[data-edrv-view] .edrv-editor-row { display: flex; flex: 1 1 auto; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-main-col { box-sizing: border-box; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-main-col > .edrv-pathbar,\n[data-edrv-view] .edrv-main-col > .edrv-tabs { flex: 0 0 auto; }\n[data-edrv-view] .edrv-editor-area { position: relative; display: flex; flex: 1 1 auto; flex-direction: column; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-sidebar { display: flex; flex-direction: row; flex-shrink: 1; min-width: 0; height: 100%; background: var(--dsw-alias-bg-layer-1, #ffffff); border-right: 1px solid var(--dsw-alias-border-l1, #e0e6e8); overflow: hidden; }\n[data-edrv-view] .edrv-rail { display: flex; flex-direction: column; align-items: center; width: 44px; flex-shrink: 0; padding: 6px 0; background: var(--dsw-alias-bg-layer-2, #f0f4f4); border-right: 1px solid var(--dsw-alias-border-l1, #e0e6e8); gap: 4px; }\n[data-edrv-view] .edrv-rail-btn { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border: none; border-radius: 8px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-rail-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rail-btn.edrv-rail-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-label-primary, #1f2933); box-shadow: inset 2px 0 0 var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-rail-icon { font-size: 15px; line-height: 1; display: inline-flex; align-items: center; justify-content: center; }\n/* 树行图标:官方原语(文件夹/文件类型),尺寸与行高对齐 @author ddj 2026-09-10 */\n[data-edrv-view] .edrv-tree-icon { flex-shrink: 0; display: inline-flex; align-items: center; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-active .edrv-tree-icon { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-rail-badge { position: absolute; top: 2px; right: 2px; min-width: 14px; height: 14px; padding: 0 3px; border-radius: 999px; background: var(--dsw-alias-brand-primary, #0f9d58); color: var(--dsw-alias-label-primary-inverted, #fff); font-size: 9px; font-weight: 600; line-height: 14px; text-align: center; box-sizing: border-box; }\n[data-edrv-view] .edrv-side-body { flex: 1; min-width: 0; min-height: 0; display: flex; overflow: hidden; }\n[data-edrv-view] .edrv-side-panel { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; position: relative; }\n[data-edrv-view] .edrv-side-head { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px 0 12px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); flex-shrink: 0; }\n[data-edrv-view] .edrv-side-title { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-side-root { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-side-btn { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-side-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-tree { flex: 1; min-height: 0; overflow: auto; padding: 4px 6px 12px; font-size: 12px; }\n[data-edrv-view] .edrv-tree-row { display: flex; align-items: center; gap: 4px; height: 22px; padding-right: 6px; border-radius: 5px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-tree-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-active { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-context { box-shadow: inset 0 0 0 1px var(--dsw-alias-brand-primary, #0f9d58); background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); }\n/* 「在资源管理器视图中显示」的定位高亮(短时淡出,区别于常驻的 active 态) */\n[data-edrv-view] .edrv-tree-row.edrv-tree-reveal { box-shadow: inset 0 0 0 1px var(--dsw-alias-brand-primary, #0f9d58); background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.18)); animation: edrv-tree-reveal-fade 2s ease-out; }\n@keyframes edrv-tree-reveal-fade { from { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.32)); } to { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.18)); } }\n[data-edrv-view] .edrv-tree-chev { width: 12px; flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; text-align: center; }\n[data-edrv-view] .edrv-tree-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-tree-name.edrv-tree-dim { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-tree-badge { min-width: 14px; height: 14px; padding: 0 4px; border-radius: 999px; background: var(--dsw-alias-state-warn-primary, #d97706); color: var(--dsw-alias-label-primary-inverted, #fff); font-size: 9px; font-weight: 600; line-height: 14px; text-align: center; box-sizing: border-box; flex-shrink: 0; }\n[data-edrv-view] .edrv-tree-loading { height: 22px; line-height: 22px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-tree-error { display: flex; align-items: center; gap: 8px; margin: 4px 2px 6px; padding: 6px 8px; border: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n/* 大纲面板:kind 字形 / detail / 行号 */\n[data-edrv-view] .edrv-outline-kind { display: inline-flex; align-items: center; justify-content: center; width: 14px; flex-shrink: 0; font-size: 12px; font-weight: 600; text-align: center; }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-func { color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-type { color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-data { color: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-ns { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-key { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-outline-detail { flex-shrink: 0; max-width: 40%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-outline-ln { flex-shrink: 0; padding-right: 2px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-side-resize { width: 5px; flex-shrink: 0; cursor: col-resize; background: transparent; }\n[data-edrv-view] .edrv-side-resize:hover { background: var(--dsw-alias-brand-primary, #0f9d58); opacity: .35; }\n[data-edrv-view] .edrv-chip-btn.edrv-chip-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-label-primary, #1f2933); }\n\n/* ===== SVN 变更面板(工作副本状态列表;颜色分级对齐 TortoiseSVN 口径) @author ddj 2026-09-16 ===== */\n[data-edrv-view] .edrv-svn-toolbar { display: flex; align-items: center; gap: 12px; padding: 4px 10px 6px 12px; flex-shrink: 0; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-svn-check { display: inline-flex; align-items: center; gap: 4px; cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-svn-check input { margin: 0; cursor: pointer; }\n[data-edrv-view] .edrv-svn-bulk { display: flex; align-items: center; gap: 6px; padding: 0 10px 6px 12px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svn-count { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n/* AI 助手 dock(12-panel-ai-bar 设计定稿):manifest 分带之 assistant 带,accent 左竖轨为唯一记忆点。\n AI 线程色三处同轨:竖轨 / dock 按钮描边 / 弹窗进度条(--dsw-alias-state-info-primary)。 @author ddj 2026-09-23 */\n[data-edrv-view] .edrv-svn-ai-bar { position: relative; display: flex; align-items: center; gap: 8px; padding: 6px 10px 6px 14px; background: var(--dsw-alias-bg-layer-2, #f7f9f9); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); flex-shrink: 0; }\n[data-edrv-view] .edrv-svn-ai-rail { position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: var(--dsw-alias-state-info-primary, #2f6fed); }\n[data-edrv-view] .edrv-svn-ai-label { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-svn-ai-btn { border-color: var(--dsw-alias-state-info-primary, #2f6fed); color: var(--dsw-alias-state-info-primary, #2f6fed); }\n[data-edrv-view] .edrv-svn-ai-btn:disabled { border-color: var(--dsw-alias-border-l1, #e0e6e8); color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n/* 状态位定宽右对齐(就绪/分析中…/等待助手投递…互换不跳版) */\n[data-edrv-view] .edrv-svn-ai-status { flex-shrink: 0; min-width: 88px; text-align: right; font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; }\n/* 批量条语义分隔(导出簇 ┊ 动作簇之间 1px 竖线) */\n[data-edrv-view] .edrv-svn-sep { width: 1px; height: 14px; background: var(--dsw-alias-border-l1, #e0e6e8); flex-shrink: 0; }\n/* 头部图标组(检查远端/刷新成组,gap 收紧) */\n[data-edrv-view] .edrv-svn-head-icons { display: inline-flex; align-items: center; gap: 2px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svn-list { flex: 1; min-height: 0; overflow: auto; padding: 2px 6px 12px; font-size: 12px; }\n[data-edrv-view] .edrv-svn-group { display: flex; align-items: center; gap: 6px; height: 22px; padding: 0 6px; margin: 2px 0; border-radius: 5px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); font-size: 10px; font-weight: 600; cursor: pointer; user-select: none; }\n[data-edrv-view] .edrv-svn-group:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-svn-fold-ch { width: 10px; flex-shrink: 0; text-align: center; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svn-group-n { margin-left: auto; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-weight: 400; }\n[data-edrv-view] .edrv-svn-row { display: flex; align-items: center; gap: 6px; height: 22px; padding: 0 6px; border-radius: 5px; cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-svn-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-svn-path { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svn-acts { display: none; align-items: center; gap: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svn-row:hover .edrv-svn-acts { display: inline-flex; }\n[data-edrv-view] .edrv-svn-act { border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 5px; padding: 1px 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-secondary, #52606d); font-size: 10px; line-height: 14px; cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-svn-act:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svn-act:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-svn-act-danger { color: var(--dsw-alias-state-error-primary, #d9534f); border-color: var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); }\n[data-edrv-view] .edrv-svn-ch { display: inline-flex; align-items: center; justify-content: center; width: 14px; flex-shrink: 0; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; font-weight: 700; }\n[data-edrv-view] .edrv-svn-ch-modified { color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svn-ch-added { color: var(--dsw-alias-state-warn-primary, #7c3aed); }\n[data-edrv-view] .edrv-svn-ch-deleted { color: var(--dsw-alias-label-secondary, #b91c1c); }\n[data-edrv-view] .edrv-svn-ch-conflict { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-svn-ch-plain { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n/* 文件树行尾 SVN 状态徽标(与差异角标并列;方形字母,区别圆形差异计数) */\n[data-edrv-view] .edrv-tree-svn { min-width: 14px; height: 14px; padding: 0 4px; border-radius: 4px; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 9px; font-weight: 700; line-height: 14px; text-align: center; box-sizing: border-box; flex-shrink: 0; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-tree-svn.edrv-svn-ch-modified { color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-tree-svn.edrv-svn-ch-added { color: var(--dsw-alias-state-warn-primary, #7c3aed); }\n[data-edrv-view] .edrv-tree-svn.edrv-svn-ch-deleted { color: var(--dsw-alias-label-secondary, #b91c1c); }\n[data-edrv-view] .edrv-tree-svn.edrv-svn-ch-conflict { color: var(--dsw-alias-state-error-primary, #d9534f); }\n/* ===== SVN 基线差异视图(BASE 左 / 工作区右,只读并排) @author ddj 2026-09-16 ===== */\n[data-edrv-view] .edrv-svndiff { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-svndiff-bar { display: flex; align-items: center; gap: 8px; height: 30px; padding: 0 10px; flex-shrink: 0; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-svndiff-title { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-svndiff-tag { padding: 1px 6px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svndiff-host { flex: 1 1 auto; min-height: 0; }\n[data-edrv-view] .edrv-svndiff-empty { display: flex; flex: 1 1 auto; align-items: center; justify-content: center; padding: 24px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 12px; text-align: center; }\n/* 差异整行色块与行首 +/- 指示符:vendored Monaco(diffEditorWidget2)静态 CSS 无\n .line-insert/.line-delete 背景规则,整行色块靠主题键 + 此处固定色兜底保证可见。\n 注意不要用 --dsw-alias-interactive-bg-hover 类 token:实测为 92% 透明中性色,肉眼不可见。\n 固定色取自研差异 UI 同色相(绿 #0f9d58 / 红 #d9534f),alpha 提到肉眼可辨。 */\n[data-edrv-view] .monaco-editor .line-insert { background: rgba(15, 157, 88, 0.18); }\n[data-edrv-view] .monaco-editor .line-delete { background: rgba(217, 83, 79, 0.16); }\n[data-edrv-view] .monaco-editor .gutter-insert { background: rgba(15, 157, 88, 0.35); }\n[data-edrv-view] .monaco-editor .gutter-delete { background: rgba(217, 83, 79, 0.35); }\n[data-edrv-view] .monaco-editor .insert-sign { color: var(--dsw-alias-state-success-primary, #0f9d58); }\n[data-edrv-view] .monaco-editor .delete-sign { color: var(--dsw-alias-state-error-primary, #d9534f); }\n/* 差异条快速跳转簇(对齐自研审查条 ↑ i/N ↓ 的形态) */\n[data-edrv-view] .edrv-svndiff-nav { display: flex; align-items: center; gap: 2px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svndiff-nav-count { min-width: 36px; text-align: center; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); }\n/* W1-3 差异统计徽标(+新增/修改 −删除/修改;色相与行块绿红一致) @author ddj 2026-09-20 */\n[data-edrv-view] .edrv-svndiff-stat { display: inline-flex; align-items: center; gap: 4px; flex-shrink: 0; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-svndiff-stat-add { color: var(--dsw-alias-state-success-primary, #0f9d58); }\n[data-edrv-view] .edrv-svndiff-stat-del { color: var(--dsw-alias-state-error-primary, #d9534f); }\n/* W1-1 差异视图选项条(右端开关组;复用 .edrv-svn-check 的 label 形态) */\n[data-edrv-view] .edrv-svndiff-opts { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }\n/* W1-2 变更面板名称过滤输入框(工具条行内,紧凑) @author ddj 2026-09-20 */\n[data-edrv-view] .edrv-svn-name-filter { width: 168px; padding: 1px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 5px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; line-height: 14px; }\n[data-edrv-view] .edrv-svn-name-filter:focus { outline: none; border-color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-svn-name-filter::placeholder { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n/* W2-3 远端更新提示条(工具条上方;warn = 失败降级) @author ddj 2026-09-20 */\n[data-edrv-view] .edrv-svn-hintbar { display: flex; align-items: center; gap: 6px; margin: 0 10px 4px 12px; padding: 3px 8px; border-radius: 5px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); font-size: 11px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svn-hintbar-warn { background: rgba(217, 83, 79, 0.12); color: var(--dsw-alias-state-error-primary, #d9534f); }\n/* W2-5 疑似改名标记(行内 ⇄;hover 见 tooltip) */\n[data-edrv-view] .edrv-svn-pair-mark { flex-shrink: 0; color: var(--dsw-alias-state-warn-primary, #7c3aed); font-size: 11px; cursor: help; }\n/* W2-1 补丁对话框 / W2-2 目录对比对话框 @author ddj 2026-09-20 */\n[data-edrv-view] .edrv-svn-patch-dialog { max-width: calc(100vw - 48px); }\n[data-edrv-view] .edrv-svn-patch-head { display: flex; align-items: center; gap: 8px; padding-bottom: 8px; }\n[data-edrv-view] .edrv-svn-patch-notes { display: flex; flex-direction: column; gap: 4px; padding-bottom: 6px; }\n[data-edrv-view] .edrv-svn-patch-warn { color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n[data-edrv-view] .edrv-svn-patch-pre { max-height: 46vh; overflow: auto; margin: 0 0 8px; padding: 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f7f9f9); color: var(--dsw-alias-label-primary, #1f2933); font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; line-height: 1.5; white-space: pre; user-select: text; }\n[data-edrv-view] .edrv-svn-patch-foot { display: flex; align-items: center; gap: 8px; }\n/* AI 智能整理弹窗(11-ai-changelist-triage):预览三分组卡 + 执行进度 @author ddj 2026-09-23 */\n[data-edrv-view] .edrv-svnplan-dialog { max-width: calc(100vw - 48px); }\n[data-edrv-view] .edrv-svnplan-head { display: flex; align-items: center; gap: 8px; padding-bottom: 4px; }\n[data-edrv-view] .edrv-svnplan-meta { display: flex; gap: 10px; padding-bottom: 6px; }\n[data-edrv-view] .edrv-svnplan-note { color: var(--dsw-alias-state-warn-primary, #b7791f); font-size: 10px; }\n[data-edrv-view] .edrv-svnplan-sec { border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; padding: 6px 8px; margin-bottom: 8px; }\n[data-edrv-view] .edrv-svnplan-sechead { display: flex; align-items: center; gap: 6px; }\n[data-edrv-view] .edrv-svnplan-sectitle { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-svnplan-list { max-height: 26vh; overflow: auto; padding-left: 18px; }\n[data-edrv-view] .edrv-svnplan-card { border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); padding: 3px 0; }\n[data-edrv-view] .edrv-svnplan-row { display: flex; align-items: center; gap: 6px; }\n[data-edrv-view] .edrv-svnplan-item { display: flex; align-items: center; gap: 6px; padding-left: 18px; }\n[data-edrv-view] .edrv-svnplan-groupname { font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-svnplan-path { font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 46ch; }\n[data-edrv-view] .edrv-svnplan-reason { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 30ch; }\n[data-edrv-view] .edrv-svnplan-stage { display: flex; align-items: center; gap: 8px; padding-bottom: 6px; }\n[data-edrv-view] .edrv-svnplan-badge { border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 5px; padding: 1px 8px; font-size: 10px; color: var(--dsw-alias-label-secondary, #52606d); background: var(--dsw-alias-bg-layer-2, #f7f9f9); white-space: nowrap; }\n[data-edrv-view] .edrv-svnplan-badge-cur { font-family: var(--ds-font-family-code, ui-monospace, monospace); overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-svnplan-bar { height: 6px; border-radius: 3px; background: var(--dsw-alias-bg-layer-2, #f7f9f9); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); overflow: hidden; margin-bottom: 8px; }\n[data-edrv-view] .edrv-svnplan-bar-in { height: 100%; background: var(--dsw-alias-state-info-primary, #2f6fed); transition: width .2s; }\n[data-edrv-view] .edrv-svnplan-logwrap { max-height: 40vh; overflow: auto; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; padding: 6px 8px; background: var(--dsw-alias-bg-layer-2, #f7f9f9); }\n[data-edrv-view] .edrv-svnplan-log { font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; line-height: 1.6; color: var(--dsw-alias-label-secondary, #52606d); user-select: text; }\n[data-edrv-view] .edrv-svnplan-log-bad { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-svnplan-foot { display: flex; align-items: center; gap: 8px; }\n[data-edrv-view] .edrv-svnplan-primary { font-weight: 600; border-color: var(--dsw-alias-state-info-primary, #2f6fed); }\n[data-edrv-view] .edrv-svn-sum-form { display: flex; align-items: center; gap: 10px; padding-bottom: 8px; }\n[data-edrv-view] .edrv-svn-sum-list { max-height: 44vh; overflow: auto; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; padding: 2px; margin-bottom: 8px; }\n[data-edrv-view] .edrv-svnlog-path-kind { flex-shrink: 0; padding: 0 5px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; }\n\n/* ===== 通用弹窗外壳(ModalShell)+ SVN 日志弹窗 @author ddj 2026-09-16 ===== */\n/* z-index 190:落在既有阶梯内(命令栏 200 > 片段二级 197 > 片段一级 195 > 190),\n 不遮挡命令栏;既有浮层数值不受影响(见 tests/overlayZOrder.test.ts)。 */\n[data-edrv-view] .edrv-modal-mask { position: fixed; inset: 0; z-index: 190; display: flex; align-items: center; justify-content: center; padding: 24px; box-sizing: border-box; background: var(--dsw-alias-bg-mask-drop, #000000aa); }\n[data-edrv-view] .edrv-svnlog-dialog { position: relative; display: flex; flex-direction: column; gap: 8px; }\n[data-edrv-view] .edrv-svnlog-head { display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; }\n[data-edrv-view] .edrv-svnlog-title { margin: 0; font-size: 15px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-svnlog-target { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-svnlog-filter { display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; }\n[data-edrv-view] .edrv-svnlog-field { flex: 0 0 auto; padding: 4px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-svnlog-search { min-width: 160px; flex: 1 1 220px; padding: 4px 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-svnlog-date { padding: 2px 4px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-svnlog-check { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); white-space: nowrap; cursor: pointer; }\n[data-edrv-view] .edrv-svnlog-error { padding: 4px 8px; border: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n/* P0-14 上中下三段全宽:body 纵向铺满弹窗(外框高度由拖拽受控) */\n[data-edrv-view] .edrv-svnlog-body { display: flex; flex-direction: column; gap: 6px; flex: 1 1 auto; min-height: 0; }\n/* 上段修订列表:列头行 + 单行五列(版本/动作/作者/日期/信息),列宽由 cell 类与 nth-child 对齐(P0-12/D30) */\n[data-edrv-view] .edrv-svnlog-list { flex: 0 0 auto; display: flex; flex-direction: column; overflow: auto; border: 2px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 8px; padding: 4px; }\n[data-edrv-view] .edrv-svnlog-cols { display: flex; align-items: center; gap: 6px; padding: 2px 6px; border-bottom: 2px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-secondary, #52606d); flex-shrink: 0; }\n[data-edrv-view] .edrv-svnlog-cols .edrv-svnlog-col:nth-child(1) { width: 52px; flex: none; }\n[data-edrv-view] .edrv-svnlog-cols .edrv-svnlog-col:nth-child(2) { width: 52px; flex: none; }\n[data-edrv-view] .edrv-svnlog-cols .edrv-svnlog-col:nth-child(3) { width: 88px; flex: none; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-svnlog-cols .edrv-svnlog-col:nth-child(4) { width: 82px; flex: none; }\n[data-edrv-view] .edrv-svnlog-cols .edrv-svnlog-col:nth-child(5) { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-svnlog-col-sortable { cursor: pointer; }\n[data-edrv-view] .edrv-svnlog-col-sortable:hover { color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svnlog-col-on { color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svnlog-sort-reset { flex: none; }\n[data-edrv-view] .edrv-svnlog-item { display: flex; align-items: center; gap: 6px; padding: 2px 6px; border-radius: 6px; cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-svnlog-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-svnlog-item.edrv-svnlog-item-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); }\n[data-edrv-view] .edrv-svnlog-item-copied .edrv-svnlog-cell-msg,\n[data-edrv-view] .edrv-svnlog-item-copied .edrv-svnlog-rev { color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svnlog-cell { overflow: hidden; text-overflow: ellipsis; font-size: 11px; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svnlog-cell-rev { width: 52px; flex: none; }\n[data-edrv-view] .edrv-svnlog-cell-act { width: 52px; flex: none; display: inline-flex; gap: 3px; }\n[data-edrv-view] .edrv-svnlog-cell-author { width: 88px; flex: none; }\n[data-edrv-view] .edrv-svnlog-cell-date { width: 82px; flex: none; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-cell-msg { flex: 1 1 auto; }\n[data-edrv-view] .edrv-svnlog-rev { font-family: var(--ds-font-family-code, ui-monospace, monospace); font-weight: 700; color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svnlog-badge { display: inline-flex; align-items: center; justify-content: center; width: 12px; height: 12px; border-radius: 3px; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 9px; font-weight: 700; }\n[data-edrv-view] .edrv-svnlog-badge-modified { color: var(--dsw-alias-brand-primary, #2563eb); background: rgba(37,99,235,.12); }\n[data-edrv-view] .edrv-svnlog-badge-added { color: var(--dsw-alias-state-warn-primary, #7c3aed); background: rgba(124,58,237,.12); }\n[data-edrv-view] .edrv-svnlog-badge-deleted { color: #b91c1c; background: rgba(185,28,28,.12); }\n[data-edrv-view] .edrv-svnlog-badge-plain { color: var(--dsw-alias-label-tertiary, #9aa5b1); background: var(--dsw-alias-bg-layer-2, #f0f4f4); }\n[data-edrv-view] .edrv-svnlog-more { padding: 6px 4px 2px; text-align: center; }\n/* P0-14 三段 pane 公共外观(上段列表自带 .edrv-svnlog-list 边框) */\n[data-edrv-view] .edrv-svnlog-pane { border: 2px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 8px; padding: 8px 10px; overflow: hidden; }\n[data-edrv-view] .edrv-svnlog-msgpane { flex: 0 0 auto; display: flex; flex-direction: column; }\n[data-edrv-view] .edrv-svnlog-pathspane { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }\n/* P0-13/P0-14:分段横向拖拽分隔条 + 变更路径独立滚动容器 */\n[data-edrv-view] .edrv-svnlog-hsplit { flex: 0 0 6px; cursor: row-resize; margin: 2px 0; border-radius: 3px; touch-action: none; }\n[data-edrv-view] .edrv-svnlog-hsplit:hover, [data-edrv-view] .edrv-svnlog-hsplit:active { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.28)); }\n[data-edrv-view] .edrv-svnlog-paths-wrap { flex: 1 1 auto; min-height: 0; overflow: auto; display: flex; flex-direction: column; }\n[data-edrv-view] .edrv-svnlog-meta { display: flex; align-items: center; gap: 10px; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); flex-wrap: wrap; }\n[data-edrv-view] .edrv-svnlog-date { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-msgpane pre.edrv-svnlog-body { margin: 6px 0 0; padding: 6px 8px; border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; line-height: 1.6; white-space: pre-wrap; word-break: break-word; overflow: auto; flex: 1 1 auto; min-height: 0; }\n/* P0-14 外框尺寸手柄(右缘调宽 / 底缘调高 / 右下角双向) */\n[data-edrv-view] .edrv-svnlog-grip { position: absolute; z-index: 2; touch-action: none; }\n[data-edrv-view] .edrv-svnlog-grip-r { top: 12px; bottom: 12px; right: 0; width: 8px; cursor: ew-resize; }\n[data-edrv-view] .edrv-svnlog-grip-b { left: 12px; right: 12px; bottom: 0; height: 8px; cursor: ns-resize; }\n[data-edrv-view] .edrv-svnlog-grip-c { right: 0; bottom: 0; width: 14px; height: 14px; cursor: nwse-resize; border-radius: 3px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); }\n[data-edrv-view] .edrv-svnlog-grip:hover, [data-edrv-view] .edrv-svnlog-grip:active { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.35)); }\n[data-edrv-view] .edrv-svnlog-paths-head { display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-secondary, #52606d); margin-bottom: 4px; }\n[data-edrv-view] .edrv-svnlog-hint { font-weight: 400; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-paths { display: flex; flex-direction: column; gap: 1px; }\n[data-edrv-view] .edrv-svnlog-path { display: flex; align-items: center; gap: 6px; height: 22px; padding: 0 6px; border-radius: 5px; cursor: default; white-space: nowrap; }\n[data-edrv-view] .edrv-svnlog-path:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-svnlog-path-dim .edrv-svnlog-pathtext,\n[data-edrv-view] .edrv-svnlog-path-dim .edrv-svnlog-copyfrom { opacity: .45; }\n[data-edrv-view] .edrv-svnlog-pathtext { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; font-size: 11px; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svnlog-copyfrom { flex: 0 1 160px; overflow: hidden; text-overflow: ellipsis; font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-svnlog-kind { font-size: 10px; padding: 0 5px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-acts { display: none; align-items: center; gap: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svnlog-path:hover .edrv-svnlog-acts { display: inline-flex; }\n[data-edrv-view] .edrv-svnlog-footwrap { display: flex; flex-direction: column; gap: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svnlog-foot { display: flex; align-items: center; gap: 10px; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-btns { display: flex; align-items: center; gap: 6px; }\n/* ===== SVN 日志统计窗(P1-10)@author ddj 2026-09-17 ===== */\n[data-edrv-view] .edrv-svnlog-stats { display: flex; flex-direction: column; max-height: 82vh; }\n[data-edrv-view] .edrv-svnlog-stats-head { display: flex; align-items: center; gap: 8px; padding: 12px 16px 0; }\n[data-edrv-view] .edrv-svnlog-stats-body { display: flex; flex-direction: column; gap: 14px; padding: 10px 16px 16px; overflow: auto; }\n[data-edrv-view] .edrv-svnlog-stat-line { display: flex; gap: 16px; flex-wrap: wrap; font-size: 12px; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svnlog-stat-block { display: flex; flex-direction: column; gap: 8px; }\n[data-edrv-view] .edrv-svnlog-stat-label { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svnlog-stat-duo { display: flex; gap: 18px; align-items: flex-start; flex-wrap: wrap; }\n[data-edrv-view] .edrv-svnlog-stat-hist { flex: 1 1 260px; display: flex; flex-direction: column; gap: 4px; min-width: 220px; }\n[data-edrv-view] .edrv-svnlog-stat-row { display: flex; align-items: center; gap: 8px; font-size: 11px; }\n[data-edrv-view] .edrv-svnlog-stat-name { width: 110px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-svnlog-stat-barwrap { flex: 1; height: 12px; border-radius: 6px; background: rgba(127,127,127,.15); overflow: hidden; }\n[data-edrv-view] .edrv-svnlog-stat-bar { display: block; height: 100%; border-radius: 6px; }\n[data-edrv-view] .edrv-svnlog-stat-count { width: 36px; text-align: right; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-svnlog-stat-pie { width: 120px; height: 120px; flex-shrink: 0; border-radius: 50%; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-svnlog-stat-days { display: flex; align-items: flex-end; gap: 2px; height: 120px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); overflow-x: auto; }\n[data-edrv-view] .edrv-svnlog-stat-day { flex: 1 0 6px; min-width: 6px; height: 100%; display: flex; flex-direction: column; justify-content: flex-end; }\n[data-edrv-view] .edrv-svnlog-stat-seg { display: block; width: 100%; }\n/* ===== SVN 日志区间弹窗(P1-6)@author ddj 2026-09-17 ===== */\n[data-edrv-view] .edrv-svnlog-range-body { display: flex; flex-direction: column; gap: 12px; padding: 14px 16px 16px; }\n[data-edrv-view] .edrv-svnlog-range-row { display: flex; gap: 14px; flex-wrap: wrap; }\n[data-edrv-view] .edrv-svnlog-range-input { width: 110px; padding: 4px 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-svnlog-range-btns { display: flex; gap: 8px; justify-content: flex-end; }\n/* SVN 日志 WC 版号行加粗(P1-9) */\n[data-edrv-view] .edrv-svnlog-item-wc { font-weight: 700; }\n/* SVN 日志 merged 行(P1-5):灰字 + 缩进(缩进量按层级内联),前置「↳」标记 */\n[data-edrv-view] .edrv-svnlog-item-merged { color: var(--dsw-alias-label-tertiary, #7b8794); }\n[data-edrv-view] .edrv-svnlog-item-merged .edrv-svnlog-merge-mark { flex: 0 0 auto; color: var(--dsw-alias-label-tertiary, #7b8794); }\n[data-edrv-view] .edrv-svnlog-item-merged .edrv-svnlog-cell-msg { font-style: italic; }\n/* ===== 诊断日志弹窗(LogDialog)@author ddj 2026-09-17 ===== */\n[data-edrv-view] .edrv-dlog-dialog { display: flex; flex-direction: column; gap: 8px; max-height: 88vh; }\n[data-edrv-view] .edrv-dlog-head { display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; }\n[data-edrv-view] .edrv-dlog-title { margin: 0; font-size: 15px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-dlog-file { max-width: 200px; padding: 4px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-dlog-level { padding: 4px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-dlog-search { min-width: 120px; flex: 0 1 200px; padding: 4px 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-dlog-auto { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); white-space: nowrap; cursor: pointer; }\n[data-edrv-view] .edrv-dlog-error { padding: 4px 8px; border: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n[data-edrv-view] .edrv-dlog-scroll { flex: 1 1 auto; min-height: 240px; overflow: auto; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 8px; padding: 4px 0; background: var(--dsw-alias-bg-layer-1, #fff); }\n[data-edrv-view] .edrv-dlog-row { display: flex; align-items: baseline; gap: 8px; padding: 1px 8px; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; line-height: 1.55; }\n[data-edrv-view] .edrv-dlog-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.06)); }\n[data-edrv-view] .edrv-dlog-at { flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-dlog-lvl { flex-shrink: 0; width: 26px; text-align: center; font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-dlog-text { flex: 1; min-width: 0; white-space: pre-wrap; word-break: break-word; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-dlog-row-error .edrv-dlog-text { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-dlog-row-warn .edrv-dlog-text { color: var(--dsw-alias-state-warning-primary, #b45309); }\n[data-edrv-view] .edrv-dlog-row-debug .edrv-dlog-text { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-dlog-foot { display: flex; align-items: center; gap: 10px; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex-shrink: 0; }\n[data-edrv-view] .edrv-dlog-path { font-family: var(--ds-font-family-code, ui-monospace, monospace); max-width: 46%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-dlog-stat { white-space: nowrap; }\n[data-edrv-view] .edrv-dlog-switch { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); white-space: nowrap; cursor: pointer; flex-shrink: 0; }\n/* SVN 更新结果条(P3:update 条目级明细,可关闭) */\n[data-edrv-view] .edrv-svnres { display: flex; align-items: flex-start; gap: 8px; flex-shrink: 0; padding: 5px 10px; font-size: 11px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, rgba(15,157,88,.06)); }\n[data-edrv-view] .edrv-svnres-head { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-svnres-list { display: flex; flex-wrap: wrap; gap: 4px 10px; min-width: 0; }\n[data-edrv-view] .edrv-svnres-item { display: inline-flex; align-items: center; gap: 3px; font-family: var(--ds-font-family-code, ui-monospace, monospace); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-svnres-item.edrv-svnres-conflict { color: var(--dsw-alias-state-error-primary, #d9534f); font-weight: 700; }\n\n/* ===== 侧栏形态(betterSidebar 面板内编辑区) ===== */\n[data-edrv-view][data-edrv-layout='side'] { box-sizing: border-box; height: 100%; }\n\n/* ===== 侧边栏引导条(旧页签形态、未装 betterSidebar 时) ===== */\n[data-edrv-view] .edrv-side-hint { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; flex-wrap: wrap; padding: 6px 12px; font-size: 12px; color: var(--dsw-alias-label-secondary, #52606d); background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, #f0f4f4)); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-side-hint-text { white-space: nowrap; }\n[data-edrv-view] .edrv-side-hint-cmd { font-size: 11px; padding: 2px 6px; border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #ffffff); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-side-hint-close { margin-left: auto; border: none; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); cursor: pointer; font-size: 14px; line-height: 1; padding: 2px 6px; border-radius: 6px; flex-shrink: 0; }\n[data-edrv-view] .edrv-side-hint-close:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n\n/* ===== search panel (sidebar, VSCode search view) ===== */\n[data-edrv-view] .edrv-search-panel { display: flex; flex-direction: column; min-height: 0; flex: 1; padding: 6px; gap: 4px; }\n[data-edrv-view] .edrv-search-qrow { display: flex; gap: 4px; }\n[data-edrv-view] .edrv-search-input { flex: 1; min-width: 0; height: 26px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search-input:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-opts { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-search-opt { min-width: 24px; height: 22px; padding: 0 6px; border: 1px solid transparent; border-radius: 5px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 11px; font-family: var(--ds-font-family-code, ui-monospace, monospace); cursor: pointer; }\n[data-edrv-view] .edrv-search-opt:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-opt.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); border-color: var(--dsw-alias-border-l2, #d5dde3); }\n[data-edrv-view] .edrv-search-spacer { flex: 1; }\n[data-edrv-view] .edrv-search-summary { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); padding: 2px 4px; }\n[data-edrv-view] .edrv-search-results { flex: 1; min-height: 0; overflow: auto; font-size: 12px; }\n[data-edrv-view] .edrv-search-group { margin-bottom: 2px; }\n[data-edrv-view] .edrv-search-file { display: flex; align-items: center; gap: 4px; height: 22px; padding: 0 4px; border-radius: 5px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-search-file:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-chev { width: 12px; flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; text-align: center; }\n[data-edrv-view] .edrv-search-fname { font-weight: 600; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-search-fdir { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-search-fcount { flex-shrink: 0; min-width: 16px; height: 15px; padding: 0 4px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); font-size: 10px; line-height: 15px; text-align: center; }\n[data-edrv-view] .edrv-search-line { display: flex; gap: 6px; padding: 1px 4px 1px 16px; border-radius: 4px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; overflow: hidden; }\n[data-edrv-view] .edrv-search-line.alt { background: var(--dsw-alias-bg-layer-1, #ffffff); }\n[data-edrv-view] .edrv-search-line:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-ln { flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; min-width: 26px; text-align: right; user-select: none; }\n[data-edrv-view] .edrv-search-text { overflow: hidden; text-overflow: ellipsis; white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; }\n[data-edrv-view] .edrv-search-hit { background: var(--dsw-alias-state-warn-primary, #e5b93f); color: var(--dsw-alias-label-primary-inverted, #1f2933); border-radius: 2px; padding: 0 1px; }\n[data-edrv-view] .edrv-search-empty { padding: 8px 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-search-error { padding: 6px 8px; border: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n[data-edrv-view] .edrv-search-warn { padding: 6px 8px; border: 1px solid var(--dsw-alias-state-warn-primary, rgba(240,173,78,.45)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover, rgba(240,173,78,.12)); color: var(--dsw-alias-state-warn-primary, #b8860b); font-size: 11px; word-break: break-all; }\n\n/* include/exclude filter rows (collapsible) */\n[data-edrv-view] .edrv-search-rows { display: flex; flex-direction: column; gap: 4px; padding: 2px 0 4px; }\n[data-edrv-view] .edrv-search-row { display: flex; align-items: center; gap: 4px; }\n[data-edrv-view] .edrv-search-field { flex: 1; min-width: 0; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 11px; outline: none; }\n[data-edrv-view] .edrv-search-field:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-field.dim { opacity: .45; }\n[data-edrv-view] .edrv-search-field::placeholder { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-search-toggle { min-width: 24px; height: 24px; padding: 0 5px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; line-height: 1; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-search-toggle:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-toggle.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); border-color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-search-toggle:disabled { opacity: .4; cursor: default; }\n\n/* ===== rules panel (sidebar, Codebuddy rules view) ===== */\n[data-edrv-view] .edrv-rules-panel { display: flex; flex-direction: column; min-width: 0; min-height: 0; flex: 1; padding: 6px; gap: 4px; }\n[data-edrv-view] .edrv-rules-tabs { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-tab { height: 24px; padding: 0 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; cursor: pointer; }\n[data-edrv-view] .edrv-rules-tab:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-tab.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); font-weight: 600; }\n[data-edrv-view] .edrv-rules-new { margin-left: auto; height: 24px; padding: 0 10px; border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-new:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-ws-line { font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); padding: 0 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 0 0 auto; user-select: none; }\n[data-edrv-view] .edrv-rules-hint { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); padding: 0 2px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-list { flex: 1; min-height: 0; overflow: auto; }\n[data-edrv-view] .edrv-rules-row { display: flex; align-items: center; gap: 4px; padding: 6px 4px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; }\n[data-edrv-view] .edrv-rules-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-row.off .edrv-rules-main { opacity: .5; }\n[data-edrv-view] .edrv-rules-main { flex: 1; min-width: 0; cursor: pointer; overflow: hidden; }\n[data-edrv-view] .edrv-rules-line1 { display: flex; align-items: center; gap: 6px; min-width: 0; }\n[data-edrv-view] .edrv-rules-sub { display: flex; align-items: center; gap: 5px; margin-top: 3px; min-width: 0; }\n[data-edrv-view] .edrv-rules-sublabel { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-file { font-weight: 600; font-size: 12px; color: var(--dsw-alias-label-primary, #1f2933); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-rules-path { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-rules-type { flex-shrink: 0; height: 15px; padding: 0 5px; border-radius: 999px; font-size: 10px; line-height: 15px; }\n[data-edrv-view] .edrv-rules-type-always { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.15)); color: var(--dsw-alias-state-success-primary, #0b7c46); }\n[data-edrv-view] .edrv-rules-type-auto { background: var(--dsw-alias-interactive-bg-hover-accent, rgba(79,140,255,.16)); color: var(--dsw-alias-link, #3367c9); }\n[data-edrv-view] .edrv-rules-type-manual { background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-rules-offtag { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-desc { font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; flex: 0 1 auto; }\n[data-edrv-view] .edrv-rules-actions { display: flex; align-items: center; gap: 2px; flex-shrink: 0; margin-left: auto; }\n[data-edrv-view] .edrv-rules-act { min-width: 22px; height: 22px; padding: 0 4px; border: none; border-radius: 5px; background: transparent; font-size: 12px; line-height: 1; cursor: pointer; color: var(--dsw-alias-label-secondary, #52606d); display: inline-flex; align-items: center; justify-content: center; }\n[data-edrv-view] .edrv-rules-act:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-switch { position: relative; width: 30px; height: 16px; border-radius: 999px; border: none; background: var(--dsw-alias-border-l2, #b9c4cc); cursor: pointer; transition: background .15s; flex-shrink: 0; padding: 0; }\n[data-edrv-view] .edrv-rules-switch.on { background: var(--dsw-alias-brand-primary, #7c5cff); }\n[data-edrv-view] .edrv-rules-knob { position: absolute; top: 2px; left: 2px; width: 12px; height: 12px; border-radius: 50%; background: var(--dsw-alias-bg-layer-1, #fff); transition: left .15s; }\n[data-edrv-view] .edrv-rules-switch.on .edrv-rules-knob { left: 16px; }\n[data-edrv-view] .edrv-rules-empty { padding: 10px 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); line-height: 1.6; }\n[data-edrv-view] .edrv-rules-err { padding: 6px 8px; border: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; word-break: break-all; }\n[data-edrv-view] .edrv-rules-editor { display: flex; flex-direction: column; min-height: 0; flex: 1; gap: 6px; }\n[data-edrv-view] .edrv-rules-editor-head { display: flex; align-items: center; justify-content: space-between; gap: 6px; font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-crumb { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-rules-editor-ctl { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-ctl-label { font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-select { height: 24px; padding: 0 4px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 11px; outline: none; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-select:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-rules-desc-input { flex: 1; min-width: 0; }\n[data-edrv-view] .edrv-rules-input { flex: 1; min-width: 0; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 11px; outline: none; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-rules-input:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-rules-body { flex: 1; min-height: 0; resize: none; padding: 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; line-height: 1.5; outline: none; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-rules-body:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-rules-editor-hint { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); line-height: 1.5; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-editor-foot { display: flex; justify-content: flex-end; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-save { height: 24px; padding: 0 14px; border: none; border-radius: 6px; background: var(--dsw-alias-brand-primary, #0f9d58); color: var(--dsw-alias-label-primary-inverted, #fff); font-size: 12px; cursor: pointer; }\n[data-edrv-view] .edrv-rules-save:disabled { opacity: .5; cursor: default; }\n\n/* 命令栏(Ctrl+Shift+P / F1):body 级 portal 浮层,故不依赖编辑区几何。\n ⚠️ 浮层 z-index 阶梯(自下而上;改动务必保持顺序,tests/overlayZOrder.test.ts 守约):\n 编辑器内浮层 60(.edrv-search-pop) / 71(.edrv-ctxmenu)\n < 190 命令栏遮罩 < 200 命令栏\n < 195 片段浮窗遮罩 < 197 片段二级弹窗遮罩\n 命令栏必须**高于**片段浮窗:曾因片段遮罩(192) 压过命令栏(191),导致片段浮窗打开时\n 命令栏被整体盖住,按 Ctrl+Shift+P 因「已打开即早退」而毫无反应(表现为快捷键失效)。 */\n[data-edrv-view] .edrv-palette-mask { position: fixed; inset: 0; z-index: 190; background: rgba(0, 0, 0, .28); }\n[data-edrv-view] .edrv-palette { position: fixed; top: 12vh; left: 50%; transform: translateX(-50%); z-index: 200; width: min(580px, calc(100vw - 32px)); max-height: 64vh; display: flex; flex-direction: column; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 12px 34px rgba(31, 41, 51, .24); overflow: hidden; }\n[data-edrv-view] .edrv-palette-input { height: 38px; flex: 0 0 auto; padding: 0 12px; border: none; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: transparent; color: var(--dsw-alias-label-primary, #1f2933); font-size: 13px; outline: none; }\n[data-edrv-view] .edrv-palette-list { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 4px; }\n[data-edrv-view] .edrv-palette-row { display: flex; align-items: center; gap: 8px; padding: 6px 10px; border-radius: 6px; font-size: 12px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; }\n[data-edrv-view] .edrv-palette-row.edrv-palette-sel { background: var(--dsw-alias-interactive-bg-hover, rgba(15, 157, 88, .10)); }\n[data-edrv-view] .edrv-palette-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-palette-cat { flex: 0 0 auto; font-size: 10px; padding: 1px 7px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-tertiary, #7b8794); }\n[data-edrv-view] .edrv-palette-key { flex: 0 0 auto; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 10px; padding: 1px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 5px; background: var(--dsw-alias-bg-layer-1, #f7f9fa); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-palette-empty { padding: 14px 10px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #7b8794); text-align: center; }\n[data-edrv-view] .edrv-palette-notice { flex: 0 0 auto; padding: 6px 10px; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 11px; color: var(--dsw-alias-state-warn-primary, #b7791f); }\n\n/* 代码片段选择器(配置 / 插入):居中浮窗 + 新建二级弹窗。\n 卡片复用 mcp.css 的 .vsm-mcp-dialog(与「添加 MCP」「工作区选择」同一视觉语言),\n 此处只补遮罩、尺寸与列表布局。⚠️ 根节点须带 data-edrv-view,否则这些规则全部失配。 */\n[data-edrv-view] .edrv-snip-mask { position: fixed; inset: 0; z-index: 195; display: flex; align-items: center; justify-content: center; padding: 24px; box-sizing: border-box; background: var(--dsw-alias-bg-mask-drop, rgba(0, 0, 0, .55)); }\n/* 二级弹窗叠在一级浮窗之上(仍在命令栏之下,见上方阶梯说明) */\n[data-edrv-view] .edrv-snip-mask-top { z-index: 197; }\n[data-edrv-view] .edrv-snip-dialog { display: flex; flex-direction: column; overflow: hidden; width: min(620px, calc(100vw - 48px)); }\n[data-edrv-view] .edrv-snip-hint { margin: 0 0 12px; font-size: 12px; line-height: 1.6; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-snip-list { display: flex; flex-direction: column; gap: 1px; min-height: 0; max-height: 46vh; overflow: auto; }\n[data-edrv-view] .edrv-snip-group { padding: 12px 2px 4px; font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-secondary, #aaa); }\n[data-edrv-view] .edrv-snip-row { display: flex; align-items: center; gap: 4px; width: 100%; box-sizing: border-box; padding: 2px; border: none; border-radius: 8px; background: transparent; text-align: left; color: var(--dsw-alias-label-primary, #e6e6e6); font: inherit; }\n[data-edrv-view] .edrv-snip-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255, 255, 255, .06)); }\n[data-edrv-view] button.edrv-snip-row { cursor: pointer; }\n[data-edrv-view] .edrv-snip-row-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; padding: 8px 10px; border: none; border-radius: 6px; background: transparent; text-align: left; cursor: pointer; color: inherit; font: inherit; }\n[data-edrv-view] .edrv-snip-label { font-size: 13px; font-weight: 600; color: var(--dsw-alias-label-primary, #e6e6e6); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-snip-desc { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-snip-src { flex: 0 0 auto; padding-right: 6px; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-snip-warn { flex: 0 0 auto; font-size: 11px; padding: 2px 7px; border-radius: 999px; background: var(--dsw-alias-state-warn-tertiary, rgba(229, 185, 63, .16)); color: var(--dsw-alias-state-warn-primary, #e5b93f); white-space: nowrap; }\n[data-edrv-view] .edrv-snip-act { flex: 0 0 auto; width: 26px; height: 26px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 13px; line-height: 1; cursor: pointer; }\n[data-edrv-view] .edrv-snip-act:hover { background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217, 83, 79, .16)); color: var(--dsw-alias-state-error-primary, #f07878); }\n[data-edrv-view] .edrv-snip-empty { padding: 12px 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); line-height: 1.6; }\n/* 当前文件语言提示条(片段按语言绑定,明确告知生效范围) */\n[data-edrv-view] .edrv-snip-langbar { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; margin: 0 0 10px; padding: 8px 10px; border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #2b2b2b); font-size: 12px; color: var(--dsw-alias-label-secondary, #aaa); }\n[data-edrv-view] .edrv-snip-langbar b { color: var(--dsw-alias-label-primary, #e6e6e6); }\n/* 二级弹窗的动作按钮(原生 .vsm-mcp-dialog-actions 已提供排版与按钮样式) */\n[data-edrv-view] .edrv-snip-dialog .vsm-mcp-dialog-actions { flex-wrap: wrap; }\n/* 删除图标按钮:.vsm-danger 的规则全部限定在 .vsm-mcp-actions button 之下,裸用无样式,此处补自有类 */\n[data-edrv-view] .edrv-snip-act.edrv-snip-danger:hover { background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217, 83, 79, .16)); color: var(--dsw-alias-state-error-primary, #f07878); }\n/* 浮窗内的原生空态(.vsm-mcp-empty 默认为整页尺寸)压缩为对话框尺寸 */\n[data-edrv-view] .edrv-snip-dialog .vsm-mcp-empty { padding: 26px 16px; border: 0; }\n\n\n\n\n\n/* 调试(DAP):断点圆点 / 停帧行 / 浮动调试工具条。\n 圆点挂在 Monaco glyphMargin(glyphMarginClassName),行背景为 isWholeLine className;\n 工具条绝对定位于编辑区右上(editorArea relative 由 .edrv-editor-area 自身定位)。 */\n/* 断点圆点:装饰类占满整行,圆点经 ::before 在本行盒子内居中(行归属明确、不跨行界) */\n[data-edrv-view] .edrv-dap-bp { cursor: pointer; }\n[data-edrv-view] .edrv-dap-bp::before { content: ''; display: block; width: 7px; height: 7px; margin: 6px auto 0; border-radius: 50%; background: var(--dsw-alias-state-error-primary, #e51400); }\n[data-edrv-view] .edrv-dap-bp-off { cursor: pointer; }\n[data-edrv-view] .edrv-dap-bp-off::before { content: ''; display: block; box-sizing: border-box; width: 7px; height: 7px; margin: 6px auto 0; border-radius: 50%; border: 1px solid var(--dsw-alias-label-tertiary, #9aa5b1); opacity: .6; }\n/* 未验证断点(适配器真实回执 verified:false):空心红圈,对齐 VS Code 空心圆语义 */\n[data-edrv-view] .edrv-dap-bp-unverified { cursor: pointer; }\n[data-edrv-view] .edrv-dap-bp-unverified::before { content: ''; display: block; box-sizing: border-box; width: 7px; height: 7px; margin: 6px auto 0; border-radius: 50%; border: 1px solid var(--dsw-alias-state-error-primary, #e51400); opacity: .75; }\n[data-edrv-view] .edrv-dap-paused-line { background: var(--dsw-alias-state-warn-tertiary, rgba(229, 185, 63, .22)); }\n[data-edrv-view] .edrv-dap-paused-glyph { cursor: pointer; }\n[data-edrv-view] .edrv-dap-paused-glyph::before { content: ''; display: block; width: 5px; height: 12px; margin: 4px auto 0; border-radius: 2px; background: var(--dsw-alias-state-warn-primary, #e5b93f); }\n[data-edrv-view] .edrv-editor-area { position: relative; }\n/* launch.json 右下角「添加配置」按钮(VSCode 同款形态):仅 launch.json 打开时渲染 */\n[data-edrv-view] .edrv-addcfg { position: absolute; right: 14px; bottom: 10px; z-index: 13; padding: 4px 12px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #f7f9fa); color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; line-height: 18px; cursor: pointer; box-shadow: 0 1px 4px rgba(0, 0, 0, .1); }\n[data-edrv-view] .edrv-addcfg:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .15)); color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-dapbar { position: absolute; top: 6px; right: 14px; z-index: 12; display: none; align-items: center; gap: 3px; padding: 3px 5px; border-radius: 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, #f7f9fa); box-shadow: 0 2px 8px rgba(0, 0, 0, .12); }\n[data-edrv-view] .edrv-dapbar.on { display: flex; border-color: var(--dsw-alias-border-l2, #cdd6da); }\n[data-edrv-view] .edrv-dapbar-grip { flex: 0 0 auto; width: 16px; height: 22px; display: inline-flex; align-items: center; justify-content: center; cursor: grab; user-select: none; color: var(--dsw-alias-label-tertiary, #7b8794); font-size: 12px; }\n[data-edrv-view] .edrv-dapbar-grip:active, [data-edrv-view] .edrv-dapbar.dragging .edrv-dapbar-grip { cursor: grabbing; }\n[data-edrv-view] .edrv-dapbar.dragging { user-select: none; }\n[data-edrv-view] .edrv-dapbar-cfg { max-width: 220px; height: 22px; font-size: 11px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); }\n[data-edrv-view] .edrv-dapbar-btn { min-width: 24px; height: 22px; padding: 0 6px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, inherit); font-size: 12px; line-height: 1; cursor: pointer; }\n[data-edrv-view] .edrv-dapbar-btn:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .15)); }\n[data-edrv-view] .edrv-dapbar-btn:disabled { opacity: .35; cursor: default; }\n[data-edrv-view] .edrv-dapbar-phase { padding: 0 4px; font-size: 11px; white-space: nowrap; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-dapbar-phase.paused { color: var(--dsw-alias-state-warn-primary, #b7791f); font-weight: 600; }\n[data-edrv-view] .edrv-dapbar-err { max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; color: var(--dsw-alias-state-error-primary, #e05252); }\n\n/* 调试面板(活动栏「调试」页签):四段折叠区 + 断点列表 + REPL。 */\n[data-edrv-view] .edrv-dappanel { display: flex; flex-direction: column; gap: 10px; height: 100%; min-height: 0; overflow: auto; padding: 2px 2px 8px; }\n[data-edrv-view] .edrv-dappanel-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; row-gap: 4px; font-size: 12px; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-dappanel-phase { padding: 2px 8px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); }\n[data-edrv-view] .edrv-dappanel-phase.paused { background: var(--dsw-alias-state-warn-tertiary, rgba(229, 185, 63, .18)); color: var(--dsw-alias-state-warn-primary, #b7791f); font-weight: 600; }\n[data-edrv-view] .edrv-dappanel-cfg { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-dappanel-pid { font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; }\n[data-edrv-view] .edrv-dappanel-err { color: var(--dsw-alias-state-error-primary, #e05252); }\n[data-edrv-view] .edrv-dapseg { display: flex; flex-direction: column; gap: 2px; min-height: 0; }\n[data-edrv-view] .edrv-dapseg-body { min-height: 0; overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain; }\n/* 段间分隔条(splitview sash):拖动调整相邻两段高度占比;各段高度由 DebugPanel 内联接管。 */\n[data-edrv-view] .edrv-dapseg-sash { flex: 0 0 auto; height: 4px; margin: 2px 0; border-radius: 2px; background: transparent; cursor: row-resize; }\n[data-edrv-view] .edrv-dapseg-sash:hover, [data-edrv-view] .edrv-dapseg-sash.dragging { background: var(--dsw-alias-border-l2, #cdd6da); }\n/* 折叠段头:chevron + 标题 + 悬浮动作区(动作 hover 显隐;REPL 头不参与折叠)。 */\n[data-edrv-view] .edrv-dapseg-head { display: flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-tertiary, #7b8794); padding: 2px 2px; cursor: pointer; border-radius: 4px; }\n[data-edrv-view] .edrv-dapseg-head:hover { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-daprepl .edrv-dapseg-head { cursor: default; padding: 2px 0; }\n[data-edrv-view] .edrv-dapseg-chevron { flex: 0 0 auto; width: 14px; text-align: center; font-size: 10px; }\n[data-edrv-view] .edrv-dapseg-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-dapseg-act { flex: 0 0 auto; min-width: 20px; height: 18px; padding: 0 4px; border: none; border-radius: 4px; background: transparent; color: var(--dsw-alias-label-tertiary, #7b8794); font-size: 11px; line-height: 1; cursor: pointer; opacity: 0; }\n[data-edrv-view] .edrv-dapseg-head:hover .edrv-dapseg-act { opacity: 1; }\n[data-edrv-view] .edrv-dapseg-act:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .15)); color: var(--dsw-alias-label-primary, inherit); }\n[data-edrv-view] .edrv-dapempty { font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); padding: 4px 2px; }\n[data-edrv-view] .edrv-dapframe { display: flex; align-items: baseline; gap: 8px; padding: 3px 4px; border-radius: 6px; cursor: pointer; font-size: 12px; }\n[data-edrv-view] .edrv-dapframe:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .12)); }\n[data-edrv-view] .edrv-dapframe-name { color: var(--dsw-alias-label-primary, inherit); font-weight: 600; }\n[data-edrv-view] .edrv-dapframe-loc { color: var(--dsw-alias-label-tertiary, #9aa5b1); font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-dapscope { font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-secondary, #52606d); padding: 4px 2px 1px; }\n[data-edrv-view] .edrv-dapvar { display: flex; align-items: baseline; gap: 6px; width: 100%; box-sizing: border-box; font-size: 12px; padding: 1px 2px; min-width: 0; }\n[data-edrv-view] .edrv-dapvar-tw { flex: 0 0 auto; width: 14px; border: none; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); cursor: pointer; font-size: 10px; padding: 0; }\n[data-edrv-view] span.edrv-dapvar-tw { cursor: default; }\n[data-edrv-view] .edrv-dapvar-name { flex: 0 1 34%; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-primary, inherit); font-family: var(--ds-font-family-code, ui-monospace, monospace); white-space: nowrap; }\n[data-edrv-view] .edrv-dapvar-val { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-dapvar-type { flex: 0 0 auto; font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-dapframe.selected { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .16)); outline: 1px solid var(--dsw-alias-border-l2, #cdd6da); }\n[data-edrv-view] .edrv-dapwatch { display: flex; align-items: baseline; gap: 6px; width: 100%; box-sizing: border-box; min-width: 0; font-size: 12px; padding: 1px 2px; }\n[data-edrv-view] .edrv-dapwatch-x { border: none; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); cursor: pointer; width: 14px; }\n[data-edrv-view] .edrv-dapwatch-x:hover { color: var(--dsw-alias-state-error-primary, #e05252); }\n[data-edrv-view] .edrv-dapwatch-add { padding: 2px 0; }\n[data-edrv-view] .edrv-dapbp { display: flex; align-items: center; gap: 6px; font-size: 12px; padding: 2px 2px; border-radius: 6px; cursor: pointer; }\n[data-edrv-view] .edrv-dapbp:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .12)); }\n[data-edrv-view] .edrv-dapbp:active { background: var(--dsw-alias-interactive-bg-pressed, rgba(127, 127, 127, .2)); }\n[data-edrv-view] .edrv-dapbp-dot { flex: 0 0 auto; width: 9px; height: 9px; border-radius: 50%; background: var(--dsw-alias-state-error-primary, #e51400); }\n[data-edrv-view] .edrv-dapbp-dot.off { background: transparent; border: 1.5px solid var(--dsw-alias-label-tertiary, #9aa5b1); opacity: .6; }\n[data-edrv-view] .edrv-dapbp-file { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; border: none; background: transparent; color: var(--dsw-alias-label-primary, inherit); cursor: pointer; padding: 0; font-size: 12px; }\n[data-edrv-view] .edrv-dapbp-dir { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; text-align: right; }\n[data-edrv-view] .edrv-dapbp-line { flex: 0 0 auto; font-size: 10px; padding: 1px 6px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-dapbp-x { flex: 0 0 auto; border: none; background: transparent; color: transparent; cursor: pointer; width: 14px; }\n[data-edrv-view] .edrv-dapbp:hover .edrv-dapbp-x { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-dapbp-x:hover { color: var(--dsw-alias-state-error-primary, #e05252) !important; }\n[data-edrv-view] .edrv-daprepl { display: flex; flex-direction: column; gap: 4px; }\n[data-edrv-view] .edrv-daprepl-log { display: flex; flex-direction: column; gap: 1px; max-height: 180px; overflow: auto; }\n[data-edrv-view] .edrv-daprepl-line { font-size: 11px; font-family: var(--ds-font-family-code, ui-monospace, monospace); color: var(--dsw-alias-label-secondary, #52606d); white-space: pre-wrap; word-break: break-all; display: flex; gap: 6px; }\n[data-edrv-view] .edrv-daprepl-line.out { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-daprepl-in { width: 100%; box-sizing: border-box; height: 26px; padding: 0 8px; font-size: 12px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); }\n[data-edrv-view] .edrv-dappanel-run { flex: 0 0 auto; width: 24px; height: 24px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, inherit); font-size: 13px; line-height: 1; cursor: pointer; }\n[data-edrv-view] .edrv-dappanel-run:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .15)); }\n[data-edrv-view] .edrv-dappanel-run:disabled { opacity: .35; cursor: default; background: transparent; }\n/* 面板顶部配置下拉(与编辑器浮动条 .edrv-dapbar-cfg 同视觉)。 */\n[data-edrv-view] .edrv-dappanel-cfg-select { max-width: 190px; height: 24px; padding: 0 4px; font-size: 11px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); }\n/* 断点行内编辑行(面板内展开编辑,控件复用 .edrv-bpwidget-* 视觉;左缩进对齐断点行文字列)。 */\n[data-edrv-view] .edrv-dapbp-edit { display: flex; align-items: center; gap: 6px; padding: 3px 2px 3px 20px; border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); }\n[data-edrv-view] .edrv-dapbp-edit .edrv-bpwidget-mode { height: 20px; }\n[data-edrv-view] .edrv-dapbp-edit .edrv-bpwidget-input { height: 20px; }\n/* 断点回执:未验证空心红圈(须排在 .off 之后,禁用态优先展示灰圈语义)。 */\n[data-edrv-view] .edrv-dapbp-dot.unverified { background: transparent; border: 1.5px solid var(--dsw-alias-state-error-primary, #e51400); opacity: .75; }\n/* 断点行内编辑浮层(Monaco content widget,锚定断点行上方;对齐 VS Code breakpointWidget 形态)。 */\n/* View Zone 浮层:宽度/左移由 BpWidget.syncWidth 按 layout 内联设置\n (Monaco .view-zones 仅内容区宽,需补偿 contentLeft 与滚动条),此处只管视觉。 */\n[data-edrv-view] .edrv-bpwidget { position: relative; box-sizing: border-box; display: flex; align-items: center; gap: 6px; padding: 3px 8px; border-top: 1px solid var(--dsw-alias-border-l2, #cdd6da); border-bottom: 1px solid var(--dsw-alias-border-l2, #cdd6da); background: var(--dsw-alias-bg-layer-1, #f7f9fa); }\n/* 断点编辑中的目标行高亮(浮层打开期间) */\n[data-edrv-view] .edrv-dap-editing-line { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .12)); }\n[data-edrv-view] .edrv-bpwidget-mode { flex: 0 0 auto; height: 22px; padding: 0 4px; font-size: 12px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 3px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); cursor: pointer; }\n[data-edrv-view] .edrv-bpwidget-input { flex: 1 1 auto !important; min-width: 0; width: auto !important; box-sizing: border-box; height: 22px; padding: 0 6px; font-size: 12px; font-family: var(--ds-font-family-code, ui-monospace, monospace); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 3px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); }\n[data-edrv-view] .edrv-bpwidget-input:focus { outline: 1px solid var(--dsw-alias-border-l2, #cdd6da); }\n\n/* 断点 hover 预览(glyph 区):半透明小红点 + pointer 光标(对齐 VS Code .codicon-debug-hint)。 */\n[data-edrv-view] .edrv-dap-bp-hint { cursor: pointer; }\n[data-edrv-view] .edrv-dap-bp-hint::before { content: ''; display: block; width: 7px; height: 7px; margin: 6px auto 0; border-radius: 50%; background: var(--dsw-alias-state-error-primary, #e51400); opacity: .4; }\n/* 行号区也给出可点提示(与 VS Code 一致:glyph 区与行号区都可点/可 hover);\n 不拦截折叠箭头等自有控件的光标。 */\n[data-edrv-view] .edrv-editor-row .monaco-editor .margin-view-overlays .line-numbers:hover { cursor: pointer; }\n\n/* 暂停态 hover 调试块 + 变量树(成员全量直显 + table 成员折叠展开)。\n ⚠️ 选择器一律用 data-*:本仓 vendored Monaco 的 markdown→DOM 管线会剥掉我们 HTML 里的\n class(supportHtml/isTrusted 都不豁免),只有 data-* 存活;用 class 会静默失效。 */\n[data-edrv-view] [data-edrv-dap] { display: block; min-width: 0; }\n[data-edrv-view] [data-edrv-head] { display: flex; align-items: baseline; gap: 2px; }\n[data-edrv-view] [data-edrv-head] [data-edrv-expr] { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] [data-edrv-head] [data-edrv-val] { font-family: var(--ds-font-family-code, ui-monospace, monospace); word-break: break-all; }\n[data-edrv-view] [data-edrv-type] { margin-top: 2px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #8a949b); }\n[data-edrv-view] [data-edrv-tree] { margin: 2px 0 0; padding: 0; list-style: none; font-variant-numeric: tabular-nums; }\n[data-edrv-view] [data-edrv-line] { display: flex; align-items: baseline; gap: 4px; padding: 1px 2px; border-radius: 3px; white-space: nowrap; }\n[data-edrv-view] [data-edrv-line]:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .12)); }\n/* 折叠按钮(对齐 CodeBuddy 调试浮窗变量树的 twist):热区 14px + hover 反馈,未可展开时留空占位 */\n[data-edrv-view] [data-edrv-twist] { flex: 0 0 auto; box-sizing: border-box; width: 14px; height: 14px; line-height: 13px; text-align: center; border-radius: 3px; color: var(--dsw-alias-label-tertiary, #8a949b); }\n[data-edrv-view] [data-edrv-twist]:not(:empty) { cursor: pointer; user-select: none; }\n[data-edrv-view] [data-edrv-twist]:not(:empty):hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .2)); color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] [data-edrv-name] { flex: 0 0 auto; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] [data-edrv-line] [data-edrv-eq] { flex: 0 0 auto; color: var(--dsw-alias-label-tertiary, #8a949b); }\n[data-edrv-view] [data-edrv-line] [data-edrv-val] { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] [data-edrv-note] { color: var(--dsw-alias-label-tertiary, #8a949b); font-style: italic; }\n/* Alt 提示层:由 hoverTree 注入到 .monaco-hover(滚动区之外)贴底常驻;容器预留同高内边距避免遮挡末行。\n 不再用 sticky / `:has()`:滚动链在 .monaco-hover-content 上,sticky 会被滚走。 */\n[data-edrv-view] .monaco-hover[data-edrv-hint-host=\"1\"] { padding-bottom: 22px; }\n[data-edrv-view] [data-edrv-hint=\"1\"] { position: absolute; left: 0; right: 0; bottom: 0; box-sizing: border-box; height: 22px; padding: 2px 8px; font-size: 11px; line-height: 18px; color: var(--dsw-alias-label-tertiary, #8a949b); background: var(--dsw-alias-bg-overlay, #ffffff); border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }";
37
37
  const tagId$1 = "dsh-vscode-mode/editor.css";
38
38
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
39
39
  const tag = document.createElement("style");
@@ -2262,6 +2262,99 @@ window.__ModuleLoader__.load({
2262
2262
  exts = new Set(DEFAULT_NATIVE_EXT);
2263
2263
  handler = null;
2264
2264
  }
2265
+ //#endregion
2266
+ //#region src/client/pendingNav.ts
2267
+ /** window 槽键名(跨热重载存活的全局挂点)。 */
2268
+ const PENDING_NAV_KEY = "__edrvPendingNav__";
2269
+ /** 交接有效期:超过即失效清槽(点击意图的有效窗口,防陈旧跳转)。 */
2270
+ const PENDING_NAV_TTL = 3e4;
2271
+ /**
2272
+ * 形状守卫:非法入参返回 null,合法则归一化为 PendingNav。
2273
+ * 行列非有限数字一律归 null(缺省语义 = 不定位行),path 必须为非空字符串。
2274
+ * @author ddj 2026年09月23号
2275
+ * @param raw 任意来源的原始值
2276
+ * @returns 归一化后的 PendingNav 或 null
2277
+ */
2278
+ function sanitizeNav(raw) {
2279
+ if (!raw || typeof raw !== "object") return null;
2280
+ const src = raw;
2281
+ if (typeof src.path !== "string" || !src.path) return null;
2282
+ const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : null;
2283
+ const at = num(src.at);
2284
+ if (at === null) return null;
2285
+ return {
2286
+ path: src.path,
2287
+ line: num(src.line),
2288
+ column: num(src.column),
2289
+ endLine: num(src.endLine),
2290
+ endColumn: num(src.endColumn),
2291
+ at
2292
+ };
2293
+ }
2294
+ /**
2295
+ * 新鲜度判定:形状合法且未超过 TTL 才算有效;过期返回 null。
2296
+ * @author ddj 2026年09月23号
2297
+ * @param nav 已归一化的待跳转(可空)
2298
+ * @param now 当前时刻(毫秒)
2299
+ * @param ttl 有效期(毫秒)
2300
+ * @returns 有效导航或 null
2301
+ */
2302
+ function freshNav(nav, now, ttl) {
2303
+ if (!nav) return null;
2304
+ return now - nav.at <= ttl ? nav : null;
2305
+ }
2306
+ /**
2307
+ * 取槽宿主:仅浏览器环境返回 window,否则 undefined(测试/SSR 降级)。
2308
+ * @author ddj 2026年09月23号
2309
+ */
2310
+ function slotHost() {
2311
+ if (typeof window === "undefined") return void 0;
2312
+ return window;
2313
+ }
2314
+ /**
2315
+ * 写入待跳转(盖写整槽;at 由调用方给定或取当前时间)。
2316
+ * 非法 path 直接丢弃,不写槽。
2317
+ * @author ddj 2026年09月23号
2318
+ * @param nav 待跳转内容(不含 at)
2319
+ * @param now 写入时刻(测试注入用)
2320
+ * @returns 是否写入成功
2321
+ */
2322
+ function putPendingNav(nav, now = Date.now()) {
2323
+ const host = slotHost();
2324
+ if (!host) return false;
2325
+ if (typeof nav?.path !== "string" || !nav.path) return false;
2326
+ host[PENDING_NAV_KEY] = {
2327
+ ...nav,
2328
+ at: now
2329
+ };
2330
+ return true;
2331
+ }
2332
+ /**
2333
+ * 读取新鲜的待跳转(**不消费**;过期或形状非法才清槽)。
2334
+ * @author ddj 2026年09月23号
2335
+ * @param now 当前时刻(测试注入用)
2336
+ * @param ttl 有效期(毫秒)
2337
+ * @returns 有效导航或 null
2338
+ */
2339
+ function readPendingNav(now = Date.now(), ttl = PENDING_NAV_TTL) {
2340
+ const host = slotHost();
2341
+ if (!host) return null;
2342
+ const nav = freshNav(sanitizeNav(host[PENDING_NAV_KEY]), now, ttl);
2343
+ if (!nav) {
2344
+ if (host["__edrvPendingNav__"] !== void 0) delete host[PENDING_NAV_KEY];
2345
+ return null;
2346
+ }
2347
+ return nav;
2348
+ }
2349
+ /**
2350
+ * 清除待跳转槽(落点成功或显式放弃时调用)。
2351
+ * @author ddj 2026年09月23号
2352
+ */
2353
+ function clearPendingNav() {
2354
+ const host = slotHost();
2355
+ if (!host) return;
2356
+ delete host[PENDING_NAV_KEY];
2357
+ }
2265
2358
  /** 作用域键 → 路径 → 磁盘版本令牌。 */
2266
2359
  const baselines = /* @__PURE__ */ new Map();
2267
2360
  /** 作用域键 → 路径 → 已读取过内容的磁盘版本(同版本不重复读盘;含当时的比对结果)。 */
@@ -3759,11 +3852,15 @@ window.__ModuleLoader__.load({
3759
3852
  byPath.get(r.path).push(r);
3760
3853
  }
3761
3854
  const files = [];
3762
- for (const [path, recs] of byPath) files.push({
3763
- path,
3764
- recs,
3765
- pending: pendingCount(recs)
3766
- });
3855
+ for (const [path, recs] of byPath) {
3856
+ const label = recs.find((r) => !!r.displayPath)?.displayPath ?? path;
3857
+ files.push({
3858
+ path,
3859
+ label,
3860
+ recs,
3861
+ pending: pendingCount(recs)
3862
+ });
3863
+ }
3767
3864
  files.sort((a, b) => a.path < b.path ? -1 : 1);
3768
3865
  const pendingFiles = files.filter((f) => f.pending > 0);
3769
3866
  return {
@@ -4033,20 +4130,20 @@ window.__ModuleLoader__.load({
4033
4130
  return true;
4034
4131
  }
4035
4132
  /**
4036
- * 路径名称过滤匹配(W1-2):`*` 任意串、`?` 单字符(忽略大小写);
4037
- * 无通配符时回落子串包含。非法正则元字符已转义,永不抛错。
4038
- * @author ddj 2026年09月20号
4039
- * @param path 条目路径(`/` 分隔)
4040
- * @param pattern 过滤串(空/空白 = 不过滤)
4041
- * @returns 是否命中
4133
+ * 名称过滤匹配器(性能版):模式解析与正则编译只做一次,循环内零构造。
4134
+ * `*` 任意串、`?` 单字符(忽略大小写);无通配符回落子串包含;
4135
+ * 非法正则元字符已转义,永不抛错。与 changeNameMatch 语义一致。
4136
+ * @author ddj 2026年09月23号
4137
+ * @param pattern 过滤串(空/空白 = 全命中)
4138
+ * @returns 单条路径命中判定
4042
4139
  */
4043
- function changeNameMatch(path, pattern) {
4140
+ function nameMatcherOf(pattern) {
4044
4141
  const query = String(pattern ?? "").trim().toLowerCase();
4045
- if (!query) return true;
4046
- const target = String(path ?? "").toLowerCase();
4047
- if (!query.includes("*") && !query.includes("?")) return target.includes(query);
4142
+ if (!query) return () => true;
4143
+ if (!query.includes("*") && !query.includes("?")) return (path) => String(path ?? "").toLowerCase().includes(query);
4048
4144
  const source = query.replace(/[.+^${}()|[\]\\]/g, "\\$&").replaceAll("*", ".*").replaceAll("?", ".");
4049
- return new RegExp("^" + source + "$").test(target);
4145
+ const tester = new RegExp("^" + source + "$");
4146
+ return (path) => tester.test(String(path ?? "").toLowerCase());
4050
4147
  }
4051
4148
  /**
4052
4149
  * 按开关过滤变更清单(过滤规则唯一出口,面板/徽标共用,避免两处漂移)。
@@ -4058,8 +4155,9 @@ window.__ModuleLoader__.load({
4058
4155
  function svnVisibleChanges(entries, filter = {}) {
4059
4156
  const showUnversioned = filter.unversioned !== false;
4060
4157
  const showIgnored = filter.ignored === true;
4158
+ const nameHit = nameMatcherOf(filter.name);
4061
4159
  return entries.filter((entry) => {
4062
- if (!changeNameMatch(entry.path, filter.name)) return false;
4160
+ if (!nameHit(entry.path)) return false;
4063
4161
  if (entry.status === "ignored") return showIgnored;
4064
4162
  if (entry.status === "unversioned") return showUnversioned;
4065
4163
  return isSvnChange(entry);
@@ -4143,6 +4241,36 @@ window.__ModuleLoader__.load({
4143
4241
  blame: "TortoiseSVN 追溯",
4144
4242
  revert: "TortoiseSVN 还原"
4145
4243
  };
4244
+ /**
4245
+ * 分区名(changelist 名)合法性校验:返回错误文案,合法返回 null。
4246
+ * 规则:去首尾空白后非空、不以 `-` 开头(防被 svn 当成选项解析)、长度 ≤ 上限。
4247
+ * client 预检 + host 权威校验共用,避免两处漂移。
4248
+ * @author ddj 2026年09月23号
4249
+ * @param name 用户输入的分区名
4250
+ * @returns 错误文案;合法为 null
4251
+ */
4252
+ function svnChangelistNameErrorOf(name) {
4253
+ const trimmed = String(name ?? "").trim();
4254
+ if (!trimmed) return "分区名不能为空";
4255
+ if (trimmed.startsWith("-")) return "分区名不能以 - 开头";
4256
+ if (trimmed.length > 64) return "分区名最长 64 字符";
4257
+ return null;
4258
+ }
4259
+ /**
4260
+ * 路径清单按单次上限分块(host 批量路径上限护栏的客户端对齐)。
4261
+ * @author ddj 2026年09月23号
4262
+ * @param paths 路径列表
4263
+ * @param cap 单块上限(≤0 或非有限值视为不分块,整包一块)
4264
+ * @returns 分块数组(保持原顺序;空入参返回 [])
4265
+ */
4266
+ function svnChunksOf(paths, cap) {
4267
+ const size = Number.isFinite(cap) && cap > 0 ? Math.floor(cap) : 0;
4268
+ if (!paths.length) return [];
4269
+ if (!size || paths.length <= size) return [[...paths]];
4270
+ const chunks = [];
4271
+ for (let start = 0; start < paths.length; start += size) chunks.push(paths.slice(start, start + size));
4272
+ return chunks;
4273
+ }
4146
4274
  /** 取路径 basename(`/`/`\` 通用;纯函数)。 */
4147
4275
  function baseNameOf$1(path) {
4148
4276
  return String(path ?? "").split(/[\\/]/).pop() ?? "";
@@ -4186,6 +4314,74 @@ window.__ModuleLoader__.load({
4186
4314
  "props-deleted": " ",
4187
4315
  "props-modified": " "
4188
4316
  };
4317
+ /**
4318
+ * 忽略路径清单 → 目录聚合写入项(纯函数):路径拆 dir + basename,同目录合并、同名去重。
4319
+ * 供 `svn.ignore` 的执行载荷构造(一个目录一次 propset,进度粒度按目录)。
4320
+ * @author ddj 2026年09月23号
4321
+ * @param paths 未版本化路径清单(工作区相对)
4322
+ * @returns 目录聚合写入项(保持目录首次出现顺序;空入参返回 [])
4323
+ */
4324
+ function ignoreItemsOf(paths) {
4325
+ const byDir = /* @__PURE__ */ new Map();
4326
+ for (const raw of paths) {
4327
+ const norm = String(raw ?? "").trim().replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+$/, "");
4328
+ if (!norm) continue;
4329
+ const cut = norm.lastIndexOf("/");
4330
+ const dir = cut <= 0 ? "" : norm.slice(0, cut);
4331
+ const name = cut <= 0 ? norm : norm.slice(cut + 1);
4332
+ if (!name) continue;
4333
+ const bucket = byDir.get(dir);
4334
+ if (bucket) {
4335
+ if (!bucket.includes(name)) bucket.push(name);
4336
+ } else byDir.set(dir, [name]);
4337
+ }
4338
+ return [...byDir.entries()].map(([dir, names]) => ({
4339
+ dir,
4340
+ names
4341
+ }));
4342
+ }
4343
+ /**
4344
+ * 会话 agent 深度分析任务文本(混合通道 02-deep-session-prompt 修正版)。
4345
+ * 在**独立新会话**草稿箱填入后由用户发送;agent 自跑只读 `svn status` 取清单
4346
+ * (prompt 定长瘦身,不随变更数膨胀),借 codegraph/读文件/sub agent 深度分析,
4347
+ * 产出方案经免鉴权 RPC `svn.aiPlanSubmit` 投递回面板收件箱——确认与执行仍全部
4348
+ * 走面板(agent 禁写、只读放行)。
4349
+ * @author ddj 2026年09月23号
4350
+ * @param wcRoot 工作副本根(取数指引内嵌)
4351
+ * @param sessionId 会话 id(投递命令内嵌;host 按它解析工作副本)
4352
+ * @returns 任务文本(定长 ~1KB:取数指引/分析要求/投递命令/硬约束)
4353
+ */
4354
+ function buildAgentPrompt(wcRoot, sessionId) {
4355
+ return [
4356
+ "请对 SVN 工作副本「" + wcRoot + "」的本地变更做**深度分析**,产出整理方案(分组/还原/忽略三段)。",
4357
+ "",
4358
+ "取数(只读命令允许):",
4359
+ "- 先执行 `svn status`(只读)获取完整变更清单;",
4360
+ "- 判断改动性质时用 `svn diff`(只读)查看具体改动。",
4361
+ "",
4362
+ "分析要求(按需使用你的工具):",
4363
+ "- 借助 codegraph 查询调用链/模块归属,判断哪些文件属于同一功能主题(分组依据);",
4364
+ "- 按需读取文件内容,判断改动性质(误改/行尾空白噪音/试验性改动 → 建议还原);",
4365
+ "- 未版本化条目判断是否为生成物/临时文件/日志/缓存(建议忽略);",
4366
+ "- 需要并行探索时可用 sub agent。",
4367
+ "",
4368
+ "方案 JSON 形状(reason 为简短中文一句话):",
4369
+ "{ \"groups\": [{ \"name\": \"英文短横线名\", \"paths\": [\"路径1\"], \"reason\": \"理由\" }],",
4370
+ " \"reverts\": [{ \"path\": \"路径\", \"reason\": \"理由\" }],",
4371
+ " \"ignores\": [{ \"path\": \"路径\", \"reason\": \"理由\" }] }",
4372
+ "",
4373
+ "硬约束:",
4374
+ "1. 禁止任何**写**操作(revert/commit/changelist/propset/update/merge 等一律禁止);只读命令(status/diff/log/cat/info)允许;",
4375
+ "2. 每个路径至多归一类(groups/reverts/ignores 互斥),拿不准的不填;",
4376
+ "3. 组名用简短英文、不以 - 开头;",
4377
+ "4. 只使用 `svn status` 实际返回的路径,绝不虚构或改写路径。",
4378
+ "",
4379
+ "分析完成后,用 shell 执行下面的命令把方案投递回面板(把 <PLAN_JSON> 替换为方案 JSON):",
4380
+ "Invoke-RestMethod -Uri http://127.0.0.1:3080/edrv/rpc -Method Post -ContentType 'application/json' -Body (@{ method = 'svn.aiPlanSubmit'; args = @{ sessionId = '" + sessionId + "'; plan = <PLAN_JSON> } } | ConvertTo-Json -Depth 8)",
4381
+ "",
4382
+ "投递成功会返回 { ok, accepted, dropped };随后我会在面板弹窗中确认执行,你无需再做任何操作。"
4383
+ ].join("\n");
4384
+ }
4189
4385
  //#endregion
4190
4386
  //#region src/shared/svnActions.ts
4191
4387
  /**
@@ -4618,6 +4814,15 @@ window.__ModuleLoader__.load({
4618
4814
  return changesStore.get(scope);
4619
4815
  }
4620
4816
  /**
4817
+ * 变更清单是否被条目上限截断(面板提示用)。
4818
+ * @author ddj 2026年09月16号
4819
+ * @param scope 状态作用域
4820
+ * @returns 是否截断
4821
+ */
4822
+ function svnChangesCapped(scope) {
4823
+ return changesStore.meta(scope).truncated === true;
4824
+ }
4825
+ /**
4621
4826
  * 路径 → 变更条目映射(文件树徽标 O(1) 查表;未加载返回空表)。
4622
4827
  * 同一路径出现多条时保留首条(svn status 对单路径只报一条)。
4623
4828
  * @author ddj 2026年09月16号
@@ -4805,6 +5010,184 @@ window.__ModuleLoader__.load({
4805
5010
  }
4806
5011
  }
4807
5012
  /**
5013
+ * 分区(changelist)批量操作:关联或解除工作副本条目的 changelist 登记。
5014
+ * `svn changelist` 成功时输出静默(host count 为 0),反馈计数以客户端 paths.length 为准;
5015
+ * 上限分块由面板层(svnChunksOf)负责,本包装单次直发。
5016
+ * @author ddj 2026年09月23号
5017
+ * @param sessionId 会话 id
5018
+ * @param paths 工作区相对路径列表
5019
+ * @param name 目标分区名;null = 移出当前分区
5020
+ * @returns 执行结果与反馈文案
5021
+ */
5022
+ async function svnChangelist(sessionId, paths, name) {
5023
+ const count = paths.length;
5024
+ const remove = name === null;
5025
+ try {
5026
+ const res = await rpc("svn.changelist", remove ? {
5027
+ sessionId,
5028
+ paths,
5029
+ remove: true
5030
+ } : {
5031
+ sessionId,
5032
+ paths,
5033
+ name: name ?? void 0
5034
+ });
5035
+ if (!res.ok) return {
5036
+ ok: false,
5037
+ message: "分区操作失败:" + res.error
5038
+ };
5039
+ return {
5040
+ ok: true,
5041
+ message: remove ? "已移出分区(" + count + " 项)" : "已移入分区「" + name + "」(" + count + " 项)"
5042
+ };
5043
+ } catch (error) {
5044
+ return {
5045
+ ok: false,
5046
+ message: "分区操作失败:" + String(error)
5047
+ };
5048
+ }
5049
+ }
5050
+ /**
5051
+ * AI 智能整理分析(host `svn.aiPlan`;只读,LLM 一次性调用最长约 120s)。
5052
+ * @author ddj 2026年09月23号
5053
+ * @param sessionId 会话 id
5054
+ * @returns 三段方案与分析元信息
5055
+ */
5056
+ async function svnAiPlan(sessionId) {
5057
+ try {
5058
+ const res = await rpc("svn.aiPlan", { sessionId });
5059
+ if (!res.ok) return {
5060
+ ok: false,
5061
+ message: "AI 分析失败:" + res.error
5062
+ };
5063
+ return {
5064
+ ok: true,
5065
+ plan: res.plan,
5066
+ entriesCount: res.entriesCount,
5067
+ diffIncluded: res.diffIncluded,
5068
+ dropped: res.dropped,
5069
+ model: res.model,
5070
+ message: "AI 分析完成"
5071
+ };
5072
+ } catch (error) {
5073
+ return {
5074
+ ok: false,
5075
+ message: "AI 分析失败:" + String(error)
5076
+ };
5077
+ }
5078
+ }
5079
+ /**
5080
+ * AI 整理执行段③:按目录合并写入 svn:ignore 属性(host `svn.ignore`)。
5081
+ * @author ddj 2026年09月23号
5082
+ * @param sessionId 会话 id
5083
+ * @param items 目录聚合写入项
5084
+ * @returns 执行结果与反馈文案
5085
+ */
5086
+ async function svnIgnore(sessionId, items) {
5087
+ try {
5088
+ const res = await rpc("svn.ignore", {
5089
+ sessionId,
5090
+ items
5091
+ });
5092
+ if (!res.ok) return {
5093
+ ok: false,
5094
+ message: "SVN 忽略失败:" + res.error
5095
+ };
5096
+ return {
5097
+ ok: true,
5098
+ message: res.summary
5099
+ };
5100
+ } catch (error) {
5101
+ return {
5102
+ ok: false,
5103
+ message: "SVN 忽略失败:" + String(error)
5104
+ };
5105
+ }
5106
+ }
5107
+ /**
5108
+ * 混合通道取件(host `svn.aiPlanPending`):轮询取会话 agent 投递的方案。
5109
+ * @author ddj 2026年09月23号
5110
+ * @param sessionId 会话 id
5111
+ * @param since 注入时刻时间戳(早于它的旧投递不算新件)
5112
+ * @returns 取件结果
5113
+ */
5114
+ async function svnAiPlanPending(sessionId, since) {
5115
+ try {
5116
+ const res = await rpc("svn.aiPlanPending", {
5117
+ sessionId,
5118
+ since
5119
+ });
5120
+ if (!res.ok) return {
5121
+ ok: false,
5122
+ message: "取件失败:" + res.error
5123
+ };
5124
+ return {
5125
+ ok: true,
5126
+ plan: res.plan,
5127
+ dropped: res.dropped,
5128
+ at: res.at,
5129
+ message: res.plan ? "方案已送达" : "暂无方案"
5130
+ };
5131
+ } catch (error) {
5132
+ return {
5133
+ ok: false,
5134
+ message: "取件失败:" + String(error)
5135
+ };
5136
+ }
5137
+ }
5138
+ /**
5139
+ * 可暂停执行引擎(AI 整理执行段编排):顺序执行步骤队列。
5140
+ * - 暂停只在**步骤边界**生效(svn 子进程不可安全中断):每步前 `ctl.wait()`;
5141
+ * - 取消后不再取步(已执行不回滚);
5142
+ * - 单步失败(ok=false 或抛错)记日志后**继续**后续步骤。
5143
+ * @author ddj 2026年09月23号
5144
+ * @param steps 步骤队列(执行顺序即数组顺序)
5145
+ * @param ctl 暂停/取消控制面
5146
+ * @param onTick 进度回调(步骤前后各一次)
5147
+ * @returns 逐步日志与取消标记
5148
+ */
5149
+ async function runPlanSteps(steps, ctl, onTick) {
5150
+ const log = [];
5151
+ const tick = (done) => onTick?.({
5152
+ done,
5153
+ total: steps.length,
5154
+ cur: done < steps.length ? steps[done].label : "",
5155
+ log: [...log]
5156
+ });
5157
+ let cancelled = false;
5158
+ tick(0);
5159
+ for (let index = 0; index < steps.length; index++) {
5160
+ if (ctl.cancelled()) {
5161
+ cancelled = true;
5162
+ break;
5163
+ }
5164
+ await ctl.wait();
5165
+ if (ctl.cancelled()) {
5166
+ cancelled = true;
5167
+ break;
5168
+ }
5169
+ const step = steps[index];
5170
+ let outcome;
5171
+ try {
5172
+ outcome = await step.run();
5173
+ } catch (error) {
5174
+ outcome = {
5175
+ ok: false,
5176
+ message: String(error)
5177
+ };
5178
+ }
5179
+ log.push({
5180
+ ok: outcome.ok,
5181
+ text: step.label + ":" + outcome.message
5182
+ });
5183
+ tick(index + 1);
5184
+ }
5185
+ return {
5186
+ log,
5187
+ cancelled
5188
+ };
5189
+ }
5190
+ /**
4808
5191
  * 生成统一格式补丁文本(W2-1,只读不落盘)。
4809
5192
  * @author ddj 2026年09月20号
4810
5193
  * @param sessionId 会话 id
@@ -7317,9 +7700,9 @@ window.__ModuleLoader__.load({
7317
7700
  if (tab === "pending") body = sum.pendingFiles.length === 0 ? react.default.createElement("div", { className: "edrv-search-empty" }, "暂无待处理差异(已全部处理)") : sum.pendingFiles.map((f) => react.default.createElement("div", {
7318
7701
  key: f.path,
7319
7702
  className: "edrv-launch-row",
7320
- title: "打开并跳转到差异 " + f.path,
7703
+ title: "打开并跳转到差异 " + (f.label ?? f.path),
7321
7704
  onClick: () => onOpenFile(f.path)
7322
- }, react.default.createElement("span", { className: "edrv-launch-path" }, f.path), react.default.createElement("span", { className: "edrv-launch-cnt" }, "待处理 " + f.pending + " 处"), react.default.createElement("button", {
7705
+ }, react.default.createElement("span", { className: "edrv-launch-path" }, f.label ?? f.path), react.default.createElement("span", { className: "edrv-launch-cnt" }, "待处理 " + f.pending + " 处"), react.default.createElement("button", {
7323
7706
  className: "edrv-btn-mini edrv-btn-keep",
7324
7707
  onClick: (e) => {
7325
7708
  e.stopPropagation();
@@ -7383,7 +7766,7 @@ window.__ModuleLoader__.load({
7383
7766
  } }, react.default.createElement("span", { style: {
7384
7767
  color: "var(--dsw-alias-label-primary,#ddd)",
7385
7768
  fontWeight: 600
7386
- } }, rec.toolName === "write" ? rec.create ? "新建" : "写入" : "编辑"), react.default.createElement("span", { style: { color: "var(--dsw-alias-state-success-primary,#2e9e44)" } }, "采纳 " + sm.accepted), react.default.createElement("span", { style: { color: "var(--dsw-alias-state-error-primary,#d9534f)" } }, "拒绝 " + sm.rejected), rec.superseded ? react.default.createElement("span", { style: { color: "var(--dsw-alias-state-warn-primary,#b7791f)" } }, "被覆盖") : null, react.default.createElement("span", { style: { color: "var(--dsw-alias-label-tertiary,#888)" } }, new Date(rec.at).toLocaleTimeString())), react.default.createElement("pre", { style: {
7769
+ } }, rec.toolName === "remote_ssh_write" ? rec.create ? "远端新建" : "远端写入" : rec.toolName === "write" ? rec.create ? "新建" : "写入" : "编辑"), react.default.createElement("span", { style: { color: "var(--dsw-alias-state-success-primary,#2e9e44)" } }, "采纳 " + sm.accepted), react.default.createElement("span", { style: { color: "var(--dsw-alias-state-error-primary,#d9534f)" } }, "拒绝 " + sm.rejected), rec.superseded ? react.default.createElement("span", { style: { color: "var(--dsw-alias-state-warn-primary,#b7791f)" } }, "被覆盖") : null, react.default.createElement("span", { style: { color: "var(--dsw-alias-label-tertiary,#888)" } }, new Date(rec.at).toLocaleTimeString())), react.default.createElement("pre", { style: {
7387
7770
  margin: 0,
7388
7771
  whiteSpace: "pre",
7389
7772
  fontFamily: MONO.fontFamily,
@@ -7430,7 +7813,7 @@ window.__ModuleLoader__.load({
7430
7813
  fontSize: 12,
7431
7814
  color: "var(--dsw-alias-label-primary,#ddd)",
7432
7815
  wordBreak: "break-all"
7433
- } }, e.path), e.batch != null ? react.default.createElement("span", { style: {
7816
+ } }, e.displayPath ?? e.path), e.batch != null ? react.default.createElement("span", { style: {
7434
7817
  fontSize: 11,
7435
7818
  color: "var(--dsw-alias-label-tertiary,#888)"
7436
7819
  } }, "批次 " + e.batch) : null, e.reason ? react.default.createElement("span", { style: {
@@ -8440,6 +8823,157 @@ window.__ModuleLoader__.load({
8440
8823
  }
8441
8824
  };
8442
8825
  }
8826
+ /** apiproxy wire 端点(POST /api/<method>;浏览器同源 fetch 自带 cookie 鉴权;实证 401=未鉴权而非 404)。 */
8827
+ const SESSION_CREATE_PATH = "/api/session/create";
8828
+ /** apiproxy wire 端点:发送任务(session/prompt;点击即发送方案)。 */
8829
+ const SESSION_PROMPT_PATH = "/api/session/prompt";
8830
+ /** mint RPC 请求 id(RpcId 品牌类型运行时即普通字符串)。 */
8831
+ function mintRpcId() {
8832
+ try {
8833
+ return globalThis.crypto?.randomUUID?.() ?? "rpc-" + Date.now();
8834
+ } catch {
8835
+ return "rpc-" + Date.now();
8836
+ }
8837
+ }
8838
+ /**
8839
+ * wire 槽实参组装(gateway `invoke` 铁证:`request.args[parameter.wire]` 具名槽,
8840
+ * `session/prompt` 的槽名 = "request",值 = RpcRequest `{rpcId, payload}`)。
8841
+ * @author ddj 2026年09月24号
8842
+ * @param payload 业务载荷
8843
+ * @returns 具名槽实参 `{ args: { request: RpcRequest } }`
8844
+ */
8845
+ function slotArg(payload) {
8846
+ return { args: { request: {
8847
+ rpcId: mintRpcId(),
8848
+ payload
8849
+ } } };
8850
+ }
8851
+ /**
8852
+ * RPC 返回解析(照官方 dsh-client-runtime 调用形态:`const { result } = await api.sessions.create(...)`)。
8853
+ * 官方 api.sessions 面返回**信封** `{ rpcId, result: RpcResult }`——须解 .result;
8854
+ * 兼容裸 RpcResult 形态(个别补丁面直接回 {ok, value})。
8855
+ * @author ddj 2026年09月23号
8856
+ * @param res 信封或裸 RpcResult
8857
+ * @returns 归一后的 { ok, value }
8858
+ */
8859
+ function rpcOk(res) {
8860
+ const r = res?.result ?? res;
8861
+ return {
8862
+ ok: r?.ok === true,
8863
+ value: r?.value
8864
+ };
8865
+ }
8866
+ /**
8867
+ * wire 直调 session/create(主路径):ClientRequest 信封 → ServerResponse.result(RpcResult 形态)。
8868
+ * 契约以当前安装版 dsh-host-apiproxy 为准(api/sessions.d.ts「Method signatures are the
8869
+ * source of truth」):`create({cwd}) → {sessionId}`;信封 = `{type:'client-request', rpcId,
8870
+ * method, payload}` → `{result: {ok:true, value:{sessionId}} | {ok:false, error}}`。
8871
+ * @author ddj 2026年09月23号
8872
+ * @param cwd 新会话工作区目录
8873
+ * @returns 新会话 id(失败空串)
8874
+ */
8875
+ async function apiSessionCreate(cwd) {
8876
+ const json = await (await fetch(SESSION_CREATE_PATH, {
8877
+ method: "POST",
8878
+ headers: { "content-type": "application/json" },
8879
+ body: JSON.stringify({
8880
+ type: "client-request",
8881
+ rpcId: mintRpcId(),
8882
+ method: "session/create",
8883
+ payload: cwd ? { cwd } : {}
8884
+ })
8885
+ })).json().catch(() => null);
8886
+ const id = json?.result?.value?.sessionId;
8887
+ return json?.result?.ok === true && typeof id === "string" ? id : "";
8888
+ }
8889
+ /**
8890
+ * wire 直发 session/prompt(点击即发送方案):任务文本投给目标会话 agent。
8891
+ * 契约 = 当前安装树 SessionsApi.prompt:`{sessionId, mode:'queue', content:[{type:'text',text}]}`。
8892
+ * 发送成功会话即有内容 → 不再被 blank 隐藏(列表可见)。
8893
+ * @author ddj 2026年09月23号
8894
+ * @param sessionId 目标会话 id(新会话)
8895
+ * @param text 任务文本
8896
+ * @returns 是否受理
8897
+ */
8898
+ async function apiSessionPrompt(sessionId, text) {
8899
+ try {
8900
+ const payload = {
8901
+ sessionId,
8902
+ mode: "queue",
8903
+ content: [{
8904
+ type: "text",
8905
+ text
8906
+ }]
8907
+ };
8908
+ return (await (await fetch(SESSION_PROMPT_PATH, {
8909
+ method: "POST",
8910
+ headers: { "content-type": "application/json" },
8911
+ body: JSON.stringify({
8912
+ type: "client-request",
8913
+ rpcId: mintRpcId(),
8914
+ method: "session/prompt",
8915
+ payload: slotArg(payload)
8916
+ })
8917
+ })).json().catch(() => null))?.result?.ok === true;
8918
+ } catch {
8919
+ return false;
8920
+ }
8921
+ }
8922
+ /**
8923
+ * 新建独立会话承载旁路任务(02-deep-session-prompt:深度分析不污染当前对话)。
8924
+ * 主路径 = apiproxy wire 直调(不依赖 service 面形态猜测);回落 remote.session.create
8925
+ * 与旧 sessions.create 两代 service 面(宽松解析)。任一步不符返回 ok:false,调用方降级。
8926
+ * @author ddj 2026年09月23号
8927
+ * @param ctx 客户端服务上下文(remote.session + sessions,仅回落用)
8928
+ * @param cwd 新会话工作区目录(与当前会话同工作区)
8929
+ * @returns 新会话结果(含 id)
8930
+ */
8931
+ async function newDraftSession(ctx, cwd) {
8932
+ try {
8933
+ const sessions = ctx.get("sessions");
8934
+ if (typeof sessions?.create === "function") {
8935
+ const created = await sessions.create(cwd ? { cwd } : void 0);
8936
+ const id = typeof created === "string" && created ? created : typeof created?.id === "string" ? created.id : typeof created?.sessionId === "string" ? created.sessionId : typeof created?.session?.id === "string" ? created.session.id : "";
8937
+ if (id) return {
8938
+ ok: true,
8939
+ id
8940
+ };
8941
+ }
8942
+ } catch {}
8943
+ try {
8944
+ const remote = ctx.get("remote.session");
8945
+ if (typeof remote?.create === "function") {
8946
+ const payload = cwd ? { cwd } : {};
8947
+ for (const arg of [
8948
+ slotArg(payload),
8949
+ { request: {
8950
+ rpcId: mintRpcId(),
8951
+ payload
8952
+ } },
8953
+ {
8954
+ rpcId: mintRpcId(),
8955
+ payload
8956
+ },
8957
+ payload
8958
+ ]) try {
8959
+ const r = rpcOk(await remote.create(arg));
8960
+ const id = r.value;
8961
+ if (r.ok && typeof id?.sessionId === "string") return {
8962
+ ok: true,
8963
+ id: id.sessionId
8964
+ };
8965
+ } catch {}
8966
+ }
8967
+ } catch {}
8968
+ try {
8969
+ const id = await apiSessionCreate(cwd);
8970
+ if (id) return {
8971
+ ok: true,
8972
+ id
8973
+ };
8974
+ } catch {}
8975
+ return { ok: false };
8976
+ }
8443
8977
  /**
8444
8978
  * 解析会话输入门面;缺失时返回 undefined(动作侧守卫降级)。
8445
8979
  * @author ddj 2026年08月25号
@@ -8546,7 +9080,109 @@ window.__ModuleLoader__.load({
8546
9080
  if (safeInsertText(input, (pad.lead ? " " : "") + mention + (pad.tail ? " " : ""), span)) return "busy";
8547
9081
  return "failed";
8548
9082
  };
8549
- return { appendReference };
9083
+ /**
9084
+ * 追加纯文本(AI 深度分析任务注入):走官方 plain-text 通道插到当前光标。
9085
+ * 失败语义与 appendReference 一致:宁可不写也不整篇重建(保护既有 chip)。
9086
+ * @author ddj 2026年09月23号
9087
+ * @param sessionId 会话 id
9088
+ * @param text 待注入文本
9089
+ * @returns 注入结果(ok / unavailable / failed)
9090
+ */
9091
+ const appendText = async (sessionId, text) => {
9092
+ const input = inputFor(ctx, sessionId);
9093
+ if (!input) return "unavailable";
9094
+ const cur = draftCursor(input);
9095
+ if (!cur) return "unavailable";
9096
+ const at = insertOffsetOf(caretOf(input), detectEndOf(cur));
9097
+ return safeInsertText(input, text, {
9098
+ start: at,
9099
+ end: at,
9100
+ draftRev: cur.draftRev
9101
+ }) ? "ok" : "failed";
9102
+ };
9103
+ /**
9104
+ * 新建独立会话(02-deep-session-prompt:旁路任务不污染当前对话)。
9105
+ * 闭包持有真服务 ctx(面板 SidebarCtx 无 .get,会话操作必须经此门面);
9106
+ * 创建后尽力 `sessions.open(id)` 切换视图(缺失不致命,草稿仍可写入)。
9107
+ * @author ddj 2026年09月23号
9108
+ * @param cwd 新会话工作区目录(与当前会话同工作区)
9109
+ * @returns 新会话结果(失败供降级)
9110
+ */
9111
+ const startDraftSession = async (cwd) => {
9112
+ const result = await newDraftSession(ctx, cwd);
9113
+ if (result.ok && result.id) try {
9114
+ const sessions = ctx.get("sessions");
9115
+ sessions?.materializeScope?.(result.id);
9116
+ const title = "AI 深度分析 · " + (String(cwd ?? "").split(/[\\/]/).pop() || "SVN 变更");
9117
+ sessions?.manager?.rename?.(result.id, title);
9118
+ sessions?.manager?.select?.(result.id);
9119
+ sessions?.open?.(result.id);
9120
+ } catch {}
9121
+ return result;
9122
+ };
9123
+ /**
9124
+ * 发送任务给目标会话 agent(点击即发送方案:任务落地会话即非 blank,列表可见)。
9125
+ * 主路径 wire 直发 session/prompt;回落 remote.session.prompt service 面。
9126
+ * @author ddj 2026年09月23号
9127
+ * @param sessionId 目标会话 id
9128
+ * @param text 任务文本
9129
+ * @returns 是否受理
9130
+ */
9131
+ const sendTask = async (sessionId, text) => {
9132
+ if (!sessionId) return false;
9133
+ const composerOnce = async () => {
9134
+ const input = inputFor(ctx, sessionId);
9135
+ if (input && typeof input.setDraft === "function" && typeof input.submit === "function") {
9136
+ input.setDraft(text);
9137
+ input.submit();
9138
+ return true;
9139
+ }
9140
+ return false;
9141
+ };
9142
+ try {
9143
+ for (let attempt = 3; attempt > 0; attempt--) {
9144
+ if (await composerOnce()) return true;
9145
+ if (attempt > 1) await new Promise((resolve) => setTimeout(resolve, 500));
9146
+ }
9147
+ } catch {}
9148
+ try {
9149
+ const remote = ctx.get("remote.session");
9150
+ if (typeof remote?.prompt === "function") {
9151
+ const payload = {
9152
+ sessionId,
9153
+ mode: "queue",
9154
+ content: [{
9155
+ type: "text",
9156
+ text
9157
+ }]
9158
+ };
9159
+ for (const arg of [
9160
+ slotArg(payload),
9161
+ { request: {
9162
+ rpcId: mintRpcId(),
9163
+ payload
9164
+ } },
9165
+ {
9166
+ rpcId: mintRpcId(),
9167
+ payload
9168
+ },
9169
+ payload
9170
+ ]) try {
9171
+ if (rpcOk(await remote.prompt(arg)).ok) return true;
9172
+ } catch {}
9173
+ }
9174
+ } catch {}
9175
+ try {
9176
+ return await apiSessionPrompt(sessionId, text);
9177
+ } catch {}
9178
+ return false;
9179
+ };
9180
+ return {
9181
+ appendReference,
9182
+ appendText,
9183
+ startDraftSession,
9184
+ sendTask
9185
+ };
8550
9186
  }
8551
9187
  /**
8552
9188
  * 由选区文本推导搜索种子。
@@ -18975,10 +19611,24 @@ window.__ModuleLoader__.load({
18975
19611
  ed.focus();
18976
19612
  return;
18977
19613
  }
18978
- const pf = pendingFocusRef.current;
19614
+ const refPf = pendingFocusRef.current;
19615
+ const slotNav = refPf ? null : readPendingNav();
19616
+ const pf = refPf || (slotNav ? {
19617
+ path: slotNav.path,
19618
+ region: null,
19619
+ line: slotNav.line ?? null,
19620
+ column: slotNav.column ?? 1,
19621
+ endLine: slotNav.endLine ?? null,
19622
+ endColumn: slotNav.endColumn ?? null
19623
+ } : null);
18979
19624
  if (!pf || !sameFile(pf.path, active)) return;
18980
- if (pf.line != null) {
19625
+ const dropPending = () => {
18981
19626
  pendingFocusRef.current = null;
19627
+ if (pf.line != null) clearPendingNav();
19628
+ };
19629
+ if (pf.line != null) {
19630
+ if (!sameFile(modelPathOf(ed), pf.path)) return;
19631
+ dropPending();
18982
19632
  const line = Math.max(1, pf.line);
18983
19633
  const column = Math.max(1, pf.column ?? 1);
18984
19634
  ed.revealLineInCenter(line);
@@ -18997,7 +19647,8 @@ window.__ModuleLoader__.load({
18997
19647
  }
18998
19648
  const target = pf.region || pendingRegions[0];
18999
19649
  if (!target) return;
19000
- pendingFocusRef.current = null;
19650
+ if (!sameFile(modelPathOf(ed), pf.path)) return;
19651
+ dropPending();
19001
19652
  ed.revealLineInCenter(Math.max(1, target.start ?? 1));
19002
19653
  ed.setPosition({
19003
19654
  lineNumber: Math.max(1, target.start ?? 1),
@@ -19923,6 +20574,13 @@ window.__ModuleLoader__.load({
19923
20574
  endLine: endLine ?? null,
19924
20575
  endColumn: endColumn ?? null
19925
20576
  };
20577
+ putPendingNav({
20578
+ path: normalized,
20579
+ line: line ?? null,
20580
+ column: column ?? 1,
20581
+ endLine: endLine ?? null,
20582
+ endColumn: endColumn ?? null
20583
+ });
19926
20584
  setFocusRequest((value) => value + 1);
19927
20585
  };
19928
20586
  const dapOpenRef = react.default.useRef(null);
@@ -20405,6 +21063,7 @@ window.__ModuleLoader__.load({
20405
21063
  onClose: () => setSnippetPicker(null)
20406
21064
  }) : null;
20407
21065
  const sidebarPanels = props.sidebarPanels;
21066
+ const svnChangeMapMemo = react.default.useMemo(() => svnChangeMapOf(scope), [scope, svnChanges]);
20408
21067
  const sidebarCtx = {
20409
21068
  sessionId,
20410
21069
  cwd: cwd ?? null,
@@ -20424,7 +21083,7 @@ window.__ModuleLoader__.load({
20424
21083
  addToConversation,
20425
21084
  svn: svnStatus,
20426
21085
  svnChanges,
20427
- svnChangeMap: svnChangeMapOf(scope),
21086
+ svnChangeMap: svnChangeMapMemo,
20428
21087
  openSvnDiff: (p) => runSvnDiffBase(p),
20429
21088
  openSvnLocalPair: runSvnDiffLocalPair,
20430
21089
  refreshSvnChanges: () => refreshSvnChanges(sessionId, scope),
@@ -21079,7 +21738,7 @@ window.__ModuleLoader__.load({
21079
21738
  if (otherFiles.length) othersEl = react.default.createElement("div", { className: "edrv-diffbox-others" }, react.default.createElement("span", { className: "edrv-diffrow-tag" }, "其他差异文件 (" + otherFiles.length + "):"), otherFiles.map((f) => react.default.createElement("button", {
21080
21739
  key: f.path,
21081
21740
  className: "edrv-diffrow-file",
21082
- title: f.path,
21741
+ title: f.label ?? f.path,
21083
21742
  onClick: () => onOpenOther(f.path)
21084
21743
  }, String(f.path).split(/[\\/]/).pop() + " (" + f.pending + ")")));
21085
21744
  bodyEl = react.default.createElement("div", { className: "edrv-diffbar-body" }, ...rows, ...stale, othersEl);
@@ -22503,6 +23162,8 @@ window.__ModuleLoader__.load({
22503
23162
  * 开关 + 模型下拉(edrv.ai.models 目录,按 provider 分组,默认「自动」)+
22504
23163
  * 思考强度下拉(随所选模型的 efforts 元数据动态渲染:无档位隐藏;含「跟随默认」)。
22505
23164
  * 保存走 edrv.ai.configUpdate;保存后广播 edrv:ai-config 事件让 provider 即时生效。
23165
+ * 第二组「AI 任务模型」:非补全 AI 调用(AI 智能整理等)专用路由,独立于补全模型;
23166
+ * 留空 = 跟随补全模型配置(向后兼容)。
22506
23167
  * 作者 ddj
22507
23168
  */
22508
23169
  /**
@@ -22521,7 +23182,10 @@ window.__ModuleLoader__.load({
22521
23182
  enabled: c.enabled,
22522
23183
  provider: c.provider,
22523
23184
  model: c.model,
22524
- effort: c.effort
23185
+ effort: c.effort,
23186
+ taskProvider: c.taskProvider || "",
23187
+ taskModel: c.taskModel || "",
23188
+ taskEffort: c.taskEffort || ""
22525
23189
  });
22526
23190
  else setError(c.error || "配置读取失败");
22527
23191
  if (d.ok) setDir(d);
@@ -22534,11 +23198,11 @@ window.__ModuleLoader__.load({
22534
23198
  if (!provider) return dir.providers[0]?.models ?? [];
22535
23199
  return dir.providers.find((p) => p.id === provider)?.models ?? [];
22536
23200
  };
22537
- /** 档位可选项:模型无 reasoning 元数据 → 空数组(选择器隐藏)。 */
22538
- const efforts = (() => {
22539
- const models = modelsOf(cfg?.provider);
22540
- return models.find((m) => m.model === cfg?.model)?.efforts ?? models[0]?.efforts ?? [];
22541
- })();
23201
+ /** 档位可选项(补全/任务两组选择器共用):模型无 reasoning 元数据 → 空数组(隐藏)。 */
23202
+ const effortsOf = (provider, model) => {
23203
+ const models = modelsOf(provider);
23204
+ return models.find((m) => m.model === model)?.efforts ?? models[0]?.efforts ?? [];
23205
+ };
22542
23206
  const save = async (patch) => {
22543
23207
  setBusy(true);
22544
23208
  setError("");
@@ -22549,7 +23213,10 @@ window.__ModuleLoader__.load({
22549
23213
  enabled: res.enabled,
22550
23214
  provider: res.provider,
22551
23215
  model: res.model,
22552
- effort: res.effort
23216
+ effort: res.effort,
23217
+ taskProvider: res.taskProvider || "",
23218
+ taskModel: res.taskModel || "",
23219
+ taskEffort: res.taskEffort || ""
22553
23220
  });
22554
23221
  setAiInlineEnabled(res.enabled);
22555
23222
  setNote("已保存");
@@ -22561,27 +23228,41 @@ window.__ModuleLoader__.load({
22561
23228
  }
22562
23229
  };
22563
23230
  const toggle = () => save({ enabled: !cfg.enabled });
22564
- const pickModel = (value) => {
22565
- if (!value) return save({
22566
- provider: "",
22567
- model: ""
22568
- });
23231
+ /** 下拉值 `provider/model` 换模型 patch(档位不属新模型时一并清空;补全/任务两组共用)。 */
23232
+ const patchOfModel = (value, keys) => {
23233
+ if (!value) return {
23234
+ [keys.provider]: "",
23235
+ [keys.model]: ""
23236
+ };
22569
23237
  const idx = value.indexOf("/");
22570
23238
  const provider = value.slice(0, idx);
22571
23239
  const model = value.slice(idx + 1);
22572
- const keep = (modelsOf(provider).find((m) => m.model === model)?.efforts ?? []).some((e) => e.id === cfg.effort);
22573
- save(keep ? {
22574
- provider,
22575
- model
23240
+ return (modelsOf(provider).find((m) => m.model === model)?.efforts ?? []).some((e) => e.id === cfg[keys.effort]) ? {
23241
+ [keys.provider]: provider,
23242
+ [keys.model]: model
22576
23243
  } : {
22577
- provider,
22578
- model,
22579
- effort: ""
22580
- });
23244
+ [keys.provider]: provider,
23245
+ [keys.model]: model,
23246
+ [keys.effort]: ""
23247
+ };
22581
23248
  };
23249
+ const pickModel = (value) => save(patchOfModel(value, {
23250
+ provider: "provider",
23251
+ model: "model",
23252
+ effort: "effort"
23253
+ }));
23254
+ const pickTaskModel = (value) => save(patchOfModel(value, {
23255
+ provider: "taskProvider",
23256
+ model: "taskModel",
23257
+ effort: "taskEffort"
23258
+ }));
22582
23259
  if (!cfg) return react.default.createElement("div", { className: "vsm-mcp-empty" }, error || "正在读取 AI 补全配置…");
22583
23260
  const modelValue = cfg.provider && cfg.model ? cfg.provider + "/" + cfg.model : "";
23261
+ const taskModelValue = cfg.taskProvider && cfg.taskModel ? cfg.taskProvider + "/" + cfg.taskModel : "";
23262
+ const efforts = effortsOf(cfg.provider, cfg.model);
23263
+ const taskEfforts = effortsOf(cfg.taskProvider, cfg.taskModel);
22584
23264
  const delisted = isDelistedModel(cfg.model);
23265
+ const taskDelisted = isDelistedModel(cfg.taskModel);
22585
23266
  return react.default.createElement("section", { className: "vsm-lsp-card" }, react.default.createElement("h3", null, "AI 自动补全(实验)"), react.default.createElement("p", { className: "vsm-lsp-note" }, "编辑停顿后由模型生成内联建议(ghost text),Tab 接受,Alt+\\ 手动触发。每次补全是一次模型调用;建议选择非推理模型,且思考强度选「跟随默认」或最低档以获得更快响应。"), delisted ? react.default.createElement("div", { className: "vsm-mcp-error vsm-mcp-banner" }, "当前模型「" + cfg.model + "」已从 DSH 默认模型列表移除(0.1.6-alpha.2 起)。该模型可能不再可用;将「模型」改回「自动」即可使用第一个可用模型(现有配置不会被自动改动)。") : null, react.default.createElement("div", { className: "vsm-lsp-row" }, react.default.createElement("button", {
22586
23267
  className: cfg.enabled ? "vsm-primary" : "",
22587
23268
  disabled: busy,
@@ -22600,6 +23281,20 @@ window.__ModuleLoader__.load({
22600
23281
  }, react.default.createElement("option", { value: "" }, "跟随默认"), efforts.map((e) => react.default.createElement("option", {
22601
23282
  key: e.id,
22602
23283
  value: e.id
23284
+ }, e.name)))) : null), react.default.createElement("h3", null, "AI 任务模型(AI 智能整理等非补全调用)"), react.default.createElement("p", { className: "vsm-lsp-note" }, "独立于补全模型:整理分析可选推理模型 + 较高思考强度,补全仍可选快模型。留空 = 跟随补全模型配置。"), taskDelisted ? react.default.createElement("div", { className: "vsm-mcp-error vsm-mcp-banner" }, "任务模型「" + cfg.taskModel + "」已从 DSH 默认模型列表移除(0.1.6-alpha.2 起)。该模型可能不再可用;将「模型」改回「自动」即可跟随补全配置(现有配置不会被自动改动)。") : null, react.default.createElement("div", { className: "vsm-lsp-row" }, react.default.createElement("label", null, "模型", react.default.createElement("select", {
23285
+ value: taskModelValue,
23286
+ disabled: busy || !dir?.providers?.length,
23287
+ onChange: (e) => pickTaskModel(e.target.value)
23288
+ }, react.default.createElement("option", { value: "" }, "自动(跟随补全配置)"), (dir?.providers ?? []).flatMap((p) => p.models.map((m) => react.default.createElement("option", {
23289
+ key: p.id + "/" + m.model,
23290
+ value: p.id + "/" + m.model
23291
+ }, p.name + " · " + m.name))))), taskEfforts.length ? react.default.createElement("label", null, "思考强度", react.default.createElement("select", {
23292
+ value: cfg.taskEffort,
23293
+ disabled: busy,
23294
+ onChange: (e) => save({ taskEffort: e.target.value })
23295
+ }, react.default.createElement("option", { value: "" }, "跟随默认"), taskEfforts.map((e) => react.default.createElement("option", {
23296
+ key: e.id,
23297
+ value: e.id
22603
23298
  }, e.name)))) : null), note && react.default.createElement("div", { className: "vsm-compat-item ok" }, react.default.createElement("span", { className: "vsm-compat-name" }, note)), error && react.default.createElement("div", { className: "vsm-mcp-error vsm-mcp-banner" }, error));
22604
23299
  }
22605
23300
  //#endregion
@@ -24248,6 +24943,25 @@ window.__ModuleLoader__.load({
24248
24943
  const IconCodeOutline16 = iconOf("IconCodeOutline16", "IconCodeOutlineRegular");
24249
24944
  /** 分支图标(SVN 面板)。 */
24250
24945
  const IconBranchOutline16 = iconOf("IconBranchOutline16", "IconBranchOutlineRegular");
24946
+ /**
24947
+ * 文件图标元素(官方 FileTypeIcon + classifyFileType 分类,未知类型为 other)。
24948
+ * 文件树与 SVN 变更行共用(原为 FileExplorer 私有副本,上移共享防两处漂移)。
24949
+ * @author ddj 2026年09月23号
24950
+ * @param name 文件名(含扩展名;目录由调用方走目录图标)
24951
+ * @returns 图标元素;原语缺失或分类异常返回 null
24952
+ */
24953
+ function fileIconEl(name) {
24954
+ if (typeof _deepseek_ai_dsh_client_ui_primitives.FileTypeIcon !== "function" || typeof _deepseek_ai_dsh_client_ui_primitives.classifyFileType !== "function") return null;
24955
+ try {
24956
+ return (0, _deepseek_ai_dsh_client_ui_primitives.FileTypeIcon)({
24957
+ kind: (0, _deepseek_ai_dsh_client_ui_primitives.classifyFileType)(String(name ?? "")),
24958
+ size: 16,
24959
+ className: "edrv-tree-icon"
24960
+ });
24961
+ } catch (error) {
24962
+ return null;
24963
+ }
24964
+ }
24251
24965
  //#endregion
24252
24966
  //#region src/client/sidebar/contextMenu.ts
24253
24967
  /** 校验菜单项并写入注册表(缺 id/run/label 抛 TypeError)。 */
@@ -24634,24 +25348,6 @@ window.__ModuleLoader__.load({
24634
25348
  });
24635
25349
  }
24636
25350
  /**
24637
- * 文件图标元素(官方 FileTypeIcon + classifyFileType 分类,未知类型为 other)。
24638
- * @author ddj 2026年09月10号
24639
- * @param name 文件名(含扩展名)
24640
- * @returns 图标元素;原语缺失或分类异常返回 null
24641
- */
24642
- function fileIconEl(name) {
24643
- if (typeof _deepseek_ai_dsh_client_ui_primitives.FileTypeIcon !== "function" || typeof _deepseek_ai_dsh_client_ui_primitives.classifyFileType !== "function") return null;
24644
- try {
24645
- return react.default.createElement(_deepseek_ai_dsh_client_ui_primitives.FileTypeIcon, {
24646
- kind: (0, _deepseek_ai_dsh_client_ui_primitives.classifyFileType)(String(name ?? "")),
24647
- size: 16,
24648
- className: "edrv-tree-icon"
24649
- });
24650
- } catch (error) {
24651
- return null;
24652
- }
24653
- }
24654
- /**
24655
25351
  * 行图标分派:目录 → 文件夹图标,文件 → 官方类型图标。
24656
25352
  * @author ddj 2026年09月10号
24657
25353
  * @param e 目录条目(name/type)
@@ -26163,6 +26859,327 @@ window.__ModuleLoader__.load({
26163
26859
  }, renderTabs(), renderWsLine(), react.default.createElement("div", { className: "edrv-rules-hint" }, tab === "user" ? "用户规则对所有会话生效(存放于 ~/.dsh/rules/)" : "项目规则仅对所在工作区的会话生效(存放于 <工作区>/.dsh/rules/)"), renderBody());
26164
26860
  }
26165
26861
  //#endregion
26862
+ //#region src/client/ui/SvnAiPlanDialog.ts
26863
+ /**
26864
+ * dsh-vscode-mode client — AI 智能整理弹窗(11-ai-changelist-triage)。
26865
+ *
26866
+ * 双阶段单弹窗:
26867
+ * - 预览(run = null):按**整理功能**划分三个分组卡(建议分组 changelist / 建议还原 revert /
26868
+ * 建议忽略 svn:ignore),每段段级全选 + 逐项勾选确认;默认「分组勾选(可逆无副作用)、
26869
+ * 还原/忽略不勾(有副作用)」,未勾选项一律不动。
26870
+ * - 执行(run 非空):弹窗不关闭,切换为进度视图——阶段徽标 + 步骤计数 + 总进度条 +
26871
+ * 逐步日志(✓/✗,失败红字);「暂停」在当前 RPC 返回后的步骤边界生效(svn 子进程不可
26872
+ * 安全中断,如实标注「等待当前步骤完成…」),「继续」从断点续跑,「取消剩余」终止未执行
26873
+ * 步骤(已执行不回滚)。
26874
+ * Esc/遮罩仅在预览阶段生效(= 取消零副作用);执行阶段防误关。
26875
+ * 作者 ddj 2026年09月23号
26876
+ */
26877
+ /**
26878
+ * 预览勾选初值:分组默认全勾(changelist 可逆),还原/忽略默认不勾(有副作用)。
26879
+ * @author ddj 2026年09月23号
26880
+ * @param plan 三段方案
26881
+ * @returns 勾选态(组级 + 逐项)
26882
+ */
26883
+ function initPlanSel(plan) {
26884
+ return {
26885
+ groups: (plan.groups || []).map((group) => ({
26886
+ name: group.name,
26887
+ reason: group.reason || "",
26888
+ checked: true,
26889
+ paths: (group.paths || []).map((path) => ({
26890
+ path,
26891
+ checked: true
26892
+ }))
26893
+ })),
26894
+ reverts: (plan.reverts || []).map((item) => ({
26895
+ path: item.path,
26896
+ reason: item.reason || "",
26897
+ checked: false
26898
+ })),
26899
+ ignores: (plan.ignores || []).map((item) => ({
26900
+ path: item.path,
26901
+ reason: item.reason || "",
26902
+ checked: false
26903
+ }))
26904
+ };
26905
+ }
26906
+ /**
26907
+ * 勾选态 → 执行载荷(空段/空组剔除;保持勾选顺序)。
26908
+ * @author ddj 2026年09月23号
26909
+ * @param sel 勾选态
26910
+ * @returns 执行载荷 { groups, reverts, ignores }
26911
+ */
26912
+ function selectedOf(sel) {
26913
+ const groups = [];
26914
+ for (const group of sel.groups) {
26915
+ const paths = group.paths.filter((p) => p.checked).map((p) => p.path);
26916
+ if (group.checked && paths.length) groups.push({
26917
+ name: group.name,
26918
+ paths
26919
+ });
26920
+ }
26921
+ return {
26922
+ groups,
26923
+ reverts: sel.reverts.filter((item) => item.checked).map((item) => item.path),
26924
+ ignores: sel.ignores.filter((item) => item.checked).map((item) => item.path)
26925
+ };
26926
+ }
26927
+ /** 执行载荷 → 已选动作总数(「执行所选」禁用判定)。 */
26928
+ function selectedCount(selected) {
26929
+ let n = selected.reverts.length + selected.ignores.length;
26930
+ for (const group of selected.groups) n += group.paths.length;
26931
+ return n;
26932
+ }
26933
+ /** 复选框元素(原生 input;仓库 UI 原语无 Checkbox,此处沿用补丁对话框的原生控件口径)。 */
26934
+ function checkBoxEl(checked, onToggle, title) {
26935
+ return react.default.createElement("input", {
26936
+ type: "checkbox",
26937
+ checked,
26938
+ title,
26939
+ onChange: () => onToggle(),
26940
+ onClick: (event) => event.stopPropagation()
26941
+ });
26942
+ }
26943
+ /** 段头(全选框 + 标题 + 计数 + 副标题)。 */
26944
+ function sectionHeadEl(title, note, allChecked, onToggleAll, countText) {
26945
+ return react.default.createElement("div", { className: "edrv-svnplan-sechead" }, checkBoxEl(allChecked, onToggleAll, "全选/全不选"), react.default.createElement("span", { className: "edrv-svnplan-sectitle" }, title), react.default.createElement("span", { className: "edrv-svn-count" }, countText), note ? react.default.createElement("span", { className: "edrv-svnplan-note" }, note) : null);
26946
+ }
26947
+ /**
26948
+ * 阶段一 · 预览确认(按整理功能三分组)。
26949
+ * @author ddj 2026年09月23号
26950
+ * @param sel 勾选态
26951
+ * @param setSel 勾选态更新
26952
+ * @param open 组卡展开集合(组名)
26953
+ * @param toggleOpen 组卡展开切换
26954
+ * @returns 预览主体元素
26955
+ */
26956
+ function previewBodyEl(sel, setSel, open, toggleOpen) {
26957
+ /** 通用段更新(reverts/ignores 共用)。 */
26958
+ const patchItems = (key, index, checked) => setSel((old) => ({
26959
+ ...old,
26960
+ [key]: old[key].map((item, i) => i === index ? {
26961
+ ...item,
26962
+ checked
26963
+ } : item)
26964
+ }));
26965
+ const toggleItemsAll = (key, checked) => setSel((old) => ({
26966
+ ...old,
26967
+ [key]: old[key].map((item) => ({
26968
+ ...item,
26969
+ checked
26970
+ }))
26971
+ }));
26972
+ /** 组级/组内更新。 */
26973
+ const patchGroup = (index, patch) => setSel((old) => ({
26974
+ ...old,
26975
+ groups: old.groups.map((group, i) => i === index ? {
26976
+ ...group,
26977
+ ...patch
26978
+ } : group)
26979
+ }));
26980
+ const toggleGroupAll = (index, checked) => setSel((old) => ({
26981
+ ...old,
26982
+ groups: old.groups.map((group, i) => i === index ? {
26983
+ ...group,
26984
+ checked,
26985
+ paths: group.paths.map((p) => ({
26986
+ ...p,
26987
+ checked
26988
+ }))
26989
+ } : group)
26990
+ }));
26991
+ const groupCards = sel.groups.map((group, index) => {
26992
+ const done = group.paths.filter((p) => p.checked).length;
26993
+ const isOpen = open.has(group.name);
26994
+ const fileRows = isOpen ? group.paths.map((item, pi) => react.default.createElement("div", {
26995
+ key: item.path,
26996
+ className: "edrv-svnplan-item"
26997
+ }, checkBoxEl(item.checked, () => patchGroup(index, { paths: group.paths.map((p, j) => j === pi ? {
26998
+ ...p,
26999
+ checked: !p.checked
27000
+ } : p) }), item.path), react.default.createElement("span", {
27001
+ className: "edrv-svnplan-path",
27002
+ title: item.path
27003
+ }, item.path))) : null;
27004
+ return react.default.createElement("div", {
27005
+ key: group.name,
27006
+ className: "edrv-svnplan-card"
27007
+ }, react.default.createElement("div", { className: "edrv-svnplan-row" }, checkBoxEl(group.checked, () => toggleGroupAll(index, !group.checked), "全选该组"), react.default.createElement("span", {
27008
+ className: "edrv-svnplan-groupname",
27009
+ title: "点击展开/收起成员",
27010
+ onClick: () => toggleOpen(group.name)
27011
+ }, (isOpen ? "▾ " : "▸ ") + group.name), react.default.createElement("span", { className: "edrv-svn-count" }, done + "/" + group.paths.length + " 项"), group.reason ? react.default.createElement("span", {
27012
+ className: "edrv-svnplan-reason",
27013
+ title: group.reason
27014
+ }, group.reason) : null), fileRows);
27015
+ });
27016
+ const itemRowsOf = (key) => sel[key].map((item, index) => react.default.createElement("div", {
27017
+ key: item.path,
27018
+ className: "edrv-svnplan-item"
27019
+ }, checkBoxEl(item.checked, () => patchItems(key, index, !item.checked), item.path), react.default.createElement("span", {
27020
+ className: "edrv-svnplan-path",
27021
+ title: item.path
27022
+ }, item.path), item.reason ? react.default.createElement("span", {
27023
+ className: "edrv-svnplan-reason",
27024
+ title: item.reason
27025
+ }, item.reason) : null));
27026
+ const groupsAll = sel.groups.length > 0 && sel.groups.every((g) => g.checked && g.paths.every((p) => p.checked));
27027
+ const revertsAll = sel.reverts.length > 0 && sel.reverts.every((i) => i.checked);
27028
+ const ignoresAll = sel.ignores.length > 0 && sel.ignores.every((i) => i.checked);
27029
+ return react.default.createElement(react.default.Fragment, null, react.default.createElement("div", { className: "edrv-svnplan-sec" }, sectionHeadEl("建议分组(changelist)", "无副作用、可逆", groupsAll, () => setSel((old) => ({
27030
+ ...old,
27031
+ groups: old.groups.map((group) => ({
27032
+ ...group,
27033
+ checked: !groupsAll,
27034
+ paths: group.paths.map((p) => ({
27035
+ ...p,
27036
+ checked: !groupsAll
27037
+ }))
27038
+ }))
27039
+ })), sel.groups.length + " 组"), react.default.createElement("div", { className: "edrv-svnplan-list" }, groupCards)), react.default.createElement("div", { className: "edrv-svnplan-sec" }, sectionHeadEl("建议还原(revert)", "放弃本地改动,默认不勾", revertsAll, () => toggleItemsAll("reverts", !revertsAll), sel.reverts.length + " 项"), react.default.createElement("div", { className: "edrv-svnplan-list" }, itemRowsOf("reverts"))), react.default.createElement("div", { className: "edrv-svnplan-sec" }, sectionHeadEl("建议忽略(svn:ignore)", "将写入 svn:ignore 属性,随提交进仓库,默认不勾", ignoresAll, () => toggleItemsAll("ignores", !ignoresAll), sel.ignores.length + " 项"), react.default.createElement("div", { className: "edrv-svnplan-list" }, itemRowsOf("ignores"))));
27040
+ }
27041
+ /**
27042
+ * 阶段二 · 执行进度(阶段徽标 + 计数 + 进度条 + 逐步日志)。
27043
+ * @author ddj 2026年09月23号
27044
+ * @param run 执行状态
27045
+ * @returns 进度主体元素
27046
+ */
27047
+ function progressBodyEl(run) {
27048
+ const pct = run.total > 0 ? Math.floor(run.index / run.total * 100) : 0;
27049
+ const statusText = run.status === "pausing" ? "等待当前步骤完成…(暂停在步骤边界生效)" : run.status === "paused" ? "已暂停" : run.status === "cancelling" ? "正在取消剩余步骤…" : run.status === "done" ? run.cancelled ? "已取消剩余步骤" : "执行完毕" : "执行中…";
27050
+ const logRows = run.log.map((entry, index) => react.default.createElement("div", {
27051
+ key: index,
27052
+ className: "edrv-svnplan-log" + (entry.ok ? "" : " edrv-svnplan-log-bad")
27053
+ }, (entry.ok ? "✓ " : "✗ ") + entry.text));
27054
+ return react.default.createElement(react.default.Fragment, null, react.default.createElement("div", { className: "edrv-svnplan-stage" }, react.default.createElement("span", { className: "edrv-svnplan-badge" }, statusText), run.cur ? react.default.createElement("span", { className: "edrv-svnplan-badge edrv-svnplan-badge-cur" }, run.cur) : null, react.default.createElement("span", { className: "edrv-svn-count" }, run.index + "/" + run.total + " 步")), react.default.createElement("div", { className: "edrv-svnplan-bar" }, react.default.createElement("div", {
27055
+ className: "edrv-svnplan-bar-in",
27056
+ style: { width: pct + "%" }
27057
+ })), react.default.createElement("div", { className: "edrv-svnplan-logwrap" }, logRows));
27058
+ }
27059
+ /**
27060
+ * AI 智能整理弹窗(预览 + 进度双阶段)。
27061
+ * @author ddj 2026年09月23号
27062
+ * @param props.plan 三段方案(host 已归一)
27063
+ * @param props.meta 分析元信息 { entriesCount, diffIncluded, dropped, model, source? }(source='agent' = 混合通道)
27064
+ * @param props.run 执行状态;null = 预览阶段(shape 见 SvnPanel runPlanSteps)
27065
+ * @param props.onExecute 预览确认(选中载荷 → 启动执行引擎)
27066
+ * @param props.onPause 暂停(步骤边界生效)
27067
+ * @param props.onResume 继续
27068
+ * @param props.onCancelRest 取消剩余
27069
+ * @param props.onClose 关闭(预览 = 取消零副作用;执行阶段按钮仅在结束后可用)
27070
+ * @returns 弹窗元素
27071
+ */
27072
+ function SvnAiPlanDialog(props) {
27073
+ const { plan, meta, run, onExecute, onPause, onResume, onCancelRest, onClose } = props;
27074
+ const [sel, setSel] = react.default.useState(() => initPlanSel(plan));
27075
+ const [open, setOpen] = react.default.useState(() => /* @__PURE__ */ new Set());
27076
+ const selected = selectedOf(sel);
27077
+ const count = selectedCount(selected);
27078
+ /** 组卡展开切换(纯 UI 态)。 */
27079
+ const toggleOpen = (name) => {
27080
+ const next = new Set(open);
27081
+ if (next.has(name)) next.delete(name);
27082
+ else next.add(name);
27083
+ setOpen(next);
27084
+ };
27085
+ const running = run !== null && run.status !== "done";
27086
+ const header = react.default.createElement("div", { className: "edrv-svnplan-head" }, react.default.createElement("h3", { className: "edrv-svnlog-title" }, "AI 智能整理 SVN 变更"), meta?.source === "agent" ? react.default.createElement("span", {
27087
+ className: "edrv-svnplan-badge",
27088
+ title: "会话 AI 助手深度分析(codegraph/读文件)产出"
27089
+ }, "AI 助手深度分析") : null, meta?.model ? react.default.createElement("span", {
27090
+ className: "edrv-svn-count",
27091
+ title: "分析模型"
27092
+ }, meta.model) : null, react.default.createElement("span", { style: { flex: 1 } }), react.default.createElement("button", {
27093
+ className: "edrv-svn-act",
27094
+ title: running ? "执行中不可关闭(可取消剩余)" : "关闭",
27095
+ disabled: running,
27096
+ onClick: onClose
27097
+ }, "✕"));
27098
+ const metaEl = react.default.createElement("div", { className: "edrv-svnplan-meta" }, react.default.createElement("span", { className: "edrv-svn-count" }, "分析条目 " + (meta?.entriesCount ?? 0) + " 项"), (meta?.dropped ?? 0) > 0 ? react.default.createElement("span", { className: "edrv-svn-count" }, "已丢弃 AI 无效建议 " + meta.dropped + " 项") : null, meta?.diffIncluded === false ? react.default.createElement("span", { className: "edrv-svnplan-note" }, "未含 diff 上下文,分析精度有限") : null);
27099
+ let body = null;
27100
+ let footer = null;
27101
+ if (run === null) {
27102
+ body = previewBodyEl(sel, setSel, open, toggleOpen);
27103
+ footer = react.default.createElement("div", { className: "edrv-svnplan-foot" }, react.default.createElement("span", { className: "edrv-svn-count" }, "已选 " + count + " 项"), react.default.createElement("span", { style: { flex: 1 } }), react.default.createElement("button", {
27104
+ className: "edrv-svn-act",
27105
+ title: "不执行任何动作",
27106
+ onClick: onClose
27107
+ }, "取消"), react.default.createElement("button", {
27108
+ className: "edrv-svn-act edrv-svnplan-primary",
27109
+ title: "执行全部勾选项(未勾选不动)",
27110
+ disabled: count === 0,
27111
+ onClick: () => onExecute(selected)
27112
+ }, "执行所选(" + count + " 项)"));
27113
+ } else {
27114
+ body = progressBodyEl(run);
27115
+ footer = react.default.createElement("div", { className: "edrv-svnplan-foot" }, react.default.createElement("span", { style: { flex: 1 } }), run.status === "done" ? react.default.createElement("button", {
27116
+ className: "edrv-svn-act edrv-svnplan-primary",
27117
+ title: "关闭弹窗并刷新变更列表",
27118
+ onClick: onClose
27119
+ }, "关闭并刷新") : react.default.createElement(react.default.Fragment, null, react.default.createElement("button", {
27120
+ className: "edrv-svn-act",
27121
+ title: run.status === "running" || run.status === "pausing" ? "暂停(当前步骤完成后生效)" : "从断点继续执行",
27122
+ disabled: run.status === "pausing" || run.status === "cancelling",
27123
+ onClick: run.status === "paused" ? onResume : onPause
27124
+ }, run.status === "paused" ? "继续" : "暂停"), react.default.createElement("button", {
27125
+ className: "edrv-svn-act edrv-svn-act-danger",
27126
+ title: "终止未执行步骤(已执行部分不回滚)",
27127
+ disabled: run.status === "cancelling",
27128
+ onClick: onCancelRest
27129
+ }, "取消剩余")));
27130
+ }
27131
+ return react.default.createElement(ModalShell, {
27132
+ key: "edrv-svn-plan",
27133
+ dialogClass: "edrv-svnplan-dialog",
27134
+ width: "min(680px, calc(100vw - 48px))",
27135
+ closeOnMask: !running,
27136
+ closeOnEsc: !running,
27137
+ onClose
27138
+ }, header, metaEl, body, footer);
27139
+ }
27140
+ //#endregion
27141
+ //#region src/client/sidebar/panels/svnListBudget.ts
27142
+ /**
27143
+ * 按 DOM 预算切分分组行(渐进渲染)。
27144
+ *
27145
+ * 预算跨组依序分配:预算内组整组保留(透传原对象,引用稳定利于行 memo),
27146
+ * 最后触及预算的组被截断,预算耗尽后不再产出**需要行数**的组;
27147
+ * 零行组(如折叠映射的空 entries 组)不占预算,恒产出组头。
27148
+ * 组头计数恒显全量(full),行只渲染预算内(entries),避免「截断组计数变小」的误导。
27149
+ * @author ddj 2026年09月23号
27150
+ * @param groups groupByChangelist 产出的分组
27151
+ * @param budget 允许渲染的条目行数上限
27152
+ * @returns 截断后的分组与计数
27153
+ */
27154
+ function budgetGroupsOf(groups, budget) {
27155
+ const total = groups.reduce((sum, group) => sum + group.entries.length, 0);
27156
+ const limit = Math.max(0, budget);
27157
+ if (total <= limit) return {
27158
+ groups: [...groups],
27159
+ shown: total,
27160
+ total,
27161
+ hasMore: false
27162
+ };
27163
+ const sliced = [];
27164
+ let used = 0;
27165
+ for (const group of groups) {
27166
+ if (used >= limit && group.entries.length > 0) break;
27167
+ const take = Math.min(group.entries.length, limit - used);
27168
+ sliced.push(take >= group.entries.length ? group : {
27169
+ name: group.name,
27170
+ entries: group.entries.slice(0, take),
27171
+ full: group.entries.length
27172
+ });
27173
+ used += take;
27174
+ }
27175
+ return {
27176
+ groups: sliced,
27177
+ shown: used,
27178
+ total,
27179
+ hasMore: true
27180
+ };
27181
+ }
27182
+ //#endregion
26166
27183
  //#region src/client/sidebar/panels/SvnPanel.ts
26167
27184
  /**
26168
27185
  * dsh-vscode-mode client — 侧边栏「SVN 变更」面板(工作副本状态视图)。
@@ -26182,6 +27199,91 @@ window.__ModuleLoader__.load({
26182
27199
  /** 还原确认文案(新增文件不会被删除是 svn revert 的实际语义,须如实告知)。 */
26183
27200
  const REVERT_CONFIRM_HEAD = "确认还原以下 ";
26184
27201
  const REVERT_CONFIRM_TAIL = " 个文件的本地改动?新增(A)文件在磁盘上会保留,仅取消登记。";
27202
+ /** 列表渐进渲染步长(初始也按此值):数据量大时避免一次建满 DOM(面板随编辑区任意刷新重渲)。 */
27203
+ const RENDER_STEP = 500;
27204
+ /** 还原确认弹窗最多完整列出的路径数(超出折叠为「…等 N 个文件」,防大列表拼超长文案卡 UI)。 */
27205
+ const CONFIRM_PREVIEW_CAP = 50;
27206
+ /** 混合通道取件轮询间隔(毫秒)与次数上限(3s × 200 = 10 分钟无件自动停)。 */
27207
+ const DEEP_POLL_MS = 3e3;
27208
+ const DEEP_POLL_MAX = 200;
27209
+ /**
27210
+ * 勾选载荷 → 步骤队列(顺序固定 还原 → 分组 → 忽略;块/组/目录各一步,进度粒度对齐)。
27211
+ * @author ddj 2026年09月23号
27212
+ * @param selected 勾选载荷
27213
+ * @param sessionId 会话 id
27214
+ * @returns 步骤队列
27215
+ */
27216
+ function planStepsOf(selected, sessionId) {
27217
+ const steps = [];
27218
+ const reverts = selected.reverts;
27219
+ let revDone = 0;
27220
+ for (const chunk of svnChunksOf(reverts, 64)) {
27221
+ revDone += chunk.length;
27222
+ steps.push({
27223
+ label: "还原 " + revDone + "/" + reverts.length + " 项",
27224
+ kind: "revert",
27225
+ n: chunk.length,
27226
+ run: () => svnRevert(sessionId, chunk)
27227
+ });
27228
+ }
27229
+ const groups = selected.groups;
27230
+ groups.forEach((group, index) => {
27231
+ let done = 0;
27232
+ for (const chunk of svnChunksOf(group.paths, 64)) {
27233
+ done += chunk.length;
27234
+ steps.push({
27235
+ label: "分组 " + (index + 1) + "/" + groups.length + " 组(" + group.name + ")" + done + "/" + group.paths.length + " 项",
27236
+ kind: "group",
27237
+ n: chunk.length,
27238
+ key: group.name,
27239
+ run: () => svnChangelist(sessionId, chunk, group.name)
27240
+ });
27241
+ }
27242
+ });
27243
+ const items = ignoreItemsOf(selected.ignores);
27244
+ items.forEach((item, index) => {
27245
+ steps.push({
27246
+ label: "忽略目录 " + (index + 1) + "/" + items.length + "(" + (item.dir || "工作副本根") + ")",
27247
+ kind: "ignore",
27248
+ n: item.names.length,
27249
+ run: () => svnIgnore(sessionId, [item])
27250
+ });
27251
+ });
27252
+ return steps;
27253
+ }
27254
+ /**
27255
+ * 逐步日志 → 汇总文案(分段计数 + 失败数与首条原因)。
27256
+ * @author ddj 2026年09月23号
27257
+ * @param steps 步骤队列(提供 kind/n/key)
27258
+ * @param log 逐步日志
27259
+ * @param cancelled 是否取消剩余
27260
+ * @returns 汇总文案
27261
+ */
27262
+ function planSummaryOf(steps, log, cancelled) {
27263
+ const sum = {
27264
+ revert: 0,
27265
+ group: 0,
27266
+ ignore: 0,
27267
+ failed: 0,
27268
+ firstFail: ""
27269
+ };
27270
+ const groupNames = /* @__PURE__ */ new Set();
27271
+ log.forEach((entry, index) => {
27272
+ const step = steps[index];
27273
+ if (!step) return;
27274
+ if (entry.ok) {
27275
+ sum[step.kind] += step.n;
27276
+ if (step.kind === "group" && step.key) groupNames.add(step.key);
27277
+ } else {
27278
+ sum.failed++;
27279
+ if (!sum.firstFail) sum.firstFail = entry.text;
27280
+ }
27281
+ });
27282
+ let text = "AI 整理完成:还原 " + sum.revert + " · 分组 " + groupNames.size + " 组 " + sum.group + " 项 · 忽略 " + sum.ignore + " 项";
27283
+ if (sum.failed) text += ";失败 " + sum.failed + "(首条:" + sum.firstFail + ")";
27284
+ if (cancelled) text += ";已取消剩余步骤";
27285
+ return text;
27286
+ }
26185
27287
  /**
26186
27288
  * 读取面板显示开关(损坏/不可用安全)。
26187
27289
  * @author ddj 2026年09月16号
@@ -26221,6 +27323,36 @@ window.__ModuleLoader__.load({
26221
27323
  } catch (error) {}
26222
27324
  }
26223
27325
  /**
27326
+ * 读取分组折叠集合(损坏/缺省安全;键独立于显示开关,旧数据无键 = 全展开,向后兼容)。
27327
+ * @author ddj 2026年09月23号
27328
+ * @param scope 作用域键
27329
+ * @returns 折叠组名集合
27330
+ */
27331
+ function loadFold(scope) {
27332
+ const empty = /* @__PURE__ */ new Set();
27333
+ if (!scope) return empty;
27334
+ try {
27335
+ const raw = window.localStorage.getItem(CACHE_KEY.svn + scope + "#fold");
27336
+ if (!raw) return empty;
27337
+ const parsed = JSON.parse(raw);
27338
+ return new Set(Array.isArray(parsed) ? parsed.filter((name) => typeof name === "string") : []);
27339
+ } catch (error) {
27340
+ return empty;
27341
+ }
27342
+ }
27343
+ /**
27344
+ * 写分组折叠集合(配额/隐私模式失败静默)。
27345
+ * @author ddj 2026年09月23号
27346
+ * @param scope 作用域键
27347
+ * @param names 折叠组名集合
27348
+ */
27349
+ function saveFold(scope, names) {
27350
+ if (!scope) return;
27351
+ try {
27352
+ window.localStorage.setItem(CACHE_KEY.svn + scope + "#fold", JSON.stringify([...names]));
27353
+ } catch (error) {}
27354
+ }
27355
+ /**
26224
27356
  * 刷新按钮图标(官方 IconRefreshOutline16;原语缺失回落文本 ⟳)。
26225
27357
  * @author ddj 2026年09月16号
26226
27358
  * @returns 图标元素或回落文本
@@ -26266,18 +27398,22 @@ window.__ModuleLoader__.load({
26266
27398
  }
26267
27399
  /**
26268
27400
  * 单条变更行(状态字母 + 路径 + 行内动作;双击 = 与基线比较)。
26269
- * @author ddj 2026年09月16号 / 2026年09月20号
27401
+ * React.memo:行 props(entry/pairNote/busy + 稳定回调)不变时跳过重渲染,
27402
+ * 面板因名称过滤/尺寸表等面板内状态重渲时,未受影响的行不再重建。
27403
+ * @author ddj 2026年09月16号 / 2026年09月20号 / 2026年09月23号
26270
27404
  * @param props.entry 变更条目
26271
27405
  * @param props.busy 批量动作进行中(按钮置灰)
26272
27406
  * @param props.onDiff 打开基线差异
26273
27407
  * @param props.onAdd 加入版本控制
26274
27408
  * @param props.onRevert 还原
26275
27409
  * @param props.onConflict 冲突副本对比(W2-4;仅冲突行出现按钮)
27410
+ * @param props.onMenu 行右键菜单(分区管理入口;参数为条目与视口坐标)
27411
+ * @param props.onOpen 单击跳转(编辑区打开/聚焦该文件)
26276
27412
  * @param props.pairNote 疑似改名标记文案(W2-5;空 = 无配对)
26277
27413
  * @returns 行元素
26278
27414
  */
26279
- function SvnRow(props) {
26280
- const { entry, busy, onDiff, onAdd, onRevert, onConflict, pairNote } = props;
27415
+ const SvnRow = react.default.memo(function SvnRow(props) {
27416
+ const { entry, busy, onDiff, onAdd, onRevert, onConflict, onMenu, onOpen, pairNote } = props;
26281
27417
  const diffable = isSvnDiffable(entry.path, entry.status);
26282
27418
  const act = (label, title, danger, run) => react.default.createElement("button", {
26283
27419
  className: "edrv-svn-act" + (danger ? " edrv-svn-act-danger" : ""),
@@ -26291,19 +27427,25 @@ window.__ModuleLoader__.load({
26291
27427
  return react.default.createElement("div", {
26292
27428
  className: "edrv-svn-row",
26293
27429
  title: entry.path,
27430
+ onClick: () => onOpen?.(entry.path),
26294
27431
  onDoubleClick: () => {
26295
27432
  if (diffable) onDiff(entry.path);
27433
+ },
27434
+ onContextMenu: (event) => {
27435
+ if (!onMenu) return;
27436
+ event.preventDefault();
27437
+ onMenu(entry, event.clientX, event.clientY);
26296
27438
  }
26297
- }, statusLetterEl(entry), react.default.createElement("span", { className: "edrv-svn-path" }, entry.path), pairNote ? react.default.createElement("span", {
27439
+ }, fileIconEl(String(entry.path ?? "").split(/[\\/]/).pop() || ""), statusLetterEl(entry), react.default.createElement("span", { className: "edrv-svn-path" }, entry.path), pairNote ? react.default.createElement("span", {
26298
27440
  className: "edrv-svn-pair-mark",
26299
27441
  title: pairNote
26300
27442
  }, "⇄") : null, react.default.createElement("span", { className: "edrv-svn-acts" }, entry.status === "conflicted" ? act("冲突对比", "与 .mine/.rN 冲突副本并排对比(解决指引见差异视图顶部)", false, () => onConflict(entry.path)) : null, diffable ? act("比较", "与基线比较(BASE 与工作区并排)", false, () => onDiff(entry.path)) : null, !entry.versioned ? act("加入", SVN_ADD_LABEL, false, () => onAdd([entry.path])) : null, entry.versioned ? act("还原", "SVN 还原(放弃本地改动)", true, () => onRevert([entry.path])) : null));
26301
- }
27443
+ });
26302
27444
  /**
26303
- * 列表主体:分组行 + 条目行;未受管理/加载中/无变更各自给出稳定文案。
26304
- * @author ddj 2026年09月16号
26305
- * @param state 列表状态(managed/entries/visible/groups
26306
- * @param handlers 行动作(onDiff/onAdd/onRevert/busy)
27445
+ * 列表主体:分组行 + 条目行(按预算渐进渲染);未受管理/加载中/无变更各自给出稳定文案。
27446
+ * @author ddj 2026年09月16号 / 2026年09月23号
27447
+ * @param state 列表状态(managed/entries/visible/budget/nameFiltered/capped/collapsedSet/onFold
27448
+ * @param handlers 行动作(onDiff/onAdd/onRevert/onMore/onGroupClRemove/onMenu/busy/pairNotes
26307
27449
  * @returns 主体元素或元素数组
26308
27450
  */
26309
27451
  function svnListBody(state, handlers) {
@@ -26311,20 +27453,70 @@ window.__ModuleLoader__.load({
26311
27453
  if (state.entries === null) return react.default.createElement("div", { className: "edrv-tree-loading" }, "读取变更中…");
26312
27454
  if (!state.visible.length) return react.default.createElement("div", { className: "edrv-tree-loading" }, state.nameFiltered ? "无匹配条目(名称过滤生效中,清空过滤框可看全部)" : "无变更(工作副本干净)");
26313
27455
  const rows = [];
26314
- for (const group of state.groups) {
26315
- if (state.groups.length > 1 || group.name !== NO_CHANGELIST) rows.push(react.default.createElement("div", {
27456
+ for (const group of state.budget.groups) {
27457
+ rows.push(react.default.createElement("div", {
26316
27458
  key: "g:" + group.name,
26317
- className: "edrv-svn-group"
26318
- }, react.default.createElement("span", null, "changelist: " + group.name), react.default.createElement("span", { className: "edrv-svn-group-n" }, String(group.entries.length))));
27459
+ className: "edrv-svn-group",
27460
+ title: "点击折叠/展开该分组",
27461
+ onClick: () => state.onFold?.(group.name)
27462
+ }, react.default.createElement("span", { className: "edrv-svn-fold-ch" }, group.folded ? "▸" : "▾"), react.default.createElement("span", null, "changelist: " + group.name), group.name !== NO_CHANGELIST && handlers.onGroupClRemove ? react.default.createElement("button", {
27463
+ className: "edrv-svn-act",
27464
+ disabled: handlers.busy,
27465
+ title: "把该分区全部文件移出 changelist(不改文件内容;超过 64 项自动分块执行)",
27466
+ onClick: (event) => {
27467
+ event.stopPropagation();
27468
+ handlers.onGroupClRemove(group.name);
27469
+ }
27470
+ }, "移出分区") : null, react.default.createElement("span", { className: "edrv-svn-group-n" }, String(group.full ?? group.entries.length))));
27471
+ if (group.folded) continue;
26319
27472
  for (const entry of group.entries) rows.push(react.default.createElement(SvnRow, Object.assign({
26320
27473
  key: entry.path,
26321
27474
  entry,
26322
27475
  pairNote: handlers.pairNotes?.[entry.path]
26323
27476
  }, handlers)));
26324
27477
  }
27478
+ if (state.budget.hasMore) rows.push(react.default.createElement("button", {
27479
+ key: "edrv-svn-more",
27480
+ className: "edrv-svn-act edrv-svn-more",
27481
+ title: "继续渲染更多条目(每次 500 条;批量动作与导出始终按全量集合计算,不受渲染预算影响)",
27482
+ onClick: handlers.onMore
27483
+ }, "已显示 " + state.budget.shown + " / " + state.budget.total + " 项,显示更多"));
27484
+ if (state.capped) rows.push(react.default.createElement("div", {
27485
+ key: "edrv-svn-capped",
27486
+ className: "edrv-tree-loading"
27487
+ }, "变更条目过多,清单已按上限截断(列表/批量/导出仅含已载入部分);可用名称过滤缩小范围"));
26325
27488
  return rows;
26326
27489
  }
26327
27490
  /**
27491
+ * AI 助手 dock(设计定稿 12-panel-ai-bar):accent 左竖轨 + 「AI 整理」标签 +
27492
+ * 快速分析/深度分析两按钮 + 定宽状态位。按钮文案恒定(忙态只换状态位文案,不跳版);
27493
+ * AI 线程色三处同轨(竖轨/按钮描边/弹窗进度条,--dsw-alias-state-info-primary)。
27494
+ * @author ddj 2026年09月23号
27495
+ * @param props.managed/忙碌标志(managed/busy/aiBusy/deepWaiting/hasRun)
27496
+ * @param props.onQuick 快速分析回调(host LLM 直调)
27497
+ * @param props.onDeep 深度分析回调(会话 agent 投递回面板)
27498
+ * @returns dock 元素
27499
+ */
27500
+ function aiBarEl(props) {
27501
+ const { managed, busy, aiBusy, deepWaiting, hasRun, onQuick, onDeep } = props;
27502
+ const locked = !managed || busy || aiBusy || hasRun;
27503
+ const status = aiBusy ? "分析中…" : deepWaiting ? "等待助手投递…" : "就绪";
27504
+ return react.default.createElement("div", { className: "edrv-svn-ai-bar" }, react.default.createElement("span", {
27505
+ className: "edrv-svn-ai-rail",
27506
+ "aria-hidden": "true"
27507
+ }), react.default.createElement("span", { className: "edrv-svn-ai-label" }, "AI 整理"), react.default.createElement("button", {
27508
+ className: "edrv-svn-act edrv-svn-ai-btn",
27509
+ title: "快速分析:由模型直读变更与差异,产出分组/还原/忽略方案(分析后需勾选确认才执行)",
27510
+ disabled: locked,
27511
+ onClick: onQuick
27512
+ }, "快速分析"), react.default.createElement("button", {
27513
+ className: "edrv-svn-act edrv-svn-ai-btn",
27514
+ title: "深度分析:把分析任务填入对话,由 AI 助手借 codegraph/读文件深度分析后投递方案回本面板(执行仍需勾选确认)",
27515
+ disabled: locked || deepWaiting,
27516
+ onClick: onDeep
27517
+ }, "深度分析"), react.default.createElement("span", { style: { flex: 1 } }), react.default.createElement("span", { className: "edrv-svn-ai-status" }, status));
27518
+ }
27519
+ /**
26328
27520
  * 工具条(显示开关 + 名称过滤 + 批量动作 + 导出)。
26329
27521
  * @author ddj 2026年09月16号 / 2026年09月20号
26330
27522
  * @param props.filter 当前开关(含 W1-2 name)
@@ -26361,11 +27553,11 @@ window.__ModuleLoader__.load({
26361
27553
  className: "edrv-svn-act",
26362
27554
  title: "导出当前列表为 CSV(带 BOM,Excel 直开;状态/路径/changelist/修订)",
26363
27555
  onClick: handlers.onExportCsv
26364
- }, "导出CSV"), react.default.createElement("button", {
27556
+ }, "导出 CSV"), react.default.createElement("button", {
26365
27557
  className: "edrv-svn-act",
26366
27558
  title: "导出当前列表为 HTML 报表(仅本地查看,不外发)",
26367
27559
  onClick: handlers.onExportHtml
26368
- }, "导出HTML"), paths.unversioned.length ? react.default.createElement("button", {
27560
+ }, "导出 HTML"), paths.unversioned.length || paths.revert.length ? react.default.createElement("span", { className: "edrv-svn-sep" }) : null, paths.unversioned.length ? react.default.createElement("button", {
26369
27561
  className: "edrv-svn-act",
26370
27562
  disabled: handlers.busy,
26371
27563
  title: "把全部未版本控制文件加入版本控制(不受名称过滤影响)",
@@ -26394,33 +27586,51 @@ window.__ModuleLoader__.load({
26394
27586
  const [remote, setRemote] = react.default.useState(null);
26395
27587
  const [remoteBusy, setRemoteBusy] = react.default.useState(false);
26396
27588
  const [sizes, setSizes] = react.default.useState({});
27589
+ const [renderLimit, setRenderLimit] = react.default.useState(RENDER_STEP);
27590
+ const ctxRef = react.default.useRef(ctx);
27591
+ ctxRef.current = ctx;
27592
+ const [menu, setMenu] = react.default.useState(null);
27593
+ const [collapsed, setCollapsed] = react.default.useState(() => loadFold(scope));
27594
+ const [aiBusy, setAiBusy] = react.default.useState(false);
27595
+ const [aiPlan, setAiPlan] = react.default.useState(null);
27596
+ const [aiRun, setAiRun] = react.default.useState(null);
27597
+ const aiCtl = react.default.useRef({
27598
+ paused: false,
27599
+ cancelled: false,
27600
+ wake: null
27601
+ });
26397
27602
  react.default.useEffect(() => {
26398
27603
  setFilter(loadFilter(scope));
26399
27604
  setRemote(null);
26400
27605
  setSizes({});
27606
+ setRenderLimit(RENDER_STEP);
27607
+ setCollapsed(loadFold(scope));
26401
27608
  }, [scope]);
26402
27609
  const applyFilter = (next) => {
26403
27610
  setFilter(next);
27611
+ setRenderLimit(RENDER_STEP);
26404
27612
  saveFilter(scope, next);
26405
27613
  };
26406
27614
  /**
26407
27615
  * 批量动作统一流程:先 confirm(仅还原需要)→ 执行 → 反馈 → 强制重查。
26408
- * @author ddj 2026年09月16号
27616
+ * 确认文案只完整列前 CONFIRM_PREVIEW_CAP 条(大列表拼几千行弹窗文案会卡 UI),总数如实展示。
27617
+ * @author ddj 2026年09月16号 / 2026年09月23号
26409
27618
  * @param kind 'add' | 'revert'
26410
27619
  * @param paths 目标相对路径列表
26411
27620
  */
26412
- const runBatch = (kind, paths) => {
27621
+ const runBatch = react.default.useCallback((kind, paths) => {
26413
27622
  if (!paths.length) return;
26414
27623
  if (kind === "revert") {
27624
+ const preview = paths.length > CONFIRM_PREVIEW_CAP ? paths.slice(0, CONFIRM_PREVIEW_CAP).join("\n") + "\n…等 " + paths.length + " 个文件" : paths.join("\n");
26415
27625
  const head = REVERT_CONFIRM_HEAD + paths.length + REVERT_CONFIRM_TAIL;
26416
- if (!window.confirm(head + "\n\n" + paths.join("\n"))) return;
27626
+ if (!window.confirm(head + "\n\n" + preview)) return;
26417
27627
  }
26418
27628
  setBusy(true);
26419
27629
  (kind === "revert" ? svnRevert(sessionId, paths) : svnAdd(sessionId, paths)).then((outcome) => {
26420
- ctx?.notify?.(outcome.message);
27630
+ ctxRef.current?.notify?.(outcome.message);
26421
27631
  refreshSvnChanges(sessionId, scope);
26422
27632
  }).finally(() => setBusy(false));
26423
- };
27633
+ }, [sessionId, scope]);
26424
27634
  /**
26425
27635
  * 远端更新检查(W2-3;host 侧 15s 短超时,离线/超时降级为提示条文案,不阻塞面板)。
26426
27636
  * @author ddj 2026年09月20号
@@ -26431,7 +27641,7 @@ window.__ModuleLoader__.load({
26431
27641
  svnRemoteStatus(sessionId, "").then((outcome) => {
26432
27642
  if (!outcome.ok) {
26433
27643
  setRemote({ failed: true });
26434
- ctx?.notify?.(outcome.message);
27644
+ ctxRef.current?.notify?.(outcome.message);
26435
27645
  return;
26436
27646
  }
26437
27647
  setRemote({
@@ -26443,62 +27653,384 @@ window.__ModuleLoader__.load({
26443
27653
  /**
26444
27654
  * 冲突副本对比入口(W2-4,只读):扫描 .mine/.working/.rN → 默认首个 .rN ↔ .mine 并排;
26445
27655
  * resolve 指引在差异视图顶部展示,本入口绝不自动执行 svn resolve(归 P2 破坏性批次)。
26446
- * @author ddj 2026年09月20号
27656
+ * @author ddj 2026年09月20号 / 2026年09月23号
26447
27657
  * @param path 冲突文件的工作区相对路径
26448
27658
  */
26449
- const openConflictDiff = (path) => {
27659
+ const openConflictDiff = react.default.useCallback((path) => {
26450
27660
  svnConflictArtifacts(sessionId, path).then((outcome) => {
27661
+ const live = ctxRef.current;
26451
27662
  if (!outcome.ok) {
26452
- ctx?.notify?.(outcome.message);
27663
+ live?.notify?.(outcome.message);
26453
27664
  return;
26454
27665
  }
26455
27666
  const artifacts = outcome.artifacts ?? [];
26456
27667
  const revSide = artifacts.find((item) => item.kind === "rev");
26457
27668
  const mineSide = artifacts.find((item) => item.kind === "mine");
26458
27669
  if (!revSide || !mineSide) {
26459
- ctx?.notify?.("未发现冲突副本(.mine/.rN):" + artifacts.map((item) => item.name).join("、"));
27670
+ live?.notify?.("未发现冲突副本(.mine/.rN):" + artifacts.map((item) => item.name).join("、"));
26460
27671
  return;
26461
27672
  }
26462
- if (!ctx?.openSvnLocalPair) {
26463
- ctx?.notify?.("当前视图不支持冲突对比");
27673
+ if (!live?.openSvnLocalPair) {
27674
+ live?.notify?.("当前视图不支持冲突对比");
26464
27675
  return;
26465
27676
  }
26466
- ctx.openSvnLocalPair(revSide.path, mineSide.path, ".r" + (revSide.rev ?? "?"), ".mine", path);
27677
+ live.openSvnLocalPair(revSide.path, mineSide.path, ".r" + (revSide.rev ?? "?"), ".mine", path);
26467
27678
  });
26468
- };
26469
- const shown = entries === null ? [] : svnVisibleChanges(entries, filter);
26470
- const actionable = entries === null ? [] : svnVisibleChanges(entries, {
27679
+ }, [sessionId]);
27680
+ const shown = react.default.useMemo(() => entries === null ? [] : svnVisibleChanges(entries, filter), [entries, filter]);
27681
+ const actionable = react.default.useMemo(() => entries === null ? [] : svnVisibleChanges(entries, {
26471
27682
  unversioned: filter.unversioned,
26472
27683
  ignored: filter.ignored
26473
- });
27684
+ }), [entries, filter]);
26474
27685
  const nameFiltered = String(filter.name || "").trim() !== "";
26475
- const missingEntries = entries === null ? [] : entries.filter((entry) => entry.status === "missing");
26476
- const unversionedEntries = entries === null ? [] : entries.filter((entry) => entry.status === "unversioned");
26477
- const candidates = [...missingEntries, ...unversionedEntries].map((entry) => entry.path);
26478
- const pairsKnown = missingEntries.length > 0 && unversionedEntries.length > 0 && candidates.every((path) => path in sizes);
27686
+ const missingEntries = react.default.useMemo(() => (entries ?? []).filter((entry) => entry.status === "missing"), [entries]);
27687
+ const unversionedEntries = react.default.useMemo(() => (entries ?? []).filter((entry) => entry.status === "unversioned"), [entries]);
27688
+ const requested = react.default.useMemo(() => [...missingEntries, ...unversionedEntries].slice(0, 200).map((entry) => entry.path), [missingEntries, unversionedEntries]);
27689
+ const candidateKey = react.default.useMemo(() => requested.join("\n"), [requested]);
27690
+ const pairsNeeded = missingEntries.length > 0 && unversionedEntries.length > 0;
27691
+ const pairsKnown = pairsNeeded && requested.every((path) => path in sizes);
26479
27692
  react.default.useEffect(() => {
26480
- if (!pairsKnown && candidates.length) svnFileSizes(sessionId, candidates).then((table) => setSizes(table));
27693
+ if (pairsKnown || !requested.length) return;
27694
+ svnFileSizes(sessionId, requested).then((table) => setSizes(table));
26481
27695
  }, [
26482
27696
  pairsKnown,
26483
- candidates.join("\n"),
27697
+ candidateKey,
26484
27698
  sessionId
26485
27699
  ]);
26486
- const pairNoteOf = pairsKnown ? (() => {
27700
+ const pairNoteOf = react.default.useMemo(() => {
27701
+ if (!pairsKnown) return {};
26487
27702
  const notes = {};
26488
27703
  for (const pair of pairMissingWithUnversioned(entries ?? [], sizes)) {
26489
27704
  notes[pair.missingPath] = "疑似改名:原文件 → " + pair.unversionedPath;
26490
27705
  notes[pair.unversionedPath] = "疑似改名:← 原文件 " + pair.missingPath;
26491
27706
  }
26492
27707
  return notes;
26493
- })() : {};
26494
- const openSvnDiff = (p) => ctx?.openSvnDiff?.(p);
27708
+ }, [
27709
+ pairsKnown,
27710
+ entries,
27711
+ sizes
27712
+ ]);
27713
+ const pairCapHint = pairsNeeded && missingEntries.length + unversionedEntries.length > 200;
27714
+ const versionedPathSet = react.default.useMemo(() => {
27715
+ const set = /* @__PURE__ */ new Set();
27716
+ for (const entry of entries ?? []) if (entry.versioned) set.add(entry.path);
27717
+ return set;
27718
+ }, [entries]);
27719
+ /**
27720
+ * 分区操作统一流程:busy → 按 host 上限分块顺序执行 → 聚合反馈 → 强制重查。
27721
+ * 反馈计数以面板层 paths.length 为准(svn changelist 成功输出静默,host count 为 0)。
27722
+ * @author ddj 2026年09月23号
27723
+ * @param paths 目标相对路径列表
27724
+ * @param name 目标分区名;null = 移出分区
27725
+ */
27726
+ const runCl = react.default.useCallback(async (paths, name) => {
27727
+ if (!paths.length) return;
27728
+ setBusy(true);
27729
+ const failures = [];
27730
+ let done = 0;
27731
+ try {
27732
+ for (const chunk of svnChunksOf(paths, 64)) {
27733
+ const outcome = await svnChangelist(sessionId, chunk, name);
27734
+ if (outcome.ok) done += chunk.length;
27735
+ else failures.push(outcome.message);
27736
+ }
27737
+ } finally {
27738
+ setBusy(false);
27739
+ }
27740
+ const total = paths.length;
27741
+ if (!failures.length) ctxRef.current?.notify?.(name === null ? "已移出分区(" + total + " 项)" : "已移入分区「" + name + "」(" + total + " 项)");
27742
+ else ctxRef.current?.notify?.("分区完成 " + done + "/" + total + " 项;" + failures[0]);
27743
+ refreshSvnChanges(sessionId, scope);
27744
+ }, [sessionId, scope]);
27745
+ /**
27746
+ * 把单条条目移入分区:弹窗输入分区名(预填当前名,可直接改名)→ 共享校验 → 执行。
27747
+ * @author ddj 2026年09月23号
27748
+ * @param entry 变更条目
27749
+ */
27750
+ const moveToChangelist = async (entry) => {
27751
+ const name = await ctxRef.current?.prompt?.("移入 SVN 分区(changelist)", entry.changelist || "");
27752
+ if (!name) return;
27753
+ const nameError = svnChangelistNameErrorOf(name);
27754
+ if (nameError) {
27755
+ ctxRef.current?.notify?.(nameError);
27756
+ return;
27757
+ }
27758
+ await runCl([entry.path], name);
27759
+ };
27760
+ /**
27761
+ * 整组移出分区:取该分区全部条目(不受名称过滤/显示开关影响,与批量动作口径一致)。
27762
+ * @author ddj 2026年09月23号
27763
+ * @param groupName 分区名
27764
+ */
27765
+ const removeGroupCl = react.default.useCallback(async (groupName) => {
27766
+ const paths = (entries ?? []).filter((entry) => entry.changelist === groupName).map((entry) => entry.path);
27767
+ await runCl(paths, null);
27768
+ }, [entries, runCl]);
27769
+ const openRowMenu = react.default.useCallback((entry, x, y) => setMenu({
27770
+ entry,
27771
+ x,
27772
+ y
27773
+ }), []);
27774
+ const closeMenu = react.default.useCallback(() => setMenu(null), []);
27775
+ /**
27776
+ * AI 智能整理分析入口:host 一次性 LLM 分析(超时 AI_PLAN_TIMEOUT_MS=300s)→ 预览弹窗;失败 notify。
27777
+ * @author ddj 2026年09月23号
27778
+ */
27779
+ const runAiPlan = react.default.useCallback(() => {
27780
+ if (aiBusy || aiRun) return;
27781
+ if (!entries || !entries.length) {
27782
+ ctxRef.current?.notify?.("无变更可分析");
27783
+ return;
27784
+ }
27785
+ setAiBusy(true);
27786
+ svnAiPlan(sessionId).then((outcome) => {
27787
+ if (!outcome.ok || !outcome.plan) {
27788
+ ctxRef.current?.notify?.(outcome.message);
27789
+ return;
27790
+ }
27791
+ setAiPlan(outcome);
27792
+ }).finally(() => setAiBusy(false));
27793
+ }, [
27794
+ aiBusy,
27795
+ aiRun,
27796
+ entries,
27797
+ sessionId
27798
+ ]);
27799
+ /** 暂停(步骤边界生效;当前 in-flight RPC 不可中断,UI 标注「等待当前步骤完成…」)。 */
27800
+ const aiPause = react.default.useCallback(() => {
27801
+ aiCtl.current.paused = true;
27802
+ setAiRun((old) => old ? {
27803
+ ...old,
27804
+ status: "pausing"
27805
+ } : old);
27806
+ }, []);
27807
+ /** 继续(唤醒步骤边界等待,从断点续跑)。 */
27808
+ const aiResume = react.default.useCallback(() => {
27809
+ aiCtl.current.paused = false;
27810
+ const wake = aiCtl.current.wake;
27811
+ aiCtl.current.wake = null;
27812
+ if (wake) wake();
27813
+ setAiRun((old) => old ? {
27814
+ ...old,
27815
+ status: "running"
27816
+ } : old);
27817
+ }, []);
27818
+ /** 取消剩余(已执行不回滚;唤醒边界等待让引擎立刻收尾)。 */
27819
+ const aiCancelRest = react.default.useCallback(() => {
27820
+ aiCtl.current.cancelled = true;
27821
+ aiCtl.current.paused = false;
27822
+ const wake = aiCtl.current.wake;
27823
+ aiCtl.current.wake = null;
27824
+ if (wake) wake();
27825
+ setAiRun((old) => old ? {
27826
+ ...old,
27827
+ status: "cancelling"
27828
+ } : old);
27829
+ }, []);
27830
+ /**
27831
+ * 预览确认 → 启动可暂停执行引擎(还原→分组→忽略固定顺序;单步失败继续)。
27832
+ * @author ddj 2026年09月23号
27833
+ * @param selected 勾选载荷
27834
+ */
27835
+ const onAiExecute = react.default.useCallback(async (selected) => {
27836
+ const live = ctxRef.current;
27837
+ const steps = planStepsOf(selected, sessionId);
27838
+ if (!steps.length) return;
27839
+ aiCtl.current = {
27840
+ paused: false,
27841
+ cancelled: false,
27842
+ wake: null
27843
+ };
27844
+ setAiRun({
27845
+ status: "running",
27846
+ index: 0,
27847
+ total: steps.length,
27848
+ cur: steps[0].label,
27849
+ log: [],
27850
+ cancelled: false
27851
+ });
27852
+ const result = await runPlanSteps(steps, {
27853
+ paused: () => aiCtl.current.paused,
27854
+ cancelled: () => aiCtl.current.cancelled,
27855
+ /** 步骤边界等待:paused 且未 cancelled 时挂起,由 resume/cancel 唤醒。 */
27856
+ wait: () => aiCtl.current.paused && !aiCtl.current.cancelled ? new Promise((resolve) => {
27857
+ aiCtl.current.wake = () => resolve(void 0);
27858
+ }) : Promise.resolve(void 0)
27859
+ }, (tick) => {
27860
+ setAiRun((old) => old ? {
27861
+ ...old,
27862
+ index: tick.done,
27863
+ total: tick.total,
27864
+ cur: tick.cur,
27865
+ log: tick.log,
27866
+ status: aiCtl.current.cancelled ? "cancelling" : old.status
27867
+ } : old);
27868
+ });
27869
+ setAiRun((old) => old ? {
27870
+ ...old,
27871
+ status: "done",
27872
+ cur: "",
27873
+ cancelled: result.cancelled
27874
+ } : old);
27875
+ live?.notify?.(planSummaryOf(steps, result.log, result.cancelled));
27876
+ refreshSvnChanges(sessionId, scope);
27877
+ }, [sessionId, scope]);
27878
+ /** 关闭整理弹窗(「关闭并刷新」;预览阶段 = 取消零副作用)。 */
27879
+ const closeAiPlan = react.default.useCallback(() => {
27880
+ setAiPlan(null);
27881
+ setAiRun(null);
27882
+ refreshSvnChanges(sessionId, scope);
27883
+ }, [sessionId, scope]);
27884
+ /** 取件轮询句柄(null = 未在轮询;卸载/取到/超时清理)。 */
27885
+ const deepTimer = react.default.useRef(null);
27886
+ const [deepWaiting, setDeepWaiting] = react.default.useState(false);
27887
+ /** 停止取件轮询(幂等)。 */
27888
+ const stopDeepPoll = react.default.useCallback(() => {
27889
+ if (deepTimer.current !== null) {
27890
+ clearInterval(deepTimer.current);
27891
+ deepTimer.current = null;
27892
+ }
27893
+ setDeepWaiting(false);
27894
+ }, []);
27895
+ react.default.useEffect(() => () => {
27896
+ if (deepTimer.current !== null) clearInterval(deepTimer.current);
27897
+ }, []);
27898
+ /**
27899
+ * 开启取件轮询:每 DEEP_POLL_MS 取一次收件箱,取到方案即开预览弹窗并停轮询;
27900
+ * DEEP_POLL_MAX 次无件自动停并提示(agent 可能没投递)。
27901
+ * @author ddj 2026年09月23号
27902
+ * @param since 注入时刻时间戳(旧投递不算新件)
27903
+ */
27904
+ const startDeepPoll = react.default.useCallback((since) => {
27905
+ stopDeepPoll();
27906
+ setDeepWaiting(true);
27907
+ let ticks = 0;
27908
+ deepTimer.current = setInterval(() => {
27909
+ ticks += 1;
27910
+ if (ticks > DEEP_POLL_MAX) {
27911
+ stopDeepPoll();
27912
+ ctxRef.current?.notify?.("等待 AI 助手方案超时(10 分钟),已停止取件");
27913
+ return;
27914
+ }
27915
+ svnAiPlanPending(sessionId, since).then((outcome) => {
27916
+ if (!outcome.ok || !outcome.plan) return;
27917
+ stopDeepPoll();
27918
+ setAiPlan({
27919
+ plan: outcome.plan,
27920
+ entriesCount: (ctxRef.current?.svnChanges ?? []).length,
27921
+ diffIncluded: true,
27922
+ dropped: outcome.dropped ?? 0,
27923
+ model: void 0,
27924
+ source: "agent"
27925
+ });
27926
+ ctxRef.current?.notify?.("AI 助手方案已送达,请勾选确认后执行");
27927
+ });
27928
+ }, DEEP_POLL_MS);
27929
+ }, [sessionId, stopDeepPoll]);
27930
+ /**
27931
+ * 深度分析入口(02-deep-session-prompt 修正版):**新建独立会话**承载任务
27932
+ * (不污染当前对话),草稿箱填入分析任务(变更清单由 agent 自跑只读 svn status
27933
+ * 取数,prompt 定长)→ 用户在新会话发送 → agent 投递方案回面板收件箱。
27934
+ * 降级:不支持自动新建会话时回落当前对话注入 + notify 注明。
27935
+ * @author ddj 2026年09月23号
27936
+ */
27937
+ const runDeepPlan = react.default.useCallback(() => {
27938
+ const live = ctxRef.current;
27939
+ if (aiBusy || aiRun || deepWaiting) return;
27940
+ if (!entries || !entries.length) {
27941
+ live?.notify?.("无变更可分析");
27942
+ return;
27943
+ }
27944
+ const wcRoot = live?.svn?.wcRoot ? String(live.svn.wcRoot) : "";
27945
+ const since = Date.now();
27946
+ const add = live?.addToConversation;
27947
+ if (!add?.appendText) {
27948
+ live?.notify?.("无法填入任务(无会话或输入框不可用)");
27949
+ return;
27950
+ }
27951
+ /** 降级:当前对话注入(不支持自动新建会话时兜底)。 */
27952
+ const degrade = (prompt) => {
27953
+ add.appendText(sessionId, prompt).then((outcome) => {
27954
+ if (outcome === "ok" || outcome === "busy") {
27955
+ live?.notify?.("已填入当前对话(降级),任务已自动发送,请在本对话查看");
27956
+ startDeepPoll(since);
27957
+ } else live?.notify?.("发起失败:" + (outcome === "unavailable" ? "无会话或输入框不可用" : "输入框忙,请重试"));
27958
+ });
27959
+ };
27960
+ /** 统一收尾(点击即发送方案):create 后构建 prompt(内嵌新会话 id)→ 发送任务。 */
27961
+ const sendAndWatch = (id) => {
27962
+ const prompt = buildAgentPrompt(wcRoot, id || sessionId || "");
27963
+ if (!id || typeof add.sendTask !== "function") {
27964
+ degrade(prompt);
27965
+ return;
27966
+ }
27967
+ add.sendTask(id, prompt).then((sent) => {
27968
+ if (sent) {
27969
+ live?.notify?.("已在新会话「AI 深度分析」发起任务并自动发送,请在左侧会话列表点开查看进度");
27970
+ startDeepPoll(since);
27971
+ } else degrade(prompt);
27972
+ });
27973
+ };
27974
+ (add.startDraftSession ? add.startDraftSession(wcRoot || void 0) : Promise.resolve({ ok: false })).then((result) => {
27975
+ sendAndWatch(result?.ok ? result.id : void 0);
27976
+ });
27977
+ }, [
27978
+ aiBusy,
27979
+ aiRun,
27980
+ deepWaiting,
27981
+ entries,
27982
+ sessionId,
27983
+ startDeepPoll
27984
+ ]);
27985
+ /**
27986
+ * 切换分组折叠(纯 UI 状态;不重置渲染预算——折叠释放预算、展开继续用已有预算)。
27987
+ * @author ddj 2026年09月23号
27988
+ * @param name 组名
27989
+ */
27990
+ const toggleFold = react.default.useCallback((name) => {
27991
+ const next = new Set(collapsed);
27992
+ if (next.has(name)) next.delete(name);
27993
+ else next.add(name);
27994
+ setCollapsed(next);
27995
+ saveFold(scope, next);
27996
+ }, [scope, collapsed]);
27997
+ /**
27998
+ * 行右键菜单条目:分区管理(svn changelist 仅支持受版本控制文件,
27999
+ * 未版本控制/忽略项禁用;目录条目的报错由 host 经 notify 透出)。
28000
+ * @author ddj 2026年09月23号
28001
+ * @param entry 变更条目
28002
+ * @returns 菜单条目
28003
+ */
28004
+ const rowMenuEntriesOf = (entry) => [{
28005
+ id: "cl-set",
28006
+ label: entry.changelist ? "移到其他分区…" : "移入分区…",
28007
+ disabled: !entry.versioned || busy,
28008
+ onClick: () => {
28009
+ moveToChangelist(entry);
28010
+ }
28011
+ }, {
28012
+ id: "cl-remove",
28013
+ label: "移出分区" + (entry.changelist ? "「" + entry.changelist + "」" : ""),
28014
+ disabled: !entry.versioned || !entry.changelist || busy,
28015
+ onClick: () => {
28016
+ runCl([entry.path], null);
28017
+ }
28018
+ }];
28019
+ const openSvnDiff = react.default.useCallback((p) => ctxRef.current?.openSvnDiff?.(p), []);
28020
+ const openFileAt = react.default.useCallback((p) => ctxRef.current?.openFile?.(p), []);
28021
+ const onAdd = react.default.useCallback((paths) => runBatch("add", paths), [runBatch]);
28022
+ const onRevert = react.default.useCallback((paths) => runBatch("revert", paths), [runBatch]);
26495
28023
  const handlers = {
26496
28024
  busy,
26497
28025
  onDiff: openSvnDiff,
26498
28026
  onConflict: openConflictDiff,
26499
28027
  pairNotes: pairNoteOf,
26500
- onAdd: (paths) => runBatch("add", paths),
26501
- onRevert: (paths) => runBatch("revert", paths)
28028
+ onAdd,
28029
+ onRevert,
28030
+ onMore: react.default.useCallback(() => setRenderLimit((old) => old + RENDER_STEP), []),
28031
+ onMenu: openRowMenu,
28032
+ onGroupClRemove: removeGroupCl,
28033
+ onOpen: openFileAt
26502
28034
  };
26503
28035
  /**
26504
28036
  * 导出当前展示列表(W1-4):CSV 带 BOM 供 Excel 直开;HTML 本地报表;失败经 notify 提示。
@@ -26521,21 +28053,35 @@ window.__ModuleLoader__.load({
26521
28053
  const stamp = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
26522
28054
  if (!(kind === "html" ? downloadText("svn-changes-" + stamp + ".html", htmlTableOf(headers, rows, "SVN 变更列表 " + stamp), "text/html") : downloadText("svn-changes-" + stamp + ".csv", csvOf([headers, ...rows]), "text/csv"))) ctx?.notify?.("导出失败:浏览器下载能力不可用");
26523
28055
  };
28056
+ const groups = react.default.useMemo(() => groupByChangelist(shown), [shown]);
26524
28057
  const listState = {
26525
28058
  managed,
26526
28059
  entries,
26527
28060
  visible: shown,
26528
- groups: groupByChangelist(shown),
26529
- nameFiltered
26530
- };
28061
+ budget: react.default.useMemo(() => budgetGroupsOf(groups.map((g) => collapsed.has(g.name) ? {
28062
+ name: g.name,
28063
+ entries: [],
28064
+ full: g.entries.length,
28065
+ folded: true
28066
+ } : g), renderLimit), [
28067
+ groups,
28068
+ collapsed,
28069
+ renderLimit
28070
+ ]),
28071
+ nameFiltered,
28072
+ capped: svnChangesCapped(scope),
28073
+ collapsedSet: collapsed,
28074
+ onFold: toggleFold
28075
+ };
28076
+ const bulkPaths = react.default.useMemo(() => ({
28077
+ unversioned: actionable.filter((entry) => !entry.versioned).map((entry) => entry.path),
28078
+ revert: actionable.filter((entry) => entry.versioned).map((entry) => entry.path)
28079
+ }), [actionable]);
26531
28080
  const toolbar = svnToolbarEl({
26532
28081
  filter,
26533
28082
  count: shown.length,
26534
28083
  countAll: actionable.length,
26535
- paths: {
26536
- unversioned: actionable.filter((entry) => !entry.versioned).map((entry) => entry.path),
26537
- revert: actionable.filter((entry) => entry.versioned).map((entry) => entry.path)
26538
- },
28084
+ paths: bulkPaths,
26539
28085
  handlers: Object.assign({}, handlers, {
26540
28086
  toggleUnversioned: () => applyFilter({
26541
28087
  ...filter,
@@ -26551,20 +28097,45 @@ window.__ModuleLoader__.load({
26551
28097
  }),
26552
28098
  onExportCsv: () => onExport("csv"),
26553
28099
  onExportHtml: () => onExport("html"),
26554
- add: (paths) => runBatch("add", paths),
26555
- revert: (paths) => runBatch("revert", paths)
28100
+ add: onAdd,
28101
+ revert: onRevert
26556
28102
  })
26557
28103
  });
26558
28104
  const rootName = ctx?.svn?.wcRoot ? String(ctx.svn.wcRoot).split(/[\\/]/).pop() || ctx.svn.wcRoot : "";
26559
- const remoteEl = remote === null ? null : react.default.createElement("div", { className: "edrv-svn-hintbar" + (remote.failed ? " edrv-svn-hintbar-warn" : "") }, react.default.createElement("span", { style: { flex: 1 } }, remote.failed ? "远端检查失败(网络不可达或超时;可用 ⟳ 或「检查远端」重试)" : remote.outdated.length ? "远端有 " + remote.outdated.length + " 个更新(against r" + (remote.againstRev ?? "?") + "),其中本地已改 " + remote.outdated.filter((item) => item.path && entries?.some((entry) => entry.path === item.path && entry.versioned)).length + " 个;更新前请先提交或还原" : "远端无更新(against r" + (remote.againstRev ?? "?") + ")"), react.default.createElement("button", {
28105
+ const remoteEl = remote === null ? null : react.default.createElement("div", { className: "edrv-svn-hintbar" + (remote.failed ? " edrv-svn-hintbar-warn" : "") }, react.default.createElement("span", { style: { flex: 1 } }, remote.failed ? "远端检查失败(网络不可达或超时;可用 ⟳ 或「检查远端」重试)" : remote.outdated.length ? "远端有 " + remote.outdated.length + " 个更新(against r" + (remote.againstRev ?? "?") + "),其中本地已改 " + remote.outdated.filter((item) => item.path && versionedPathSet.has(item.path)).length + " 个;更新前请先提交或还原" : "远端无更新(against r" + (remote.againstRev ?? "?") + ")"), react.default.createElement("button", {
26560
28106
  className: "edrv-svn-act",
26561
28107
  title: "关闭提示条",
26562
28108
  onClick: () => setRemote(null)
26563
28109
  }, "✕"));
28110
+ const pairCapEl = pairCapHint ? react.default.createElement("div", { className: "edrv-svn-hintbar" }, "改名配对候选超过 200 个,仅评估前 200 个(缺失文件优先)") : null;
28111
+ const menuEl = menu ? react.default.createElement(ContextMenu, {
28112
+ key: "edrv-svn-row-menu",
28113
+ x: menu.x,
28114
+ y: menu.y,
28115
+ entries: rowMenuEntriesOf(menu.entry),
28116
+ onClose: closeMenu
28117
+ }) : null;
28118
+ const aiPlanEl = aiPlan ? react.default.createElement(SvnAiPlanDialog, {
28119
+ key: "edrv-svn-ai-plan",
28120
+ plan: aiPlan.plan,
28121
+ meta: {
28122
+ entriesCount: aiPlan.entriesCount,
28123
+ diffIncluded: aiPlan.diffIncluded,
28124
+ dropped: aiPlan.dropped,
28125
+ model: aiPlan.model,
28126
+ source: aiPlan.source
28127
+ },
28128
+ run: aiRun,
28129
+ onExecute: onAiExecute,
28130
+ onPause: aiPause,
28131
+ onResume: aiResume,
28132
+ onCancelRest: aiCancelRest,
28133
+ onClose: closeAiPlan
28134
+ }) : null;
26564
28135
  return react.default.createElement("div", { className: "edrv-side-panel" }, react.default.createElement("div", { className: "edrv-side-head" }, react.default.createElement("span", { className: "edrv-side-title" }, "SVN 变更"), react.default.createElement("span", {
26565
28136
  className: "edrv-side-root",
26566
28137
  title: ctx?.svn?.wcRoot || ""
26567
- }, rootName), react.default.createElement("span", { style: { flex: 1 } }), react.default.createElement("button", {
28138
+ }, rootName), react.default.createElement("span", { style: { flex: 1 } }), react.default.createElement("span", { className: "edrv-svn-head-icons" }, react.default.createElement("button", {
26568
28139
  className: "edrv-side-btn",
26569
28140
  title: "检查远端更新(svn status -u;约数秒,离线自动降级)",
26570
28141
  onClick: checkRemote
@@ -26575,7 +28146,15 @@ window.__ModuleLoader__.load({
26575
28146
  refreshSvnChanges(sessionId, scope);
26576
28147
  ctx?.refreshRecords?.();
26577
28148
  }
26578
- }, refreshIconEl())), remoteEl, ...toolbar, react.default.createElement("div", { className: "edrv-svn-list" }, svnListBody(listState, handlers)));
28149
+ }, refreshIconEl()))), aiBarEl({
28150
+ managed,
28151
+ busy,
28152
+ aiBusy,
28153
+ deepWaiting,
28154
+ hasRun: Boolean(aiRun),
28155
+ onQuick: runAiPlan,
28156
+ onDeep: runDeepPlan
28157
+ }), remoteEl, pairCapEl, ...toolbar, react.default.createElement("div", { className: "edrv-svn-list" }, svnListBody(listState, handlers)), menuEl, aiPlanEl);
26579
28158
  }
26580
28159
  //#endregion
26581
28160
  //#region src/client/dap/variableTree.ts