dsh-vscode-mode 0.1.6 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -29,7 +29,7 @@ window.__ModuleLoader__.load({
29
29
  let react = require("react");
30
30
  react = __toESM(react, 1);
31
31
  //#region \0dsh-css:/home/runner/work/DSH_VsCodeMode/DSH_VsCodeMode/src/client/styles/editor.css.mjs
32
- const css = "/* dsh-vscode-mode 编辑区样式(原 ensureEdrvStyles 字符串,落盘为真 .css,由 tsdown CSS-inline 注入) */\n/* 浅色主题(对齐参考图:#f8f8f8 近白底 + 薄荷绿药丸 + 青绿文字 + 三文鱼 undo + 浅灰边框):\n 在 [data-edrv-view] 作用域内重定义 --dsw-alias-*,级联命中组件内联样式与 CSS。 */\n[data-edrv-view] { --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-path-input { flex: 1; min-width: 140px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search-wrap { position: relative; flex-shrink: 0; display: flex; align-items: center; padding: 2px 8px 2px 4px; }\n[data-edrv-view] .edrv-search { width: 190px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-pop { position: absolute; top: calc(100% + 4px); right: 8px; width: min(460px, calc(100vw - 24px)); max-height: 300px; overflow: auto; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 10px; box-shadow: 0 6px 20px rgba(0,0,0,.4); z-index: 60; padding: 4px; }\n[data-edrv-view] .edrv-search-item { display: flex; flex-direction: column; gap: 1px; padding: 5px 8px; border-radius: 6px; cursor: pointer; }\n[data-edrv-view] .edrv-search-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.07)); }\n[data-edrv-view] .edrv-search-item .n { color: var(--dsw-alias-label-primary, #eee); font-size: 12px; word-break: break-all; }\n[data-edrv-view] .edrv-search-item .d { color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-search-empty { padding: 8px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #888); }\n[data-edrv-view] .edrv-btn-mini { font-size: 11px; padding: 2px 9px; border: none; border-radius: 999px; cursor: pointer; color: #fff; font-weight: 600; white-space: nowrap; }\n[data-edrv-view] .edrv-btn-keep { background: var(--dsw-alias-state-success-primary, #2e9e44); }\n[data-edrv-view] .edrv-btn-undo { background: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-btn-mini:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-statusbar { display: flex; align-items: center; gap: 10px; padding: 3px 10px; border-top: 1px solid var(--dsw-alias-border-l1, #333); background: var(--dsw-alias-bg-layer-1, transparent); font-size: 11px; color: var(--dsw-alias-label-tertiary, #888); flex-shrink: 0; white-space: nowrap; overflow: hidden; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-path { flex: 1; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-diffchip { font-size: 11px; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #333); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-state-warn-primary, #b7791f); cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn { font-size: 12px; padding: 2px 6px; border: none; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; border-radius: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-mn-add-line { background: rgba(15,157,88,.10); }\n[data-edrv-view] .edrv-mn-gutter-add { color: #0f9d58 !important; font-weight: 700; display: flex !important; align-items: center; justify-content: center; }\n[data-edrv-view] .edrv-mn-gutter-add::before { content: \"+\"; }\n[data-edrv-view] .edrv-del-zone { background: #fdeaea; border-top: 1px solid rgba(217,83,79,.35); border-bottom: 1px solid rgba(217,83,79,.35); box-shadow: inset 0 0 0 1px rgba(217,83,79,.12); }\n[data-edrv-view] .edrv-del-row { white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 12.5px; line-height: 20px; color: #c0392b; }\n[data-edrv-view] .edrv-del-text { display: inline-block; white-space: pre; }\n[data-edrv-view] .edrv-minus-overlay { position: absolute; left: 0; top: 0; pointer-events: none; z-index: 6; }\n[data-edrv-view] .edrv-minus-item { position: absolute; width: 16px; text-align: center; color: #d9534f; font-weight: 700; font-size: 12.5px; line-height: 20px; }\n[data-edrv-view] .edrv-monaco-host { flex: 1; min-height: 0; position: relative; }\n[data-edrv-view] .edrv-monaco-host > div { position: absolute; inset: 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: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 4px 16px rgba(31,41,51,.12); overflow: visible; display: flex; flex-direction: column; }\n[data-edrv-view] .edrv-diffbar-row { display: flex; align-items: center; gap: 6px; height: 34px; padding: 0 8px; 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[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, [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";
32
+ const css = "/* dsh-vscode-mode 编辑区样式(原 ensureEdrvStyles 字符串,落盘为真 .css,由 tsdown CSS-inline 注入) */\n/* 浅色主题(对齐参考图:#f8f8f8 近白底 + 薄荷绿药丸 + 青绿文字 + 三文鱼 undo + 浅灰边框):\n 在 [data-edrv-view] 作用域内重定义 --dsw-alias-*,级联命中组件内联样式与 CSS。 */\n[data-edrv-view] { --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-path-input { flex: 1; min-width: 140px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search-wrap { position: relative; flex-shrink: 0; display: flex; align-items: center; padding: 2px 8px 2px 4px; }\n[data-edrv-view] .edrv-search { width: 190px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-pop { position: absolute; top: calc(100% + 4px); right: 8px; width: min(460px, calc(100vw - 24px)); max-height: 300px; overflow: auto; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 10px; box-shadow: 0 6px 20px rgba(0,0,0,.4); z-index: 60; padding: 4px; }\n[data-edrv-view] .edrv-search-item { display: flex; flex-direction: column; gap: 1px; padding: 5px 8px; border-radius: 6px; cursor: pointer; }\n[data-edrv-view] .edrv-search-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.07)); }\n[data-edrv-view] .edrv-search-item .n { color: var(--dsw-alias-label-primary, #eee); font-size: 12px; word-break: break-all; }\n[data-edrv-view] .edrv-search-item .d { color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-search-empty { padding: 8px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #888); }\n[data-edrv-view] .edrv-btn-mini { font-size: 11px; padding: 2px 9px; border: none; border-radius: 999px; cursor: pointer; color: #fff; font-weight: 600; white-space: nowrap; }\n[data-edrv-view] .edrv-btn-keep { background: var(--dsw-alias-state-success-primary, #2e9e44); }\n[data-edrv-view] .edrv-btn-undo { background: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-btn-mini:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-statusbar { display: flex; align-items: center; gap: 10px; padding: 3px 10px; border-top: 1px solid var(--dsw-alias-border-l1, #333); background: var(--dsw-alias-bg-layer-1, transparent); font-size: 11px; color: var(--dsw-alias-label-tertiary, #888); flex-shrink: 0; white-space: nowrap; overflow: hidden; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-path { flex: 1; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-diffchip { font-size: 11px; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #333); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-state-warn-primary, #b7791f); cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn { font-size: 12px; padding: 2px 6px; border: none; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; border-radius: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-mn-add-line { background: rgba(15,157,88,.10); }\n[data-edrv-view] .edrv-mn-gutter-add { color: #0f9d58 !important; font-weight: 700; display: flex !important; align-items: center; justify-content: center; }\n[data-edrv-view] .edrv-mn-gutter-add::before { content: \"+\"; }\n[data-edrv-view] .edrv-del-zone { background: #fdeaea; border-top: 1px solid rgba(217,83,79,.35); border-bottom: 1px solid rgba(217,83,79,.35); box-shadow: inset 0 0 0 1px rgba(217,83,79,.12); }\n[data-edrv-view] .edrv-del-row { white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 12.5px; line-height: 20px; color: #c0392b; }\n[data-edrv-view] .edrv-del-text { display: inline-block; white-space: pre; }\n[data-edrv-view] .edrv-minus-overlay { position: absolute; left: 0; top: 0; width: 100%; height: 100%; max-width: 100%; overflow: visible; pointer-events: none; z-index: 6; }\n[data-edrv-view] .edrv-minus-item { position: absolute; box-sizing: border-box; max-width: 100%; overflow: hidden; }\n[data-edrv-view] .edrv-minus-item::before { content: ''; position: absolute; left: 4px; top: 50%; width: 8px; height: 2px; transform: translateY(-50%); border-radius: 2px; background: #d9534f; }\n[data-edrv-view] .edrv-monaco-host { flex: 1; min-height: 0; position: relative; }\n[data-edrv-view] .edrv-monaco-host > div { position: absolute; inset: 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: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 4px 16px rgba(31,41,51,.12); overflow: visible; display: flex; flex-direction: column; }\n[data-edrv-view] .edrv-diffbar-row { display: flex; align-items: center; gap: 6px; height: 34px; padding: 0 8px; 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[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";
33
33
  const tagId = "dsh-vscode-mode/editor.css";
34
34
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
35
35
  const tag = document.createElement("style");
@@ -114,6 +114,63 @@ window.__ModuleLoader__.load({
114
114
  */
115
115
  const MONACO_BASE = "/edrv/vendor/monaco/vs";
116
116
  let monacoPromise = null;
117
+ let monacoStage = {
118
+ phase: "idle",
119
+ progress: 0,
120
+ message: "准备加载 Monaco…"
121
+ };
122
+ const stageListeners = /* @__PURE__ */ new Set();
123
+ /**
124
+ * Monaco 加载阶段:这是阶段进度而非网络字节进度,避免误导用户。
125
+ * @author ddj 2026年08月22号
126
+ */
127
+ const MONACO_STAGES = {
128
+ loader: {
129
+ progress: 18,
130
+ message: "加载 Monaco 引导模块…"
131
+ },
132
+ core: {
133
+ progress: 72,
134
+ message: "加载编辑器核心模块…"
135
+ },
136
+ ready: {
137
+ progress: 100,
138
+ message: "Monaco 编辑器已就绪"
139
+ },
140
+ error: {
141
+ progress: 0,
142
+ message: "Monaco 编辑器加载失败"
143
+ }
144
+ };
145
+ /**
146
+ * 发布 Monaco 加载阶段,监听器异常不得影响编辑器加载。
147
+ * @author ddj 2026年08月22号
148
+ * @param phase 阶段名
149
+ * @param progress 阶段百分比
150
+ * @param message 用户可读状态
151
+ */
152
+ function publishStage(phase, progress, message) {
153
+ monacoStage = {
154
+ phase,
155
+ progress,
156
+ message
157
+ };
158
+ for (const listener of stageListeners) try {
159
+ listener(monacoStage);
160
+ } catch (error) {}
161
+ }
162
+ /**
163
+ * 订阅 Monaco 加载阶段。
164
+ * @author ddj 2026年08月22号
165
+ * @param listener 阶段回调
166
+ * @returns 取消订阅函数
167
+ */
168
+ function subscribeStage(listener) {
169
+ if (typeof listener !== "function") return () => {};
170
+ stageListeners.add(listener);
171
+ listener(monacoStage);
172
+ return () => stageListeners.delete(listener);
173
+ }
117
174
  /** 扩展名 → Monaco language id(常见语言;未知回退 plaintext)。 */
118
175
  const LANG_BY_EXT = {
119
176
  js: "javascript",
@@ -184,34 +241,40 @@ window.__ModuleLoader__.load({
184
241
  * @author ddj 2026年08月20号
185
242
  * @returns Promise<object> window.monaco
186
243
  */
187
- function loadMonaco() {
188
- if (!monacoPromise) monacoPromise = new Promise((resolve, reject) => {
189
- const boot = () => {
190
- try {
191
- window.require.config({ paths: { vs: MONACO_BASE } });
192
- window.require(["vs/editor/editor.main"], () => resolve(window.monaco), (err) => {
193
- monacoPromise = null;
194
- reject(/* @__PURE__ */ new Error("Monaco 模块加载失败:" + String(err)));
195
- });
196
- } catch (error) {
244
+ function loadMonaco(onProgress) {
245
+ const unsubscribe = subscribeStage(onProgress);
246
+ if (!monacoPromise) {
247
+ publishStage("loader", MONACO_STAGES.loader.progress, MONACO_STAGES.loader.message);
248
+ monacoPromise = new Promise((resolve, reject) => {
249
+ const fail = (error) => {
197
250
  monacoPromise = null;
251
+ publishStage("error", MONACO_STAGES.error.progress, MONACO_STAGES.error.message);
198
252
  reject(error);
199
- }
200
- };
201
- if (document.querySelector("script[data-edrv-monaco-loader]")) boot();
202
- else {
203
- const s = document.createElement("script");
204
- s.src = "/edrv/vendor/monaco/vs/loader.js";
205
- s.dataset.edrvMonacoLoader = "1";
206
- s.onload = boot;
207
- s.onerror = () => {
208
- monacoPromise = null;
209
- reject(/* @__PURE__ */ new Error("Monaco loader 加载失败"));
210
253
  };
211
- document.head.appendChild(s);
212
- }
213
- });
214
- return monacoPromise;
254
+ const boot = () => {
255
+ try {
256
+ window.require.config({ paths: { vs: MONACO_BASE } });
257
+ publishStage("core", MONACO_STAGES.core.progress, MONACO_STAGES.core.message);
258
+ window.require(["vs/editor/editor.main"], () => {
259
+ publishStage("ready", MONACO_STAGES.ready.progress, MONACO_STAGES.ready.message);
260
+ resolve(window.monaco);
261
+ }, (err) => fail(/* @__PURE__ */ new Error("Monaco 模块加载失败:" + String(err))));
262
+ } catch (error) {
263
+ fail(error);
264
+ }
265
+ };
266
+ if (document.querySelector("script[data-edrv-monaco-loader]")) boot();
267
+ else {
268
+ const s = document.createElement("script");
269
+ s.src = "/edrv/vendor/monaco/vs/loader.js";
270
+ s.dataset.edrvMonacoLoader = "1";
271
+ s.onload = boot;
272
+ s.onerror = () => fail(/* @__PURE__ */ new Error("Monaco loader 加载失败"));
273
+ document.head.appendChild(s);
274
+ }
275
+ });
276
+ }
277
+ return monacoPromise.finally(unsubscribe);
215
278
  }
216
279
  //#endregion
217
280
  //#region src/client/monaco/diffRender.ts
@@ -305,8 +368,10 @@ window.__ModuleLoader__.load({
305
368
  try {
306
369
  li = editor.getLayoutInfo();
307
370
  } catch (e) {}
308
- const left = li ? li.decorationsLeft : 0;
371
+ const rawLeft = li ? li.decorationsLeft : 0;
309
372
  const width = li && li.decorationsWidth > 0 ? li.decorationsWidth : 16;
373
+ const maxLeft = Math.max(0, root.clientWidth - width);
374
+ const left = Math.max(0, Math.min(maxLeft, rawLeft + 12));
310
375
  const lineCount = editor.getModel().getLineCount();
311
376
  let itemIdx = 0;
312
377
  let zi = 0;
@@ -318,7 +383,7 @@ window.__ModuleLoader__.load({
318
383
  for (let i = 0; i < z.n; i++) {
319
384
  const item = document.createElement("div");
320
385
  item.className = "edrv-minus-item";
321
- item.textContent = "-";
386
+ item.textContent = "";
322
387
  item.style.width = width + "px";
323
388
  item.style.height = lineH + "px";
324
389
  item.dataset.zone = String(zi);
@@ -346,7 +411,14 @@ window.__ModuleLoader__.load({
346
411
  const edRect = root.getBoundingClientRect();
347
412
  const st = editor.getScrollTop() || 0;
348
413
  const items = overlay.querySelectorAll(".edrv-minus-item");
414
+ let correctedLeft = left;
415
+ try {
416
+ const layout = editor.getLayoutInfo();
417
+ const markerWidth = layout.decorationsWidth > 0 ? layout.decorationsWidth : width;
418
+ correctedLeft = Math.max(0, Math.min(Math.max(0, root.clientWidth - markerWidth), (layout.decorationsLeft || 0) + 12));
419
+ } catch (e) {}
349
420
  for (const item of items) {
421
+ item.style.left = correctedLeft + "px";
350
422
  const zIndex = Number(item.dataset.zone);
351
423
  const rIndex = Number(item.dataset.row);
352
424
  const z = createdZones[zIndex];
@@ -1116,6 +1188,11 @@ window.__ModuleLoader__.load({
1116
1188
  const [content, setContent] = react.default.useState(null);
1117
1189
  const [status, setStatus] = react.default.useState("");
1118
1190
  const [error, setError] = react.default.useState(null);
1191
+ const [loadError, setLoadError] = react.default.useState(null);
1192
+ const [loadStage, setLoadStage] = react.default.useState({
1193
+ progress: 0,
1194
+ message: "准备加载编辑器…"
1195
+ });
1119
1196
  const [openInput, setOpenInput] = react.default.useState(false);
1120
1197
  const [pathDraft, setPathDraft] = react.default.useState("");
1121
1198
  const [cursor, setCursor] = react.default.useState("");
@@ -1136,7 +1213,10 @@ window.__ModuleLoader__.load({
1136
1213
  const lineRegionMapRef = react.default.useRef(/* @__PURE__ */ new Map());
1137
1214
  const hoverKeyRef = react.default.useRef(null);
1138
1215
  const hoverTopRef = react.default.useRef(null);
1216
+ const hoverRightRef = react.default.useRef(null);
1139
1217
  const hideTimerRef = react.default.useRef(null);
1218
+ const hoverEditorRef = react.default.useRef(false);
1219
+ const hoverPanelRef = react.default.useRef(false);
1140
1220
  const batchBusyRef = react.default.useRef(false);
1141
1221
  const diffRendererRef = react.default.useRef(null);
1142
1222
  if (!diffRendererRef.current) diffRendererRef.current = createDiffRenderer((sid, t) => dbg(sid, t));
@@ -1187,6 +1267,11 @@ window.__ModuleLoader__.load({
1187
1267
  };
1188
1268
  const loadContent = (path, sid) => {
1189
1269
  const seq = ++loadSeqRef.current;
1270
+ setLoadError(null);
1271
+ setLoadStage({
1272
+ progress: monaco ? 72 : 12,
1273
+ message: "读取文件内容…"
1274
+ });
1190
1275
  rpc("edrv.read", {
1191
1276
  sessionId: sid,
1192
1277
  path
@@ -1194,16 +1279,23 @@ window.__ModuleLoader__.load({
1194
1279
  if (seq !== loadSeqRef.current || path !== active) return;
1195
1280
  if (res && res.ok) {
1196
1281
  setContent(res.content);
1282
+ setLoadStage((prev) => ({
1283
+ progress: Math.max(84, prev.progress),
1284
+ message: "文件已读取,准备创建编辑器…"
1285
+ }));
1197
1286
  setStatus("已加载");
1198
1287
  } else {
1199
- setError(res?.error ? String(res.error) : "读取失败");
1288
+ const message = res?.error ? String(res.error) : "读取失败";
1289
+ setLoadError(message);
1290
+ setError(message);
1200
1291
  setStatus("读取失败");
1201
1292
  }
1202
1293
  }).catch((e) => {
1203
- if (seq === loadSeqRef.current) {
1204
- setError("read异常:" + String(e));
1205
- setStatus("读取失败");
1206
- }
1294
+ if (seq !== loadSeqRef.current) return;
1295
+ const message = "read异常:" + String(e);
1296
+ setLoadError(message);
1297
+ setError(message);
1298
+ setStatus("读取失败");
1207
1299
  });
1208
1300
  };
1209
1301
  react.default.useEffect(() => {
@@ -1260,13 +1352,26 @@ window.__ModuleLoader__.load({
1260
1352
  react.default.useEffect(() => {
1261
1353
  if (!active) return;
1262
1354
  setContent(null);
1355
+ setLoadError(null);
1356
+ setLoadStage({
1357
+ progress: 10,
1358
+ message: "准备读取文件…"
1359
+ });
1263
1360
  setStatus("加载中…");
1264
1361
  loadContent(active, sessionId);
1265
1362
  }, [active, sessionId]);
1266
1363
  react.default.useEffect(() => {
1267
1364
  if (monaco || monacoErr) return;
1268
1365
  let alive = true;
1269
- loadMonaco().then((m) => {
1366
+ const onProgress = (stage) => {
1367
+ if (!alive) return;
1368
+ const progress = stage.phase === "ready" ? 70 : Math.round(10 + stage.progress * .6);
1369
+ setLoadStage((prev) => ({
1370
+ progress: Math.max(prev.progress, progress),
1371
+ message: stage.message
1372
+ }));
1373
+ };
1374
+ loadMonaco(onProgress).then((m) => {
1270
1375
  if (alive) setMonaco(m);
1271
1376
  }).catch((e) => {
1272
1377
  if (alive) {
@@ -1335,6 +1440,10 @@ window.__ModuleLoader__.load({
1335
1440
  const ed = editorRef.current;
1336
1441
  const model = getModel(active, content);
1337
1442
  if (ed.getModel() !== model) ed.setModel(model);
1443
+ setLoadStage((prev) => ({
1444
+ progress: Math.max(96, prev.progress),
1445
+ message: "创建编辑器视图…"
1446
+ }));
1338
1447
  }, [
1339
1448
  monaco,
1340
1449
  active,
@@ -1343,6 +1452,10 @@ window.__ModuleLoader__.load({
1343
1452
  react.default.useEffect(() => {
1344
1453
  if (!monaco || !editorRef.current || !active || content === null) return;
1345
1454
  diffRendererRef.current.render(monaco, editorRef.current, pendingRegions, sessionId);
1455
+ setLoadStage({
1456
+ progress: 100,
1457
+ message: "编辑器已就绪"
1458
+ });
1346
1459
  }, [
1347
1460
  monaco,
1348
1461
  active,
@@ -1408,41 +1521,49 @@ window.__ModuleLoader__.load({
1408
1521
  setCursor("Ln " + e.position.lineNumber + ", Col " + e.position.column);
1409
1522
  });
1410
1523
  const hideSoon = () => {
1411
- if (hideTimerRef.current) return;
1524
+ if (hoverEditorRef.current || hoverPanelRef.current || hideTimerRef.current) return;
1412
1525
  hideTimerRef.current = setTimeout(() => {
1413
1526
  hideTimerRef.current = null;
1527
+ if (hoverEditorRef.current || hoverPanelRef.current) return;
1414
1528
  hoverKeyRef.current = null;
1415
1529
  hoverTopRef.current = null;
1416
1530
  setHoverAct(null);
1417
1531
  }, 180);
1418
1532
  };
1419
1533
  ed.onMouseMove((e) => {
1534
+ hoverEditorRef.current = true;
1420
1535
  const line = e?.target?.position?.lineNumber;
1421
1536
  const map = lineRegionMapRef.current;
1422
1537
  if (!line || !map.size) {
1538
+ hoverEditorRef.current = false;
1423
1539
  hideSoon();
1424
1540
  return;
1425
1541
  }
1426
1542
  const hit = map.get(line);
1427
1543
  if (!hit) {
1544
+ hoverEditorRef.current = false;
1428
1545
  hideSoon();
1429
1546
  return;
1430
1547
  }
1431
1548
  const key = callIdAttr(hit.callId, hit.idx);
1432
1549
  const top = Math.max(0, ed.getTopForLineNumber(Math.max(1, hit.start)) - ed.getScrollTop());
1433
- if (hoverKeyRef.current === key && hoverTopRef.current === top) return;
1550
+ const layout = ed.getLayoutInfo();
1551
+ const minimapLeft = layout.minimap?.minimapLeft || 0;
1552
+ const right = minimapLeft > 0 ? Math.max(12, layout.width - minimapLeft + 8) : Math.max(12, layout.verticalScrollbarWidth + 8);
1553
+ if (hoverKeyRef.current === key && hoverTopRef.current === top && hoverRightRef.current === right) return;
1434
1554
  hoverKeyRef.current = key;
1435
1555
  hoverTopRef.current = top;
1556
+ hoverRightRef.current = right;
1436
1557
  if (hideTimerRef.current) {
1437
1558
  clearTimeout(hideTimerRef.current);
1438
1559
  hideTimerRef.current = null;
1439
1560
  }
1440
1561
  setHoverAct({
1441
1562
  region: hit,
1442
- top
1563
+ top,
1564
+ right
1443
1565
  });
1444
1566
  });
1445
- ed.onMouseLeave(hideSoon);
1446
1567
  editorRef.current = ed;
1447
1568
  }, []);
1448
1569
  react.default.useEffect(() => {
@@ -1504,6 +1625,22 @@ window.__ModuleLoader__.load({
1504
1625
  refreshRecords();
1505
1626
  };
1506
1627
  /**
1628
+ * 关闭当前差异浮窗并清理 hover 锚点。
1629
+ * @author ddj 2026年08月21号
1630
+ */
1631
+ const dismissHover = () => {
1632
+ hoverKeyRef.current = null;
1633
+ hoverTopRef.current = null;
1634
+ hoverRightRef.current = null;
1635
+ hoverEditorRef.current = false;
1636
+ hoverPanelRef.current = false;
1637
+ if (hideTimerRef.current) {
1638
+ clearTimeout(hideTimerRef.current);
1639
+ hideTimerRef.current = null;
1640
+ }
1641
+ setHoverAct(null);
1642
+ };
1643
+ /**
1507
1644
  * 对单个差异区域执行采纳/不采纳。
1508
1645
  * @author ddj 2026年08月20号
1509
1646
  * @param region 差异区域(callId/idx/create)
@@ -1686,39 +1823,98 @@ window.__ModuleLoader__.load({
1686
1823
  onClick: reloadFile
1687
1824
  }, "⟳"));
1688
1825
  const otherFiles = sum.pendingFiles.filter((f) => f.path !== active);
1826
+ /**
1827
+ * 渲染编辑器/文件加载进度面板。
1828
+ * @author ddj 2026年08月22号
1829
+ * @param message 当前加载阶段
1830
+ * @param progress 阶段进度
1831
+ * @param retry 可选重试回调
1832
+ * @returns 加载面板 React 元素
1833
+ */
1834
+ const loadingBody = (message, progress, retry) => react.default.createElement("div", {
1835
+ className: "edrv-empty edrv-loading",
1836
+ "aria-live": "polite"
1837
+ }, react.default.createElement("div", { className: "edrv-loading-title" }, message), react.default.createElement("div", {
1838
+ className: "edrv-progress",
1839
+ role: "progressbar",
1840
+ "aria-label": "编辑器加载进度",
1841
+ "aria-valuemin": 0,
1842
+ "aria-valuemax": 100,
1843
+ "aria-valuenow": progress
1844
+ }, react.default.createElement("div", {
1845
+ className: "edrv-progress-value",
1846
+ style: { width: Math.max(0, Math.min(100, progress)) + "%" }
1847
+ })), react.default.createElement("div", { className: "edrv-loading-percent" }, Math.round(progress) + "%"), retry ? react.default.createElement("button", {
1848
+ className: "edrv-pill edrv-pill-ghost",
1849
+ onClick: retry
1850
+ }, "重试") : null);
1689
1851
  let body;
1690
- if (!monaco && !monacoErr) body = react.default.createElement("div", { className: "edrv-empty" }, "正在加载 Monaco 编辑器…");
1691
- else if (monacoErr) body = react.default.createElement("div", { className: "edrv-empty" }, react.default.createElement("div", null, "Monaco 编辑器加载失败:" + String(monacoErr)), react.default.createElement("div", { style: { fontSize: 11 } }, "请确认插件包 assets/vendor/monaco 完整(/edrv/vendor 路由可达)"));
1852
+ if (!monaco && !monacoErr) body = loadingBody(loadStage.message, loadStage.progress);
1853
+ else if (monacoErr) body = react.default.createElement("div", { className: "edrv-empty" }, react.default.createElement("div", null, "Monaco 编辑器加载失败:" + String(monacoErr)), react.default.createElement("div", { style: { fontSize: 11 } }, "请确认插件包 assets/vendor/monaco 完整(/edrv/vendor 路由可达)"), react.default.createElement("button", {
1854
+ className: "edrv-pill edrv-pill-ghost",
1855
+ onClick: () => {
1856
+ setMonacoErr(null);
1857
+ setLoadStage({
1858
+ progress: 0,
1859
+ message: "准备重试 Monaco…"
1860
+ });
1861
+ }
1862
+ }, "重试"));
1692
1863
  else if (!active) body = react.default.createElement("div", { className: "edrv-empty" }, react.default.createElement("div", null, "暂无打开的文件"), react.default.createElement("div", { style: { fontSize: 12 } }, "使用右上搜索框 (Ctrl+P) 打开工作区文件;agent 修改文件后顶部会出现差异角标"));
1693
- else if (content === null) body = react.default.createElement("div", { className: "edrv-empty" }, "加载中…");
1864
+ else if (content === null && loadError) body = loadingBody("文件加载失败:" + loadError, 0, () => {
1865
+ setLoadError(null);
1866
+ setContent(null);
1867
+ setLoadStage({
1868
+ progress: 10,
1869
+ message: "重新读取文件…"
1870
+ });
1871
+ loadContent(active, sessionId);
1872
+ });
1873
+ else if (content === null) body = loadingBody(loadStage.message || "读取文件内容…", loadStage.progress);
1694
1874
  else body = react.default.createElement("div", { className: "edrv-monaco-host" }, react.default.createElement("div", { ref: ensureEditor }));
1695
1875
  const hoverEl = hoverAct && !launcherOpen ? react.default.createElement("div", {
1696
1876
  className: "edrv-hoveract",
1697
1877
  style: {
1698
1878
  top: hoverAct.top,
1699
- right: 12
1879
+ right: hoverAct.right ?? 12
1700
1880
  },
1701
1881
  onMouseEnter: () => {
1882
+ hoverPanelRef.current = true;
1883
+ if (hideTimerRef.current) {
1884
+ clearTimeout(hideTimerRef.current);
1885
+ hideTimerRef.current = null;
1886
+ }
1887
+ },
1888
+ onMouseMove: () => {
1889
+ hoverPanelRef.current = true;
1702
1890
  if (hideTimerRef.current) {
1703
1891
  clearTimeout(hideTimerRef.current);
1704
1892
  hideTimerRef.current = null;
1705
1893
  }
1706
1894
  },
1707
1895
  onMouseLeave: () => {
1708
- const t = setTimeout(() => {
1896
+ hoverPanelRef.current = false;
1897
+ if (hoverEditorRef.current || hideTimerRef.current) return;
1898
+ hideTimerRef.current = setTimeout(() => {
1709
1899
  hideTimerRef.current = null;
1900
+ if (hoverEditorRef.current || hoverPanelRef.current) return;
1710
1901
  hoverKeyRef.current = null;
1711
1902
  hoverTopRef.current = null;
1712
1903
  setHoverAct(null);
1713
- }, 180);
1714
- hideTimerRef.current = t;
1904
+ }, 420);
1715
1905
  }
1716
1906
  }, react.default.createElement("button", {
1717
1907
  className: "edrv-pill edrv-pill-keep",
1718
- onClick: () => actHunk(hoverAct.region, false)
1908
+ onClick: () => {
1909
+ dismissHover();
1910
+ actHunk(hoverAct.region, false);
1911
+ }
1719
1912
  }, "✓ Keep"), react.default.createElement("button", {
1720
1913
  className: "edrv-pill edrv-pill-undo",
1721
- onClick: () => actHunk(hoverAct.region, true)
1914
+ onClick: () => {
1915
+ dismissHover();
1916
+ actHunk(hoverAct.region, true);
1917
+ }
1722
1918
  }, "↩ Undo")) : null;
1723
1919
  const overlay = launcherOpen ? react.default.createElement(react.default.Fragment, null, react.default.createElement("div", {
1724
1920
  style: {