dsh-diff-approval 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -18,6 +18,7 @@ window.__ModuleLoader__.load({
18
18
  //#endregion
19
19
  let react_jsx_runtime = require("react/jsx-runtime");
20
20
  let react = require("react");
21
+ let react_dom = require("react-dom");
21
22
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
22
23
  //#region node_modules/.pnpm/diff@9.0.0/node_modules/diff/libesm/diff/base.js
23
24
  var Diff = class {
@@ -654,6 +655,16 @@ window.__ModuleLoader__.load({
654
655
  function computeWholeFileDiff(oldText, newText) {
655
656
  oldText = oldText.replace(/\r\n?/g, "\n");
656
657
  newText = newText.replace(/\r\n?/g, "\n");
658
+ if (oldText === newText) return {
659
+ rows: contentLines(oldText).map((text, index) => ({
660
+ kind: "context",
661
+ text,
662
+ oldLine: index + 1,
663
+ newLine: index + 1
664
+ })),
665
+ removed: 0,
666
+ added: 0
667
+ };
657
668
  const oldLines = contentLines(oldText);
658
669
  const newLines = contentLines(newText);
659
670
  const context = Math.max(1, oldLines.length, newLines.length);
@@ -11693,6 +11704,15 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
11693
11704
  //#endregion
11694
11705
  //#region lib/types/client/reference.js
11695
11706
  /**
11707
+ * Reference labels for the selection toolbar: a workspace-relative path (or
11708
+ * the absolute path when the file is outside the workspace) plus a 1-based
11709
+ * line range. Pure derivation so the display rule is unit-testable without
11710
+ * the panel.
11711
+ * @module dsh-diff-approval/client/reference
11712
+ */
11713
+ /** The marker that replaces a reference's line number when its lines are gone. */
11714
+ const LINE_MISSING_LABEL = "LINE_MISSING";
11715
+ /**
11696
11716
  * The path embedded in a copied reference: workspace-relative (forward
11697
11717
  * slashes) when the file lives inside the current workspace, the absolute
11698
11718
  * path otherwise. A bare file name is never enough — a reference must resolve
@@ -11720,15 +11740,66 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
11720
11740
  return start === end ? String(start) : `${start}-${end}`;
11721
11741
  }
11722
11742
  /**
11723
- * Build the clipboard text for a selected line range.
11743
+ * Build the clipboard text for a selected line range, wrapped in parentheses so
11744
+ * the reference reads as one unambiguous token (and can be matched precisely).
11724
11745
  * @param path - the selected file's path.
11725
11746
  * @param workspacePath - the current workspace root, or `undefined`.
11726
11747
  * @param start - first selected line number.
11727
11748
  * @param end - last selected line number.
11728
- * @returns the `path:range` reference text.
11749
+ * @returns the `(path:range)` reference text.
11729
11750
  */
11730
11751
  function referenceOf(path, workspacePath, start, end) {
11731
- return `${referencePathOf(path, workspacePath)}:${lineRangeLabel(start, end)}`;
11752
+ return `(${referencePathOf(path, workspacePath)}:${lineRangeLabel(start, end)})`;
11753
+ }
11754
+ /**
11755
+ * Map one referenced line range from `oldContent` coordinates to `newContent`
11756
+ * coordinates. Lines that survive (unchanged context) map to their new line
11757
+ * numbers, and the surviving lines' min/max span is returned. When every line
11758
+ * in the range was removed, returns `undefined` (the reference is expired).
11759
+ * @param oldContent - the file content the reference was made against.
11760
+ * @param newContent - the file content now.
11761
+ * @param start - first referenced line (1-based, inclusive).
11762
+ * @param end - last referenced line (1-based, inclusive).
11763
+ * @returns the surviving range, or `undefined` when nothing survives.
11764
+ */
11765
+ function remapReferenceRange(oldContent, newContent, start, end) {
11766
+ const diff = computeWholeFileDiff(oldContent, newContent);
11767
+ const oldToNew = /* @__PURE__ */ new Map();
11768
+ for (const row of diff.rows) if (row.oldLine !== void 0 && row.newLine !== void 0) oldToNew.set(row.oldLine, row.newLine);
11769
+ let min = Infinity;
11770
+ let max = -Infinity;
11771
+ for (let line = start; line <= end; line++) {
11772
+ const next = oldToNew.get(line);
11773
+ if (next === void 0) continue;
11774
+ min = Math.min(min, next);
11775
+ max = Math.max(max, next);
11776
+ }
11777
+ if (min === Infinity) return void 0;
11778
+ return {
11779
+ start: min,
11780
+ end: max
11781
+ };
11782
+ }
11783
+ /**
11784
+ * Rewrite every `(referencePath:line)` / `(referencePath:start-end)` occurrence
11785
+ * in `text`, remapping each range from `oldContent` to `newContent`. A range
11786
+ * whose lines all survived becomes the new range; one whose lines were all
11787
+ * removed becomes `(referencePath:LINE_MISSING)`.
11788
+ * @param text - the free text (composer draft, queued message) to rewrite.
11789
+ * @param referencePath - the file's reference path (workspace-relative or absolute).
11790
+ * @param oldContent - the file content the references were made against.
11791
+ * @param newContent - the file content now.
11792
+ * @returns the rewritten text.
11793
+ */
11794
+ function remapReferences(text, referencePath, oldContent, newContent) {
11795
+ const escaped = referencePath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
11796
+ const regex = new RegExp(`\\(${escaped}:(\\d+)(?:-(\\d+))?\\)`, "g");
11797
+ return text.replace(regex, (_whole, startText, endText) => {
11798
+ const start = Number(startText);
11799
+ const mapped = remapReferenceRange(oldContent, newContent, start, endText === void 0 ? start : Number(endText));
11800
+ if (mapped === void 0) return `(${referencePath}:${LINE_MISSING_LABEL})`;
11801
+ return `(${referencePath}:${lineRangeLabel(mapped.start, mapped.end)})`;
11802
+ });
11732
11803
  }
11733
11804
  //#endregion
11734
11805
  //#region lib/types/client/settings.js
@@ -11805,9 +11876,42 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
11805
11876
  function setSplitMode(value) {
11806
11877
  localStorage.setItem(SPLIT_MODE_KEY, value ? "1" : "0");
11807
11878
  }
11879
+ const QUICK_SUMMON_KEY = "diff-approval:quick-summon-key";
11880
+ /**
11881
+ * The quick-summon chord. Stored as `Modifier+...+Key`; falls back to
11882
+ * {@link DEFAULT_QUICK_SUMMON}.
11883
+ * @returns the chord string.
11884
+ */
11885
+ function quickSummonKey() {
11886
+ return localStorage.getItem(QUICK_SUMMON_KEY) ?? "Ctrl+D";
11887
+ }
11888
+ /** Persist the quick-summon chord. */
11889
+ function setQuickSummonKey(value) {
11890
+ localStorage.setItem(QUICK_SUMMON_KEY, value);
11891
+ }
11892
+ /**
11893
+ * Whether a keyboard event matches a chord string like `Ctrl+D`. Modifier
11894
+ * names are matched case-insensitively (`Ctrl`/`Control`, `Alt`/`Option`,
11895
+ * `Shift`, `Meta`/`Cmd`/`Command`/`Win`); the final part is the key. Exact
11896
+ * modifier set is required (extra modifiers do not match).
11897
+ * @param event - the keydown event.
11898
+ * @param shortcut - the chord string.
11899
+ * @returns whether the event matches.
11900
+ */
11901
+ function matchesShortcut(event, shortcut) {
11902
+ const parts = shortcut.split("+").map((part) => part.trim().toLowerCase());
11903
+ const key = parts.pop();
11904
+ if (key === void 0 || key === "") return false;
11905
+ const mods = new Set(parts);
11906
+ const ctrl = mods.has("ctrl") || mods.has("control");
11907
+ const alt = mods.has("alt") || mods.has("option");
11908
+ const shift = mods.has("shift");
11909
+ const meta = mods.has("meta") || mods.has("cmd") || mods.has("command") || mods.has("win");
11910
+ return event.key.toLowerCase() === key && event.ctrlKey === ctrl && event.altKey === alt && event.shiftKey === shift && event.metaKey === meta;
11911
+ }
11808
11912
  //#endregion
11809
11913
  //#region \0dsh-css:/home/runner/work/dsh-diff-approval/dsh-diff-approval/src/client/PendingPanel.module.css.mjs
11810
- const css = ".F1KBNa_layer{box-sizing:border-box;flex:none;align-items:center;width:calc(100% + 4px);height:42px;margin:4px -2px;display:flex;position:relative}.F1KBNa_footerButtons{align-items:center;width:100%;display:flex}.F1KBNa_badge{box-sizing:border-box;width:100%;height:42px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:12px;align-items:center;gap:8px;padding:0 10px 0 8px;font-family:inherit;font-size:14px;line-height:22px;display:flex;overflow:hidden}.F1KBNa_badge:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_badge[data-active]{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_badge:disabled{color:var(--dsw-alias-label-tertiary);cursor:default;background:0 0}.F1KBNa_badgeLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.F1KBNa_badgeCount{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;margin-left:auto;font-size:12px;line-height:16px}.F1KBNa_layer.F1KBNa_rail{width:36px;height:36px;margin:8px 0 10px}.F1KBNa_rail .F1KBNa_badge{border-radius:50%;justify-content:center;gap:0;width:36px;height:36px;padding:0}.F1KBNa_rail .F1KBNa_badgeLabel{display:none}.F1KBNa_rail .F1KBNa_badgeCount{box-sizing:border-box;background:var(--dsw-alias-state-business-primary);min-width:18px;height:18px;color:var(--dsw-alias-label-primary-foreground);font-variant-numeric:tabular-nums;border-radius:9px;justify-content:center;align-items:center;padding:0 4px;font-size:11px;line-height:18px;display:flex;position:absolute;top:-3px;right:-7px}.F1KBNa_fullscreenBackdrop{z-index:29;background:var(--dsw-specific-sidebar-fill);position:fixed;inset:0}.F1KBNa_panel{z-index:30;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:auto;max-width:none;box-shadow:var(--dsw-shadow-lv2);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:12px;flex-direction:column;display:flex;position:fixed;inset:8px 8px 128px;overflow:hidden}.F1KBNa_header{box-sizing:border-box;border-bottom:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;justify-content:space-between;align-items:center;min-height:44px;padding:10px 12px;display:flex}.F1KBNa_headerActions{align-items:center;gap:2px;display:flex}.F1KBNa_settingsPage{padding:8px 12px}.F1KBNa_settingsRow{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:16px 0;display:flex}.F1KBNa_settingsRowText{flex-direction:column;flex:1;gap:4px;min-width:0;padding-right:48px;display:flex}.F1KBNa_settingsRowTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}.F1KBNa_settingsRowDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.F1KBNa_settingsSelector{background:var(--dsw-alias-bg-module-platform);height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:12px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.F1KBNa_settingsSelector:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_settingsSelectorChevron{flex:none}.F1KBNa_states{flex-direction:column;flex:1;min-height:0;padding:4px 12px 12px;display:flex;overflow-y:auto}.F1KBNa_split{flex:1;align-items:stretch;min-height:0;display:flex;position:relative}.F1KBNa_fileListFloat{z-index:40;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:12px;flex-direction:column;padding:6px 8px 10px;display:flex;position:absolute;overflow:hidden}.F1KBNa_fileList{box-sizing:border-box;border-right:1px solid var(--dsw-alias-border-l2);flex-direction:column;flex:none;width:240px;min-height:0;padding:4px 8px 12px;display:flex}.F1KBNa_listScroll{flex:1;min-height:0;overflow-y:auto}.F1KBNa_bulkActions{flex:none;gap:6px;padding-top:8px;display:flex}.F1KBNa_bulkActions .F1KBNa_action{text-align:center;flex:1}.F1KBNa_resizeHandle{cursor:col-resize;background:0 0;flex:none;width:5px;margin:0 -2px}.F1KBNa_resizeHandle:hover{background:var(--dsw-alias-border-l2)}.F1KBNa_detail{flex-direction:column;flex:1;min-width:0;min-height:0;display:flex}.F1KBNa_detailEmpty{color:var(--dsw-alias-label-tertiary);text-align:center;flex:1;justify-content:center;align-items:center;margin:0;padding:24px;font-size:12px;line-height:18px;display:flex}.F1KBNa_title{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:20px}.F1KBNa_note,.F1KBNa_readError,.F1KBNa_hint{color:var(--dsw-alias-label-tertiary);margin:4px 0;font-size:12px;line-height:18px}.F1KBNa_noteCentered{text-align:center;margin:auto}.F1KBNa_emptyState{flex-direction:column;align-items:center;gap:10px;margin:auto;display:flex}.F1KBNa_importButton{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:5px 14px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_importButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_importButton:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_importNote{color:var(--dsw-alias-label-tertiary);text-align:center;margin:0;font-size:12px;line-height:18px}.F1KBNa_readError{color:var(--dsw-alias-state-error-primary)}.F1KBNa_group{color:var(--dsw-alias-label-tertiary);margin:8px 0 4px;font-size:12px;font-weight:500;line-height:16px}.F1KBNa_rows{margin:0;padding:0;list-style:none}.F1KBNa_row{border:1px solid #0000;border-radius:10px;margin:2px 0}.F1KBNa_rowHead{width:100%;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:10px;align-items:baseline;gap:8px;padding:6px 8px;display:flex}.F1KBNa_rowHead:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_rowHead[data-selected]{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_rowPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;font:var(--dsw-font-markdown-code-block);overflow:hidden}.F1KBNa_kindTag{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-tertiary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_kindHint{color:var(--dsw-alias-label-tertiary);flex:none;font-size:12px;line-height:16px}.F1KBNa_divergedHint,.F1KBNa_missingHint{border-bottom:1px solid var(--dsw-alias-border-l2);margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missing{border:1px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary));white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_rowFailed{border:1px solid var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_actionError{border-bottom:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missingHint{color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary))}.F1KBNa_rowMeta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;gap:6px;margin-left:auto;font-size:12px;line-height:16px;display:inline-flex}.F1KBNa_addCount{color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 60%, var(--dsw-alias-label-primary))}.F1KBNa_delCount{color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 60%, var(--dsw-alias-label-primary))}.F1KBNa_diff{background:var(--dsw-alias-markdown-code-block);flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_diffHeader{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block);flex:1;font-size:12px;line-height:18px;overflow:hidden}.F1KBNa_diffActions{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffStats{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:16px}.F1KBNa_flexSpacer{flex:1}.F1KBNa_action{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_action:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_action:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_actionPrimary{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_actionPrimary:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}.F1KBNa_actionPrimary:disabled{background:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:.55}.F1KBNa_actionQuietDisabled:disabled{cursor:pointer;color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l1);background:0 0}.F1KBNa_actionPrimary.F1KBNa_actionQuietDisabled:disabled{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:1}.F1KBNa_iconAction{justify-content:center;align-items:center;min-height:25px;padding:4px 6px;display:inline-flex}.F1KBNa_close{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_close:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expand{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_expand:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expandExpanded svg{transform:rotate(180deg)}.F1KBNa_diffBodyWrap{flex:1;min-height:0;display:flex;position:relative}.F1KBNa_diffBody{min-width:0;font:var(--dsw-font-markdown-code-block);cursor:text;outline:none;flex:1;padding:0;position:relative;overflow:auto}.F1KBNa_diffBody::-webkit-scrollbar,.F1KBNa_diffBody::-webkit-scrollbar-track,.F1KBNa_diffBody::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_blockActions{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);z-index:2;border-radius:10px;align-items:center;gap:9px;padding:5px;display:flex;position:absolute;right:8px}.F1KBNa_blockPosition{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;margin-top:1px;margin-left:7px;font-size:12px;line-height:16px}.F1KBNa_searchBar{z-index:3;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);border-radius:10px;align-items:center;gap:4px;padding:4px;display:flex;position:absolute;top:8px;right:8px}.F1KBNa_searchInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);width:150px;color:var(--dsw-alias-label-primary);border-radius:6px;outline:none;padding:3px 8px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_searchInput:focus{border-color:var(--dsw-alias-state-business-primary)}.F1KBNa_searchCount{text-align:center;min-width:34px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:12px;line-height:16px}.F1KBNa_diffBody [data-diff-search=hit]{background-image:linear-gradient(#facc1529,#facc1529)}.F1KBNa_diffBody [data-diff-search=current]{background-image:linear-gradient(#facc1552,#facc1552)}.F1KBNa_blockFlash{z-index:1;box-sizing:border-box;border:2px solid var(--dsw-alias-state-business-primary);pointer-events:none;border-radius:4px;animation:1s ease-out forwards F1KBNa_diffFlash;position:absolute;left:0;right:0}@keyframes F1KBNa_diffFlash{0%{opacity:1}to{opacity:0}}.F1KBNa_overviewRuler{pointer-events:none;opacity:.5;width:4px;position:absolute;top:0;bottom:0;right:0}.F1KBNa_overviewMarker{border-radius:2px;width:100%;min-height:2px;position:absolute;right:0}.F1KBNa_markerDel{background-color:var(--dsw-alias-state-error-primary)}.F1KBNa_markerAdd{background-color:var(--dsw-alias-state-success-primary)}.F1KBNa_lines{border-spacing:0;width:max-content;min-width:100%;display:table}.F1KBNa_line{height:22px;line-height:22px;display:table-row}.F1KBNa_vSpacer{display:table-row}.F1KBNa_gutter{box-sizing:border-box;text-align:right;width:44px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;user-select:none;cursor:default;padding-right:10px;display:table-cell}.F1KBNa_code{white-space:pre;display:table-cell}.F1KBNa_context{color:var(--dsw-alias-label-primary)}.F1KBNa_del{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_add{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}.F1KBNa_statusBar{box-sizing:border-box;border-top:1px solid var(--dsw-alias-border-l2);height:34px;color:var(--dsw-alias-label-tertiary);font-family:var(--dsw-font-markdown-code-block);font-variant-numeric:tabular-nums;flex:none;align-items:center;gap:8px;padding:0 8px;font-size:12px;line-height:18px;display:flex}.F1KBNa_statusAction{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);white-space:nowrap;cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_statusAction:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langSelect{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;flex:none;align-items:center;gap:4px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px;display:inline-flex}.F1KBNa_langSelect:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langLabel{text-overflow:ellipsis;white-space:nowrap;max-width:140px;overflow:hidden}.F1KBNa_notice{z-index:60;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);max-width:360px;box-shadow:var(--dsw-shadow-lv3);border-radius:10px;align-items:flex-start;gap:12px;padding:12px 14px;display:flex;position:fixed;bottom:24px;right:24px}.F1KBNa_noticeText{font:var(--dsw-font-caption);color:var(--dsw-alias-label-primary);flex:1;margin:0;line-height:1.45}.F1KBNa_noticeButton{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);font:var(--dsw-font-caption);cursor:pointer;border-radius:6px;flex:none;padding:4px 10px}.F1KBNa_noticeButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_wrap .F1KBNa_line{height:auto;min-height:22px}.F1KBNa_subline{white-space:pre;height:22px;line-height:22px;display:block;overflow:hidden}.F1KBNa_wrapActive{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_wrapActive:hover{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}.F1KBNa_splitRoot{flex-direction:column;flex:1;min-height:0;display:flex;position:relative}.F1KBNa_diffBodySplit{flex:1;min-height:0;overflow-x:hidden}.F1KBNa_splitCols{width:100%;min-width:0;display:flex}.F1KBNa_splitCol{box-sizing:border-box;flex:1 1 0;min-width:0;overflow:hidden}.F1KBNa_splitDivider{background:var(--dsw-alias-border-l2);flex:0 0 1px}.F1KBNa_splitCol .F1KBNa_gutter,.F1KBNa_splitCol .F1KBNa_code{vertical-align:top}.F1KBNa_splitHScrollRow{border-top:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;width:100%;min-width:0;display:flex}.F1KBNa_splitHScroll{flex:1 1 0;min-width:0;height:15px;overflow:auto hidden}.F1KBNa_splitHScroll::-webkit-scrollbar{height:15px}.F1KBNa_splitHScroll::-webkit-scrollbar-track{cursor:default}.F1KBNa_splitHScroll::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_splitHScrollFill{height:1px}.F1KBNa_splitLdel{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_splitLadd{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}.F1KBNa_splitRdel{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_splitRadd{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}";
11914
+ const css = ".F1KBNa_layer{box-sizing:border-box;flex:none;align-items:center;width:calc(100% + 4px);height:42px;margin:4px -2px;display:flex;position:relative}.F1KBNa_footerButtons{align-items:center;width:100%;display:flex}.F1KBNa_badge{box-sizing:border-box;width:100%;height:42px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:12px;align-items:center;gap:8px;padding:0 10px 0 8px;font-family:inherit;font-size:14px;line-height:22px;display:flex;overflow:hidden}.F1KBNa_badge:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_badge[data-active]{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_badge:disabled{color:var(--dsw-alias-label-tertiary);cursor:default;background:0 0}.F1KBNa_badgeLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.F1KBNa_badgeCount{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;margin-left:auto;font-size:12px;line-height:16px}.F1KBNa_layer.F1KBNa_rail{width:36px;height:36px;margin:8px 0 10px}.F1KBNa_rail .F1KBNa_badge{border-radius:50%;justify-content:center;gap:0;width:36px;height:36px;padding:0}.F1KBNa_rail .F1KBNa_badgeLabel{display:none}.F1KBNa_rail .F1KBNa_badgeCount{box-sizing:border-box;background:var(--dsw-alias-state-business-primary);min-width:18px;height:18px;color:var(--dsw-alias-label-primary-foreground);font-variant-numeric:tabular-nums;border-radius:9px;justify-content:center;align-items:center;padding:0 4px;font-size:11px;line-height:18px;display:flex;position:absolute;top:-3px;right:-7px}.F1KBNa_fullscreenBackdrop{z-index:29;background:var(--dsw-specific-sidebar-fill);position:fixed;inset:0}.F1KBNa_panel{z-index:30;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:auto;max-width:none;box-shadow:var(--dsw-shadow-lv2);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:12px;flex-direction:column;display:flex;position:fixed;inset:8px 8px 128px;overflow:hidden}.F1KBNa_header{box-sizing:border-box;border-bottom:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;justify-content:space-between;align-items:center;min-height:44px;padding:10px 12px;display:flex}.F1KBNa_headerActions{align-items:center;gap:2px;display:flex}.F1KBNa_settingsPage{padding:8px 12px}.F1KBNa_settingsRow{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:16px 0;display:flex}.F1KBNa_settingsRowText{flex-direction:column;flex:1;gap:4px;min-width:0;padding-right:48px;display:flex}.F1KBNa_settingsRowTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}.F1KBNa_settingsRowDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.F1KBNa_settingsSelector{background:var(--dsw-alias-bg-module-platform);height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:12px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.F1KBNa_settingsSelector:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_settingsSelectorChevron{flex:none}.F1KBNa_states{flex-direction:column;flex:1;min-height:0;padding:4px 12px 12px;display:flex;overflow-y:auto}.F1KBNa_split{flex:1;align-items:stretch;min-height:0;display:flex;position:relative}.F1KBNa_fileListFloat{z-index:40;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:12px;flex-direction:column;padding:6px 8px 10px;display:flex;position:absolute;overflow:hidden}.F1KBNa_fileList{box-sizing:border-box;border-right:1px solid var(--dsw-alias-border-l2);flex-direction:column;flex:none;width:240px;min-height:0;padding:4px 8px 12px;display:flex}.F1KBNa_listScroll{flex:1;min-height:0;overflow-y:auto}.F1KBNa_bulkActions{flex:none;gap:6px;padding-top:8px;display:flex}.F1KBNa_bulkActions .F1KBNa_action{text-align:center;flex:1}.F1KBNa_resizeHandle{cursor:col-resize;background:0 0;flex:none;width:5px;margin:0 -2px}.F1KBNa_resizeHandle:hover{background:var(--dsw-alias-border-l2)}.F1KBNa_detail{flex-direction:column;flex:1;min-width:0;min-height:0;display:flex}.F1KBNa_detailEmpty{color:var(--dsw-alias-label-tertiary);text-align:center;flex:1;justify-content:center;align-items:center;margin:0;padding:24px;font-size:12px;line-height:18px;display:flex}.F1KBNa_confirmBackdrop{z-index:5;background:color-mix(in srgb, var(--dsw-alias-bg-base) 55%, transparent);justify-content:center;align-items:center;padding:24px;display:flex;position:absolute;inset:0}.F1KBNa_confirmCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);max-width:340px;box-shadow:var(--dsw-shadow-lv3);border-radius:12px;flex-direction:column;gap:12px;padding:16px;display:flex}.F1KBNa_confirmText{font:var(--dsw-font-caption);color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;margin:0;line-height:1.5}.F1KBNa_confirmActions{justify-content:flex-end;gap:8px;display:flex}.F1KBNa_title{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:20px}.F1KBNa_note,.F1KBNa_readError,.F1KBNa_hint{color:var(--dsw-alias-label-tertiary);margin:4px 0;font-size:12px;line-height:18px}.F1KBNa_noteCentered{text-align:center;margin:auto}.F1KBNa_emptyState{flex-direction:column;align-items:center;gap:10px;margin:auto;display:flex}.F1KBNa_importButton{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:5px 14px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_importButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_importButton:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_importNote{color:var(--dsw-alias-label-tertiary);text-align:center;margin:0;font-size:12px;line-height:18px}.F1KBNa_readError{color:var(--dsw-alias-state-error-primary)}.F1KBNa_group{color:var(--dsw-alias-label-tertiary);margin:8px 0 4px;font-size:12px;font-weight:500;line-height:16px}.F1KBNa_rows{margin:0;padding:0;list-style:none}.F1KBNa_row{border:1px solid #0000;border-radius:10px;margin:2px 0}.F1KBNa_rowHead{width:100%;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:10px;align-items:baseline;gap:8px;padding:6px 8px;display:flex}.F1KBNa_rowHead:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_rowHead[data-selected]{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_rowPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;font:var(--dsw-font-markdown-code-block);overflow:hidden}.F1KBNa_kindTag{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-tertiary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_kindHint{color:var(--dsw-alias-label-tertiary);flex:none;font-size:12px;line-height:16px}.F1KBNa_divergedHint,.F1KBNa_missingHint{border-bottom:1px solid var(--dsw-alias-border-l2);margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missing{border:1px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary));white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_rowFailed{border:1px solid var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_actionError{border-bottom:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missingHint{color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary))}.F1KBNa_rowMeta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;gap:6px;margin-left:auto;font-size:12px;line-height:16px;display:inline-flex}.F1KBNa_addCount{color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 60%, var(--dsw-alias-label-primary))}.F1KBNa_delCount{color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 60%, var(--dsw-alias-label-primary))}.F1KBNa_diff{background:var(--dsw-alias-markdown-code-block);flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_diffHeader{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block);flex:1;font-size:12px;line-height:18px;overflow:hidden}.F1KBNa_diffActions{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffStats{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:16px}.F1KBNa_flexSpacer{flex:1}.F1KBNa_action{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_action:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_action:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_actionPrimary{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_actionPrimary:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}.F1KBNa_actionPrimary:disabled{background:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:.55}.F1KBNa_actionQuietDisabled:disabled{cursor:pointer;color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l1);background:0 0}.F1KBNa_actionPrimary.F1KBNa_actionQuietDisabled:disabled{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:1}.F1KBNa_iconAction{justify-content:center;align-items:center;min-height:25px;padding:4px 6px;display:inline-flex}.F1KBNa_close{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_close:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expand{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_expand:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expandExpanded svg{transform:rotate(180deg)}.F1KBNa_diffBodyWrap{flex:1;min-height:0;display:flex;position:relative}.F1KBNa_diffBody{min-width:0;font:var(--dsw-font-markdown-code-block);-webkit-text-size-adjust:100%;text-size-adjust:100%;cursor:text;outline:none;flex:1;padding:0;position:relative;overflow:auto}.F1KBNa_diffBody::-webkit-scrollbar,.F1KBNa_diffBody::-webkit-scrollbar-track,.F1KBNa_diffBody::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_blockActions{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);z-index:2;border-radius:10px;align-items:center;gap:9px;padding:5px;display:flex;position:absolute;right:8px}.F1KBNa_blockPosition{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;margin-top:1px;margin-left:7px;font-size:12px;line-height:16px}.F1KBNa_searchBar{z-index:3;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);border-radius:10px;align-items:center;gap:4px;padding:4px;display:flex;position:absolute;top:8px;right:8px}.F1KBNa_searchInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);width:150px;color:var(--dsw-alias-label-primary);border-radius:6px;outline:none;padding:3px 8px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_searchInput:focus{border-color:var(--dsw-alias-state-business-primary)}.F1KBNa_searchCount{text-align:center;min-width:34px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:12px;line-height:16px}.F1KBNa_diffBody [data-diff-search=hit]{background-image:linear-gradient(#facc1529,#facc1529)}.F1KBNa_diffBody [data-diff-search=current]{background-image:linear-gradient(#facc1552,#facc1552)}.F1KBNa_blockFlash{z-index:1;box-sizing:border-box;border:2px solid var(--dsw-alias-state-business-primary);pointer-events:none;border-radius:4px;animation:1s ease-out forwards F1KBNa_diffFlash;position:absolute;left:0;right:0}@keyframes F1KBNa_diffFlash{0%{opacity:1}to{opacity:0}}.F1KBNa_overviewRuler{pointer-events:none;opacity:.5;width:4px;position:absolute;top:0;bottom:0;right:0}.F1KBNa_overviewMarker{border-radius:2px;width:100%;min-height:2px;position:absolute;right:0}.F1KBNa_markerDel{background-color:var(--dsw-alias-state-error-primary)}.F1KBNa_markerAdd{background-color:var(--dsw-alias-state-success-primary)}.F1KBNa_lines{border-spacing:0;width:max-content;min-width:100%;display:table}.F1KBNa_line{height:22px;line-height:22px;display:table-row}.F1KBNa_vSpacer{display:table-row}.F1KBNa_gutter{box-sizing:border-box;text-align:right;width:44px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;user-select:none;cursor:default;padding-right:10px;display:table-cell}.F1KBNa_code{white-space:pre;display:table-cell}.F1KBNa_context{color:var(--dsw-alias-label-primary)}.F1KBNa_del{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_add{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}.F1KBNa_statusBar{box-sizing:border-box;border-top:1px solid var(--dsw-alias-border-l2);height:34px;color:var(--dsw-alias-label-tertiary);font-family:var(--dsw-font-markdown-code-block);font-variant-numeric:tabular-nums;flex:none;align-items:center;gap:8px;padding:0 8px;font-size:12px;line-height:18px;display:flex}.F1KBNa_statusAction{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);white-space:nowrap;cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_statusAction:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langSelect{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;flex:none;align-items:center;gap:4px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px;display:inline-flex}.F1KBNa_langSelect:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langLabel{text-overflow:ellipsis;white-space:nowrap;max-width:140px;overflow:hidden}.F1KBNa_notice{z-index:60;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);max-width:360px;box-shadow:var(--dsw-shadow-lv3);border-radius:10px;align-items:flex-start;gap:12px;padding:12px 14px;display:flex;position:fixed;bottom:24px;right:24px}.F1KBNa_noticeText{font:var(--dsw-font-caption);color:var(--dsw-alias-label-primary);flex:1;margin:0;line-height:1.45}.F1KBNa_noticeButton{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);font:var(--dsw-font-caption);cursor:pointer;border-radius:6px;flex:none;padding:4px 10px}.F1KBNa_noticeButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_wrap .F1KBNa_line{height:auto;min-height:22px}.F1KBNa_subline{white-space:pre;height:22px;line-height:22px;display:block;overflow:hidden}.F1KBNa_wrapActive{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_wrapActive:hover{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}.F1KBNa_splitRoot{flex-direction:column;flex:1;min-height:0;display:flex;position:relative}.F1KBNa_diffBodySplit{flex:1;min-height:0;overflow-x:hidden}.F1KBNa_splitCols{width:100%;min-width:0;display:flex}.F1KBNa_splitCol{box-sizing:border-box;flex:1 1 0;min-width:0;overflow:hidden}.F1KBNa_splitDivider{background:var(--dsw-alias-border-l2);flex:0 0 1px}.F1KBNa_splitCol .F1KBNa_gutter,.F1KBNa_splitCol .F1KBNa_code{vertical-align:top}.F1KBNa_splitHScrollRow{border-top:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;width:100%;min-width:0;display:flex}.F1KBNa_splitHScroll{flex:1 1 0;min-width:0;height:15px;overflow:auto hidden}.F1KBNa_splitHScroll::-webkit-scrollbar{height:15px}.F1KBNa_splitHScroll::-webkit-scrollbar-track{cursor:default}.F1KBNa_splitHScroll::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_splitHScrollFill{height:1px}.F1KBNa_splitLdel{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_splitLadd{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}.F1KBNa_splitRdel{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_splitRadd{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}";
11811
11915
  const tagId = "dsh-diff-approval/PendingPanel.module.css";
11812
11916
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
11813
11917
  const tag = document.createElement("style");
@@ -11817,111 +11921,115 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
11817
11921
  document.head.appendChild(tag);
11818
11922
  }
11819
11923
  var PendingPanel_module_css_default = {
11820
- "layer": "F1KBNa_layer",
11821
- "rowHead": "F1KBNa_rowHead",
11822
- "header": "F1KBNa_header",
11823
- "searchCount": "F1KBNa_searchCount",
11924
+ "kindHint": "F1KBNa_kindHint",
11925
+ "searchBar": "F1KBNa_searchBar",
11926
+ "diffPath": "F1KBNa_diffPath",
11927
+ "flexSpacer": "F1KBNa_flexSpacer",
11824
11928
  "splitRdel": "F1KBNa_splitRdel",
11825
- "blockActions": "F1KBNa_blockActions",
11826
- "badge": "F1KBNa_badge",
11827
- "fileList": "F1KBNa_fileList",
11828
- "badgeLabel": "F1KBNa_badgeLabel",
11829
- "rows": "F1KBNa_rows",
11830
11929
  "settingsRowTitle": "F1KBNa_settingsRowTitle",
11831
- "rail": "F1KBNa_rail",
11832
- "settingsPage": "F1KBNa_settingsPage",
11833
- "add": "F1KBNa_add",
11834
- "splitCols": "F1KBNa_splitCols",
11835
- "splitHScrollRow": "F1KBNa_splitHScrollRow",
11836
- "splitHScroll": "F1KBNa_splitHScroll",
11837
- "diffPath": "F1KBNa_diffPath",
11838
- "settingsRowText": "F1KBNa_settingsRowText",
11839
- "detailEmpty": "F1KBNa_detailEmpty",
11840
- "action": "F1KBNa_action",
11841
- "notice": "F1KBNa_notice",
11842
- "splitHScrollFill": "F1KBNa_splitHScrollFill",
11843
- "splitLdel": "F1KBNa_splitLdel",
11844
- "diffBodySplit": "F1KBNa_diffBodySplit",
11845
- "wrap": "F1KBNa_wrap",
11846
- "row": "F1KBNa_row",
11847
- "expand": "F1KBNa_expand",
11930
+ "settingsSelectorChevron": "F1KBNa_settingsSelectorChevron",
11931
+ "group": "F1KBNa_group",
11932
+ "iconAction": "F1KBNa_iconAction",
11848
11933
  "blockFlash": "F1KBNa_blockFlash",
11849
- "importButton": "F1KBNa_importButton",
11850
- "del": "F1KBNa_del",
11851
- "splitRoot": "F1KBNa_splitRoot",
11934
+ "overviewRuler": "F1KBNa_overviewRuler",
11935
+ "row": "F1KBNa_row",
11936
+ "close": "F1KBNa_close",
11937
+ "settingsRowDesc": "F1KBNa_settingsRowDesc",
11852
11938
  "states": "F1KBNa_states",
11853
- "note": "F1KBNa_note",
11854
- "panel": "F1KBNa_panel",
11855
- "title": "F1KBNa_title",
11856
- "settingsSelector": "F1KBNa_settingsSelector",
11939
+ "code": "F1KBNa_code",
11940
+ "kindTag": "F1KBNa_kindTag",
11941
+ "badgeCount": "F1KBNa_badgeCount",
11942
+ "badge": "F1KBNa_badge",
11943
+ "emptyState": "F1KBNa_emptyState",
11944
+ "rowPath": "F1KBNa_rowPath",
11945
+ "notice": "F1KBNa_notice",
11857
11946
  "diffBodyWrap": "F1KBNa_diffBodyWrap",
11858
- "diffBody": "F1KBNa_diffBody",
11947
+ "missingHint": "F1KBNa_missingHint",
11948
+ "resizeHandle": "F1KBNa_resizeHandle",
11949
+ "splitRoot": "F1KBNa_splitRoot",
11950
+ "expandExpanded": "F1KBNa_expandExpanded",
11951
+ "splitLadd": "F1KBNa_splitLadd",
11952
+ "settingsPage": "F1KBNa_settingsPage",
11953
+ "fullscreenBackdrop": "F1KBNa_fullscreenBackdrop",
11954
+ "layer": "F1KBNa_layer",
11955
+ "settingsSelector": "F1KBNa_settingsSelector",
11859
11956
  "readError": "F1KBNa_readError",
11860
- "bulkActions": "F1KBNa_bulkActions",
11861
- "delCount": "F1KBNa_delCount",
11957
+ "importButton": "F1KBNa_importButton",
11862
11958
  "addCount": "F1KBNa_addCount",
11863
- "diffStats": "F1KBNa_diffStats",
11864
- "close": "F1KBNa_close",
11865
- "kindHint": "F1KBNa_kindHint",
11866
- "blockPosition": "F1KBNa_blockPosition",
11867
- "searchInput": "F1KBNa_searchInput",
11868
- "overviewRuler": "F1KBNa_overviewRuler",
11869
- "vSpacer": "F1KBNa_vSpacer",
11870
11959
  "context": "F1KBNa_context",
11871
- "fullscreenBackdrop": "F1KBNa_fullscreenBackdrop",
11960
+ "header": "F1KBNa_header",
11872
11961
  "gutter": "F1KBNa_gutter",
11873
- "iconAction": "F1KBNa_iconAction",
11874
- "statusBar": "F1KBNa_statusBar",
11962
+ "confirmActions": "F1KBNa_confirmActions",
11963
+ "searchInput": "F1KBNa_searchInput",
11964
+ "importNote": "F1KBNa_importNote",
11875
11965
  "noticeText": "F1KBNa_noticeText",
11876
- "wrapActive": "F1KBNa_wrapActive",
11877
- "splitRadd": "F1KBNa_splitRadd",
11966
+ "wrap": "F1KBNa_wrap",
11967
+ "splitHScrollRow": "F1KBNa_splitHScrollRow",
11968
+ "blockActions": "F1KBNa_blockActions",
11969
+ "splitHScroll": "F1KBNa_splitHScroll",
11970
+ "splitHScrollFill": "F1KBNa_splitHScrollFill",
11971
+ "fileListFloat": "F1KBNa_fileListFloat",
11972
+ "noteCentered": "F1KBNa_noteCentered",
11973
+ "diffActions": "F1KBNa_diffActions",
11974
+ "searchCount": "F1KBNa_searchCount",
11975
+ "add": "F1KBNa_add",
11976
+ "diffStats": "F1KBNa_diffStats",
11977
+ "langLabel": "F1KBNa_langLabel",
11978
+ "detailEmpty": "F1KBNa_detailEmpty",
11979
+ "actionPrimary": "F1KBNa_actionPrimary",
11980
+ "diffBody": "F1KBNa_diffBody",
11878
11981
  "rowMeta": "F1KBNa_rowMeta",
11879
11982
  "diffHeader": "F1KBNa_diffHeader",
11880
- "footerButtons": "F1KBNa_footerButtons",
11983
+ "blockPosition": "F1KBNa_blockPosition",
11984
+ "subline": "F1KBNa_subline",
11985
+ "splitCol": "F1KBNa_splitCol",
11986
+ "missing": "F1KBNa_missing",
11987
+ "splitDivider": "F1KBNa_splitDivider",
11988
+ "rowFailed": "F1KBNa_rowFailed",
11989
+ "listScroll": "F1KBNa_listScroll",
11990
+ "actionError": "F1KBNa_actionError",
11881
11991
  "headerActions": "F1KBNa_headerActions",
11992
+ "confirmCard": "F1KBNa_confirmCard",
11882
11993
  "actionQuietDisabled": "F1KBNa_actionQuietDisabled",
11883
- "detail": "F1KBNa_detail",
11884
- "missing": "F1KBNa_missing",
11885
11994
  "markerDel": "F1KBNa_markerDel",
11886
- "settingsRowDesc": "F1KBNa_settingsRowDesc",
11887
- "langSelect": "F1KBNa_langSelect",
11888
- "importNote": "F1KBNa_importNote",
11889
- "listScroll": "F1KBNa_listScroll",
11890
- "group": "F1KBNa_group",
11995
+ "bulkActions": "F1KBNa_bulkActions",
11891
11996
  "divergedHint": "F1KBNa_divergedHint",
11892
- "splitCol": "F1KBNa_splitCol",
11893
- "resizeHandle": "F1KBNa_resizeHandle",
11894
- "actionPrimary": "F1KBNa_actionPrimary",
11895
- "diffFlash": "F1KBNa_diffFlash",
11896
- "subline": "F1KBNa_subline",
11897
- "statusAction": "F1KBNa_statusAction",
11898
- "noteCentered": "F1KBNa_noteCentered",
11899
- "actionError": "F1KBNa_actionError",
11900
11997
  "lines": "F1KBNa_lines",
11901
- "hint": "F1KBNa_hint",
11902
- "diff": "F1KBNa_diff",
11998
+ "badgeLabel": "F1KBNa_badgeLabel",
11999
+ "detail": "F1KBNa_detail",
12000
+ "splitRadd": "F1KBNa_splitRadd",
12001
+ "footerButtons": "F1KBNa_footerButtons",
12002
+ "expand": "F1KBNa_expand",
12003
+ "overviewMarker": "F1KBNa_overviewMarker",
11903
12004
  "markerAdd": "F1KBNa_markerAdd",
11904
- "code": "F1KBNa_code",
11905
- "emptyState": "F1KBNa_emptyState",
11906
- "expandExpanded": "F1KBNa_expandExpanded",
11907
- "langLabel": "F1KBNa_langLabel",
11908
- "searchBar": "F1KBNa_searchBar",
11909
- "badgeCount": "F1KBNa_badgeCount",
11910
- "diffActions": "F1KBNa_diffActions",
11911
- "splitDivider": "F1KBNa_splitDivider",
12005
+ "hint": "F1KBNa_hint",
12006
+ "line": "F1KBNa_line",
12007
+ "wrapActive": "F1KBNa_wrapActive",
12008
+ "diffBodySplit": "F1KBNa_diffBodySplit",
12009
+ "delCount": "F1KBNa_delCount",
12010
+ "confirmText": "F1KBNa_confirmText",
12011
+ "note": "F1KBNa_note",
12012
+ "rows": "F1KBNa_rows",
11912
12013
  "settingsRow": "F1KBNa_settingsRow",
11913
- "noticeButton": "F1KBNa_noticeButton",
11914
- "splitLadd": "F1KBNa_splitLadd",
11915
- "settingsSelectorChevron": "F1KBNa_settingsSelectorChevron",
11916
- "rowPath": "F1KBNa_rowPath",
11917
- "fileListFloat": "F1KBNa_fileListFloat",
11918
- "missingHint": "F1KBNa_missingHint",
11919
- "rowFailed": "F1KBNa_rowFailed",
11920
- "overviewMarker": "F1KBNa_overviewMarker",
11921
- "kindTag": "F1KBNa_kindTag",
11922
- "flexSpacer": "F1KBNa_flexSpacer",
12014
+ "diffFlash": "F1KBNa_diffFlash",
12015
+ "del": "F1KBNa_del",
12016
+ "title": "F1KBNa_title",
12017
+ "statusAction": "F1KBNa_statusAction",
12018
+ "panel": "F1KBNa_panel",
12019
+ "fileList": "F1KBNa_fileList",
12020
+ "splitCols": "F1KBNa_splitCols",
12021
+ "settingsRowText": "F1KBNa_settingsRowText",
12022
+ "diff": "F1KBNa_diff",
12023
+ "confirmBackdrop": "F1KBNa_confirmBackdrop",
12024
+ "statusBar": "F1KBNa_statusBar",
12025
+ "splitLdel": "F1KBNa_splitLdel",
11923
12026
  "split": "F1KBNa_split",
11924
- "line": "F1KBNa_line"
12027
+ "langSelect": "F1KBNa_langSelect",
12028
+ "rail": "F1KBNa_rail",
12029
+ "rowHead": "F1KBNa_rowHead",
12030
+ "action": "F1KBNa_action",
12031
+ "vSpacer": "F1KBNa_vSpacer",
12032
+ "noticeButton": "F1KBNa_noticeButton"
11925
12033
  };
11926
12034
  //#endregion
11927
12035
  //#region lib/types/client/PendingPanel.js
@@ -11960,6 +12068,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
11960
12068
  /** Total width of the two line-number gutters, subtracted from the code width
11961
12069
  * when measuring wrapped line heights. */
11962
12070
  const WRAP_GUTTERS_PX = 88;
12071
+ /** The dsh shell's sidebar auto-collapse breakpoint (ui-layout columns.ts):
12072
+ * below it the sidebar auto-collapses, and the file list floats on the same
12073
+ * breakpoint so the two stay consistent. */
12074
+ const SIDEBAR_AUTO_COLLAPSE_PX = 1024;
11963
12075
  /** A shared canvas for measuring wrapped line heights (CPU-only, no DOM reflow). */
11964
12076
  let measureCanvas;
11965
12077
  /**
@@ -12551,12 +12663,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12551
12663
  const clamped = Math.max(0, Math.min(target, body.scrollHeight - body.clientHeight));
12552
12664
  if (body.scrollTop !== clamped) body.scrollTop = clamped;
12553
12665
  setScrollTop(clamped);
12554
- }, [
12555
- model,
12556
- focus,
12557
- flashKey,
12558
- pairCount
12559
- ]);
12666
+ }, [focus, flashKey]);
12560
12667
  const onScroll = () => {
12561
12668
  setScrollTop(bodyRef.current?.scrollTop ?? 0);
12562
12669
  };
@@ -12951,7 +13058,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12951
13058
  title: failedMessage,
12952
13059
  children: t("row.failed")
12953
13060
  }),
12954
- (0, react_jsx_runtime.jsxs)("span", {
13061
+ (stats.added !== 0 || stats.removed !== 0) && (0, react_jsx_runtime.jsxs)("span", {
12955
13062
  className: PendingPanel_module_css_default.rowMeta,
12956
13063
  children: [(0, react_jsx_runtime.jsx)("span", {
12957
13064
  className: PendingPanel_module_css_default.addCount,
@@ -12967,7 +13074,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12967
13074
  });
12968
13075
  }
12969
13076
  /** The selected file's diff, actions, jump controls, and copy toolbar. */
12970
- function PendingDiff({ file, busy, workspacePath, jumpSignal, undoFlash, failedMessage, onPasteReference, t, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen, floatMode, floatOpen, onToggleFileList }) {
13077
+ function PendingDiff({ file, busy, workspacePath, jumpSignal, undoFlash, failedMessage, onPasteReference, onToast, t, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen, floatMode, floatOpen, onToggleFileList }) {
12971
13078
  const [langOverride, setLangOverride] = (0, react.useState)(void 0);
12972
13079
  const [langMenuOpen, setLangMenuOpen] = (0, react.useState)(false);
12973
13080
  const langMenuItems = (0, react.useMemo)(() => [{
@@ -13071,6 +13178,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13071
13178
  const [flashKey, setFlashKey] = (0, react.useState)(0);
13072
13179
  (0, react.useEffect)(() => {
13073
13180
  setFocus(0);
13181
+ setScrollTick((tick) => tick + 1);
13074
13182
  bodyRef.current?.focus();
13075
13183
  setFlashKey((key) => key + 1);
13076
13184
  setHoveredBlock(void 0);
@@ -13091,6 +13199,32 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13091
13199
  const blockRanges = (0, react.useMemo)(() => {
13092
13200
  return model.blocks.map((block) => blockRangesOf(model.diff.rows, block));
13093
13201
  }, [model]);
13202
+ const coveredBlockIndices = (0, react.useMemo)(() => {
13203
+ if (selection === void 0 || splitView) return [];
13204
+ const covered = [];
13205
+ for (let index = 0; index < model.blocks.length; index++) {
13206
+ const block = model.blocks[index];
13207
+ if (selection.start <= block.start && block.end <= selection.end) covered.push(index);
13208
+ }
13209
+ return covered;
13210
+ }, [
13211
+ selection,
13212
+ splitView,
13213
+ model
13214
+ ]);
13215
+ const selectionRange = (0, react.useMemo)(() => {
13216
+ if (coveredBlockIndices.length === 0) return void 0;
13217
+ const firstIndex = coveredBlockIndices[0];
13218
+ const lastIndex = coveredBlockIndices[coveredBlockIndices.length - 1];
13219
+ if (firstIndex === void 0 || lastIndex === void 0) return void 0;
13220
+ const first = model.blocks[firstIndex];
13221
+ const last = model.blocks[lastIndex];
13222
+ if (first === void 0 || last === void 0) return void 0;
13223
+ return blockRangesOf(model.diff.rows, {
13224
+ start: first.start,
13225
+ end: last.end
13226
+ });
13227
+ }, [coveredBlockIndices, model]);
13094
13228
  const searchMatches = (0, react.useMemo)(() => {
13095
13229
  if (searchQuery === "") return [];
13096
13230
  const lower = searchQuery.toLowerCase();
@@ -13196,6 +13330,13 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13196
13330
  const visibleRows = rows.slice(start, end);
13197
13331
  const blockEnd = hoveredBlock === void 0 ? void 0 : model.blocks[hoveredBlock]?.end;
13198
13332
  const blockActionsTop = blockEnd === void 0 ? 0 : Math.min(offsetOf(blockEnd + 1), Math.max(0, totalHeight - BLOCK_ACTIONS_FRAME_PX));
13333
+ const selectionBlockEnd = (() => {
13334
+ if (coveredBlockIndices.length === 0) return void 0;
13335
+ const lastIndex = coveredBlockIndices[coveredBlockIndices.length - 1];
13336
+ if (lastIndex === void 0) return void 0;
13337
+ return model.blocks[lastIndex]?.end;
13338
+ })();
13339
+ const selectionActionsTop = selectionBlockEnd === void 0 ? 0 : Math.min(offsetOf(selectionBlockEnd + 1), Math.max(0, totalHeight - BLOCK_ACTIONS_FRAME_PX));
13199
13340
  const widestLine = (0, react.useMemo)(() => {
13200
13341
  let widest = 0;
13201
13342
  for (const row of model.diff.rows) if (row.text.length > widest) widest = row.text.length;
@@ -13239,10 +13380,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13239
13380
  if (body.scrollTop !== clamped) body.scrollTop = clamped;
13240
13381
  setScrollTop(clamped);
13241
13382
  }, [
13242
- model,
13243
13383
  focus,
13244
13384
  scrollTick,
13245
- rowCount,
13246
13385
  rowOffsets === null
13247
13386
  ]);
13248
13387
  const jump = (direction) => {
@@ -13278,10 +13417,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13278
13417
  setScrollTick((tick) => tick + 1);
13279
13418
  setFlashKey((key) => key + 1);
13280
13419
  };
13281
- const handleBlockAction = async (action) => {
13282
- if (busy || hoveredBlock === void 0) return;
13283
- const operated = hoveredBlock;
13284
- const range = blockRanges[operated];
13420
+ const runBlockAction = async (action, range, operated) => {
13285
13421
  await (action === "keep" ? onBlockKeep(file.sessionId, file.id, range) : onBlockRevert(file.sessionId, file.id, range));
13286
13422
  const count = model.blocks.length;
13287
13423
  if (count === 0) return;
@@ -13291,6 +13427,18 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13291
13427
  setScrollTick((tick) => tick + 1);
13292
13428
  setFlashKey((key) => key + 1);
13293
13429
  };
13430
+ const handleBlockAction = async (action) => {
13431
+ if (busy || hoveredBlock === void 0) return;
13432
+ const operated = hoveredBlock;
13433
+ const range = blockRanges[operated];
13434
+ await runBlockAction(action, range, operated);
13435
+ };
13436
+ const handleSelectionAction = async (action) => {
13437
+ if (busy || selectionRange === void 0) return;
13438
+ const firstCovered = coveredBlockIndices[0];
13439
+ if (firstCovered === void 0) return;
13440
+ await runBlockAction(action, selectionRange, firstCovered);
13441
+ };
13294
13442
  (0, react.useEffect)(() => {
13295
13443
  if (jumpSignal === 0) return;
13296
13444
  jumpBlock(1);
@@ -13329,16 +13477,22 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13329
13477
  })();
13330
13478
  const copySelection = (0, react.useCallback)(async () => {
13331
13479
  if (selectionReference === void 0) return;
13480
+ if (pasteOnCopyEnabled()) {
13481
+ onPasteReference(file.sessionId, selectionReference);
13482
+ return;
13483
+ }
13332
13484
  if (!await (0, _deepseek_ai_dsh_client_ui_primitives.writeClipboard)(selectionReference)) return;
13333
13485
  setCopied(true);
13334
- if (pasteOnCopyEnabled()) onPasteReference(file.sessionId, selectionReference);
13486
+ onToast(t("action.copied"));
13335
13487
  window.setTimeout(() => {
13336
13488
  setCopied(false);
13337
13489
  }, 1500);
13338
13490
  }, [
13339
13491
  file.sessionId,
13340
13492
  onPasteReference,
13341
- selectionReference
13493
+ onToast,
13494
+ selectionReference,
13495
+ t
13342
13496
  ]);
13343
13497
  (0, react.useEffect)(() => {
13344
13498
  const onKeyDown = (event) => {
@@ -13458,7 +13612,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13458
13612
  children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconListPenOutline16, { size: 14 })
13459
13613
  })
13460
13614
  }),
13461
- (0, react_jsx_runtime.jsx)("span", {
13615
+ (model.diff.added !== 0 || model.diff.removed !== 0) && (0, react_jsx_runtime.jsx)("span", {
13462
13616
  className: PendingPanel_module_css_default.diffStats,
13463
13617
  children: t("panel.stats", {
13464
13618
  added: model.diff.added,
@@ -13600,7 +13754,30 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13600
13754
  "aria-hidden": "true"
13601
13755
  })
13602
13756
  ]
13603
- }), hoveredBlock !== void 0 && model.blocks[hoveredBlock] !== void 0 && (0, react_jsx_runtime.jsxs)("div", {
13757
+ }), selectionRange !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
13758
+ className: PendingPanel_module_css_default.blockActions,
13759
+ "data-diff-selection-actions": true,
13760
+ style: { top: selectionActionsTop },
13761
+ children: [(0, react_jsx_runtime.jsx)("button", {
13762
+ type: "button",
13763
+ className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
13764
+ "data-diff-selection-keep": true,
13765
+ disabled: busy,
13766
+ onClick: () => {
13767
+ handleSelectionAction("keep");
13768
+ },
13769
+ children: t("action.keep")
13770
+ }), (0, react_jsx_runtime.jsx)("button", {
13771
+ type: "button",
13772
+ className: PendingPanel_module_css_default.action,
13773
+ "data-diff-selection-revert": true,
13774
+ disabled: busy,
13775
+ onClick: () => {
13776
+ handleSelectionAction("revert");
13777
+ },
13778
+ children: t("action.revert")
13779
+ })]
13780
+ }) : hoveredBlock !== void 0 && model.blocks[hoveredBlock] !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
13604
13781
  className: PendingPanel_module_css_default.blockActions,
13605
13782
  "data-diff-block-actions": true,
13606
13783
  style: { top: blockActionsTop },
@@ -13656,7 +13833,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13656
13833
  children: t("action.revert")
13657
13834
  })
13658
13835
  ]
13659
- })]
13836
+ }) : null]
13660
13837
  }),
13661
13838
  focusedBlock !== void 0 && flashKey > 0 && (0, react_jsx_runtime.jsx)("div", {
13662
13839
  className: PendingPanel_module_css_default.blockFlash,
@@ -13818,7 +13995,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13818
13995
  });
13819
13996
  }
13820
13997
  /** Render the pending-edit review panel and its unified footer action. */
13821
- function PendingPanel({ wide, useSessions, usePending, onRefresh, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen, onPasteReference, onUndo, onRedo, onImportVcs, onAckRedoCleared, t }) {
13998
+ function PendingPanel({ wide, useSessions, usePending, onRefresh, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen, onPasteReference, onUndo, onRedo, onImportVcs, onAckRedoCleared, onAckJustResolved, collapseSidebar, t }) {
13822
13999
  const current = useSessions((state) => state.current);
13823
14000
  const currentBlank = useSessions((state) => {
13824
14001
  const id = state.current;
@@ -13846,8 +14023,12 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13846
14023
  const [importToast, setImportToast] = (0, react.useState)(null);
13847
14024
  /** A transient banner for a keep/revert failure. */
13848
14025
  const [actionToast, setActionToast] = (0, react.useState)(null);
14026
+ /** A transient banner confirming a reference was copied to the clipboard. */
14027
+ const [copyToast, setCopyToast] = (0, react.useState)(null);
13849
14028
  /** Whether the redo-cleared notice is showing (bottom-right, OK to dismiss). */
13850
14029
  const [redoClearedNotice, setRedoClearedNotice] = (0, react.useState)(false);
14030
+ /** A file whose last block just resolved, pending a remove-or-keep choice. */
14031
+ const [confirmDismiss, setConfirmDismiss] = (0, react.useState)(null);
13851
14032
  /** Bottom offset tracking the chat composer's top edge so the input stays visible. */
13852
14033
  const [bottomPx, setBottomPx] = (0, react.useState)(FALLBACK_BOTTOM_PX);
13853
14034
  /** Fullscreen expanded: the panel bottom pins to the window edge, ignoring the composer offset. */
@@ -13860,6 +14041,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13860
14041
  /** The review panel's width, measured so the file list can collapse when it
13861
14042
  * would take more than a third of it (browser zoom / window resize). */
13862
14043
  const [panelWidth, setPanelWidth] = (0, react.useState)(0);
14044
+ const [viewportWidth, setViewportWidth] = (0, react.useState)(() => window.innerWidth);
13863
14045
  const panelRef = (0, react.useRef)(null);
13864
14046
  const splitRef = (0, react.useRef)(null);
13865
14047
  /** The code scroll box's bounds within the split, so the floating card is
@@ -13887,10 +14069,19 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13887
14069
  observer?.disconnect();
13888
14070
  };
13889
14071
  }, [open]);
13890
- const floatMode = panelWidth > 0 && listWidth > panelWidth / 3;
14072
+ const floatMode = viewportWidth < SIDEBAR_AUTO_COLLAPSE_PX;
13891
14073
  const toggleFileList = () => {
13892
14074
  setFloatOpen((value) => !value);
13893
14075
  };
14076
+ (0, react.useEffect)(() => {
14077
+ const onResize = () => {
14078
+ setViewportWidth(window.innerWidth);
14079
+ };
14080
+ window.addEventListener("resize", onResize);
14081
+ return () => {
14082
+ window.removeEventListener("resize", onResize);
14083
+ };
14084
+ }, []);
13894
14085
  (0, react.useEffect)(() => {
13895
14086
  if (!floatMode || !floatOpen) return;
13896
14087
  const el = panelRef.current;
@@ -13992,6 +14183,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13992
14183
  if (fresh.length > 0) setActionToast(fresh[0][1]);
13993
14184
  failedRef.current = current;
13994
14185
  }, [snapshot.failed]);
14186
+ (0, react.useEffect)(() => {
14187
+ if (snapshot.justResolved === void 0) return;
14188
+ setConfirmDismiss(snapshot.justResolved);
14189
+ onAckJustResolved();
14190
+ }, [snapshot.justResolved, onAckJustResolved]);
13995
14191
  (0, react.useEffect)(() => {
13996
14192
  if (!open) return;
13997
14193
  if (selected !== "" && files.some((file) => file.id === selected)) return;
@@ -14022,6 +14218,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14022
14218
  }
14023
14219
  };
14024
14220
  const toggleOpen = () => {
14221
+ if (!open) collapseSidebar();
14025
14222
  setOpen((value) => !value);
14026
14223
  };
14027
14224
  (0, react.useEffect)(() => {
@@ -14048,6 +14245,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14048
14245
  }
14049
14246
  }, entry.id);
14050
14247
  const selectedFile = files.find((file) => file.id === selected);
14248
+ /** The file whose removal is being confirmed, if any. */
14249
+ const confirmFile = confirmDismiss === null ? void 0 : files.find((file) => file.id === confirmDismiss);
14051
14250
  const fileListBody = (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {
14052
14251
  className: PendingPanel_module_css_default.listScroll,
14053
14252
  children: files.length > 0 && (0, react_jsx_runtime.jsxs)("section", { children: [(0, react_jsx_runtime.jsx)("h3", {
@@ -14115,6 +14314,58 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14115
14314
  handleUndo,
14116
14315
  handleRedo
14117
14316
  ]);
14317
+ (0, react.useEffect)(() => {
14318
+ if (!open || current === void 0) return;
14319
+ const onKeyDown = (event) => {
14320
+ if (!(event.ctrlKey || event.metaKey) || event.altKey) return;
14321
+ if (event.key.toLowerCase() !== "tab") return;
14322
+ const target = event.target;
14323
+ if (target instanceof Element && target.closest("input, textarea, [contenteditable=\"true\"]") !== null) return;
14324
+ if (files.length === 0) return;
14325
+ event.preventDefault();
14326
+ const index = files.findIndex((file) => file.id === selected);
14327
+ const direction = event.shiftKey ? -1 : 1;
14328
+ const next = files[(index + direction + files.length) % files.length];
14329
+ if (next !== void 0) setSelected(next.id);
14330
+ };
14331
+ window.addEventListener("keydown", onKeyDown, true);
14332
+ return () => {
14333
+ window.removeEventListener("keydown", onKeyDown, true);
14334
+ };
14335
+ }, [
14336
+ open,
14337
+ current,
14338
+ files,
14339
+ selected
14340
+ ]);
14341
+ (0, react.useEffect)(() => {
14342
+ const onKeyDown = (event) => {
14343
+ if (!matchesShortcut(event, quickSummonKey())) return;
14344
+ const target = event.target;
14345
+ if (target instanceof Element && target.closest("input, textarea, [contenteditable=\"true\"]") !== null) return;
14346
+ event.preventDefault();
14347
+ if (!open) collapseSidebar();
14348
+ setOpen((value) => !value);
14349
+ };
14350
+ window.addEventListener("keydown", onKeyDown, true);
14351
+ return () => {
14352
+ window.removeEventListener("keydown", onKeyDown, true);
14353
+ };
14354
+ }, [open, collapseSidebar]);
14355
+ (0, react.useEffect)(() => {
14356
+ if (!open) return;
14357
+ const onKeyDown = (event) => {
14358
+ if (event.key !== "Escape") return;
14359
+ const target = event.target;
14360
+ if (target instanceof Element && target.closest("input, textarea, [contenteditable=\"true\"]") !== null) return;
14361
+ event.preventDefault();
14362
+ setOpen(false);
14363
+ };
14364
+ window.addEventListener("keydown", onKeyDown, true);
14365
+ return () => {
14366
+ window.removeEventListener("keydown", onKeyDown, true);
14367
+ };
14368
+ }, [open]);
14118
14369
  /** Drag the list/detail divider; width follows the pointer within its bounds. */
14119
14370
  const startResize = (event) => {
14120
14371
  if (event.button !== 0) return;
@@ -14156,162 +14407,207 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14156
14407
  setActionToast(null);
14157
14408
  }
14158
14409
  }),
14159
- open && expanded && (0, react_jsx_runtime.jsx)("div", {
14410
+ copyToast !== null && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
14411
+ text: copyToast,
14412
+ onDone: () => {
14413
+ setCopyToast(null);
14414
+ }
14415
+ }),
14416
+ open && (0, react_dom.createPortal)((0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [expanded && (0, react_jsx_runtime.jsx)("div", {
14160
14417
  className: PendingPanel_module_css_default.fullscreenBackdrop,
14161
14418
  "data-diff-fullscreen-backdrop": true
14162
- }),
14163
- open && (0, react_jsx_runtime.jsxs)("section", {
14419
+ }), (0, react_jsx_runtime.jsxs)("section", {
14164
14420
  className: PendingPanel_module_css_default.panel,
14165
14421
  ref: panelRef,
14166
14422
  style: { bottom: expanded ? PANEL_INSET_PX : bottomPx },
14167
14423
  "data-diff-approval-panel": true,
14168
14424
  "aria-label": t("panel.title"),
14169
- children: [(0, react_jsx_runtime.jsxs)("header", {
14170
- className: PendingPanel_module_css_default.header,
14171
- children: [(0, react_jsx_runtime.jsx)("span", {
14172
- className: PendingPanel_module_css_default.title,
14173
- children: t("panel.title")
14174
- }), (0, react_jsx_runtime.jsxs)("div", {
14175
- className: PendingPanel_module_css_default.headerActions,
14176
- children: [
14177
- (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
14178
- label: t("action.settings"),
14179
- side: "bottom",
14180
- delayMs: 500,
14181
- children: (0, react_jsx_runtime.jsx)("button", {
14182
- type: "button",
14183
- className: PendingPanel_module_css_default.expand,
14184
- "data-diff-approval-settings": true,
14185
- "aria-label": t("action.settings"),
14186
- onClick: () => {
14187
- setOpen(false);
14188
- openSettingsSection(t("settings.tabLabel"));
14189
- },
14190
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSettingsOutline16, { size: 14 })
14425
+ children: [
14426
+ (0, react_jsx_runtime.jsxs)("header", {
14427
+ className: PendingPanel_module_css_default.header,
14428
+ children: [(0, react_jsx_runtime.jsx)("span", {
14429
+ className: PendingPanel_module_css_default.title,
14430
+ children: t("panel.title")
14431
+ }), (0, react_jsx_runtime.jsxs)("div", {
14432
+ className: PendingPanel_module_css_default.headerActions,
14433
+ children: [
14434
+ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
14435
+ label: t("action.settings"),
14436
+ side: "bottom",
14437
+ delayMs: 500,
14438
+ children: (0, react_jsx_runtime.jsx)("button", {
14439
+ type: "button",
14440
+ className: PendingPanel_module_css_default.expand,
14441
+ "data-diff-approval-settings": true,
14442
+ "aria-label": t("action.settings"),
14443
+ onClick: () => {
14444
+ setOpen(false);
14445
+ openSettingsSection(t("settings.tabLabel"));
14446
+ },
14447
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSettingsOutline16, { size: 14 })
14448
+ })
14449
+ }),
14450
+ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
14451
+ label: t(expanded ? "action.exitFullscreen" : "action.expand"),
14452
+ side: "bottom",
14453
+ delayMs: 500,
14454
+ children: (0, react_jsx_runtime.jsx)("button", {
14455
+ type: "button",
14456
+ className: expanded ? `${PendingPanel_module_css_default.expand} ${PendingPanel_module_css_default.expandExpanded}` : PendingPanel_module_css_default.expand,
14457
+ "data-diff-approval-expand": true,
14458
+ "aria-label": t(expanded ? "action.exitFullscreen" : "action.expand"),
14459
+ onClick: () => {
14460
+ if (!expanded) collapseSidebar();
14461
+ setExpanded((value) => !value);
14462
+ },
14463
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFullscreenOutline16, { size: 14 })
14464
+ })
14465
+ }),
14466
+ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
14467
+ label: t("action.close"),
14468
+ side: "bottom",
14469
+ delayMs: 500,
14470
+ children: (0, react_jsx_runtime.jsx)("button", {
14471
+ type: "button",
14472
+ className: PendingPanel_module_css_default.close,
14473
+ "data-diff-approval-close": true,
14474
+ "aria-label": t("action.close"),
14475
+ onClick: () => {
14476
+ setOpen(false);
14477
+ },
14478
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, { size: 14 })
14479
+ })
14191
14480
  })
14481
+ ]
14482
+ })]
14483
+ }),
14484
+ snapshot.error !== void 0 || !snapshot.read || files.length === 0 ? (0, react_jsx_runtime.jsxs)("div", {
14485
+ className: PendingPanel_module_css_default.states,
14486
+ children: [
14487
+ snapshot.error !== void 0 && (0, react_jsx_runtime.jsx)("p", {
14488
+ className: PendingPanel_module_css_default.readError,
14489
+ role: "alert",
14490
+ children: t("panel.readFailed", { message: snapshot.error })
14192
14491
  }),
14193
- (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
14194
- label: t(expanded ? "action.exitFullscreen" : "action.expand"),
14195
- side: "bottom",
14196
- delayMs: 500,
14197
- children: (0, react_jsx_runtime.jsx)("button", {
14198
- type: "button",
14199
- className: expanded ? `${PendingPanel_module_css_default.expand} ${PendingPanel_module_css_default.expandExpanded}` : PendingPanel_module_css_default.expand,
14200
- "data-diff-approval-expand": true,
14201
- "aria-label": t(expanded ? "action.exitFullscreen" : "action.expand"),
14202
- onClick: () => {
14203
- setExpanded((value) => !value);
14492
+ !snapshot.read && snapshot.error === void 0 && (0, react_jsx_runtime.jsx)("p", {
14493
+ className: PendingPanel_module_css_default.note,
14494
+ children: t("panel.loading")
14495
+ }),
14496
+ snapshot.read && snapshot.error === void 0 && files.length === 0 && (0, react_jsx_runtime.jsxs)("div", {
14497
+ className: PendingPanel_module_css_default.emptyState,
14498
+ children: [
14499
+ (0, react_jsx_runtime.jsx)("p", {
14500
+ className: `${PendingPanel_module_css_default.note} ${PendingPanel_module_css_default.noteCentered}`,
14501
+ children: t("panel.empty")
14502
+ }),
14503
+ (0, react_jsx_runtime.jsx)("button", {
14504
+ type: "button",
14505
+ className: PendingPanel_module_css_default.importButton,
14506
+ "data-diff-import-vcs": true,
14507
+ disabled: importBusy,
14508
+ onClick: () => {
14509
+ runImportVcs();
14510
+ },
14511
+ children: importBusy ? t("action.importVcsBusy") : t("action.importVcs")
14512
+ }),
14513
+ importNote !== void 0 && (0, react_jsx_runtime.jsx)("p", {
14514
+ className: PendingPanel_module_css_default.importNote,
14515
+ role: importFailed ? "alert" : void 0,
14516
+ children: importNote
14517
+ })
14518
+ ]
14519
+ })
14520
+ ]
14521
+ }) : (0, react_jsx_runtime.jsxs)("div", {
14522
+ className: PendingPanel_module_css_default.split,
14523
+ ref: splitRef,
14524
+ children: [
14525
+ !floatMode && (0, react_jsx_runtime.jsx)("nav", {
14526
+ className: PendingPanel_module_css_default.fileList,
14527
+ style: { width: listWidth },
14528
+ "data-diff-approval-file-list": true,
14529
+ children: fileListBody
14530
+ }),
14531
+ !floatMode && (0, react_jsx_runtime.jsx)("div", {
14532
+ className: PendingPanel_module_css_default.resizeHandle,
14533
+ "data-diff-resize": true,
14534
+ onMouseDown: startResize
14535
+ }),
14536
+ (0, react_jsx_runtime.jsx)("div", {
14537
+ className: PendingPanel_module_css_default.detail,
14538
+ children: selectedFile === void 0 ? (0, react_jsx_runtime.jsx)("p", {
14539
+ className: PendingPanel_module_css_default.detailEmpty,
14540
+ children: t("panel.selectHint")
14541
+ }) : (0, react_jsx_runtime.jsx)(PendingDiff, {
14542
+ file: selectedFile,
14543
+ busy: snapshot.busy.has(selectedFile.id),
14544
+ workspacePath: snapshot.workspacePath,
14545
+ jumpSignal,
14546
+ undoFlash,
14547
+ failedMessage: failed.get(selectedFile.id),
14548
+ onPasteReference,
14549
+ onToast: (text) => {
14550
+ setCopyToast(text);
14204
14551
  },
14205
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFullscreenOutline16, { size: 14 })
14552
+ t,
14553
+ onKeep,
14554
+ onRevert,
14555
+ onBlockKeep,
14556
+ onBlockRevert,
14557
+ onOpen,
14558
+ floatMode,
14559
+ floatOpen,
14560
+ onToggleFileList: toggleFileList
14206
14561
  })
14207
14562
  }),
14208
- (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
14209
- label: t("action.close"),
14210
- side: "bottom",
14211
- delayMs: 500,
14212
- children: (0, react_jsx_runtime.jsx)("button", {
14563
+ floatMode && floatOpen && files.length > 0 && floatBox !== null && (0, react_jsx_runtime.jsx)("div", {
14564
+ className: PendingPanel_module_css_default.fileListFloat,
14565
+ style: {
14566
+ left: floatBox.left + FLOAT_LIST_MARGIN_PX,
14567
+ top: floatBox.top + FLOAT_LIST_MARGIN_PX,
14568
+ width: Math.min(listWidth, Math.max(0, floatBox.width - 24)),
14569
+ height: Math.max(0, floatBox.height - 24)
14570
+ },
14571
+ "data-diff-floating-file-list": true,
14572
+ children: fileListBody
14573
+ })
14574
+ ]
14575
+ }),
14576
+ confirmFile !== void 0 && (0, react_jsx_runtime.jsx)("div", {
14577
+ className: PendingPanel_module_css_default.confirmBackdrop,
14578
+ "data-diff-confirm": true,
14579
+ children: (0, react_jsx_runtime.jsxs)("div", {
14580
+ className: PendingPanel_module_css_default.confirmCard,
14581
+ role: "dialog",
14582
+ "aria-modal": "true",
14583
+ children: [(0, react_jsx_runtime.jsx)("p", {
14584
+ className: PendingPanel_module_css_default.confirmText,
14585
+ children: t("panel.resolvedAsk", { file: basenameOf(confirmFile.path) })
14586
+ }), (0, react_jsx_runtime.jsxs)("div", {
14587
+ className: PendingPanel_module_css_default.confirmActions,
14588
+ children: [(0, react_jsx_runtime.jsx)("button", {
14213
14589
  type: "button",
14214
- className: PendingPanel_module_css_default.close,
14215
- "data-diff-approval-close": true,
14216
- "aria-label": t("action.close"),
14590
+ className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
14591
+ "data-diff-confirm-remove": true,
14217
14592
  onClick: () => {
14218
- setOpen(false);
14593
+ setConfirmDismiss(null);
14594
+ onKeep(confirmFile.sessionId, confirmFile.id);
14219
14595
  },
14220
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, { size: 14 })
14221
- })
14222
- })
14223
- ]
14224
- })]
14225
- }), snapshot.error !== void 0 || !snapshot.read || files.length === 0 ? (0, react_jsx_runtime.jsxs)("div", {
14226
- className: PendingPanel_module_css_default.states,
14227
- children: [
14228
- snapshot.error !== void 0 && (0, react_jsx_runtime.jsx)("p", {
14229
- className: PendingPanel_module_css_default.readError,
14230
- role: "alert",
14231
- children: t("panel.readFailed", { message: snapshot.error })
14232
- }),
14233
- !snapshot.read && snapshot.error === void 0 && (0, react_jsx_runtime.jsx)("p", {
14234
- className: PendingPanel_module_css_default.note,
14235
- children: t("panel.loading")
14236
- }),
14237
- snapshot.read && snapshot.error === void 0 && files.length === 0 && (0, react_jsx_runtime.jsxs)("div", {
14238
- className: PendingPanel_module_css_default.emptyState,
14239
- children: [
14240
- (0, react_jsx_runtime.jsx)("p", {
14241
- className: `${PendingPanel_module_css_default.note} ${PendingPanel_module_css_default.noteCentered}`,
14242
- children: t("panel.empty")
14243
- }),
14244
- (0, react_jsx_runtime.jsx)("button", {
14596
+ children: t("row.dismiss")
14597
+ }), (0, react_jsx_runtime.jsx)("button", {
14245
14598
  type: "button",
14246
- className: PendingPanel_module_css_default.importButton,
14247
- "data-diff-import-vcs": true,
14248
- disabled: importBusy,
14599
+ className: PendingPanel_module_css_default.action,
14600
+ "data-diff-confirm-keep": true,
14249
14601
  onClick: () => {
14250
- runImportVcs();
14602
+ setConfirmDismiss(null);
14251
14603
  },
14252
- children: importBusy ? t("action.importVcsBusy") : t("action.importVcs")
14253
- }),
14254
- importNote !== void 0 && (0, react_jsx_runtime.jsx)("p", {
14255
- className: PendingPanel_module_css_default.importNote,
14256
- role: importFailed ? "alert" : void 0,
14257
- children: importNote
14258
- })
14259
- ]
14604
+ children: t("panel.keepInList")
14605
+ })]
14606
+ })]
14260
14607
  })
14261
- ]
14262
- }) : (0, react_jsx_runtime.jsxs)("div", {
14263
- className: PendingPanel_module_css_default.split,
14264
- ref: splitRef,
14265
- children: [
14266
- !floatMode && (0, react_jsx_runtime.jsx)("nav", {
14267
- className: PendingPanel_module_css_default.fileList,
14268
- style: { width: listWidth },
14269
- "data-diff-approval-file-list": true,
14270
- children: fileListBody
14271
- }),
14272
- !floatMode && (0, react_jsx_runtime.jsx)("div", {
14273
- className: PendingPanel_module_css_default.resizeHandle,
14274
- "data-diff-resize": true,
14275
- onMouseDown: startResize
14276
- }),
14277
- (0, react_jsx_runtime.jsx)("div", {
14278
- className: PendingPanel_module_css_default.detail,
14279
- children: selectedFile === void 0 ? (0, react_jsx_runtime.jsx)("p", {
14280
- className: PendingPanel_module_css_default.detailEmpty,
14281
- children: t("panel.selectHint")
14282
- }) : (0, react_jsx_runtime.jsx)(PendingDiff, {
14283
- file: selectedFile,
14284
- busy: snapshot.busy.has(selectedFile.id),
14285
- workspacePath: snapshot.workspacePath,
14286
- jumpSignal,
14287
- undoFlash,
14288
- failedMessage: failed.get(selectedFile.id),
14289
- onPasteReference,
14290
- t,
14291
- onKeep,
14292
- onRevert,
14293
- onBlockKeep,
14294
- onBlockRevert,
14295
- onOpen,
14296
- floatMode,
14297
- floatOpen,
14298
- onToggleFileList: toggleFileList
14299
- })
14300
- }),
14301
- floatMode && floatOpen && files.length > 0 && floatBox !== null && (0, react_jsx_runtime.jsx)("div", {
14302
- className: PendingPanel_module_css_default.fileListFloat,
14303
- style: {
14304
- left: floatBox.left + FLOAT_LIST_MARGIN_PX,
14305
- top: floatBox.top + FLOAT_LIST_MARGIN_PX,
14306
- width: Math.min(listWidth, Math.max(0, floatBox.width - 24)),
14307
- height: Math.max(0, floatBox.height - 24)
14308
- },
14309
- "data-diff-floating-file-list": true,
14310
- children: fileListBody
14311
- })
14312
- ]
14313
- })]
14314
- }),
14608
+ })
14609
+ ]
14610
+ })] }), document.body),
14315
14611
  (0, react_jsx_runtime.jsx)("div", {
14316
14612
  className: PendingPanel_module_css_default.footerButtons,
14317
14613
  children: (0, react_jsx_runtime.jsxs)("button", {
@@ -14474,6 +14770,69 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14474
14770
  })]
14475
14771
  });
14476
14772
  }
14773
+ /** Build the `Modifier+...+Key` chord label from a keydown event; a bare
14774
+ * modifier key alone returns undefined (wait for the full combo). */
14775
+ function chordLabel(event) {
14776
+ const key = event.key;
14777
+ if (key === "Control" || key === "Shift" || key === "Alt" || key === "Meta") return void 0;
14778
+ const parts = [];
14779
+ if (event.ctrlKey) parts.push("Ctrl");
14780
+ if (event.altKey) parts.push("Alt");
14781
+ if (event.shiftKey) parts.push("Shift");
14782
+ if (event.metaKey) parts.push("Meta");
14783
+ parts.push(key.length === 1 ? key.toUpperCase() : key);
14784
+ return parts.join("+");
14785
+ }
14786
+ /** A button that records the next key chord (modifiers + key) as the shortcut. */
14787
+ function ShortcutRecorder({ value, onChange, dataAttribute, placeholder }) {
14788
+ const [recording, setRecording] = (0, react.useState)(false);
14789
+ return (0, react_jsx_runtime.jsxs)("button", {
14790
+ type: "button",
14791
+ className: PendingPanel_module_css_default.settingsSelector,
14792
+ onClick: () => {
14793
+ setRecording(true);
14794
+ },
14795
+ onBlur: () => {
14796
+ setRecording(false);
14797
+ },
14798
+ onKeyDown: recording ? (event) => {
14799
+ event.preventDefault();
14800
+ event.stopPropagation();
14801
+ if (event.key === "Escape") {
14802
+ setRecording(false);
14803
+ return;
14804
+ }
14805
+ const chord = chordLabel(event);
14806
+ if (chord !== void 0) {
14807
+ onChange(chord);
14808
+ setRecording(false);
14809
+ }
14810
+ } : void 0,
14811
+ [dataAttribute]: true,
14812
+ children: [recording ? placeholder : value, (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: PendingPanel_module_css_default.settingsSelectorChevron })]
14813
+ });
14814
+ }
14815
+ /** One shortcut row: title + description, chord recorder right. */
14816
+ function ShortcutRow({ title, description, value, onChange, dataAttribute, placeholder }) {
14817
+ return (0, react_jsx_runtime.jsxs)("div", {
14818
+ className: PendingPanel_module_css_default.settingsRow,
14819
+ children: [(0, react_jsx_runtime.jsxs)("div", {
14820
+ className: PendingPanel_module_css_default.settingsRowText,
14821
+ children: [(0, react_jsx_runtime.jsx)("div", {
14822
+ className: PendingPanel_module_css_default.settingsRowTitle,
14823
+ children: title
14824
+ }), (0, react_jsx_runtime.jsx)("div", {
14825
+ className: PendingPanel_module_css_default.settingsRowDesc,
14826
+ children: description
14827
+ })]
14828
+ }), (0, react_jsx_runtime.jsx)(ShortcutRecorder, {
14829
+ value,
14830
+ onChange,
14831
+ dataAttribute,
14832
+ placeholder
14833
+ })]
14834
+ });
14835
+ }
14477
14836
  /**
14478
14837
  * The plugin's preferences: auto-paste a copied reference into the input,
14479
14838
  * whether importing workspace VCS changes includes untracked files, and the
@@ -14490,6 +14849,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14490
14849
  const [tabOpen, setTabOpen] = (0, react.useState)(false);
14491
14850
  const [split, setSplitState] = (0, react.useState)(splitMode);
14492
14851
  const [splitOpen, setSplitOpen] = (0, react.useState)(false);
14852
+ const [summon, setSummonState] = (0, react.useState)(quickSummonKey);
14853
+ const setSummon = (value) => {
14854
+ setSummonState(value);
14855
+ setQuickSummonKey(value);
14856
+ };
14493
14857
  const setPasteOnCopy = (value) => {
14494
14858
  setPasteOnCopyState(value);
14495
14859
  setPasteOnCopyEnabled(value);
@@ -14548,6 +14912,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14548
14912
  onSelect: setSplit,
14549
14913
  dataAttribute: "data-diff-split-mode-select",
14550
14914
  t
14915
+ }),
14916
+ (0, react_jsx_runtime.jsx)(ShortcutRow, {
14917
+ title: t("panel.quickSummon"),
14918
+ description: t("panel.quickSummonDesc"),
14919
+ value: summon,
14920
+ onChange: setSummon,
14921
+ dataAttribute: "data-diff-quick-summon-key",
14922
+ placeholder: t("panel.recordShortcut")
14551
14923
  })
14552
14924
  ]
14553
14925
  });
@@ -14671,9 +15043,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14671
15043
  const outcome = value.outcome;
14672
15044
  if (outcome !== "kept" && outcome !== "reverted" && outcome !== "missing" && outcome !== "undone" && outcome !== "redone" && outcome !== "nothing") throw new Error("the action returned a malformed outcome");
14673
15045
  const id = value.id;
14674
- return {
15046
+ const entryId = typeof id === "string" && id.length > 0 ? id : void 0;
15047
+ return value.resolved === true ? {
15048
+ outcome,
15049
+ id: entryId,
15050
+ resolved: true
15051
+ } : {
14675
15052
  outcome,
14676
- id: typeof id === "string" && id.length > 0 ? id : void 0
15053
+ id: entryId
14677
15054
  };
14678
15055
  }
14679
15056
  /** Narrow the vcs-import endpoint's value; a malformed wire value is a failure. */
@@ -14726,11 +15103,18 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14726
15103
  };
14727
15104
  const listeners = /* @__PURE__ */ new Set();
14728
15105
  let redoCleared = false;
15106
+ let justResolved;
14729
15107
  const publish = (next) => {
14730
- snapshot = redoCleared ? {
14731
- ...next,
15108
+ let result = next;
15109
+ if (redoCleared) result = {
15110
+ ...result,
14732
15111
  redoCleared: true
14733
- } : next;
15112
+ };
15113
+ if (justResolved !== void 0) result = {
15114
+ ...result,
15115
+ justResolved
15116
+ };
15117
+ snapshot = result;
14734
15118
  for (const listener of [...listeners]) listener();
14735
15119
  };
14736
15120
  const failedOf = (value) => value.failed ?? EMPTY_FAILED;
@@ -14839,8 +15223,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14839
15223
  ...base,
14840
15224
  busy: /* @__PURE__ */ new Set([...snapshot.busy, id])
14841
15225
  });
15226
+ let value;
14842
15227
  try {
14843
- await port.blockKeep(sessionId, id, block);
15228
+ value = await port.blockKeep(sessionId, id, block);
14844
15229
  } catch (error) {
14845
15230
  markFailed(id, error instanceof Error ? error.message : String(error));
14846
15231
  publish({
@@ -14850,6 +15235,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14850
15235
  return;
14851
15236
  }
14852
15237
  clearFailed(id);
15238
+ if (value.resolved === true) justResolved = id;
14853
15239
  await this.refresh(sessionId);
14854
15240
  },
14855
15241
  async blockRevert(sessionId, id, block) {
@@ -14858,8 +15244,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14858
15244
  ...base,
14859
15245
  busy: /* @__PURE__ */ new Set([...snapshot.busy, id])
14860
15246
  });
15247
+ let value;
14861
15248
  try {
14862
- await port.blockRevert(sessionId, id, block);
15249
+ value = await port.blockRevert(sessionId, id, block);
14863
15250
  } catch (error) {
14864
15251
  markFailed(id, error instanceof Error ? error.message : String(error));
14865
15252
  publish({
@@ -14869,6 +15256,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14869
15256
  return;
14870
15257
  }
14871
15258
  clearFailed(id);
15259
+ if (value.resolved === true) justResolved = id;
14872
15260
  await this.refresh(sessionId);
14873
15261
  },
14874
15262
  async undo(sessionId) {
@@ -14907,6 +15295,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14907
15295
  }
14908
15296
  },
14909
15297
  reset() {
15298
+ justResolved = void 0;
14910
15299
  publish({
14911
15300
  read: false,
14912
15301
  files: [],
@@ -14917,6 +15306,131 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14917
15306
  redoCleared = false;
14918
15307
  const { redoCleared: _omit, ...rest } = snapshot;
14919
15308
  publish(rest);
15309
+ },
15310
+ clearJustResolved() {
15311
+ justResolved = void 0;
15312
+ const { justResolved: _omit, ...rest } = snapshot;
15313
+ publish(rest);
15314
+ }
15315
+ };
15316
+ }
15317
+ //#endregion
15318
+ //#region lib/types/client/remap-sync.js
15319
+ /**
15320
+ * Reference remapping sync: track each pending file's last-seen content and,
15321
+ * when it changes (an agent edit, a block revert, or an external adoption),
15322
+ * rewrite stale references in the current composer draft and the pending queue.
15323
+ * Pure orchestration over the pending store; the actual line remapping lives in
15324
+ * `reference.ts`.
15325
+ * @module dsh-diff-approval/client/remap-sync
15326
+ */
15327
+ /**
15328
+ * Subscribe to the pending store and remap references as each file's content
15329
+ * changes. The first observation of a file only seeds the baseline; a later
15330
+ * `newText` change remaps (draft + queue) and advances the baseline. Files that
15331
+ * leave the list drop their baseline so a future re-appearance re-baselines.
15332
+ * @param opts - the sync inputs.
15333
+ * @returns an unsubscribe function plus a direct remap verb for whole-file reverts.
15334
+ */
15335
+ function attachReferenceRemap(opts) {
15336
+ const { store, readDraft, writeDraft, readQueue, writeQueue } = opts;
15337
+ const lastContent = /* @__PURE__ */ new Map();
15338
+ const remap = (path, oldText, newText, workspacePath) => {
15339
+ const referencePath = referencePathOf(path, workspacePath);
15340
+ const draft = readDraft();
15341
+ if (draft !== void 0 && draft !== "") {
15342
+ const rewritten = remapReferences(draft, referencePath, oldText, newText);
15343
+ if (rewritten !== draft) writeDraft(rewritten);
15344
+ }
15345
+ for (const message of readQueue()) {
15346
+ let changed = false;
15347
+ const content = message.content.map((block) => {
15348
+ if (block.type !== "text" || block.text === void 0) return block;
15349
+ const rewritten = remapReferences(block.text, referencePath, oldText, newText);
15350
+ if (rewritten !== block.text) {
15351
+ changed = true;
15352
+ return {
15353
+ ...block,
15354
+ text: rewritten
15355
+ };
15356
+ }
15357
+ return block;
15358
+ });
15359
+ if (changed) writeQueue(message.id, content);
15360
+ }
15361
+ };
15362
+ const observe = () => {
15363
+ const snapshot = store.getSnapshot();
15364
+ for (const file of snapshot.files) {
15365
+ const previous = lastContent.get(file.path);
15366
+ if (previous === void 0) lastContent.set(file.path, file.newText);
15367
+ else if (previous !== file.newText) {
15368
+ remap(file.path, previous, file.newText, snapshot.workspacePath);
15369
+ lastContent.set(file.path, file.newText);
15370
+ }
15371
+ }
15372
+ for (const path of [...lastContent.keys()]) if (!snapshot.files.some((file) => file.path === path)) lastContent.delete(path);
15373
+ };
15374
+ const unsubscribe = store.subscribe(observe);
15375
+ observe();
15376
+ return {
15377
+ unsubscribe,
15378
+ remapFile: (path, oldText, newText) => {
15379
+ remap(path, oldText, newText, store.getSnapshot().workspacePath);
15380
+ }
15381
+ };
15382
+ }
15383
+ //#endregion
15384
+ //#region lib/types/client/conversation-access.js
15385
+ /**
15386
+ * Scope-addressed access to the session's composer draft and pending queue.
15387
+ * Extracted from the plugin entry so the wiring (not just the remap math) is
15388
+ * unit-testable against a faithful fake of the DSH conversation service.
15389
+ * @module dsh-diff-approval/client/conversation-access
15390
+ */
15391
+ /**
15392
+ * Resolve the current session's scoped conversation face. The scoped context
15393
+ * (`sessions.scope(id)`) carries no `conversation` inject of its own, so reading
15394
+ * it as a property (`actx.conversation`) trips Cordis's inject check and throws
15395
+ * `cannot get property "conversation" without inject`. `actx.get('conversation')`
15396
+ * bypasses that check yet still returns the traceable bound to `actx`, so its
15397
+ * verbs (e.g. `updateQueue`) resolve the right session scope.
15398
+ */
15399
+ function resolveConversation(ctx, sessionId) {
15400
+ if (sessionId === void 0) return void 0;
15401
+ const actx = ctx.get("sessions")?.scope(sessionId);
15402
+ if (actx === void 0) return void 0;
15403
+ const conversation = actx.get("conversation");
15404
+ if (conversation?.input === void 0) return void 0;
15405
+ return {
15406
+ actx,
15407
+ conversation
15408
+ };
15409
+ }
15410
+ /**
15411
+ * Build the per-call-resolved draft/queue accessor. `sessionId` is a function
15412
+ * so the accessor always addresses the *current* session, even though it is
15413
+ * handed to the remap sync once.
15414
+ */
15415
+ function conversationAccess(ctx, sessionId) {
15416
+ return {
15417
+ writeDraft: (text) => {
15418
+ const scoped = resolveConversation(ctx, sessionId());
15419
+ if (scoped === void 0) return;
15420
+ scoped.conversation.input.for(scoped.actx).setDraft(text);
15421
+ },
15422
+ readQueue: () => {
15423
+ const scoped = resolveConversation(ctx, sessionId());
15424
+ if (scoped === void 0) return [];
15425
+ return scoped.conversation.input.for(scoped.actx).state.getSnapshot().queue.filter((item) => item.placement === "queued");
15426
+ },
15427
+ writeQueue: (itemId, content) => {
15428
+ const scoped = resolveConversation(ctx, sessionId());
15429
+ if (scoped === void 0) return;
15430
+ scoped.conversation.updateQueue(itemId, {
15431
+ kind: "edit",
15432
+ content
15433
+ });
14920
15434
  }
14921
15435
  };
14922
15436
  }
@@ -14950,9 +15464,13 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14950
15464
  "panel.tabWidthDesc": "差异中制表符的缩进宽度,可选 2 / 4 / 8 个空格(默认 4),同时作用于行宽折行测量。",
14951
15465
  "panel.splitMode": "双栏对比",
14952
15466
  "panel.splitModeDesc": "开启后整文件差异用左「改前」|右「当前」双栏、逐行对齐的视图展示,默认关闭使用单栏(合并)视图。",
15467
+ "panel.quickSummon": "快速呼出",
15468
+ "panel.quickSummonDesc": "用键盘快捷键打开/关闭差异面板(默认 Ctrl+D)。点击右侧按钮后按下新的按键组合即可修改,Esc 取消。",
15469
+ "panel.recordShortcut": "按下快捷键…",
14953
15470
  "settings.tabLabel": "改动审批",
14954
15471
  "row.create": "新增文件",
14955
15472
  "row.failed": "失败",
15473
+ "row.dismiss": "移除",
14956
15474
  "row.added": "+{added}",
14957
15475
  "row.removed": "-{removed}",
14958
15476
  "action.keep": "保留",
@@ -14987,7 +15505,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14987
15505
  "action.close": "关闭",
14988
15506
  "status.kept": "已保留",
14989
15507
  "status.reverted": "已回退",
14990
- "status.missing": "该改动已不存在"
15508
+ "status.missing": "该改动已不存在",
15509
+ "panel.resolvedAsk": "「{file}」的所有改动都已处理,是否从列表移除?",
15510
+ "panel.keepInList": "保留在列表"
14991
15511
  };
14992
15512
  /** English pending-edit review messages. */
14993
15513
  const en = {
@@ -15015,9 +15535,13 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15015
15535
  "panel.tabWidthDesc": "The indent width of a tab character in the differences, as 2 / 4 / 8 spaces (default 4). Also drives the wrapped-line measurement.",
15016
15536
  "panel.splitMode": "Side-by-side view",
15017
15537
  "panel.splitModeDesc": "When on, the whole-file differences render as a side-by-side (left \"before\" | right \"current\") line-aligned view. Off (default) uses the single-column unified view.",
15538
+ "panel.quickSummon": "Quick summon",
15539
+ "panel.quickSummonDesc": "Open or close the diff panel with a keyboard shortcut (default Ctrl+D). Click the button and press a new chord to change it; Esc cancels.",
15540
+ "panel.recordShortcut": "Press keys…",
15018
15541
  "settings.tabLabel": "Diff Approval",
15019
15542
  "row.create": "New file",
15020
15543
  "row.failed": "Failed",
15544
+ "row.dismiss": "Remove",
15021
15545
  "row.added": "+{added}",
15022
15546
  "row.removed": "-{removed}",
15023
15547
  "action.keep": "Keep",
@@ -15052,17 +15576,21 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15052
15576
  "action.close": "Close",
15053
15577
  "status.kept": "Kept",
15054
15578
  "status.reverted": "Reverted",
15055
- "status.missing": "This change no longer exists"
15579
+ "status.missing": "This change no longer exists",
15580
+ "panel.resolvedAsk": "All changes in \"{file}\" are resolved. Remove it from the list?",
15581
+ "panel.keepInList": "Keep in list"
15056
15582
  };
15057
15583
  //#endregion
15058
15584
  //#region lib/types/client/index.js
15059
15585
  /** Pending-edit review panel, browser half: footer action, pending list, and whole-file diff viewer. */
15060
- /** Required services: locale, slots, the wire channel, and the current session. */
15586
+ /** Required services: locale, slots, the wire channel, the current session, and
15587
+ * the layout controller (this plugin collapses the sidebar before its modal opens). */
15061
15588
  const inject = [
15062
15589
  "slots",
15063
15590
  "locale",
15064
15591
  "connection",
15065
- "sessions"
15592
+ "sessions",
15593
+ "layout"
15066
15594
  ];
15067
15595
  /**
15068
15596
  * The dsh web-react renderer gives `div[data-slot="sidebar.footer.action"]` an
@@ -15129,6 +15657,29 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15129
15657
  }), "ui-diff-approval: dictionaries");
15130
15658
  const t = ctx.locale.bind(NS);
15131
15659
  const store = createPendingDiffStore(createDiffApprovalPort(ctx.get("connection").rpc));
15660
+ let currentSessionId;
15661
+ let remapFile = () => {};
15662
+ const access = conversationAccess(ctx, () => currentSessionId);
15663
+ ctx.effect(() => {
15664
+ const attached = attachReferenceRemap({
15665
+ store,
15666
+ readDraft: () => document.querySelector("[data-composer-card] textarea")?.value,
15667
+ writeDraft: access.writeDraft,
15668
+ readQueue: access.readQueue,
15669
+ writeQueue: access.writeQueue
15670
+ });
15671
+ remapFile = attached.remapFile;
15672
+ return attached.unsubscribe;
15673
+ }, "diff-approval: reference remap");
15674
+ const collapseSidebar = () => {
15675
+ if (window.innerWidth >= 1024) return;
15676
+ const ctxLayout = ctx.layout;
15677
+ if (ctxLayout === void 0) return;
15678
+ if (document.querySelector("[data-sidebar-collapsed]") !== null) return;
15679
+ try {
15680
+ ctxLayout.toggleSidebar();
15681
+ } catch {}
15682
+ };
15132
15683
  ctx.on("connection/reset", () => {
15133
15684
  store.reset();
15134
15685
  });
@@ -15139,10 +15690,19 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15139
15690
  inject: () => ({
15140
15691
  hooks: { pending: store },
15141
15692
  onRefresh: (sessionId) => {
15693
+ currentSessionId = sessionId;
15142
15694
  store.refresh(sessionId);
15143
15695
  },
15144
15696
  onKeep: (sessionId, path) => store.keep(sessionId, path),
15145
- onRevert: (sessionId, path) => store.revert(sessionId, path),
15697
+ onRevert: (sessionId, path) => {
15698
+ const entry = store.getSnapshot().files.find((file) => file.id === path);
15699
+ const before = entry?.newText;
15700
+ const after = entry?.oldText;
15701
+ const filePath = entry?.path;
15702
+ return store.revert(sessionId, path).then(() => {
15703
+ if (filePath !== void 0 && before !== void 0 && after !== void 0) remapFile(filePath, before, after);
15704
+ });
15705
+ },
15146
15706
  onBlockKeep: (sessionId, id, block) => store.blockKeep(sessionId, id, block),
15147
15707
  onBlockRevert: (sessionId, id, block) => store.blockRevert(sessionId, id, block),
15148
15708
  onOpen: (sessionId, id, action) => store.open(sessionId, id, action),
@@ -15150,6 +15710,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15150
15710
  onRedo: (sessionId) => store.redo(sessionId),
15151
15711
  onImportVcs: (sessionId, includeUntracked) => store.importVcs(sessionId, includeUntracked),
15152
15712
  onAckRedoCleared: () => store.clearRedoCleared(),
15713
+ onAckJustResolved: () => store.clearJustResolved(),
15153
15714
  onPasteReference: (sessionId, reference) => {
15154
15715
  const actx = ctx.get("sessions")?.scope(sessionId);
15155
15716
  if (actx === void 0) return;
@@ -15159,7 +15720,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15159
15720
  const base = textarea?.value ?? "";
15160
15721
  conversation.input.for(actx).setDraft(base === "" ? reference : `${base} ${reference}`);
15161
15722
  textarea?.focus();
15162
- }
15723
+ },
15724
+ collapseSidebar
15163
15725
  })
15164
15726
  }, PendingPanel));
15165
15727
  ctx.slots.inject("settings.section", () => ctx.slots.register({