dsh-diff-approval 0.14.0 → 0.15.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
@@ -535,7 +535,10 @@ window.__ModuleLoader__.load({
535
535
  return value;
536
536
  }
537
537
  };
538
- new ArrayDiff();
538
+ const arrayDiff = new ArrayDiff();
539
+ function diffArrays(oldArr, newArr, options) {
540
+ return arrayDiff.diff(oldArr, newArr, options);
541
+ }
539
542
  //#endregion
540
543
  //#region node_modules/.pnpm/diff@9.0.0/node_modules/diff/libesm/patch/create.js
541
544
  function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
@@ -722,6 +725,246 @@ window.__ModuleLoader__.load({
722
725
  added
723
726
  };
724
727
  }
728
+ /** Minimum similarity for a del/add pair to receive an intra-line diff. */
729
+ const INTRA_SIMILARITY_THRESHOLD = .4;
730
+ /** Lines longer than this are skipped (a single pathological line would make the
731
+ * token-diff O(n²) and only ever show a noise floor). Mirrors the highlighting
732
+ * cap so a review stays bounded. */
733
+ const INTRA_MAX_LINE_LENGTH = 2e3;
734
+ /** A similarity-alignment block larger than this many cell-and-compare pairs
735
+ * falls back to by-order pairing: the O(n·m) scan and DP would stall on a
736
+ * whole-file rewrite for no benefit. */
737
+ const INTRA_MAX_ALIGN_CELLS = 8192;
738
+ const WORD_CHAR_RE = /[\p{L}\p{N}_]/u;
739
+ /** CJK characters — Chinese han, Japanese kana, CJK fullwidth forms. Each is an
740
+ * independent unit (there is no whitespace word boundary), so one token each. */
741
+ function isCJKCode$1(cp) {
742
+ return cp >= 12352 && cp <= 12543 || cp >= 13312 && cp <= 19903 || cp >= 19968 && cp <= 40959 || cp >= 63744 && cp <= 64255 || cp >= 65072 && cp <= 65103 || cp >= 65280 && cp <= 65519 || cp >= 131072 && cp <= 195103;
743
+ }
744
+ /** Space, tab, or the ideographic space — whitespace is a break opportunity. */
745
+ function isSpaceCode$1(cp) {
746
+ return cp === 32 || cp === 9 || cp === 12288;
747
+ }
748
+ /**
749
+ * Tokenize a line for an intra-line diff, into a lossless array of tokens whose
750
+ * concatenation equals the input. Word-based for space-delimited scripts: a
751
+ * maximal run of letters/numbers/underscore (any script except CJK) is one
752
+ * token, so a whole edited word stays a single run instead of per-character.
753
+ * Each CJK character is its own token (there is no word boundary), as is each
754
+ * punctuation/symbol character (a run of different punctuation carries no
755
+ * meaning, so it diffs atomically), while a maximal whitespace run stays one
756
+ * token as a natural break. This yields clean word-level highlights for English
757
+ * and per-character precision for CJK and punctuation.
758
+ * @param text - the line's content.
759
+ * @returns the tokens.
760
+ */
761
+ function tokenizeLine(text) {
762
+ const tokens = [];
763
+ let cur = "";
764
+ let runKind;
765
+ const flush = () => {
766
+ if (cur !== "") {
767
+ tokens.push(cur);
768
+ cur = "";
769
+ }
770
+ };
771
+ for (const ch of text) {
772
+ const cp = ch.codePointAt(0) ?? 0;
773
+ const word = WORD_CHAR_RE.test(ch);
774
+ if (isCJKCode$1(cp) || !word && !isSpaceCode$1(cp)) {
775
+ flush();
776
+ runKind = void 0;
777
+ tokens.push(ch);
778
+ continue;
779
+ }
780
+ const kind = word ? "word" : "space";
781
+ if (kind !== runKind) {
782
+ flush();
783
+ runKind = kind;
784
+ }
785
+ cur += ch;
786
+ }
787
+ flush();
788
+ return tokens;
789
+ }
790
+ /**
791
+ * Raw similarity of a del/add line pair in `[0, 1]`, or `-1` when the pair
792
+ * cannot be meaningfully compared (identical lines, either side empty, or over
793
+ * the length cap). Used both by the intra-line gate and by the similarity
794
+ * alignment, so the two always agree on what counts as "changed".
795
+ * @param oldText - the removed side's line text.
796
+ * @param newText - the added side's line text.
797
+ * @returns the similarity ratio, or `-1` when incomparable.
798
+ */
799
+ function lineSimilarity(oldText, newText) {
800
+ if (oldText === newText || oldText === "" || newText === "") return -1;
801
+ if (oldText.length > INTRA_MAX_LINE_LENGTH || newText.length > INTRA_MAX_LINE_LENGTH) return -1;
802
+ return 2 * diffArrays(tokenizeLine(oldText), tokenizeLine(newText)).reduce((sum, change) => change.removed || change.added ? sum : sum + change.value.join("").length, 0) / (oldText.length + newText.length);
803
+ }
804
+ /**
805
+ * Compute the intra-line runs for one del/add line pair, or `undefined` when
806
+ * the pair should not be annotated: identical lines (no internal change) or
807
+ * lines too dissimilar to be a modification (a rewrite, not an edit).
808
+ * Word-based via the `diff` package's `diffArrays` over `tokenizeLine`'s
809
+ * tokens, so an English edit highlights whole changed words and a CJK edit
810
+ * highlights the individual changed characters.
811
+ * @param oldText - the removed side's line text.
812
+ * @param newText - the added side's line text.
813
+ * @returns the del-side and add-side runs, or `undefined` to skip annotation.
814
+ */
815
+ function intraRunsOf(oldText, newText) {
816
+ if (lineSimilarity(oldText, newText) < INTRA_SIMILARITY_THRESHOLD) return void 0;
817
+ const changes = diffArrays(tokenizeLine(oldText), tokenizeLine(newText));
818
+ const del = [];
819
+ const add = [];
820
+ for (const change of changes) {
821
+ const text = change.value.join("");
822
+ if (change.removed) del.push({
823
+ text,
824
+ kind: "del"
825
+ });
826
+ else if (change.added) add.push({
827
+ text,
828
+ kind: "add"
829
+ });
830
+ else {
831
+ del.push({
832
+ text,
833
+ kind: "same"
834
+ });
835
+ add.push({
836
+ text,
837
+ kind: "same"
838
+ });
839
+ }
840
+ }
841
+ if (!del.some((run) => run.kind === "del") && !add.some((run) => run.kind === "add")) return void 0;
842
+ return {
843
+ del,
844
+ add
845
+ };
846
+ }
847
+ /**
848
+ * Align a del run with the following add run. By order (the baseline) pairs
849
+ * `del[i]`↔`add[i]`. With similarity alignment, an order-preserving best match
850
+ * pairs each del with the add that maximises total similarity, keeping a pair
851
+ * only when it clears the similarity threshold — so a lone insert or delete in
852
+ * a mixed block stays unaligned instead of being forced onto a wrong line.
853
+ * @param delRows - the run's del rows (index + text).
854
+ * @param addRows - the run's add rows (index + text).
855
+ * @param alignBySimilarity - whether to use the similarity-based matching.
856
+ * @returns the aligned pairs and the unmatched sides.
857
+ */
858
+ function alignChangedBlock(delRows, addRows, alignBySimilarity) {
859
+ const byOrder = () => {
860
+ const min = Math.min(delRows.length, addRows.length);
861
+ const pairs = [];
862
+ for (let i = 0; i < min; i++) pairs.push({
863
+ delIndex: delRows[i].index,
864
+ addIndex: addRows[i].index
865
+ });
866
+ return {
867
+ pairs,
868
+ delOnly: delRows.slice(min).map((row) => row.index),
869
+ addOnly: addRows.slice(min).map((row) => row.index),
870
+ usedSimilarity: false
871
+ };
872
+ };
873
+ if (!alignBySimilarity) return byOrder();
874
+ const n = delRows.length;
875
+ const m = addRows.length;
876
+ if (n * m > INTRA_MAX_ALIGN_CELLS) return byOrder();
877
+ const sim = [];
878
+ for (let i = 0; i < n; i++) {
879
+ const row = [];
880
+ for (let j = 0; j < m; j++) row.push(lineSimilarity(delRows[i].text, addRows[j].text));
881
+ sim.push(row);
882
+ }
883
+ const dp = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));
884
+ for (let i = 1; i <= n; i++) for (let j = 1; j <= m; j++) {
885
+ const skipDel = dp[i - 1][j];
886
+ const skipAdd = dp[i][j - 1];
887
+ const s = sim[i - 1][j - 1];
888
+ const pair = s >= INTRA_SIMILARITY_THRESHOLD ? dp[i - 1][j - 1] + s : Number.NEGATIVE_INFINITY;
889
+ dp[i][j] = Math.max(skipDel, skipAdd, pair);
890
+ }
891
+ const pairs = [];
892
+ const delOnly = [];
893
+ const addOnly = [];
894
+ let i = n;
895
+ let j = m;
896
+ while (i > 0 || j > 0) {
897
+ const s = i > 0 && j > 0 ? sim[i - 1][j - 1] : Number.NEGATIVE_INFINITY;
898
+ if (i > 0 && j > 0 && s >= INTRA_SIMILARITY_THRESHOLD && dp[i][j] === dp[i - 1][j - 1] + s) {
899
+ pairs.push({
900
+ delIndex: delRows[i - 1].index,
901
+ addIndex: addRows[j - 1].index
902
+ });
903
+ i--;
904
+ j--;
905
+ } else if (i > 0 && dp[i][j] === dp[i - 1][j]) {
906
+ delOnly.push(delRows[i - 1].index);
907
+ i--;
908
+ } else if (j > 0) {
909
+ addOnly.push(addRows[j - 1].index);
910
+ j--;
911
+ } else break;
912
+ }
913
+ pairs.reverse();
914
+ delOnly.reverse();
915
+ addOnly.reverse();
916
+ return {
917
+ pairs,
918
+ delOnly,
919
+ addOnly,
920
+ usedSimilarity: true
921
+ };
922
+ }
923
+ /**
924
+ * Derive intra-line runs for a whole-file row list. Each del/add block is
925
+ * aligned (by order, or by similarity when `alignBySimilarity`), and each
926
+ * matched pair is compared by `intraRunsOf`. Returns a map keyed by the row's
927
+ * index in `rows`, present only for rows that carry a highlight.
928
+ * @param rows - the unified `WholeFileDiff` row list.
929
+ * @param alignBySimilarity - align blocks by similarity instead of by order.
930
+ * @returns per-row-index intra-line runs for annotated del/add rows.
931
+ */
932
+ function computeIntraLineDiff(rows, alignBySimilarity = false) {
933
+ const result = /* @__PURE__ */ new Map();
934
+ let i = 0;
935
+ while (i < rows.length) {
936
+ if (rows[i].kind !== "del") {
937
+ i++;
938
+ continue;
939
+ }
940
+ const delIndices = [];
941
+ while (i < rows.length && rows[i].kind === "del") {
942
+ delIndices.push(i);
943
+ i++;
944
+ }
945
+ const addIndices = [];
946
+ while (i < rows.length && rows[i].kind === "add") {
947
+ addIndices.push(i);
948
+ i++;
949
+ }
950
+ const alignment = alignChangedBlock(delIndices.map((index) => ({
951
+ index,
952
+ text: rows[index].text
953
+ })), addIndices.map((index) => ({
954
+ index,
955
+ text: rows[index].text
956
+ })), alignBySimilarity);
957
+ if (alignBySimilarity && !alignment.usedSimilarity) continue;
958
+ for (const pair of alignment.pairs) {
959
+ const intra = intraRunsOf(rows[pair.delIndex].text, rows[pair.addIndex].text);
960
+ if (intra !== void 0) {
961
+ result.set(pair.delIndex, intra.del);
962
+ result.set(pair.addIndex, intra.add);
963
+ }
964
+ }
965
+ }
966
+ return result;
967
+ }
725
968
  /**
726
969
  * Split a side's text into its content lines, with the diff card's terminator
727
970
  * rule: empty text is zero lines, and a single trailing newline is a line
@@ -761,57 +1004,78 @@ window.__ModuleLoader__.load({
761
1004
  };
762
1005
  }
763
1006
  /**
764
- * Regroup the whole-file rows into aligned split pairs, pairing a deletion run
765
- * with a following addition run line-by-line (so a replaced line is one pair),
766
- * and leaving a stray deletion or addition as a one-sided pair.
1007
+ * Regroup the whole-file rows into aligned split pairs. By order, a deletion
1008
+ * run pairs line-by-line with a following addition run; with similarity
1009
+ * alignment, each deletion pairs with its most-similar addition (order
1010
+ * preserved, threshold-bounded) so a mixed insert/delete block does not force a
1011
+ * wrong line together. A stray deletion or addition stays a one-sided pair.
767
1012
  * @param rows - the whole-file diff rows.
1013
+ * @param alignBySimilarity - align a change block by similarity instead of order.
768
1014
  * @returns the split pairs plus the row→pair index map.
769
1015
  */
770
- function computeSideBySideDiff(rows) {
1016
+ function computeSideBySideDiff(rows, alignBySimilarity = false) {
771
1017
  const pairs = [];
772
1018
  const pairOfRow = /* @__PURE__ */ new Map();
773
- const pendingDel = [];
774
- const push = (pair, rows) => {
1019
+ const push = (pair, pairRows) => {
775
1020
  const index = pairs.length;
776
1021
  pairs.push(pair);
777
- for (const r of rows) pairOfRow.set(r, index);
778
- };
779
- const flushPending = () => {
780
- for (const { index, row } of pendingDel) push({
781
- kind: "del",
782
- left: leftSideOf(row),
783
- right: void 0
784
- }, [index]);
785
- pendingDel.length = 0;
1022
+ for (const r of pairRows) pairOfRow.set(r, index);
786
1023
  };
787
- for (let i = 0; i < rows.length; i++) {
1024
+ let i = 0;
1025
+ while (i < rows.length) {
788
1026
  const row = rows[i];
789
1027
  if (row.kind === "context") {
790
- flushPending();
791
1028
  push({
792
1029
  kind: "context",
793
1030
  left: leftSideOf(row),
794
1031
  right: rightSideOf(row)
795
1032
  }, [i]);
796
- } else if (row.kind === "del") pendingDel.push({
797
- index: i,
798
- row
799
- });
800
- else {
801
- const del = pendingDel.shift();
802
- if (del !== void 0) push({
1033
+ i++;
1034
+ continue;
1035
+ }
1036
+ const delRows = [];
1037
+ const addRows = [];
1038
+ if (row.kind === "del") while (i < rows.length && rows[i].kind === "del") {
1039
+ delRows.push({
1040
+ index: i,
1041
+ row: rows[i]
1042
+ });
1043
+ i++;
1044
+ }
1045
+ while (i < rows.length && rows[i].kind === "add") {
1046
+ addRows.push({
1047
+ index: i,
1048
+ row: rows[i]
1049
+ });
1050
+ i++;
1051
+ }
1052
+ const alignment = alignChangedBlock(delRows.map((d) => ({
1053
+ index: d.index,
1054
+ text: d.row.text
1055
+ })), addRows.map((a) => ({
1056
+ index: a.index,
1057
+ text: a.row.text
1058
+ })), alignBySimilarity);
1059
+ for (const p of alignment.pairs) {
1060
+ const del = delRows.find((d) => d.index === p.delIndex);
1061
+ const add = addRows.find((a) => a.index === p.addIndex);
1062
+ push({
803
1063
  kind: "replace",
804
1064
  left: leftSideOf(del.row),
805
- right: rightSideOf(row)
806
- }, [del.index, i]);
807
- else push({
808
- kind: "add",
809
- left: void 0,
810
- right: rightSideOf(row)
811
- }, [i]);
1065
+ right: rightSideOf(add.row)
1066
+ }, [p.delIndex, p.addIndex]);
812
1067
  }
1068
+ for (const d of alignment.delOnly) push({
1069
+ kind: "del",
1070
+ left: leftSideOf(delRows.find((x) => x.index === d).row),
1071
+ right: void 0
1072
+ }, [d]);
1073
+ for (const a of alignment.addOnly) push({
1074
+ kind: "add",
1075
+ left: void 0,
1076
+ right: rightSideOf(addRows.find((x) => x.index === a).row)
1077
+ }, [a]);
813
1078
  }
814
- flushPending();
815
1079
  return {
816
1080
  pairs,
817
1081
  pairOfRow
@@ -11833,6 +12097,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
11833
12097
  const IMPORT_UNTRACKED_KEY = "diff-approval:import-untracked";
11834
12098
  const TAB_WIDTH_KEY = "diff-approval:tab-size";
11835
12099
  const SPLIT_MODE_KEY = "diff-approval:split-mode";
12100
+ const NAV_LEAD_KEY = "diff-approval:nav-lead-rows";
11836
12101
  const WRAP_PREFIX = "diff-approval:wrap:";
11837
12102
  /**
11838
12103
  * Whether copying a reference should also paste it into the chat input and
@@ -11901,6 +12166,21 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
11901
12166
  function setSplitMode(value) {
11902
12167
  localStorage.setItem(SPLIT_MODE_KEY, value ? "1" : "0");
11903
12168
  }
12169
+ /**
12170
+ * How many rows of lead the diff block jump leaves above the jumped-to block,
12171
+ * and how far the anchored navigation scans. Defaults to 2; an out-of-range or
12172
+ * non-integer value falls back to the default.
12173
+ * @returns the lead row count.
12174
+ */
12175
+ function navLeadRows() {
12176
+ const raw = Number.parseInt(localStorage.getItem(NAV_LEAD_KEY) ?? "", 10);
12177
+ if (!Number.isInteger(raw)) return 2;
12178
+ return Math.max(0, Math.min(10, raw));
12179
+ }
12180
+ /** Persist the block-jump lead row count. */
12181
+ function setNavLeadRows(value) {
12182
+ localStorage.setItem(NAV_LEAD_KEY, String(Math.max(0, Math.min(10, value))));
12183
+ }
11904
12184
  const QUICK_SUMMON_KEY = "diff-approval:quick-summon-key";
11905
12185
  /**
11906
12186
  * The quick-summon chord. Stored as `Modifier+...+Key`; falls back to
@@ -11936,7 +12216,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
11936
12216
  }
11937
12217
  //#endregion
11938
12218
  //#region \0dsh-css:/home/runner/work/dsh-diff-approval/dsh-diff-approval/src/client/PendingPanel.module.css.mjs
11939
- 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{-webkit-user-select:none;user-select:none;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;-webkit-user-select:none;user-select:none;cursor:default;padding-right:10px;display:table-cell}.F1KBNa_code{white-space:pre;-webkit-user-select:text;user-select:text;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)}";
12219
+ 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_toggle{border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:18px;flex:none;width:60px;height:36px;padding:0;position:relative}.F1KBNa_toggle:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_toggle:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.F1KBNa_toggleOn{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-state-business-primary)}.F1KBNa_toggleOn:hover{background:var(--dsw-alias-state-business-primary)}.F1KBNa_toggleThumb{background:var(--dsw-alias-label-primary);border-radius:50%;width:28px;height:28px;transition:left .12s;position:absolute;top:3px;left:3px}.F1KBNa_toggleOn .F1KBNa_toggleThumb{background:#fff;left:27px}.F1KBNa_stepper{align-items:center;gap:6px;display:inline-flex}.F1KBNa_stepperButton{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-module-platform);width:32px;height:32px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:8px;font-size:16px;line-height:1}.F1KBNa_stepperButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_stepperButton:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_stepperValue{text-align:center;min-width:2ch;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-size:14px;line-height:22px}.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{white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block);-webkit-user-select:text;user-select:text;flex:1;font-size:12px;line-height:18px;overflow:auto 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{-webkit-user-select:none;user-select:none;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;-webkit-user-select:none;user-select:none;cursor:default;padding-right:10px;display:table-cell}.F1KBNa_code{white-space:pre;-webkit-user-select:text;user-select:text;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)}.F1KBNa_intraDel{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 26%, transparent);text-decoration:line-through}.F1KBNa_intraAdd{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 24%, transparent)}";
11940
12220
  const tagId = "dsh-diff-approval/PendingPanel.module.css";
11941
12221
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
11942
12222
  const tag = document.createElement("style");
@@ -11946,115 +12226,123 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
11946
12226
  document.head.appendChild(tag);
11947
12227
  }
11948
12228
  var PendingPanel_module_css_default = {
11949
- "searchBar": "F1KBNa_searchBar",
11950
- "delCount": "F1KBNa_delCount",
11951
- "gutter": "F1KBNa_gutter",
11952
- "subline": "F1KBNa_subline",
11953
- "noteCentered": "F1KBNa_noteCentered",
11954
- "splitDivider": "F1KBNa_splitDivider",
11955
- "splitHScrollFill": "F1KBNa_splitHScrollFill",
11956
- "action": "F1KBNa_action",
11957
- "noticeText": "F1KBNa_noticeText",
11958
- "header": "F1KBNa_header",
12229
+ "splitLadd": "F1KBNa_splitLadd",
12230
+ "badge": "F1KBNa_badge",
11959
12231
  "settingsRowTitle": "F1KBNa_settingsRowTitle",
12232
+ "code": "F1KBNa_code",
11960
12233
  "confirmCard": "F1KBNa_confirmCard",
11961
- "markerDel": "F1KBNa_markerDel",
11962
- "wrapActive": "F1KBNa_wrapActive",
12234
+ "title": "F1KBNa_title",
12235
+ "diffBody": "F1KBNa_diffBody",
12236
+ "diffFlash": "F1KBNa_diffFlash",
12237
+ "states": "F1KBNa_states",
12238
+ "actionQuietDisabled": "F1KBNa_actionQuietDisabled",
12239
+ "resizeHandle": "F1KBNa_resizeHandle",
12240
+ "addCount": "F1KBNa_addCount",
12241
+ "actionPrimary": "F1KBNa_actionPrimary",
12242
+ "splitHScrollFill": "F1KBNa_splitHScrollFill",
12243
+ "importButton": "F1KBNa_importButton",
12244
+ "splitDivider": "F1KBNa_splitDivider",
12245
+ "divergedHint": "F1KBNa_divergedHint",
12246
+ "close": "F1KBNa_close",
12247
+ "importNote": "F1KBNa_importNote",
12248
+ "langSelect": "F1KBNa_langSelect",
12249
+ "langLabel": "F1KBNa_langLabel",
12250
+ "vSpacer": "F1KBNa_vSpacer",
12251
+ "emptyState": "F1KBNa_emptyState",
12252
+ "blockFlash": "F1KBNa_blockFlash",
12253
+ "splitCol": "F1KBNa_splitCol",
12254
+ "rail": "F1KBNa_rail",
12255
+ "action": "F1KBNa_action",
12256
+ "group": "F1KBNa_group",
12257
+ "confirmBackdrop": "F1KBNa_confirmBackdrop",
11963
12258
  "listScroll": "F1KBNa_listScroll",
11964
- "hint": "F1KBNa_hint",
12259
+ "bulkActions": "F1KBNa_bulkActions",
12260
+ "searchInput": "F1KBNa_searchInput",
12261
+ "splitLdel": "F1KBNa_splitLdel",
11965
12262
  "diffPath": "F1KBNa_diffPath",
11966
- "splitLadd": "F1KBNa_splitLadd",
11967
- "blockActions": "F1KBNa_blockActions",
12263
+ "line": "F1KBNa_line",
12264
+ "intraDel": "F1KBNa_intraDel",
12265
+ "settingsRowDesc": "F1KBNa_settingsRowDesc",
12266
+ "actionError": "F1KBNa_actionError",
12267
+ "rows": "F1KBNa_rows",
12268
+ "wrapActive": "F1KBNa_wrapActive",
12269
+ "hint": "F1KBNa_hint",
12270
+ "kindTag": "F1KBNa_kindTag",
12271
+ "wrap": "F1KBNa_wrap",
12272
+ "fullscreenBackdrop": "F1KBNa_fullscreenBackdrop",
12273
+ "readError": "F1KBNa_readError",
12274
+ "add": "F1KBNa_add",
12275
+ "overviewRuler": "F1KBNa_overviewRuler",
12276
+ "splitHScrollRow": "F1KBNa_splitHScrollRow",
12277
+ "splitRadd": "F1KBNa_splitRadd",
12278
+ "detailEmpty": "F1KBNa_detailEmpty",
12279
+ "statusAction": "F1KBNa_statusAction",
12280
+ "diffBodyWrap": "F1KBNa_diffBodyWrap",
12281
+ "toggleOn": "F1KBNa_toggleOn",
12282
+ "badgeCount": "F1KBNa_badgeCount",
12283
+ "settingsPage": "F1KBNa_settingsPage",
11968
12284
  "missingHint": "F1KBNa_missingHint",
12285
+ "footerButtons": "F1KBNa_footerButtons",
12286
+ "noteCentered": "F1KBNa_noteCentered",
12287
+ "intraAdd": "F1KBNa_intraAdd",
12288
+ "expandExpanded": "F1KBNa_expandExpanded",
12289
+ "headerActions": "F1KBNa_headerActions",
11969
12290
  "split": "F1KBNa_split",
12291
+ "diffHeader": "F1KBNa_diffHeader",
12292
+ "lines": "F1KBNa_lines",
12293
+ "stepperValue": "F1KBNa_stepperValue",
12294
+ "splitRoot": "F1KBNa_splitRoot",
11970
12295
  "rowHead": "F1KBNa_rowHead",
11971
- "langLabel": "F1KBNa_langLabel",
12296
+ "stepperButton": "F1KBNa_stepperButton",
12297
+ "rowMeta": "F1KBNa_rowMeta",
12298
+ "expand": "F1KBNa_expand",
12299
+ "settingsRow": "F1KBNa_settingsRow",
12300
+ "diff": "F1KBNa_diff",
12301
+ "panel": "F1KBNa_panel",
12302
+ "diffBodySplit": "F1KBNa_diffBodySplit",
11972
12303
  "note": "F1KBNa_note",
11973
- "splitRadd": "F1KBNa_splitRadd",
12304
+ "rowPath": "F1KBNa_rowPath",
12305
+ "detail": "F1KBNa_detail",
12306
+ "confirmActions": "F1KBNa_confirmActions",
12307
+ "badgeLabel": "F1KBNa_badgeLabel",
12308
+ "blockActions": "F1KBNa_blockActions",
12309
+ "blockPosition": "F1KBNa_blockPosition",
11974
12310
  "confirmText": "F1KBNa_confirmText",
11975
- "expandExpanded": "F1KBNa_expandExpanded",
11976
- "divergedHint": "F1KBNa_divergedHint",
11977
- "diffBody": "F1KBNa_diffBody",
11978
- "missing": "F1KBNa_missing",
12311
+ "context": "F1KBNa_context",
12312
+ "subline": "F1KBNa_subline",
12313
+ "settingsSelector": "F1KBNa_settingsSelector",
12314
+ "kindHint": "F1KBNa_kindHint",
12315
+ "notice": "F1KBNa_notice",
12316
+ "noticeText": "F1KBNa_noticeText",
11979
12317
  "markerAdd": "F1KBNa_markerAdd",
12318
+ "flexSpacer": "F1KBNa_flexSpacer",
12319
+ "stepper": "F1KBNa_stepper",
12320
+ "toggle": "F1KBNa_toggle",
12321
+ "settingsSelectorChevron": "F1KBNa_settingsSelectorChevron",
12322
+ "splitHScroll": "F1KBNa_splitHScroll",
12323
+ "noticeButton": "F1KBNa_noticeButton",
12324
+ "header": "F1KBNa_header",
12325
+ "rowFailed": "F1KBNa_rowFailed",
11980
12326
  "del": "F1KBNa_del",
11981
- "add": "F1KBNa_add",
11982
- "detailEmpty": "F1KBNa_detailEmpty",
11983
- "badge": "F1KBNa_badge",
11984
- "title": "F1KBNa_title",
11985
- "blockPosition": "F1KBNa_blockPosition",
11986
- "badgeLabel": "F1KBNa_badgeLabel",
11987
- "headerActions": "F1KBNa_headerActions",
11988
- "panel": "F1KBNa_panel",
11989
- "group": "F1KBNa_group",
11990
- "blockFlash": "F1KBNa_blockFlash",
11991
- "settingsRow": "F1KBNa_settingsRow",
11992
- "importNote": "F1KBNa_importNote",
11993
- "diffFlash": "F1KBNa_diffFlash",
11994
- "notice": "F1KBNa_notice",
11995
- "rowPath": "F1KBNa_rowPath",
11996
- "readError": "F1KBNa_readError",
11997
- "settingsPage": "F1KBNa_settingsPage",
12327
+ "diffActions": "F1KBNa_diffActions",
11998
12328
  "settingsRowText": "F1KBNa_settingsRowText",
11999
12329
  "fileListFloat": "F1KBNa_fileListFloat",
12000
- "bulkActions": "F1KBNa_bulkActions",
12001
- "kindTag": "F1KBNa_kindTag",
12002
- "rowFailed": "F1KBNa_rowFailed",
12330
+ "gutter": "F1KBNa_gutter",
12003
12331
  "layer": "F1KBNa_layer",
12004
- "states": "F1KBNa_states",
12005
- "diffBodyWrap": "F1KBNa_diffBodyWrap",
12006
- "emptyState": "F1KBNa_emptyState",
12007
- "flexSpacer": "F1KBNa_flexSpacer",
12008
- "splitLdel": "F1KBNa_splitLdel",
12009
- "diffActions": "F1KBNa_diffActions",
12010
- "settingsSelectorChevron": "F1KBNa_settingsSelectorChevron",
12011
- "detail": "F1KBNa_detail",
12012
- "actionError": "F1KBNa_actionError",
12013
- "actionQuietDisabled": "F1KBNa_actionQuietDisabled",
12014
- "searchInput": "F1KBNa_searchInput",
12015
- "searchCount": "F1KBNa_searchCount",
12016
- "vSpacer": "F1KBNa_vSpacer",
12017
- "code": "F1KBNa_code",
12018
- "iconAction": "F1KBNa_iconAction",
12019
- "kindHint": "F1KBNa_kindHint",
12020
- "splitHScroll": "F1KBNa_splitHScroll",
12021
- "overviewMarker": "F1KBNa_overviewMarker",
12022
- "rail": "F1KBNa_rail",
12023
- "wrap": "F1KBNa_wrap",
12024
- "splitRdel": "F1KBNa_splitRdel",
12025
- "close": "F1KBNa_close",
12026
- "rows": "F1KBNa_rows",
12027
- "resizeHandle": "F1KBNa_resizeHandle",
12028
- "importButton": "F1KBNa_importButton",
12029
12332
  "fileList": "F1KBNa_fileList",
12030
- "expand": "F1KBNa_expand",
12031
- "langSelect": "F1KBNa_langSelect",
12032
- "addCount": "F1KBNa_addCount",
12033
- "splitHScrollRow": "F1KBNa_splitHScrollRow",
12034
- "fullscreenBackdrop": "F1KBNa_fullscreenBackdrop",
12035
- "splitCol": "F1KBNa_splitCol",
12036
- "overviewRuler": "F1KBNa_overviewRuler",
12037
- "settingsSelector": "F1KBNa_settingsSelector",
12038
- "badgeCount": "F1KBNa_badgeCount",
12039
- "confirmActions": "F1KBNa_confirmActions",
12040
- "row": "F1KBNa_row",
12041
- "rowMeta": "F1KBNa_rowMeta",
12042
- "settingsRowDesc": "F1KBNa_settingsRowDesc",
12043
- "diffStats": "F1KBNa_diffStats",
12044
- "splitRoot": "F1KBNa_splitRoot",
12045
- "actionPrimary": "F1KBNa_actionPrimary",
12046
- "lines": "F1KBNa_lines",
12047
- "context": "F1KBNa_context",
12048
- "footerButtons": "F1KBNa_footerButtons",
12049
- "confirmBackdrop": "F1KBNa_confirmBackdrop",
12050
- "diffBodySplit": "F1KBNa_diffBodySplit",
12051
- "diff": "F1KBNa_diff",
12052
- "diffHeader": "F1KBNa_diffHeader",
12333
+ "overviewMarker": "F1KBNa_overviewMarker",
12053
12334
  "splitCols": "F1KBNa_splitCols",
12054
- "line": "F1KBNa_line",
12055
- "statusAction": "F1KBNa_statusAction",
12335
+ "searchBar": "F1KBNa_searchBar",
12336
+ "splitRdel": "F1KBNa_splitRdel",
12337
+ "missing": "F1KBNa_missing",
12056
12338
  "statusBar": "F1KBNa_statusBar",
12057
- "noticeButton": "F1KBNa_noticeButton"
12339
+ "diffStats": "F1KBNa_diffStats",
12340
+ "markerDel": "F1KBNa_markerDel",
12341
+ "delCount": "F1KBNa_delCount",
12342
+ "toggleThumb": "F1KBNa_toggleThumb",
12343
+ "iconAction": "F1KBNa_iconAction",
12344
+ "row": "F1KBNa_row",
12345
+ "searchCount": "F1KBNa_searchCount"
12058
12346
  };
12059
12347
  //#endregion
12060
12348
  //#region lib/types/client/PendingPanel.js
@@ -12080,7 +12368,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12080
12368
  /** Interactive composer/approval cards; clicking these keeps the panel open.
12081
12369
  Deliberately the cards themselves, not the seat: the approval frame's wide
12082
12370
  side gutters are blank space, so a click there must still close. */
12083
- const KEEP_OPEN_SELECTOR = "[data-composer-card],[data-question-key] > *,[data-plan-review-key] > *";
12371
+ const KEEP_OPEN_SELECTOR = "[data-composer-card],[data-question-key] > *,[data-plan-review-key] > *,[data-approval-key] > *";
12084
12372
  /** Seat counts as docked when its bottom is this close to the window bottom. */
12085
12373
  const DOCKED_TOLERANCE_PX = 48;
12086
12374
  /** File-list pane width bounds for the manual split drag, in px. */
@@ -12090,6 +12378,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12090
12378
  const FLOAT_LIST_MARGIN_PX = 12;
12091
12379
  /** Fixed diff-row height in px; the virtual window and jump math are built on it. */
12092
12380
  const ROW_HEIGHT_PX = 22;
12381
+ /** Tolerance absorbed when comparing a block's offset to the navigation anchor,
12382
+ * so a sub-pixel float error (wrapped row heights, fractional scrollTop) never
12383
+ * mis-classifies the block the view is sitting on. Half a row height. */
12384
+ const NAV_ANCHOR_TOLERANCE_PX = ROW_HEIGHT_PX / 4;
12093
12385
  /** Total width of the two line-number gutters, subtracted from the code width
12094
12386
  * when measuring wrapped line heights. */
12095
12387
  const WRAP_GUTTERS_PX = 88;
@@ -12304,6 +12596,55 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12304
12596
  }
12305
12597
  return nodes.length === 0 ? "\xA0" : nodes;
12306
12598
  }
12599
+ /** Chip styling for each intra-line run: removed chars and added chars stand out. */
12600
+ const INTRA_CLASS = {
12601
+ same: void 0,
12602
+ del: PendingPanel_module_css_default.intraDel,
12603
+ add: PendingPanel_module_css_default.intraAdd
12604
+ };
12605
+ /** Clip intra-line runs to a character range, renumbering each cut run. */
12606
+ function clipIntra(intra, start, end) {
12607
+ const out = [];
12608
+ let pos = 0;
12609
+ for (const run of intra) {
12610
+ const runStart = pos;
12611
+ const runEnd = pos + run.text.length;
12612
+ pos = runEnd;
12613
+ if (runEnd <= start || runStart >= end) continue;
12614
+ const text = run.text.slice(Math.max(runStart, start) - runStart, Math.min(runEnd, end) - runStart);
12615
+ if (text.length === 0) continue;
12616
+ out.push({
12617
+ text,
12618
+ kind: run.kind
12619
+ });
12620
+ }
12621
+ return out;
12622
+ }
12623
+ /**
12624
+ * Render a character range as intra-line runs, with the syntax color clipped
12625
+ * back onto each run. Context (`same`) runs show no draw; removed/added runs
12626
+ * carry the chip draw. `intra` must cover `[start, end)` — it is clipped and
12627
+ * reassembled per run, so the returned nodes concatenate to that range.
12628
+ * @param runs - the syntax highlight for the whole line, or undefined.
12629
+ * @param intra - the intra-line runs for the whole line.
12630
+ * @param start - the range start (character offset in the line).
12631
+ * @param end - the range end (exclusive).
12632
+ * @returns the merged spans for the range.
12633
+ */
12634
+ function renderIntra(runs, intra, start, end) {
12635
+ const clipped = clipIntra(intra, start, end);
12636
+ let cursor = start;
12637
+ return clipped.map((run, i) => {
12638
+ const runStart = cursor;
12639
+ const runEnd = runStart + run.text.length;
12640
+ cursor = runEnd;
12641
+ const syntax = runs !== void 0 && runs.length > 0 ? clipRuns(runs, runStart, runEnd) : run.text;
12642
+ return (0, react_jsx_runtime.jsx)("span", {
12643
+ className: INTRA_CLASS[run.kind],
12644
+ children: syntax
12645
+ }, i);
12646
+ });
12647
+ }
12307
12648
  /**
12308
12649
  * One rendered diff row, memoized so a poll or an unrelated state change
12309
12650
  * does not re-render rows whose content, highlight, and focus are unchanged.
@@ -12424,10 +12765,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12424
12765
  return blocks;
12425
12766
  }
12426
12767
  /** One side's line-content for the split view: the highlighted runs or plain text. */
12427
- function splitSideContent(side, wrapped, runs) {
12768
+ function splitSideContent(side, wrapped, runs, intra) {
12428
12769
  if (side === void 0) return "";
12429
12770
  const highlighted = runs !== void 0 && runs.length > 0;
12430
- if (wrapped === void 0) return highlighted ? runs.map((span, i) => (0, react_jsx_runtime.jsx)("span", {
12771
+ const hasIntra = intra !== void 0 && intra.length > 0;
12772
+ if (wrapped === void 0) return hasIntra ? renderIntra(runs, intra, 0, side.text.length) : highlighted ? runs.map((span, i) => (0, react_jsx_runtime.jsx)("span", {
12431
12773
  style: span.style,
12432
12774
  children: span.text
12433
12775
  }, i)) : side.text === "" ? "\xA0" : side.text;
@@ -12435,7 +12777,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12435
12777
  return wrapped.map((line, i) => {
12436
12778
  const start = offset;
12437
12779
  offset += line.length;
12438
- const content = highlighted ? clipRuns(runs, start, offset) : line === "" ? "\xA0" : line;
12780
+ const content = hasIntra ? renderIntra(runs, intra, start, offset) : highlighted ? clipRuns(runs, start, offset) : line === "" ? "\xA0" : line;
12439
12781
  return (0, react_jsx_runtime.jsx)("div", {
12440
12782
  className: PendingPanel_module_css_default.subline,
12441
12783
  children: content
@@ -12451,7 +12793,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12451
12793
  * one side is longer. The gutter and code are top-aligned so sub-lines line up
12452
12794
  * across the divider.
12453
12795
  */
12454
- function SplitSideRow({ index, side, wrapped, runs, kind, isLeft, height, focused, searchHit, searchCurrent, onHover }) {
12796
+ function SplitSideRow({ index, side, wrapped, runs, kind, isLeft, height, focused, searchHit, searchCurrent, onHover, intra }) {
12455
12797
  const tint = isLeft ? kind === "del" || kind === "replace" ? PendingPanel_module_css_default.splitLdel : "" : kind === "add" || kind === "replace" ? PendingPanel_module_css_default.splitRadd : "";
12456
12798
  return (0, react_jsx_runtime.jsxs)("div", {
12457
12799
  className: PendingPanel_module_css_default.line,
@@ -12468,14 +12810,26 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12468
12810
  }), (0, react_jsx_runtime.jsx)("span", {
12469
12811
  className: `${PendingPanel_module_css_default.code} ${tint}`,
12470
12812
  "data-diff-code": true,
12471
- children: splitSideContent(side, wrapped, runs)
12813
+ children: splitSideContent(side, wrapped, runs, intra)
12472
12814
  })]
12473
12815
  });
12474
12816
  }
12475
12817
  /** The two-column (side-by-side) whole-file diff view. */
12476
- const SplitDiff = (0, react.forwardRef)(function SplitDiff({ file, model, runs, langWrap, tabWidthSpaces, busy, t, onBlockKeep, onBlockRevert }, ref) {
12477
- const { pairs, pairOfRow } = (0, react.useMemo)(() => computeSideBySideDiff(model.diff.rows), [model]);
12818
+ const SplitDiff = (0, react.forwardRef)(function SplitDiff({ file, model, runs, langWrap, tabWidthSpaces, busy, t, selection, leadRows, onBlockKeep, onBlockRevert }, ref) {
12819
+ const { pairs, pairOfRow } = (0, react.useMemo)(() => computeSideBySideDiff(model.diff.rows, true), [model]);
12478
12820
  const pairCount = pairs.length;
12821
+ const pairRowIndices = (0, react.useMemo)(() => {
12822
+ const map = /* @__PURE__ */ new Map();
12823
+ model.diff.rows.forEach((row, rowIndex) => {
12824
+ const pairIndex = pairOfRow.get(rowIndex);
12825
+ if (pairIndex === void 0) return;
12826
+ const entry = map.get(pairIndex) ?? {};
12827
+ if (row.kind !== "add") entry.left = rowIndex;
12828
+ if (row.kind !== "del") entry.right = rowIndex;
12829
+ map.set(pairIndex, entry);
12830
+ });
12831
+ return map;
12832
+ }, [model, pairOfRow]);
12479
12833
  const bodyRef = (0, react.useRef)(null);
12480
12834
  const [scrollTop, setScrollTop] = (0, react.useState)(0);
12481
12835
  const [viewportH, setViewportH] = (0, react.useState)(0);
@@ -12661,8 +13015,12 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12661
13015
  return lo;
12662
13016
  };
12663
13017
  const viewport = viewportH > 0 ? viewportH : totalHeight;
12664
- const start = Math.max(0, pairAtY(scrollTop) - OVERSCAN_ROWS);
12665
- const end = Math.min(pairCount, pairAtY(scrollTop + viewport) + OVERSCAN_ROWS);
13018
+ let start = Math.max(0, pairAtY(scrollTop) - OVERSCAN_ROWS);
13019
+ let end = Math.min(pairCount, pairAtY(scrollTop + viewport) + OVERSCAN_ROWS);
13020
+ if (selection !== void 0) {
13021
+ start = Math.min(start, selection.start);
13022
+ end = Math.max(end, selection.end + 1);
13023
+ }
12666
13024
  const visiblePairs = pairs.slice(start, end);
12667
13025
  const jump = (direction) => {
12668
13026
  if (blockOfPair.length === 0) return;
@@ -12684,13 +13042,21 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12684
13042
  if (block === void 0) return;
12685
13043
  const body = bodyRef.current;
12686
13044
  if (body === null) return;
12687
- const target = off(block.start) - 44;
13045
+ const target = off(block.start) - leadRows * ROW_HEIGHT_PX;
12688
13046
  const clamped = Math.max(0, Math.min(target, body.scrollHeight - body.clientHeight));
12689
13047
  if (body.scrollTop !== clamped) body.scrollTop = clamped;
12690
13048
  setScrollTop(clamped);
12691
- }, [focus, flashKey]);
13049
+ }, [flashKey]);
12692
13050
  const onScroll = () => {
12693
- setScrollTop(bodyRef.current?.scrollTop ?? 0);
13051
+ const body = bodyRef.current;
13052
+ if (body === null) return;
13053
+ setScrollTop(body.scrollTop);
13054
+ const count = blockOfPair.length;
13055
+ if (count === 0) return;
13056
+ const anchor = body.scrollTop + leadRows * ROW_HEIGHT_PX;
13057
+ let ref = -1;
13058
+ for (let index = 0; index < count; index++) if (off(blockOfPair[index].start) <= anchor + NAV_ANCHOR_TOLERANCE_PX) ref = index;
13059
+ setFocus(ref === -1 ? 0 : ref);
12694
13060
  };
12695
13061
  const inFocused = (k) => {
12696
13062
  const block = blockOfPair[focus];
@@ -12732,6 +13098,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12732
13098
  visiblePairs.map((pair, offset) => {
12733
13099
  const index = start + offset;
12734
13100
  const leftRuns = pair.left === void 0 ? void 0 : runs?.oldRuns?.[(pair.left.line ?? 0) - 1];
13101
+ const sideIndex = pairRowIndices.get(index);
12735
13102
  return (0, react_jsx_runtime.jsx)(SplitSideRow, {
12736
13103
  index,
12737
13104
  side: pair.left,
@@ -12743,7 +13110,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12743
13110
  focused: inFocused(index),
12744
13111
  searchHit: searchHitSet.has(index),
12745
13112
  searchCurrent: index === currentSearchPair,
12746
- onHover: () => onPairHover(index)
13113
+ onHover: () => onPairHover(index),
13114
+ intra: sideIndex?.left === void 0 ? void 0 : model.intra.get(sideIndex.left)
12747
13115
  }, index);
12748
13116
  }),
12749
13117
  end < pairCount && (0, react_jsx_runtime.jsx)("div", {
@@ -12771,6 +13139,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12771
13139
  visiblePairs.map((pair, offset) => {
12772
13140
  const index = start + offset;
12773
13141
  const rightRuns = pair.right === void 0 ? void 0 : runs?.newRuns?.[(pair.right.line ?? 0) - 1];
13142
+ const sideIndex = pairRowIndices.get(index);
12774
13143
  return (0, react_jsx_runtime.jsx)(SplitSideRow, {
12775
13144
  index,
12776
13145
  side: pair.right,
@@ -12782,7 +13151,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12782
13151
  focused: inFocused(index),
12783
13152
  searchHit: searchHitSet.has(index),
12784
13153
  searchCurrent: index === currentSearchPair,
12785
- onHover: () => onPairHover(index)
13154
+ onHover: () => onPairHover(index),
13155
+ intra: sideIndex?.right === void 0 ? void 0 : model.intra.get(sideIndex.right)
12786
13156
  }, index);
12787
13157
  }),
12788
13158
  end < pairCount && (0, react_jsx_runtime.jsx)("div", {
@@ -13039,6 +13409,39 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13039
13409
  return codeCellAt(node)?.textContent?.length ?? 0;
13040
13410
  }
13041
13411
  /**
13412
+ * Reconstruct the plain text of the current selection so auto-wrap's visual
13413
+ * line breaks never leak into the clipboard. A wrapped row renders its code as
13414
+ * several `.subline` block elements, and the browser's default copy inserts a
13415
+ * newline between them; those segments form one logical line, so they are joined
13416
+ * without a newline while the real newline between diff rows is kept.
13417
+ */
13418
+ function selectedPlainText() {
13419
+ const selection = window.getSelection();
13420
+ if (selection === null || selection.rangeCount === 0 || selection.isCollapsed) return void 0;
13421
+ const range = selection.getRangeAt(0);
13422
+ const container = document.createElement("div");
13423
+ container.appendChild(range.cloneContents());
13424
+ const parts = [];
13425
+ let atLineStart = true;
13426
+ const push = (text) => {
13427
+ if (text.length === 0) return;
13428
+ parts.push(text);
13429
+ atLineStart = text.endsWith("\n");
13430
+ };
13431
+ const walk = (node) => {
13432
+ if (node.nodeType === Node.TEXT_NODE) {
13433
+ push(node.textContent ?? "");
13434
+ return;
13435
+ }
13436
+ if (!(node instanceof Element)) return;
13437
+ const el = node;
13438
+ if ((el.dataset.diffRow !== void 0 || el.dataset.diffSplitRow !== void 0 || el.dataset.diffSplitIndex !== void 0) && !atLineStart) push("\n");
13439
+ for (const child of node.childNodes) walk(child);
13440
+ };
13441
+ walk(container);
13442
+ return parts.join("");
13443
+ }
13444
+ /**
13042
13445
  * Derive the selected diff-row range from a native text selection. A
13043
13446
  * boundary sitting exactly at a line edge contributes no content: a start at
13044
13447
  * the line's end skips to the next line, an end at the line's start falls
@@ -13134,15 +13537,22 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13134
13537
  };
13135
13538
  const [tabWidthSpaces] = (0, react.useState)(() => tabWidth());
13136
13539
  const splitView = splitMode();
13540
+ const leadRows = navLeadRows();
13137
13541
  const splitDiffRef = (0, react.useRef)(null);
13138
13542
  const model = (0, react.useMemo)(() => {
13139
13543
  const diff = computeWholeFileDiff(file.oldText, file.newText);
13544
+ const intra = splitView ? computeIntraLineDiff(diff.rows, true) : /* @__PURE__ */ new Map();
13140
13545
  return {
13141
13546
  diff,
13142
- blocks: changeBlocksOf(diff)
13547
+ blocks: changeBlocksOf(diff),
13548
+ intra
13143
13549
  };
13144
- }, [file.oldText, file.newText]);
13145
- const splitPairs = (0, react.useMemo)(() => splitView ? computeSideBySideDiff(model.diff.rows).pairs : null, [splitView, model]);
13550
+ }, [
13551
+ file.oldText,
13552
+ file.newText,
13553
+ splitView
13554
+ ]);
13555
+ const splitPairs = (0, react.useMemo)(() => splitView ? computeSideBySideDiff(model.diff.rows, true).pairs : null, [splitView, model]);
13146
13556
  const rulerMarkers = (0, react.useMemo)(() => {
13147
13557
  const rows = model.diff.rows;
13148
13558
  const total = rows.length;
@@ -13360,18 +13770,22 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13360
13770
  return lo;
13361
13771
  };
13362
13772
  const viewport = viewportHeight > 0 ? viewportHeight : totalHeight;
13363
- const start = Math.max(0, rowAtY(scrollTop) - OVERSCAN_ROWS);
13364
- const end = Math.min(rowCount, rowAtY(scrollTop + viewport) + OVERSCAN_ROWS);
13773
+ let start = Math.max(0, rowAtY(scrollTop) - OVERSCAN_ROWS);
13774
+ let end = Math.min(rowCount, rowAtY(scrollTop + viewport) + OVERSCAN_ROWS);
13775
+ if (selection !== void 0) {
13776
+ start = Math.min(start, selection.start);
13777
+ end = Math.max(end, selection.end + 1);
13778
+ }
13365
13779
  const visibleRows = rows.slice(start, end);
13366
13780
  const blockEnd = hoveredBlock === void 0 ? void 0 : model.blocks[hoveredBlock]?.end;
13367
- const blockActionsTop = blockEnd === void 0 ? 0 : Math.min(offsetOf(blockEnd + 1), Math.max(0, totalHeight - BLOCK_ACTIONS_FRAME_PX));
13781
+ const blockActionsTop = blockEnd === void 0 ? 0 : Math.max(0, Math.min(offsetOf(blockEnd + 1) - scrollTop, Math.max(0, viewportHeight - BLOCK_ACTIONS_FRAME_PX)));
13368
13782
  const selectionBlockEnd = (() => {
13369
13783
  if (coveredBlockIndices.length === 0) return void 0;
13370
13784
  const lastIndex = coveredBlockIndices[coveredBlockIndices.length - 1];
13371
13785
  if (lastIndex === void 0) return void 0;
13372
13786
  return model.blocks[lastIndex]?.end;
13373
13787
  })();
13374
- const selectionActionsTop = selectionBlockEnd === void 0 ? 0 : Math.min(offsetOf(selectionBlockEnd + 1), Math.max(0, totalHeight - BLOCK_ACTIONS_FRAME_PX));
13788
+ const selectionActionsTop = selectionBlockEnd === void 0 ? 0 : Math.max(0, Math.min(offsetOf(selectionBlockEnd + 1) - scrollTop, Math.max(0, viewportHeight - BLOCK_ACTIONS_FRAME_PX)));
13375
13789
  const widestLine = (0, react.useMemo)(() => {
13376
13790
  let widest = 0;
13377
13791
  for (const row of model.diff.rows) if (row.text.length > widest) widest = row.text.length;
@@ -13410,15 +13824,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13410
13824
  if (block === void 0) return;
13411
13825
  const body = bodyRef.current;
13412
13826
  if (body === null) return;
13413
- const target = offsetOf(block.start) - 44;
13827
+ const target = offsetOf(block.start) - leadRows * ROW_HEIGHT_PX;
13414
13828
  const clamped = Math.max(0, Math.min(target, body.scrollHeight - body.clientHeight));
13415
13829
  if (body.scrollTop !== clamped) body.scrollTop = clamped;
13416
13830
  setScrollTop(clamped);
13417
- }, [
13418
- focus,
13419
- scrollTick,
13420
- rowOffsets === null
13421
- ]);
13831
+ }, [scrollTick, rowOffsets === null]);
13422
13832
  const jump = (direction) => {
13423
13833
  if (rowCount === 0) return;
13424
13834
  setFocus((current) => {
@@ -13483,6 +13893,15 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13483
13893
  if (body === null) return;
13484
13894
  setScrollTop(body.scrollTop);
13485
13895
  setViewportHeight(body.clientHeight);
13896
+ const count = model.blocks.length;
13897
+ if (rowCount === 0 || count === 0) return;
13898
+ const anchor = body.scrollTop + leadRows * ROW_HEIGHT_PX;
13899
+ let ref = -1;
13900
+ for (let index = 0; index < count; index++) {
13901
+ const block = model.blocks[index];
13902
+ if (block !== void 0 && offsetOf(block.start) <= anchor + NAV_ANCHOR_TOLERANCE_PX) ref = index;
13903
+ }
13904
+ setFocus(ref === -1 ? 0 : ref);
13486
13905
  };
13487
13906
  (0, react.useEffect)(() => {
13488
13907
  const update = () => setSelection(splitView ? splitRowRangeOf(window.getSelection()) : rowRangeOf(window.getSelection()));
@@ -13492,6 +13911,20 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13492
13911
  document.removeEventListener("selectionchange", update);
13493
13912
  };
13494
13913
  }, [file.id, splitView]);
13914
+ (0, react.useEffect)(() => {
13915
+ const onCopy = (event) => {
13916
+ const anchor = window.getSelection()?.anchorNode;
13917
+ if (!((anchor instanceof Element ? anchor : anchor?.parentElement)?.closest("[data-diff-code]") !== null)) return;
13918
+ const text = selectedPlainText();
13919
+ if (text === void 0) return;
13920
+ event.preventDefault();
13921
+ event.clipboardData?.setData("text/plain", text);
13922
+ };
13923
+ document.addEventListener("copy", onCopy);
13924
+ return () => {
13925
+ document.removeEventListener("copy", onCopy);
13926
+ };
13927
+ }, []);
13495
13928
  const selectionReference = (() => {
13496
13929
  if (selection === void 0) return void 0;
13497
13930
  if (splitView) {
@@ -13654,10 +14087,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13654
14087
  removed: model.diff.removed
13655
14088
  })
13656
14089
  }),
13657
- file.kind === "create" && (0, react_jsx_runtime.jsx)("span", {
13658
- className: PendingPanel_module_css_default.kindHint,
13659
- children: t("panel.createHint")
13660
- }),
13661
14090
  model.blocks.length > 0 && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
13662
14091
  label: `${t("action.prevDiff")} (Ctrl+↑)`,
13663
14092
  side: "bottom",
@@ -13721,7 +14150,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13721
14150
  onClick: () => {
13722
14151
  onRevert(file.sessionId, file.id);
13723
14152
  },
13724
- children: t("action.revert")
14153
+ children: file.kind === "create" ? t("action.delete") : t("action.revert")
13725
14154
  })
13726
14155
  ]
13727
14156
  }),
@@ -13743,22 +14172,24 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13743
14172
  tabWidthSpaces,
13744
14173
  busy,
13745
14174
  t,
14175
+ selection,
14176
+ leadRows,
13746
14177
  onBlockKeep,
13747
14178
  onBlockRevert
13748
14179
  }) : (0, react_jsx_runtime.jsxs)("div", {
13749
14180
  className: PendingPanel_module_css_default.diffBodyWrap,
14181
+ onMouseLeave: () => {
14182
+ setHoveredBlock(void 0);
14183
+ },
13750
14184
  children: [
13751
- (0, react_jsx_runtime.jsxs)("div", {
14185
+ (0, react_jsx_runtime.jsx)("div", {
13752
14186
  className: PendingPanel_module_css_default.diffBody,
13753
14187
  ref: bodyRef,
13754
14188
  tabIndex: 0,
13755
14189
  onScroll,
13756
- onMouseLeave: () => {
13757
- setHoveredBlock(void 0);
13758
- },
13759
14190
  style: { tabSize: tabWidthSpaces },
13760
14191
  "data-diff-body": true,
13761
- children: [(0, react_jsx_runtime.jsxs)("div", {
14192
+ children: (0, react_jsx_runtime.jsxs)("div", {
13762
14193
  className: `${PendingPanel_module_css_default.lines}${langWrap ? " " + PendingPanel_module_css_default.wrap : ""}`,
13763
14194
  style: langWrap ? {
13764
14195
  width: "100%",
@@ -13789,87 +14220,88 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13789
14220
  "aria-hidden": "true"
13790
14221
  })
13791
14222
  ]
13792
- }), selectionRange !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
13793
- className: PendingPanel_module_css_default.blockActions,
13794
- "data-diff-selection-actions": true,
13795
- style: { top: selectionActionsTop },
13796
- children: [(0, react_jsx_runtime.jsx)("button", {
14223
+ })
14224
+ }),
14225
+ selectionRange !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
14226
+ className: PendingPanel_module_css_default.blockActions,
14227
+ "data-diff-selection-actions": true,
14228
+ style: { top: selectionActionsTop },
14229
+ children: [(0, react_jsx_runtime.jsx)("button", {
14230
+ type: "button",
14231
+ className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
14232
+ "data-diff-selection-keep": true,
14233
+ disabled: busy,
14234
+ onClick: () => {
14235
+ handleSelectionAction("keep");
14236
+ },
14237
+ children: t("action.keep")
14238
+ }), (0, react_jsx_runtime.jsx)("button", {
14239
+ type: "button",
14240
+ className: PendingPanel_module_css_default.action,
14241
+ "data-diff-selection-revert": true,
14242
+ disabled: busy,
14243
+ onClick: () => {
14244
+ handleSelectionAction("revert");
14245
+ },
14246
+ children: t("action.revert")
14247
+ })]
14248
+ }) : hoveredBlock !== void 0 && model.blocks[hoveredBlock] !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
14249
+ className: PendingPanel_module_css_default.blockActions,
14250
+ "data-diff-block-actions": true,
14251
+ style: { top: blockActionsTop },
14252
+ children: [
14253
+ (0, react_jsx_runtime.jsx)("span", {
14254
+ className: PendingPanel_module_css_default.blockPosition,
14255
+ "data-diff-block-position": true,
14256
+ children: t("panel.blockPosition", {
14257
+ current: hoveredBlock + 1,
14258
+ total: model.blocks.length
14259
+ })
14260
+ }),
14261
+ (0, react_jsx_runtime.jsx)("button", {
14262
+ type: "button",
14263
+ className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
14264
+ "data-diff-block-prev": true,
14265
+ "aria-label": t("action.prevDiff"),
14266
+ disabled: busy,
14267
+ onClick: () => {
14268
+ stepBlock(-1);
14269
+ },
14270
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, { size: 14 })
14271
+ }),
14272
+ (0, react_jsx_runtime.jsx)("button", {
14273
+ type: "button",
14274
+ className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
14275
+ "data-diff-block-next": true,
14276
+ "aria-label": t("action.nextDiff"),
14277
+ disabled: busy,
14278
+ onClick: () => {
14279
+ stepBlock(1);
14280
+ },
14281
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 })
14282
+ }),
14283
+ (0, react_jsx_runtime.jsx)("button", {
13797
14284
  type: "button",
13798
14285
  className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
13799
- "data-diff-selection-keep": true,
14286
+ "data-diff-block-keep": true,
13800
14287
  disabled: busy,
13801
14288
  onClick: () => {
13802
- handleSelectionAction("keep");
14289
+ handleBlockAction("keep");
13803
14290
  },
13804
14291
  children: t("action.keep")
13805
- }), (0, react_jsx_runtime.jsx)("button", {
14292
+ }),
14293
+ (0, react_jsx_runtime.jsx)("button", {
13806
14294
  type: "button",
13807
14295
  className: PendingPanel_module_css_default.action,
13808
- "data-diff-selection-revert": true,
14296
+ "data-diff-block-revert": true,
13809
14297
  disabled: busy,
13810
14298
  onClick: () => {
13811
- handleSelectionAction("revert");
14299
+ handleBlockAction("revert");
13812
14300
  },
13813
14301
  children: t("action.revert")
13814
- })]
13815
- }) : hoveredBlock !== void 0 && model.blocks[hoveredBlock] !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
13816
- className: PendingPanel_module_css_default.blockActions,
13817
- "data-diff-block-actions": true,
13818
- style: { top: blockActionsTop },
13819
- children: [
13820
- (0, react_jsx_runtime.jsx)("span", {
13821
- className: PendingPanel_module_css_default.blockPosition,
13822
- "data-diff-block-position": true,
13823
- children: t("panel.blockPosition", {
13824
- current: hoveredBlock + 1,
13825
- total: model.blocks.length
13826
- })
13827
- }),
13828
- (0, react_jsx_runtime.jsx)("button", {
13829
- type: "button",
13830
- className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
13831
- "data-diff-block-prev": true,
13832
- "aria-label": t("action.prevDiff"),
13833
- disabled: busy,
13834
- onClick: () => {
13835
- stepBlock(-1);
13836
- },
13837
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, { size: 14 })
13838
- }),
13839
- (0, react_jsx_runtime.jsx)("button", {
13840
- type: "button",
13841
- className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
13842
- "data-diff-block-next": true,
13843
- "aria-label": t("action.nextDiff"),
13844
- disabled: busy,
13845
- onClick: () => {
13846
- stepBlock(1);
13847
- },
13848
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 })
13849
- }),
13850
- (0, react_jsx_runtime.jsx)("button", {
13851
- type: "button",
13852
- className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
13853
- "data-diff-block-keep": true,
13854
- disabled: busy,
13855
- onClick: () => {
13856
- handleBlockAction("keep");
13857
- },
13858
- children: t("action.keep")
13859
- }),
13860
- (0, react_jsx_runtime.jsx)("button", {
13861
- type: "button",
13862
- className: PendingPanel_module_css_default.action,
13863
- "data-diff-block-revert": true,
13864
- disabled: busy,
13865
- onClick: () => {
13866
- handleBlockAction("revert");
13867
- },
13868
- children: t("action.revert")
13869
- })
13870
- ]
13871
- }) : null]
13872
- }),
14302
+ })
14303
+ ]
14304
+ }) : null,
13873
14305
  focusedBlock !== void 0 && flashKey > 0 && (0, react_jsx_runtime.jsx)("div", {
13874
14306
  className: PendingPanel_module_css_default.blockFlash,
13875
14307
  "data-diff-block-flash": true,
@@ -14690,42 +15122,26 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14690
15122
  //#endregion
14691
15123
  //#region lib/types/client/SettingsTab.js
14692
15124
  /** DSH Settings top-level section for this plugin's preferences. */
14693
- /** A pill picker offering the two boolean states 打开 / 关闭. */
14694
- function OnOffPicker({ value, open, onOpenChange, onSelect, dataAttribute, t }) {
14695
- return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
14696
- open,
14697
- onClose: () => {
14698
- onOpenChange(false);
14699
- },
14700
- items: [{
14701
- id: "on",
14702
- label: t("action.toggleOn")
14703
- }, {
14704
- id: "off",
14705
- label: t("action.toggleOff")
14706
- }],
14707
- selectedId: value ? "on" : "off",
14708
- onSelect: (id) => {
14709
- onOpenChange(false);
14710
- onSelect(id === "on");
15125
+ /** A toggle switch offering the two boolean states 打开 / 关闭. */
15126
+ function OnOffToggle({ value, onSelect, dataAttribute, t }) {
15127
+ return (0, react_jsx_runtime.jsx)("button", {
15128
+ type: "button",
15129
+ role: "switch",
15130
+ "aria-checked": value,
15131
+ "aria-label": value ? t("action.toggleOn") : t("action.toggleOff"),
15132
+ className: `${PendingPanel_module_css_default.toggle}${value ? " " + PendingPanel_module_css_default.toggleOn : ""}`,
15133
+ [dataAttribute]: true,
15134
+ onClick: () => {
15135
+ onSelect(!value);
14711
15136
  },
14712
- align: "end",
14713
- portal: true,
14714
- anchor: (0, react_jsx_runtime.jsxs)("button", {
14715
- type: "button",
14716
- className: PendingPanel_module_css_default.settingsSelector,
14717
- "aria-haspopup": "menu",
14718
- "aria-expanded": open,
14719
- onClick: () => {
14720
- onOpenChange(!open);
14721
- },
14722
- [dataAttribute]: true,
14723
- children: [value ? t("action.toggleOn") : t("action.toggleOff"), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: PendingPanel_module_css_default.settingsSelectorChevron })]
15137
+ children: (0, react_jsx_runtime.jsx)("span", {
15138
+ className: PendingPanel_module_css_default.toggleThumb,
15139
+ "aria-hidden": "true"
14724
15140
  })
14725
15141
  });
14726
15142
  }
14727
- /** One Agent-preset-style preference row: title + description, pill picker right. */
14728
- function PreferenceRow({ title, description, value, open, onOpenChange, onSelect, dataAttribute, t }) {
15143
+ /** One Agent-preset-style preference row: title + description, toggle right. */
15144
+ function PreferenceRow({ title, description, value, onSelect, dataAttribute, t }) {
14729
15145
  return (0, react_jsx_runtime.jsxs)("div", {
14730
15146
  className: PendingPanel_module_css_default.settingsRow,
14731
15147
  children: [(0, react_jsx_runtime.jsxs)("div", {
@@ -14737,10 +15153,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14737
15153
  className: PendingPanel_module_css_default.settingsRowDesc,
14738
15154
  children: description
14739
15155
  })]
14740
- }), (0, react_jsx_runtime.jsx)(OnOffPicker, {
15156
+ }), (0, react_jsx_runtime.jsx)(OnOffToggle, {
14741
15157
  value,
14742
- open,
14743
- onOpenChange,
14744
15158
  onSelect,
14745
15159
  dataAttribute,
14746
15160
  t
@@ -14805,6 +15219,53 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14805
15219
  })]
14806
15220
  });
14807
15221
  }
15222
+ /** A +/- number stepper for an integer preference, clamped to [min, max]. */
15223
+ function StepperRow({ title, description, value, onChange, min, max, dataAttribute, t }) {
15224
+ return (0, react_jsx_runtime.jsxs)("div", {
15225
+ className: PendingPanel_module_css_default.settingsRow,
15226
+ children: [(0, react_jsx_runtime.jsxs)("div", {
15227
+ className: PendingPanel_module_css_default.settingsRowText,
15228
+ children: [(0, react_jsx_runtime.jsx)("div", {
15229
+ className: PendingPanel_module_css_default.settingsRowTitle,
15230
+ children: title
15231
+ }), (0, react_jsx_runtime.jsx)("div", {
15232
+ className: PendingPanel_module_css_default.settingsRowDesc,
15233
+ children: description
15234
+ })]
15235
+ }), (0, react_jsx_runtime.jsxs)("div", {
15236
+ className: PendingPanel_module_css_default.stepper,
15237
+ children: [
15238
+ (0, react_jsx_runtime.jsx)("button", {
15239
+ type: "button",
15240
+ className: PendingPanel_module_css_default.stepperButton,
15241
+ "data-diff-stepper-down": true,
15242
+ "aria-label": t("action.decrease"),
15243
+ disabled: value <= min,
15244
+ onClick: () => {
15245
+ onChange(Math.max(min, value - 1));
15246
+ },
15247
+ children: "−"
15248
+ }),
15249
+ (0, react_jsx_runtime.jsx)("span", {
15250
+ className: PendingPanel_module_css_default.stepperValue,
15251
+ [dataAttribute]: true,
15252
+ children: value
15253
+ }),
15254
+ (0, react_jsx_runtime.jsx)("button", {
15255
+ type: "button",
15256
+ className: PendingPanel_module_css_default.stepperButton,
15257
+ "data-diff-stepper-up": true,
15258
+ "aria-label": t("action.increase"),
15259
+ disabled: value >= max,
15260
+ onClick: () => {
15261
+ onChange(Math.min(max, value + 1));
15262
+ },
15263
+ children: "+"
15264
+ })
15265
+ ]
15266
+ })]
15267
+ });
15268
+ }
14808
15269
  /** Build the `Modifier+...+Key` chord label from a keydown event; a bare
14809
15270
  * modifier key alone returns undefined (wait for the full combo). */
14810
15271
  function chordLabel(event) {
@@ -14877,13 +15338,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14877
15338
  */
14878
15339
  function DiffApprovalSettingsTab({ t }) {
14879
15340
  const [pasteOnCopy, setPasteOnCopyState] = (0, react.useState)(pasteOnCopyEnabled);
14880
- const [pasteOnCopyOpen, setPasteOnCopyOpen] = (0, react.useState)(false);
14881
15341
  const [includeUntracked, setIncludeUntrackedState] = (0, react.useState)(includeUntrackedEnabled);
14882
- const [includeUntrackedOpen, setIncludeUntrackedOpen] = (0, react.useState)(false);
14883
15342
  const [tab, setTabState] = (0, react.useState)(tabWidth);
14884
15343
  const [tabOpen, setTabOpen] = (0, react.useState)(false);
14885
15344
  const [split, setSplitState] = (0, react.useState)(splitMode);
14886
- const [splitOpen, setSplitOpen] = (0, react.useState)(false);
15345
+ const [lead, setLeadState] = (0, react.useState)(navLeadRows);
14887
15346
  const [summon, setSummonState] = (0, react.useState)(quickSummonKey);
14888
15347
  const setSummon = (value) => {
14889
15348
  setSummonState(value);
@@ -14905,6 +15364,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14905
15364
  setSplitState(value);
14906
15365
  setSplitMode(value);
14907
15366
  };
15367
+ const setLead = (value) => {
15368
+ setLeadState(value);
15369
+ setNavLeadRows(value);
15370
+ };
14908
15371
  return (0, react_jsx_runtime.jsxs)("div", {
14909
15372
  className: PendingPanel_module_css_default.settingsPage,
14910
15373
  "data-diff-settings": true,
@@ -14913,8 +15376,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14913
15376
  title: t("panel.pasteOnCopy"),
14914
15377
  description: t("panel.pasteOnCopyDesc"),
14915
15378
  value: pasteOnCopy,
14916
- open: pasteOnCopyOpen,
14917
- onOpenChange: setPasteOnCopyOpen,
14918
15379
  onSelect: setPasteOnCopy,
14919
15380
  dataAttribute: "data-diff-paste-on-copy-select",
14920
15381
  t
@@ -14923,8 +15384,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14923
15384
  title: t("panel.importUntracked"),
14924
15385
  description: t("panel.importUntrackedDesc"),
14925
15386
  value: includeUntracked,
14926
- open: includeUntrackedOpen,
14927
- onOpenChange: setIncludeUntrackedOpen,
14928
15387
  onSelect: setIncludeUntracked,
14929
15388
  dataAttribute: "data-diff-import-untracked-select",
14930
15389
  t
@@ -14942,12 +15401,20 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14942
15401
  title: t("panel.splitMode"),
14943
15402
  description: t("panel.splitModeDesc"),
14944
15403
  value: split,
14945
- open: splitOpen,
14946
- onOpenChange: setSplitOpen,
14947
15404
  onSelect: setSplit,
14948
15405
  dataAttribute: "data-diff-split-mode-select",
14949
15406
  t
14950
15407
  }),
15408
+ (0, react_jsx_runtime.jsx)(StepperRow, {
15409
+ title: t("panel.navLeadRows"),
15410
+ description: t("panel.navLeadRowsDesc"),
15411
+ value: lead,
15412
+ onChange: setLead,
15413
+ min: 0,
15414
+ max: 10,
15415
+ dataAttribute: "data-diff-nav-lead-rows",
15416
+ t
15417
+ }),
14951
15418
  (0, react_jsx_runtime.jsx)(ShortcutRow, {
14952
15419
  title: t("panel.quickSummon"),
14953
15420
  description: t("panel.quickSummonDesc"),
@@ -15497,7 +15964,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15497
15964
  "panel.missingHint": "该文件已不存在,回退会恢复该文件。",
15498
15965
  "panel.externalChanged": "检测到文件在外部被修改,已更新对比并新建撤销点;重做历史已被重置。",
15499
15966
  "panel.dismiss": "知道了",
15500
- "panel.createHint": "回退会删除该新建的文件。",
15501
15967
  "panel.pasteOnCopy": "复制引用后自动粘贴到消息输入框",
15502
15968
  "panel.pasteOnCopyDesc": "开启后,复制的引用会自动填入消息输入框,输入框会获得焦点。",
15503
15969
  "panel.importUntracked": "导入未跟踪的文件改动",
@@ -15506,8 +15972,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15506
15972
  "panel.tabWidthDesc": "差异中制表符的缩进宽度,可选 2 / 4 / 8 个空格(默认 4),同时作用于行宽折行测量。",
15507
15973
  "panel.splitMode": "双栏对比",
15508
15974
  "panel.splitModeDesc": "开启后整文件差异用左「改前」|右「当前」双栏、逐行对齐的视图展示,默认关闭使用单栏(合并)视图。",
15975
+ "panel.navLeadRows": "差异跳转行距",
15976
+ "panel.navLeadRowsDesc": "按上/下跳转差异时,目标差异上方保留的行数(默认 2)。也用于从当前滚动位置定位上/下一个差异。",
15509
15977
  "panel.quickSummon": "快速呼出",
15510
- "panel.quickSummonDesc": "用键盘快捷键打开/关闭差异面板(默认 Ctrl+D)。点击右侧按钮后按下新的按键组合即可修改,Esc 取消。",
15978
+ "panel.quickSummonDesc": "用键盘快捷键打开/关闭差异面板。点击右侧按钮后按下新的按键组合即可修改。",
15511
15979
  "panel.recordShortcut": "按下快捷键…",
15512
15980
  "settings.tabLabel": "改动审批",
15513
15981
  "row.create": "新增文件",
@@ -15517,6 +15985,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15517
15985
  "row.removed": "-{removed}",
15518
15986
  "action.keep": "保留",
15519
15987
  "action.revert": "回退",
15988
+ "action.delete": "删除",
15520
15989
  "action.keepAll": "全部保留",
15521
15990
  "action.revertAll": "全部回退",
15522
15991
  "action.openFile": "打开文件",
@@ -15534,6 +16003,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15534
16003
  "action.wrap": "自动换行",
15535
16004
  "action.toggleOn": "打开",
15536
16005
  "action.toggleOff": "关闭",
16006
+ "action.decrease": "减小",
16007
+ "action.increase": "增大",
15537
16008
  "action.importVcs": "导入工作区改动",
15538
16009
  "action.importVcsBusy": "导入中…",
15539
16010
  "panel.importNone": "没有可导入的改动",
@@ -15568,7 +16039,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15568
16039
  "panel.missingHint": "This file no longer exists; reverting restores it.",
15569
16040
  "panel.externalChanged": "A file changed outside the review. The comparison was updated and a new undo point created; the redo history was reset.",
15570
16041
  "panel.dismiss": "Got it",
15571
- "panel.createHint": "Reverting removes this created file.",
15572
16042
  "panel.pasteOnCopy": "Paste the copied reference into the composer",
15573
16043
  "panel.pasteOnCopyDesc": "When enabled, a copied reference is pasted into the composer, which then receives focus.",
15574
16044
  "panel.importUntracked": "Import changes to untracked files",
@@ -15577,8 +16047,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15577
16047
  "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.",
15578
16048
  "panel.splitMode": "Side-by-side view",
15579
16049
  "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.",
16050
+ "panel.navLeadRows": "Block jump lead rows",
16051
+ "panel.navLeadRowsDesc": "Rows left above the jumped-to diff block on up/down navigation (default 2). Also used to locate the previous/next diff from the current scroll position.",
15580
16052
  "panel.quickSummon": "Quick summon",
15581
- "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.",
16053
+ "panel.quickSummonDesc": "Open or close the diff panel with a keyboard shortcut. Click the button and press a new chord to change it.",
15582
16054
  "panel.recordShortcut": "Press keys…",
15583
16055
  "settings.tabLabel": "Diff Approval",
15584
16056
  "row.create": "New file",
@@ -15588,6 +16060,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15588
16060
  "row.removed": "-{removed}",
15589
16061
  "action.keep": "Keep",
15590
16062
  "action.revert": "Revert",
16063
+ "action.delete": "Delete",
15591
16064
  "action.keepAll": "Keep all",
15592
16065
  "action.revertAll": "Revert all",
15593
16066
  "action.openFile": "Open file",
@@ -15605,6 +16078,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15605
16078
  "action.wrap": "Wrap lines",
15606
16079
  "action.toggleOn": "On",
15607
16080
  "action.toggleOff": "Off",
16081
+ "action.decrease": "Decrease",
16082
+ "action.increase": "Increase",
15608
16083
  "action.importVcs": "Import workspace changes",
15609
16084
  "action.importVcsBusy": "Importing…",
15610
16085
  "panel.importNone": "No changes to import",