dsh-vscode-mode 0.1.47 → 0.1.49
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/README.md +10 -1
- package/lib/client.js +729 -205
- package/lib/client.js.map +1 -1
- package/lib/index.js +562 -3
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client/addToConversation.ts +32 -19
- package/src/client/compat.ts +1 -1
- package/src/client/index.ts +9 -2
- package/src/client/paths.ts +2 -0
- package/src/client/sidebar/SidebarView.ts +82 -16
- package/src/client/sidebar/menuItems.ts +23 -2
- package/src/client/sidebar/panels/FileExplorer.ts +2 -4
- package/src/client/sidebar/panels/RulesPanel.ts +284 -0
- package/src/client/sidebar/panels/index.ts +18 -2
- package/src/client/sidebar/types.ts +5 -0
- package/src/client/sidebarMin.ts +48 -0
- package/src/client/styles/editor.css +43 -0
- package/src/client/ui/EditorView.ts +25 -13
- package/src/client/ui/McpSettings.ts +37 -2
- package/src/client/ui/SideEditorTab.ts +1 -0
- package/src/client/ui/menuPosition.ts +2 -28
- package/src/fileOpenSettings.ts +2 -0
- package/src/index.ts +5 -1
- package/src/rpc.ts +37 -0
- package/src/rules.ts +528 -0
- package/src/shared/rpc.ts +11 -0
- package/src/shared/rules.ts +60 -0
package/lib/client.js
CHANGED
|
@@ -30,7 +30,7 @@ window.__ModuleLoader__.load({
|
|
|
30
30
|
react = __toESM(react, 1);
|
|
31
31
|
let react_dom = require("react-dom");
|
|
32
32
|
//#region \0dsh-css:/home/runner/work/DSH_VsCodeMode/DSH_VsCodeMode/src/client/styles/editor.css.mjs
|
|
33
|
-
const css$1 = "/* dsh-vscode-mode 编辑区样式(原 ensureEdrvStyles 字符串,落盘为真 .css,由 tsdown CSS-inline 注入) */\n/* 浅色主题(对齐参考图:#f8f8f8 近白底 + 薄荷绿药丸 + 青绿文字 + 三文鱼 undo + 浅灰边框):\n 在 [data-edrv-view] 作用域内重定义 --dsw-alias-*,级联命中组件内联样式与 CSS。 */\n[data-edrv-view] { box-sizing: border-box; --edrv-tab-h: 34px; --dsw-alias-bg-base: #f8f8f8; --dsw-alias-bg-layer-1: #ffffff; --dsw-alias-bg-layer-2: #f0f4f4; --dsw-alias-bg-overlay: #ffffff; --dsw-alias-label-primary: #1f2933; --dsw-alias-label-secondary: #52606d; --dsw-alias-label-tertiary: #9aa5b1; --dsw-alias-border-l1: #e0e6e8; --dsw-alias-border-l2: #cbd2d9; --dsw-alias-brand-primary: #0f9d58; --dsw-alias-state-success-primary: #0f9d58; --dsw-alias-state-error-primary: #d9534f; --dsw-alias-state-warn-primary: #d97706; --dsw-alias-interactive-bg-hover: rgba(15,157,88,.08); }\n\n[data-edrv-view] .edrv-tabs { display: flex; align-items: center; gap: 2px; padding: 2px 8px 0; background: var(--dsw-alias-bg-layer-1, transparent); overflow-x: auto; scrollbar-width: thin; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab { display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 8px 0 12px; border: none; border-radius: 6px 6px 0 0; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 12px; cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-tab.edrv-tab-active { background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); box-shadow: inset 0 -2px 0 var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-tab .edrv-tab-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--dsw-alias-brand-primary, #4f8cff); flex-shrink: 0; }\n[data-edrv-view] .edrv-tab .edrv-tab-x { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; border-radius: 4px; color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; }\n[data-edrv-view] .edrv-tab .edrv-tab-x:hover { background: rgba(255,255,255,.12); color: var(--dsw-alias-label-primary, #eee); }\n[data-edrv-view] .edrv-tab-add { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; margin-left: 2px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 14px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab-add:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-pathbar { display: flex; align-items: center; gap: 8px; height: 26px; padding: 0 10px; background: var(--dsw-alias-bg-layer-1, #ffffff); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 12px; flex-shrink: 0; overflow: hidden; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-name { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-full { flex: 1; min-width: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; direction: rtl; text-align: left; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-meta { flex-shrink: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-status { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-path-input { flex: 1; min-width: 140px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search-wrap { position: relative; flex-shrink: 0; display: flex; align-items: center; padding: 2px 8px 2px 4px; }\n[data-edrv-view] .edrv-search { width: 190px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-pop { position: absolute; top: calc(100% + 4px); right: 8px; width: min(460px, calc(100vw - 24px)); max-height: 300px; overflow: auto; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 10px; box-shadow: 0 6px 20px rgba(0,0,0,.4); z-index: 60; padding: 4px; }\n[data-edrv-view] .edrv-search-item { display: flex; flex-direction: column; gap: 1px; padding: 5px 8px; border-radius: 6px; cursor: pointer; }\n[data-edrv-view] .edrv-search-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.07)); }\n[data-edrv-view] .edrv-search-item .n { color: var(--dsw-alias-label-primary, #eee); font-size: 12px; word-break: break-all; }\n[data-edrv-view] .edrv-search-item .d { color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-search-empty { padding: 8px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #888); }\n[data-edrv-view] .edrv-btn-mini { font-size: 11px; padding: 2px 9px; border: none; border-radius: 999px; cursor: pointer; color: #fff; font-weight: 600; white-space: nowrap; }\n[data-edrv-view] .edrv-btn-keep { background: var(--dsw-alias-state-success-primary, #2e9e44); }\n[data-edrv-view] .edrv-btn-undo { background: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-btn-mini:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-statusbar { display: flex; align-items: center; gap: 10px; padding: 3px 10px; border-top: 1px solid var(--dsw-alias-border-l1, #333); background: var(--dsw-alias-bg-layer-1, transparent); font-size: 11px; color: var(--dsw-alias-label-tertiary, #888); flex-shrink: 0; white-space: nowrap; overflow: hidden; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-path { flex: 1; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-lsp { flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-progress-message { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-statusbar .edrv-sp-progress { flex: 0 0 auto; min-width: 36px; text-align: right; font-variant-numeric: tabular-nums; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-lsp-status-dot { width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto; background: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-lsp-status-dot.ready { background: var(--dsw-alias-state-success-primary, #0f9d58); }\n[data-edrv-view] .edrv-lsp-status-dot.busy { background: var(--dsw-alias-state-warn-primary, #d97706); animation: edrv-lsp-pulse 1.2s ease-in-out infinite; }\n@keyframes edrv-lsp-pulse { 50% { opacity: .45; } }\n/* Ctrl+hover 可导航标识符下划线提示(绑定 Monaco inlineClassName 装饰) */\n[data-edrv-view] .edrv-nav-underline { text-decoration: underline; text-decoration-color: var(--dsw-alias-interactive-primary, #4fc1ff); text-underline-offset: 1px; cursor: pointer; }\n[data-edrv-view] .edrv-diffchip { font-size: 11px; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #333); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-state-warn-primary, #b7791f); cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn { font-size: 12px; padding: 2px 6px; border: none; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; border-radius: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-chip-btn:disabled { opacity: .35; cursor: default; }\n[data-edrv-view] .edrv-chip-btn:disabled:hover { background: transparent; }\n[data-edrv-view] .edrv-mn-add-line { background: rgba(15,157,88,.10); }\n[data-edrv-view] .edrv-mn-gutter-add { color: #0f9d58 !important; font-weight: 700; display: flex !important; align-items: center; justify-content: center; }\n[data-edrv-view] .edrv-mn-gutter-add::before { content: \"+\"; }\n[data-edrv-view] .edrv-del-zone { background: #fdeaea; border-top: 1px solid rgba(217,83,79,.35); border-bottom: 1px solid rgba(217,83,79,.35); box-shadow: inset 0 0 0 1px rgba(217,83,79,.12); }\n[data-edrv-view] .edrv-del-row { white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 12.5px; line-height: 20px; color: #c0392b; }\n[data-edrv-view] .edrv-del-text { display: inline-block; white-space: pre; }\n[data-edrv-view] .edrv-minus-overlay { position: absolute; left: 0; top: 0; width: 100%; height: 100%; max-width: 100%; overflow: visible; pointer-events: none; z-index: 6; }\n[data-edrv-view] .edrv-minus-item { position: absolute; box-sizing: border-box; max-width: 100%; overflow: hidden; }\n[data-edrv-view] .edrv-minus-item::before { content: ''; position: absolute; left: 4px; top: 50%; width: 8px; height: 2px; transform: translateY(-50%); border-radius: 2px; background: #d9534f; }\n[data-edrv-view] .edrv-monaco-host { flex: 1 1 auto; min-width: 0; min-height: 0; position: relative; overflow: hidden; }\n[data-edrv-view] .edrv-monaco-host > div { position: absolute; inset: 0; min-width: 0; min-height: 0; }\n[data-edrv-view] .edrv-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; height: 100%; color: var(--dsw-alias-label-tertiary, #777); font-size: 13px; }\n[data-edrv-view] .edrv-diffbar { position: absolute; left: 0; right: 0; bottom: 10px; margin: 0 auto; z-index: 25; width: fit-content; max-width: calc(100% - 20px); border-radius: 12px; background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, #f0f4f4)); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); box-shadow: none; overflow: visible; display: flex; flex-direction: column; }\n[data-edrv-view] .edrv-editor-area > .edrv-diffbar { max-height: calc(100% - 20px); }\n[data-edrv-view] .edrv-diffbar-row { display: flex; align-items: center; gap: 6px; height: 36px; padding: 4px 5px 4px 12px; flex-wrap: nowrap; }\n[data-edrv-view] .edrv-diffbar-count { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); min-width: 42px; text-align: center; white-space: nowrap; cursor: pointer; }\n[data-edrv-view] .edrv-diffbar-count.edrv-count-file { min-width: 64px; cursor: default; }\n[data-edrv-view] .edrv-diffbar-file { flex: 1; min-width: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-pill { font-size: 11px; padding: 3px 10px; border: none; border-radius: 999px; cursor: pointer; white-space: nowrap; font-weight: 600; }\n[data-edrv-view] .edrv-pill-keep { background: #e8f8e8; color: #0f7a45; border: 1px solid rgba(15,157,88,.4); }\n[data-edrv-view] .edrv-pill-undo { background: #fdeaea; color: #c0392b; border: 1px solid rgba(217,83,79,.4); }\n[data-edrv-view] .edrv-pill-ghost { background: #ffffff; color: var(--dsw-alias-label-secondary, #52606d); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-pill:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-diffbar-menu { position: absolute; right: 8px; bottom: calc(100% + 6px); z-index: 45; min-width: 160px; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 6px 20px rgba(31,41,51,.16); padding: 4px; display: flex; flex-direction: column; gap: 2px; }\n[data-edrv-view] .edrv-diffmenu-item { display: flex; align-items: center; gap: 8px; font-size: 12px; padding: 6px 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; text-align: left; }\n[data-edrv-view] .edrv-diffmenu-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-diffmenu-item.danger { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-diffmenu-sep { height: 1px; margin: 2px 4px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n/* 编辑区 / Tab 右键菜单(添加文件/选中内容到对话) */\n[data-edrv-view] .edrv-ctxmenu { position: fixed; z-index: 71; min-width: 200px; max-width: 320px; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 8px 26px rgba(31,41,51,.2); padding: 4px; display: flex; flex-direction: column; gap: 1px; }\n[data-edrv-view] .edrv-ctxmenu-item { display: flex; align-items: center; gap: 8px; font-size: 12px; line-height: 18px; padding: 7px 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-ctxmenu-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-danger { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-ctxmenu-item:disabled,\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-disabled { color: var(--dsw-alias-label-disabled, #b0b7c0); cursor: default; background: transparent; }\n[data-edrv-view] .edrv-ctxmenu-sep { height: 1px; margin: 3px 4px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-diffbar-body { max-height: 130px; max-width: min(560px, calc(100vw - 40px)); overflow: auto; padding: 4px 8px 8px; display: flex; flex-direction: column; gap: 4px; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-diffrow { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); cursor: pointer; flex-wrap: wrap; }\n[data-edrv-view] .edrv-diffrow:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-diffrow-l { font-size: 11px; color: var(--dsw-alias-label-primary, #1f2933); min-width: 74px; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-o { font-size: 11px; color: var(--dsw-alias-state-error-primary, #d9534f); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-n { font-size: 11px; color: var(--dsw-alias-state-success-primary, #0f9d58); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-tag { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-diffrow-stale { border-color: rgba(217,119,6,.5); cursor: default; }\n[data-edrv-view] .edrv-diffbox-others { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; padding: 4px 2px 0; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); margin-top: 2px; }\n[data-edrv-view] .edrv-diffrow-file { font-size: 11px; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); cursor: pointer; white-space: nowrap; max-width: 200px; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-diffrow-file:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n/* 编辑区 hover 差异块的 Keep/Undo 浮层 */\n[data-edrv-view] .edrv-hoveract { position: absolute; z-index: 30; display: flex; align-items: center; gap: 4px; padding: 2px 6px; border-radius: 8px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 4px 14px rgba(31,41,51,.14); }\n[data-edrv-view] .edrv-launch { position: absolute; left: 12px; right: 12px; bottom: 12px; z-index: 40; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); box-shadow: 0 6px 24px rgba(0,0,0,.5); display: flex; flex-direction: column; max-height: 60%; overflow: hidden; }\n[data-edrv-view] .edrv-launch-head { display: flex; align-items: center; gap: 6px; padding: 6px 8px; border-bottom: 1px solid var(--dsw-alias-border-l1, #333); }\n[data-edrv-view] .edrv-launch-tab { font-size: 12px; padding: 3px 12px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; }\n[data-edrv-view] .edrv-launch-tab.on { background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-label-primary, #eee); font-weight: 600; }\n[data-edrv-view] .edrv-launch-body { flex: 1; min-height: 0; overflow: auto; padding: 6px 8px; display: flex; flex-direction: column; gap: 4px; }\n[data-edrv-view] .edrv-launch-row { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1, #333); border-radius: 6px; cursor: pointer; flex-wrap: wrap; }\n[data-edrv-view] .edrv-launch-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-launch-path { flex: 1; min-width: 0; font-size: 12px; color: var(--dsw-alias-label-primary, #eee); word-break: break-all; }\n[data-edrv-view] .edrv-launch-cnt { font-size: 11px; color: var(--dsw-alias-label-tertiary, #888); white-space: nowrap; }\n[data-edrv-view] .edrv-launch-arch { display: flex; flex-direction: column; gap: 6px; }\n[data-edrv-view] .monaco-editor { overflow: hidden !important; }\n[data-edrv-view] .monaco-editor .sticky-widget { z-index: 30 !important; background: var(--dsw-alias-bg-base, #f8f8f8) !important; }\n[data-edrv-view] .monaco-editor .sticky-widget .sticky-line-content,\n[data-edrv-view] .monaco-editor .sticky-widget .sticky-line-number { background: var(--dsw-alias-bg-base, #f8f8f8) !important; }\n[data-edrv-view] .monaco-editor, [data-edrv-view] .monaco-editor .margin, [data-edrv-view] .monaco-editor-background { background: transparent !important; }\n[data-edrv-view] .monaco-editor .scrollbar .slider { background: rgba(128,128,128,.3) !important; }\n[data-edrv-view] .edrv-loading { gap: 8px; padding: 20px; }\n[data-edrv-view] .edrv-loading-title { color: var(--dsw-alias-label-primary, #1f2933); font-size: 13px; }\n[data-edrv-view] .edrv-progress { width: min(360px, 72%); height: 6px; overflow: hidden; border-radius: 999px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-progress-value { height: 100%; border-radius: inherit; background: var(--dsw-alias-brand-primary, #0f9d58); transition: width .24s ease; }\n[data-edrv-view] .edrv-loading-percent { color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; font-variant-numeric: tabular-nums; }\n@media (prefers-reduced-motion: reduce) {\n [data-edrv-view] .edrv-progress-value { transition: none; }\n}\n\n/* ===== 唯一会话级差异 dock(遵循 DSH todo/queue 原生布局) ===== */\n[data-edrv-diff-dock-shell] {\n box-sizing: border-box;\n width: calc(100% - var(--dsh-composer-side-clearance) - var(--dsh-composer-side-clearance) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));\n max-width: calc(var(--dsh-composer-card-max-width) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));\n margin: 0 auto;\n padding: 0;\n flex: none;\n border: 1px solid var(--dsw-alias-border-l1, #e0e6e8);\n border-radius: 12px;\n background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, transparent));\n box-shadow: none;\n overflow: hidden;\n}\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock {\n box-sizing: border-box;\n position: relative;\n left: auto;\n right: auto;\n bottom: auto;\n z-index: auto;\n width: 100%;\n max-width: none;\n margin: 0;\n display: flex;\n flex-direction: column;\n border: none;\n border-radius: 0;\n background: transparent;\n box-shadow: none;\n overflow: visible;\n}\n[data-edrv-diff-dock-shell] .edrv-diffbar-row { min-height: 36px; padding: 6px 12px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-row { min-height: 36px; padding: 6px 12px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-body { max-height: 180px; overflow: auto; padding: 6px 12px 10px; border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-button { box-sizing: border-box; display: flex; align-items: center; justify-content: center; width: 100%; height: 24px; border: none; border-radius: 8px; padding: 0 12px; background: transparent; color: var(--dsw-alias-label-primary); font-size: 13px; font-weight: 500; line-height: 24px; text-align: center; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-button:hover { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diffbar-count { display: inline-flex; align-items: center; color: var(--dsw-alias-label-primary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 500; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-file { display: inline-flex; align-items: center; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-editor-row { display: flex; align-items: center; height: 36px; min-height: 36px; padding: 4px 12px; overflow-x: auto; scrollbar-width: thin; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-editor-content { display: flex; align-items: center; gap: 10px; width: 100%; min-width: max-content; min-height: 28px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-nav,\n[data-edrv-diff-dock-shell] .edrv-diffbar-files,\n[data-edrv-diff-dock-shell] .edrv-diffbar-actions { display: flex; align-items: center; gap: 6px; flex: none; height: 28px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-actions { margin-left: auto; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-details-toggle { display: inline-flex; align-items: center; justify-content: center; width: 28px; min-width: 28px; padding: 0; font-size: 13px; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-details-toggle svg { width: 14px; height: 14px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-files { min-width: 0; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-files .edrv-diffbar-file { min-width: 72px; max-width: 240px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-progress { min-width: 0; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; font-variant-numeric: tabular-nums; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-summary { min-width: 0; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-pill { box-sizing: border-box; height: 28px; padding: 0 9px; border: none; border-radius: 999px; cursor: pointer; white-space: nowrap; font-size: 11px; line-height: 26px; font-weight: 600; }\n[data-edrv-diff-dock-shell] .edrv-pill-keep { background: var(--dsw-alias-state-success-tertiary); color: var(--dsw-alias-state-success-primary); border: 1px solid var(--dsw-alias-state-success-secondary); }\n[data-edrv-diff-dock-shell] .edrv-pill-undo { background: var(--dsw-alias-state-error-tertiary); color: var(--dsw-alias-state-error-primary); border: 1px solid var(--dsw-alias-state-error-secondary); }\n[data-edrv-diff-dock-shell] .edrv-pill-ghost { background: transparent; color: var(--dsw-alias-label-secondary); border: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-pill:hover:not(:disabled) { background-color: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-pill:focus-visible { outline: 2px solid var(--dsw-alias-label-tertiary); outline-offset: -2px; }\n[data-edrv-diff-dock-shell] .edrv-pill:disabled { opacity: .45; cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diffrow { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; background: transparent; cursor: pointer; flex-wrap: wrap; }\n[data-edrv-diff-dock-shell] .edrv-diffrow:hover { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-l { color: var(--dsw-alias-label-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-o { color: var(--dsw-alias-state-error-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-n { color: var(--dsw-alias-state-success-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-tag { color: var(--dsw-alias-label-tertiary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-stale { border-color: var(--dsw-alias-state-warn-secondary); cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diffbox-others { border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-file { border-color: var(--dsw-alias-border-l1); background: transparent; color: var(--dsw-alias-label-secondary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-file:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }\n[data-edrv-diff-dock-shell] .edrv-diff-details { display: flex; flex-direction: column; gap: 2px; padding: 6px 12px 8px; border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item { display: flex; align-items: center; width: 100%; min-height: 28px; gap: 8px; padding: 4px 8px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary); cursor: pointer; text-align: left; font-size: 12px; line-height: 20px; }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item.danger { color: var(--dsw-alias-state-error-primary); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item:disabled { opacity: .45; cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-sep { height: 1px; margin: 2px 4px; background: var(--dsw-alias-border-l1); }\n@media (max-width: 620px) {\n [data-edrv-diff-dock-shell] .edrv-diffbar-editor-content { width: max-content; }\n [data-edrv-diff-dock-shell] .edrv-diffbar-files .edrv-diffbar-file { max-width: 160px; }\n}\n\n/* ===== 侧边栏(活动栏 + 面板区 + 文件树) ===== */\n[data-edrv-view] .edrv-editor-row { display: flex; flex: 1 1 auto; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-main-col { box-sizing: border-box; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-main-col > .edrv-pathbar,\n[data-edrv-view] .edrv-main-col > .edrv-tabs { flex: 0 0 auto; }\n[data-edrv-view] .edrv-editor-area { position: relative; display: flex; flex: 1 1 auto; flex-direction: column; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-sidebar { display: flex; flex-direction: row; flex-shrink: 0; min-width: 0; height: 100%; background: var(--dsw-alias-bg-layer-1, #ffffff); border-right: 1px solid var(--dsw-alias-border-l1, #e0e6e8); overflow: hidden; }\n[data-edrv-view] .edrv-rail { display: flex; flex-direction: column; align-items: center; width: 44px; flex-shrink: 0; padding: 6px 0; background: var(--dsw-alias-bg-layer-2, #f0f4f4); border-right: 1px solid var(--dsw-alias-border-l1, #e0e6e8); gap: 4px; }\n[data-edrv-view] .edrv-rail-btn { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border: none; border-radius: 8px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-rail-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rail-btn.edrv-rail-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-label-primary, #1f2933); box-shadow: inset 2px 0 0 var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-rail-icon { font-size: 15px; line-height: 1; }\n[data-edrv-view] .edrv-rail-badge { position: absolute; top: 2px; right: 2px; min-width: 14px; height: 14px; padding: 0 3px; border-radius: 999px; background: var(--dsw-alias-brand-primary, #0f9d58); color: #fff; font-size: 9px; font-weight: 600; line-height: 14px; text-align: center; box-sizing: border-box; }\n[data-edrv-view] .edrv-side-body { flex: 1; min-width: 0; min-height: 0; display: flex; overflow: hidden; }\n[data-edrv-view] .edrv-side-panel { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; position: relative; }\n[data-edrv-view] .edrv-side-head { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px 0 12px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); flex-shrink: 0; }\n[data-edrv-view] .edrv-side-title { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-side-root { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-side-btn { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-side-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-tree { flex: 1; min-height: 0; overflow: auto; padding: 4px 6px 12px; font-size: 12px; }\n[data-edrv-view] .edrv-tree-row { display: flex; align-items: center; gap: 4px; height: 22px; padding-right: 6px; border-radius: 5px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-tree-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-active { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-context { box-shadow: inset 0 0 0 1px var(--dsw-alias-brand-primary, #0f9d58); background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); }\n[data-edrv-view] .edrv-tree-chev { width: 12px; flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; text-align: center; }\n[data-edrv-view] .edrv-tree-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-tree-name.edrv-tree-dim { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-tree-badge { min-width: 14px; height: 14px; padding: 0 4px; border-radius: 999px; background: var(--dsw-alias-state-warn-primary, #d97706); color: #fff; font-size: 9px; font-weight: 600; line-height: 14px; text-align: center; box-sizing: border-box; flex-shrink: 0; }\n[data-edrv-view] .edrv-tree-loading { height: 22px; line-height: 22px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-tree-error { display: flex; align-items: center; gap: 8px; margin: 4px 2px 6px; padding: 6px 8px; border: 1px solid rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n/* 大纲面板:kind 字形 / detail / 行号 */\n[data-edrv-view] .edrv-outline-kind { display: inline-flex; align-items: center; justify-content: center; width: 14px; flex-shrink: 0; font-size: 12px; font-weight: 600; text-align: center; }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-func { color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-type { color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-data { color: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-ns { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-key { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-outline-detail { flex-shrink: 0; max-width: 40%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-outline-ln { flex-shrink: 0; padding-right: 2px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-side-resize { width: 5px; flex-shrink: 0; cursor: col-resize; background: transparent; }\n[data-edrv-view] .edrv-side-resize:hover { background: var(--dsw-alias-brand-primary, #0f9d58); opacity: .35; }\n[data-edrv-view] .edrv-chip-btn.edrv-chip-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-label-primary, #1f2933); }\n\n/* ===== 侧栏形态(betterSidebar 面板内编辑区) ===== */\n[data-edrv-view][data-edrv-layout='side'] { box-sizing: border-box; height: 100%; }\n\n/* ===== 侧边栏引导条(旧页签形态、未装 betterSidebar 时) ===== */\n[data-edrv-view] .edrv-side-hint { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; flex-wrap: wrap; padding: 6px 12px; font-size: 12px; color: var(--dsw-alias-label-secondary, #52606d); background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, #f0f4f4)); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-side-hint-text { white-space: nowrap; }\n[data-edrv-view] .edrv-side-hint-cmd { font-size: 11px; padding: 2px 6px; border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #ffffff); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-side-hint-close { margin-left: auto; border: none; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); cursor: pointer; font-size: 14px; line-height: 1; padding: 2px 6px; border-radius: 6px; flex-shrink: 0; }\n[data-edrv-view] .edrv-side-hint-close:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n\n/* ===== search panel (sidebar, VSCode search view) ===== */\n[data-edrv-view] .edrv-search-panel { display: flex; flex-direction: column; min-height: 0; flex: 1; padding: 6px; gap: 4px; }\n[data-edrv-view] .edrv-search-qrow { display: flex; gap: 4px; }\n[data-edrv-view] .edrv-search-input { flex: 1; min-width: 0; height: 26px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search-input:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-opts { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-search-opt { min-width: 24px; height: 22px; padding: 0 6px; border: 1px solid transparent; border-radius: 5px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 11px; font-family: var(--ds-font-family-code, ui-monospace, monospace); cursor: pointer; }\n[data-edrv-view] .edrv-search-opt:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-opt.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); border-color: var(--dsw-alias-border-l2, #d5dde3); }\n[data-edrv-view] .edrv-search-spacer { flex: 1; }\n[data-edrv-view] .edrv-search-summary { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); padding: 2px 4px; }\n[data-edrv-view] .edrv-search-results { flex: 1; min-height: 0; overflow: auto; font-size: 12px; }\n[data-edrv-view] .edrv-search-group { margin-bottom: 2px; }\n[data-edrv-view] .edrv-search-file { display: flex; align-items: center; gap: 4px; height: 22px; padding: 0 4px; border-radius: 5px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-search-file:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-chev { width: 12px; flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; text-align: center; }\n[data-edrv-view] .edrv-search-fname { font-weight: 600; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-search-fdir { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-search-fcount { flex-shrink: 0; min-width: 16px; height: 15px; padding: 0 4px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); font-size: 10px; line-height: 15px; text-align: center; }\n[data-edrv-view] .edrv-search-line { display: flex; gap: 6px; padding: 1px 4px 1px 16px; border-radius: 4px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; overflow: hidden; }\n[data-edrv-view] .edrv-search-line.alt { background: var(--dsw-alias-bg-layer-1, #ffffff); }\n[data-edrv-view] .edrv-search-line:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-ln { flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; min-width: 26px; text-align: right; user-select: none; }\n[data-edrv-view] .edrv-search-text { overflow: hidden; text-overflow: ellipsis; white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; }\n[data-edrv-view] .edrv-search-hit { background: var(--dsw-alias-state-warn-primary, #e5b93f); color: #1f2933; border-radius: 2px; padding: 0 1px; }\n[data-edrv-view] .edrv-search-empty { padding: 8px 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-search-error { padding: 6px 8px; border: 1px solid rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n[data-edrv-view] .edrv-search-warn { padding: 6px 8px; border: 1px solid rgba(240,173,78,.45); border-radius: 6px; background: #fdf6e3; color: #b8860b; font-size: 11px; word-break: break-all; }\n\n/* include/exclude filter rows (collapsible) */\n[data-edrv-view] .edrv-search-rows { display: flex; flex-direction: column; gap: 4px; padding: 2px 0 4px; }\n[data-edrv-view] .edrv-search-row { display: flex; align-items: center; gap: 4px; }\n[data-edrv-view] .edrv-search-field { flex: 1; min-width: 0; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 11px; outline: none; }\n[data-edrv-view] .edrv-search-field:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-field.dim { opacity: .45; }\n[data-edrv-view] .edrv-search-field::placeholder { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-search-toggle { min-width: 24px; height: 24px; padding: 0 5px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; line-height: 1; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-search-toggle:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-toggle.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); border-color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-search-toggle:disabled { opacity: .4; cursor: default; }\n\n\n\n";
|
|
33
|
+
const css$1 = "/* dsh-vscode-mode 编辑区样式(原 ensureEdrvStyles 字符串,落盘为真 .css,由 tsdown CSS-inline 注入) */\n/* 浅色主题(对齐参考图:#f8f8f8 近白底 + 薄荷绿药丸 + 青绿文字 + 三文鱼 undo + 浅灰边框):\n 在 [data-edrv-view] 作用域内重定义 --dsw-alias-*,级联命中组件内联样式与 CSS。 */\n[data-edrv-view] { box-sizing: border-box; --edrv-tab-h: 34px; --dsw-alias-bg-base: #f8f8f8; --dsw-alias-bg-layer-1: #ffffff; --dsw-alias-bg-layer-2: #f0f4f4; --dsw-alias-bg-overlay: #ffffff; --dsw-alias-label-primary: #1f2933; --dsw-alias-label-secondary: #52606d; --dsw-alias-label-tertiary: #9aa5b1; --dsw-alias-border-l1: #e0e6e8; --dsw-alias-border-l2: #cbd2d9; --dsw-alias-brand-primary: #0f9d58; --dsw-alias-state-success-primary: #0f9d58; --dsw-alias-state-error-primary: #d9534f; --dsw-alias-state-warn-primary: #d97706; --dsw-alias-interactive-bg-hover: rgba(15,157,88,.08); }\n\n[data-edrv-view] .edrv-tabs { display: flex; align-items: center; gap: 2px; padding: 2px 8px 0; background: var(--dsw-alias-bg-layer-1, transparent); overflow-x: auto; scrollbar-width: thin; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab { display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 8px 0 12px; border: none; border-radius: 6px 6px 0 0; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 12px; cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-tab.edrv-tab-active { background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); box-shadow: inset 0 -2px 0 var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-tab .edrv-tab-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--dsw-alias-brand-primary, #4f8cff); flex-shrink: 0; }\n[data-edrv-view] .edrv-tab .edrv-tab-x { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; border-radius: 4px; color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; }\n[data-edrv-view] .edrv-tab .edrv-tab-x:hover { background: rgba(255,255,255,.12); color: var(--dsw-alias-label-primary, #eee); }\n[data-edrv-view] .edrv-tab-add { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; margin-left: 2px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 14px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab-add:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-pathbar { display: flex; align-items: center; gap: 8px; height: 26px; padding: 0 10px; background: var(--dsw-alias-bg-layer-1, #ffffff); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 12px; flex-shrink: 0; overflow: hidden; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-name { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-full { flex: 1; min-width: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; direction: rtl; text-align: left; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-meta { flex-shrink: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-status { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-path-input { flex: 1; min-width: 140px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search-wrap { position: relative; flex-shrink: 0; display: flex; align-items: center; padding: 2px 8px 2px 4px; }\n[data-edrv-view] .edrv-search { width: 190px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-pop { position: absolute; top: calc(100% + 4px); right: 8px; width: min(460px, calc(100vw - 24px)); max-height: 300px; overflow: auto; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 10px; box-shadow: 0 6px 20px rgba(0,0,0,.4); z-index: 60; padding: 4px; }\n[data-edrv-view] .edrv-search-item { display: flex; flex-direction: column; gap: 1px; padding: 5px 8px; border-radius: 6px; cursor: pointer; }\n[data-edrv-view] .edrv-search-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.07)); }\n[data-edrv-view] .edrv-search-item .n { color: var(--dsw-alias-label-primary, #eee); font-size: 12px; word-break: break-all; }\n[data-edrv-view] .edrv-search-item .d { color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-search-empty { padding: 8px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #888); }\n[data-edrv-view] .edrv-btn-mini { font-size: 11px; padding: 2px 9px; border: none; border-radius: 999px; cursor: pointer; color: #fff; font-weight: 600; white-space: nowrap; }\n[data-edrv-view] .edrv-btn-keep { background: var(--dsw-alias-state-success-primary, #2e9e44); }\n[data-edrv-view] .edrv-btn-undo { background: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-btn-mini:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-statusbar { display: flex; align-items: center; gap: 10px; padding: 3px 10px; border-top: 1px solid var(--dsw-alias-border-l1, #333); background: var(--dsw-alias-bg-layer-1, transparent); font-size: 11px; color: var(--dsw-alias-label-tertiary, #888); flex-shrink: 0; white-space: nowrap; overflow: hidden; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-path { flex: 1; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-lsp { flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-progress-message { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-statusbar .edrv-sp-progress { flex: 0 0 auto; min-width: 36px; text-align: right; font-variant-numeric: tabular-nums; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-lsp-status-dot { width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto; background: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-lsp-status-dot.ready { background: var(--dsw-alias-state-success-primary, #0f9d58); }\n[data-edrv-view] .edrv-lsp-status-dot.busy { background: var(--dsw-alias-state-warn-primary, #d97706); animation: edrv-lsp-pulse 1.2s ease-in-out infinite; }\n@keyframes edrv-lsp-pulse { 50% { opacity: .45; } }\n/* Ctrl+hover 可导航标识符下划线提示(绑定 Monaco inlineClassName 装饰) */\n[data-edrv-view] .edrv-nav-underline { text-decoration: underline; text-decoration-color: var(--dsw-alias-interactive-primary, #4fc1ff); text-underline-offset: 1px; cursor: pointer; }\n[data-edrv-view] .edrv-diffchip { font-size: 11px; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #333); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-state-warn-primary, #b7791f); cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn { font-size: 12px; padding: 2px 6px; border: none; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; border-radius: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-chip-btn:disabled { opacity: .35; cursor: default; }\n[data-edrv-view] .edrv-chip-btn:disabled:hover { background: transparent; }\n[data-edrv-view] .edrv-mn-add-line { background: rgba(15,157,88,.10); }\n[data-edrv-view] .edrv-mn-gutter-add { color: #0f9d58 !important; font-weight: 700; display: flex !important; align-items: center; justify-content: center; }\n[data-edrv-view] .edrv-mn-gutter-add::before { content: \"+\"; }\n[data-edrv-view] .edrv-del-zone { background: #fdeaea; border-top: 1px solid rgba(217,83,79,.35); border-bottom: 1px solid rgba(217,83,79,.35); box-shadow: inset 0 0 0 1px rgba(217,83,79,.12); }\n[data-edrv-view] .edrv-del-row { white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 12.5px; line-height: 20px; color: #c0392b; }\n[data-edrv-view] .edrv-del-text { display: inline-block; white-space: pre; }\n[data-edrv-view] .edrv-minus-overlay { position: absolute; left: 0; top: 0; width: 100%; height: 100%; max-width: 100%; overflow: visible; pointer-events: none; z-index: 6; }\n[data-edrv-view] .edrv-minus-item { position: absolute; box-sizing: border-box; max-width: 100%; overflow: hidden; }\n[data-edrv-view] .edrv-minus-item::before { content: ''; position: absolute; left: 4px; top: 50%; width: 8px; height: 2px; transform: translateY(-50%); border-radius: 2px; background: #d9534f; }\n[data-edrv-view] .edrv-monaco-host { flex: 1 1 auto; min-width: 0; min-height: 0; position: relative; overflow: hidden; }\n[data-edrv-view] .edrv-monaco-host > div { position: absolute; inset: 0; min-width: 0; min-height: 0; }\n[data-edrv-view] .edrv-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; height: 100%; color: var(--dsw-alias-label-tertiary, #777); font-size: 13px; }\n[data-edrv-view] .edrv-diffbar { position: absolute; left: 0; right: 0; bottom: 10px; margin: 0 auto; z-index: 25; width: fit-content; max-width: calc(100% - 20px); border-radius: 12px; background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, #f0f4f4)); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); box-shadow: none; overflow: visible; display: flex; flex-direction: column; }\n[data-edrv-view] .edrv-editor-area > .edrv-diffbar { max-height: calc(100% - 20px); }\n[data-edrv-view] .edrv-diffbar-row { display: flex; align-items: center; gap: 6px; height: 36px; padding: 4px 5px 4px 12px; flex-wrap: nowrap; }\n[data-edrv-view] .edrv-diffbar-count { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); min-width: 42px; text-align: center; white-space: nowrap; cursor: pointer; }\n[data-edrv-view] .edrv-diffbar-count.edrv-count-file { min-width: 64px; cursor: default; }\n[data-edrv-view] .edrv-diffbar-file { flex: 1; min-width: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-pill { font-size: 11px; padding: 3px 10px; border: none; border-radius: 999px; cursor: pointer; white-space: nowrap; font-weight: 600; }\n[data-edrv-view] .edrv-pill-keep { background: #e8f8e8; color: #0f7a45; border: 1px solid rgba(15,157,88,.4); }\n[data-edrv-view] .edrv-pill-undo { background: #fdeaea; color: #c0392b; border: 1px solid rgba(217,83,79,.4); }\n[data-edrv-view] .edrv-pill-ghost { background: #ffffff; color: var(--dsw-alias-label-secondary, #52606d); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-pill:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-diffbar-menu { position: absolute; right: 8px; bottom: calc(100% + 6px); z-index: 45; min-width: 160px; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 6px 20px rgba(31,41,51,.16); padding: 4px; display: flex; flex-direction: column; gap: 2px; }\n[data-edrv-view] .edrv-diffmenu-item { display: flex; align-items: center; gap: 8px; font-size: 12px; padding: 6px 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; text-align: left; }\n[data-edrv-view] .edrv-diffmenu-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-diffmenu-item.danger { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-diffmenu-sep { height: 1px; margin: 2px 4px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n/* 编辑区 / Tab 右键菜单(添加文件/选中内容到对话) */\n[data-edrv-view] .edrv-ctxmenu { position: fixed; z-index: 71; min-width: 200px; max-width: 320px; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 8px 26px rgba(31,41,51,.2); padding: 4px; display: flex; flex-direction: column; gap: 1px; }\n[data-edrv-view] .edrv-ctxmenu-item { display: flex; align-items: center; gap: 8px; font-size: 12px; line-height: 18px; padding: 7px 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-ctxmenu-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-danger { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-ctxmenu-item:disabled,\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-disabled { color: var(--dsw-alias-label-disabled, #b0b7c0); cursor: default; background: transparent; }\n[data-edrv-view] .edrv-ctxmenu-sep { height: 1px; margin: 3px 4px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-diffbar-body { max-height: 130px; max-width: min(560px, calc(100vw - 40px)); overflow: auto; padding: 4px 8px 8px; display: flex; flex-direction: column; gap: 4px; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-diffrow { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); cursor: pointer; flex-wrap: wrap; }\n[data-edrv-view] .edrv-diffrow:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-diffrow-l { font-size: 11px; color: var(--dsw-alias-label-primary, #1f2933); min-width: 74px; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-o { font-size: 11px; color: var(--dsw-alias-state-error-primary, #d9534f); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-n { font-size: 11px; color: var(--dsw-alias-state-success-primary, #0f9d58); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-tag { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-diffrow-stale { border-color: rgba(217,119,6,.5); cursor: default; }\n[data-edrv-view] .edrv-diffbox-others { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; padding: 4px 2px 0; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); margin-top: 2px; }\n[data-edrv-view] .edrv-diffrow-file { font-size: 11px; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); cursor: pointer; white-space: nowrap; max-width: 200px; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-diffrow-file:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n/* 编辑区 hover 差异块的 Keep/Undo 浮层 */\n[data-edrv-view] .edrv-hoveract { position: absolute; z-index: 30; display: flex; align-items: center; gap: 4px; padding: 2px 6px; border-radius: 8px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 4px 14px rgba(31,41,51,.14); }\n[data-edrv-view] .edrv-launch { position: absolute; left: 12px; right: 12px; bottom: 12px; z-index: 40; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); box-shadow: 0 6px 24px rgba(0,0,0,.5); display: flex; flex-direction: column; max-height: 60%; overflow: hidden; }\n[data-edrv-view] .edrv-launch-head { display: flex; align-items: center; gap: 6px; padding: 6px 8px; border-bottom: 1px solid var(--dsw-alias-border-l1, #333); }\n[data-edrv-view] .edrv-launch-tab { font-size: 12px; padding: 3px 12px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; }\n[data-edrv-view] .edrv-launch-tab.on { background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-label-primary, #eee); font-weight: 600; }\n[data-edrv-view] .edrv-launch-body { flex: 1; min-height: 0; overflow: auto; padding: 6px 8px; display: flex; flex-direction: column; gap: 4px; }\n[data-edrv-view] .edrv-launch-row { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1, #333); border-radius: 6px; cursor: pointer; flex-wrap: wrap; }\n[data-edrv-view] .edrv-launch-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-launch-path { flex: 1; min-width: 0; font-size: 12px; color: var(--dsw-alias-label-primary, #eee); word-break: break-all; }\n[data-edrv-view] .edrv-launch-cnt { font-size: 11px; color: var(--dsw-alias-label-tertiary, #888); white-space: nowrap; }\n[data-edrv-view] .edrv-launch-arch { display: flex; flex-direction: column; gap: 6px; }\n[data-edrv-view] .monaco-editor { overflow: hidden !important; }\n[data-edrv-view] .monaco-editor .sticky-widget { z-index: 30 !important; background: var(--dsw-alias-bg-base, #f8f8f8) !important; }\n[data-edrv-view] .monaco-editor .sticky-widget .sticky-line-content,\n[data-edrv-view] .monaco-editor .sticky-widget .sticky-line-number { background: var(--dsw-alias-bg-base, #f8f8f8) !important; }\n[data-edrv-view] .monaco-editor, [data-edrv-view] .monaco-editor .margin, [data-edrv-view] .monaco-editor-background { background: transparent !important; }\n[data-edrv-view] .monaco-editor .scrollbar .slider { background: rgba(128,128,128,.3) !important; }\n[data-edrv-view] .edrv-loading { gap: 8px; padding: 20px; }\n[data-edrv-view] .edrv-loading-title { color: var(--dsw-alias-label-primary, #1f2933); font-size: 13px; }\n[data-edrv-view] .edrv-progress { width: min(360px, 72%); height: 6px; overflow: hidden; border-radius: 999px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-progress-value { height: 100%; border-radius: inherit; background: var(--dsw-alias-brand-primary, #0f9d58); transition: width .24s ease; }\n[data-edrv-view] .edrv-loading-percent { color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; font-variant-numeric: tabular-nums; }\n@media (prefers-reduced-motion: reduce) {\n [data-edrv-view] .edrv-progress-value { transition: none; }\n}\n\n/* ===== 唯一会话级差异 dock(遵循 DSH todo/queue 原生布局) ===== */\n[data-edrv-diff-dock-shell] {\n box-sizing: border-box;\n width: calc(100% - var(--dsh-composer-side-clearance) - var(--dsh-composer-side-clearance) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));\n max-width: calc(var(--dsh-composer-card-max-width) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));\n margin: 0 auto;\n padding: 0;\n flex: none;\n border: 1px solid var(--dsw-alias-border-l1, #e0e6e8);\n border-radius: 12px;\n background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, transparent));\n box-shadow: none;\n overflow: hidden;\n}\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock {\n box-sizing: border-box;\n position: relative;\n left: auto;\n right: auto;\n bottom: auto;\n z-index: auto;\n width: 100%;\n max-width: none;\n margin: 0;\n display: flex;\n flex-direction: column;\n border: none;\n border-radius: 0;\n background: transparent;\n box-shadow: none;\n overflow: visible;\n}\n[data-edrv-diff-dock-shell] .edrv-diffbar-row { min-height: 36px; padding: 6px 12px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-row { min-height: 36px; padding: 6px 12px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-body { max-height: 180px; overflow: auto; padding: 6px 12px 10px; border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-button { box-sizing: border-box; display: flex; align-items: center; justify-content: center; width: 100%; height: 24px; border: none; border-radius: 8px; padding: 0 12px; background: transparent; color: var(--dsw-alias-label-primary); font-size: 13px; font-weight: 500; line-height: 24px; text-align: center; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-button:hover { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diffbar-count { display: inline-flex; align-items: center; color: var(--dsw-alias-label-primary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 500; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-file { display: inline-flex; align-items: center; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-editor-row { display: flex; align-items: center; height: 36px; min-height: 36px; padding: 4px 12px; overflow-x: auto; scrollbar-width: thin; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-editor-content { display: flex; align-items: center; gap: 10px; width: 100%; min-width: max-content; min-height: 28px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-nav,\n[data-edrv-diff-dock-shell] .edrv-diffbar-files,\n[data-edrv-diff-dock-shell] .edrv-diffbar-actions { display: flex; align-items: center; gap: 6px; flex: none; height: 28px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-actions { margin-left: auto; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-details-toggle { display: inline-flex; align-items: center; justify-content: center; width: 28px; min-width: 28px; padding: 0; font-size: 13px; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-details-toggle svg { width: 14px; height: 14px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-files { min-width: 0; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-files .edrv-diffbar-file { min-width: 72px; max-width: 240px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-progress { min-width: 0; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; font-variant-numeric: tabular-nums; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-summary { min-width: 0; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-pill { box-sizing: border-box; height: 28px; padding: 0 9px; border: none; border-radius: 999px; cursor: pointer; white-space: nowrap; font-size: 11px; line-height: 26px; font-weight: 600; }\n[data-edrv-diff-dock-shell] .edrv-pill-keep { background: var(--dsw-alias-state-success-tertiary); color: var(--dsw-alias-state-success-primary); border: 1px solid var(--dsw-alias-state-success-secondary); }\n[data-edrv-diff-dock-shell] .edrv-pill-undo { background: var(--dsw-alias-state-error-tertiary); color: var(--dsw-alias-state-error-primary); border: 1px solid var(--dsw-alias-state-error-secondary); }\n[data-edrv-diff-dock-shell] .edrv-pill-ghost { background: transparent; color: var(--dsw-alias-label-secondary); border: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-pill:hover:not(:disabled) { background-color: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-pill:focus-visible { outline: 2px solid var(--dsw-alias-label-tertiary); outline-offset: -2px; }\n[data-edrv-diff-dock-shell] .edrv-pill:disabled { opacity: .45; cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diffrow { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; background: transparent; cursor: pointer; flex-wrap: wrap; }\n[data-edrv-diff-dock-shell] .edrv-diffrow:hover { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-l { color: var(--dsw-alias-label-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-o { color: var(--dsw-alias-state-error-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-n { color: var(--dsw-alias-state-success-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-tag { color: var(--dsw-alias-label-tertiary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-stale { border-color: var(--dsw-alias-state-warn-secondary); cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diffbox-others { border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-file { border-color: var(--dsw-alias-border-l1); background: transparent; color: var(--dsw-alias-label-secondary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-file:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }\n[data-edrv-diff-dock-shell] .edrv-diff-details { display: flex; flex-direction: column; gap: 2px; padding: 6px 12px 8px; border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item { display: flex; align-items: center; width: 100%; min-height: 28px; gap: 8px; padding: 4px 8px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary); cursor: pointer; text-align: left; font-size: 12px; line-height: 20px; }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item.danger { color: var(--dsw-alias-state-error-primary); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item:disabled { opacity: .45; cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-sep { height: 1px; margin: 2px 4px; background: var(--dsw-alias-border-l1); }\n@media (max-width: 620px) {\n [data-edrv-diff-dock-shell] .edrv-diffbar-editor-content { width: max-content; }\n [data-edrv-diff-dock-shell] .edrv-diffbar-files .edrv-diffbar-file { max-width: 160px; }\n}\n\n/* ===== 侧边栏(活动栏 + 面板区 + 文件树) ===== */\n[data-edrv-view] .edrv-editor-row { display: flex; flex: 1 1 auto; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-main-col { box-sizing: border-box; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-main-col > .edrv-pathbar,\n[data-edrv-view] .edrv-main-col > .edrv-tabs { flex: 0 0 auto; }\n[data-edrv-view] .edrv-editor-area { position: relative; display: flex; flex: 1 1 auto; flex-direction: column; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-sidebar { display: flex; flex-direction: row; flex-shrink: 0; min-width: 0; height: 100%; background: var(--dsw-alias-bg-layer-1, #ffffff); border-right: 1px solid var(--dsw-alias-border-l1, #e0e6e8); overflow: hidden; }\n[data-edrv-view] .edrv-rail { display: flex; flex-direction: column; align-items: center; width: 44px; flex-shrink: 0; padding: 6px 0; background: var(--dsw-alias-bg-layer-2, #f0f4f4); border-right: 1px solid var(--dsw-alias-border-l1, #e0e6e8); gap: 4px; }\n[data-edrv-view] .edrv-rail-btn { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border: none; border-radius: 8px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-rail-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rail-btn.edrv-rail-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-label-primary, #1f2933); box-shadow: inset 2px 0 0 var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-rail-icon { font-size: 15px; line-height: 1; }\n[data-edrv-view] .edrv-rail-badge { position: absolute; top: 2px; right: 2px; min-width: 14px; height: 14px; padding: 0 3px; border-radius: 999px; background: var(--dsw-alias-brand-primary, #0f9d58); color: #fff; font-size: 9px; font-weight: 600; line-height: 14px; text-align: center; box-sizing: border-box; }\n[data-edrv-view] .edrv-side-body { flex: 1; min-width: 0; min-height: 0; display: flex; overflow: hidden; }\n[data-edrv-view] .edrv-side-panel { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; position: relative; }\n[data-edrv-view] .edrv-side-head { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px 0 12px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); flex-shrink: 0; }\n[data-edrv-view] .edrv-side-title { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-side-root { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-side-btn { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-side-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-tree { flex: 1; min-height: 0; overflow: auto; padding: 4px 6px 12px; font-size: 12px; }\n[data-edrv-view] .edrv-tree-row { display: flex; align-items: center; gap: 4px; height: 22px; padding-right: 6px; border-radius: 5px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-tree-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-active { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-context { box-shadow: inset 0 0 0 1px var(--dsw-alias-brand-primary, #0f9d58); background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); }\n[data-edrv-view] .edrv-tree-chev { width: 12px; flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; text-align: center; }\n[data-edrv-view] .edrv-tree-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-tree-name.edrv-tree-dim { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-tree-badge { min-width: 14px; height: 14px; padding: 0 4px; border-radius: 999px; background: var(--dsw-alias-state-warn-primary, #d97706); color: #fff; font-size: 9px; font-weight: 600; line-height: 14px; text-align: center; box-sizing: border-box; flex-shrink: 0; }\n[data-edrv-view] .edrv-tree-loading { height: 22px; line-height: 22px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-tree-error { display: flex; align-items: center; gap: 8px; margin: 4px 2px 6px; padding: 6px 8px; border: 1px solid rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n/* 大纲面板:kind 字形 / detail / 行号 */\n[data-edrv-view] .edrv-outline-kind { display: inline-flex; align-items: center; justify-content: center; width: 14px; flex-shrink: 0; font-size: 12px; font-weight: 600; text-align: center; }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-func { color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-type { color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-data { color: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-ns { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-key { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-outline-detail { flex-shrink: 0; max-width: 40%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-outline-ln { flex-shrink: 0; padding-right: 2px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-side-resize { width: 5px; flex-shrink: 0; cursor: col-resize; background: transparent; }\n[data-edrv-view] .edrv-side-resize:hover { background: var(--dsw-alias-brand-primary, #0f9d58); opacity: .35; }\n[data-edrv-view] .edrv-chip-btn.edrv-chip-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-label-primary, #1f2933); }\n\n/* ===== 侧栏形态(betterSidebar 面板内编辑区) ===== */\n[data-edrv-view][data-edrv-layout='side'] { box-sizing: border-box; height: 100%; }\n\n/* ===== 侧边栏引导条(旧页签形态、未装 betterSidebar 时) ===== */\n[data-edrv-view] .edrv-side-hint { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; flex-wrap: wrap; padding: 6px 12px; font-size: 12px; color: var(--dsw-alias-label-secondary, #52606d); background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, #f0f4f4)); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-side-hint-text { white-space: nowrap; }\n[data-edrv-view] .edrv-side-hint-cmd { font-size: 11px; padding: 2px 6px; border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #ffffff); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-side-hint-close { margin-left: auto; border: none; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); cursor: pointer; font-size: 14px; line-height: 1; padding: 2px 6px; border-radius: 6px; flex-shrink: 0; }\n[data-edrv-view] .edrv-side-hint-close:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n\n/* ===== search panel (sidebar, VSCode search view) ===== */\n[data-edrv-view] .edrv-search-panel { display: flex; flex-direction: column; min-height: 0; flex: 1; padding: 6px; gap: 4px; }\n[data-edrv-view] .edrv-search-qrow { display: flex; gap: 4px; }\n[data-edrv-view] .edrv-search-input { flex: 1; min-width: 0; height: 26px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search-input:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-opts { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-search-opt { min-width: 24px; height: 22px; padding: 0 6px; border: 1px solid transparent; border-radius: 5px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 11px; font-family: var(--ds-font-family-code, ui-monospace, monospace); cursor: pointer; }\n[data-edrv-view] .edrv-search-opt:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-opt.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); border-color: var(--dsw-alias-border-l2, #d5dde3); }\n[data-edrv-view] .edrv-search-spacer { flex: 1; }\n[data-edrv-view] .edrv-search-summary { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); padding: 2px 4px; }\n[data-edrv-view] .edrv-search-results { flex: 1; min-height: 0; overflow: auto; font-size: 12px; }\n[data-edrv-view] .edrv-search-group { margin-bottom: 2px; }\n[data-edrv-view] .edrv-search-file { display: flex; align-items: center; gap: 4px; height: 22px; padding: 0 4px; border-radius: 5px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-search-file:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-chev { width: 12px; flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; text-align: center; }\n[data-edrv-view] .edrv-search-fname { font-weight: 600; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-search-fdir { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-search-fcount { flex-shrink: 0; min-width: 16px; height: 15px; padding: 0 4px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); font-size: 10px; line-height: 15px; text-align: center; }\n[data-edrv-view] .edrv-search-line { display: flex; gap: 6px; padding: 1px 4px 1px 16px; border-radius: 4px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; overflow: hidden; }\n[data-edrv-view] .edrv-search-line.alt { background: var(--dsw-alias-bg-layer-1, #ffffff); }\n[data-edrv-view] .edrv-search-line:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-ln { flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; min-width: 26px; text-align: right; user-select: none; }\n[data-edrv-view] .edrv-search-text { overflow: hidden; text-overflow: ellipsis; white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; }\n[data-edrv-view] .edrv-search-hit { background: var(--dsw-alias-state-warn-primary, #e5b93f); color: #1f2933; border-radius: 2px; padding: 0 1px; }\n[data-edrv-view] .edrv-search-empty { padding: 8px 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-search-error { padding: 6px 8px; border: 1px solid rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n[data-edrv-view] .edrv-search-warn { padding: 6px 8px; border: 1px solid rgba(240,173,78,.45); border-radius: 6px; background: #fdf6e3; color: #b8860b; font-size: 11px; word-break: break-all; }\n\n/* include/exclude filter rows (collapsible) */\n[data-edrv-view] .edrv-search-rows { display: flex; flex-direction: column; gap: 4px; padding: 2px 0 4px; }\n[data-edrv-view] .edrv-search-row { display: flex; align-items: center; gap: 4px; }\n[data-edrv-view] .edrv-search-field { flex: 1; min-width: 0; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 11px; outline: none; }\n[data-edrv-view] .edrv-search-field:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-field.dim { opacity: .45; }\n[data-edrv-view] .edrv-search-field::placeholder { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-search-toggle { min-width: 24px; height: 24px; padding: 0 5px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; line-height: 1; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-search-toggle:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-toggle.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); border-color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-search-toggle:disabled { opacity: .4; cursor: default; }\n\n/* ===== rules panel (sidebar, Codebuddy rules view) ===== */\n[data-edrv-view] .edrv-rules-panel { display: flex; flex-direction: column; 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 { position: relative; padding: 7px 100px 6px 4px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-rules-row.off .edrv-rules-file, [data-edrv-view] .edrv-rules-row.off .edrv-rules-desc { opacity: .5; }\n[data-edrv-view] .edrv-rules-main { display: flex; align-items: center; gap: 6px; min-width: 0; cursor: pointer; }\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-shrink: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-rules-type { flex-shrink: 0; height: 15px; padding: 0 5px; border-radius: 999px; font-size: 10px; line-height: 15px; }\n[data-edrv-view] .edrv-rules-type-always { background: rgba(15,157,88,.15); color: #0b7c46; }\n[data-edrv-view] .edrv-rules-type-auto { background: rgba(79,140,255,.16); color: #3367c9; }\n[data-edrv-view] .edrv-rules-type-manual { background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-rules-offtag { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-desc { margin-top: 3px; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-rules-actions { position: absolute; top: 5px; right: 4px; display: flex; align-items: center; gap: 2px; }\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); }\n[data-edrv-view] .edrv-rules-act:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-switch { position: relative; width: 30px; height: 16px; border-radius: 999px; border: none; background: #b9c4cc; cursor: pointer; transition: background .15s; flex-shrink: 0; padding: 0; }\n[data-edrv-view] .edrv-rules-switch.on { background: #7c5cff; }\n[data-edrv-view] .edrv-rules-knob { position: absolute; top: 2px; left: 2px; width: 12px; height: 12px; border-radius: 50%; background: #fff; transition: left .15s; }\n[data-edrv-view] .edrv-rules-switch.on .edrv-rules-knob { left: 16px; }\n[data-edrv-view] .edrv-rules-empty { padding: 10px 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); line-height: 1.6; }\n[data-edrv-view] .edrv-rules-err { padding: 6px 8px; border: 1px solid rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; word-break: break-all; }\n[data-edrv-view] .edrv-rules-editor { display: flex; flex-direction: column; min-height: 0; flex: 1; gap: 6px; }\n[data-edrv-view] .edrv-rules-editor-head { display: flex; align-items: center; justify-content: space-between; font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-editor-file { display: flex; align-items: center; gap: 6px; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-input { flex: 1; min-width: 0; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 11px; outline: none; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-rules-input:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-rules-body { flex: 1; min-height: 0; resize: none; padding: 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; line-height: 1.5; outline: none; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-rules-body:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-rules-editor-hint { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); line-height: 1.5; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-editor-foot { display: flex; justify-content: flex-end; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-save { height: 24px; padding: 0 14px; border: none; border-radius: 6px; background: var(--dsw-alias-brand-primary, #0f9d58); color: #fff; font-size: 12px; cursor: pointer; }\n[data-edrv-view] .edrv-rules-save:disabled { opacity: .5; cursor: default; }\n\n\n\n";
|
|
34
34
|
const tagId$1 = "dsh-vscode-mode/editor.css";
|
|
35
35
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
36
36
|
const tag = document.createElement("style");
|
|
@@ -2166,44 +2166,87 @@ window.__ModuleLoader__.load({
|
|
|
2166
2166
|
//#endregion
|
|
2167
2167
|
//#region src/client/sidebar/SidebarView.ts
|
|
2168
2168
|
/**
|
|
2169
|
-
* dsh-vscode-mode client —
|
|
2170
|
-
*
|
|
2171
|
-
*
|
|
2172
|
-
*
|
|
2169
|
+
* dsh-vscode-mode client — 侧边栏容器(活动栏常显 + 可隐藏面板区 + 拖拽调宽)。
|
|
2170
|
+
* 面板列表来自注册表(活动栏图标/徽标/激活态);最左侧图标列(活动栏)常显,
|
|
2171
|
+
* 右侧详情面板区可拖拽调宽/隐藏:visible=false 时仅保留图标列(宽 = 图标列宽),
|
|
2172
|
+
* 点击任一图标重新展开面板(onShow),底部按钮在 ◀ 收起 / ▶ 展开间切换。
|
|
2173
|
+
* 拖拽调宽下限 = minWidth prop(通用设置 sidebarMinWidth,默认 300),低于下限直接收起面板区。
|
|
2174
|
+
* 作者 ddj 2026-08-26 / 2026-09-04
|
|
2173
2175
|
*/
|
|
2174
|
-
const W_MIN = 180;
|
|
2175
2176
|
const W_MAX = 560;
|
|
2177
|
+
/** 隐藏态拖出面板区的触发阈值(px,拖过即展开并继续实时调宽)。 */
|
|
2178
|
+
const PULL_OUT_THRESHOLD = 12;
|
|
2176
2179
|
/**
|
|
2177
2180
|
* 侧边栏容器。
|
|
2178
2181
|
* @param props.registry 面板注册表(list() 提供面板顺序)
|
|
2179
2182
|
* @param props.ctx 面板共享上下文
|
|
2180
2183
|
* @param props.activePanel 当前激活面板 id
|
|
2181
2184
|
* @param props.onActive 激活面板变化回调
|
|
2185
|
+
* @param props.visible 面板区是否可见(false = 只显示活动栏)
|
|
2186
|
+
* @param props.onShow 重新展开面板区回调(活动栏图标点击/底部按钮)
|
|
2182
2187
|
* @param props.width 面板区宽度
|
|
2183
2188
|
* @param props.onWidth 宽度变化回调
|
|
2184
|
-
* @param props.onHide
|
|
2189
|
+
* @param props.onHide 收起面板区回调
|
|
2190
|
+
* @param props.minWidth 最小宽度(通用设置 sidebarMinWidth;拖拽低于它触发隐藏)
|
|
2185
2191
|
*/
|
|
2186
2192
|
function SidebarView(props) {
|
|
2187
2193
|
const panels = props.registry?.list?.() ?? [];
|
|
2188
2194
|
const ctx = props.ctx;
|
|
2189
2195
|
const activePanel = props.activePanel;
|
|
2190
2196
|
const onActive = props.onActive;
|
|
2197
|
+
const visible = props.visible !== false;
|
|
2198
|
+
const onShow = props.onShow;
|
|
2191
2199
|
const width = props.width;
|
|
2192
2200
|
const onWidth = props.onWidth;
|
|
2193
2201
|
const onHide = props.onHide;
|
|
2202
|
+
const wMin = Math.max(120, Math.min(W_MAX, Math.round(Number(props.minWidth) || 300)));
|
|
2194
2203
|
const active = panels.find((p) => p.id === activePanel) || panels[0];
|
|
2195
2204
|
const onPointerDown = (e) => {
|
|
2196
2205
|
e.preventDefault();
|
|
2197
2206
|
const startX = e.clientX;
|
|
2198
2207
|
const startW = width;
|
|
2208
|
+
const cleanup = () => {
|
|
2209
|
+
window.removeEventListener("pointermove", onMove);
|
|
2210
|
+
window.removeEventListener("pointerup", onUp);
|
|
2211
|
+
};
|
|
2212
|
+
const onUp = () => cleanup();
|
|
2199
2213
|
const onMove = (ev) => {
|
|
2200
|
-
const
|
|
2201
|
-
|
|
2214
|
+
const raw = startW + (ev.clientX - startX);
|
|
2215
|
+
if (raw < wMin) {
|
|
2216
|
+
cleanup();
|
|
2217
|
+
onHide();
|
|
2218
|
+
return;
|
|
2219
|
+
}
|
|
2220
|
+
onWidth(Math.min(W_MAX, raw));
|
|
2202
2221
|
};
|
|
2203
|
-
|
|
2222
|
+
window.addEventListener("pointermove", onMove);
|
|
2223
|
+
window.addEventListener("pointerup", onUp);
|
|
2224
|
+
};
|
|
2225
|
+
/**
|
|
2226
|
+
* 隐藏态接缝拖拽:向右拖过阈值把面板区拉出来(以记忆宽度展开),继续拖动实时调宽。
|
|
2227
|
+
* @param e pointerdown 事件
|
|
2228
|
+
*/
|
|
2229
|
+
const onSeamPointerDown = (e) => {
|
|
2230
|
+
e.preventDefault();
|
|
2231
|
+
const startX = e.clientX;
|
|
2232
|
+
const baseW = Math.max(wMin, Math.min(W_MAX, Math.round(Number(width) || wMin)));
|
|
2233
|
+
let expanded = false;
|
|
2234
|
+
let expandStartX = 0;
|
|
2235
|
+
const cleanup = () => {
|
|
2204
2236
|
window.removeEventListener("pointermove", onMove);
|
|
2205
2237
|
window.removeEventListener("pointerup", onUp);
|
|
2206
2238
|
};
|
|
2239
|
+
const onUp = () => cleanup();
|
|
2240
|
+
const onMove = (ev) => {
|
|
2241
|
+
if (!expanded) {
|
|
2242
|
+
if (ev.clientX - startX < PULL_OUT_THRESHOLD) return;
|
|
2243
|
+
expanded = true;
|
|
2244
|
+
expandStartX = ev.clientX;
|
|
2245
|
+
onShow();
|
|
2246
|
+
return;
|
|
2247
|
+
}
|
|
2248
|
+
onWidth(Math.max(wMin, Math.min(W_MAX, baseW + (ev.clientX - expandStartX))));
|
|
2249
|
+
};
|
|
2207
2250
|
window.addEventListener("pointermove", onMove);
|
|
2208
2251
|
window.addEventListener("pointerup", onUp);
|
|
2209
2252
|
};
|
|
@@ -2216,21 +2259,28 @@ window.__ModuleLoader__.load({
|
|
|
2216
2259
|
const count = typeof p.badge === "function" ? p.badge(ctx) : null;
|
|
2217
2260
|
return react.default.createElement("button", {
|
|
2218
2261
|
key: p.id,
|
|
2219
|
-
className: "edrv-rail-btn" + (active && p.id === active.id ? " edrv-rail-on" : ""),
|
|
2262
|
+
className: "edrv-rail-btn" + (visible && active && p.id === active.id ? " edrv-rail-on" : ""),
|
|
2220
2263
|
title: p.title,
|
|
2221
|
-
onClick: () =>
|
|
2264
|
+
onClick: () => {
|
|
2265
|
+
onActive(p.id);
|
|
2266
|
+
if (!visible && typeof onShow === "function") onShow();
|
|
2267
|
+
}
|
|
2222
2268
|
}, react.default.createElement("span", { className: "edrv-rail-icon" }, p.icon), count > 0 ? react.default.createElement("span", { className: "edrv-rail-badge" }, String(count)) : null);
|
|
2223
2269
|
})), react.default.createElement("button", {
|
|
2224
2270
|
className: "edrv-rail-btn",
|
|
2225
|
-
title: "
|
|
2226
|
-
onClick: onHide
|
|
2227
|
-
}, "◀"));
|
|
2271
|
+
title: (visible ? "隐藏面板区" : "展开面板区") + " (Ctrl+B)",
|
|
2272
|
+
onClick: () => visible ? onHide() : onShow?.()
|
|
2273
|
+
}, visible ? "◀" : "▶"));
|
|
2228
2274
|
return react.default.createElement("div", {
|
|
2229
|
-
className: "edrv-sidebar",
|
|
2230
|
-
style: { width }
|
|
2231
|
-
}, rail, react.default.createElement("div", { className: "edrv-side-body" }, active ? active.render(ctx) : null), react.default.createElement("div", {
|
|
2275
|
+
className: "edrv-sidebar" + (visible ? "" : " edrv-sidebar-rail-only"),
|
|
2276
|
+
style: { width: visible ? width : 49 }
|
|
2277
|
+
}, rail, visible ? react.default.createElement("div", { className: "edrv-side-body" }, active ? active.render(ctx) : null) : null, visible ? react.default.createElement("div", {
|
|
2232
2278
|
className: "edrv-side-resize",
|
|
2233
2279
|
onPointerDown
|
|
2280
|
+
}) : react.default.createElement("div", {
|
|
2281
|
+
className: "edrv-side-resize",
|
|
2282
|
+
title: "拖拽展开面板区",
|
|
2283
|
+
onPointerDown: onSeamPointerDown
|
|
2234
2284
|
}));
|
|
2235
2285
|
}
|
|
2236
2286
|
//#endregion
|
|
@@ -2431,7 +2481,9 @@ window.__ModuleLoader__.load({
|
|
|
2431
2481
|
/** 侧边栏提示已关闭标记(全局,无会话)。 */
|
|
2432
2482
|
sideHint: "edrv.side-hint-dismissed",
|
|
2433
2483
|
/** 「性能优化」页工作区栏目展开状态(workspaceFoldCache v1,全局不按会话)。 */
|
|
2434
|
-
workspaceFold: "edrv.ws-fold.v1."
|
|
2484
|
+
workspaceFold: "edrv.ws-fold.v1.",
|
|
2485
|
+
/** 规则面板 UI 状态(RulesPanel v1:Tab 与项目工作区选择,全局不按会话)。 */
|
|
2486
|
+
rules: "edrv.rules.v1."
|
|
2435
2487
|
};
|
|
2436
2488
|
//#endregion
|
|
2437
2489
|
//#region src/client/state/viewStateCache.ts
|
|
@@ -2537,6 +2589,36 @@ window.__ModuleLoader__.load({
|
|
|
2537
2589
|
window.localStorage.setItem(KEY_PREFIX$2 + String(sessionId), serializeViewStates(states));
|
|
2538
2590
|
} catch (error) {}
|
|
2539
2591
|
}
|
|
2592
|
+
let currentMin = 300;
|
|
2593
|
+
/**
|
|
2594
|
+
* 归一化最小宽度:非法(NaN/非有限/负数)回退默认,越界夹取到 [180, 560]。
|
|
2595
|
+
* @author ddj 2026年09月04号
|
|
2596
|
+
* @param value 原始值(设置文档来的任意 JSON 值)
|
|
2597
|
+
* @returns 合法最小宽度
|
|
2598
|
+
*/
|
|
2599
|
+
function normalizeSidebarMinWidth(value) {
|
|
2600
|
+
const n = typeof value === "number" ? value : Number(value);
|
|
2601
|
+
if (!Number.isFinite(n) || n <= 0) return 300;
|
|
2602
|
+
return Math.max(180, Math.min(560, Math.round(n)));
|
|
2603
|
+
}
|
|
2604
|
+
/**
|
|
2605
|
+
* 应用设置值(client/index.ts 设置订阅同步调用)。
|
|
2606
|
+
* @author ddj 2026年09月04号
|
|
2607
|
+
* @param value 设置文档中的 sidebarMinWidth
|
|
2608
|
+
* @returns 归一化后的生效值
|
|
2609
|
+
*/
|
|
2610
|
+
function sidebarMinApply(value) {
|
|
2611
|
+
currentMin = normalizeSidebarMinWidth(value);
|
|
2612
|
+
return currentMin;
|
|
2613
|
+
}
|
|
2614
|
+
/**
|
|
2615
|
+
* 读取当前生效的最小宽度(编辑器初始/恢复/拖拽夹取共用)。
|
|
2616
|
+
* @author ddj 2026年09月04号
|
|
2617
|
+
* @returns 当前最小宽度
|
|
2618
|
+
*/
|
|
2619
|
+
function getSidebarMinWidth() {
|
|
2620
|
+
return currentMin;
|
|
2621
|
+
}
|
|
2540
2622
|
/** 路径一致(容忍相对路径大小写差异,对齐既有 sameFile 语义常用写法)。 */
|
|
2541
2623
|
function samePath(a, b) {
|
|
2542
2624
|
if (a === b) return true;
|
|
@@ -2601,6 +2683,154 @@ window.__ModuleLoader__.load({
|
|
|
2601
2683
|
};
|
|
2602
2684
|
}
|
|
2603
2685
|
//#endregion
|
|
2686
|
+
//#region src/client/addToConversation.ts
|
|
2687
|
+
/** 把追加引用结果映射为可读文案(ok 用 okText;busy 提示已降级纯文本;unavailable 提示不可用)。
|
|
2688
|
+
* @author ddj 2026年09月03号
|
|
2689
|
+
* @param outcome 追加结果状态
|
|
2690
|
+
* @param okText 成功文案(如「已添加文件引用」/「已添加文件夹引用」)
|
|
2691
|
+
* @returns 状态栏/通知用文案
|
|
2692
|
+
*/
|
|
2693
|
+
function statusOfAdd(outcome, okText) {
|
|
2694
|
+
if (outcome === "ok") return okText;
|
|
2695
|
+
if (outcome === "busy") return okText + "(输入框忙,已降级纯文本)";
|
|
2696
|
+
return "无法添加到对话(无会话或输入框不可用)";
|
|
2697
|
+
}
|
|
2698
|
+
/** DSH reference source 名(dsh-client-ui-reference 注册的 @file/@session 统一源)。 */
|
|
2699
|
+
const REF_SOURCE = "reference";
|
|
2700
|
+
/**
|
|
2701
|
+
* 生成 DSH @file 语法引用串:cwd 相对化、\ → /、含空白时按 @"path" 语法加引号。
|
|
2702
|
+
* cwd 外/无法相对化的路径回退原路径。
|
|
2703
|
+
* @author ddj 2026年08月25号
|
|
2704
|
+
* @param path 打开的文件路径(相对 cwd 或绝对)
|
|
2705
|
+
* @param cwd 会话工作区目录(可选)
|
|
2706
|
+
* @returns 引用串(如 @src/index.ts 或 @"a b.ts")
|
|
2707
|
+
*/
|
|
2708
|
+
function mentionOf(path, cwd) {
|
|
2709
|
+
const raw = String(path);
|
|
2710
|
+
let rel = raw;
|
|
2711
|
+
if (cwd) {
|
|
2712
|
+
const base = String(cwd).replace(/[\\/]+$/, "");
|
|
2713
|
+
const up = raw.replace(/\\/g, "/");
|
|
2714
|
+
const baseUp = base.replace(/\\/g, "/");
|
|
2715
|
+
if (up.startsWith(baseUp + "/")) rel = up.slice(baseUp.length + 1);
|
|
2716
|
+
else if (up === baseUp) rel = "";
|
|
2717
|
+
}
|
|
2718
|
+
rel = rel.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
2719
|
+
if (!rel) rel = raw.replace(/\\/g, "/");
|
|
2720
|
+
if (/[\u0000-\u001f\u007f-\u009f"]/u.test(rel)) return "@" + raw;
|
|
2721
|
+
return /\s/u.test(rel) ? `@"${rel}"` : `@${rel}`;
|
|
2722
|
+
}
|
|
2723
|
+
/** 引用标签:文件名 + 可选行区间(chip 内展示,不带 @ 前缀)。
|
|
2724
|
+
* @author ddj 2026年08月25号 */
|
|
2725
|
+
function labelOf(path, range) {
|
|
2726
|
+
const base = String(path).split(/[\\/]/).pop() || String(path);
|
|
2727
|
+
if (!range || range.endLine < range.startLine) return base;
|
|
2728
|
+
return range.startLine === range.endLine ? `${base} L${range.startLine}` : `${base} L${range.startLine}-${range.endLine}`;
|
|
2729
|
+
}
|
|
2730
|
+
/** 引用 ref:引用串 + 可选行区间(序列化直出,agent 据此读取对应片段)。
|
|
2731
|
+
* @author ddj 2026年08月25号 */
|
|
2732
|
+
function refOf(mention, range) {
|
|
2733
|
+
if (!range || range.endLine < range.startLine) return mention;
|
|
2734
|
+
return range.startLine === range.endLine ? `${mention} L${range.startLine}` : `${mention} L${range.startLine}-${range.endLine}`;
|
|
2735
|
+
}
|
|
2736
|
+
/** 构造 DSH 文件引用插入载荷(source=reference,发送序列化为 mention(+range) 文本)。
|
|
2737
|
+
* @param path 目标路径(相对 cwd 或绝对)
|
|
2738
|
+
* @param cwd 会话工作区目录(可选)
|
|
2739
|
+
* @param range 行区间(可选)
|
|
2740
|
+
* @param appearance 引用外观:'file'(默认)| 'folder'
|
|
2741
|
+
*/
|
|
2742
|
+
function buildFileRef(path, cwd, range, appearance = "file") {
|
|
2743
|
+
const mention = mentionOf(path, cwd);
|
|
2744
|
+
return {
|
|
2745
|
+
mention,
|
|
2746
|
+
reference: {
|
|
2747
|
+
source: REF_SOURCE,
|
|
2748
|
+
ref: refOf(mention, range),
|
|
2749
|
+
label: labelOf(path, range),
|
|
2750
|
+
appearance,
|
|
2751
|
+
clipboardText: mention
|
|
2752
|
+
}
|
|
2753
|
+
};
|
|
2754
|
+
}
|
|
2755
|
+
/**
|
|
2756
|
+
* 解析会话输入门面;缺失时返回 undefined(动作侧守卫降级)。
|
|
2757
|
+
* @author ddj 2026年08月25号
|
|
2758
|
+
* @param ctx 客户端服务上下文
|
|
2759
|
+
* @param sessionId 会话 id
|
|
2760
|
+
* @returns SessionInput 或 undefined
|
|
2761
|
+
*/
|
|
2762
|
+
function inputFor(ctx, sessionId) {
|
|
2763
|
+
if (!sessionId) return void 0;
|
|
2764
|
+
try {
|
|
2765
|
+
const sessions = ctx.get("sessions");
|
|
2766
|
+
const conversation = ctx.get("conversation");
|
|
2767
|
+
const actx = sessions?.scope?.(sessionId);
|
|
2768
|
+
const shell = actx && conversation?.input?.for?.(actx);
|
|
2769
|
+
return shell && typeof shell.setDraft === "function" ? shell : void 0;
|
|
2770
|
+
} catch {
|
|
2771
|
+
return;
|
|
2772
|
+
}
|
|
2773
|
+
}
|
|
2774
|
+
/** 取当前草稿长度与版本;无输入门面时返回 null。
|
|
2775
|
+
* @author ddj 2026年08月25号 */
|
|
2776
|
+
function draftCursor(input) {
|
|
2777
|
+
try {
|
|
2778
|
+
const s = input?.state?.getSnapshot?.();
|
|
2779
|
+
if (!s) return null;
|
|
2780
|
+
return {
|
|
2781
|
+
draft: String(s.draft ?? ""),
|
|
2782
|
+
draftRev: Number(s.draftRev ?? 0)
|
|
2783
|
+
};
|
|
2784
|
+
} catch {
|
|
2785
|
+
return null;
|
|
2786
|
+
}
|
|
2787
|
+
}
|
|
2788
|
+
/** 从 sessions 列表快照读会话工作区目录(与 index.ts 既有读取方式一致)。
|
|
2789
|
+
* @author ddj 2026年08月25号 */
|
|
2790
|
+
function cwdOf(ctx, sessionId) {
|
|
2791
|
+
if (!sessionId) return void 0;
|
|
2792
|
+
try {
|
|
2793
|
+
return ctx.get("sessions")?.list?.getSnapshot?.()?.byId?.[sessionId]?.cwd;
|
|
2794
|
+
} catch {
|
|
2795
|
+
return;
|
|
2796
|
+
}
|
|
2797
|
+
}
|
|
2798
|
+
/** 输入门面插入引用(拦截异常视作未应用,走降级)。
|
|
2799
|
+
* @author ddj 2026年08月25号 */
|
|
2800
|
+
function safeInsert(input, reference, span) {
|
|
2801
|
+
try {
|
|
2802
|
+
return input.insertReference(reference, span) === true;
|
|
2803
|
+
} catch {
|
|
2804
|
+
return false;
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
/**
|
|
2808
|
+
* 创建「添加到对话」动作集(apply 阶段构建一次,随 props 传给 EditorView)。
|
|
2809
|
+
* @author ddj 2026年08月25号
|
|
2810
|
+
* @param ctx 客户端服务上下文(sessions + conversation)
|
|
2811
|
+
* @returns 动作集
|
|
2812
|
+
*/
|
|
2813
|
+
function createAddToConversation(ctx) {
|
|
2814
|
+
const appendReference = async (sessionId, path, range, appearance) => {
|
|
2815
|
+
const input = inputFor(ctx, sessionId);
|
|
2816
|
+
if (!input) return "unavailable";
|
|
2817
|
+
const cur = draftCursor(input);
|
|
2818
|
+
if (!cur) return "unavailable";
|
|
2819
|
+
const { reference, mention } = buildFileRef(path, cwdOf(ctx, sessionId), range, appearance);
|
|
2820
|
+
if (!safeInsert(input, reference, {
|
|
2821
|
+
start: cur.draft.length,
|
|
2822
|
+
end: cur.draft.length,
|
|
2823
|
+
draftRev: cur.draftRev
|
|
2824
|
+
})) {
|
|
2825
|
+
const gap = cur.draft.length > 0 && !/\s$/.test(cur.draft) ? " " : "";
|
|
2826
|
+
input.setDraft(cur.draft + gap + mention + " ");
|
|
2827
|
+
return "busy";
|
|
2828
|
+
}
|
|
2829
|
+
return "ok";
|
|
2830
|
+
};
|
|
2831
|
+
return { appendReference };
|
|
2832
|
+
}
|
|
2833
|
+
//#endregion
|
|
2604
2834
|
//#region src/shared/lsp.ts
|
|
2605
2835
|
/** LSP semantic token 标准类型(host 归一化后,client 与 Monaco 共用)。 */
|
|
2606
2836
|
const LSP_SEMANTIC_TOKEN_TYPES = [
|
|
@@ -3386,7 +3616,7 @@ window.__ModuleLoader__.load({
|
|
|
3386
3616
|
const [fileIdx, setFileIdx] = react.default.useState(0);
|
|
3387
3617
|
const [tabMenu, setTabMenu] = react.default.useState(null);
|
|
3388
3618
|
const [sidebarOn, setSidebarOn] = react.default.useState(layout !== "side");
|
|
3389
|
-
const [sidebarW, setSidebarW] = react.default.useState(
|
|
3619
|
+
const [sidebarW, setSidebarW] = react.default.useState(() => getSidebarMinWidth());
|
|
3390
3620
|
const [activePanel, setActivePanel] = react.default.useState("explorer");
|
|
3391
3621
|
const [focusRequest, setFocusRequest] = react.default.useState(0);
|
|
3392
3622
|
useKeybindingsVersion();
|
|
@@ -3857,11 +4087,20 @@ window.__ModuleLoader__.load({
|
|
|
3857
4087
|
if (raw) {
|
|
3858
4088
|
const saved = JSON.parse(raw);
|
|
3859
4089
|
if (typeof saved.on === "boolean") setSidebarOn(saved.on);
|
|
3860
|
-
if (typeof saved.width === "number") setSidebarW(Math.max(
|
|
4090
|
+
if (typeof saved.width === "number") setSidebarW(Math.max(getSidebarMinWidth(), Math.min(560, saved.width)));
|
|
3861
4091
|
if (typeof saved.panel === "string") setActivePanel(saved.panel);
|
|
3862
4092
|
}
|
|
3863
4093
|
} catch (e) {}
|
|
3864
4094
|
}, [sessionId, sidebarKey]);
|
|
4095
|
+
const [sidebarMinW, setSidebarMinW] = react.default.useState(() => getSidebarMinWidth());
|
|
4096
|
+
react.default.useEffect(() => {
|
|
4097
|
+
const onMinChange = () => {
|
|
4098
|
+
setSidebarMinW(getSidebarMinWidth());
|
|
4099
|
+
setSidebarW((w) => Math.max(getSidebarMinWidth(), w));
|
|
4100
|
+
};
|
|
4101
|
+
window.addEventListener("edrv:sidebar-min-width", onMinChange);
|
|
4102
|
+
return () => window.removeEventListener("edrv:sidebar-min-width", onMinChange);
|
|
4103
|
+
}, []);
|
|
3865
4104
|
react.default.useEffect(() => {
|
|
3866
4105
|
if (!sessionId) return;
|
|
3867
4106
|
try {
|
|
@@ -4551,14 +4790,7 @@ window.__ModuleLoader__.load({
|
|
|
4551
4790
|
const dismissMenus = () => {
|
|
4552
4791
|
setTabMenu(null);
|
|
4553
4792
|
};
|
|
4554
|
-
/**
|
|
4555
|
-
* @author ddj 2026年08月25号 */
|
|
4556
|
-
const statusOfAdd = (outcome, okText) => {
|
|
4557
|
-
if (outcome === "ok") return okText;
|
|
4558
|
-
if (outcome === "busy") return okText + "(输入框忙,已降级纯文本)";
|
|
4559
|
-
return "无法添加到对话(无会话或输入框不可用)";
|
|
4560
|
-
};
|
|
4561
|
-
/** 添加文件/选中区引用到对话(异步,状态栏反馈)。 */
|
|
4793
|
+
/** 添加文件/选中区引用到对话(异步,状态栏反馈;状态文案走共享 statusOfAdd)。 */
|
|
4562
4794
|
const addRefToChat = (path, range) => {
|
|
4563
4795
|
if (!path) {
|
|
4564
4796
|
setStatus("无活动文件");
|
|
@@ -4747,7 +4979,7 @@ window.__ModuleLoader__.load({
|
|
|
4747
4979
|
onClick: navForward
|
|
4748
4980
|
}, "→"), react.default.createElement("button", {
|
|
4749
4981
|
className: "edrv-chip-btn" + (sidebarOn ? " edrv-chip-on" : ""),
|
|
4750
|
-
title: "
|
|
4982
|
+
title: "切换面板区 (" + (chordOf("edrv.toggleSidebar") ?? "Ctrl+B") + "),图标列常显",
|
|
4751
4983
|
onClick: () => setSidebarOn((v) => !v)
|
|
4752
4984
|
}, "☰"), react.default.createElement("button", {
|
|
4753
4985
|
className: "edrv-chip-btn",
|
|
@@ -4945,6 +5177,7 @@ window.__ModuleLoader__.load({
|
|
|
4945
5177
|
const sidebarPanels = props.sidebarPanels;
|
|
4946
5178
|
const sidebarCtx = {
|
|
4947
5179
|
sessionId,
|
|
5180
|
+
cwd: props.sessions?.list?.getSnapshot?.()?.byId?.[sessionId]?.cwd ?? null,
|
|
4948
5181
|
openFile: (p) => openFile(p, false),
|
|
4949
5182
|
openFileAt,
|
|
4950
5183
|
activePath: active,
|
|
@@ -4957,6 +5190,7 @@ window.__ModuleLoader__.load({
|
|
|
4957
5190
|
editor: () => editorRef.current,
|
|
4958
5191
|
outlineSources: props.outlineSources,
|
|
4959
5192
|
fileMenuItems: props.fileMenuItems,
|
|
5193
|
+
addToConversation,
|
|
4960
5194
|
notify: (message) => setStatus(message)
|
|
4961
5195
|
};
|
|
4962
5196
|
const editorArea = react.default.createElement("div", { className: "edrv-editor-area" }, body, hoverEl, overlay);
|
|
@@ -4990,14 +5224,17 @@ window.__ModuleLoader__.load({
|
|
|
4990
5224
|
overflow: "hidden"
|
|
4991
5225
|
}
|
|
4992
5226
|
}, pathBar, tabRow, sideHintEl, editorArea, lspFooter);
|
|
4993
|
-
const editorRow = react.default.createElement("div", { className: "edrv-editor-row" },
|
|
5227
|
+
const editorRow = react.default.createElement("div", { className: "edrv-editor-row" }, sidebarPanels ? react.default.createElement(SidebarView, {
|
|
4994
5228
|
registry: sidebarPanels,
|
|
4995
5229
|
ctx: sidebarCtx,
|
|
4996
5230
|
activePanel,
|
|
4997
5231
|
onActive: setActivePanel,
|
|
5232
|
+
visible: sidebarOn,
|
|
5233
|
+
onShow: () => setSidebarOn(true),
|
|
4998
5234
|
width: sidebarW,
|
|
4999
5235
|
onWidth: setSidebarW,
|
|
5000
|
-
onHide: () => setSidebarOn(false)
|
|
5236
|
+
onHide: () => setSidebarOn(false),
|
|
5237
|
+
minWidth: sidebarMinW
|
|
5001
5238
|
}) : null, mainCol);
|
|
5002
5239
|
const baseStyle = {
|
|
5003
5240
|
minHeight: 0,
|
|
@@ -6767,7 +7004,7 @@ window.__ModuleLoader__.load({
|
|
|
6767
7004
|
}));
|
|
6768
7005
|
return react.default.createElement("section", { className: "vsm-project" }, head, body);
|
|
6769
7006
|
}
|
|
6770
|
-
/** 通用设置:选择当前对话文件链接的打开器 +
|
|
7007
|
+
/** 通用设置:选择当前对话文件链接的打开器 + 开发形态开关 + 编辑器布局(侧边栏最小宽度)。 */
|
|
6771
7008
|
function GeneralSettings({ registry }) {
|
|
6772
7009
|
const [tool, setTool] = react.default.useState(AUTO_OPEN_TOOL);
|
|
6773
7010
|
const [busy, setBusy] = react.default.useState(false);
|
|
@@ -6775,6 +7012,8 @@ window.__ModuleLoader__.load({
|
|
|
6775
7012
|
const [devForm, setDevForm] = react.default.useState(null);
|
|
6776
7013
|
const [devBusy, setDevBusy] = react.default.useState(false);
|
|
6777
7014
|
const [devMessage, setDevMessage] = react.default.useState("");
|
|
7015
|
+
const [minW, setMinW] = react.default.useState(300);
|
|
7016
|
+
const [minDraft, setMinDraft] = react.default.useState(null);
|
|
6778
7017
|
const settings = react.default.useContext(SettingsContext);
|
|
6779
7018
|
const snapshot = settings?.getSnapshot?.();
|
|
6780
7019
|
const loading = !snapshot || snapshot.status === "loading";
|
|
@@ -6782,8 +7021,10 @@ window.__ModuleLoader__.load({
|
|
|
6782
7021
|
const notReady = snapshot?.status !== "ready";
|
|
6783
7022
|
react.default.useEffect(() => {
|
|
6784
7023
|
const onChange = () => {
|
|
6785
|
-
const
|
|
7024
|
+
const snap = settings?.getSnapshot?.();
|
|
7025
|
+
const next = snap?.value?.fileOpenTool;
|
|
6786
7026
|
if (typeof next === "string") setTool(next);
|
|
7027
|
+
setMinW(normalizeSidebarMinWidth(snap?.value?.sidebarMinWidth));
|
|
6787
7028
|
};
|
|
6788
7029
|
onChange();
|
|
6789
7030
|
return settings?.subscribe?.(onChange);
|
|
@@ -6804,6 +7045,25 @@ window.__ModuleLoader__.load({
|
|
|
6804
7045
|
}
|
|
6805
7046
|
settings.set("fileOpenTool", value).catch((e) => setError(String(e))).finally(() => setBusy(false));
|
|
6806
7047
|
};
|
|
7048
|
+
/** 提交侧边栏最小宽度(归一化夹取 180–560 后持久化)。 */
|
|
7049
|
+
const saveMinW = (raw) => {
|
|
7050
|
+
const next = normalizeSidebarMinWidth(raw);
|
|
7051
|
+
setMinW(next);
|
|
7052
|
+
setBusy(true);
|
|
7053
|
+
setError("");
|
|
7054
|
+
if (!settings?.set) {
|
|
7055
|
+
setError("设置服务不可用");
|
|
7056
|
+
setBusy(false);
|
|
7057
|
+
return;
|
|
7058
|
+
}
|
|
7059
|
+
settings.set("sidebarMinWidth", next).catch((e) => setError(String(e))).finally(() => setBusy(false));
|
|
7060
|
+
};
|
|
7061
|
+
/** 结束输入(blur/Enter)时提交草稿。 */
|
|
7062
|
+
const commitMinW = () => {
|
|
7063
|
+
if (minDraft === null) return;
|
|
7064
|
+
setMinDraft(null);
|
|
7065
|
+
saveMinW(minDraft);
|
|
7066
|
+
};
|
|
6807
7067
|
const closeDevForm = () => {
|
|
6808
7068
|
if (!window.confirm("关闭开发形态:插件将切换为正式版安装(版本依赖 + 删除工作区链接),pnpm 装配后需重启 DSH 生效。确认关闭?")) return;
|
|
6809
7069
|
setDevBusy(true);
|
|
@@ -6839,7 +7099,20 @@ window.__ModuleLoader__.load({
|
|
|
6839
7099
|
}, options.map((item) => react.default.createElement("option", {
|
|
6840
7100
|
key: item.id,
|
|
6841
7101
|
value: item.id
|
|
6842
|
-
}, item.label))), loading && react.default.createElement("small", null, "读取中…")), devFormRow)))
|
|
7102
|
+
}, item.label))), loading && react.default.createElement("small", null, "读取中…")), devFormRow)), react.default.createElement("section", { className: "vsm-panel" }, react.default.createElement("h3", { className: "vsm-panel-title" }, "编辑器"), react.default.createElement("div", { className: "vsm-panel-body" }, react.default.createElement("label", { className: "vsm-general-row" }, react.default.createElement("span", null, "侧边栏最小宽度"), react.default.createElement("input", {
|
|
7103
|
+
type: "number",
|
|
7104
|
+
min: 180,
|
|
7105
|
+
max: 560,
|
|
7106
|
+
step: 10,
|
|
7107
|
+
value: minDraft ?? minW,
|
|
7108
|
+
disabled: loading || unavailable || notReady || busy || snapshot?.writable === false,
|
|
7109
|
+
title: "180–560 px;拖拽侧边栏低于该宽度时自动隐藏",
|
|
7110
|
+
onChange: (event) => setMinDraft(event.target.value),
|
|
7111
|
+
onBlur: commitMinW,
|
|
7112
|
+
onKeyDown: (event) => {
|
|
7113
|
+
if (event.key === "Enter") commitMinW();
|
|
7114
|
+
}
|
|
7115
|
+
}), react.default.createElement("small", null, "180–560 px;拖拽低于该宽度自动隐藏")))));
|
|
6843
7116
|
}
|
|
6844
7117
|
/** 兼容性小节:host 报告(RPC compat)+ 客户端本地适配项。 */
|
|
6845
7118
|
function CompatSection({ getSummary }) {
|
|
@@ -7226,151 +7499,11 @@ window.__ModuleLoader__.load({
|
|
|
7226
7499
|
addToConversation: props?.addToConversation,
|
|
7227
7500
|
sidebarPanels: props?.sidebarPanels,
|
|
7228
7501
|
outlineSources: props?.outlineSources,
|
|
7229
|
-
fileMenuItems: props?.fileMenuItems
|
|
7502
|
+
fileMenuItems: props?.fileMenuItems,
|
|
7503
|
+
sessions: props?.sessions
|
|
7230
7504
|
});
|
|
7231
7505
|
}
|
|
7232
7506
|
//#endregion
|
|
7233
|
-
//#region src/client/addToConversation.ts
|
|
7234
|
-
/** DSH reference source 名(dsh-client-ui-reference 注册的 @file/@session 统一源)。 */
|
|
7235
|
-
const REF_SOURCE = "reference";
|
|
7236
|
-
/**
|
|
7237
|
-
* 生成 DSH @file 语法引用串:cwd 相对化、\ → /、含空白时按 @"path" 语法加引号。
|
|
7238
|
-
* cwd 外/无法相对化的路径回退原路径。
|
|
7239
|
-
* @author ddj 2026年08月25号
|
|
7240
|
-
* @param path 打开的文件路径(相对 cwd 或绝对)
|
|
7241
|
-
* @param cwd 会话工作区目录(可选)
|
|
7242
|
-
* @returns 引用串(如 @src/index.ts 或 @"a b.ts")
|
|
7243
|
-
*/
|
|
7244
|
-
function mentionOf(path, cwd) {
|
|
7245
|
-
const raw = String(path);
|
|
7246
|
-
let rel = raw;
|
|
7247
|
-
if (cwd) {
|
|
7248
|
-
const base = String(cwd).replace(/[\\/]+$/, "");
|
|
7249
|
-
const up = raw.replace(/\\/g, "/");
|
|
7250
|
-
const baseUp = base.replace(/\\/g, "/");
|
|
7251
|
-
if (up.startsWith(baseUp + "/")) rel = up.slice(baseUp.length + 1);
|
|
7252
|
-
else if (up === baseUp) rel = "";
|
|
7253
|
-
}
|
|
7254
|
-
rel = rel.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
7255
|
-
if (!rel) rel = raw.replace(/\\/g, "/");
|
|
7256
|
-
if (/[\u0000-\u001f\u007f-\u009f"]/u.test(rel)) return "@" + raw;
|
|
7257
|
-
return /\s/u.test(rel) ? `@"${rel}"` : `@${rel}`;
|
|
7258
|
-
}
|
|
7259
|
-
/** 引用标签:文件名 + 可选行区间(chip 内展示,不带 @ 前缀)。
|
|
7260
|
-
* @author ddj 2026年08月25号 */
|
|
7261
|
-
function labelOf(path, range) {
|
|
7262
|
-
const base = String(path).split(/[\\/]/).pop() || String(path);
|
|
7263
|
-
if (!range || range.endLine < range.startLine) return base;
|
|
7264
|
-
return range.startLine === range.endLine ? `${base} L${range.startLine}` : `${base} L${range.startLine}-${range.endLine}`;
|
|
7265
|
-
}
|
|
7266
|
-
/** 引用 ref:引用串 + 可选行区间(序列化直出,agent 据此读取对应片段)。
|
|
7267
|
-
* @author ddj 2026年08月25号 */
|
|
7268
|
-
function refOf(mention, range) {
|
|
7269
|
-
if (!range || range.endLine < range.startLine) return mention;
|
|
7270
|
-
return range.startLine === range.endLine ? `${mention} L${range.startLine}` : `${mention} L${range.startLine}-${range.endLine}`;
|
|
7271
|
-
}
|
|
7272
|
-
/** 构造 DSH 文件引用插入载荷(source=reference,发送序列化为 mention(+range) 文本)。 */
|
|
7273
|
-
function buildFileRef(path, cwd, range) {
|
|
7274
|
-
const mention = mentionOf(path, cwd);
|
|
7275
|
-
return {
|
|
7276
|
-
mention,
|
|
7277
|
-
reference: {
|
|
7278
|
-
source: REF_SOURCE,
|
|
7279
|
-
ref: refOf(mention, range),
|
|
7280
|
-
label: labelOf(path, range),
|
|
7281
|
-
appearance: "file",
|
|
7282
|
-
clipboardText: mention
|
|
7283
|
-
}
|
|
7284
|
-
};
|
|
7285
|
-
}
|
|
7286
|
-
/**
|
|
7287
|
-
* 解析会话输入门面;缺失时返回 undefined(动作侧守卫降级)。
|
|
7288
|
-
* @author ddj 2026年08月25号
|
|
7289
|
-
* @param ctx 客户端服务上下文
|
|
7290
|
-
* @param sessionId 会话 id
|
|
7291
|
-
* @returns SessionInput 或 undefined
|
|
7292
|
-
*/
|
|
7293
|
-
function inputFor(ctx, sessionId) {
|
|
7294
|
-
if (!sessionId) return void 0;
|
|
7295
|
-
try {
|
|
7296
|
-
const sessions = ctx.get("sessions");
|
|
7297
|
-
const conversation = ctx.get("conversation");
|
|
7298
|
-
const actx = sessions?.scope?.(sessionId);
|
|
7299
|
-
const shell = actx && conversation?.input?.for?.(actx);
|
|
7300
|
-
return shell && typeof shell.setDraft === "function" ? shell : void 0;
|
|
7301
|
-
} catch {
|
|
7302
|
-
return;
|
|
7303
|
-
}
|
|
7304
|
-
}
|
|
7305
|
-
/** 取当前草稿长度与版本;无输入门面时返回 null。
|
|
7306
|
-
* @author ddj 2026年08月25号 */
|
|
7307
|
-
function draftCursor(input) {
|
|
7308
|
-
try {
|
|
7309
|
-
const s = input?.state?.getSnapshot?.();
|
|
7310
|
-
if (!s) return null;
|
|
7311
|
-
return {
|
|
7312
|
-
draft: String(s.draft ?? ""),
|
|
7313
|
-
draftRev: Number(s.draftRev ?? 0)
|
|
7314
|
-
};
|
|
7315
|
-
} catch {
|
|
7316
|
-
return null;
|
|
7317
|
-
}
|
|
7318
|
-
}
|
|
7319
|
-
/** 从 sessions 列表快照读会话工作区目录(与 index.ts 既有读取方式一致)。
|
|
7320
|
-
* @author ddj 2026年08月25号 */
|
|
7321
|
-
function cwdOf(ctx, sessionId) {
|
|
7322
|
-
if (!sessionId) return void 0;
|
|
7323
|
-
try {
|
|
7324
|
-
return ctx.get("sessions")?.list?.getSnapshot?.()?.byId?.[sessionId]?.cwd;
|
|
7325
|
-
} catch {
|
|
7326
|
-
return;
|
|
7327
|
-
}
|
|
7328
|
-
}
|
|
7329
|
-
/** 写入成功后的 composer 内联提示(门面可用时;失败静默)。
|
|
7330
|
-
* @author ddj 2026年08月25号 */
|
|
7331
|
-
function notify(input, text) {
|
|
7332
|
-
try {
|
|
7333
|
-
input.notify?.("info", text);
|
|
7334
|
-
} catch {}
|
|
7335
|
-
}
|
|
7336
|
-
/** 输入门面插入引用(拦截异常视作未应用,走降级)。
|
|
7337
|
-
* @author ddj 2026年08月25号 */
|
|
7338
|
-
function safeInsert(input, reference, span) {
|
|
7339
|
-
try {
|
|
7340
|
-
return input.insertReference(reference, span) === true;
|
|
7341
|
-
} catch {
|
|
7342
|
-
return false;
|
|
7343
|
-
}
|
|
7344
|
-
}
|
|
7345
|
-
/**
|
|
7346
|
-
* 创建「添加到对话」动作集(apply 阶段构建一次,随 props 传给 EditorView)。
|
|
7347
|
-
* @author ddj 2026年08月25号
|
|
7348
|
-
* @param ctx 客户端服务上下文(sessions + conversation)
|
|
7349
|
-
* @returns 动作集
|
|
7350
|
-
*/
|
|
7351
|
-
function createAddToConversation(ctx) {
|
|
7352
|
-
const appendReference = async (sessionId, path, range) => {
|
|
7353
|
-
const input = inputFor(ctx, sessionId);
|
|
7354
|
-
if (!input) return "unavailable";
|
|
7355
|
-
const cur = draftCursor(input);
|
|
7356
|
-
if (!cur) return "unavailable";
|
|
7357
|
-
const { reference, mention } = buildFileRef(path, cwdOf(ctx, sessionId), range);
|
|
7358
|
-
if (!safeInsert(input, reference, {
|
|
7359
|
-
start: cur.draft.length,
|
|
7360
|
-
end: cur.draft.length,
|
|
7361
|
-
draftRev: cur.draftRev
|
|
7362
|
-
})) {
|
|
7363
|
-
const gap = cur.draft.length > 0 && !/\s$/.test(cur.draft) ? " " : "";
|
|
7364
|
-
input.setDraft(cur.draft + gap + mention + " ");
|
|
7365
|
-
notify(input, "已添加文件引用 " + mention);
|
|
7366
|
-
return "busy";
|
|
7367
|
-
}
|
|
7368
|
-
notify(input, "已添加文件引用 " + mention);
|
|
7369
|
-
return "ok";
|
|
7370
|
-
};
|
|
7371
|
-
return { appendReference };
|
|
7372
|
-
}
|
|
7373
|
-
//#endregion
|
|
7374
7507
|
//#region src/client/sidebar/registry.ts
|
|
7375
7508
|
/** 校验面板定义并写入注册表(缺 id/render 抛 TypeError)。 */
|
|
7376
7509
|
function panelRegister(entries, notify, panel) {
|
|
@@ -7428,24 +7561,6 @@ window.__ModuleLoader__.load({
|
|
|
7428
7561
|
top: Math.max(4, Math.min(y, maxTop))
|
|
7429
7562
|
};
|
|
7430
7563
|
}
|
|
7431
|
-
/**
|
|
7432
|
-
* 将文件树行右键菜单锚定到目标行右侧;无法测量时回退到鼠标坐标。
|
|
7433
|
-
* @author ddj 2026年08月28号
|
|
7434
|
-
* @param rect 目标行的布局矩形
|
|
7435
|
-
* @param fallbackX 鼠标 viewport x 坐标
|
|
7436
|
-
* @param fallbackY 鼠标 viewport y 坐标
|
|
7437
|
-
* @returns 菜单初始位置
|
|
7438
|
-
*/
|
|
7439
|
-
function rowMenuPosition(rect, fallbackX, fallbackY) {
|
|
7440
|
-
if (!rect || rect.width <= 0 || rect.height <= 0) return {
|
|
7441
|
-
left: fallbackX,
|
|
7442
|
-
top: fallbackY
|
|
7443
|
-
};
|
|
7444
|
-
return {
|
|
7445
|
-
left: rect.right + 4,
|
|
7446
|
-
top: rect.top
|
|
7447
|
-
};
|
|
7448
|
-
}
|
|
7449
7564
|
//#endregion
|
|
7450
7565
|
//#region src/client/ui/ContextMenu.ts
|
|
7451
7566
|
/**
|
|
@@ -8039,11 +8154,9 @@ window.__ModuleLoader__.load({
|
|
|
8039
8154
|
onContextMenu: (ev) => {
|
|
8040
8155
|
ev.preventDefault();
|
|
8041
8156
|
ev.stopPropagation();
|
|
8042
|
-
const rect = ev.currentTarget?.getBoundingClientRect?.();
|
|
8043
|
-
const position = rowMenuPosition(rect, ev.clientX, ev.clientY);
|
|
8044
8157
|
setMenu({
|
|
8045
|
-
x:
|
|
8046
|
-
y:
|
|
8158
|
+
x: ev.clientX,
|
|
8159
|
+
y: ev.clientY,
|
|
8047
8160
|
target: {
|
|
8048
8161
|
path: e.path,
|
|
8049
8162
|
type: e.type
|
|
@@ -8458,10 +8571,384 @@ window.__ModuleLoader__.load({
|
|
|
8458
8571
|
})), optsBar, filterRows, summary, warnBanner, body);
|
|
8459
8572
|
}
|
|
8460
8573
|
//#endregion
|
|
8574
|
+
//#region src/client/sidebar/panels/RulesPanel.ts
|
|
8575
|
+
/**
|
|
8576
|
+
* dsh-vscode-mode client — 侧边栏「规则」面板(Codebuddy 规则管理形态)。
|
|
8577
|
+
* 双 Tab:用户规则(~/.dsh/rules/)与项目规则(<工作区>/.dsh/rules/);
|
|
8578
|
+
* 列表行 = 文件名 + 相对提示 + 类型徽标(总是/自动/手动)+ 描述 + 编辑/删除/启用开关;
|
|
8579
|
+
* 新建/编辑 = 内嵌表单(文件名 + 原始 .mdc 文本域,frontmatter 可见),保存走 rules.save。
|
|
8580
|
+
* 作者 ddj 2026年09月03号
|
|
8581
|
+
*/
|
|
8582
|
+
/** 新建规则模板(frontmatter 字段与 host parseRuleMdc 对齐)。 */
|
|
8583
|
+
const NEW_TEMPLATE = "---\ndescription: \nalwaysApply: true\n---\n\n";
|
|
8584
|
+
const TYPE_LABEL = {
|
|
8585
|
+
always: "总是",
|
|
8586
|
+
auto: "自动",
|
|
8587
|
+
manual: "手动"
|
|
8588
|
+
};
|
|
8589
|
+
/**
|
|
8590
|
+
* 读 localStorage(损坏/不可用安全)。
|
|
8591
|
+
* @author ddj 2026年09月03号
|
|
8592
|
+
* @param key 键
|
|
8593
|
+
* @returns 值或 null
|
|
8594
|
+
*/
|
|
8595
|
+
function readLocal(key) {
|
|
8596
|
+
try {
|
|
8597
|
+
return localStorage.getItem(key);
|
|
8598
|
+
} catch (e) {
|
|
8599
|
+
return null;
|
|
8600
|
+
}
|
|
8601
|
+
}
|
|
8602
|
+
/**
|
|
8603
|
+
* 写 localStorage(不可用安全)。
|
|
8604
|
+
* @author ddj 2026年09月03号
|
|
8605
|
+
* @param key 键
|
|
8606
|
+
* @param value 值
|
|
8607
|
+
*/
|
|
8608
|
+
function writeLocal(key, value) {
|
|
8609
|
+
try {
|
|
8610
|
+
localStorage.setItem(key, value);
|
|
8611
|
+
} catch (e) {}
|
|
8612
|
+
}
|
|
8613
|
+
/**
|
|
8614
|
+
* 类型徽标(总是=绿 / 自动=蓝 / 手动=灰)。
|
|
8615
|
+
* @author ddj 2026年09月03号
|
|
8616
|
+
* @param type 规则类型
|
|
8617
|
+
* @returns 徽标元素
|
|
8618
|
+
*/
|
|
8619
|
+
function typeBadge(type) {
|
|
8620
|
+
return react.default.createElement("span", { className: "edrv-rules-type edrv-rules-type-" + type }, TYPE_LABEL[type] ?? type);
|
|
8621
|
+
}
|
|
8622
|
+
/**
|
|
8623
|
+
* 渲染一条规则行:文件名 + 相对提示 + 类型徽标,第二行描述;右侧编辑/删除/开关。
|
|
8624
|
+
* @author ddj 2026年09月03号
|
|
8625
|
+
* @param props.rule 规则元信息
|
|
8626
|
+
* @param props.onEdit 编辑回调
|
|
8627
|
+
* @param props.onRemove 删除回调
|
|
8628
|
+
* @param props.onToggle 开关回调
|
|
8629
|
+
* @returns 行元素
|
|
8630
|
+
*/
|
|
8631
|
+
function RuleRow(props) {
|
|
8632
|
+
const rule = props.rule;
|
|
8633
|
+
const desc = [rule.error ? "解析失败:" + rule.error : null, rule.description || (rule.type === "auto" ? "globs: " + rule.globs.join(", ") : "")].filter(Boolean).join(" · ");
|
|
8634
|
+
return react.default.createElement("div", { className: "edrv-rules-row" + (rule.enabled ? "" : " off") }, react.default.createElement("div", {
|
|
8635
|
+
className: "edrv-rules-main",
|
|
8636
|
+
onClick: () => props.onEdit(rule),
|
|
8637
|
+
title: rule.absPath
|
|
8638
|
+
}, react.default.createElement("span", { className: "edrv-rules-file" }, rule.file), react.default.createElement("span", { className: "edrv-rules-path" }, "[" + rule.relHint + rule.file + "]"), typeBadge(rule.type), !rule.enabled ? react.default.createElement("span", { className: "edrv-rules-offtag" }, "已停用") : null), react.default.createElement("div", {
|
|
8639
|
+
className: "edrv-rules-desc",
|
|
8640
|
+
title: desc
|
|
8641
|
+
}, desc ? "描述: " + desc : "描述: —"), react.default.createElement("div", { className: "edrv-rules-actions" }, react.default.createElement("button", {
|
|
8642
|
+
className: "edrv-rules-act",
|
|
8643
|
+
title: "编辑",
|
|
8644
|
+
onClick: () => props.onEdit(rule)
|
|
8645
|
+
}, "✏️"), react.default.createElement("button", {
|
|
8646
|
+
className: "edrv-rules-act",
|
|
8647
|
+
title: "删除",
|
|
8648
|
+
onClick: () => props.onRemove(rule)
|
|
8649
|
+
}, "🗑"), react.default.createElement("button", {
|
|
8650
|
+
className: "edrv-rules-switch" + (rule.enabled ? " on" : ""),
|
|
8651
|
+
role: "switch",
|
|
8652
|
+
"aria-checked": rule.enabled,
|
|
8653
|
+
title: rule.enabled ? "已启用(点击停用)" : "已停用(点击启用)",
|
|
8654
|
+
onClick: () => props.onToggle(rule)
|
|
8655
|
+
}, react.default.createElement("span", { className: "edrv-rules-knob" }))));
|
|
8656
|
+
}
|
|
8657
|
+
/**
|
|
8658
|
+
* 新建/编辑表单:文件名(仅新建可改)+ 原始 .mdc 文本域 + 保存/取消。
|
|
8659
|
+
* @author ddj 2026年09月03号
|
|
8660
|
+
* @param props.form 表单状态(mode/scope/workspacePath/file/content/error/saving)
|
|
8661
|
+
* @param props.setForm 表单更新函数
|
|
8662
|
+
* @param props.onSave 保存回调
|
|
8663
|
+
* @param props.onCancel 取消回调
|
|
8664
|
+
* @returns 表单元素
|
|
8665
|
+
*/
|
|
8666
|
+
function RuleEditor(props) {
|
|
8667
|
+
const form = props.form;
|
|
8668
|
+
const isNew = form.mode === "new";
|
|
8669
|
+
return react.default.createElement("div", { className: "edrv-rules-editor" }, react.default.createElement("div", { className: "edrv-rules-editor-head" }, isNew ? "新建" + (form.scope === "project" ? "项目" : "用户") + "规则" : "编辑:" + form.file, react.default.createElement("button", {
|
|
8670
|
+
className: "edrv-rules-act",
|
|
8671
|
+
title: "取消",
|
|
8672
|
+
onClick: props.onCancel
|
|
8673
|
+
}, "✕")), react.default.createElement("div", { className: "edrv-rules-editor-file" }, react.default.createElement("label", null, "文件名"), react.default.createElement("input", {
|
|
8674
|
+
className: "edrv-rules-input",
|
|
8675
|
+
value: form.file,
|
|
8676
|
+
disabled: !isNew,
|
|
8677
|
+
spellCheck: false,
|
|
8678
|
+
placeholder: "my-rule.mdc",
|
|
8679
|
+
onChange: (e) => props.setForm({
|
|
8680
|
+
...form,
|
|
8681
|
+
file: e.target.value
|
|
8682
|
+
})
|
|
8683
|
+
})), react.default.createElement("textarea", {
|
|
8684
|
+
className: "edrv-rules-body",
|
|
8685
|
+
spellCheck: false,
|
|
8686
|
+
value: form.content,
|
|
8687
|
+
onChange: (e) => props.setForm({
|
|
8688
|
+
...form,
|
|
8689
|
+
content: e.target.value
|
|
8690
|
+
})
|
|
8691
|
+
}), react.default.createElement("div", { className: "edrv-rules-editor-hint" }, "frontmatter 支持 description / alwaysApply / globs / enabled;无 frontmatter 的纯 markdown 视为「手动」规则"), form.error ? react.default.createElement("div", { className: "edrv-rules-err" }, form.error) : null, react.default.createElement("div", { className: "edrv-rules-editor-foot" }, react.default.createElement("button", {
|
|
8692
|
+
className: "edrv-rules-save",
|
|
8693
|
+
disabled: form.saving,
|
|
8694
|
+
onClick: props.onSave
|
|
8695
|
+
}, form.saving ? "保存中…" : "保存")));
|
|
8696
|
+
}
|
|
8697
|
+
/**
|
|
8698
|
+
* 规则面板主体。
|
|
8699
|
+
* @param props.ctx 面板共享上下文(notify 可选)
|
|
8700
|
+
*/
|
|
8701
|
+
function RulesPanel(props) {
|
|
8702
|
+
const ctx = props?.ctx;
|
|
8703
|
+
const notify = ctx?.notify ?? ((message) => {});
|
|
8704
|
+
const cwd = ctx?.cwd ?? null;
|
|
8705
|
+
const [tab, setTab] = react.default.useState(() => readLocal(CACHE_KEY.rules + "tab") === "project" ? "project" : "user");
|
|
8706
|
+
const [data, setData] = react.default.useState(null);
|
|
8707
|
+
const [error, setError] = react.default.useState("");
|
|
8708
|
+
const [form, setForm] = react.default.useState(null);
|
|
8709
|
+
const mountedRef = react.default.useRef(true);
|
|
8710
|
+
/**
|
|
8711
|
+
* 当前工作区对应的项目聚合(按 ctx.cwd 自动匹配;无会话/未注册返回 null)。
|
|
8712
|
+
* @returns RuleProject 或 null
|
|
8713
|
+
*/
|
|
8714
|
+
const activeProject = () => {
|
|
8715
|
+
if (!cwd) return null;
|
|
8716
|
+
return (data?.projects ?? []).find((p) => p.workspacePath === cwd) ?? null;
|
|
8717
|
+
};
|
|
8718
|
+
/** 拉取规则总列表(rules.list)。 */
|
|
8719
|
+
const load = () => {
|
|
8720
|
+
rpc("rules.list", {}).then((res) => {
|
|
8721
|
+
if (!mountedRef.current) return;
|
|
8722
|
+
if (res && res.ok) {
|
|
8723
|
+
setData(res);
|
|
8724
|
+
setError("");
|
|
8725
|
+
} else setError(res?.error ?? "读取规则失败");
|
|
8726
|
+
}).catch((e) => {
|
|
8727
|
+
if (mountedRef.current) setError("读取规则异常: " + String(e));
|
|
8728
|
+
});
|
|
8729
|
+
};
|
|
8730
|
+
react.default.useEffect(() => {
|
|
8731
|
+
mountedRef.current = true;
|
|
8732
|
+
load();
|
|
8733
|
+
return () => {
|
|
8734
|
+
mountedRef.current = false;
|
|
8735
|
+
};
|
|
8736
|
+
}, []);
|
|
8737
|
+
/**
|
|
8738
|
+
* 切换 Tab(记忆到 localStorage)。
|
|
8739
|
+
* @param next 目标 Tab
|
|
8740
|
+
*/
|
|
8741
|
+
const switchTab = (next) => {
|
|
8742
|
+
setTab(next);
|
|
8743
|
+
writeLocal(CACHE_KEY.rules + "tab", next);
|
|
8744
|
+
};
|
|
8745
|
+
/**
|
|
8746
|
+
* 打开新建表单(按当前 Tab 决定作用域;项目规则跟随当前会话工作区)。
|
|
8747
|
+
*/
|
|
8748
|
+
const openNew = () => {
|
|
8749
|
+
const scope = tab === "project" ? "project" : "user";
|
|
8750
|
+
if (scope === "project" && !cwd) {
|
|
8751
|
+
notify("当前会话没有工作区,无法新建项目规则");
|
|
8752
|
+
return;
|
|
8753
|
+
}
|
|
8754
|
+
setForm({
|
|
8755
|
+
mode: "new",
|
|
8756
|
+
scope,
|
|
8757
|
+
workspacePath: scope === "project" ? cwd : void 0,
|
|
8758
|
+
file: "",
|
|
8759
|
+
content: NEW_TEMPLATE,
|
|
8760
|
+
error: "",
|
|
8761
|
+
saving: false
|
|
8762
|
+
});
|
|
8763
|
+
};
|
|
8764
|
+
/**
|
|
8765
|
+
* 打开编辑表单:先拉全文再进入编辑态。
|
|
8766
|
+
* @param rule 目标规则
|
|
8767
|
+
*/
|
|
8768
|
+
const openEdit = (rule) => {
|
|
8769
|
+
rpc("rules.read", {
|
|
8770
|
+
scope: rule.scope,
|
|
8771
|
+
workspacePath: rule.scope === "project" ? rule.workspacePath : void 0,
|
|
8772
|
+
file: rule.file
|
|
8773
|
+
}).then((res) => {
|
|
8774
|
+
if (res && res.ok) setForm({
|
|
8775
|
+
mode: "edit",
|
|
8776
|
+
scope: rule.scope,
|
|
8777
|
+
workspacePath: rule.workspacePath,
|
|
8778
|
+
file: rule.file,
|
|
8779
|
+
content: res.content,
|
|
8780
|
+
error: "",
|
|
8781
|
+
saving: false
|
|
8782
|
+
});
|
|
8783
|
+
else notify(res?.error ?? "读取规则失败");
|
|
8784
|
+
}).catch((e) => notify("读取规则异常: " + String(e)));
|
|
8785
|
+
};
|
|
8786
|
+
/** 保存表单(rules.save;文件名仅新建校验非空)。 */
|
|
8787
|
+
const saveForm = () => {
|
|
8788
|
+
const next = {
|
|
8789
|
+
...form,
|
|
8790
|
+
saving: true,
|
|
8791
|
+
error: ""
|
|
8792
|
+
};
|
|
8793
|
+
const file = String(form.file ?? "").trim();
|
|
8794
|
+
if (!file) {
|
|
8795
|
+
setForm({
|
|
8796
|
+
...next,
|
|
8797
|
+
saving: false,
|
|
8798
|
+
error: "文件名不能为空"
|
|
8799
|
+
});
|
|
8800
|
+
return;
|
|
8801
|
+
}
|
|
8802
|
+
setForm(next);
|
|
8803
|
+
rpc("rules.save", {
|
|
8804
|
+
scope: form.scope,
|
|
8805
|
+
workspacePath: form.workspacePath,
|
|
8806
|
+
file,
|
|
8807
|
+
content: form.content
|
|
8808
|
+
}).then((res) => {
|
|
8809
|
+
if (res && res.ok) {
|
|
8810
|
+
setForm(null);
|
|
8811
|
+
notify("规则已保存:" + file);
|
|
8812
|
+
load();
|
|
8813
|
+
} else setForm((prev) => ({
|
|
8814
|
+
...prev,
|
|
8815
|
+
saving: false,
|
|
8816
|
+
error: res?.error ?? "保存失败"
|
|
8817
|
+
}));
|
|
8818
|
+
}).catch((e) => setForm((prev) => ({
|
|
8819
|
+
...prev,
|
|
8820
|
+
saving: false,
|
|
8821
|
+
error: "保存异常: " + String(e)
|
|
8822
|
+
})));
|
|
8823
|
+
};
|
|
8824
|
+
/**
|
|
8825
|
+
* 删除规则(confirm 后走 rules.remove)。
|
|
8826
|
+
* @param rule 目标规则
|
|
8827
|
+
*/
|
|
8828
|
+
const removeRule = (rule) => {
|
|
8829
|
+
if (!window.confirm("删除规则 " + rule.file + "?(不可恢复)")) return;
|
|
8830
|
+
rpc("rules.remove", {
|
|
8831
|
+
scope: rule.scope,
|
|
8832
|
+
workspacePath: rule.workspacePath,
|
|
8833
|
+
file: rule.file
|
|
8834
|
+
}).then((res) => {
|
|
8835
|
+
if (res && res.ok) {
|
|
8836
|
+
notify("已删除:" + rule.file);
|
|
8837
|
+
load();
|
|
8838
|
+
} else notify(res?.error ?? "删除失败");
|
|
8839
|
+
}).catch((e) => notify("删除异常: " + String(e)));
|
|
8840
|
+
};
|
|
8841
|
+
/**
|
|
8842
|
+
* 切换启用开关:本地乐观翻转(按 workspacePath+file 定位,失败回滚)。
|
|
8843
|
+
* @param rule 目标规则(project 已注入 workspacePath)
|
|
8844
|
+
*/
|
|
8845
|
+
const toggleRule = (rule) => {
|
|
8846
|
+
const enabled = !rule.enabled;
|
|
8847
|
+
const applyLocal = (on) => setData((prev) => prev ? {
|
|
8848
|
+
...prev,
|
|
8849
|
+
user: prev.user.map((r) => r.scope === "user" && r.file === rule.file ? {
|
|
8850
|
+
...r,
|
|
8851
|
+
enabled: on
|
|
8852
|
+
} : r),
|
|
8853
|
+
projects: prev.projects.map((p) => p.workspacePath === rule.workspacePath ? {
|
|
8854
|
+
...p,
|
|
8855
|
+
rules: p.rules.map((r) => r.file === rule.file ? {
|
|
8856
|
+
...r,
|
|
8857
|
+
enabled: on
|
|
8858
|
+
} : r)
|
|
8859
|
+
} : p)
|
|
8860
|
+
} : prev);
|
|
8861
|
+
applyLocal(enabled);
|
|
8862
|
+
rpc("rules.toggle", {
|
|
8863
|
+
scope: rule.scope,
|
|
8864
|
+
workspacePath: rule.workspacePath,
|
|
8865
|
+
file: rule.file,
|
|
8866
|
+
enabled
|
|
8867
|
+
}).then((res) => {
|
|
8868
|
+
if (res && res.ok) {
|
|
8869
|
+
applyLocal(res.rule?.enabled === true);
|
|
8870
|
+
notify(res.rule?.enabled === false ? "已停用:" + rule.file : "已启用:" + rule.file);
|
|
8871
|
+
} else {
|
|
8872
|
+
applyLocal(!enabled);
|
|
8873
|
+
notify(res?.error ?? "切换失败");
|
|
8874
|
+
}
|
|
8875
|
+
}).catch((e) => {
|
|
8876
|
+
applyLocal(!enabled);
|
|
8877
|
+
notify("切换异常: " + String(e));
|
|
8878
|
+
});
|
|
8879
|
+
};
|
|
8880
|
+
/** 当前列表数据(按 Tab 取用户规则或当前工作区的项目规则)。 */
|
|
8881
|
+
const rowsOf = () => {
|
|
8882
|
+
if (!data) return [];
|
|
8883
|
+
if (tab === "user") return data.user;
|
|
8884
|
+
return activeProject()?.rules ?? [];
|
|
8885
|
+
};
|
|
8886
|
+
const renderTabs = () => react.default.createElement("div", { className: "edrv-rules-tabs" }, react.default.createElement("button", {
|
|
8887
|
+
className: "edrv-rules-tab" + (tab === "user" ? " on" : ""),
|
|
8888
|
+
onClick: () => switchTab("user")
|
|
8889
|
+
}, "用户规则"), react.default.createElement("button", {
|
|
8890
|
+
className: "edrv-rules-tab" + (tab === "project" ? " on" : ""),
|
|
8891
|
+
onClick: () => switchTab("project")
|
|
8892
|
+
}, "项目规则"), react.default.createElement("button", {
|
|
8893
|
+
className: "edrv-rules-new",
|
|
8894
|
+
title: "新建规则",
|
|
8895
|
+
onClick: openNew
|
|
8896
|
+
}, "+ 新建规则"));
|
|
8897
|
+
/** 项目 Tab 的工作区展示(不可编辑,自动跟随当前会话)。 */
|
|
8898
|
+
const renderWsLine = () => {
|
|
8899
|
+
if (tab !== "project") return null;
|
|
8900
|
+
return react.default.createElement("div", {
|
|
8901
|
+
className: "edrv-rules-ws-line",
|
|
8902
|
+
title: cwd ?? ""
|
|
8903
|
+
}, "工作区:" + (cwd ?? "当前会话未打开工作区"));
|
|
8904
|
+
};
|
|
8905
|
+
const renderEmpty = () => {
|
|
8906
|
+
if (tab === "project") {
|
|
8907
|
+
if (!cwd) return "当前会话没有工作区,项目规则不可用(项目规则跟随会话所在工作区)";
|
|
8908
|
+
if (!data?.projects?.length) return "当前 DSH 没有已注册的工作区;在目标工作区打开一次会话后再来管理";
|
|
8909
|
+
if (!activeProject()) return "当前工作区未注册为 DSH workspace,暂不能管理其项目规则";
|
|
8910
|
+
return "<工作区>/.dsh/rules/ 还没有规则,点击「+ 新建规则」创建";
|
|
8911
|
+
}
|
|
8912
|
+
return "还没有用户规则(~/.dsh/rules/),点击「+ 新建规则」创建";
|
|
8913
|
+
};
|
|
8914
|
+
const renderBody = () => {
|
|
8915
|
+
if (form) return react.default.createElement(RuleEditor, {
|
|
8916
|
+
form,
|
|
8917
|
+
setForm,
|
|
8918
|
+
onSave: saveForm,
|
|
8919
|
+
onCancel: () => setForm(null)
|
|
8920
|
+
});
|
|
8921
|
+
if (!data) return react.default.createElement("div", { className: "edrv-rules-empty" }, "加载中…");
|
|
8922
|
+
if (error) return react.default.createElement("div", { className: "edrv-rules-err" }, error);
|
|
8923
|
+
const rows = rowsOf();
|
|
8924
|
+
if (!rows.length) return react.default.createElement("div", { className: "edrv-rules-empty" }, renderEmpty());
|
|
8925
|
+
const common = {
|
|
8926
|
+
onEdit: (rule) => openEdit({
|
|
8927
|
+
...rule,
|
|
8928
|
+
workspacePath: rule.scope === "project" ? cwd : void 0
|
|
8929
|
+
}),
|
|
8930
|
+
onRemove: (rule) => removeRule({
|
|
8931
|
+
...rule,
|
|
8932
|
+
workspacePath: rule.scope === "project" ? cwd : void 0
|
|
8933
|
+
}),
|
|
8934
|
+
onToggle: (rule) => toggleRule({
|
|
8935
|
+
...rule,
|
|
8936
|
+
workspacePath: rule.scope === "project" ? cwd : void 0
|
|
8937
|
+
})
|
|
8938
|
+
};
|
|
8939
|
+
return react.default.createElement("div", { className: "edrv-rules-list" }, rows.map((rule) => react.default.createElement(RuleRow, {
|
|
8940
|
+
key: rule.scope + ":" + rule.file,
|
|
8941
|
+
rule,
|
|
8942
|
+
...common
|
|
8943
|
+
})));
|
|
8944
|
+
};
|
|
8945
|
+
return react.default.createElement("div", { className: "edrv-rules-panel" }, renderTabs(), renderWsLine(), react.default.createElement("div", { className: "edrv-rules-hint" }, tab === "user" ? "用户规则对所有会话生效(存放于 ~/.dsh/rules/)" : "项目规则仅对所在工作区的会话生效(存放于 <工作区>/.dsh/rules/)"), renderBody());
|
|
8946
|
+
}
|
|
8947
|
+
//#endregion
|
|
8461
8948
|
//#region src/client/sidebar/panels/index.ts
|
|
8462
8949
|
/**
|
|
8463
|
-
* dsh-vscode-mode client — 侧边栏面板定义(文件管理 +
|
|
8464
|
-
* 作者 ddj 2026-08-26 / 2026-
|
|
8950
|
+
* dsh-vscode-mode client — 侧边栏面板定义(文件管理 + 搜索 + 规则)。
|
|
8951
|
+
* 作者 ddj 2026-08-26 / 2026-09-03
|
|
8465
8952
|
*/
|
|
8466
8953
|
/**
|
|
8467
8954
|
* 构造文件管理面板定义。
|
|
@@ -8492,13 +8979,28 @@ window.__ModuleLoader__.load({
|
|
|
8492
8979
|
render: (ctx) => react.default.createElement(SearchPanel, { ctx })
|
|
8493
8980
|
};
|
|
8494
8981
|
}
|
|
8982
|
+
/**
|
|
8983
|
+
* 构造规则管理面板定义(Codebuddy 规则形态:用户规则/项目规则双 Tab + 开关)。
|
|
8984
|
+
* @author ddj 2026年09月03号
|
|
8985
|
+
* @returns 面板定义(无徽标;活动栏图标 📏,与大纲 📜 区分)
|
|
8986
|
+
*/
|
|
8987
|
+
function createRulesPanel() {
|
|
8988
|
+
return {
|
|
8989
|
+
id: "rules",
|
|
8990
|
+
title: "规则",
|
|
8991
|
+
icon: "📏",
|
|
8992
|
+
order: 20,
|
|
8993
|
+
render: (ctx) => react.default.createElement(RulesPanel, { ctx })
|
|
8994
|
+
};
|
|
8995
|
+
}
|
|
8495
8996
|
//#endregion
|
|
8496
8997
|
//#region src/client/sidebar/menuItems.ts
|
|
8497
8998
|
/**
|
|
8498
8999
|
* dsh-vscode-mode client — 文件管理右键菜单内置项。
|
|
8499
|
-
*
|
|
9000
|
+
* 内置项:「在文件浏览器中打开」(文件→OS Explorer 定位选中、目录→打开目录);
|
|
9001
|
+
* 「添加引用到对话」(文件/文件夹引用注入当前会话对话输入框)。
|
|
8500
9002
|
* 反馈统一走 ctx.notify(由 EditorView 提供,落到编辑区路径栏状态)。
|
|
8501
|
-
* 作者 ddj 2026-08-27
|
|
9003
|
+
* 作者 ddj 2026-08-27 / 2026-09-03
|
|
8502
9004
|
*/
|
|
8503
9005
|
/**
|
|
8504
9006
|
* 构造内置右键菜单项列表(后续内置项直接追加)。
|
|
@@ -8515,6 +9017,23 @@ window.__ModuleLoader__.load({
|
|
|
8515
9017
|
ctx.notify?.(outcome.ok ? "已在文件浏览器中打开" : "打开失败:" + (outcome.error ?? "未知错误"));
|
|
8516
9018
|
});
|
|
8517
9019
|
}
|
|
9020
|
+
}, {
|
|
9021
|
+
id: "add-to-conversation",
|
|
9022
|
+
label: "添加引用到对话",
|
|
9023
|
+
order: 1,
|
|
9024
|
+
visible: (target, ctx) => Boolean(target.path && ctx.sessionId && ctx.addToConversation),
|
|
9025
|
+
run: (target, ctx) => {
|
|
9026
|
+
const isDir = target.type === "directory";
|
|
9027
|
+
const add = ctx.addToConversation;
|
|
9028
|
+
if (!add) {
|
|
9029
|
+
ctx.notify?.("添加到对话不可用");
|
|
9030
|
+
return;
|
|
9031
|
+
}
|
|
9032
|
+
const okText = isDir ? "已添加文件夹引用" : "已添加文件引用";
|
|
9033
|
+
add.appendReference(ctx.sessionId, target.path, void 0, isDir ? "folder" : "file").then((outcome) => {
|
|
9034
|
+
ctx.notify?.(statusOfAdd(outcome, okText));
|
|
9035
|
+
});
|
|
9036
|
+
}
|
|
8518
9037
|
}];
|
|
8519
9038
|
}
|
|
8520
9039
|
//#endregion
|
|
@@ -9408,6 +9927,7 @@ window.__ModuleLoader__.load({
|
|
|
9408
9927
|
ctx.provide("edrvSidebarPanels", sidebarPanels);
|
|
9409
9928
|
ctx.effect(() => sidebarPanels.register(createFilePanel()), "vscode-mode: sidebar panel");
|
|
9410
9929
|
ctx.effect(() => sidebarPanels.register(createSearchPanel()), "vscode-mode: sidebar panel search");
|
|
9930
|
+
ctx.effect(() => sidebarPanels.register(createRulesPanel()), "vscode-mode: sidebar panel rules");
|
|
9411
9931
|
const fileMenuItems = createTreeMenuRegistry();
|
|
9412
9932
|
ctx.provide("edrvFileContextMenuItems", fileMenuItems);
|
|
9413
9933
|
for (const item of createDefaultFileMenuItems()) ctx.effect(() => fileMenuItems.register(item), "vscode-mode: file context menu item " + item.id);
|
|
@@ -9443,6 +9963,8 @@ window.__ModuleLoader__.load({
|
|
|
9443
9963
|
const snapshot = settings.getSnapshot();
|
|
9444
9964
|
if (snapshot.status === "loading") return;
|
|
9445
9965
|
keybindingsApply(snapshot.value?.keybindings);
|
|
9966
|
+
const minW = sidebarMinApply(snapshot.value?.sidebarMinWidth);
|
|
9967
|
+
window.dispatchEvent(new CustomEvent("edrv:sidebar-min-width", { detail: { value: minW } }));
|
|
9446
9968
|
};
|
|
9447
9969
|
sync();
|
|
9448
9970
|
return settings.subscribe(sync);
|
|
@@ -9475,7 +9997,8 @@ window.__ModuleLoader__.load({
|
|
|
9475
9997
|
addToConversation,
|
|
9476
9998
|
sidebarPanels,
|
|
9477
9999
|
outlineSources,
|
|
9478
|
-
fileMenuItems
|
|
10000
|
+
fileMenuItems,
|
|
10001
|
+
sessions
|
|
9479
10002
|
})));
|
|
9480
10003
|
};
|
|
9481
10004
|
let sideDisposer = null;
|
|
@@ -9494,7 +10017,8 @@ window.__ModuleLoader__.load({
|
|
|
9494
10017
|
addToConversation,
|
|
9495
10018
|
sidebarPanels,
|
|
9496
10019
|
outlineSources,
|
|
9497
|
-
fileMenuItems
|
|
10020
|
+
fileMenuItems,
|
|
10021
|
+
sessions
|
|
9498
10022
|
})),
|
|
9499
10023
|
activeSession: () => {
|
|
9500
10024
|
const snapshot = sessions?.list?.getSnapshot?.();
|