@young1lin/dsh-ui-gitworkbench 0.1.2 → 0.1.4

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
@@ -487,6 +487,597 @@ window.__ModuleLoader__.load({
487
487
  };
488
488
  }
489
489
  //#endregion
490
+ //#region src/client/commit-filter.ts
491
+ /**
492
+ * Render a commit's ISO 8601 date in full — "Aug 4, 2026, 5:30 PM", in the
493
+ * viewer's locale and timezone (or the overrides, which exist for tests).
494
+ *
495
+ * git's relative prose ("3 weeks ago") is right for the row and useless for
496
+ * the hover card, where the question is exactly WHEN. `%cI` is a strict ISO
497
+ * timestamp, so `new Date` parses it and the formatter renders local time —
498
+ * the same moment the viewer's own clock shows, which is the only timezone a
499
+ * hover card should speak. Unparsable input yields an empty string rather
500
+ * than a thrown RangeError: the card simply omits the line.
501
+ * @param iso - `%cI` string from the host log, possibly empty or absent.
502
+ * @param options - locale/timezone overrides; both optional.
503
+ */
504
+ function formatCommitDate(iso, options = {}) {
505
+ if (iso.length === 0) return "";
506
+ const date = new Date(iso);
507
+ if (Number.isNaN(date.getTime())) return "";
508
+ return new Intl.DateTimeFormat(options.locale, {
509
+ year: "numeric",
510
+ month: "short",
511
+ day: "numeric",
512
+ hour: "2-digit",
513
+ minute: "2-digit",
514
+ ...options.timeZone !== void 0 ? { timeZone: options.timeZone } : {}
515
+ }).format(date);
516
+ }
517
+ //#endregion
518
+ //#region src/client/log-filter-query.ts
519
+ /** The filter that filters nothing. */
520
+ function emptyQueryFilter() {
521
+ return {
522
+ users: [],
523
+ text: "",
524
+ textRegex: false,
525
+ paths: [],
526
+ after: "",
527
+ before: ""
528
+ };
529
+ }
530
+ const PREFIX_RE = /^(user|path|after|before):(.*)$/i;
531
+ function tokenize(query) {
532
+ const tokens = [];
533
+ let i = 0;
534
+ while (i < query.length) {
535
+ while (i < query.length && /\s/.test(query[i])) i += 1;
536
+ if (i >= query.length) break;
537
+ if (query[i] === "\"") {
538
+ const end = query.indexOf("\"", i + 1);
539
+ const value = end === -1 ? query.slice(i + 1) : query.slice(i + 1, end);
540
+ tokens.push({
541
+ value,
542
+ quoted: true
543
+ });
544
+ i = end === -1 ? query.length : end + 1;
545
+ continue;
546
+ }
547
+ const prefixQuote = /^(user|path|after|before):"/i.exec(query.slice(i));
548
+ if (prefixQuote !== null) {
549
+ const kind = prefixQuote[1].toLowerCase();
550
+ const open = i + prefixQuote[0].length;
551
+ const end = query.indexOf("\"", open);
552
+ const value = end === -1 ? query.slice(open) : query.slice(open, end);
553
+ tokens.push({
554
+ value,
555
+ quoted: true,
556
+ kind
557
+ });
558
+ i = end === -1 ? query.length : end + 1;
559
+ continue;
560
+ }
561
+ const start = i;
562
+ while (i < query.length && !/\s/.test(query[i])) i += 1;
563
+ const word = query.slice(start, i);
564
+ const match = PREFIX_RE.exec(word);
565
+ tokens.push(match === null ? {
566
+ value: word,
567
+ quoted: false
568
+ } : {
569
+ value: match[2],
570
+ quoted: false,
571
+ kind: match[1].toLowerCase()
572
+ });
573
+ }
574
+ return tokens;
575
+ }
576
+ /**
577
+ * Parse the box's text into a filter.
578
+ * @param query - raw box contents.
579
+ */
580
+ function parseLogQuery(query) {
581
+ const tokens = tokenize(query);
582
+ const users = [];
583
+ const paths = [];
584
+ let text = "";
585
+ let after = "";
586
+ let before = "";
587
+ const textWords = [];
588
+ let i = 0;
589
+ while (i < tokens.length) {
590
+ const token = tokens[i];
591
+ if (token.kind === void 0) {
592
+ textWords.push(token.value);
593
+ i += 1;
594
+ continue;
595
+ }
596
+ if (token.kind === "user" || token.kind === "path") {
597
+ const list = token.kind === "user" ? users : paths;
598
+ if (token.value.length > 0 && !list.includes(token.value)) list.push(token.value);
599
+ i += 1;
600
+ continue;
601
+ }
602
+ const parts = [token.value];
603
+ let j = token.quoted ? i : i + 1;
604
+ while (j < tokens.length && tokens[j].kind === void 0 && !tokens[j].quoted && tokens[j].value.length > 0) {
605
+ parts.push(tokens[j].value);
606
+ j += 1;
607
+ }
608
+ const value = parts.join(" ").trim();
609
+ if (token.kind === "after") after = value;
610
+ else before = value;
611
+ i = token.quoted ? i + 1 : j;
612
+ }
613
+ text = textWords.join(" ").trim();
614
+ return {
615
+ users,
616
+ text,
617
+ textRegex: false,
618
+ paths,
619
+ after,
620
+ before
621
+ };
622
+ }
623
+ /** Quote a serialized value iff it would not reparse as itself. */
624
+ function quote(value) {
625
+ return /\s/.test(value) ? `"${value}"` : value;
626
+ }
627
+ /**
628
+ * Render a filter back into the box's grammar. The text criterion goes last
629
+ * and is quoted when any of its words would parse as a prefix token.
630
+ * @param filter - the filter to render.
631
+ */
632
+ function serializeLogQuery(filter) {
633
+ const parts = [];
634
+ for (const user of filter.users) parts.push(`user:${quote(user)}`);
635
+ for (const path of filter.paths) parts.push(`path:${quote(path)}`);
636
+ if (filter.after.length > 0) parts.push(`after:${quote(filter.after)}`);
637
+ if (filter.before.length > 0) parts.push(`before:${quote(filter.before)}`);
638
+ if (filter.text.length > 0) {
639
+ const looksPrefixed = filter.text.split(/\s+/).some((word) => PREFIX_RE.test(word));
640
+ parts.push(looksPrefixed ? `"${filter.text}"` : filter.text);
641
+ }
642
+ return parts.join(" ");
643
+ }
644
+ /**
645
+ * One chip per criterion, in grammar order: users, paths, bounds, text.
646
+ * @param filter - the filter to decompose.
647
+ */
648
+ function chipsFromFilter(filter) {
649
+ const chips = [];
650
+ for (const user of filter.users) chips.push({
651
+ kind: "user",
652
+ value: user
653
+ });
654
+ for (const path of filter.paths) chips.push({
655
+ kind: "path",
656
+ value: path
657
+ });
658
+ if (filter.after.length > 0) chips.push({
659
+ kind: "after",
660
+ value: filter.after
661
+ });
662
+ if (filter.before.length > 0) chips.push({
663
+ kind: "before",
664
+ value: filter.before
665
+ });
666
+ if (filter.text.length > 0) chips.push({
667
+ kind: "text",
668
+ value: filter.text
669
+ });
670
+ return chips;
671
+ }
672
+ /**
673
+ * The filter minus one chip. Immutable; dropping the last criterion yields
674
+ * the empty filter.
675
+ * @param filter - current filter.
676
+ * @param kind - the chip's criterion kind.
677
+ * @param value - the chip's value (which user, which path).
678
+ */
679
+ function removeChip(filter, kind, value) {
680
+ switch (kind) {
681
+ case "user": return {
682
+ ...filter,
683
+ users: filter.users.filter((user) => user !== value)
684
+ };
685
+ case "path": return {
686
+ ...filter,
687
+ paths: filter.paths.filter((path) => path !== value)
688
+ };
689
+ case "after": return {
690
+ ...filter,
691
+ after: ""
692
+ };
693
+ case "before": return {
694
+ ...filter,
695
+ before: ""
696
+ };
697
+ case "text": return {
698
+ ...filter,
699
+ text: "",
700
+ textRegex: false
701
+ };
702
+ }
703
+ }
704
+ //#endregion
705
+ //#region src/client/dir-tree.ts
706
+ /**
707
+ * Fold a flat path list into a sorted directory tree carrying its files.
708
+ * Root-level files live on no directory; the SEARCH ({@link searchPaths}) is
709
+ * where they surface.
710
+ * @param paths - repo-relative file paths, any order, no duplicates assumed.
711
+ * @returns the top-level directories, children and files sorted by name.
712
+ */
713
+ function buildDirTree(paths) {
714
+ const rootNode = {
715
+ name: "",
716
+ path: "",
717
+ files: [],
718
+ children: /* @__PURE__ */ new Map()
719
+ };
720
+ for (const path of paths) {
721
+ if (path.length === 0) continue;
722
+ const parts = path.split("/");
723
+ let node = rootNode;
724
+ for (let i = 0; i < parts.length - 1; i += 1) {
725
+ const name = parts[i];
726
+ let child = node.children.get(name);
727
+ if (child === void 0) {
728
+ child = {
729
+ name,
730
+ path: parts.slice(0, i + 1).join("/"),
731
+ files: [],
732
+ children: /* @__PURE__ */ new Map()
733
+ };
734
+ node.children.set(name, child);
735
+ }
736
+ node = child;
737
+ }
738
+ node.files.push(parts[parts.length - 1]);
739
+ }
740
+ const freeze = (node) => {
741
+ const children = [...node.children.values()].sort((a, b) => a.name.localeCompare(b.name)).map(freeze);
742
+ const files = [...node.files].sort((a, b) => a.localeCompare(b));
743
+ const subtreeCount = files.length + children.reduce((sum, child) => sum + child.fileCount, 0);
744
+ return {
745
+ name: node.name,
746
+ path: node.path,
747
+ fileCount: subtreeCount,
748
+ files,
749
+ children
750
+ };
751
+ };
752
+ return freeze(rootNode).children;
753
+ }
754
+ /**
755
+ * Search the repository's paths for a fragment — case-insensitive, over the
756
+ * full path. Results are FLAT: a search list is not a tree (the same honesty
757
+ * as the filtered commit list), and each hit ticks as a pathspec directly.
758
+ *
759
+ * Directories match too: every directory is some file's prefix, and ticking a
760
+ * directory covers its subtree — the search takes the raw path list the host
761
+ * sent, so root-level files and unexpanded directories are all in scope.
762
+ * @param paths - repo-relative file paths, exactly as `repoTree` returned.
763
+ * @param needle - raw search text; blank matches nothing (caller shows the tree).
764
+ */
765
+ function searchPaths(paths, needle) {
766
+ const n = needle.trim().toLowerCase();
767
+ if (n.length === 0) return [];
768
+ const hits = [];
769
+ const seen = /* @__PURE__ */ new Set();
770
+ for (const path of paths) {
771
+ if (path.toLowerCase().includes(n)) {
772
+ hits.push({
773
+ path,
774
+ isFile: true
775
+ });
776
+ seen.add(path);
777
+ }
778
+ const parts = path.split("/");
779
+ for (let i = 1; i < parts.length; i += 1) {
780
+ const dir = parts.slice(0, i).join("/");
781
+ if (!seen.has(dir) && dir.toLowerCase().includes(n)) {
782
+ seen.add(dir);
783
+ hits.push({
784
+ path: dir,
785
+ isFile: false
786
+ });
787
+ }
788
+ }
789
+ }
790
+ return [...hits.filter((hit) => hit.isFile), ...hits.filter((hit) => !hit.isFile)];
791
+ }
792
+ //#endregion
793
+ //#region src/client/file-filter.ts
794
+ /**
795
+ * Narrowing a file list by typing at it.
796
+ *
797
+ * A commit that touched 140 files is a scroll, not a list, and the drawer's
798
+ * tree is the same object in every tab — so the rule lives here once and both
799
+ * the working tree and a commit's contents get it.
800
+ *
801
+ * Two decisions worth stating, because both are the kind that get "simplified"
802
+ * later:
803
+ *
804
+ * - **Terms are ANDed, in any order.** `panel css` finds
805
+ * `src/client/GitWorkbenchPanel.module.css` — which is how anyone types
806
+ * when they half-remember a path, and is the behaviour a single-substring
807
+ * match gets wrong for exactly the paths that are long enough to need
808
+ * filtering.
809
+ * - **Smart case.** An all-lowercase query ignores case; the moment the
810
+ * reader types a capital they mean it. `README` should not match
811
+ * `readme-generator`, and `readme` should still find `README.md`.
812
+ *
813
+ * The result keeps the caller's order and its element type: the tree is built
814
+ * from whatever survives, so filtering never has to know what a file is beyond
815
+ * its path.
816
+ *
817
+ * @module @young1lin/dsh-ui-gitworkbench/client/file-filter
818
+ */
819
+ /** Split a raw query into the terms every path must contain. */
820
+ function termsOf(query) {
821
+ return query.split(/\s+/).filter((term) => term.length > 0);
822
+ }
823
+ /**
824
+ * Whether one path satisfies a query.
825
+ *
826
+ * @param path - repo-relative path, as the tree lists it.
827
+ * @param query - raw text from the filter box; blank matches everything, so a
828
+ * caller that renders `filterFiles` unconditionally shows the
829
+ * whole list until something is typed.
830
+ */
831
+ function matchesPath(path, query) {
832
+ const terms = termsOf(query);
833
+ if (terms.length === 0) return true;
834
+ return terms.every((term) => {
835
+ return term.toLowerCase() !== term ? path.includes(term) : path.toLowerCase().includes(term.toLowerCase());
836
+ });
837
+ }
838
+ /**
839
+ * Keep the files whose path satisfies the query, in the order given.
840
+ *
841
+ * @param files - anything carrying a `path`; the tree's own file objects.
842
+ * @param query - raw text from the filter box.
843
+ * @returns the same array instance when nothing is filtered out, so a blank
844
+ * query costs no re-render downstream.
845
+ */
846
+ function filterFiles(files, query) {
847
+ if (termsOf(query).length === 0) return files;
848
+ return files.filter((file) => matchesPath(file.path, query));
849
+ }
850
+ //#endregion
851
+ //#region src/client/path-select.ts
852
+ /**
853
+ * Index a raw path list for child lookup.
854
+ * @param paths - repo-relative file paths, exactly as `repoTree` returned.
855
+ */
856
+ function buildIndex(paths) {
857
+ const dirs = /* @__PURE__ */ new Map();
858
+ const files = /* @__PURE__ */ new Map();
859
+ const noteDir = (dir) => {
860
+ if (!dirs.has(dir)) dirs.set(dir, []);
861
+ };
862
+ noteDir("");
863
+ for (const path of paths) {
864
+ if (path.length === 0) continue;
865
+ const parts = path.split("/");
866
+ let dir = "";
867
+ for (let i = 0; i < parts.length - 1; i += 1) {
868
+ const childDir = dir === "" ? parts[i] : `${dir}/${parts[i]}`;
869
+ noteDir(childDir);
870
+ const list = dirs.get(dir);
871
+ if (!list.includes(childDir)) list.push(childDir);
872
+ dir = childDir;
873
+ }
874
+ const list = files.get(dir) ?? [];
875
+ list.push(path);
876
+ files.set(dir, list);
877
+ }
878
+ for (const list of dirs.values()) list.sort();
879
+ for (const list of files.values()) list.sort();
880
+ return {
881
+ dirs,
882
+ files
883
+ };
884
+ }
885
+ /** Children of a directory, alphabetical by full path — the tree's order. */
886
+ function childrenOf(index, dir) {
887
+ return [...index.dirs.get(dir) ?? [], ...index.files.get(dir) ?? []].sort();
888
+ }
889
+ /**
890
+ * Is `p` selected — itself ticked, or inside a ticked directory?
891
+ * (Segment-boundary prefix: `src` does not cover `src2`.)
892
+ */
893
+ function isCovered(paths, p) {
894
+ return paths.some((tick) => tick === p || p.startsWith(`${tick}/`));
895
+ }
896
+ /**
897
+ * Tick a path. No-op when an ancestor already covers it; absorbs every
898
+ * descendant it covers, keeping the set minimal — one folder chip, never the
899
+ * pile of files under it.
900
+ */
901
+ function addPath(paths, p) {
902
+ if (isCovered(paths, p)) return paths;
903
+ return [...paths.filter((tick) => !(tick === p || tick.startsWith(`${p}/`))), p];
904
+ }
905
+ /**
906
+ * Untick a path. Removing an exact tick drops it; removing a file COVERED by
907
+ * a ticked folder replaces that folder with its other children, level by
908
+ * level down to the file — the standard cascade-out.
909
+ */
910
+ function removePath(paths, p, index) {
911
+ const out = [];
912
+ for (const tick of paths) {
913
+ if (tick !== p && !p.startsWith(`${tick}/`)) {
914
+ out.push(tick);
915
+ continue;
916
+ }
917
+ let dir = tick;
918
+ while (dir !== p) {
919
+ const rest = p.slice(dir.length + 1);
920
+ const nextName = dir === "" ? p.split("/")[0] : rest.split("/")[0];
921
+ const next = dir === "" ? nextName : `${dir}/${nextName}`;
922
+ for (const child of childrenOf(index, dir)) if (child !== next) out.push(child);
923
+ dir = next;
924
+ }
925
+ }
926
+ return out;
927
+ }
928
+ /** Every file under a directory (empty for a file path). */
929
+ function filesUnder$1(index, dir) {
930
+ const out = [];
931
+ const stack = [dir];
932
+ while (stack.length > 0) {
933
+ const current = stack.pop();
934
+ out.push(...index.files.get(current) ?? []);
935
+ stack.push(...index.dirs.get(current) ?? []);
936
+ }
937
+ return out;
938
+ }
939
+ /**
940
+ * A row's checkbox state, derived: `on` when covered — by an ancestor tick OR
941
+ * by every file under it being covered individually; `partial` when a
942
+ * directory holds some but not all of its files; else `off`.
943
+ */
944
+ function checkedState(paths, p, index) {
945
+ if (isCovered(paths, p)) return "on";
946
+ const files = filesUnder$1(index, p);
947
+ if (files.length === 0) return "off";
948
+ const covered = files.filter((file) => isCovered(paths, file)).length;
949
+ return covered === files.length ? "on" : covered > 0 ? "partial" : "off";
950
+ }
951
+ //#endregion
952
+ //#region src/client/calendar.ts
953
+ const DAY_MS = 864e5;
954
+ function toIso(date) {
955
+ const m = String(date.getUTCMonth() + 1).padStart(2, "0");
956
+ const d = String(date.getUTCDate()).padStart(2, "0");
957
+ return `${date.getUTCFullYear()}-${m}-${d}`;
958
+ }
959
+ /**
960
+ * The 6×7 Monday-first grid for one month.
961
+ * @param year - displayed year.
962
+ * @param month - displayed month, 0-based like `Date`.
963
+ * @param todayIso - what counts as today, for the accent; `''` accents nothing.
964
+ */
965
+ function monthGrid(year, month, todayIso) {
966
+ const first = new Date(Date.UTC(year, month, 1));
967
+ const lead = (first.getUTCDay() + 6) % 7;
968
+ const start = /* @__PURE__ */ new Date(first.getTime() - lead * DAY_MS);
969
+ const weeks = [];
970
+ for (let w = 0; w < 6; w += 1) {
971
+ const row = [];
972
+ for (let d = 0; d < 7; d += 1) {
973
+ const date = new Date(start.getTime() + (w * 7 + d) * DAY_MS);
974
+ const iso = toIso(date);
975
+ row.push({
976
+ iso,
977
+ day: date.getUTCDate(),
978
+ inMonth: date.getUTCMonth() === month,
979
+ isToday: iso === todayIso
980
+ });
981
+ }
982
+ weeks.push(row);
983
+ }
984
+ return weeks;
985
+ }
986
+ /**
987
+ * Single-letter weekday header row, Monday-first, via the viewer's own locale
988
+ * (or an explicit one, which is what the test does).
989
+ * @param locale - BCP 47 tag; undefined means the runtime default.
990
+ */
991
+ function weekdayLabels(locale) {
992
+ const labels = [];
993
+ for (let d = 2; d <= 8; d += 1) labels.push(new Intl.DateTimeFormat(locale, { weekday: "narrow" }).format(new Date(Date.UTC(2023, 0, d))));
994
+ return labels;
995
+ }
996
+ /**
997
+ * Whether a day falls strictly BETWEEN the two bounds, so the grid can tint
998
+ * the span the filter admits rather than only its two endpoints.
999
+ *
1000
+ * Both bounds have to be `yyyy-mm-dd` for a range to exist: the bounds also
1001
+ * accept approxidate text (`1 week ago`), which names no grid day at all, and
1002
+ * lexical comparison on iso dates is the same as chronological. An inverted
1003
+ * pair (after > before) is a range git returns nothing for, and it tints
1004
+ * nothing here for the same reason.
1005
+ *
1006
+ * @param iso - the cell's day.
1007
+ * @param after - lower bound, exclusive here (it renders as an endpoint).
1008
+ * @param before - upper bound, exclusive here.
1009
+ */
1010
+ function inCalRange(iso, after, before) {
1011
+ if (!ISO_DAY.test(after) || !ISO_DAY.test(before)) return false;
1012
+ return iso > after && iso < before;
1013
+ }
1014
+ const ISO_DAY = /^\d{4}-\d{2}-\d{2}$/;
1015
+ /** Today as `yyyy-mm-dd` in the viewer's local timezone (for `todayIso`). */
1016
+ function localTodayIso() {
1017
+ const now = /* @__PURE__ */ new Date();
1018
+ const m = String(now.getMonth() + 1).padStart(2, "0");
1019
+ const d = String(now.getDate()).padStart(2, "0");
1020
+ return `${now.getFullYear()}-${m}-${d}`;
1021
+ }
1022
+ //#endregion
1023
+ //#region src/client/active-file.ts
1024
+ /** No filter — a shared empty so callers keep a stable reference. */
1025
+ const NO_PATHS = [];
1026
+ /**
1027
+ * Whether a file is what a pathspec selected: the file itself, or anything in
1028
+ * its subtree.
1029
+ *
1030
+ * A pathspec from the picker is either a file path or a directory path with no
1031
+ * trailing slash (`dir.path` / the file's full path — `path-select.ts`), and
1032
+ * the two cases are told apart by the file rather than by the spec: `===` is
1033
+ * the file, `spec + '/'` prefix is the subtree. Guessing which KIND a spec is
1034
+ * from its string alone is what a trailing-slash convention would force, and
1035
+ * it would be wrong for any file without an extension.
1036
+ */
1037
+ function covers(spec, path) {
1038
+ return path === spec || path.startsWith(`${spec}/`);
1039
+ }
1040
+ /**
1041
+ * The file a view should highlight.
1042
+ *
1043
+ * The order of preference, and why it is this order:
1044
+ *
1045
+ * 1. **The selection, if this view has it.** Stepping down a filtered list is
1046
+ * the whole point of filtering; changing the file under the reader every
1047
+ * time they move a row would undo it. This also means an explicit click
1048
+ * outranks the filter — the reader looked somewhere on purpose.
1049
+ * 2. **A file the filter names EXACTLY.** Ticking `xx/aa/dd.ts` is a statement
1050
+ * about that file; ticking `xx` is a statement about a region. When a
1051
+ * commit touches both kinds, the named file is the more specific intent, so
1052
+ * it wins. (The two can only coexist across disjoint trees: the picker's
1053
+ * invariant is that no ticked path covers another.)
1054
+ * 3. **A file under a filtered directory.**
1055
+ * 4. **The first file.** No filter, or nothing in this commit matched it —
1056
+ * the behaviour before any of this existed.
1057
+ *
1058
+ * Ties inside 2 and 3 go to the commit's own file order, which is the order
1059
+ * the tree renders: the highlight lands on the topmost matching row, so it is
1060
+ * where the reader is already looking and never needs a scroll to find. The
1061
+ * alternative — first match in FILTER order — would be arbitrary, since that
1062
+ * order is an artifact of the sequence the boxes were ticked in and is never
1063
+ * shown anywhere.
1064
+ *
1065
+ * @param files - the view's files, in the order the tree shows them.
1066
+ * @param filterPaths - active path filter; empty on views that have none.
1067
+ * @param previous - the currently selected path, or null.
1068
+ * @returns the path to highlight, or null when there are no files at all.
1069
+ */
1070
+ function preferredFile(files, filterPaths, previous) {
1071
+ if (previous !== null && files.some((file) => file.path === previous)) return previous;
1072
+ if (filterPaths.length > 0) {
1073
+ const exact = files.find((file) => filterPaths.some((spec) => file.path === spec));
1074
+ if (exact !== void 0) return exact.path;
1075
+ const under = files.find((file) => filterPaths.some((spec) => covers(spec, file.path)));
1076
+ if (under !== void 0) return under.path;
1077
+ }
1078
+ return files[0]?.path ?? null;
1079
+ }
1080
+ //#endregion
490
1081
  //#region src/client/stage-tree.ts
491
1082
  /**
492
1083
  * One file's tick.
@@ -11613,7 +12204,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
11613
12204
  }
11614
12205
  //#endregion
11615
12206
  //#region \0dsh-css:src/client/GitWorkbenchPanel.module.css.mjs
11616
- const css = ".SD8qLW_card{border:1px solid var(--dsw-alias-border-l2);min-height:28px;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;cursor:pointer;background:0 0;border-radius:8px;align-items:center;gap:7px;padding:3px 10px;font-size:12px;line-height:18px;transition:background .12s,border-color .12s;display:inline-flex}.SD8qLW_card:hover,.SD8qLW_card:focus-visible{background:var(--dsw-alias-interactive-bg-hover);border-color:var(--dsw-alias-border-l3)}.SD8qLW_cardBranch{max-width:220px;color:var(--dsw-alias-label-primary);align-items:center;gap:4px;font-weight:550;display:inline-flex;overflow:hidden}.SD8qLW_cardBranchName{min-width:0;overflow:hidden}.SD8qLW_cardGlyph{opacity:.7;flex:none}.SD8qLW_cardDetached{background:var(--dsw-alias-state-warning-bg,#bb800926);color:var(--dsw-alias-state-warning-primary,#d29922);letter-spacing:.02em;border-radius:999px;padding:0 6px;font-size:10px;line-height:16px}.SD8qLW_cardWt{background:var(--dsw-alias-state-business-bg,#388bfd29);max-width:150px;color:var(--dsw-alias-state-business-primary,#58a6ff);letter-spacing:.02em;white-space:nowrap;text-overflow:ellipsis;border-radius:999px;align-items:center;gap:3px;padding:0 6px;font-size:10px;line-height:16px;display:inline-flex;overflow:hidden}.SD8qLW_cardAhead,.SD8qLW_cardBehind{color:var(--dsw-alias-label-tertiary);font-size:11px}.SD8qLW_cardAhead{color:var(--dsw-alias-state-success-primary)}.SD8qLW_cardBehind{color:var(--dsw-alias-state-attention-primary,#d29922)}.SD8qLW_cardSep{background:var(--dsw-alias-border-l2);width:1px;height:14px}.SD8qLW_cardAdded{color:var(--dsw-alias-state-success-primary)}.SD8qLW_cardDeleted{color:var(--dsw-alias-state-error-primary)}.SD8qLW_cardFiles{color:var(--dsw-alias-label-tertiary)}.SD8qLW_overlay[data-gs-theme=github-dark]{--gs-bg:#0d1117;--gs-panel:#161b22;--gs-raise:#21262d;--gs-border:#30363d;--gs-border-soft:#21262d;--gs-fg:#e6edf3;--gs-fg-muted:#c9d1d9;--gs-fg-dim:#8b949e;--gs-fg-faint:#6e7681;--gs-fg-fainter:#484f58;--gs-accent:#58a6ff;--gs-accent-bg:#388bfd24;--gs-accent-border:#388bfd8c;--gs-add:#3fb950;--gs-del:#f85149;--gs-warn:#d29922;--gs-info:#79c0ff;--gs-add-bg:#2ea04329;--gs-del-bg:#f8514929;--gs-warn-bg:#bb800929;--gs-info-bg:#388bfd29;--gs-add-line:#12261e;--gs-del-line:#25181c;--gs-add-word:#1a4a29;--gs-del-word:#6b2b2b;--gs-add-num:#1c4428;--gs-del-num:#542426;--gs-hunk:#111d2e;--gs-hunk-num:#0c2d6b;--gs-neutral-bg:#6e76812e;--gs-backdrop:#01040999;--gs-shadow:#0104098c}.SD8qLW_overlay[data-gs-theme=github-light]{--gs-bg:#fff;--gs-panel:#f6f8fa;--gs-raise:#eaeef2;--gs-border:#d0d7de;--gs-border-soft:#eaeef2;--gs-fg:#1f2328;--gs-fg-muted:#32383f;--gs-fg-dim:#656d76;--gs-fg-faint:#8c959f;--gs-fg-fainter:#afb8c1;--gs-accent:#0969da;--gs-accent-bg:#0969da1a;--gs-accent-border:#0969da73;--gs-add:#1a7f37;--gs-del:#cf222e;--gs-warn:#9a6700;--gs-info:#0550ae;--gs-add-bg:#1a7f371f;--gs-del-bg:#cf222e1f;--gs-warn-bg:#9a67001f;--gs-info-bg:#0969da1f;--gs-add-line:#dafbe1;--gs-del-line:#ffebe9;--gs-add-word:#aceebb;--gs-del-word:#ffcecb;--gs-add-num:#aceebb;--gs-del-num:#ffcecb;--gs-hunk:#ddf4ff;--gs-hunk-num:#b6e3ff;--gs-neutral-bg:#6e76811f;--gs-backdrop:#1f232847;--gs-shadow:#1f232838}.SD8qLW_overlay[data-gs-theme=idea-dark]{--gs-bg:#1e1f22;--gs-panel:#2b2d30;--gs-raise:#393b40;--gs-border:#393b40;--gs-border-soft:#2b2d30;--gs-fg:#dfe1e5;--gs-fg-muted:#ced0d6;--gs-fg-dim:#9da0a8;--gs-fg-faint:#6f737a;--gs-fg-fainter:#4e5157;--gs-accent:#548af7;--gs-accent-bg:#548af729;--gs-accent-border:#548af78c;--gs-add:#5fad65;--gs-del:#e26e6e;--gs-warn:#f0a732;--gs-info:#3592c4;--gs-add-bg:#5fad6529;--gs-del-bg:#e26e6e29;--gs-warn-bg:#f0a73229;--gs-info-bg:#3592c429;--gs-add-line:#293c2e;--gs-del-line:#3d2b2b;--gs-add-word:#3d6640;--gs-del-word:#6b3838;--gs-hunk:#548af71a;--gs-neutral-bg:#9da0a82e;--gs-backdrop:#10111399;--gs-shadow:#00000080}.SD8qLW_overlay[data-gs-theme=idea-light]{--gs-bg:#fff;--gs-panel:#f7f8fa;--gs-raise:#ebecf0;--gs-border:#d3d5db;--gs-border-soft:#ebecf0;--gs-fg:#1e1f22;--gs-fg-muted:#3c3f44;--gs-fg-dim:#6c707e;--gs-fg-faint:#818594;--gs-fg-fainter:#a8adbd;--gs-accent:#3574f0;--gs-accent-bg:#3574f01a;--gs-accent-border:#3574f073;--gs-add:#398a4a;--gs-del:#cc4a4a;--gs-warn:#a8760b;--gs-info:#2b7fb8;--gs-add-bg:#398a4a1f;--gs-del-bg:#cc4a4a1f;--gs-warn-bg:#a8760b1f;--gs-info-bg:#2b7fb81f;--gs-add-line:#e6f5e9;--gs-del-line:#fbe9ea;--gs-add-word:#c2e5c9;--gs-del-word:#f5c9cc;--gs-hunk:#3574f012;--gs-neutral-bg:#6c707e1f;--gs-backdrop:#1e1f2242;--gs-shadow:#1e1f222e}.SD8qLW_overlay[data-gs-theme=vscode-dark]{--gs-bg:#1e1e1e;--gs-panel:#252526;--gs-raise:#2d2d30;--gs-border:#3e3e42;--gs-border-soft:#2d2d30;--gs-fg:#d4d4d4;--gs-fg-muted:#ccc;--gs-fg-dim:#9d9d9d;--gs-fg-faint:gray;--gs-fg-fainter:#5a5a5a;--gs-accent:#0098ff;--gs-accent-bg:#007acc3d;--gs-accent-border:#0098ff99;--gs-add:#89d185;--gs-del:#f14c4c;--gs-warn:#cca700;--gs-info:#75beff;--gs-add-bg:#89d1852e;--gs-del-bg:#f14c4c2e;--gs-warn-bg:#cca7002e;--gs-info-bg:#75beff2e;--gs-add-line:#9bb9552e;--gs-del-line:#ff000029;--gs-add-word:#9bb95566;--gs-del-word:#ff00005c;--gs-hunk:#007acc24;--gs-neutral-bg:#bebebe24;--gs-backdrop:#0000008c;--gs-shadow:#0009}.SD8qLW_overlay[data-gs-theme=vscode-light]{--gs-bg:#fff;--gs-panel:#f3f3f3;--gs-raise:#e8e8e8;--gs-border:#cecece;--gs-border-soft:#e8e8e8;--gs-fg:#1e1e1e;--gs-fg-muted:#333;--gs-fg-dim:#616161;--gs-fg-faint:#767676;--gs-fg-fainter:#a0a0a0;--gs-accent:#005fb8;--gs-accent-bg:#005fb81a;--gs-accent-border:#005fb873;--gs-add:#10793f;--gs-del:#b5200d;--gs-warn:#855b00;--gs-info:#005fb8;--gs-add-bg:#10793f1f;--gs-del-bg:#b5200d1f;--gs-warn-bg:#855b001f;--gs-info-bg:#005fb81f;--gs-add-line:#9bb95538;--gs-del-line:#ff000021;--gs-add-word:#9bb95573;--gs-del-word:#ff00004d;--gs-hunk:#005fb812;--gs-neutral-bg:#6161611f;--gs-backdrop:#00000040;--gs-shadow:#0000002e}.SD8qLW_overlay[data-gs-theme=cyberpunk-dark]{--gs-bg:#0b0417;--gs-panel:#14082a;--gs-raise:#1f0d3d;--gs-border:#3a1f6b;--gs-border-soft:#26124a;--gs-fg:#f0e6ff;--gs-fg-muted:#d5c2f5;--gs-fg-dim:#a98fd6;--gs-fg-faint:#7d64a8;--gs-fg-fainter:#56427a;--gs-accent:#00f0ff;--gs-on-accent:#0b0417;--gs-accent-bg:#00f0ff24;--gs-accent-border:#00f0ff80;--gs-add:#39ff88;--gs-del:#ff2e88;--gs-warn:#fc0;--gs-info:#00f0ff;--gs-add-bg:#39ff8824;--gs-del-bg:#ff2e8824;--gs-warn-bg:#ffcc0024;--gs-info-bg:#00f0ff24;--gs-add-line:#39ff881f;--gs-del-line:#ff2e881f;--gs-add-word:#39ff8857;--gs-del-word:#ff2e8857;--gs-hunk:#00f0ff1a;--gs-neutral-bg:#a98fd629;--gs-backdrop:#06020ead;--gs-shadow:#00f0ff24}.SD8qLW_overlay[data-gs-theme=cyberpunk-light]{--gs-bg:#fdfbff;--gs-panel:#f4eeff;--gs-raise:#e9dfff;--gs-border:#c9b3f0;--gs-border-soft:#e0d2f7;--gs-fg:#1a0b2e;--gs-fg-muted:#33195c;--gs-fg-dim:#6b4ba0;--gs-fg-faint:#8f74bd;--gs-fg-fainter:#b9a5d6;--gs-accent:#00a6b8;--gs-accent-bg:#00a6b81f;--gs-accent-border:#00a6b880;--gs-add:#00875a;--gs-del:#d6006e;--gs-warn:#b37a00;--gs-info:#00a6b8;--gs-add-bg:#00875a1f;--gs-del-bg:#d6006e1f;--gs-warn-bg:#b37a001f;--gs-info-bg:#00a6b81f;--gs-add-line:#00c88224;--gs-del-line:#ff2e881f;--gs-add-word:#00c88257;--gs-del-word:#ff2e884d;--gs-hunk:#00a6b814;--gs-neutral-bg:#6b4ba01f;--gs-backdrop:#1a0b2e47;--gs-shadow:#1a0b2e29}.SD8qLW_overlay[data-gs-theme=one-dark]{--gs-bg:#282c34;--gs-panel:#21252b;--gs-raise:#2c313a;--gs-border:#3e4451;--gs-border-soft:#2c313a;--gs-fg:#abb2bf;--gs-fg-muted:#b6bdca;--gs-fg-dim:#7f848e;--gs-fg-faint:#636d83;--gs-fg-fainter:#4b5263;--gs-accent:#61afef;--gs-accent-bg:#61afef24;--gs-accent-border:#61afef8c;--gs-add:#98c379;--gs-del:#e06c75;--gs-warn:#e5c07b;--gs-info:#56b6c2;--gs-add-bg:#98c37929;--gs-del-bg:#e06c7529;--gs-warn-bg:#e5c07b29;--gs-info-bg:#56b6c229;--gs-add-line:#98c37924;--gs-del-line:#e06c7524;--gs-add-word:#98c37961;--gs-del-word:#e06c7561;--gs-hunk:#61afef1a;--gs-neutral-bg:#7f848e2e;--gs-backdrop:#171a2199;--gs-shadow:#0f11158c}.SD8qLW_overlay[data-gs-theme=one-light]{--gs-bg:#fafafa;--gs-panel:#f0f0f0;--gs-raise:#e5e5e6;--gs-border:#d4d4d4;--gs-border-soft:#e5e5e6;--gs-fg:#383a42;--gs-fg-muted:#4a4c53;--gs-fg-dim:#696c77;--gs-fg-faint:#909196;--gs-fg-fainter:#b8b9bd;--gs-accent:#4078f2;--gs-accent-bg:#4078f21a;--gs-accent-border:#4078f273;--gs-add:#50a14f;--gs-del:#e45649;--gs-warn:#c18401;--gs-info:#0184bc;--gs-add-bg:#50a14f1f;--gs-del-bg:#e456491f;--gs-warn-bg:#c184011f;--gs-info-bg:#0184bc1f;--gs-add-line:#50a14f24;--gs-del-line:#e4564921;--gs-add-word:#50a14f57;--gs-del-word:#e4564952;--gs-hunk:#4078f212;--gs-neutral-bg:#696c771f;--gs-backdrop:#383a4242;--gs-shadow:#383a422e}.SD8qLW_overlay[data-gs-theme=solarized-dark]{--gs-bg:#002b36;--gs-panel:#073642;--gs-raise:#0a4553;--gs-border:#0f5666;--gs-border-soft:#073642;--gs-fg:#93a1a1;--gs-fg-muted:#839496;--gs-fg-dim:#657b83;--gs-fg-faint:#586e75;--gs-fg-fainter:#45636b;--gs-accent:#268bd2;--gs-accent-bg:#268bd229;--gs-accent-border:#268bd28c;--gs-add:#859900;--gs-del:#dc322f;--gs-warn:#b58900;--gs-info:#2aa198;--gs-add-bg:#85990033;--gs-del-bg:#dc322f2e;--gs-warn-bg:#b589002e;--gs-info-bg:#2aa1982e;--gs-add-line:#85990029;--gs-del-line:#dc322f26;--gs-add-word:#85990066;--gs-del-word:#dc322f61;--gs-hunk:#268bd21f;--gs-neutral-bg:#657b8333;--gs-backdrop:#00141a9e;--gs-shadow:#00141a8c}.SD8qLW_overlay[data-gs-theme=solarized-light]{--gs-bg:#fdf6e3;--gs-panel:#eee8d5;--gs-raise:#e3ddca;--gs-border:#d5cfbb;--gs-border-soft:#eee8d5;--gs-fg:#586e75;--gs-fg-muted:#657b83;--gs-fg-dim:#839496;--gs-fg-faint:#93a1a1;--gs-fg-fainter:#b5b0a0;--gs-accent:#268bd2;--gs-accent-bg:#268bd21f;--gs-accent-border:#268bd273;--gs-add:#6c7c00;--gs-del:#cb2825;--gs-warn:#9a7400;--gs-info:#21867f;--gs-add-bg:#8599002e;--gs-del-bg:#dc322f24;--gs-warn-bg:#b5890029;--gs-info-bg:#2aa19824;--gs-add-line:#85990029;--gs-del-line:#dc322f1f;--gs-add-word:#85990061;--gs-del-word:#dc322f4d;--gs-hunk:#268bd214;--gs-neutral-bg:#586e7524;--gs-backdrop:#586e7542;--gs-shadow:#586e7533}.SD8qLW_overlay[data-gs-theme=nord-dark]{--gs-bg:#2e3440;--gs-panel:#3b4252;--gs-raise:#434c5e;--gs-border:#4c566a;--gs-border-soft:#3b4252;--gs-fg:#eceff4;--gs-fg-muted:#d8dee9;--gs-fg-dim:#9aa5b8;--gs-fg-faint:#7b88a1;--gs-fg-fainter:#5d6a82;--gs-accent:#88c0d0;--gs-on-accent:#2e3440;--gs-accent-bg:#88c0d024;--gs-accent-border:#88c0d08c;--gs-add:#a3be8c;--gs-del:#bf616a;--gs-warn:#ebcb8b;--gs-info:#81a1c1;--gs-add-bg:#a3be8c29;--gs-del-bg:#bf616a2e;--gs-warn-bg:#ebcb8b29;--gs-info-bg:#81a1c129;--gs-add-line:#a3be8c24;--gs-del-line:#bf616a26;--gs-add-word:#a3be8c61;--gs-del-word:#bf616a66;--gs-hunk:#88c0d01a;--gs-neutral-bg:#9aa5b829;--gs-backdrop:#1d232d9e;--gs-shadow:#1419218c}.SD8qLW_overlay[data-gs-theme=nord-light]{--gs-bg:#eceff4;--gs-panel:#e5e9f0;--gs-raise:#d8dee9;--gs-border:#c3cbd8;--gs-border-soft:#dfe4ec;--gs-fg:#2e3440;--gs-fg-muted:#3b4252;--gs-fg-dim:#4c566a;--gs-fg-faint:#6b7689;--gs-fg-fainter:#9aa4b5;--gs-accent:#5e81ac;--gs-accent-bg:#5e81ac1f;--gs-accent-border:#5e81ac80;--gs-add:#5e7d47;--gs-del:#a5424c;--gs-warn:#97701f;--gs-info:#4c7a8c;--gs-add-bg:#5e7d4724;--gs-del-bg:#a5424c21;--gs-warn-bg:#97701f24;--gs-info-bg:#4c7a8c21;--gs-add-line:#5e7d4724;--gs-del-line:#a5424c1f;--gs-add-word:#5e7d4757;--gs-del-word:#a5424c52;--gs-hunk:#5e81ac17;--gs-neutral-bg:#4c566a21;--gs-backdrop:#2e344042;--gs-shadow:#2e34402e}.SD8qLW_overlay{--gs-inset:14px;--gs-h-control:28px;--gs-h-compact:24px;--gs-pad-control:0 12px;--gs-pad-compact:0 10px;--gs-on-accent:#fff;--gs-graph-0:#58a6ff;--gs-graph-1:#3fb950;--gs-graph-2:#d29922;--gs-graph-3:#bc8cff;--gs-graph-4:#f778ba;--gs-graph-5:#39c5cf;--gs-r-pill:999px;--gs-r-control:8px;--gs-r-surface:12px;--gs-r-drawer:14px;--gs-t-meta:11px;--gs-t-dense:12px;--gs-t-ui:13px;--gs-gutter:16px;--gs-gutter-pane:12px;z-index:1000;padding:var(--gs-inset);box-sizing:border-box;background:var(--gs-backdrop);justify-content:flex-end;align-items:stretch;gap:12px;animation:.16s ease-out SD8qLW_gsFade;display:flex;position:fixed;inset:0}.SD8qLW_drawer{box-sizing:border-box;width:min(1600px,94vw);height:100%;color:var(--gs-fg);background:var(--gs-bg);border:1px solid var(--gs-border);border-radius:var(--gs-r-drawer);box-shadow:0 24px 64px var(--gs-shadow);font-family:var(--dsw-font-ui,-apple-system, BlinkMacSystemFont, \"Segoe UI\", Helvetica, Arial, sans-serif);--gs-surface:var(--gs-bg);--gs-surface-2:var(--gs-panel);flex-direction:column;animation:.18s cubic-bezier(.22,1,.36,1) SD8qLW_gsSlide;display:flex;position:relative;overflow:hidden}.SD8qLW_drawer[data-gs-bg]{--gs-surface:color-mix(in srgb, var(--gs-bg) var(--gs-veil), transparent);--gs-surface-2:color-mix(in srgb, var(--gs-panel) var(--gs-veil), transparent)}.SD8qLW_drawer[data-gs-bg]:before{content:\"\";z-index:0;background-image:var(--gs-bg-image);filter:blur(var(--gs-bg-blur));pointer-events:none;background-position:50%;background-size:cover;position:absolute;inset:0;transform:scale(1.12)}.SD8qLW_drawer>:not(.SD8qLW_resizer){z-index:1;position:relative}.SD8qLW_drawer>.SD8qLW_header{z-index:24}.SD8qLW_drawer>.SD8qLW_tabs{z-index:23}.SD8qLW_drawer>.SD8qLW_compareBar{z-index:22}.SD8qLW_drawer>.SD8qLW_syncBar{z-index:20}.SD8qLW_overlayMax{gap:0;padding:0}.SD8qLW_overlayMax .SD8qLW_drawer{border-width:0 0 0 1px;border-radius:0;flex:auto;width:auto;min-width:0}@keyframes SD8qLW_gsFade{0%{opacity:0}}@keyframes SD8qLW_gsSlide{0%{opacity:0;transform:translate(24px)}}.SD8qLW_resizer{z-index:30;cursor:col-resize;touch-action:none;justify-content:center;align-items:center;width:10px;display:flex;position:absolute;top:0;bottom:0;left:0}.SD8qLW_resizer:after{content:\"\";background:var(--gs-fg-fainter);opacity:0;border-radius:999px;width:3px;height:32px;transition:opacity .14s,height .14s}.SD8qLW_resizer:hover:after{opacity:.6}.SD8qLW_resizerActive:after{opacity:.9;height:56px}.SD8qLW_paneDivider{z-index:5;cursor:col-resize;touch-action:none;flex:none;justify-content:center;align-items:center;width:7px;display:flex;position:relative}.SD8qLW_paneDivider:before{content:\"\";background:var(--gs-border-soft);width:1px;position:absolute;top:0;bottom:0;left:3px}.SD8qLW_paneDivider:after{content:\"\";background:var(--gs-fg-fainter);opacity:0;border-radius:999px;width:3px;height:28px;transition:opacity .14s,height .14s;position:relative}.SD8qLW_paneDivider:hover:after{opacity:.6}.SD8qLW_paneDividerActive:after{opacity:.9;height:48px}.SD8qLW_header{padding:10px var(--gs-gutter);border-bottom:1px solid var(--gs-border);background:var(--gs-surface-2);font-family:var(--dsw-font-ui,system-ui, sans-serif);font-size:var(--gs-t-ui);flex:none;justify-content:space-between;align-items:center;gap:12px;display:flex}.SD8qLW_headerLeft{flex-wrap:wrap;align-items:center;gap:10px;min-width:0;display:flex}.SD8qLW_headerBranch{border:1px solid var(--gs-accent-border);background:var(--gs-accent-bg);color:var(--gs-accent);border-radius:999px;align-items:center;gap:6px;padding:2px 10px;font-weight:600;display:inline-flex}.SD8qLW_refButton.SD8qLW_headerPicker{border-color:var(--gs-accent-border);background:var(--gs-accent-bg);max-width:420px;color:var(--gs-accent);font-weight:600}.SD8qLW_refButton.SD8qLW_headerPicker:hover{background:var(--gs-accent-bg);color:var(--gs-accent);border-color:var(--gs-accent)}.SD8qLW_elide{flex:0 auto;align-items:baseline;min-width:0;display:inline-flex}.SD8qLW_elideHead{white-space:nowrap;text-overflow:ellipsis;flex:0 999 auto;min-width:0;overflow:hidden}.SD8qLW_elideTail{white-space:nowrap;text-overflow:ellipsis;flex:0 auto;min-width:0;overflow:hidden}.SD8qLW_headerPathMain{color:var(--gs-fg-faint);font-size:var(--gs-t-meta)}.SD8qLW_headerPathMain .SD8qLW_elideTail{color:var(--gs-fg-dim)}.SD8qLW_headerViewRef{max-width:160px}.SD8qLW_headerView{background:var(--gs-neutral-bg);color:var(--gs-fg-muted);font-size:var(--gs-t-meta);font-variant-numeric:tabular-nums;border-radius:999px;flex:none;padding:1px 8px}.SD8qLW_headerDetached{background:var(--gs-warn-bg);color:var(--gs-warn);font-size:var(--gs-t-meta);letter-spacing:.02em;border-radius:999px;padding:1px 8px}.SD8qLW_headerTotals{font-variant-numeric:tabular-nums}.SD8qLW_headerTotalsAdd{color:var(--gs-add);font-weight:600}.SD8qLW_headerTotalsDel{color:var(--gs-del);font-weight:600}.SD8qLW_headerTotalsDim{color:var(--gs-fg-dim);font-size:var(--gs-t-dense)}.SD8qLW_headerRight{flex:none;gap:8px;display:flex;position:relative}.SD8qLW_theme{display:inline-flex;position:relative}.SD8qLW_refPop.SD8qLW_settingsPop{width:320px;max-width:calc(100vw - 32px);max-height:min(560px,100vh - 120px);top:calc(100% + 6px);left:auto;right:0}.SD8qLW_themeRail{min-height:0;font-family:var(--dsw-font-ui,system-ui, sans-serif);flex-direction:column;flex:1;gap:14px;padding:12px 14px 16px;display:flex;overflow-y:auto}.SD8qLW_themeGroup{flex-direction:column;gap:6px;display:flex}.SD8qLW_themeLabel{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);letter-spacing:.04em;text-transform:uppercase;font-weight:600}.SD8qLW_themeRowSplit{justify-content:space-between;align-items:center;gap:8px;display:flex}.SD8qLW_segmented{gap:6px;display:flex}.SD8qLW_segment{box-sizing:border-box;border:1px solid var(--gs-border);border-radius:var(--gs-r-control);color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-meta);cursor:pointer;background:0 0;flex-direction:column;flex:1 1 0;align-items:stretch;gap:4px;padding:4px;transition:background .12s,color .12s,border-color .12s;display:flex}.SD8qLW_segment:hover{background:var(--gs-raise);border-color:var(--gs-fg-fainter);color:var(--gs-fg)}.SD8qLW_segment:focus-visible{outline:2px solid var(--gs-accent);outline-offset:1px}.SD8qLW_segmentChip{border-radius:calc(var(--gs-r-control) - 4px);border:1px solid #80808073;height:20px}.SD8qLW_chipLight{background:#fff}.SD8qLW_chipDark{background:#0b0b0d}.SD8qLW_chipSystem{background:linear-gradient(105deg,#fff 0 50%,#0b0b0d 50% 100%)}.SD8qLW_paletteRow{box-sizing:border-box;border-radius:var(--gs-r-control);width:100%;color:var(--gs-fg-muted);font-family:inherit;font-size:var(--gs-t-dense);text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:8px;padding:5px 8px;display:flex}.SD8qLW_paletteRow:hover{background:var(--gs-raise);color:var(--gs-fg)}.SD8qLW_swatch{border:1px solid var(--gs-border);border-radius:3px;flex:none;width:26px;height:12px;display:inline-flex;overflow:hidden}.SD8qLW_swatch span{flex:1}.SD8qLW_scopeRow{gap:6px;display:flex}.SD8qLW_scopeHint{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);overflow-wrap:anywhere}.SD8qLW_bgPreview{border:1px solid var(--gs-border);border-radius:var(--gs-r-control);background-color:var(--gs-bg);background-position:50%;background-size:cover;height:64px}.SD8qLW_bgEmpty{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);justify-content:center;align-items:center;display:flex}.SD8qLW_sliderRow{font-size:var(--gs-t-meta);color:var(--gs-fg-dim);align-items:center;gap:8px;display:flex}.SD8qLW_sliderRow input{min-width:0;accent-color:var(--gs-accent);flex:1}.SD8qLW_sliderValue{text-align:right;font-variant-numeric:tabular-nums;flex:none;width:38px}.SD8qLW_cssArea{box-sizing:border-box;border:1px solid var(--gs-border);border-radius:var(--gs-r-control);background:var(--gs-bg);width:100%;min-height:96px;max-height:220px;color:var(--gs-fg);font-family:var(--dsw-font-mono,ui-monospace, Consolas, monospace);font-size:var(--gs-t-meta);resize:vertical;outline:none;padding:7px 8px}.SD8qLW_cssArea:focus{border-color:var(--gs-accent-border)}.SD8qLW_themeNote{color:var(--gs-warn);font-size:var(--gs-t-meta)}.SD8qLW_themeDirty{color:var(--gs-accent);font-size:var(--gs-t-meta)}.SD8qLW_wtCurrent{color:var(--gs-add);font-size:8px;line-height:1}.SD8qLW_commitCopy{margin-left:auto}.SD8qLW_commitPop{z-index:40;box-sizing:border-box;border:1px solid var(--gs-border);border-radius:var(--gs-r-surface);background:var(--gs-panel);width:min(380px,100vw - 24px);color:var(--gs-fg);box-shadow:0 16px 40px var(--gs-shadow);font-family:var(--dsw-font-ui,-apple-system, BlinkMacSystemFont, \"Segoe UI\", Helvetica, Arial, sans-serif);font-size:var(--gs-t-dense);flex-direction:column;gap:6px;padding:10px 12px 12px;display:flex;position:fixed;overflow:auto}.SD8qLW_commitPopTop{align-items:center;gap:8px;display:flex}.SD8qLW_commitPopTop .SD8qLW_commitWhen{margin-right:auto}.SD8qLW_commitPopSubject{color:var(--gs-fg);font-size:var(--gs-t-ui);white-space:pre-wrap;overflow-wrap:anywhere;user-select:text;font-weight:600;line-height:18px}.SD8qLW_commitPopBody{color:var(--gs-fg-muted);font-family:inherit;font-size:var(--gs-t-dense);white-space:pre-wrap;overflow-wrap:anywhere;user-select:text;margin:0;line-height:18px}.SD8qLW_tabs{padding:0 var(--gs-gutter);border-bottom:1px solid var(--gs-border-soft);background:var(--gs-surface-2);flex:none;gap:24px;font-family:inherit;display:flex}.SD8qLW_tab{font-family:inherit;font-size:var(--gs-t-ui);color:var(--gs-fg-dim);cursor:pointer;background:0 0;border:none;padding:8px 0 9px;font-weight:500;line-height:16px;position:relative}.SD8qLW_tab:after{content:\"\";background:0 0;border-radius:2px;height:2px;position:absolute;bottom:1px;left:0;right:0}.SD8qLW_tabActive{color:var(--gs-accent)}.SD8qLW_tabActive:after{background:var(--gs-accent)}.SD8qLW_compareBar{padding:8px var(--gs-gutter);border-bottom:1px solid var(--gs-border-soft);background:var(--gs-surface-2);color:var(--gs-fg-dim);font-family:var(--dsw-font-ui,system-ui, sans-serif);font-size:var(--gs-t-dense);flex-wrap:wrap;flex:none;align-items:center;gap:10px;display:flex}.SD8qLW_compareArrow{color:var(--gs-fg-faint)}.SD8qLW_refPicker{align-items:center;gap:6px;display:inline-flex;position:relative}.SD8qLW_refLabel{color:var(--gs-fg-faint);flex:none}.SD8qLW_refButton{justify-content:space-between;max-width:260px}.SD8qLW_refValue{min-width:0;overflow:hidden}.SD8qLW_refCaret{color:var(--gs-fg-faint);flex:none;font-size:9px}.SD8qLW_refPop{z-index:10;border:1px solid var(--gs-border);border-radius:var(--gs-r-control);background:var(--gs-panel);width:300px;max-width:80vw;box-shadow:0 12px 32px var(--gs-shadow);flex-direction:column;display:flex;position:absolute;top:calc(100% + 4px);left:0;overflow:hidden}.SD8qLW_menuPop{width:auto;min-width:100%;padding:4px;left:auto;right:0}.SD8qLW_refSearch{border:0;border-bottom:1px solid var(--gs-border-soft);background:var(--gs-bg);color:var(--gs-fg);font-family:inherit;font-size:var(--gs-t-dense);outline:none;flex:none;padding:7px 10px}.SD8qLW_refSearch::placeholder{color:var(--gs-fg-faint)}.SD8qLW_refList{flex:1;max-height:280px;padding:4px;overflow-y:auto}.SD8qLW_refGroup{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);letter-spacing:.04em;text-transform:uppercase;padding:6px 8px 3px;font-weight:600}.SD8qLW_refRow{box-sizing:border-box;border-radius:var(--gs-r-control);width:100%;color:var(--gs-fg-muted);font-family:inherit;font-size:var(--gs-t-dense);text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:6px;padding:5px 8px;display:flex}.SD8qLW_refRow:hover{background:var(--gs-raise);color:var(--gs-fg)}.SD8qLW_refRowSpacer{flex:none;width:12px}.SD8qLW_refRowName{flex:auto;min-width:0;overflow:hidden}.SD8qLW_refEmpty{color:var(--gs-fg-faint);font-size:var(--gs-t-dense);padding:14px 10px}.SD8qLW_refFoot{border-top:1px solid var(--gs-border-soft);color:var(--gs-fg-faint);font-size:var(--gs-t-meta);flex:none;padding:5px 10px}.SD8qLW_commitsPane{box-sizing:border-box;width:26%;min-height:0;min-width:var(--gs-min-commits);background:var(--gs-surface);flex-direction:column;flex:0 auto;max-width:340px;display:flex}.SD8qLW_paneHead{box-sizing:border-box;min-height:37px;padding:6px var(--gs-gutter-pane);border-bottom:1px solid var(--gs-border-soft);color:var(--gs-fg-dim);font-family:var(--dsw-font-ui,system-ui, sans-serif);font-size:var(--gs-t-dense);flex:none;align-items:center;gap:8px;display:flex}.SD8qLW_paneTitle{font-weight:600}.SD8qLW_commitsSentinel{flex:none;height:1px}.SD8qLW_commitsFoot{color:var(--gs-fg-faint);font-family:var(--dsw-font-ui,system-ui, sans-serif);font-size:var(--gs-t-meta);text-align:center;flex:none;min-height:16px;padding:8px}.SD8qLW_commits{flex-direction:column;flex:1;min-height:0;padding:4px 6px 4px 0;display:flex;overflow-y:auto}.SD8qLW_commitLine{flex:none;align-items:stretch;height:48px;display:flex}.SD8qLW_graphCell{flex:none;display:block}.SD8qLW_commit{box-sizing:border-box;border-radius:var(--gs-r-surface);text-align:left;cursor:pointer;min-width:0;height:100%;font-family:inherit;font-size:var(--gs-t-dense);background:0 0;border:1px solid #0000;flex-direction:column;flex:auto;justify-content:center;gap:2px;margin:1px 0;padding:4px 8px;transition:background .12s,border-color .12s;display:flex;overflow:hidden}.SD8qLW_commit:hover{background:var(--gs-raise)}.SD8qLW_commitActive{border-color:var(--gs-accent-border);background:var(--gs-accent-bg)}.SD8qLW_commitTop{justify-content:space-between;align-items:center;gap:8px;display:flex}.SD8qLW_commitHash{color:var(--gs-info)}.SD8qLW_commitSubjectRow{align-items:baseline;gap:4px;min-width:0;display:flex}.SD8qLW_commitSubject{white-space:nowrap;text-overflow:ellipsis;min-width:0;color:var(--gs-fg-muted);flex:1;overflow:hidden}.SD8qLW_commitHasBody{color:var(--gs-fg-faint);letter-spacing:.04em;flex:none}.SD8qLW_commitRef{white-space:nowrap;text-overflow:ellipsis;border:1px solid var(--gs-accent-border);border-radius:var(--gs-r-pill);background:var(--gs-accent-bg);max-width:96px;color:var(--gs-accent);font-size:var(--gs-t-meta);flex:none;padding:0 5px;line-height:15px;overflow:hidden}.SD8qLW_commitWhen{color:var(--gs-fg-faint);flex:none}.SD8qLW_body{z-index:1;flex:1;min-height:0;display:flex}.SD8qLW_treeCol{box-sizing:border-box;width:28%;min-height:0;min-width:var(--gs-min-tree);background:var(--gs-surface);flex-direction:column;flex:0 auto;max-width:400px;display:flex}.SD8qLW_treeWrap{box-sizing:border-box;flex-direction:column;flex:1;min-width:0;min-height:0;display:flex}.SD8qLW_treeTools{box-sizing:border-box;min-height:37px;padding:6px var(--gs-gutter-pane);border-bottom:1px solid var(--gs-border-soft);flex-wrap:wrap;flex:none;justify-content:space-between;align-items:center;gap:6px;display:flex}.SD8qLW_treeActions{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.SD8qLW_treeLead{align-items:center;gap:4px;min-width:0;display:flex}.SD8qLW_treeLabel{white-space:nowrap;color:var(--gs-fg-dim);font-size:var(--gs-t-dense);flex:none}.SD8qLW_tree{flex:1;min-height:0;margin:0;padding:6px 0 16px;list-style:none;overflow:auto}.SD8qLW_treeEmpty{min-height:0;color:var(--gs-fg-faint);font-size:var(--gs-t-ui);flex:1;justify-content:center;align-items:center;display:flex}.SD8qLW_treeSub{margin:0;padding:0;list-style:none;position:relative}.SD8qLW_treeSub:before{content:\"\";top:0;bottom:0;left:var(--gs-rail,0);background:var(--gs-border-soft);width:1px;position:absolute}.SD8qLW_treeDirLi{position:relative}.SD8qLW_treeDir{box-sizing:border-box;width:100%;color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-dense);text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:6px;padding:4px 12px 4px 8px;font-weight:600;display:flex}.SD8qLW_treeDir:hover{background:var(--gs-panel);color:var(--gs-fg-muted)}.SD8qLW_treeDirActive{color:var(--gs-fg-muted)}.SD8qLW_chevron{width:10px;color:var(--gs-fg-fainter);font-size:var(--gs-t-meta);flex:none;transition:transform .12s;display:inline-block}.SD8qLW_chevronOpen{transform:rotate(90deg)}.SD8qLW_treeDirName{white-space:nowrap;text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.SD8qLW_treeDirCount{background:var(--gs-neutral-bg);color:var(--gs-fg-dim);font-size:var(--gs-t-meta);border-radius:999px;flex:none;padding:0 6px;font-weight:600;line-height:16px}.SD8qLW_treeDirCounts{font-size:var(--gs-t-meta);font-variant-numeric:tabular-nums;flex:none}.SD8qLW_file{box-sizing:border-box;width:100%;color:var(--gs-fg-muted);font-family:inherit;font-size:var(--gs-t-dense);text-align:left;cursor:pointer;background:0 0;border:0;border-left:2px solid #0000;align-items:center;gap:8px;padding:5px 14px;display:flex}.SD8qLW_file:hover{background:var(--gs-panel)}.SD8qLW_fileActive{background:var(--gs-panel);border-left-color:var(--gs-accent);color:var(--gs-fg)}.SD8qLW_fileStatus{width:18px;height:18px;font-weight:700;font-size:var(--gs-t-meta);border-radius:5px;flex:none;justify-content:center;align-items:center;line-height:1;display:inline-flex}.SD8qLW_stAdded,.SD8qLW_stUntracked{color:var(--gs-add);background:var(--gs-add-bg)}.SD8qLW_stDeleted{color:var(--gs-del);background:var(--gs-del-bg)}.SD8qLW_stModified{color:var(--gs-warn);background:var(--gs-warn-bg)}.SD8qLW_stRenamed{color:var(--gs-info);background:var(--gs-info-bg)}.SD8qLW_filePath{white-space:nowrap;text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.SD8qLW_fileBinary{background:var(--gs-neutral-bg);color:var(--gs-fg-dim);letter-spacing:.06em;border-radius:4px;flex:none;padding:0 5px;font-size:9px;font-weight:700}.SD8qLW_fileCounts{font-size:var(--gs-t-meta);font-variant-numeric:tabular-nums;flex:none}.SD8qLW_fileCountAdd{color:var(--gs-add)}.SD8qLW_fileCountDel{color:var(--gs-del)}.SD8qLW_diffPane{min-width:var(--gs-min-diff);background:var(--gs-surface);flex:1 1 0;overflow:auto}.SD8qLW_diffPre{width:max-content;min-width:100%;font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;font-size:var(--gs-t-dense);font-variant-ligatures:none;font-feature-settings:\"liga\" 0, \"calt\" 0;tab-size:4;flex-direction:column;margin:0;padding:8px 0 16px;font-weight:400;line-height:20px;display:flex}.SD8qLW_renameLine{border-bottom:1px solid var(--gs-border-soft);color:var(--gs-info);font-size:var(--gs-t-dense);padding:8px 16px}.SD8qLW_renameLine code{color:var(--gs-fg)}.SD8qLW_line{white-space:nowrap;align-items:stretch;width:max-content;min-width:100%;min-height:20px;line-height:20px;display:flex}.SD8qLW_lnOld,.SD8qLW_lnNew{box-sizing:border-box;text-align:right;width:3.2em;color:var(--gs-fg-fainter);user-select:none;font-variant-numeric:tabular-nums;flex:none;padding:0 8px}.SD8qLW_line:hover .SD8qLW_lnOld,.SD8qLW_line:hover .SD8qLW_lnNew{color:var(--gs-fg-dim)}.SD8qLW_gutter{text-align:center;user-select:none;flex:none;width:1.4em}.SD8qLW_code{white-space:pre;flex:1 0 auto;padding:0 16px 0 10px}.SD8qLW_lineAdd{background:var(--gs-add-line)}.SD8qLW_lineDel{background:var(--gs-del-line)}.SD8qLW_lineAdd .SD8qLW_lnOld,.SD8qLW_lineAdd .SD8qLW_lnNew,.SD8qLW_lineAdd .SD8qLW_gutter{background:var(--gs-add-num,var(--gs-add-line))}.SD8qLW_lineDel .SD8qLW_lnOld,.SD8qLW_lineDel .SD8qLW_lnNew,.SD8qLW_lineDel .SD8qLW_gutter{background:var(--gs-del-num,var(--gs-del-line))}.SD8qLW_lineContext{color:var(--gs-fg-muted)}.SD8qLW_lineHunk{background:var(--gs-hunk)}.SD8qLW_lineHunk .SD8qLW_code{color:var(--gs-fg-dim)}.SD8qLW_lineHunk .SD8qLW_lnOld,.SD8qLW_lineHunk .SD8qLW_lnNew,.SD8qLW_lineHunk .SD8qLW_gutter{background:var(--gs-hunk-num,var(--gs-hunk))}.SD8qLW_signAdd{color:var(--gs-add)}.SD8qLW_signDel{color:var(--gs-del)}.SD8qLW_wordAdd{background:var(--gs-add-word);border-radius:2px}.SD8qLW_wordDel{background:var(--gs-del-word);border-radius:2px}.SD8qLW_empty{color:var(--gs-fg-faint);font-size:var(--gs-t-ui);padding:32px 24px}.SD8qLW_syncBar{padding:8px var(--gs-gutter);border-bottom:1px solid var(--gs-border-soft);background:var(--gs-surface-2);font-size:var(--gs-t-dense);color:var(--gs-fg-dim);flex-wrap:wrap;flex:none;align-items:center;gap:8px;display:flex}.SD8qLW_syncUpstream{white-space:nowrap;text-overflow:ellipsis;max-width:260px;color:var(--gs-fg-muted);font-variant-numeric:tabular-nums;overflow:hidden}.SD8qLW_syncLevel{color:var(--gs-fg-faint)}.SD8qLW_syncSpacer{flex:auto}.SD8qLW_btn:disabled,.SD8qLW_treeIcon:disabled,.SD8qLW_miniBtn:disabled,.SD8qLW_refButton:disabled{opacity:.45;cursor:default}.SD8qLW_btn[data-quiet]:disabled,.SD8qLW_refButton[data-quiet]:disabled{opacity:1}.SD8qLW_opBanner{padding:8px var(--gs-gutter);border-bottom:1px solid var(--gs-border-soft);font-size:var(--gs-t-dense);white-space:pre-wrap;overflow-wrap:anywhere;user-select:text;flex:none;line-height:18px}.SD8qLW_opBannerOk{background:var(--gs-add-bg);color:var(--gs-add)}.SD8qLW_opBannerBad{background:var(--gs-del-bg);color:var(--gs-del)}.SD8qLW_fileLi{align-items:stretch;display:flex}.SD8qLW_fileLi .SD8qLW_file{flex:auto;min-width:0}.SD8qLW_treeRow{align-items:stretch;display:flex}.SD8qLW_treeRow .SD8qLW_treeDir{flex:auto;min-width:0}.SD8qLW_checkBox{cursor:pointer;background:0 0;border:0;flex:none;justify-content:center;align-items:center;width:22px;padding:0;display:flex}.SD8qLW_checkMark{box-sizing:border-box;border:1px solid var(--gs-fg-faint);background:var(--gs-bg);color:#0000;border-radius:3px;justify-content:center;align-items:center;width:14px;height:14px;font-size:10px;font-weight:700;line-height:1;transition:background .12s,border-color .12s;display:flex}.SD8qLW_checkBox:hover .SD8qLW_checkMark{border-color:var(--gs-accent)}.SD8qLW_checkBox:focus-visible{outline:none}.SD8qLW_checkBox:focus-visible .SD8qLW_checkMark{outline:2px solid var(--gs-accent);outline-offset:1px}.SD8qLW_checkMarkOn,.SD8qLW_checkMarkPartial{border-color:var(--gs-accent);background:var(--gs-accent);color:var(--gs-on-accent)}.SD8qLW_commitBox{padding:8px var(--gs-gutter-pane) 10px;border-top:1px solid var(--gs-border);background:var(--gs-surface-2);flex-direction:column;flex:none;gap:6px;display:flex}.SD8qLW_commitMessage{box-sizing:border-box;border:1px solid var(--gs-border);border-radius:var(--gs-r-control);background:var(--gs-bg);width:100%;min-height:46px;max-height:160px;color:var(--gs-fg);font-family:inherit;font-size:var(--gs-t-dense);resize:vertical;outline:none;padding:6px 8px;line-height:18px}.SD8qLW_commitMessage:focus{border-color:var(--gs-accent-border)}.SD8qLW_commitMessage::placeholder{color:var(--gs-fg-faint)}.SD8qLW_commitRow{align-items:center;gap:8px;display:flex}.SD8qLW_commitAmend{color:var(--gs-fg-dim);font-size:var(--gs-t-meta);cursor:pointer;align-items:center;gap:4px;display:inline-flex}.SD8qLW_commitAmend input{accent-color:var(--gs-accent);cursor:pointer}.SD8qLW_commitStaged{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);margin-left:auto}.SD8qLW_commitLead{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);margin:0;line-height:15px}.SD8qLW_commitBtn{box-sizing:border-box;min-width:92px;height:var(--gs-h-control);border-radius:var(--gs-r-control);background:var(--gs-accent);color:var(--gs-on-accent);font-family:inherit;font-size:var(--gs-t-ui);white-space:nowrap;cursor:pointer;border:1px solid #0000;flex:none;justify-content:center;align-items:center;padding:0 16px;font-weight:600;line-height:1;transition:filter .12s,opacity .12s;display:inline-flex}.SD8qLW_commitBtn:hover:not(:disabled){filter:brightness(1.1)}.SD8qLW_commitBtn:focus-visible{outline:2px solid var(--gs-accent);outline-offset:2px}.SD8qLW_commitBtn:disabled{background:var(--gs-raise);color:var(--gs-fg-faint);border-color:var(--gs-border);cursor:default}.SD8qLW_btn,.SD8qLW_miniBtn,.SD8qLW_treeIcon,.SD8qLW_commitCopy,.SD8qLW_scopeBtn,.SD8qLW_refButton{box-sizing:border-box;height:var(--gs-h-control);padding:var(--gs-pad-control);border:1px solid var(--gs-border);border-radius:var(--gs-r-control);color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-ui);white-space:nowrap;cursor:pointer;background:0 0;flex:none;justify-content:center;align-items:center;gap:6px;line-height:1;transition:background .12s,color .12s,border-color .12s;display:inline-flex}.SD8qLW_btn:hover,.SD8qLW_miniBtn:hover,.SD8qLW_treeIcon:hover,.SD8qLW_commitCopy:hover,.SD8qLW_scopeBtn:hover,.SD8qLW_refButton:hover{background:var(--gs-raise);color:var(--gs-fg);border-color:var(--gs-fg-fainter)}.SD8qLW_btn:focus-visible,.SD8qLW_miniBtn:focus-visible,.SD8qLW_treeIcon:focus-visible,.SD8qLW_commitCopy:focus-visible,.SD8qLW_scopeBtn:focus-visible,.SD8qLW_refButton:focus-visible{outline:2px solid var(--gs-accent);outline-offset:1px}.SD8qLW_btn,.SD8qLW_refButton{border-radius:var(--gs-r-pill)}.SD8qLW_treeIcon,.SD8qLW_commitCopy{height:var(--gs-h-compact);padding:var(--gs-pad-compact);font-size:var(--gs-t-dense)}.SD8qLW_treeIcon{width:var(--gs-h-compact);padding:0}.SD8qLW_treeIconGlyph{font-size:var(--gs-t-meta);line-height:1;display:block}.SD8qLW_treeIconDown{transform:rotate(90deg)}.SD8qLW_scopeBtn{flex:1 1 0}.SD8qLW_scopeBtnActive,.SD8qLW_miniBtnPrimary,.SD8qLW_segmentActive,.SD8qLW_refRowActive,.SD8qLW_paletteRowActive{border-color:var(--gs-accent-border);background:var(--gs-accent-bg);color:var(--gs-accent);font-weight:600}.SD8qLW_btnIcon{width:var(--gs-h-control);padding:0}.SD8qLW_btnIcon svg{display:block}.SD8qLW_btnClose:hover:not(:disabled){border-color:var(--gs-del);background:var(--gs-del-bg);color:var(--gs-del)}.SD8qLW_btnBehind{border-color:var(--gs-warn);background:var(--gs-warn-bg);color:var(--gs-warn);font-weight:600}.SD8qLW_btnBehind:hover:not(:disabled){background:var(--gs-warn-bg);color:var(--gs-warn);border-color:var(--gs-warn)}.SD8qLW_btnAhead{border-color:var(--gs-add);background:var(--gs-add-bg);color:var(--gs-add);font-weight:600}.SD8qLW_btnAhead:hover:not(:disabled){background:var(--gs-add-bg);color:var(--gs-add);border-color:var(--gs-add)}.SD8qLW_btnPrimary{border-color:var(--gs-accent);background:var(--gs-accent);color:var(--gs-on-accent,#fff);font-weight:600}.SD8qLW_btnPrimary:hover:not(:disabled){background:var(--gs-accent);color:var(--gs-on-accent,#fff);border-color:var(--gs-accent)}.SD8qLW_btnCount{font-variant-numeric:tabular-nums;opacity:.85;border-left:1px solid;margin-left:1px;padding-left:6px}.SD8qLW_pullGroup{flex:none;align-items:center;display:inline-flex}.SD8qLW_pullGroup>.SD8qLW_refPicker>.SD8qLW_refButton{border-right-color:#0000;border-top-right-radius:0;border-bottom-right-radius:0}.SD8qLW_pullGroup>.SD8qLW_btn{border-top-left-radius:0;border-bottom-left-radius:0;margin-left:-1px}.SD8qLW_drawer{scrollbar-width:thin;scrollbar-color:var(--gs-border) transparent}.SD8qLW_drawer ::-webkit-scrollbar{width:10px;height:10px}.SD8qLW_drawer ::-webkit-scrollbar-track,.SD8qLW_drawer ::-webkit-scrollbar-corner{background:0 0}.SD8qLW_drawer ::-webkit-scrollbar-thumb{background:var(--gs-border);background-clip:padding-box;border:3px solid #0000;border-radius:999px}.SD8qLW_drawer ::-webkit-scrollbar-thumb:hover{background:var(--gs-fg-faint);background-clip:padding-box}.SD8qLW_commitRefMore{border-radius:var(--gs-r-pill);background:var(--gs-neutral-bg);color:var(--gs-fg-dim);font-size:var(--gs-t-meta);cursor:default;flex:none;padding:0 5px;line-height:15px}";
12207
+ const css = ".SD8qLW_card{border:1px solid var(--dsw-alias-border-l2);min-height:28px;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;cursor:pointer;background:0 0;border-radius:8px;align-items:center;gap:7px;padding:3px 10px;font-size:12px;line-height:18px;transition:background .12s,border-color .12s;display:inline-flex}.SD8qLW_card:hover,.SD8qLW_card:focus-visible{background:var(--dsw-alias-interactive-bg-hover);border-color:var(--dsw-alias-border-l3)}.SD8qLW_cardBranch{max-width:220px;color:var(--dsw-alias-label-primary);align-items:center;gap:4px;font-weight:550;display:inline-flex;overflow:hidden}.SD8qLW_cardBranchName{min-width:0;overflow:hidden}.SD8qLW_cardGlyph{opacity:.7;flex:none}.SD8qLW_cardDetached{background:var(--dsw-alias-state-warning-bg,#bb800926);color:var(--dsw-alias-state-warning-primary,#d29922);letter-spacing:.02em;border-radius:999px;padding:0 6px;font-size:10px;line-height:16px}.SD8qLW_cardWt{background:var(--dsw-alias-state-business-bg,#388bfd29);max-width:150px;color:var(--dsw-alias-state-business-primary,#58a6ff);letter-spacing:.02em;white-space:nowrap;text-overflow:ellipsis;border-radius:999px;align-items:center;gap:3px;padding:0 6px;font-size:10px;line-height:16px;display:inline-flex;overflow:hidden}.SD8qLW_cardAhead,.SD8qLW_cardBehind{color:var(--dsw-alias-label-tertiary);font-size:11px}.SD8qLW_cardAhead{color:var(--dsw-alias-state-success-primary)}.SD8qLW_cardBehind{color:var(--dsw-alias-state-attention-primary,#d29922)}.SD8qLW_cardSep{background:var(--dsw-alias-border-l2);width:1px;height:14px}.SD8qLW_cardAdded{color:var(--dsw-alias-state-success-primary)}.SD8qLW_cardDeleted{color:var(--dsw-alias-state-error-primary)}.SD8qLW_cardFiles{color:var(--dsw-alias-label-tertiary)}.SD8qLW_overlay[data-gs-theme=github-dark]{--gs-bg:#0d1117;--gs-panel:#161b22;--gs-raise:#21262d;--gs-border:#30363d;--gs-border-soft:#21262d;--gs-fg:#e6edf3;--gs-fg-muted:#c9d1d9;--gs-fg-dim:#8b949e;--gs-fg-faint:#6e7681;--gs-fg-fainter:#484f58;--gs-accent:#58a6ff;--gs-accent-bg:#388bfd24;--gs-accent-border:#388bfd8c;--gs-add:#3fb950;--gs-del:#f85149;--gs-warn:#d29922;--gs-info:#79c0ff;--gs-add-bg:#2ea04329;--gs-del-bg:#f8514929;--gs-warn-bg:#bb800929;--gs-info-bg:#388bfd29;--gs-add-line:#12261e;--gs-del-line:#25181c;--gs-add-word:#1a4a29;--gs-del-word:#6b2b2b;--gs-add-num:#1c4428;--gs-del-num:#542426;--gs-hunk:#111d2e;--gs-hunk-num:#0c2d6b;--gs-neutral-bg:#6e76812e;--gs-backdrop:#01040999;--gs-shadow:#0104098c}.SD8qLW_overlay[data-gs-theme=github-light]{--gs-bg:#fff;--gs-panel:#f6f8fa;--gs-raise:#eaeef2;--gs-border:#d0d7de;--gs-border-soft:#eaeef2;--gs-fg:#1f2328;--gs-fg-muted:#32383f;--gs-fg-dim:#656d76;--gs-fg-faint:#8c959f;--gs-fg-fainter:#afb8c1;--gs-accent:#0969da;--gs-accent-bg:#0969da1a;--gs-accent-border:#0969da73;--gs-add:#1a7f37;--gs-del:#cf222e;--gs-warn:#9a6700;--gs-info:#0550ae;--gs-add-bg:#1a7f371f;--gs-del-bg:#cf222e1f;--gs-warn-bg:#9a67001f;--gs-info-bg:#0969da1f;--gs-add-line:#dafbe1;--gs-del-line:#ffebe9;--gs-add-word:#aceebb;--gs-del-word:#ffcecb;--gs-add-num:#aceebb;--gs-del-num:#ffcecb;--gs-hunk:#ddf4ff;--gs-hunk-num:#b6e3ff;--gs-neutral-bg:#6e76811f;--gs-backdrop:#1f232847;--gs-shadow:#1f232838}.SD8qLW_overlay[data-gs-theme=idea-dark]{--gs-bg:#1e1f22;--gs-panel:#2b2d30;--gs-raise:#393b40;--gs-border:#393b40;--gs-border-soft:#2b2d30;--gs-fg:#dfe1e5;--gs-fg-muted:#ced0d6;--gs-fg-dim:#9da0a8;--gs-fg-faint:#6f737a;--gs-fg-fainter:#4e5157;--gs-accent:#548af7;--gs-accent-bg:#548af729;--gs-accent-border:#548af78c;--gs-add:#5fad65;--gs-del:#e26e6e;--gs-warn:#f0a732;--gs-info:#3592c4;--gs-add-bg:#5fad6529;--gs-del-bg:#e26e6e29;--gs-warn-bg:#f0a73229;--gs-info-bg:#3592c429;--gs-add-line:#293c2e;--gs-del-line:#3d2b2b;--gs-add-word:#3d6640;--gs-del-word:#6b3838;--gs-hunk:#548af71a;--gs-neutral-bg:#9da0a82e;--gs-backdrop:#10111399;--gs-shadow:#00000080}.SD8qLW_overlay[data-gs-theme=idea-light]{--gs-bg:#fff;--gs-panel:#f7f8fa;--gs-raise:#ebecf0;--gs-border:#d3d5db;--gs-border-soft:#ebecf0;--gs-fg:#1e1f22;--gs-fg-muted:#3c3f44;--gs-fg-dim:#6c707e;--gs-fg-faint:#818594;--gs-fg-fainter:#a8adbd;--gs-accent:#3574f0;--gs-accent-bg:#3574f01a;--gs-accent-border:#3574f073;--gs-add:#398a4a;--gs-del:#cc4a4a;--gs-warn:#a8760b;--gs-info:#2b7fb8;--gs-add-bg:#398a4a1f;--gs-del-bg:#cc4a4a1f;--gs-warn-bg:#a8760b1f;--gs-info-bg:#2b7fb81f;--gs-add-line:#e6f5e9;--gs-del-line:#fbe9ea;--gs-add-word:#c2e5c9;--gs-del-word:#f5c9cc;--gs-hunk:#3574f012;--gs-neutral-bg:#6c707e1f;--gs-backdrop:#1e1f2242;--gs-shadow:#1e1f222e}.SD8qLW_overlay[data-gs-theme=vscode-dark]{--gs-bg:#1e1e1e;--gs-panel:#252526;--gs-raise:#2d2d30;--gs-border:#3e3e42;--gs-border-soft:#2d2d30;--gs-fg:#d4d4d4;--gs-fg-muted:#ccc;--gs-fg-dim:#9d9d9d;--gs-fg-faint:gray;--gs-fg-fainter:#5a5a5a;--gs-accent:#0098ff;--gs-accent-bg:#007acc3d;--gs-accent-border:#0098ff99;--gs-add:#89d185;--gs-del:#f14c4c;--gs-warn:#cca700;--gs-info:#75beff;--gs-add-bg:#89d1852e;--gs-del-bg:#f14c4c2e;--gs-warn-bg:#cca7002e;--gs-info-bg:#75beff2e;--gs-add-line:#9bb9552e;--gs-del-line:#ff000029;--gs-add-word:#9bb95566;--gs-del-word:#ff00005c;--gs-hunk:#007acc24;--gs-neutral-bg:#bebebe24;--gs-backdrop:#0000008c;--gs-shadow:#0009}.SD8qLW_overlay[data-gs-theme=vscode-light]{--gs-bg:#fff;--gs-panel:#f3f3f3;--gs-raise:#e8e8e8;--gs-border:#cecece;--gs-border-soft:#e8e8e8;--gs-fg:#1e1e1e;--gs-fg-muted:#333;--gs-fg-dim:#616161;--gs-fg-faint:#767676;--gs-fg-fainter:#a0a0a0;--gs-accent:#005fb8;--gs-accent-bg:#005fb81a;--gs-accent-border:#005fb873;--gs-add:#10793f;--gs-del:#b5200d;--gs-warn:#855b00;--gs-info:#005fb8;--gs-add-bg:#10793f1f;--gs-del-bg:#b5200d1f;--gs-warn-bg:#855b001f;--gs-info-bg:#005fb81f;--gs-add-line:#9bb95538;--gs-del-line:#ff000021;--gs-add-word:#9bb95573;--gs-del-word:#ff00004d;--gs-hunk:#005fb812;--gs-neutral-bg:#6161611f;--gs-backdrop:#00000040;--gs-shadow:#0000002e}.SD8qLW_overlay[data-gs-theme=cyberpunk-dark]{--gs-bg:#0b0417;--gs-panel:#14082a;--gs-raise:#1f0d3d;--gs-border:#3a1f6b;--gs-border-soft:#26124a;--gs-fg:#f0e6ff;--gs-fg-muted:#d5c2f5;--gs-fg-dim:#a98fd6;--gs-fg-faint:#7d64a8;--gs-fg-fainter:#56427a;--gs-accent:#00f0ff;--gs-on-accent:#0b0417;--gs-accent-bg:#00f0ff24;--gs-accent-border:#00f0ff80;--gs-add:#39ff88;--gs-del:#ff2e88;--gs-warn:#fc0;--gs-info:#00f0ff;--gs-add-bg:#39ff8824;--gs-del-bg:#ff2e8824;--gs-warn-bg:#ffcc0024;--gs-info-bg:#00f0ff24;--gs-add-line:#39ff881f;--gs-del-line:#ff2e881f;--gs-add-word:#39ff8857;--gs-del-word:#ff2e8857;--gs-hunk:#00f0ff1a;--gs-neutral-bg:#a98fd629;--gs-backdrop:#06020ead;--gs-shadow:#00f0ff24}.SD8qLW_overlay[data-gs-theme=cyberpunk-light]{--gs-bg:#fdfbff;--gs-panel:#f4eeff;--gs-raise:#e9dfff;--gs-border:#c9b3f0;--gs-border-soft:#e0d2f7;--gs-fg:#1a0b2e;--gs-fg-muted:#33195c;--gs-fg-dim:#6b4ba0;--gs-fg-faint:#8f74bd;--gs-fg-fainter:#b9a5d6;--gs-accent:#00a6b8;--gs-accent-bg:#00a6b81f;--gs-accent-border:#00a6b880;--gs-add:#00875a;--gs-del:#d6006e;--gs-warn:#b37a00;--gs-info:#00a6b8;--gs-add-bg:#00875a1f;--gs-del-bg:#d6006e1f;--gs-warn-bg:#b37a001f;--gs-info-bg:#00a6b81f;--gs-add-line:#00c88224;--gs-del-line:#ff2e881f;--gs-add-word:#00c88257;--gs-del-word:#ff2e884d;--gs-hunk:#00a6b814;--gs-neutral-bg:#6b4ba01f;--gs-backdrop:#1a0b2e47;--gs-shadow:#1a0b2e29}.SD8qLW_overlay[data-gs-theme=one-dark]{--gs-bg:#282c34;--gs-panel:#21252b;--gs-raise:#2c313a;--gs-border:#3e4451;--gs-border-soft:#2c313a;--gs-fg:#abb2bf;--gs-fg-muted:#b6bdca;--gs-fg-dim:#7f848e;--gs-fg-faint:#636d83;--gs-fg-fainter:#4b5263;--gs-accent:#61afef;--gs-accent-bg:#61afef24;--gs-accent-border:#61afef8c;--gs-add:#98c379;--gs-del:#e06c75;--gs-warn:#e5c07b;--gs-info:#56b6c2;--gs-add-bg:#98c37929;--gs-del-bg:#e06c7529;--gs-warn-bg:#e5c07b29;--gs-info-bg:#56b6c229;--gs-add-line:#98c37924;--gs-del-line:#e06c7524;--gs-add-word:#98c37961;--gs-del-word:#e06c7561;--gs-hunk:#61afef1a;--gs-neutral-bg:#7f848e2e;--gs-backdrop:#171a2199;--gs-shadow:#0f11158c}.SD8qLW_overlay[data-gs-theme=one-light]{--gs-bg:#fafafa;--gs-panel:#f0f0f0;--gs-raise:#e5e5e6;--gs-border:#d4d4d4;--gs-border-soft:#e5e5e6;--gs-fg:#383a42;--gs-fg-muted:#4a4c53;--gs-fg-dim:#696c77;--gs-fg-faint:#909196;--gs-fg-fainter:#b8b9bd;--gs-accent:#4078f2;--gs-accent-bg:#4078f21a;--gs-accent-border:#4078f273;--gs-add:#50a14f;--gs-del:#e45649;--gs-warn:#c18401;--gs-info:#0184bc;--gs-add-bg:#50a14f1f;--gs-del-bg:#e456491f;--gs-warn-bg:#c184011f;--gs-info-bg:#0184bc1f;--gs-add-line:#50a14f24;--gs-del-line:#e4564921;--gs-add-word:#50a14f57;--gs-del-word:#e4564952;--gs-hunk:#4078f212;--gs-neutral-bg:#696c771f;--gs-backdrop:#383a4242;--gs-shadow:#383a422e}.SD8qLW_overlay[data-gs-theme=solarized-dark]{--gs-bg:#002b36;--gs-panel:#073642;--gs-raise:#0a4553;--gs-border:#0f5666;--gs-border-soft:#073642;--gs-fg:#93a1a1;--gs-fg-muted:#839496;--gs-fg-dim:#657b83;--gs-fg-faint:#586e75;--gs-fg-fainter:#45636b;--gs-accent:#268bd2;--gs-accent-bg:#268bd229;--gs-accent-border:#268bd28c;--gs-add:#859900;--gs-del:#dc322f;--gs-warn:#b58900;--gs-info:#2aa198;--gs-add-bg:#85990033;--gs-del-bg:#dc322f2e;--gs-warn-bg:#b589002e;--gs-info-bg:#2aa1982e;--gs-add-line:#85990029;--gs-del-line:#dc322f26;--gs-add-word:#85990066;--gs-del-word:#dc322f61;--gs-hunk:#268bd21f;--gs-neutral-bg:#657b8333;--gs-backdrop:#00141a9e;--gs-shadow:#00141a8c}.SD8qLW_overlay[data-gs-theme=solarized-light]{--gs-bg:#fdf6e3;--gs-panel:#eee8d5;--gs-raise:#e3ddca;--gs-border:#d5cfbb;--gs-border-soft:#eee8d5;--gs-fg:#586e75;--gs-fg-muted:#657b83;--gs-fg-dim:#839496;--gs-fg-faint:#93a1a1;--gs-fg-fainter:#b5b0a0;--gs-accent:#268bd2;--gs-accent-bg:#268bd21f;--gs-accent-border:#268bd273;--gs-add:#6c7c00;--gs-del:#cb2825;--gs-warn:#9a7400;--gs-info:#21867f;--gs-add-bg:#8599002e;--gs-del-bg:#dc322f24;--gs-warn-bg:#b5890029;--gs-info-bg:#2aa19824;--gs-add-line:#85990029;--gs-del-line:#dc322f1f;--gs-add-word:#85990061;--gs-del-word:#dc322f4d;--gs-hunk:#268bd214;--gs-neutral-bg:#586e7524;--gs-backdrop:#586e7542;--gs-shadow:#586e7533}.SD8qLW_overlay[data-gs-theme=nord-dark]{--gs-bg:#2e3440;--gs-panel:#3b4252;--gs-raise:#434c5e;--gs-border:#4c566a;--gs-border-soft:#3b4252;--gs-fg:#eceff4;--gs-fg-muted:#d8dee9;--gs-fg-dim:#9aa5b8;--gs-fg-faint:#7b88a1;--gs-fg-fainter:#5d6a82;--gs-accent:#88c0d0;--gs-on-accent:#2e3440;--gs-accent-bg:#88c0d024;--gs-accent-border:#88c0d08c;--gs-add:#a3be8c;--gs-del:#bf616a;--gs-warn:#ebcb8b;--gs-info:#81a1c1;--gs-add-bg:#a3be8c29;--gs-del-bg:#bf616a2e;--gs-warn-bg:#ebcb8b29;--gs-info-bg:#81a1c129;--gs-add-line:#a3be8c24;--gs-del-line:#bf616a26;--gs-add-word:#a3be8c61;--gs-del-word:#bf616a66;--gs-hunk:#88c0d01a;--gs-neutral-bg:#9aa5b829;--gs-backdrop:#1d232d9e;--gs-shadow:#1419218c}.SD8qLW_overlay[data-gs-theme=nord-light]{--gs-bg:#eceff4;--gs-panel:#e5e9f0;--gs-raise:#d8dee9;--gs-border:#c3cbd8;--gs-border-soft:#dfe4ec;--gs-fg:#2e3440;--gs-fg-muted:#3b4252;--gs-fg-dim:#4c566a;--gs-fg-faint:#6b7689;--gs-fg-fainter:#9aa4b5;--gs-accent:#5e81ac;--gs-accent-bg:#5e81ac1f;--gs-accent-border:#5e81ac80;--gs-add:#5e7d47;--gs-del:#a5424c;--gs-warn:#97701f;--gs-info:#4c7a8c;--gs-add-bg:#5e7d4724;--gs-del-bg:#a5424c21;--gs-warn-bg:#97701f24;--gs-info-bg:#4c7a8c21;--gs-add-line:#5e7d4724;--gs-del-line:#a5424c1f;--gs-add-word:#5e7d4757;--gs-del-word:#a5424c52;--gs-hunk:#5e81ac17;--gs-neutral-bg:#4c566a21;--gs-backdrop:#2e344042;--gs-shadow:#2e34402e}.SD8qLW_overlay{--gs-inset:14px;--gs-h-control:28px;--gs-h-compact:24px;--gs-pad-control:0 12px;--gs-pad-compact:0 10px;--gs-on-accent:#fff;--gs-graph-0:#58a6ff;--gs-graph-1:#3fb950;--gs-graph-2:#d29922;--gs-graph-3:#bc8cff;--gs-graph-4:#f778ba;--gs-graph-5:#39c5cf;--gs-r-pill:999px;--gs-r-control:8px;--gs-r-surface:12px;--gs-r-drawer:14px;--gs-t-meta:11px;--gs-t-dense:12px;--gs-t-ui:13px;--gs-gutter:16px;--gs-gutter-pane:12px;z-index:1000;padding:var(--gs-inset);box-sizing:border-box;background:var(--gs-backdrop);justify-content:flex-end;align-items:stretch;gap:12px;animation:.16s ease-out SD8qLW_gsFade;display:flex;position:fixed;inset:0}.SD8qLW_drawer{box-sizing:border-box;width:min(1600px,94vw);height:100%;color:var(--gs-fg);background:var(--gs-bg);border:1px solid var(--gs-border);border-radius:var(--gs-r-drawer);box-shadow:0 24px 64px var(--gs-shadow);font-family:var(--dsw-font-ui,-apple-system, BlinkMacSystemFont, \"Segoe UI\", Helvetica, Arial, sans-serif);--gs-surface:var(--gs-bg);--gs-surface-2:var(--gs-panel);flex-direction:column;animation:.18s cubic-bezier(.22,1,.36,1) SD8qLW_gsSlide;display:flex;position:relative;overflow:hidden}.SD8qLW_drawer[data-gs-bg]{--gs-surface:color-mix(in srgb, var(--gs-bg) var(--gs-veil), transparent);--gs-surface-2:color-mix(in srgb, var(--gs-panel) var(--gs-veil), transparent)}.SD8qLW_drawer[data-gs-bg]:before{content:\"\";z-index:0;background-image:var(--gs-bg-image);filter:blur(var(--gs-bg-blur));pointer-events:none;background-position:50%;background-size:cover;position:absolute;inset:0;transform:scale(1.12)}.SD8qLW_drawer>:not(.SD8qLW_resizer){z-index:1;position:relative}.SD8qLW_drawer>.SD8qLW_header{z-index:24}.SD8qLW_drawer>.SD8qLW_tabs{z-index:23}.SD8qLW_drawer>.SD8qLW_compareBar{z-index:22}.SD8qLW_drawer>.SD8qLW_syncBar{z-index:20}.SD8qLW_drawer>.SD8qLW_confirmScrim{z-index:40;position:absolute;inset:0}.SD8qLW_overlayMax{gap:0;padding:0}.SD8qLW_overlayMax .SD8qLW_drawer{border-width:0 0 0 1px;border-radius:0;flex:auto;width:auto;min-width:0}@keyframes SD8qLW_gsFade{0%{opacity:0}}@keyframes SD8qLW_gsSlide{0%{opacity:0;transform:translate(24px)}}.SD8qLW_resizer{z-index:30;cursor:col-resize;touch-action:none;justify-content:center;align-items:center;width:10px;display:flex;position:absolute;top:0;bottom:0;left:0}.SD8qLW_resizer:after{content:\"\";background:var(--gs-fg-fainter);opacity:0;border-radius:999px;width:3px;height:32px;transition:opacity .14s,height .14s}.SD8qLW_resizer:hover:after{opacity:.6}.SD8qLW_resizerActive:after{opacity:.9;height:56px}.SD8qLW_paneDivider{z-index:5;cursor:col-resize;touch-action:none;flex:none;justify-content:center;align-items:center;width:7px;display:flex;position:relative}.SD8qLW_paneDivider:before{content:\"\";background:var(--gs-border-soft);width:1px;position:absolute;top:0;bottom:0;left:3px}.SD8qLW_paneDivider:after{content:\"\";background:var(--gs-fg-fainter);opacity:0;border-radius:999px;width:3px;height:28px;transition:opacity .14s,height .14s;position:relative}.SD8qLW_paneDivider:hover:after{opacity:.6}.SD8qLW_paneDividerActive:after{opacity:.9;height:48px}.SD8qLW_header{padding:10px var(--gs-gutter);border-bottom:1px solid var(--gs-border);background:var(--gs-surface-2);font-family:var(--dsw-font-ui,system-ui, sans-serif);font-size:var(--gs-t-ui);flex:none;justify-content:space-between;align-items:center;gap:12px;display:flex}.SD8qLW_headerLeft{flex-wrap:wrap;align-items:center;gap:10px;min-width:0;display:flex}.SD8qLW_headerBranch{border:1px solid var(--gs-accent-border);background:var(--gs-accent-bg);color:var(--gs-accent);border-radius:999px;align-items:center;gap:6px;padding:2px 10px;font-weight:600;display:inline-flex}.SD8qLW_refButton.SD8qLW_headerPicker{border-color:var(--gs-accent-border);background:var(--gs-accent-bg);max-width:420px;color:var(--gs-accent);font-weight:600}.SD8qLW_refButton.SD8qLW_headerPicker:hover{background:var(--gs-accent-bg);color:var(--gs-accent);border-color:var(--gs-accent)}.SD8qLW_elide{flex:0 auto;align-items:baseline;min-width:0;display:inline-flex}.SD8qLW_elideHead{white-space:nowrap;text-overflow:ellipsis;flex:0 999 auto;min-width:0;overflow:hidden}.SD8qLW_elideTail{white-space:nowrap;text-overflow:ellipsis;flex:0 auto;min-width:0;overflow:hidden}.SD8qLW_headerPathMain{color:var(--gs-fg-faint);font-size:var(--gs-t-meta)}.SD8qLW_headerPathMain .SD8qLW_elideTail{color:var(--gs-fg-dim)}.SD8qLW_headerViewRef{max-width:160px}.SD8qLW_headerView{background:var(--gs-neutral-bg);color:var(--gs-fg-muted);font-size:var(--gs-t-meta);font-variant-numeric:tabular-nums;border-radius:999px;flex:none;padding:1px 8px}.SD8qLW_headerDetached{background:var(--gs-warn-bg);color:var(--gs-warn);font-size:var(--gs-t-meta);letter-spacing:.02em;border-radius:999px;padding:1px 8px}.SD8qLW_headerTotals{font-variant-numeric:tabular-nums}.SD8qLW_headerTotalsAdd{color:var(--gs-add);font-weight:600}.SD8qLW_headerTotalsDel{color:var(--gs-del);font-weight:600}.SD8qLW_headerTotalsDim{color:var(--gs-fg-dim);font-size:var(--gs-t-dense)}.SD8qLW_headerRight{flex:none;gap:8px;display:flex;position:relative}.SD8qLW_theme{display:inline-flex;position:relative}.SD8qLW_refPop.SD8qLW_settingsPop{width:320px;max-width:calc(100vw - 32px);max-height:min(560px,100vh - 120px);top:calc(100% + 6px);left:auto;right:0}.SD8qLW_themeRail{min-height:0;font-family:var(--dsw-font-ui,system-ui, sans-serif);flex-direction:column;flex:1;gap:14px;padding:12px 14px 16px;display:flex;overflow-y:auto}.SD8qLW_themeGroup{flex-direction:column;gap:6px;display:flex}.SD8qLW_themeLabel{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);letter-spacing:.04em;text-transform:uppercase;font-weight:600}.SD8qLW_themeRowSplit{justify-content:space-between;align-items:center;gap:8px;display:flex}.SD8qLW_segmented{gap:6px;display:flex}.SD8qLW_segment{box-sizing:border-box;border:1px solid var(--gs-border);border-radius:var(--gs-r-control);color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-meta);cursor:pointer;background:0 0;flex-direction:column;flex:1 1 0;align-items:stretch;gap:4px;padding:4px;transition:background .12s,color .12s,border-color .12s;display:flex}.SD8qLW_segment:hover{background:var(--gs-raise);border-color:var(--gs-fg-fainter);color:var(--gs-fg)}.SD8qLW_segment:focus-visible{outline:2px solid var(--gs-accent);outline-offset:1px}.SD8qLW_segmentChip{border-radius:calc(var(--gs-r-control) - 4px);border:1px solid #80808073;height:20px}.SD8qLW_chipLight{background:#fff}.SD8qLW_chipDark{background:#0b0b0d}.SD8qLW_chipSystem{background:linear-gradient(105deg,#fff 0 50%,#0b0b0d 50% 100%)}.SD8qLW_paletteRow{box-sizing:border-box;border-radius:var(--gs-r-control);width:100%;color:var(--gs-fg-muted);font-family:inherit;font-size:var(--gs-t-dense);text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:8px;padding:5px 8px;display:flex}.SD8qLW_paletteRow:hover{background:var(--gs-raise);color:var(--gs-fg)}.SD8qLW_swatch{border:1px solid var(--gs-border);border-radius:3px;flex:none;width:26px;height:12px;display:inline-flex;overflow:hidden}.SD8qLW_swatch span{flex:1}.SD8qLW_scopeRow{gap:6px;display:flex}.SD8qLW_scopeHint{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);overflow-wrap:anywhere}.SD8qLW_bgPreview{border:1px solid var(--gs-border);border-radius:var(--gs-r-control);background-color:var(--gs-bg);background-position:50%;background-size:cover;height:64px}.SD8qLW_bgEmpty{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);justify-content:center;align-items:center;display:flex}.SD8qLW_sliderRow{font-size:var(--gs-t-meta);color:var(--gs-fg-dim);align-items:center;gap:8px;display:flex}.SD8qLW_sliderRow input{min-width:0;accent-color:var(--gs-accent);flex:1}.SD8qLW_sliderValue{text-align:right;font-variant-numeric:tabular-nums;flex:none;width:38px}.SD8qLW_cssArea{box-sizing:border-box;border:1px solid var(--gs-border);border-radius:var(--gs-r-control);background:var(--gs-bg);width:100%;min-height:96px;max-height:220px;color:var(--gs-fg);font-family:var(--dsw-font-mono,ui-monospace, Consolas, monospace);font-size:var(--gs-t-meta);resize:vertical;outline:none;padding:7px 8px}.SD8qLW_cssArea:focus{border-color:var(--gs-accent-border)}.SD8qLW_themeNote{color:var(--gs-warn);font-size:var(--gs-t-meta)}.SD8qLW_themeDirty{color:var(--gs-accent);font-size:var(--gs-t-meta)}.SD8qLW_wtCurrent{color:var(--gs-add);font-size:8px;line-height:1}.SD8qLW_commitCopy{margin-left:auto}.SD8qLW_commitPop{z-index:40;box-sizing:border-box;border:1px solid var(--gs-border);border-radius:var(--gs-r-surface);background:var(--gs-panel);width:min(380px,100vw - 24px);color:var(--gs-fg);box-shadow:0 16px 40px var(--gs-shadow);font-family:var(--dsw-font-ui,-apple-system, BlinkMacSystemFont, \"Segoe UI\", Helvetica, Arial, sans-serif);font-size:var(--gs-t-dense);flex-direction:column;gap:6px;padding:10px 12px 12px;display:flex;position:fixed;overflow:auto}.SD8qLW_commitPopTop{align-items:center;gap:8px;display:flex}.SD8qLW_commitPopTop .SD8qLW_commitWhen{margin-right:auto}.SD8qLW_commitPopMeta{color:var(--gs-fg-muted);font-size:var(--gs-t-dense);flex-direction:column;gap:2px;line-height:16px;display:flex}.SD8qLW_commitFilter{min-width:120px;height:var(--gs-h-control);box-sizing:border-box;border:1px solid var(--gs-border-soft);border-radius:var(--gs-r-control);background:var(--gs-bg);color:var(--gs-fg);font-family:inherit;font-size:var(--gs-t-dense);outline:none;flex:auto;padding:0 10px}.SD8qLW_commitFilter:focus{border-color:var(--gs-accent)}.SD8qLW_commitFilter::placeholder{color:var(--gs-fg-faint)}.SD8qLW_filterChips{border-bottom:1px solid var(--gs-border-soft);flex-wrap:wrap;flex:none;align-items:center;gap:6px;padding:6px 10px;display:flex}.SD8qLW_filterChip{border:1px solid var(--gs-border-soft);border-radius:var(--gs-r-control);background:var(--gs-surface-2);max-width:220px;font-size:var(--gs-t-dense);align-items:center;gap:2px;line-height:18px;display:inline-flex}.SD8qLW_filterChipLabel{text-overflow:ellipsis;white-space:nowrap;color:var(--gs-fg-muted);padding:2px 4px 2px 8px;overflow:hidden}.SD8qLW_filterChipRemove{border:none;border-left:1px solid var(--gs-border-soft);color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-dense);cursor:pointer;background:0 0;flex:none;padding:0 6px;line-height:20px}.SD8qLW_filterChipRemove:hover{color:var(--gs-danger,var(--gs-fg))}.SD8qLW_filterClear{color:var(--gs-fg-faint);font-family:inherit;font-size:var(--gs-t-dense);cursor:pointer;background:0 0;border:none;padding:2px 4px;line-height:18px}.SD8qLW_filterClear:hover{color:var(--gs-fg)}.SD8qLW_funnel{display:inline-flex;position:relative}.SD8qLW_funnelButton.SD8qLW_funnelButtonActive{color:var(--gs-accent);border-color:var(--gs-accent)}.SD8qLW_funnelPop{z-index:40;box-sizing:border-box;border:1px solid var(--gs-border);border-radius:var(--gs-r-surface);background:var(--gs-panel);width:320px;max-width:calc(100vw - 24px);box-shadow:0 16px 40px var(--gs-shadow);font-size:var(--gs-t-dense);flex-direction:column;display:flex;position:fixed;overflow:hidden}.SD8qLW_funnelTabs{border:1px solid var(--gs-border-soft);border-radius:var(--gs-r-pill);background:var(--gs-bg);flex:none;gap:2px;margin:8px 8px 0;padding:2px;display:flex}.SD8qLW_funnelTab{border-radius:var(--gs-r-pill);min-width:0;height:22px;color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-dense);white-space:nowrap;cursor:pointer;background:0 0;border:none;flex:1;padding:0 8px;line-height:1;transition:background .12s,color .12s}.SD8qLW_funnelTab:hover{color:var(--gs-fg)}.SD8qLW_funnelTab.SD8qLW_funnelTabActive{color:var(--gs-fg);background:var(--gs-raise);box-shadow:inset 0 0 0 1px var(--gs-border)}.SD8qLW_funnelTab:focus-visible{outline:2px solid var(--gs-accent);outline-offset:1px}.SD8qLW_funnelTabCount{color:var(--gs-accent);font-variant-numeric:tabular-nums;margin-left:4px}.SD8qLW_funnelPane{flex-direction:column;flex:auto;gap:6px;min-height:0;padding:8px;display:flex}.SD8qLW_funnelCaption{color:var(--gs-fg-faint);letter-spacing:.04em;text-transform:uppercase;flex:none;font-size:11px;line-height:14px}.SD8qLW_funnelBounds{border:1px solid var(--gs-border-soft);border-radius:var(--gs-r-control);background:var(--gs-bg);flex:none;gap:2px;padding:2px;display:flex}.SD8qLW_funnelBoundBtn{border-radius:calc(var(--gs-r-control) - 3px);min-width:0;height:20px;color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-dense);cursor:pointer;background:0 0;border:none;flex:1;padding:0 6px;line-height:1;transition:background .12s,color .12s}.SD8qLW_funnelBoundBtn:hover{color:var(--gs-fg)}.SD8qLW_funnelBoundBtn.SD8qLW_funnelBoundBtnActive{color:var(--gs-accent);background:var(--gs-accent-bg);box-shadow:inset 0 0 0 1px var(--gs-accent-border)}.SD8qLW_cal{flex-direction:column;flex:none;gap:4px;display:flex}.SD8qLW_calHead{align-items:center;gap:4px;display:flex}.SD8qLW_calTitle{text-align:center;color:var(--gs-fg);font-size:var(--gs-t-dense);flex:1;line-height:20px}.SD8qLW_calNav{border-radius:var(--gs-r-control);width:22px;height:20px;color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-ui);cursor:pointer;background:0 0;border:none;flex:none;padding:0}.SD8qLW_calNav:hover{color:var(--gs-fg);background:var(--gs-raise)}.SD8qLW_calWeek,.SD8qLW_calGrid{grid-template-columns:repeat(7,1fr);gap:2px;display:grid}.SD8qLW_calWeek span{text-align:center;color:var(--gs-fg-faint);font-size:11px;line-height:14px}.SD8qLW_calGrid button{border-radius:var(--gs-r-control);height:26px;color:var(--gs-fg-muted);font-family:inherit;font-size:var(--gs-t-dense);font-variant-numeric:tabular-nums;cursor:pointer;background:0 0;border:none}.SD8qLW_calGrid button:hover{background:var(--gs-raise);color:var(--gs-fg)}.SD8qLW_calGrid button.SD8qLW_calOut{color:var(--gs-fg-fainter)}.SD8qLW_calGrid button.SD8qLW_calToday{color:var(--gs-accent);font-weight:600}.SD8qLW_calGrid button.SD8qLW_calIn{background:var(--gs-accent-bg);color:var(--gs-fg)}.SD8qLW_calGrid button.SD8qLW_calMark{background:var(--gs-accent);color:var(--gs-on-accent);font-weight:600}.SD8qLW_funnelBoundRows{flex:none;grid-template-columns:1fr 1fr;gap:6px;display:grid}.SD8qLW_funnelBoundRow{box-sizing:border-box;border:1px solid var(--gs-border-soft);border-radius:var(--gs-r-control);background:var(--gs-bg);align-items:center;gap:4px;min-width:0;padding:3px 6px;font-size:11px;line-height:16px;display:flex}.SD8qLW_funnelBoundKey{color:var(--gs-fg-faint);flex:none}.SD8qLW_funnelBoundVal{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--gs-fg-faint);font-variant-numeric:tabular-nums;flex:1;overflow:hidden}.SD8qLW_funnelBoundValSet{color:var(--gs-fg)}.SD8qLW_funnelBoundClear{color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-dense);cursor:pointer;background:0 0;border:none;flex:none;padding:0 2px;line-height:1}.SD8qLW_funnelBoundClear:hover{color:var(--gs-danger,var(--gs-fg))}.SD8qLW_funnelSearch{box-sizing:border-box;border:1px solid var(--gs-border-soft);border-radius:var(--gs-r-control);background:var(--gs-bg);height:26px;color:var(--gs-fg);font-family:inherit;font-size:var(--gs-t-dense);outline:none;flex:none;padding:0 8px}.SD8qLW_funnelSearch::placeholder{color:var(--gs-fg-faint)}.SD8qLW_funnelSearch:focus{border-color:var(--gs-accent);box-shadow:0 0 0 2px var(--gs-accent-bg)}.SD8qLW_funnelList{overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:var(--gs-fg-fainter) transparent;flex-direction:column;flex:auto;gap:1px;min-height:0;margin:0 -4px;padding:0 4px;display:flex;overflow-y:auto}.SD8qLW_funnelList::-webkit-scrollbar{width:10px}.SD8qLW_funnelList::-webkit-scrollbar-track{background:0 0}.SD8qLW_funnelList::-webkit-scrollbar-thumb{background:var(--gs-fg-fainter);background-clip:content-box;border:3px solid #0000;border-radius:5px}.SD8qLW_funnelRow{box-sizing:border-box;border-radius:var(--gs-r-control);cursor:pointer;align-items:center;gap:6px;min-height:24px;padding:0 4px;display:flex}.SD8qLW_funnelRow:hover{background:var(--gs-raise)}.SD8qLW_funnelRow:has(input[type=checkbox]:checked) .SD8qLW_funnelName,.SD8qLW_funnelRow:has(input[type=checkbox]:indeterminate) .SD8qLW_funnelName{color:var(--gs-fg)}.SD8qLW_funnelRow input[type=checkbox]{-webkit-appearance:none;appearance:none;box-sizing:border-box;border:1px solid var(--gs-fg-fainter);cursor:pointer;background:0 0;border-radius:3px;flex:none;width:14px;height:14px;margin:0;transition:background .12s,border-color .12s;position:relative}.SD8qLW_funnelRow input[type=checkbox]:hover{border-color:var(--gs-fg-dim)}.SD8qLW_funnelRow input[type=checkbox]:checked,.SD8qLW_funnelRow input[type=checkbox]:indeterminate{background:var(--gs-accent);border-color:var(--gs-accent)}.SD8qLW_funnelRow input[type=checkbox]:focus-visible{outline:2px solid var(--gs-accent);outline-offset:1px}.SD8qLW_funnelRow input[type=checkbox]:checked:after{content:\"\";border:solid var(--gs-on-accent);border-width:0 1.5px 1.5px 0;width:3px;height:7px;position:absolute;top:1px;left:4px;transform:rotate(42deg)}.SD8qLW_funnelRow input[type=checkbox]:indeterminate:after{content:\"\";background:var(--gs-on-accent);border-radius:1px;width:8px;height:2px;position:absolute;top:5px;left:2px}.SD8qLW_pathNode,.SD8qLW_pathChildren{flex-direction:column;display:flex}.SD8qLW_pathFileGlyph,.SD8qLW_pathDirGlyph{width:16px;height:16px;color:var(--gs-fg-dim);flex:none}.SD8qLW_funnelRow:hover .SD8qLW_pathFileGlyph,.SD8qLW_funnelRow:hover .SD8qLW_pathDirGlyph{color:var(--gs-fg-muted)}.SD8qLW_funnelName{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--gs-fg-muted);flex:1;overflow:hidden}.SD8qLW_funnelCount{color:var(--gs-fg-faint);font-variant-numeric:tabular-nums;flex:none;font-size:11px}.SD8qLW_funnelMore{color:var(--gs-fg-faint);padding:4px 6px}.SD8qLW_funnelChevron{width:14px;color:var(--gs-fg-faint);cursor:pointer;background:0 0;border:none;flex:none;padding:0;font-family:inherit;font-size:9px;line-height:16px}.SD8qLW_funnelChevron:hover:not(:disabled){color:var(--gs-fg)}.SD8qLW_funnelChevron:disabled{cursor:default}.SD8qLW_funnelPresets{flex:none;gap:4px;display:flex}.SD8qLW_funnelPreset{flex:1 1 0;min-width:0;padding:0 6px}.SD8qLW_funnelPreset.SD8qLW_funnelPresetActive{color:var(--gs-accent);border-color:var(--gs-accent);background:var(--gs-accent-bg)}.SD8qLW_funnelFoot{border-top:1px solid var(--gs-border-soft);background:var(--gs-bg);flex:none;justify-content:space-between;align-items:center;gap:8px;padding:6px 10px;font-size:11px;line-height:16px;display:flex}.SD8qLW_funnelFootCount{color:var(--gs-fg-faint);font-variant-numeric:tabular-nums}.SD8qLW_funnelFootCountOn{color:var(--gs-fg-muted)}.SD8qLW_funnelFootClear{border-radius:var(--gs-r-control);color:var(--gs-fg-dim);cursor:pointer;background:0 0;border:none;flex:none;padding:2px 6px;font-family:inherit;font-size:11px;line-height:16px}.SD8qLW_funnelFootClear:hover:not(:disabled){color:var(--gs-fg);background:var(--gs-raise)}.SD8qLW_funnelFootClear:disabled{color:var(--gs-fg-fainter);cursor:default}.SD8qLW_commitPopSubject{color:var(--gs-fg);font-size:var(--gs-t-ui);white-space:pre-wrap;overflow-wrap:anywhere;user-select:text;font-weight:600;line-height:18px}.SD8qLW_commitPopBody{color:var(--gs-fg-muted);font-family:inherit;font-size:var(--gs-t-dense);white-space:pre-wrap;overflow-wrap:anywhere;user-select:text;margin:0;line-height:18px}.SD8qLW_tabs{padding:0 var(--gs-gutter);border-bottom:1px solid var(--gs-border-soft);background:var(--gs-surface-2);flex:none;gap:24px;font-family:inherit;display:flex}.SD8qLW_tab{font-family:inherit;font-size:var(--gs-t-ui);color:var(--gs-fg-dim);cursor:pointer;background:0 0;border:none;padding:8px 0 9px;font-weight:500;line-height:16px;position:relative}.SD8qLW_tab:after{content:\"\";background:0 0;border-radius:2px;height:2px;position:absolute;bottom:1px;left:0;right:0}.SD8qLW_tabActive{color:var(--gs-accent)}.SD8qLW_tabActive:after{background:var(--gs-accent)}.SD8qLW_compareBar{padding:8px var(--gs-gutter);border-bottom:1px solid var(--gs-border-soft);background:var(--gs-surface-2);color:var(--gs-fg-dim);font-family:var(--dsw-font-ui,system-ui, sans-serif);font-size:var(--gs-t-dense);flex-wrap:wrap;flex:none;align-items:center;gap:10px;display:flex}.SD8qLW_compareArrow{color:var(--gs-fg-faint)}.SD8qLW_refPicker{align-items:center;gap:6px;display:inline-flex;position:relative}.SD8qLW_refLabel{color:var(--gs-fg-faint);flex:none}.SD8qLW_refButton{justify-content:space-between;max-width:260px}.SD8qLW_refValue{min-width:0;overflow:hidden}.SD8qLW_refCaret{color:var(--gs-fg-faint);flex:none;font-size:9px}.SD8qLW_refPop{z-index:10;border:1px solid var(--gs-border);border-radius:var(--gs-r-control);background:var(--gs-panel);width:300px;max-width:80vw;box-shadow:0 12px 32px var(--gs-shadow);flex-direction:column;display:flex;position:absolute;top:calc(100% + 4px);left:0;overflow:hidden}.SD8qLW_menuPop{width:auto;min-width:100%;padding:4px;left:auto;right:0}.SD8qLW_refSearch{border:0;border-bottom:1px solid var(--gs-border-soft);background:var(--gs-bg);color:var(--gs-fg);font-family:inherit;font-size:var(--gs-t-dense);outline:none;flex:none;padding:7px 10px}.SD8qLW_refSearch::placeholder{color:var(--gs-fg-faint)}.SD8qLW_refList{flex:1;max-height:280px;padding:4px;overflow-y:auto}.SD8qLW_refGroup{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);letter-spacing:.04em;text-transform:uppercase;padding:6px 8px 3px;font-weight:600}.SD8qLW_refRow{box-sizing:border-box;border-radius:var(--gs-r-control);width:100%;color:var(--gs-fg-muted);font-family:inherit;font-size:var(--gs-t-dense);text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:6px;padding:5px 8px;display:flex}.SD8qLW_refRow:hover{background:var(--gs-raise);color:var(--gs-fg)}.SD8qLW_refRowSpacer{flex:none;width:12px}.SD8qLW_refRowName{flex:auto;min-width:0;overflow:hidden}.SD8qLW_refEmpty{color:var(--gs-fg-faint);font-size:var(--gs-t-dense);padding:14px 10px}.SD8qLW_refFoot{border-top:1px solid var(--gs-border-soft);color:var(--gs-fg-faint);font-size:var(--gs-t-meta);flex:none;padding:5px 10px}.SD8qLW_commitsPane{box-sizing:border-box;width:26%;min-height:0;min-width:var(--gs-min-commits);background:var(--gs-surface);flex-direction:column;flex:0 auto;max-width:340px;display:flex}.SD8qLW_paneHead{box-sizing:border-box;min-height:37px;padding:6px var(--gs-gutter-pane);border-bottom:1px solid var(--gs-border-soft);color:var(--gs-fg-dim);font-family:var(--dsw-font-ui,system-ui, sans-serif);font-size:var(--gs-t-dense);flex:none;align-items:center;gap:8px;display:flex}.SD8qLW_paneTitle{font-weight:600}.SD8qLW_commitsSentinel{flex:none;height:1px}.SD8qLW_commitsFoot{color:var(--gs-fg-faint);font-family:var(--dsw-font-ui,system-ui, sans-serif);font-size:var(--gs-t-meta);text-align:center;flex:none;min-height:16px;padding:8px}.SD8qLW_commits{flex-direction:column;flex:1;min-height:0;padding:4px 6px 4px 0;display:flex;overflow-y:auto}.SD8qLW_commitLine{flex:none;align-items:stretch;height:48px;display:flex}.SD8qLW_graphCell{flex:none;display:block}.SD8qLW_commit{box-sizing:border-box;border-radius:var(--gs-r-surface);text-align:left;cursor:pointer;min-width:0;height:100%;font-family:inherit;font-size:var(--gs-t-dense);background:0 0;border:1px solid #0000;flex-direction:column;flex:auto;justify-content:center;gap:2px;margin:1px 0;padding:4px 8px;transition:background .12s,border-color .12s;display:flex;overflow:hidden}.SD8qLW_commit:hover{background:var(--gs-raise)}.SD8qLW_commitActive{border-color:var(--gs-accent-border);background:var(--gs-accent-bg)}.SD8qLW_commitTop{justify-content:space-between;align-items:center;gap:8px;display:flex}.SD8qLW_commitHash{color:var(--gs-info)}.SD8qLW_commitSubjectRow{align-items:baseline;gap:4px;min-width:0;display:flex}.SD8qLW_commitSubject{white-space:nowrap;text-overflow:ellipsis;min-width:0;color:var(--gs-fg-muted);flex:1;overflow:hidden}.SD8qLW_commitHasBody{color:var(--gs-fg-faint);letter-spacing:.04em;flex:none}.SD8qLW_commitRef{white-space:nowrap;text-overflow:ellipsis;border:1px solid var(--gs-accent-border);border-radius:var(--gs-r-pill);background:var(--gs-accent-bg);max-width:96px;color:var(--gs-accent);font-size:var(--gs-t-meta);flex:none;padding:0 5px;line-height:15px;overflow:hidden}.SD8qLW_commitWhen{color:var(--gs-fg-faint);flex:none}.SD8qLW_commitAuthor{text-overflow:ellipsis;white-space:nowrap;max-width:120px;color:var(--gs-fg-dim);flex:none;overflow:hidden}.SD8qLW_body{z-index:1;flex:1;min-height:0;display:flex}.SD8qLW_treeCol{box-sizing:border-box;width:28%;min-height:0;min-width:var(--gs-min-tree);background:var(--gs-surface);flex-direction:column;flex:0 auto;max-width:400px;display:flex}.SD8qLW_treeWrap{box-sizing:border-box;flex-direction:column;flex:1;min-width:0;min-height:0;display:flex}.SD8qLW_treeTools{box-sizing:border-box;min-height:37px;padding:6px var(--gs-gutter-pane);border-bottom:1px solid var(--gs-border-soft);flex-wrap:wrap;flex:none;justify-content:space-between;align-items:center;gap:6px;display:flex}.SD8qLW_treeActions{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.SD8qLW_treeLead{align-items:center;gap:4px;min-width:0;display:flex}.SD8qLW_treeLabel{white-space:nowrap;color:var(--gs-fg-dim);font-size:var(--gs-t-dense);flex:none}.SD8qLW_treeFilter{padding:6px var(--gs-gutter-pane);border-bottom:1px solid var(--gs-border-soft);flex:none;align-items:center;display:flex;position:relative}.SD8qLW_treeFilterInput{min-width:0;height:var(--gs-h-compact);box-sizing:border-box;border:1px solid var(--gs-border-soft);border-radius:var(--gs-r-control);background:var(--gs-bg);color:var(--gs-fg);font-family:inherit;font-size:var(--gs-t-dense);outline:none;flex:auto;padding:0 24px 0 8px}.SD8qLW_treeFilterInput:focus{border-color:var(--gs-accent)}.SD8qLW_treeFilterInput::placeholder{color:var(--gs-fg-faint)}.SD8qLW_treeFilterClear{right:calc(var(--gs-gutter-pane) + 6px);border-radius:var(--gs-r-pill);width:16px;height:16px;color:var(--gs-fg-faint);font-size:var(--gs-t-ui);cursor:pointer;background:0 0;border:0;justify-content:center;align-items:center;padding:0;line-height:1;display:flex;position:absolute}.SD8qLW_treeFilterClear:hover{color:var(--gs-fg)}.SD8qLW_tree{flex:1;min-height:0;margin:0;padding:6px 0 16px;list-style:none;overflow:auto}.SD8qLW_treeEmpty{min-height:0;color:var(--gs-fg-faint);font-size:var(--gs-t-ui);flex:1;justify-content:center;align-items:center;display:flex}.SD8qLW_treeSub{margin:0;padding:0;list-style:none;position:relative}.SD8qLW_treeSub:before{content:\"\";top:0;bottom:0;left:var(--gs-rail,0);background:var(--gs-border-soft);width:1px;position:absolute}.SD8qLW_treeDirLi{position:relative}.SD8qLW_treeDir{box-sizing:border-box;width:100%;color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-dense);text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:6px;padding:4px 12px 4px 8px;font-weight:600;display:flex}.SD8qLW_treeDir:hover{background:var(--gs-panel);color:var(--gs-fg-muted)}.SD8qLW_treeDirActive{color:var(--gs-fg-muted)}.SD8qLW_chevron{width:10px;color:var(--gs-fg-fainter);font-size:var(--gs-t-meta);flex:none;transition:transform .12s;display:inline-block}.SD8qLW_chevronOpen{transform:rotate(90deg)}.SD8qLW_treeDirName{white-space:nowrap;text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.SD8qLW_treeDirCount{background:var(--gs-neutral-bg);color:var(--gs-fg-dim);font-size:var(--gs-t-meta);border-radius:999px;flex:none;padding:0 6px;font-weight:600;line-height:16px}.SD8qLW_treeDirCounts{font-size:var(--gs-t-meta);font-variant-numeric:tabular-nums;flex:none}.SD8qLW_file{box-sizing:border-box;width:100%;color:var(--gs-fg-muted);font-family:inherit;font-size:var(--gs-t-dense);text-align:left;cursor:pointer;background:0 0;border:0;border-left:2px solid #0000;align-items:center;gap:8px;padding:5px 14px;display:flex}.SD8qLW_file:hover{background:var(--gs-panel)}.SD8qLW_fileActive{background:var(--gs-panel);border-left-color:var(--gs-accent);color:var(--gs-fg)}.SD8qLW_fileStatus{width:18px;height:18px;font-weight:700;font-size:var(--gs-t-meta);border-radius:5px;flex:none;justify-content:center;align-items:center;line-height:1;display:inline-flex}.SD8qLW_stAdded,.SD8qLW_stUntracked{color:var(--gs-add);background:var(--gs-add-bg)}.SD8qLW_stDeleted{color:var(--gs-del);background:var(--gs-del-bg)}.SD8qLW_stModified{color:var(--gs-warn);background:var(--gs-warn-bg)}.SD8qLW_stRenamed{color:var(--gs-info);background:var(--gs-info-bg)}.SD8qLW_filePath{white-space:nowrap;text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.SD8qLW_fileBinary{background:var(--gs-neutral-bg);color:var(--gs-fg-dim);letter-spacing:.06em;border-radius:4px;flex:none;padding:0 5px;font-size:9px;font-weight:700}.SD8qLW_fileCounts{font-size:var(--gs-t-meta);font-variant-numeric:tabular-nums;flex:none}.SD8qLW_fileCountAdd{color:var(--gs-add)}.SD8qLW_fileCountDel{color:var(--gs-del)}.SD8qLW_diffPane{min-width:var(--gs-min-diff);background:var(--gs-surface);flex:1 1 0;overflow:auto}.SD8qLW_diffPre{width:max-content;min-width:100%;font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;font-size:var(--gs-t-dense);font-variant-ligatures:none;font-feature-settings:\"liga\" 0, \"calt\" 0;tab-size:4;flex-direction:column;margin:0;padding:8px 0 16px;font-weight:400;line-height:20px;display:flex}.SD8qLW_renameLine{border-bottom:1px solid var(--gs-border-soft);color:var(--gs-info);font-size:var(--gs-t-dense);padding:8px 16px}.SD8qLW_renameLine code{color:var(--gs-fg)}.SD8qLW_line{white-space:nowrap;align-items:stretch;width:max-content;min-width:100%;min-height:20px;line-height:20px;display:flex}.SD8qLW_lnOld,.SD8qLW_lnNew{box-sizing:border-box;text-align:right;width:3.2em;color:var(--gs-fg-fainter);user-select:none;font-variant-numeric:tabular-nums;flex:none;padding:0 8px}.SD8qLW_line:hover .SD8qLW_lnOld,.SD8qLW_line:hover .SD8qLW_lnNew{color:var(--gs-fg-dim)}.SD8qLW_gutter{text-align:center;user-select:none;flex:none;width:1.4em}.SD8qLW_code{white-space:pre;flex:1 0 auto;padding:0 16px 0 10px}.SD8qLW_lineAdd{background:var(--gs-add-line)}.SD8qLW_lineDel{background:var(--gs-del-line)}.SD8qLW_lineAdd .SD8qLW_lnOld,.SD8qLW_lineAdd .SD8qLW_lnNew,.SD8qLW_lineAdd .SD8qLW_gutter{background:var(--gs-add-num,var(--gs-add-line))}.SD8qLW_lineDel .SD8qLW_lnOld,.SD8qLW_lineDel .SD8qLW_lnNew,.SD8qLW_lineDel .SD8qLW_gutter{background:var(--gs-del-num,var(--gs-del-line))}.SD8qLW_lineContext{color:var(--gs-fg-muted)}.SD8qLW_lineHunk{background:var(--gs-hunk)}.SD8qLW_lineHunk .SD8qLW_code{color:var(--gs-fg-dim)}.SD8qLW_lineHunk .SD8qLW_lnOld,.SD8qLW_lineHunk .SD8qLW_lnNew,.SD8qLW_lineHunk .SD8qLW_gutter{background:var(--gs-hunk-num,var(--gs-hunk))}.SD8qLW_signAdd{color:var(--gs-add)}.SD8qLW_signDel{color:var(--gs-del)}.SD8qLW_wordAdd{background:var(--gs-add-word);border-radius:2px}.SD8qLW_wordDel{background:var(--gs-del-word);border-radius:2px}.SD8qLW_empty{color:var(--gs-fg-faint);font-size:var(--gs-t-ui);padding:32px 24px}.SD8qLW_syncBar{padding:8px var(--gs-gutter);border-bottom:1px solid var(--gs-border-soft);background:var(--gs-surface-2);font-size:var(--gs-t-dense);color:var(--gs-fg-dim);flex-wrap:wrap;flex:none;align-items:center;gap:8px;display:flex}.SD8qLW_syncUpstream{white-space:nowrap;text-overflow:ellipsis;max-width:260px;color:var(--gs-fg-muted);font-variant-numeric:tabular-nums;overflow:hidden}.SD8qLW_syncLevel{color:var(--gs-fg-faint)}.SD8qLW_syncSpacer{flex:auto}.SD8qLW_btn:disabled,.SD8qLW_treeIcon:disabled,.SD8qLW_miniBtn:disabled,.SD8qLW_refButton:disabled,.SD8qLW_funnelButton:disabled{opacity:.45;cursor:default}.SD8qLW_btn[data-quiet]:disabled,.SD8qLW_refButton[data-quiet]:disabled{opacity:1}.SD8qLW_opBanner{padding:8px var(--gs-gutter);border-bottom:1px solid var(--gs-border-soft);font-size:var(--gs-t-dense);white-space:pre-wrap;overflow-wrap:anywhere;user-select:text;flex:none;line-height:18px}.SD8qLW_opBannerOk{background:var(--gs-add-bg);color:var(--gs-add)}.SD8qLW_opBannerBad{background:var(--gs-del-bg);color:var(--gs-del)}.SD8qLW_fileLi{align-items:stretch;display:flex}.SD8qLW_fileLi .SD8qLW_file{flex:auto;min-width:0}.SD8qLW_fileDiscard{width:22px;color:var(--gs-fg-faint);opacity:0;cursor:pointer;background:0 0;border:0;flex:none;justify-content:center;align-items:center;padding:0;transition:opacity .12s,color .12s;display:flex}.SD8qLW_fileLi:hover .SD8qLW_fileDiscard,.SD8qLW_fileDiscard:focus-visible{opacity:1}.SD8qLW_fileDiscard:hover{color:var(--gs-del)}.SD8qLW_fileDiscard:focus-visible{outline:2px solid var(--gs-accent);outline-offset:-2px;border-radius:var(--gs-r-control)}.SD8qLW_treeRow{align-items:stretch;display:flex}.SD8qLW_treeRow .SD8qLW_treeDir{flex:auto;min-width:0}.SD8qLW_checkBox{cursor:pointer;background:0 0;border:0;flex:none;justify-content:center;align-items:center;width:22px;padding:0;display:flex}.SD8qLW_checkMark{box-sizing:border-box;border:1px solid var(--gs-fg-faint);background:var(--gs-bg);color:#0000;border-radius:3px;justify-content:center;align-items:center;width:14px;height:14px;font-size:10px;font-weight:700;line-height:1;transition:background .12s,border-color .12s;display:flex}.SD8qLW_checkBox:hover .SD8qLW_checkMark{border-color:var(--gs-accent)}.SD8qLW_checkBox:focus-visible{outline:none}.SD8qLW_checkBox:focus-visible .SD8qLW_checkMark{outline:2px solid var(--gs-accent);outline-offset:1px}.SD8qLW_checkMarkOn,.SD8qLW_checkMarkPartial{border-color:var(--gs-accent);background:var(--gs-accent);color:var(--gs-on-accent)}.SD8qLW_commitBox{padding:8px var(--gs-gutter-pane) 10px;border-top:1px solid var(--gs-border);background:var(--gs-surface-2);flex-direction:column;flex:none;gap:6px;display:flex}.SD8qLW_commitMessage{box-sizing:border-box;border:1px solid var(--gs-border);border-radius:var(--gs-r-control);background:var(--gs-bg);width:100%;min-height:46px;max-height:160px;color:var(--gs-fg);font-family:inherit;font-size:var(--gs-t-dense);resize:vertical;outline:none;padding:6px 8px;line-height:18px}.SD8qLW_commitMessage:focus{border-color:var(--gs-accent-border)}.SD8qLW_commitMessage::placeholder{color:var(--gs-fg-faint)}.SD8qLW_commitRow{align-items:center;gap:8px;display:flex}.SD8qLW_commitAmend{color:var(--gs-fg-dim);font-size:var(--gs-t-meta);cursor:pointer;align-items:center;gap:4px;display:inline-flex}.SD8qLW_commitAmend input{accent-color:var(--gs-accent);cursor:pointer}.SD8qLW_commitStaged{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);margin-left:auto}.SD8qLW_commitLead{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);margin:0;line-height:15px}.SD8qLW_commitBtn{box-sizing:border-box;min-width:92px;height:var(--gs-h-control);border-radius:var(--gs-r-control);background:var(--gs-accent);color:var(--gs-on-accent);font-family:inherit;font-size:var(--gs-t-ui);white-space:nowrap;cursor:pointer;border:1px solid #0000;flex:none;justify-content:center;align-items:center;padding:0 16px;font-weight:600;line-height:1;transition:filter .12s,opacity .12s;display:inline-flex}.SD8qLW_commitBtn:hover:not(:disabled){filter:brightness(1.1)}.SD8qLW_commitBtn:focus-visible{outline:2px solid var(--gs-accent);outline-offset:2px}.SD8qLW_commitBtn:disabled{background:var(--gs-raise);color:var(--gs-fg-faint);border-color:var(--gs-border);cursor:default}.SD8qLW_btn,.SD8qLW_miniBtn,.SD8qLW_treeIcon,.SD8qLW_commitCopy,.SD8qLW_scopeBtn,.SD8qLW_refButton,.SD8qLW_funnelButton,.SD8qLW_funnelPreset{box-sizing:border-box;height:var(--gs-h-control);padding:var(--gs-pad-control);border:1px solid var(--gs-border);border-radius:var(--gs-r-control);color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-ui);white-space:nowrap;cursor:pointer;background:0 0;flex:none;justify-content:center;align-items:center;gap:6px;line-height:1;transition:background .12s,color .12s,border-color .12s;display:inline-flex}.SD8qLW_btn:hover,.SD8qLW_miniBtn:hover,.SD8qLW_treeIcon:hover,.SD8qLW_commitCopy:hover,.SD8qLW_scopeBtn:hover,.SD8qLW_refButton:hover,.SD8qLW_funnelButton:hover,.SD8qLW_funnelPreset:hover{background:var(--gs-raise);color:var(--gs-fg);border-color:var(--gs-fg-fainter)}.SD8qLW_btn:focus-visible,.SD8qLW_miniBtn:focus-visible,.SD8qLW_treeIcon:focus-visible,.SD8qLW_commitCopy:focus-visible,.SD8qLW_scopeBtn:focus-visible,.SD8qLW_refButton:focus-visible,.SD8qLW_funnelPreset:focus-visible{outline:2px solid var(--gs-accent);outline-offset:1px}.SD8qLW_btn,.SD8qLW_refButton{border-radius:var(--gs-r-pill)}.SD8qLW_treeIcon,.SD8qLW_commitCopy,.SD8qLW_funnelPreset{height:var(--gs-h-compact);padding:var(--gs-pad-compact);font-size:var(--gs-t-dense)}.SD8qLW_treeIcon{width:var(--gs-h-compact);padding:0}.SD8qLW_treeIcon.SD8qLW_treeIconOn{color:var(--gs-accent);border-color:var(--gs-accent)}.SD8qLW_treeIconGlyph{font-size:var(--gs-t-meta);line-height:1;display:block}.SD8qLW_treeIconDown{transform:rotate(90deg)}.SD8qLW_scopeBtn{flex:1 1 0}.SD8qLW_scopeBtnActive,.SD8qLW_miniBtnPrimary,.SD8qLW_segmentActive,.SD8qLW_refRowActive,.SD8qLW_paletteRowActive{border-color:var(--gs-accent-border);background:var(--gs-accent-bg);color:var(--gs-accent);font-weight:600}.SD8qLW_btnIcon{width:var(--gs-h-control);padding:0}.SD8qLW_btnIcon svg{display:block}.SD8qLW_btnClose:hover:not(:disabled){border-color:var(--gs-del);background:var(--gs-del-bg);color:var(--gs-del)}.SD8qLW_btnBehind{border-color:var(--gs-warn);background:var(--gs-warn-bg);color:var(--gs-warn);font-weight:600}.SD8qLW_btnBehind:hover:not(:disabled){background:var(--gs-warn-bg);color:var(--gs-warn);border-color:var(--gs-warn)}.SD8qLW_btnAhead{border-color:var(--gs-add);background:var(--gs-add-bg);color:var(--gs-add);font-weight:600}.SD8qLW_btnAhead:hover:not(:disabled){background:var(--gs-add-bg);color:var(--gs-add);border-color:var(--gs-add)}.SD8qLW_btnPrimary{border-color:var(--gs-accent);background:var(--gs-accent);color:var(--gs-on-accent,#fff);font-weight:600}.SD8qLW_btnPrimary:hover:not(:disabled){background:var(--gs-accent);color:var(--gs-on-accent,#fff);border-color:var(--gs-accent)}.SD8qLW_btnCount{font-variant-numeric:tabular-nums;opacity:.85;border-left:1px solid;margin-left:1px;padding-left:6px}.SD8qLW_pullGroup{flex:none;align-items:center;display:inline-flex}.SD8qLW_pullGroup>.SD8qLW_refPicker>.SD8qLW_refButton{border-right-color:#0000;border-top-right-radius:0;border-bottom-right-radius:0}.SD8qLW_pullGroup>.SD8qLW_btn{border-top-left-radius:0;border-bottom-left-radius:0;margin-left:-1px}.SD8qLW_drawer{scrollbar-width:thin;scrollbar-color:var(--gs-border) transparent}.SD8qLW_drawer ::-webkit-scrollbar{width:10px;height:10px}.SD8qLW_drawer ::-webkit-scrollbar-track,.SD8qLW_drawer ::-webkit-scrollbar-corner{background:0 0}.SD8qLW_drawer ::-webkit-scrollbar-thumb{background:var(--gs-border);background-clip:padding-box;border:3px solid #0000;border-radius:999px}.SD8qLW_drawer ::-webkit-scrollbar-thumb:hover{background:var(--gs-fg-faint);background-clip:padding-box}.SD8qLW_commitRefMore{border-radius:var(--gs-r-pill);background:var(--gs-neutral-bg);color:var(--gs-fg-dim);font-size:var(--gs-t-meta);cursor:default;flex:none;padding:0 5px;line-height:15px}.SD8qLW_confirmScrim{background:var(--gs-backdrop);justify-content:center;align-items:center;padding:24px;animation:.12s ease-out SD8qLW_gsFade;display:flex}.SD8qLW_confirmBox{box-sizing:border-box;border:1px solid var(--gs-border);border-radius:var(--gs-r-drawer);background:var(--gs-bg);width:min(440px,100%);box-shadow:0 18px 48px var(--gs-shadow);flex-direction:column;gap:10px;padding:18px;display:flex}.SD8qLW_confirmTitle{color:var(--gs-fg);font-size:var(--gs-t-ui);font-weight:600}.SD8qLW_confirmBody{color:var(--gs-fg-dim);font-size:var(--gs-t-dense);overflow-wrap:anywhere;line-height:1.55}.SD8qLW_confirmActions{flex-direction:row-reverse;gap:8px;margin-top:2px;display:flex}.SD8qLW_btn.SD8qLW_btnDanger{border-color:var(--gs-del);background:var(--gs-del);color:var(--gs-on-accent,#fff);font-weight:600}.SD8qLW_btn.SD8qLW_btnDanger:hover:not(:disabled){border-color:var(--gs-del);background:var(--gs-del);color:var(--gs-on-accent,#fff)}";
11617
12208
  const tagId = "@young1lin/dsh-ui-gitworkbench/GitWorkbenchPanel.module.css";
11618
12209
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
11619
12210
  const tag = document.createElement("style");
@@ -11623,196 +12214,262 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
11623
12214
  document.head.appendChild(tag);
11624
12215
  }
11625
12216
  var GitWorkbenchPanel_module_css_default = {
11626
- "paneHead": "SD8qLW_paneHead",
11627
- "commitSubject": "SD8qLW_commitSubject",
11628
- "treeDirCount": "SD8qLW_treeDirCount",
11629
- "elideTail": "SD8qLW_elideTail",
11630
- "opBannerBad": "SD8qLW_opBannerBad",
11631
- "treeIconGlyph": "SD8qLW_treeIconGlyph",
11632
- "segmentActive": "SD8qLW_segmentActive",
11633
- "headerViewRef": "SD8qLW_headerViewRef",
11634
- "themeGroup": "SD8qLW_themeGroup",
11635
- "refGroup": "SD8qLW_refGroup",
11636
- "bgPreview": "SD8qLW_bgPreview",
11637
- "themeLabel": "SD8qLW_themeLabel",
11638
- "refList": "SD8qLW_refList",
11639
- "gutter": "SD8qLW_gutter",
11640
- "headerLeft": "SD8qLW_headerLeft",
11641
- "lineDel": "SD8qLW_lineDel",
11642
- "checkBox": "SD8qLW_checkBox",
11643
- "btnPrimary": "SD8qLW_btnPrimary",
11644
- "refCaret": "SD8qLW_refCaret",
11645
- "lineAdd": "SD8qLW_lineAdd",
12217
+ "syncSpacer": "SD8qLW_syncSpacer",
12218
+ "treeDirActive": "SD8qLW_treeDirActive",
12219
+ "commits": "SD8qLW_commits",
12220
+ "btnAhead": "SD8qLW_btnAhead",
12221
+ "commitTop": "SD8qLW_commitTop",
12222
+ "commitPopSubject": "SD8qLW_commitPopSubject",
12223
+ "segment": "SD8qLW_segment",
12224
+ "funnelChevron": "SD8qLW_funnelChevron",
12225
+ "resizerActive": "SD8qLW_resizerActive",
12226
+ "segmented": "SD8qLW_segmented",
12227
+ "commitMessage": "SD8qLW_commitMessage",
12228
+ "signDel": "SD8qLW_signDel",
11646
12229
  "themeRail": "SD8qLW_themeRail",
11647
- "headerTotals": "SD8qLW_headerTotals",
11648
- "btn": "SD8qLW_btn",
11649
- "btnCount": "SD8qLW_btnCount",
11650
- "compareArrow": "SD8qLW_compareArrow",
11651
- "headerTotalsDel": "SD8qLW_headerTotalsDel",
11652
- "overlay": "SD8qLW_overlay",
11653
- "empty": "SD8qLW_empty",
11654
- "commitRow": "SD8qLW_commitRow",
11655
12230
  "cardAdded": "SD8qLW_cardAdded",
11656
- "headerBranch": "SD8qLW_headerBranch",
11657
- "treeIcon": "SD8qLW_treeIcon",
11658
- "scopeBtnActive": "SD8qLW_scopeBtnActive",
11659
- "treeDirLi": "SD8qLW_treeDirLi",
12231
+ "refEmpty": "SD8qLW_refEmpty",
12232
+ "file": "SD8qLW_file",
11660
12233
  "elide": "SD8qLW_elide",
11661
- "settingsPop": "SD8qLW_settingsPop",
11662
- "opBannerOk": "SD8qLW_opBannerOk",
11663
- "fileActive": "SD8qLW_fileActive",
11664
- "cardGlyph": "SD8qLW_cardGlyph",
11665
- "fileCountAdd": "SD8qLW_fileCountAdd",
11666
- "syncUpstream": "SD8qLW_syncUpstream",
11667
- "commit": "SD8qLW_commit",
11668
- "treeActions": "SD8qLW_treeActions",
12234
+ "sliderValue": "SD8qLW_sliderValue",
12235
+ "fileBinary": "SD8qLW_fileBinary",
12236
+ "wtCurrent": "SD8qLW_wtCurrent",
12237
+ "funnelBoundBtnActive": "SD8qLW_funnelBoundBtnActive",
12238
+ "wordDel": "SD8qLW_wordDel",
12239
+ "themeRowSplit": "SD8qLW_themeRowSplit",
12240
+ "funnelBounds": "SD8qLW_funnelBounds",
12241
+ "graphCell": "SD8qLW_graphCell",
12242
+ "treeIcon": "SD8qLW_treeIcon",
12243
+ "scopeHint": "SD8qLW_scopeHint",
12244
+ "paletteRow": "SD8qLW_paletteRow",
11669
12245
  "btnBehind": "SD8qLW_btnBehind",
11670
- "refRow": "SD8qLW_refRow",
12246
+ "stAdded": "SD8qLW_stAdded",
12247
+ "line": "SD8qLW_line",
12248
+ "gutter": "SD8qLW_gutter",
12249
+ "funnelPreset": "SD8qLW_funnelPreset",
12250
+ "treeFilterClear": "SD8qLW_treeFilterClear",
12251
+ "funnelBoundKey": "SD8qLW_funnelBoundKey",
12252
+ "commitActive": "SD8qLW_commitActive",
12253
+ "code": "SD8qLW_code",
12254
+ "commitFilter": "SD8qLW_commitFilter",
12255
+ "funnelPop": "SD8qLW_funnelPop",
12256
+ "treeRow": "SD8qLW_treeRow",
12257
+ "funnelList": "SD8qLW_funnelList",
12258
+ "chevronOpen": "SD8qLW_chevronOpen",
12259
+ "segmentChip": "SD8qLW_segmentChip",
12260
+ "refLabel": "SD8qLW_refLabel",
12261
+ "calNav": "SD8qLW_calNav",
12262
+ "refFoot": "SD8qLW_refFoot",
11671
12263
  "miniBtn": "SD8qLW_miniBtn",
11672
- "commitBox": "SD8qLW_commitBox",
11673
- "tabActive": "SD8qLW_tabActive",
11674
- "card": "SD8qLW_card",
11675
- "menuPop": "SD8qLW_menuPop",
11676
- "drawer": "SD8qLW_drawer",
11677
- "treeCol": "SD8qLW_treeCol",
11678
- "treeIconDown": "SD8qLW_treeIconDown",
11679
- "segmented": "SD8qLW_segmented",
11680
- "commitPopSubject": "SD8qLW_commitPopSubject",
11681
- "lnNew": "SD8qLW_lnNew",
11682
- "chevronOpen": "SD8qLW_chevronOpen",
11683
- "stUntracked": "SD8qLW_stUntracked",
11684
- "commitPopBody": "SD8qLW_commitPopBody",
11685
- "signDel": "SD8qLW_signDel",
11686
- "swatch": "SD8qLW_swatch",
12264
+ "commitAmend": "SD8qLW_commitAmend",
12265
+ "treeDirCounts": "SD8qLW_treeDirCounts",
12266
+ "chevron": "SD8qLW_chevron",
12267
+ "headerPicker": "SD8qLW_headerPicker",
12268
+ "overlay": "SD8qLW_overlay",
12269
+ "syncBar": "SD8qLW_syncBar",
12270
+ "funnelPresetActive": "SD8qLW_funnelPresetActive",
12271
+ "refValue": "SD8qLW_refValue",
12272
+ "refList": "SD8qLW_refList",
12273
+ "funnelBoundRows": "SD8qLW_funnelBoundRows",
12274
+ "funnelPresets": "SD8qLW_funnelPresets",
12275
+ "funnelTabActive": "SD8qLW_funnelTabActive",
12276
+ "headerPathMain": "SD8qLW_headerPathMain",
12277
+ "treeLabel": "SD8qLW_treeLabel",
12278
+ "bgEmpty": "SD8qLW_bgEmpty",
12279
+ "themeNote": "SD8qLW_themeNote",
12280
+ "treeFilter": "SD8qLW_treeFilter",
12281
+ "treeDirCount": "SD8qLW_treeDirCount",
12282
+ "stModified": "SD8qLW_stModified",
12283
+ "cardFiles": "SD8qLW_cardFiles",
12284
+ "funnelButtonActive": "SD8qLW_funnelButtonActive",
12285
+ "calWeek": "SD8qLW_calWeek",
12286
+ "tabs": "SD8qLW_tabs",
12287
+ "funnelFootCount": "SD8qLW_funnelFootCount",
12288
+ "fileActive": "SD8qLW_fileActive",
12289
+ "gsFade": "SD8qLW_gsFade",
12290
+ "calIn": "SD8qLW_calIn",
12291
+ "filePath": "SD8qLW_filePath",
12292
+ "funnelBoundVal": "SD8qLW_funnelBoundVal",
12293
+ "refRow": "SD8qLW_refRow",
12294
+ "commitBox": "SD8qLW_commitBox",
12295
+ "calMark": "SD8qLW_calMark",
12296
+ "treeFilterInput": "SD8qLW_treeFilterInput",
12297
+ "commit": "SD8qLW_commit",
12298
+ "btnDanger": "SD8qLW_btnDanger",
12299
+ "commitHasBody": "SD8qLW_commitHasBody",
12300
+ "confirmBox": "SD8qLW_confirmBox",
11687
12301
  "commitsFoot": "SD8qLW_commitsFoot",
12302
+ "settingsPop": "SD8qLW_settingsPop",
12303
+ "checkBox": "SD8qLW_checkBox",
12304
+ "diffPre": "SD8qLW_diffPre",
12305
+ "headerView": "SD8qLW_headerView",
12306
+ "commitAuthor": "SD8qLW_commitAuthor",
12307
+ "filterClear": "SD8qLW_filterClear",
12308
+ "treeTools": "SD8qLW_treeTools",
12309
+ "scopeBtnActive": "SD8qLW_scopeBtnActive",
12310
+ "chipLight": "SD8qLW_chipLight",
12311
+ "fileCounts": "SD8qLW_fileCounts",
12312
+ "refPop": "SD8qLW_refPop",
12313
+ "themeGroup": "SD8qLW_themeGroup",
12314
+ "funnelTabCount": "SD8qLW_funnelTabCount",
12315
+ "cardBranchName": "SD8qLW_cardBranchName",
12316
+ "card": "SD8qLW_card",
12317
+ "commitWhen": "SD8qLW_commitWhen",
12318
+ "cal": "SD8qLW_cal",
12319
+ "calOut": "SD8qLW_calOut",
12320
+ "refRowName": "SD8qLW_refRowName",
12321
+ "diffPane": "SD8qLW_diffPane",
12322
+ "headerDetached": "SD8qLW_headerDetached",
12323
+ "drawer": "SD8qLW_drawer",
12324
+ "refRowSpacer": "SD8qLW_refRowSpacer",
12325
+ "calTitle": "SD8qLW_calTitle",
11688
12326
  "wordAdd": "SD8qLW_wordAdd",
11689
- "lnOld": "SD8qLW_lnOld",
11690
- "cardBranch": "SD8qLW_cardBranch",
12327
+ "cardDetached": "SD8qLW_cardDetached",
12328
+ "funnelTabs": "SD8qLW_funnelTabs",
12329
+ "funnelFoot": "SD8qLW_funnelFoot",
12330
+ "cssArea": "SD8qLW_cssArea",
12331
+ "gsSlide": "SD8qLW_gsSlide",
12332
+ "elideTail": "SD8qLW_elideTail",
12333
+ "treeCol": "SD8qLW_treeCol",
12334
+ "fileCountAdd": "SD8qLW_fileCountAdd",
12335
+ "stDeleted": "SD8qLW_stDeleted",
12336
+ "commitRow": "SD8qLW_commitRow",
12337
+ "stUntracked": "SD8qLW_stUntracked",
12338
+ "treeSub": "SD8qLW_treeSub",
12339
+ "stRenamed": "SD8qLW_stRenamed",
12340
+ "syncLevel": "SD8qLW_syncLevel",
11691
12341
  "elideHead": "SD8qLW_elideHead",
11692
- "commitWhen": "SD8qLW_commitWhen",
11693
- "miniBtnPrimary": "SD8qLW_miniBtnPrimary",
11694
- "lineHunk": "SD8qLW_lineHunk",
11695
- "cardDeleted": "SD8qLW_cardDeleted",
11696
- "headerView": "SD8qLW_headerView",
12342
+ "compareArrow": "SD8qLW_compareArrow",
12343
+ "chipDark": "SD8qLW_chipDark",
12344
+ "cardWt": "SD8qLW_cardWt",
12345
+ "funnelBoundClear": "SD8qLW_funnelBoundClear",
12346
+ "headerTotalsDim": "SD8qLW_headerTotalsDim",
12347
+ "confirmScrim": "SD8qLW_confirmScrim",
12348
+ "funnelPane": "SD8qLW_funnelPane",
12349
+ "tree": "SD8qLW_tree",
12350
+ "treeIconGlyph": "SD8qLW_treeIconGlyph",
12351
+ "btnCount": "SD8qLW_btnCount",
12352
+ "commitHash": "SD8qLW_commitHash",
12353
+ "headerViewRef": "SD8qLW_headerViewRef",
12354
+ "funnelBoundValSet": "SD8qLW_funnelBoundValSet",
12355
+ "confirmBody": "SD8qLW_confirmBody",
12356
+ "empty": "SD8qLW_empty",
12357
+ "btnPrimary": "SD8qLW_btnPrimary",
12358
+ "fileDiscard": "SD8qLW_fileDiscard",
12359
+ "pathChildren": "SD8qLW_pathChildren",
12360
+ "opBannerOk": "SD8qLW_opBannerOk",
12361
+ "confirmTitle": "SD8qLW_confirmTitle",
12362
+ "funnelCount": "SD8qLW_funnelCount",
12363
+ "cardBranch": "SD8qLW_cardBranch",
12364
+ "segmentActive": "SD8qLW_segmentActive",
12365
+ "lineContext": "SD8qLW_lineContext",
11697
12366
  "treeDirName": "SD8qLW_treeDirName",
11698
- "resizer": "SD8qLW_resizer",
11699
12367
  "commitPop": "SD8qLW_commitPop",
11700
- "fileStatus": "SD8qLW_fileStatus",
11701
- "chipDark": "SD8qLW_chipDark",
11702
- "compareBar": "SD8qLW_compareBar",
11703
- "stAdded": "SD8qLW_stAdded",
11704
- "stDeleted": "SD8qLW_stDeleted",
11705
- "commitMessage": "SD8qLW_commitMessage",
11706
- "commits": "SD8qLW_commits",
11707
- "scopeRow": "SD8qLW_scopeRow",
11708
- "stRenamed": "SD8qLW_stRenamed",
11709
- "btnClose": "SD8qLW_btnClose",
11710
- "paletteRow": "SD8qLW_paletteRow",
11711
- "commitLine": "SD8qLW_commitLine",
11712
- "headerTotalsAdd": "SD8qLW_headerTotalsAdd",
11713
- "resizerActive": "SD8qLW_resizerActive",
11714
- "themeDirty": "SD8qLW_themeDirty",
12368
+ "filterChipLabel": "SD8qLW_filterChipLabel",
12369
+ "commitPopBody": "SD8qLW_commitPopBody",
12370
+ "refRowActive": "SD8qLW_refRowActive",
12371
+ "headerLeft": "SD8qLW_headerLeft",
12372
+ "headerTotals": "SD8qLW_headerTotals",
12373
+ "resizer": "SD8qLW_resizer",
12374
+ "funnel": "SD8qLW_funnel",
12375
+ "funnelBoundRow": "SD8qLW_funnelBoundRow",
12376
+ "refGroup": "SD8qLW_refGroup",
12377
+ "opBanner": "SD8qLW_opBanner",
12378
+ "miniBtnPrimary": "SD8qLW_miniBtnPrimary",
12379
+ "btnIcon": "SD8qLW_btnIcon",
12380
+ "funnelButton": "SD8qLW_funnelButton",
12381
+ "funnelSearch": "SD8qLW_funnelSearch",
11715
12382
  "refSearch": "SD8qLW_refSearch",
11716
- "fileCountDel": "SD8qLW_fileCountDel",
12383
+ "commitsPane": "SD8qLW_commitsPane",
12384
+ "lnOld": "SD8qLW_lnOld",
12385
+ "treeIconOn": "SD8qLW_treeIconOn",
12386
+ "headerBranch": "SD8qLW_headerBranch",
12387
+ "swatch": "SD8qLW_swatch",
12388
+ "funnelTab": "SD8qLW_funnelTab",
12389
+ "syncUpstream": "SD8qLW_syncUpstream",
12390
+ "commitLead": "SD8qLW_commitLead",
12391
+ "pullGroup": "SD8qLW_pullGroup",
12392
+ "lineAdd": "SD8qLW_lineAdd",
12393
+ "treeIconDown": "SD8qLW_treeIconDown",
12394
+ "checkMark": "SD8qLW_checkMark",
11717
12395
  "commitStaged": "SD8qLW_commitStaged",
11718
- "treeLabel": "SD8qLW_treeLabel",
11719
- "sliderRow": "SD8qLW_sliderRow",
11720
- "code": "SD8qLW_code",
11721
- "gsFade": "SD8qLW_gsFade",
11722
- "tabs": "SD8qLW_tabs",
11723
- "treeRow": "SD8qLW_treeRow",
11724
- "refValue": "SD8qLW_refValue",
11725
- "chipLight": "SD8qLW_chipLight",
11726
- "commitActive": "SD8qLW_commitActive",
11727
- "commitSubjectRow": "SD8qLW_commitSubjectRow",
12396
+ "lineHunk": "SD8qLW_lineHunk",
11728
12397
  "treeWrap": "SD8qLW_treeWrap",
11729
- "checkMark": "SD8qLW_checkMark",
11730
- "btnIcon": "SD8qLW_btnIcon",
11731
- "btnAhead": "SD8qLW_btnAhead",
11732
- "segmentChip": "SD8qLW_segmentChip",
11733
- "commitHash": "SD8qLW_commitHash",
11734
- "themeRowSplit": "SD8qLW_themeRowSplit",
11735
- "cardAhead": "SD8qLW_cardAhead",
11736
- "treeTools": "SD8qLW_treeTools",
11737
- "cardBehind": "SD8qLW_cardBehind",
11738
- "paneDividerActive": "SD8qLW_paneDividerActive",
11739
- "refRowName": "SD8qLW_refRowName",
11740
- "commitTop": "SD8qLW_commitTop",
11741
- "refLabel": "SD8qLW_refLabel",
11742
- "treeDirCounts": "SD8qLW_treeDirCounts",
11743
- "checkMarkPartial": "SD8qLW_checkMarkPartial",
11744
- "pullGroup": "SD8qLW_pullGroup",
11745
- "cssArea": "SD8qLW_cssArea",
11746
- "treeLead": "SD8qLW_treeLead",
11747
- "headerTotalsDim": "SD8qLW_headerTotalsDim",
11748
- "commitCopy": "SD8qLW_commitCopy",
12398
+ "overlayMax": "SD8qLW_overlayMax",
12399
+ "menuPop": "SD8qLW_menuPop",
12400
+ "tabActive": "SD8qLW_tabActive",
12401
+ "btn": "SD8qLW_btn",
12402
+ "headerTotalsDel": "SD8qLW_headerTotalsDel",
12403
+ "lnNew": "SD8qLW_lnNew",
12404
+ "paneTitle": "SD8qLW_paneTitle",
12405
+ "refCaret": "SD8qLW_refCaret",
11749
12406
  "renameLine": "SD8qLW_renameLine",
11750
- "header": "SD8qLW_header",
12407
+ "scopeRow": "SD8qLW_scopeRow",
11751
12408
  "paneDivider": "SD8qLW_paneDivider",
11752
- "body": "SD8qLW_body",
11753
- "headerPathMain": "SD8qLW_headerPathMain",
11754
- "treeDirActive": "SD8qLW_treeDirActive",
11755
- "cardFiles": "SD8qLW_cardFiles",
11756
- "tree": "SD8qLW_tree",
11757
- "syncSpacer": "SD8qLW_syncSpacer",
11758
- "refPicker": "SD8qLW_refPicker",
12409
+ "refButton": "SD8qLW_refButton",
12410
+ "cardDeleted": "SD8qLW_cardDeleted",
12411
+ "headerRight": "SD8qLW_headerRight",
11759
12412
  "paletteRowActive": "SD8qLW_paletteRowActive",
11760
- "fileLi": "SD8qLW_fileLi",
11761
- "refFoot": "SD8qLW_refFoot",
11762
- "lineContext": "SD8qLW_lineContext",
11763
- "headerDetached": "SD8qLW_headerDetached",
11764
- "commitBtn": "SD8qLW_commitBtn",
11765
- "stModified": "SD8qLW_stModified",
11766
- "paneTitle": "SD8qLW_paneTitle",
12413
+ "checkMarkPartial": "SD8qLW_checkMarkPartial",
11767
12414
  "scopeBtn": "SD8qLW_scopeBtn",
11768
- "sliderValue": "SD8qLW_sliderValue",
11769
- "line": "SD8qLW_line",
11770
- "commitAmend": "SD8qLW_commitAmend",
11771
- "cardWt": "SD8qLW_cardWt",
11772
- "cardSep": "SD8qLW_cardSep",
11773
- "commitsSentinel": "SD8qLW_commitsSentinel",
11774
- "gsSlide": "SD8qLW_gsSlide",
11775
- "refRowSpacer": "SD8qLW_refRowSpacer",
11776
- "overlayMax": "SD8qLW_overlayMax",
11777
- "filePath": "SD8qLW_filePath",
11778
- "diffPane": "SD8qLW_diffPane",
11779
- "syncLevel": "SD8qLW_syncLevel",
11780
- "syncBar": "SD8qLW_syncBar",
11781
- "refPop": "SD8qLW_refPop",
11782
- "segment": "SD8qLW_segment",
11783
- "theme": "SD8qLW_theme",
11784
- "chipSystem": "SD8qLW_chipSystem",
11785
- "wtCurrent": "SD8qLW_wtCurrent",
11786
- "commitRef": "SD8qLW_commitRef",
11787
- "scopeHint": "SD8qLW_scopeHint",
11788
- "bgEmpty": "SD8qLW_bgEmpty",
11789
- "cardDetached": "SD8qLW_cardDetached",
11790
- "refEmpty": "SD8qLW_refEmpty",
11791
- "treeEmpty": "SD8qLW_treeEmpty",
11792
- "headerRight": "SD8qLW_headerRight",
11793
- "cardBranchName": "SD8qLW_cardBranchName",
11794
- "fileBinary": "SD8qLW_fileBinary",
11795
- "fileCounts": "SD8qLW_fileCounts",
11796
- "headerPicker": "SD8qLW_headerPicker",
11797
- "signAdd": "SD8qLW_signAdd",
11798
- "commitLead": "SD8qLW_commitLead",
12415
+ "lineDel": "SD8qLW_lineDel",
12416
+ "themeDirty": "SD8qLW_themeDirty",
12417
+ "confirmActions": "SD8qLW_confirmActions",
12418
+ "opBannerBad": "SD8qLW_opBannerBad",
12419
+ "commitCopy": "SD8qLW_commitCopy",
12420
+ "sliderRow": "SD8qLW_sliderRow",
12421
+ "fileLi": "SD8qLW_fileLi",
12422
+ "funnelCaption": "SD8qLW_funnelCaption",
12423
+ "body": "SD8qLW_body",
12424
+ "commitPopMeta": "SD8qLW_commitPopMeta",
11799
12425
  "commitPopTop": "SD8qLW_commitPopTop",
11800
12426
  "tab": "SD8qLW_tab",
11801
- "themeNote": "SD8qLW_themeNote",
11802
- "file": "SD8qLW_file",
11803
- "diffPre": "SD8qLW_diffPre",
11804
- "refButton": "SD8qLW_refButton",
11805
- "opBanner": "SD8qLW_opBanner",
12427
+ "commitSubject": "SD8qLW_commitSubject",
12428
+ "commitsSentinel": "SD8qLW_commitsSentinel",
12429
+ "cardGlyph": "SD8qLW_cardGlyph",
12430
+ "paneDividerActive": "SD8qLW_paneDividerActive",
12431
+ "funnelRow": "SD8qLW_funnelRow",
11806
12432
  "commitRefMore": "SD8qLW_commitRefMore",
11807
- "graphCell": "SD8qLW_graphCell",
12433
+ "themeLabel": "SD8qLW_themeLabel",
12434
+ "commitBtn": "SD8qLW_commitBtn",
12435
+ "refPicker": "SD8qLW_refPicker",
12436
+ "treeLead": "SD8qLW_treeLead",
12437
+ "funnelBoundBtn": "SD8qLW_funnelBoundBtn",
12438
+ "treeDirLi": "SD8qLW_treeDirLi",
12439
+ "fileStatus": "SD8qLW_fileStatus",
12440
+ "btnClose": "SD8qLW_btnClose",
12441
+ "funnelFootCountOn": "SD8qLW_funnelFootCountOn",
12442
+ "paneHead": "SD8qLW_paneHead",
12443
+ "funnelMore": "SD8qLW_funnelMore",
12444
+ "headerTotalsAdd": "SD8qLW_headerTotalsAdd",
12445
+ "fileCountDel": "SD8qLW_fileCountDel",
12446
+ "bgPreview": "SD8qLW_bgPreview",
12447
+ "cardBehind": "SD8qLW_cardBehind",
12448
+ "header": "SD8qLW_header",
12449
+ "compareBar": "SD8qLW_compareBar",
12450
+ "theme": "SD8qLW_theme",
12451
+ "filterChips": "SD8qLW_filterChips",
12452
+ "cardAhead": "SD8qLW_cardAhead",
12453
+ "filterChip": "SD8qLW_filterChip",
12454
+ "commitSubjectRow": "SD8qLW_commitSubjectRow",
12455
+ "pathDirGlyph": "SD8qLW_pathDirGlyph",
11808
12456
  "treeDir": "SD8qLW_treeDir",
12457
+ "commitRef": "SD8qLW_commitRef",
12458
+ "commitLine": "SD8qLW_commitLine",
12459
+ "treeActions": "SD8qLW_treeActions",
12460
+ "cardSep": "SD8qLW_cardSep",
12461
+ "funnelFootClear": "SD8qLW_funnelFootClear",
12462
+ "funnelName": "SD8qLW_funnelName",
12463
+ "chipSystem": "SD8qLW_chipSystem",
12464
+ "treeEmpty": "SD8qLW_treeEmpty",
12465
+ "pathNode": "SD8qLW_pathNode",
11809
12466
  "checkMarkOn": "SD8qLW_checkMarkOn",
11810
- "commitsPane": "SD8qLW_commitsPane",
11811
- "wordDel": "SD8qLW_wordDel",
11812
- "commitHasBody": "SD8qLW_commitHasBody",
11813
- "chevron": "SD8qLW_chevron",
11814
- "treeSub": "SD8qLW_treeSub",
11815
- "refRowActive": "SD8qLW_refRowActive"
12467
+ "pathFileGlyph": "SD8qLW_pathFileGlyph",
12468
+ "calToday": "SD8qLW_calToday",
12469
+ "signAdd": "SD8qLW_signAdd",
12470
+ "filterChipRemove": "SD8qLW_filterChipRemove",
12471
+ "calHead": "SD8qLW_calHead",
12472
+ "calGrid": "SD8qLW_calGrid"
11816
12473
  };
11817
12474
  //#endregion
11818
12475
  //#region src/client/GitWorkbenchPanel.tsx
@@ -12037,7 +12694,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12037
12694
  renamed: GitWorkbenchPanel_module_css_default.stRenamed,
12038
12695
  deleted: GitWorkbenchPanel_module_css_default.stDeleted
12039
12696
  };
12040
- function GitWorkbenchPanel({ sessionId, useSessions, t, fetchStats, fetchFileDiff, fetchWorktreeStatus, fetchSessionBinding, fetchCommitStats, fetchCommits, fetchCompare, fetchStyle, saveStyle, fetchSync, runGitOp }) {
12697
+ function GitWorkbenchPanel({ sessionId, useSessions, t, fetchStats, fetchFileDiff, fetchWorktreeStatus, fetchSessionBinding, fetchCommitStats, fetchCommits, fetchAuthors, fetchRepoTree, fetchCompare, fetchStyle, saveStyle, fetchSync, runGitOp, fetchDiscardPlan }) {
12041
12698
  const worktreePath = useSessions((state) => state?.byId?.[sessionId]?.cwd);
12042
12699
  /** Whether the session's agent has a turn in flight — the store mirrors it
12043
12700
  * live, so it is the signal for polling faster while there is something to
@@ -12082,6 +12739,22 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12082
12739
  /** First page of the history list in flight — the pane says "loading", not
12083
12740
  * "no commit history", which is a claim about the repository. */
12084
12741
  const [historyLoading, setHistoryLoading] = (0, react.useState)(false);
12742
+ /** Why the history list is empty when it is git's word, not the log's: a
12743
+ * bad filter pattern or date, with the stderr tail to say so. */
12744
+ const [historyError, setHistoryError] = (0, react.useState)(null);
12745
+ /** The history filter box's raw text. Parsed into the LogFilter the host
12746
+ * compiles into git log arguments — the funnel popup writes here too: one
12747
+ * grammar, one filter, however the criterion arrived. */
12748
+ const [historyQuery, setHistoryQuery] = (0, react.useState)("");
12749
+ const historyFilterKey = serializeLogQuery(parseLogQuery(historyQuery));
12750
+ /** Debounced by KEY, not by text: "liam " and "liam" are the same query and
12751
+ * must not refetch. 300ms is a keystroke's pause, not a page's wait. */
12752
+ const [liveFilterKey, setLiveFilterKey] = (0, react.useState)("");
12753
+ (0, react.useEffect)(() => {
12754
+ const id = window.setTimeout(() => setLiveFilterKey(historyFilterKey), 300);
12755
+ return () => window.clearTimeout(id);
12756
+ }, [historyFilterKey]);
12757
+ const liveFilter = (0, react.useMemo)(() => liveFilterKey.length === 0 ? emptyQueryFilter() : parseLogQuery(liveFilterKey), [liveFilterKey]);
12085
12758
  const [loadingMore, setLoadingMore] = (0, react.useState)(false);
12086
12759
  /** In-flight marker for paging, read synchronously — see {@link loadMoreCommits}. */
12087
12760
  const loadingRef = (0, react.useRef)(false);
@@ -12409,12 +13082,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12409
13082
  setCommitHash(null);
12410
13083
  setCommitStats(null);
12411
13084
  setHistoryLoading(true);
12412
- fetchCommits(statsPath, effectiveHistoryRef, 0, HISTORY_PAGE, ctrl.signal).then((page) => {
13085
+ setHistoryError(null);
13086
+ fetchCommits(statsPath, effectiveHistoryRef, 0, HISTORY_PAGE, liveFilter, ctrl.signal).then((page) => {
12413
13087
  if (!alive) return;
12414
13088
  setHistoryLoading(false);
12415
13089
  if (page === null) return;
12416
13090
  setHistoryCommits(page.commits);
12417
13091
  setHistoryHasMore(page.hasMore);
13092
+ setHistoryError(page.error ?? null);
12418
13093
  }).catch(() => {
12419
13094
  if (alive) setHistoryLoading(false);
12420
13095
  });
@@ -12427,7 +13102,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12427
13102
  statsPath,
12428
13103
  effectiveHistoryRef,
12429
13104
  fetchCommits,
12430
- gen
13105
+ gen,
13106
+ liveFilter
12431
13107
  ]);
12432
13108
  (0, react.useEffect)(() => {
12433
13109
  if (tab !== "history" || commitHash !== null) return;
@@ -12718,7 +13394,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12718
13394
  loadingRef.current = true;
12719
13395
  setLoadingMore(true);
12720
13396
  const ctrl = new AbortController();
12721
- fetchCommits(statsPath, effectiveHistoryRef, historyCommits.length, HISTORY_PAGE, ctrl.signal).then((page) => {
13397
+ fetchCommits(statsPath, effectiveHistoryRef, historyCommits.length, HISTORY_PAGE, liveFilter, ctrl.signal).then((page) => {
12722
13398
  if (page === null) return;
12723
13399
  setHistoryCommits((prev) => [...prev, ...page.commits]);
12724
13400
  setHistoryHasMore(page.hasMore);
@@ -12760,6 +13436,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12760
13436
  onLoadMoreCommits: loadMoreCommits,
12761
13437
  historyRef: effectiveHistoryRef,
12762
13438
  onHistoryRef: setHistoryRef,
13439
+ historyQuery,
13440
+ onHistoryQuery: setHistoryQuery,
13441
+ historyError,
13442
+ fetchAuthors,
13443
+ fetchRepoTree,
12763
13444
  branches,
12764
13445
  worktreeBranches,
12765
13446
  branchesTruncated,
@@ -12801,6 +13482,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12801
13482
  busy,
12802
13483
  opResult,
12803
13484
  runOp,
13485
+ fetchDiscardPlan,
12804
13486
  pendingTicks,
12805
13487
  onTick: queueTicks,
12806
13488
  fetchFileDiff: fetchDiffForView,
@@ -12923,7 +13605,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12923
13605
  ]
12924
13606
  });
12925
13607
  }
12926
- function Drawer({ stats, shown, tab, onSwitchTab, commits, commitHash, onSelectCommit, hasMoreCommits, loadingMore, onLoadMoreCommits, historyRef, onHistoryRef, branches, worktreeBranches, branchesTruncated, baseRef, headRef, onBaseRef, onHeadRef, comparable, t, binding, worktrees, sessionPath, statsPath, onSwitchSource, segments, selected, onSelect, maximized, onToggleMaximized, theme, mode, family, onMode, onFamily, style, background, onStyle, width, onWidth, panes, onPane, onClose, onRefresh, commitDraft, onCommitDraft, commitAmend, onCommitAmend, sync, treeLoading, historyLoading, busy, opResult, runOp, pendingTicks, onTick, fetchFileDiff, viewKey, gen, collapsed, onCollapsedChange }) {
13608
+ function Drawer({ stats, shown, tab, onSwitchTab, commits, commitHash, onSelectCommit, hasMoreCommits, loadingMore, onLoadMoreCommits, historyRef, onHistoryRef, historyQuery, onHistoryQuery, historyError, fetchAuthors, fetchRepoTree, branches, worktreeBranches, branchesTruncated, baseRef, headRef, onBaseRef, onHeadRef, comparable, t, binding, worktrees, sessionPath, statsPath, onSwitchSource, segments, selected, onSelect, maximized, onToggleMaximized, theme, mode, family, onMode, onFamily, style, background, onStyle, width, onWidth, panes, onPane, onClose, onRefresh, commitDraft, onCommitDraft, commitAmend, onCommitAmend, sync, treeLoading, historyLoading, busy, opResult, runOp, fetchDiscardPlan, pendingTicks, onTick, fetchFileDiff, viewKey, gen, collapsed, onCollapsedChange }) {
12927
13609
  const body = shown ?? EMPTY_STATS;
12928
13610
  /** The file list with ticks still awaiting git laid over them. The tree and
12929
13611
  * the commit box read this, so a click moves its box and the "N ticked"
@@ -12934,8 +13616,16 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12934
13616
  * while a refresh lands over it. Derived once and handed to both the header
12935
13617
  * and the tree: spelling it twice is what let the header get it wrong. */
12936
13618
  const pending = showsPending(treeLoading, body.files.length);
12937
- const active = selected !== null && body.files.some((file) => file.path === selected) ? selected : body.files[0]?.path ?? null;
13619
+ /** The history filter's paths, which decide what a commit OPENS on. Only the
13620
+ * history tab has one: the changes and compare trees are not filtered, and
13621
+ * steering their default selection by a query the reader cannot see from
13622
+ * there would be a spooky action. */
13623
+ const activeFilterPaths = (0, react.useMemo)(() => tab === "history" ? parseLogQuery(historyQuery).paths : NO_PATHS, [tab, historyQuery]);
13624
+ const active = preferredFile(body.files, activeFilterPaths, selected);
12938
13625
  const activeFile = body.files.find((file) => file.path === active) ?? null;
13626
+ /** The file whose roll-back is being asked about; `plan` is null while the
13627
+ * host is still being asked what it would do. */
13628
+ const [discardPending, setDiscardPending] = (0, react.useState)(null);
12939
13629
  const [fetched, setFetched] = (0, react.useState)(/* @__PURE__ */ new Map());
12940
13630
  const [loading, setLoading] = (0, react.useState)(false);
12941
13631
  const bundled = active === null ? "" : segments.get(active) ?? "";
@@ -12967,6 +13657,55 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12967
13657
  setFetched(/* @__PURE__ */ new Map());
12968
13658
  }, [gen]);
12969
13659
  const selectAndReveal = (path) => onSelect(path);
13660
+ /**
13661
+ * Roll-back, in two steps that are deliberately not one.
13662
+ *
13663
+ * The click asks the host what rolling this file back would DO, and only the
13664
+ * answer opens the dialog. Deriving the wording from the clicked row instead
13665
+ * would mean describing a file as the last poll saw it: the difference
13666
+ * between "goes back to its committed content" and "leaves the disk and
13667
+ * cannot come back" is the entire subject of the question being asked, and it
13668
+ * is exactly the thing a stale row gets wrong.
13669
+ *
13670
+ * `recover` — a deleted file coming back — shows no dialog at all. It loses
13671
+ * nothing, and a confirmation in front of a pure gain is how people learn to
13672
+ * dismiss confirmations without reading them.
13673
+ */
13674
+ const askDiscard = (file) => {
13675
+ setDiscardPending({
13676
+ file,
13677
+ plan: null
13678
+ });
13679
+ (async () => {
13680
+ const preview = await fetchDiscardPlan(statsPath, file.path, new AbortController().signal);
13681
+ if (preview === null || preview.effect === void 0) {
13682
+ setDiscardPending(null);
13683
+ onRefresh();
13684
+ return;
13685
+ }
13686
+ if (preview.irreversible !== true) {
13687
+ setDiscardPending(null);
13688
+ runOp("discardFile", {
13689
+ path: file.path,
13690
+ expectedEffect: preview.effect
13691
+ });
13692
+ return;
13693
+ }
13694
+ setDiscardPending({
13695
+ file,
13696
+ plan: preview
13697
+ });
13698
+ })();
13699
+ };
13700
+ const confirmDiscard = () => {
13701
+ const pending = discardPending;
13702
+ if (pending === null || pending.plan === null) return;
13703
+ setDiscardPending(null);
13704
+ runOp("discardFile", {
13705
+ path: pending.file.path,
13706
+ expectedEffect: pending.plan.effect
13707
+ });
13708
+ };
12970
13709
  const drawerRef = (0, react.useRef)(null);
12971
13710
  const commitsRef = (0, react.useRef)(null);
12972
13711
  const treeRef = (0, react.useRef)(null);
@@ -13202,7 +13941,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13202
13941
  branches,
13203
13942
  worktreeBranches,
13204
13943
  truncated: branchesTruncated,
13205
- onPick: onHistoryRef
13944
+ onPick: onHistoryRef,
13945
+ allLabel: t("allBranches")
13206
13946
  })
13207
13947
  }) : null,
13208
13948
  tab === "changes" && sync !== null && sync.hasRemote ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SyncBar, {
@@ -13231,7 +13971,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13231
13971
  onSelect: onSelectCommit,
13232
13972
  hasMore: hasMoreCommits,
13233
13973
  loadingMore,
13234
- onLoadMore: onLoadMoreCommits
13974
+ onLoadMore: onLoadMoreCommits,
13975
+ query: historyQuery,
13976
+ onQueryChange: onHistoryQuery,
13977
+ error: historyError,
13978
+ statsPath,
13979
+ refName: historyRef,
13980
+ fetchAuthors,
13981
+ fetchRepoTree
13235
13982
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PaneDivider, {
13236
13983
  label: t("resizeCommits"),
13237
13984
  onDrag: paneDrag("commits", commitsRef)
@@ -13243,6 +13990,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13243
13990
  "data-gs-part": "tree",
13244
13991
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FileTree, {
13245
13992
  t,
13993
+ scopeKey: viewKey,
13246
13994
  loading: pending,
13247
13995
  lead: tab === "changes" ? t("workingTree") : void 0,
13248
13996
  files: tickedFiles,
@@ -13255,6 +14003,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13255
14003
  const paths = pathsFor(checked, action);
13256
14004
  if (paths.length > 0) onTick(action, paths);
13257
14005
  } : void 0,
14006
+ onDiscard: tab === "changes" ? askDiscard : void 0,
13258
14007
  footer: tab === "changes" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CommitBox, {
13259
14008
  t,
13260
14009
  files: tickedFiles,
@@ -13303,6 +14052,86 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13303
14052
  })]
13304
14053
  })
13305
14054
  ]
14055
+ }),
14056
+ discardPending?.plan != null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DiscardConfirm, {
14057
+ t,
14058
+ file: discardPending.file,
14059
+ plan: discardPending.plan,
14060
+ onCancel: () => setDiscardPending(null),
14061
+ onConfirm: confirmDiscard
14062
+ }) : null
14063
+ ]
14064
+ })
14065
+ });
14066
+ }
14067
+ /**
14068
+ * The one dialog in this drawer, because this is the one act it cannot undo.
14069
+ *
14070
+ * It never asks a generic "are you sure": the body names the file and states
14071
+ * which of the three consequences is about to happen, in the host's own reading
14072
+ * of that file taken moments ago. Cancel holds the initial focus and Escape
14073
+ * closes, because the default answer to an irreversible question is no.
14074
+ *
14075
+ * There is deliberately no "don't ask again". This is the only path in the
14076
+ * drawer with nothing behind it, and a checkbox whose whole function is to
14077
+ * switch off the last guard is a feature that eventually gets clicked.
14078
+ */
14079
+ function DiscardConfirm({ t, file, plan, onCancel, onConfirm }) {
14080
+ const cancelRef = (0, react.useRef)(null);
14081
+ (0, react.useEffect)(() => {
14082
+ cancelRef.current?.focus();
14083
+ }, []);
14084
+ (0, react.useEffect)(() => {
14085
+ const onKey = (event) => {
14086
+ if (event.key !== "Escape") return;
14087
+ event.stopPropagation();
14088
+ onCancel();
14089
+ };
14090
+ window.addEventListener("keydown", onKey, true);
14091
+ return () => {
14092
+ window.removeEventListener("keydown", onKey, true);
14093
+ };
14094
+ }, [onCancel]);
14095
+ const body = plan.effect === "delete" ? t("discardBodyDelete", { path: file.path }) : plan.effect === "unrename" ? t("discardBodyUnrename", {
14096
+ path: file.path,
14097
+ previousPath: plan.previousPath ?? ""
14098
+ }) : t("discardBodyRestore", {
14099
+ path: file.path,
14100
+ added: file.addedLines,
14101
+ deleted: file.deletedLines
14102
+ });
14103
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
14104
+ className: GitWorkbenchPanel_module_css_default.confirmScrim,
14105
+ onClick: onCancel,
14106
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
14107
+ className: GitWorkbenchPanel_module_css_default.confirmBox,
14108
+ role: "alertdialog",
14109
+ "aria-modal": "true",
14110
+ "aria-label": t("discardTitle"),
14111
+ onClick: (event) => event.stopPropagation(),
14112
+ children: [
14113
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
14114
+ className: GitWorkbenchPanel_module_css_default.confirmTitle,
14115
+ children: t("discardTitle")
14116
+ }),
14117
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
14118
+ className: GitWorkbenchPanel_module_css_default.confirmBody,
14119
+ children: body
14120
+ }),
14121
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
14122
+ className: GitWorkbenchPanel_module_css_default.confirmActions,
14123
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
14124
+ ref: cancelRef,
14125
+ type: "button",
14126
+ className: GitWorkbenchPanel_module_css_default.btn,
14127
+ onClick: onCancel,
14128
+ children: t("discardCancel")
14129
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
14130
+ type: "button",
14131
+ className: `${GitWorkbenchPanel_module_css_default.btn} ${GitWorkbenchPanel_module_css_default.btnDanger}`,
14132
+ onClick: onConfirm,
14133
+ children: t("discardConfirm")
14134
+ })]
13306
14135
  })
13307
14136
  ]
13308
14137
  })
@@ -13835,7 +14664,12 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13835
14664
  * checked-out branch is the likeliest thing to want. Enter takes the first
13836
14665
  * match, so a distinctive substring plus Enter reaches any branch in the list.
13837
14666
  */
13838
- function RefPicker({ t, label, value, branches, worktreeBranches, truncated, onPick }) {
14667
+ /** Sentinel ref meaning "walk every ref" same string the host special-cases
14668
+ * into `--all`. A real ref cannot begin with a dash, so it collides with
14669
+ * nothing; defined separately on both halves (client bundles import no host
14670
+ * values), tied by this comment and the probe. */
14671
+ const ALL_REFS = "--all";
14672
+ function RefPicker({ t, label, value, branches, worktreeBranches, truncated, onPick, allLabel }) {
13839
14673
  const [open, setOpen] = (0, react.useState)(false);
13840
14674
  const [query, setQuery] = (0, react.useState)("");
13841
14675
  const rootRef = useDismissable(open, setOpen);
@@ -13876,7 +14710,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13876
14710
  title: value.length > 0 ? value : void 0,
13877
14711
  onClick: () => setOpen((isOpen) => !isOpen),
13878
14712
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Elided, {
13879
- text: value.length > 0 ? value : "—",
14713
+ text: value === ALL_REFS && allLabel !== void 0 ? allLabel : value.length > 0 ? value : "—",
13880
14714
  className: GitWorkbenchPanel_module_css_default.refValue
13881
14715
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13882
14716
  className: GitWorkbenchPanel_module_css_default.refCaret,
@@ -13901,6 +14735,18 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13901
14735
  role: "listbox",
13902
14736
  "aria-label": label,
13903
14737
  children: [
14738
+ allLabel !== void 0 && (needle.length === 0 || allLabel.toLowerCase().includes(needle)) ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
14739
+ type: "button",
14740
+ role: "option",
14741
+ "aria-selected": value === ALL_REFS,
14742
+ className: value === ALL_REFS ? `${GitWorkbenchPanel_module_css_default.refRow} ${GitWorkbenchPanel_module_css_default.refRowActive}` : GitWorkbenchPanel_module_css_default.refRow,
14743
+ title: allLabel,
14744
+ onClick: () => choose(ALL_REFS),
14745
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: GitWorkbenchPanel_module_css_default.refRowSpacer }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Elided, {
14746
+ text: allLabel,
14747
+ className: GitWorkbenchPanel_module_css_default.refRowName
14748
+ })]
14749
+ }) : null,
13904
14750
  checkedOut.length > 0 && rest.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
13905
14751
  className: GitWorkbenchPanel_module_css_default.refGroup,
13906
14752
  children: t("refWorktrees")
@@ -13911,7 +14757,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13911
14757
  children: t("refBranches")
13912
14758
  }) : null,
13913
14759
  rest.map((ref) => row(ref, false)),
13914
- matched.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
14760
+ matched.length === 0 && !(allLabel !== void 0 && needle.length > 0 && allLabel.toLowerCase().includes(needle)) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
13915
14761
  className: GitWorkbenchPanel_module_css_default.refEmpty,
13916
14762
  children: t("refNone")
13917
14763
  }) : null
@@ -14014,6 +14860,53 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14014
14860
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: SYNC_GLYPH[of] })
14015
14861
  });
14016
14862
  }
14863
+ /**
14864
+ * Filter this list: a magnifier, not the funnel above the commit list. The two
14865
+ * are deliberately different glyphs because they do different things — the
14866
+ * funnel asks git for a different set of commits, this only hides rows already
14867
+ * on screen — and the drawer shows both at once.
14868
+ */
14869
+ function FilterGlyph() {
14870
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
14871
+ width: "13",
14872
+ height: "13",
14873
+ viewBox: "0 0 16 16",
14874
+ fill: "none",
14875
+ stroke: "currentColor",
14876
+ strokeWidth: "1.25",
14877
+ strokeLinecap: "round",
14878
+ strokeLinejoin: "round",
14879
+ "aria-hidden": "true",
14880
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
14881
+ cx: "7",
14882
+ cy: "7",
14883
+ r: "4"
14884
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M10 10l3.5 3.5" })]
14885
+ });
14886
+ }
14887
+ /** Nothing folded. A constant so the filtered tree does not allocate a new Set
14888
+ * on every render and re-run `TreeChildren`'s memo. */
14889
+ const EMPTY_COLLAPSED = /* @__PURE__ */ new Set();
14890
+ /**
14891
+ * Roll back: the counter-clockwise arc every editor and VCS uses for undo,
14892
+ * drawn in the same New UI idiom as the node glyphs beside it — 16px grid,
14893
+ * 1px stroke, no fill — so the row does not mix an outlined file icon with a
14894
+ * solid action icon.
14895
+ */
14896
+ function RollbackGlyph() {
14897
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
14898
+ width: "14",
14899
+ height: "14",
14900
+ viewBox: "0 0 16 16",
14901
+ fill: "none",
14902
+ stroke: "currentColor",
14903
+ strokeWidth: "1.25",
14904
+ strokeLinecap: "round",
14905
+ strokeLinejoin: "round",
14906
+ "aria-hidden": "true",
14907
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M3.5 6.5a5 5 0 1 0 1.9-2.2" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.6 3.2v3.4h3.4" })]
14908
+ });
14909
+ }
14017
14910
  const PULL_MODES = [
14018
14911
  "ff-only",
14019
14912
  "rebase",
@@ -14388,6 +15281,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14388
15281
  const enterTimer = (0, react.useRef)(0);
14389
15282
  const leaveTimer = (0, react.useRef)(0);
14390
15283
  const body = commit.body ?? "";
15284
+ const authorName = commit.authorName ?? "";
15285
+ const committerName = commit.committerName ?? "";
15286
+ const exactDate = formatCommitDate(commit.dateIso ?? "");
14391
15287
  const cancel = () => {
14392
15288
  window.clearTimeout(enterTimer.current);
14393
15289
  window.clearTimeout(leaveTimer.current);
@@ -14438,13 +15334,20 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14438
15334
  onMouseLeave: hide,
14439
15335
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
14440
15336
  className: GitWorkbenchPanel_module_css_default.commitTop,
14441
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
14442
- className: GitWorkbenchPanel_module_css_default.commitHash,
14443
- children: commit.hash
14444
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
14445
- className: GitWorkbenchPanel_module_css_default.commitWhen,
14446
- children: commit.when
14447
- })]
15337
+ children: [
15338
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
15339
+ className: GitWorkbenchPanel_module_css_default.commitHash,
15340
+ children: commit.hash
15341
+ }),
15342
+ authorName.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
15343
+ className: GitWorkbenchPanel_module_css_default.commitAuthor,
15344
+ children: authorName
15345
+ }) : null,
15346
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
15347
+ className: GitWorkbenchPanel_module_css_default.commitWhen,
15348
+ children: commit.when
15349
+ })
15350
+ ]
14448
15351
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
14449
15352
  className: GitWorkbenchPanel_module_css_default.commitSubjectRow,
14450
15353
  children: [
@@ -14495,22 +15398,249 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14495
15398
  className: GitWorkbenchPanel_module_css_default.commitWhen,
14496
15399
  children: commit.when
14497
15400
  }),
14498
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopyCommitButton, {
14499
- t,
14500
- text: commitMessageText(commit)
15401
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopyCommitButton, {
15402
+ t,
15403
+ text: commitMessageText(commit)
15404
+ })
15405
+ ]
15406
+ }),
15407
+ authorName.length > 0 || committerName.length > 0 || exactDate.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
15408
+ className: GitWorkbenchPanel_module_css_default.commitPopMeta,
15409
+ children: [
15410
+ authorName.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
15411
+ t("commitAuthor"),
15412
+ ": ",
15413
+ authorName
15414
+ ] }) : null,
15415
+ committerName.length > 0 && committerName !== authorName ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
15416
+ t("commitCommitter"),
15417
+ ": ",
15418
+ committerName
15419
+ ] }) : null,
15420
+ exactDate.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
15421
+ t("commitDate"),
15422
+ ": ",
15423
+ exactDate
15424
+ ] }) : null
15425
+ ]
15426
+ }) : null,
15427
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
15428
+ className: GitWorkbenchPanel_module_css_default.commitPopSubject,
15429
+ children: commit.subject
15430
+ }),
15431
+ body.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
15432
+ className: GitWorkbenchPanel_module_css_default.commitPopBody,
15433
+ children: body
15434
+ }) : null
15435
+ ]
15436
+ }), host) : null] });
15437
+ }
15438
+ /** The filter's own calendar — a hand-rolled 6×7 Monday-first grid (pure
15439
+ * arithmetic in `calendar.ts`), because the native date input renders as the
15440
+ * platform's bare widget and the bundle's purity gate forbids pulling in a
15441
+ * library. Picking a day hands `yyyy-mm-dd` to the bound the segmented
15442
+ * control armed; the host expands it to the whole day. */
15443
+ function FilterCalendar({ year, month, after, before, locale, onPick, onShift }) {
15444
+ const grid = monthGrid(year, month, localTodayIso());
15445
+ const title = new Intl.DateTimeFormat(locale, {
15446
+ year: "numeric",
15447
+ month: "long"
15448
+ }).format(new Date(year, month, 1));
15449
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
15450
+ className: GitWorkbenchPanel_module_css_default.cal,
15451
+ children: [
15452
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
15453
+ className: GitWorkbenchPanel_module_css_default.calHead,
15454
+ children: [
15455
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
15456
+ type: "button",
15457
+ className: GitWorkbenchPanel_module_css_default.calNav,
15458
+ "aria-label": "‹",
15459
+ onClick: () => onShift(-1),
15460
+ children: "‹"
15461
+ }),
15462
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
15463
+ className: GitWorkbenchPanel_module_css_default.calTitle,
15464
+ children: title
15465
+ }),
15466
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
15467
+ type: "button",
15468
+ className: GitWorkbenchPanel_module_css_default.calNav,
15469
+ "aria-label": "›",
15470
+ onClick: () => onShift(1),
15471
+ children: "›"
15472
+ })
15473
+ ]
15474
+ }),
15475
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
15476
+ className: GitWorkbenchPanel_module_css_default.calWeek,
15477
+ children: weekdayLabels(locale).map((label, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label }, index))
15478
+ }),
15479
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
15480
+ className: GitWorkbenchPanel_module_css_default.calGrid,
15481
+ children: grid.flat().map((cell) => cell === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
15482
+ type: "button",
15483
+ "aria-label": cell.iso,
15484
+ title: cell.iso,
15485
+ className: [
15486
+ cell.inMonth ? "" : GitWorkbenchPanel_module_css_default.calOut,
15487
+ cell.isToday ? GitWorkbenchPanel_module_css_default.calToday : "",
15488
+ inCalRange(cell.iso, after, before) ? GitWorkbenchPanel_module_css_default.calIn : "",
15489
+ cell.iso === after || cell.iso === before ? GitWorkbenchPanel_module_css_default.calMark : ""
15490
+ ].filter((cls) => cls.length > 0).join(" "),
15491
+ onClick: () => onPick(cell.iso),
15492
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: cell.day })
15493
+ }, cell.iso))
15494
+ })
15495
+ ]
15496
+ });
15497
+ }
15498
+ /**
15499
+ * The two node glyphs, in IntelliJ's New UI icon idiom: a 16px grid, 1px
15500
+ * strokes, no fill, rounded joins — outlines, where the old UI shipped filled
15501
+ * silhouettes. Hand-drawn here rather than imported, because the bundle purity
15502
+ * gate forbids an icon package and the drawer needs exactly these two; they
15503
+ * are shapes in that language, not JetBrains' own assets.
15504
+ *
15505
+ * `strokeWidth` is 1 against a viewBox that renders 1:1 at 16px, so every
15506
+ * stroke lands on a whole pixel instead of straddling two.
15507
+ *
15508
+ * Every place the drawer names a file or a directory uses these: the path
15509
+ * picker in the history filter, and the file tree behind all three tabs. The
15510
+ * CLASS names keep their `path` prefix — `scripts/verify_history_feature.py`
15511
+ * selects the picker's file rows by `label:has([class*="pathFileGlyph"])`.
15512
+ */
15513
+ function PathDirGlyph() {
15514
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
15515
+ className: GitWorkbenchPanel_module_css_default.pathDirGlyph,
15516
+ width: "16",
15517
+ height: "16",
15518
+ viewBox: "0 0 16 16",
15519
+ fill: "none",
15520
+ stroke: "currentColor",
15521
+ strokeWidth: "1",
15522
+ strokeLinejoin: "round",
15523
+ strokeLinecap: "round",
15524
+ "aria-hidden": "true",
15525
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.5 12.75V4.25A.75.75 0 0 1 3.25 3.5H6l1.6 2h5.15A.75.75 0 0 1 13.5 6.25v6.5a.75.75 0 0 1-.75.75H3.25a.75.75 0 0 1-.75-.75Z" })
15526
+ });
15527
+ }
15528
+ function PathFileGlyph() {
15529
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
15530
+ className: GitWorkbenchPanel_module_css_default.pathFileGlyph,
15531
+ width: "16",
15532
+ height: "16",
15533
+ viewBox: "0 0 16 16",
15534
+ fill: "none",
15535
+ stroke: "currentColor",
15536
+ strokeWidth: "1",
15537
+ strokeLinejoin: "round",
15538
+ strokeLinecap: "round",
15539
+ "aria-hidden": "true",
15540
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M3.5 12.75V3.25A.75.75 0 0 1 4.25 2.5H9l3.5 3.5v6.75a.75.75 0 0 1-.75.75H4.25a.75.75 0 0 1-.75-.75Z" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M9 2.5v2.75a.75.75 0 0 0 .75.75h2.75" })]
15541
+ });
15542
+ }
15543
+ /** Files shown per expanded directory. The search box is the way to a file in
15544
+ * a crowded directory; the tree shows enough to browse without flooding the
15545
+ * list, and says so when it cut the tail. */
15546
+ const PATH_FILES_SHOWN = 100;
15547
+ /** Horizontal step per nesting level in the path picker. The whole indent now
15548
+ * comes from this one number: `.pathChildren` used to add a margin and a rail
15549
+ * of its own on top of it, so every level cost 29px and a 320px popover ran
15550
+ * out of width three directories deep. */
15551
+ const PATH_INDENT = 14;
15552
+ /** One level of the path picker's directory tree — directories (chevron,
15553
+ * subtree count) then their files (doc glyph, leaf rows). Collapsed subtrees
15554
+ * are not in the DOM at all, so a monorepo costs only what the reader has
15555
+ * opened. */
15556
+ /** A checkbox that also carries the tree's third state — `indeterminate` is a
15557
+ * DOM property, not an attribute, so it is set through the ref. */
15558
+ function TriStateCheckbox({ state, onChange, ariaLabel }) {
15559
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
15560
+ type: "checkbox",
15561
+ "aria-label": ariaLabel,
15562
+ checked: state === "on",
15563
+ ref: (el) => {
15564
+ if (el !== null) el.indeterminate = state === "partial";
15565
+ },
15566
+ onChange
15567
+ });
15568
+ }
15569
+ function PathTreeRows({ dirs, depth, expanded, stateOf, onToggleOpen, onTogglePath }) {
15570
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: dirs.map((dir) => {
15571
+ const open = expanded.includes(dir.path);
15572
+ const expandable = dir.children.length > 0 || dir.files.length > 0;
15573
+ const shown = dir.files.slice(0, PATH_FILES_SHOWN);
15574
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
15575
+ className: GitWorkbenchPanel_module_css_default.pathNode,
15576
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
15577
+ className: GitWorkbenchPanel_module_css_default.funnelRow,
15578
+ style: { paddingLeft: depth * PATH_INDENT + 4 },
15579
+ children: [
15580
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
15581
+ type: "button",
15582
+ className: GitWorkbenchPanel_module_css_default.funnelChevron,
15583
+ disabled: !expandable,
15584
+ "aria-expanded": open,
15585
+ onClick: () => onToggleOpen(dir.path),
15586
+ children: expandable ? open ? "▾" : "▸" : ""
15587
+ }),
15588
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TriStateCheckbox, {
15589
+ state: stateOf(dir.path),
15590
+ ariaLabel: dir.path,
15591
+ onChange: () => onTogglePath(dir.path)
15592
+ }),
15593
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PathDirGlyph, {}),
15594
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
15595
+ className: GitWorkbenchPanel_module_css_default.funnelName,
15596
+ title: dir.path,
15597
+ children: dir.name
15598
+ }),
15599
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
15600
+ className: GitWorkbenchPanel_module_css_default.funnelCount,
15601
+ children: dir.fileCount
14501
15602
  })
14502
15603
  ]
14503
- }),
14504
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
14505
- className: GitWorkbenchPanel_module_css_default.commitPopSubject,
14506
- children: commit.subject
14507
- }),
14508
- body.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
14509
- className: GitWorkbenchPanel_module_css_default.commitPopBody,
14510
- children: body
14511
- }) : null
14512
- ]
14513
- }), host) : null] });
15604
+ }), open ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
15605
+ className: GitWorkbenchPanel_module_css_default.pathChildren,
15606
+ children: [
15607
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PathTreeRows, {
15608
+ dirs: dir.children,
15609
+ depth: depth + 1,
15610
+ expanded,
15611
+ stateOf,
15612
+ onToggleOpen,
15613
+ onTogglePath
15614
+ }),
15615
+ shown.map((file) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
15616
+ className: GitWorkbenchPanel_module_css_default.funnelRow,
15617
+ style: { paddingLeft: (depth + 1) * PATH_INDENT + 4 },
15618
+ children: [
15619
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
15620
+ className: GitWorkbenchPanel_module_css_default.funnelChevron,
15621
+ "aria-hidden": "true"
15622
+ }),
15623
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TriStateCheckbox, {
15624
+ state: stateOf(`${dir.path}/${file}`),
15625
+ ariaLabel: `${dir.path}/${file}`,
15626
+ onChange: () => onTogglePath(`${dir.path}/${file}`)
15627
+ }),
15628
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PathFileGlyph, {}),
15629
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
15630
+ className: GitWorkbenchPanel_module_css_default.funnelName,
15631
+ title: `${dir.path}/${file}`,
15632
+ children: file
15633
+ })
15634
+ ]
15635
+ }, file)),
15636
+ dir.files.length > PATH_FILES_SHOWN ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
15637
+ className: GitWorkbenchPanel_module_css_default.funnelMore,
15638
+ children: ["+", dir.files.length - PATH_FILES_SHOWN]
15639
+ }) : null
15640
+ ]
15641
+ }) : null]
15642
+ }, dir.path);
15643
+ }) });
14514
15644
  }
14515
15645
  /**
14516
15646
  * The commit log as its own full-height pane.
@@ -14530,9 +15660,131 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14530
15660
  * what GitHub and GitLens do. The observer is rebuilt whenever the list grows,
14531
15661
  * so a page too short to fill the pane immediately triggers the next one.
14532
15662
  */
14533
- function CommitList({ paneRef, style, t, loading, commits, active, onSelect, hasMore, loadingMore, onLoadMore }) {
15663
+ function CommitList({ paneRef, style, t, loading, commits, active, onSelect, hasMore, loadingMore, onLoadMore, query, onQueryChange, error, statsPath, refName, fetchAuthors, fetchRepoTree }) {
14534
15664
  const scrollRef = (0, react.useRef)(null);
14535
15665
  const sentinelRef = (0, react.useRef)(null);
15666
+ const filterModel = (0, react.useMemo)(() => parseLogQuery(query), [query]);
15667
+ const chips = chipsFromFilter(filterModel);
15668
+ const dateCount = (filterModel.after.length > 0 ? 1 : 0) + (filterModel.before.length > 0 ? 1 : 0);
15669
+ const selectedCount = filterModel.users.length + filterModel.paths.length + dateCount;
15670
+ const [funnelOpen, setFunnelOpen] = (0, react.useState)(false);
15671
+ const [authors, setAuthors] = (0, react.useState)(null);
15672
+ const [authorsQuery, setAuthorsQuery] = (0, react.useState)("");
15673
+ const [pathTree, setPathTree] = (0, react.useState)(null);
15674
+ const [expandedDirs, setExpandedDirs] = (0, react.useState)([]);
15675
+ const [pathsQuery, setPathsQuery] = (0, react.useState)("");
15676
+ const [funnelSection, setFunnelSection] = (0, react.useState)("users");
15677
+ const [calMonth, setCalMonth] = (0, react.useState)(() => {
15678
+ const now = /* @__PURE__ */ new Date();
15679
+ return {
15680
+ year: now.getFullYear(),
15681
+ month: now.getMonth()
15682
+ };
15683
+ });
15684
+ const [calBound, setCalBound] = (0, react.useState)("after");
15685
+ const funnelAnchorRef = (0, react.useRef)(null);
15686
+ const funnelPanelRef = (0, react.useRef)(null);
15687
+ const [funnelBox, setFunnelBox] = (0, react.useState)(null);
15688
+ (0, react.useEffect)(() => {
15689
+ if (!funnelOpen) {
15690
+ setFunnelBox(null);
15691
+ return;
15692
+ }
15693
+ const onDown = (event) => {
15694
+ const target = event.target;
15695
+ if (funnelAnchorRef.current?.contains(target) === true) return;
15696
+ if (funnelPanelRef.current?.contains(target) === true) return;
15697
+ setFunnelOpen(false);
15698
+ };
15699
+ const onKey = (event) => {
15700
+ if (event.key === "Escape") setFunnelOpen(false);
15701
+ };
15702
+ const id = window.setTimeout(() => document.addEventListener("mousedown", onDown), 0);
15703
+ document.addEventListener("keydown", onKey);
15704
+ return () => {
15705
+ window.clearTimeout(id);
15706
+ document.removeEventListener("mousedown", onDown);
15707
+ document.removeEventListener("keydown", onKey);
15708
+ };
15709
+ }, [funnelOpen]);
15710
+ (0, react.useEffect)(() => {
15711
+ if (!funnelOpen) return;
15712
+ const rect = funnelAnchorRef.current?.getBoundingClientRect();
15713
+ if (rect === void 0) return;
15714
+ const width = 300;
15715
+ const left = Math.max(12, Math.min(rect.left + rect.width - width, window.innerWidth - width - 12));
15716
+ const top = rect.bottom + 4;
15717
+ setFunnelBox({
15718
+ top,
15719
+ left,
15720
+ maxHeight: Math.max(160, window.innerHeight - top - 16)
15721
+ });
15722
+ }, [funnelOpen]);
15723
+ (0, react.useEffect)(() => {
15724
+ if (!funnelOpen) return;
15725
+ const ctrl = new AbortController();
15726
+ setAuthors(null);
15727
+ setPathTree(null);
15728
+ fetchAuthors(statsPath, refName, ctrl.signal).then((roster) => {
15729
+ if (!ctrl.signal.aborted) setAuthors(roster);
15730
+ }).catch(() => {});
15731
+ fetchRepoTree(statsPath, ctrl.signal).then((tree) => {
15732
+ if (!ctrl.signal.aborted && tree !== null) setPathTree({
15733
+ dirs: buildDirTree(tree.paths),
15734
+ paths: tree.paths,
15735
+ truncated: tree.truncated
15736
+ });
15737
+ }).catch(() => {});
15738
+ return () => {
15739
+ ctrl.abort();
15740
+ };
15741
+ }, [
15742
+ funnelOpen,
15743
+ statsPath,
15744
+ refName,
15745
+ fetchAuthors,
15746
+ fetchRepoTree
15747
+ ]);
15748
+ /** Every funnel interaction writes the filter through the box's grammar, so
15749
+ * the box, the chips and the fetch can never disagree about the query. */
15750
+ const applyFilter = (next) => {
15751
+ onQueryChange(serializeLogQuery(next));
15752
+ };
15753
+ const toggleUser = (name) => {
15754
+ const has = filterModel.users.includes(name);
15755
+ applyFilter({
15756
+ ...filterModel,
15757
+ users: has ? filterModel.users.filter((user) => user !== name) : [...filterModel.users, name]
15758
+ });
15759
+ };
15760
+ const pathIndex = (0, react.useMemo)(() => pathTree === null ? null : buildIndex(pathTree.paths), [pathTree]);
15761
+ const pathState = (path) => pathIndex === null ? "off" : checkedState(filterModel.paths, path, pathIndex);
15762
+ const togglePath = (path) => {
15763
+ if (pathIndex === null) return;
15764
+ applyFilter({
15765
+ ...filterModel,
15766
+ paths: isCovered(filterModel.paths, path) ? removePath(filterModel.paths, path, pathIndex) : addPath(filterModel.paths, path)
15767
+ });
15768
+ };
15769
+ const toggleDirOpen = (path) => {
15770
+ setExpandedDirs((prev) => prev.includes(path) ? prev.filter((p) => p !== path) : [...prev, path]);
15771
+ };
15772
+ const needle = authorsQuery.trim().toLowerCase();
15773
+ const matchedAuthors = authors === null ? [] : needle.length === 0 ? authors.authors : authors.authors.filter((entry) => entry.name.toLowerCase().includes(needle) || entry.email.toLowerCase().includes(needle));
15774
+ const DATE_PRESETS = [
15775
+ {
15776
+ key: "filterToday",
15777
+ value: "midnight"
15778
+ },
15779
+ {
15780
+ key: "filterLast7",
15781
+ value: "1 week ago"
15782
+ },
15783
+ {
15784
+ key: "filterLast30",
15785
+ value: "30 days ago"
15786
+ }
15787
+ ];
14536
15788
  const graph = (0, react.useMemo)(() => layoutGraph(commits.map((commit) => ({
14537
15789
  hash: commit.hash,
14538
15790
  parents: commit.parents ?? []
@@ -14562,39 +15814,353 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14562
15814
  className: GitWorkbenchPanel_module_css_default.commitsPane,
14563
15815
  style,
14564
15816
  "data-gs-part": "commits",
14565
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
14566
- className: GitWorkbenchPanel_module_css_default.paneHead,
14567
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
14568
- className: GitWorkbenchPanel_module_css_default.paneTitle,
14569
- children: t("historyLabel")
15817
+ children: [
15818
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
15819
+ className: GitWorkbenchPanel_module_css_default.paneHead,
15820
+ children: [
15821
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
15822
+ className: GitWorkbenchPanel_module_css_default.paneTitle,
15823
+ children: t("historyLabel")
15824
+ }),
15825
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
15826
+ className: GitWorkbenchPanel_module_css_default.funnel,
15827
+ ref: funnelAnchorRef,
15828
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
15829
+ type: "button",
15830
+ className: funnelOpen || chips.length > 0 ? `${GitWorkbenchPanel_module_css_default.funnelButton} ${GitWorkbenchPanel_module_css_default.funnelButtonActive}` : GitWorkbenchPanel_module_css_default.funnelButton,
15831
+ "aria-expanded": funnelOpen,
15832
+ onClick: () => setFunnelOpen((isOpen) => !isOpen),
15833
+ children: [t("filterBy"), " ▾"]
15834
+ })
15835
+ }),
15836
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
15837
+ className: GitWorkbenchPanel_module_css_default.commitFilter,
15838
+ type: "search",
15839
+ value: query,
15840
+ onChange: (event) => onQueryChange(event.target.value),
15841
+ placeholder: t("historyFilterPlaceholder"),
15842
+ "aria-label": t("historyFilterPlaceholder"),
15843
+ spellCheck: false
15844
+ })
15845
+ ]
15846
+ }),
15847
+ funnelOpen && funnelBox !== null ? (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
15848
+ ref: funnelPanelRef,
15849
+ className: GitWorkbenchPanel_module_css_default.funnelPop,
15850
+ style: funnelBox,
15851
+ role: "dialog",
15852
+ "aria-label": t("filterBy"),
15853
+ children: [
15854
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
15855
+ className: GitWorkbenchPanel_module_css_default.funnelTabs,
15856
+ role: "tablist",
15857
+ children: [
15858
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
15859
+ type: "button",
15860
+ role: "tab",
15861
+ "aria-selected": funnelSection === "users",
15862
+ className: funnelSection === "users" ? `${GitWorkbenchPanel_module_css_default.funnelTab} ${GitWorkbenchPanel_module_css_default.funnelTabActive}` : GitWorkbenchPanel_module_css_default.funnelTab,
15863
+ onClick: () => setFunnelSection("users"),
15864
+ children: [t("filterUsers"), filterModel.users.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
15865
+ className: GitWorkbenchPanel_module_css_default.funnelTabCount,
15866
+ children: filterModel.users.length
15867
+ }) : null]
15868
+ }),
15869
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
15870
+ type: "button",
15871
+ role: "tab",
15872
+ "aria-selected": funnelSection === "date",
15873
+ className: funnelSection === "date" ? `${GitWorkbenchPanel_module_css_default.funnelTab} ${GitWorkbenchPanel_module_css_default.funnelTabActive}` : GitWorkbenchPanel_module_css_default.funnelTab,
15874
+ onClick: () => setFunnelSection("date"),
15875
+ children: [t("filterDate"), dateCount > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
15876
+ className: GitWorkbenchPanel_module_css_default.funnelTabCount,
15877
+ children: dateCount
15878
+ }) : null]
15879
+ }),
15880
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
15881
+ type: "button",
15882
+ role: "tab",
15883
+ "aria-selected": funnelSection === "paths",
15884
+ className: funnelSection === "paths" ? `${GitWorkbenchPanel_module_css_default.funnelTab} ${GitWorkbenchPanel_module_css_default.funnelTabActive}` : GitWorkbenchPanel_module_css_default.funnelTab,
15885
+ onClick: () => setFunnelSection("paths"),
15886
+ children: [t("filterPaths"), filterModel.paths.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
15887
+ className: GitWorkbenchPanel_module_css_default.funnelTabCount,
15888
+ children: filterModel.paths.length
15889
+ }) : null]
15890
+ })
15891
+ ]
15892
+ }),
15893
+ funnelSection === "users" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
15894
+ className: GitWorkbenchPanel_module_css_default.funnelPane,
15895
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
15896
+ className: GitWorkbenchPanel_module_css_default.funnelSearch,
15897
+ type: "search",
15898
+ value: authorsQuery,
15899
+ onChange: (event) => setAuthorsQuery(event.target.value),
15900
+ placeholder: t("filterUserSearch"),
15901
+ "aria-label": t("filterUserSearch"),
15902
+ spellCheck: false
15903
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
15904
+ className: GitWorkbenchPanel_module_css_default.funnelList,
15905
+ children: [authors === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
15906
+ className: GitWorkbenchPanel_module_css_default.funnelMore,
15907
+ children: t("loading")
15908
+ }) : matchedAuthors.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
15909
+ className: GitWorkbenchPanel_module_css_default.funnelMore,
15910
+ children: authors.authors.length === 0 ? t("noCommits") : t("historyNoMatch")
15911
+ }) : matchedAuthors.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
15912
+ className: GitWorkbenchPanel_module_css_default.funnelRow,
15913
+ children: [
15914
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
15915
+ type: "checkbox",
15916
+ checked: filterModel.users.includes(entry.name),
15917
+ onChange: () => toggleUser(entry.name)
15918
+ }),
15919
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
15920
+ className: GitWorkbenchPanel_module_css_default.funnelName,
15921
+ title: `${entry.name} <${entry.email}>`,
15922
+ children: entry.name
15923
+ }),
15924
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
15925
+ className: GitWorkbenchPanel_module_css_default.funnelCount,
15926
+ children: entry.count
15927
+ })
15928
+ ]
15929
+ }, `${entry.name}\x1f${entry.email}`)), authors?.truncated === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
15930
+ className: GitWorkbenchPanel_module_css_default.funnelMore,
15931
+ children: t("filterAuthorsMore")
15932
+ }) : null]
15933
+ })]
15934
+ }) : null,
15935
+ funnelSection === "date" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
15936
+ className: GitWorkbenchPanel_module_css_default.funnelPane,
15937
+ children: [
15938
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
15939
+ className: GitWorkbenchPanel_module_css_default.funnelPresets,
15940
+ children: DATE_PRESETS.map((preset) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
15941
+ type: "button",
15942
+ className: filterModel.after === preset.value ? `${GitWorkbenchPanel_module_css_default.funnelPreset} ${GitWorkbenchPanel_module_css_default.funnelPresetActive}` : GitWorkbenchPanel_module_css_default.funnelPreset,
15943
+ onClick: () => applyFilter({
15944
+ ...filterModel,
15945
+ after: filterModel.after === preset.value ? "" : preset.value
15946
+ }),
15947
+ children: t(preset.key)
15948
+ }, preset.key))
15949
+ }),
15950
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
15951
+ className: GitWorkbenchPanel_module_css_default.funnelCaption,
15952
+ children: t("filterCalendarSets")
15953
+ }),
15954
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
15955
+ className: GitWorkbenchPanel_module_css_default.funnelBounds,
15956
+ role: "group",
15957
+ "aria-label": t("filterCalendarSets"),
15958
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
15959
+ type: "button",
15960
+ "aria-pressed": calBound === "after",
15961
+ className: calBound === "after" ? `${GitWorkbenchPanel_module_css_default.funnelBoundBtn} ${GitWorkbenchPanel_module_css_default.funnelBoundBtnActive}` : GitWorkbenchPanel_module_css_default.funnelBoundBtn,
15962
+ onClick: () => setCalBound("after"),
15963
+ children: t("filterAfter")
15964
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
15965
+ type: "button",
15966
+ "aria-pressed": calBound === "before",
15967
+ className: calBound === "before" ? `${GitWorkbenchPanel_module_css_default.funnelBoundBtn} ${GitWorkbenchPanel_module_css_default.funnelBoundBtnActive}` : GitWorkbenchPanel_module_css_default.funnelBoundBtn,
15968
+ onClick: () => setCalBound("before"),
15969
+ children: t("filterBefore")
15970
+ })]
15971
+ }),
15972
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FilterCalendar, {
15973
+ year: calMonth.year,
15974
+ month: calMonth.month,
15975
+ after: filterModel.after,
15976
+ before: filterModel.before,
15977
+ locale: t("filterLocale"),
15978
+ onPick: (iso) => applyFilter({
15979
+ ...filterModel,
15980
+ [calBound]: iso
15981
+ }),
15982
+ onShift: (delta) => setCalMonth((current) => {
15983
+ const next = new Date(current.year, current.month + delta, 1);
15984
+ return {
15985
+ year: next.getFullYear(),
15986
+ month: next.getMonth()
15987
+ };
15988
+ })
15989
+ }),
15990
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
15991
+ className: GitWorkbenchPanel_module_css_default.funnelBoundRows,
15992
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
15993
+ className: GitWorkbenchPanel_module_css_default.funnelBoundRow,
15994
+ children: [
15995
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
15996
+ className: GitWorkbenchPanel_module_css_default.funnelBoundKey,
15997
+ children: t("filterAfter")
15998
+ }),
15999
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16000
+ className: filterModel.after.length > 0 ? `${GitWorkbenchPanel_module_css_default.funnelBoundVal} ${GitWorkbenchPanel_module_css_default.funnelBoundValSet}` : GitWorkbenchPanel_module_css_default.funnelBoundVal,
16001
+ children: filterModel.after.length > 0 ? filterModel.after : "—"
16002
+ }),
16003
+ filterModel.after.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
16004
+ type: "button",
16005
+ className: GitWorkbenchPanel_module_css_default.funnelBoundClear,
16006
+ "aria-label": t("filterAfter"),
16007
+ onClick: () => applyFilter({
16008
+ ...filterModel,
16009
+ after: ""
16010
+ }),
16011
+ children: "×"
16012
+ }) : null
16013
+ ]
16014
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
16015
+ className: GitWorkbenchPanel_module_css_default.funnelBoundRow,
16016
+ children: [
16017
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16018
+ className: GitWorkbenchPanel_module_css_default.funnelBoundKey,
16019
+ children: t("filterBefore")
16020
+ }),
16021
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16022
+ className: filterModel.before.length > 0 ? `${GitWorkbenchPanel_module_css_default.funnelBoundVal} ${GitWorkbenchPanel_module_css_default.funnelBoundValSet}` : GitWorkbenchPanel_module_css_default.funnelBoundVal,
16023
+ children: filterModel.before.length > 0 ? filterModel.before : "—"
16024
+ }),
16025
+ filterModel.before.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
16026
+ type: "button",
16027
+ className: GitWorkbenchPanel_module_css_default.funnelBoundClear,
16028
+ "aria-label": t("filterBefore"),
16029
+ onClick: () => applyFilter({
16030
+ ...filterModel,
16031
+ before: ""
16032
+ }),
16033
+ children: "×"
16034
+ }) : null
16035
+ ]
16036
+ })]
16037
+ })
16038
+ ]
16039
+ }) : null,
16040
+ funnelSection === "paths" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16041
+ className: GitWorkbenchPanel_module_css_default.funnelPane,
16042
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
16043
+ className: GitWorkbenchPanel_module_css_default.funnelSearch,
16044
+ type: "search",
16045
+ value: pathsQuery,
16046
+ onChange: (event) => setPathsQuery(event.target.value),
16047
+ placeholder: t("filterPathSearch"),
16048
+ "aria-label": t("filterPathSearch"),
16049
+ spellCheck: false
16050
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16051
+ className: GitWorkbenchPanel_module_css_default.funnelList,
16052
+ children: [pathTree === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
16053
+ className: GitWorkbenchPanel_module_css_default.funnelMore,
16054
+ children: t("loading")
16055
+ }) : pathsQuery.trim().length > 0 ? (() => {
16056
+ const hits = searchPaths(pathTree.paths, pathsQuery).slice(0, 200);
16057
+ if (hits.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
16058
+ className: GitWorkbenchPanel_module_css_default.funnelMore,
16059
+ children: t("historyNoMatch")
16060
+ });
16061
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [hits.map((hit) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
16062
+ className: GitWorkbenchPanel_module_css_default.funnelRow,
16063
+ children: [
16064
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TriStateCheckbox, {
16065
+ state: pathState(hit.path),
16066
+ ariaLabel: hit.path,
16067
+ onChange: () => togglePath(hit.path)
16068
+ }),
16069
+ hit.isFile ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PathFileGlyph, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PathDirGlyph, {}),
16070
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16071
+ className: GitWorkbenchPanel_module_css_default.funnelName,
16072
+ title: hit.path,
16073
+ children: hit.path
16074
+ })
16075
+ ]
16076
+ }, hit.path)), searchPaths(pathTree.paths, pathsQuery).length > 200 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
16077
+ className: GitWorkbenchPanel_module_css_default.funnelMore,
16078
+ children: t("filterPathsMore")
16079
+ }) : null] });
16080
+ })() : pathTree.dirs.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
16081
+ className: GitWorkbenchPanel_module_css_default.funnelMore,
16082
+ children: t("noCommits")
16083
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PathTreeRows, {
16084
+ dirs: pathTree.dirs,
16085
+ depth: 0,
16086
+ expanded: expandedDirs,
16087
+ stateOf: pathState,
16088
+ onToggleOpen: toggleDirOpen,
16089
+ onTogglePath: togglePath
16090
+ }), pathTree?.truncated === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
16091
+ className: GitWorkbenchPanel_module_css_default.funnelMore,
16092
+ children: t("filterPathsMore")
16093
+ }) : null]
16094
+ })]
16095
+ }) : null,
16096
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16097
+ className: GitWorkbenchPanel_module_css_default.funnelFoot,
16098
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16099
+ className: selectedCount > 0 ? `${GitWorkbenchPanel_module_css_default.funnelFootCount} ${GitWorkbenchPanel_module_css_default.funnelFootCountOn}` : GitWorkbenchPanel_module_css_default.funnelFootCount,
16100
+ children: t("filterSelected", { count: selectedCount })
16101
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
16102
+ type: "button",
16103
+ className: GitWorkbenchPanel_module_css_default.funnelFootClear,
16104
+ disabled: selectedCount === 0,
16105
+ onClick: () => onQueryChange(""),
16106
+ children: t("filterClearAll")
16107
+ })]
16108
+ })
16109
+ ]
16110
+ }), funnelAnchorRef.current?.closest("[data-gs-part=\"overlay\"]") ?? (typeof document === "undefined" ? null : document.body)) : null,
16111
+ chips.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16112
+ className: GitWorkbenchPanel_module_css_default.filterChips,
16113
+ children: [chips.map((chip) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
16114
+ className: GitWorkbenchPanel_module_css_default.filterChip,
16115
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
16116
+ className: GitWorkbenchPanel_module_css_default.filterChipLabel,
16117
+ children: [
16118
+ chip.kind,
16119
+ ":",
16120
+ chip.value
16121
+ ]
16122
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
16123
+ type: "button",
16124
+ className: GitWorkbenchPanel_module_css_default.filterChipRemove,
16125
+ "aria-label": `${chip.kind} ${chip.value}`,
16126
+ onClick: () => onQueryChange(serializeLogQuery(removeChip(filterModel, chip.kind, chip.value))),
16127
+ children: "×"
16128
+ })]
16129
+ }, `${chip.kind}\x1f${chip.value}`)), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
16130
+ type: "button",
16131
+ className: GitWorkbenchPanel_module_css_default.filterClear,
16132
+ onClick: () => onQueryChange(""),
16133
+ children: t("filterClearAll")
16134
+ })]
16135
+ }) : null,
16136
+ commits.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
16137
+ className: GitWorkbenchPanel_module_css_default.empty,
16138
+ children: loading ? t("loading") : error !== null ? error : chips.length > 0 ? t("historyNoMatch") : t("noCommits")
16139
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16140
+ className: GitWorkbenchPanel_module_css_default.commits,
16141
+ role: "listbox",
16142
+ "aria-label": t("historyLabel"),
16143
+ ref: scrollRef,
16144
+ children: [
16145
+ commits.map((commit, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CommitRow, {
16146
+ t,
16147
+ commit,
16148
+ active: commit.hash === active,
16149
+ onSelect,
16150
+ graphRow: graph.rows[index],
16151
+ graphWidth: graph.width
16152
+ }, commit.hash)),
16153
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
16154
+ ref: sentinelRef,
16155
+ className: GitWorkbenchPanel_module_css_default.commitsSentinel
16156
+ }),
16157
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
16158
+ className: GitWorkbenchPanel_module_css_default.commitsFoot,
16159
+ children: loadingMore ? t("loading") : hasMore ? "" : t("historyEnd")
16160
+ })
16161
+ ]
14570
16162
  })
14571
- }), commits.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
14572
- className: GitWorkbenchPanel_module_css_default.empty,
14573
- children: loading ? t("loading") : t("noCommits")
14574
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
14575
- className: GitWorkbenchPanel_module_css_default.commits,
14576
- role: "listbox",
14577
- "aria-label": t("historyLabel"),
14578
- ref: scrollRef,
14579
- children: [
14580
- commits.map((commit, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CommitRow, {
14581
- t,
14582
- commit,
14583
- active: commit.hash === active,
14584
- onSelect,
14585
- graphRow: graph.rows[index],
14586
- graphWidth: graph.width
14587
- }, commit.hash)),
14588
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
14589
- ref: sentinelRef,
14590
- className: GitWorkbenchPanel_module_css_default.commitsSentinel
14591
- }),
14592
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
14593
- className: GitWorkbenchPanel_module_css_default.commitsFoot,
14594
- children: loadingMore ? t("loading") : hasMore ? "" : t("historyEnd")
14595
- })
14596
- ]
14597
- })]
16163
+ ]
14598
16164
  });
14599
16165
  }
14600
16166
  /** Horizontal step per nesting level. */
@@ -14697,8 +16263,23 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14697
16263
  dirs
14698
16264
  };
14699
16265
  }
14700
- function FileTree({ t, loading, lead, files, active, onSelect, collapsed, onCollapsedChange, onCheck, footer }) {
14701
- const tree = (0, react.useMemo)(() => buildTree(files), [files]);
16266
+ function FileTree({ t, loading, lead, files, active, onSelect, collapsed, onCollapsedChange, onCheck, onDiscard, footer, scopeKey }) {
16267
+ /**
16268
+ * The filter over this list. Local, because it describes a way of LOOKING at
16269
+ * the pane rather than anything the drawer stores: closing and reopening on
16270
+ * an unfiltered list is what someone expects, and a query kept in the panel
16271
+ * would have to be cleared from four places instead of one.
16272
+ */
16273
+ const [query, setQuery] = (0, react.useState)("");
16274
+ const [filterOpen, setFilterOpen] = (0, react.useState)(false);
16275
+ const filterRef = (0, react.useRef)(null);
16276
+ (0, react.useEffect)(() => {
16277
+ setQuery("");
16278
+ setFilterOpen(false);
16279
+ }, [scopeKey]);
16280
+ const shownFiles = (0, react.useMemo)(() => filterFiles(files, query), [files, query]);
16281
+ const filtering = shownFiles !== files;
16282
+ const tree = (0, react.useMemo)(() => buildTree(shownFiles), [shownFiles]);
14702
16283
  /** Default: a dir collapses when it holds more than 12 files anywhere below it. */
14703
16284
  const effective = collapsed ?? defaultCollapsed(tree);
14704
16285
  (0, react.useEffect)(() => {
@@ -14736,54 +16317,117 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14736
16317
  state: tree.check,
14737
16318
  label: tree.check === "on" ? t("unstageAll") : t("stageAll"),
14738
16319
  indent: 0,
14739
- onToggle: () => onCheck(files, tree.check)
16320
+ onToggle: () => onCheck(shownFiles, tree.check)
14740
16321
  }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
14741
16322
  className: GitWorkbenchPanel_module_css_default.treeLabel,
14742
- children: loading === true ? t("loading") : `${lead !== void 0 ? `${lead} · ` : ""}${t("files", { count: files.length })}`
16323
+ children: loading === true ? t("loading") : `${lead !== void 0 ? `${lead} · ` : ""}${filtering ? t("filesFiltered", {
16324
+ shown: shownFiles.length,
16325
+ count: files.length
16326
+ }) : t("files", { count: files.length })}`
14743
16327
  })]
14744
16328
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
14745
16329
  className: GitWorkbenchPanel_module_css_default.treeActions,
14746
16330
  "data-gs-part": "tree-actions",
14747
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
14748
- type: "button",
14749
- className: GitWorkbenchPanel_module_css_default.treeIcon,
14750
- "data-gs-part": "expand-all",
14751
- title: t("expandAll"),
14752
- "aria-label": t("expandAll"),
14753
- onClick: () => setAll(true),
14754
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
14755
- className: `${GitWorkbenchPanel_module_css_default.treeIconGlyph} ${GitWorkbenchPanel_module_css_default.treeIconDown}`,
14756
- children: "▸"
14757
- })
14758
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
14759
- type: "button",
14760
- className: GitWorkbenchPanel_module_css_default.treeIcon,
14761
- "data-gs-part": "collapse-all",
14762
- title: t("collapseAll"),
14763
- "aria-label": t("collapseAll"),
14764
- onClick: () => setAll(false),
14765
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
14766
- className: GitWorkbenchPanel_module_css_default.treeIconGlyph,
14767
- children: ""
16331
+ children: [
16332
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
16333
+ type: "button",
16334
+ className: filterOpen || filtering ? `${GitWorkbenchPanel_module_css_default.treeIcon} ${GitWorkbenchPanel_module_css_default.treeIconOn}` : GitWorkbenchPanel_module_css_default.treeIcon,
16335
+ "data-gs-part": "filter-files",
16336
+ title: t("filterFiles"),
16337
+ "aria-label": t("filterFiles"),
16338
+ "aria-pressed": filterOpen,
16339
+ onClick: () => {
16340
+ if (filterOpen) {
16341
+ setQuery("");
16342
+ setFilterOpen(false);
16343
+ return;
16344
+ }
16345
+ setFilterOpen(true);
16346
+ window.setTimeout(() => filterRef.current?.focus(), 0);
16347
+ },
16348
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FilterGlyph, {})
16349
+ }),
16350
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
16351
+ type: "button",
16352
+ className: GitWorkbenchPanel_module_css_default.treeIcon,
16353
+ "data-gs-part": "expand-all",
16354
+ title: t("expandAll"),
16355
+ "aria-label": t("expandAll"),
16356
+ onClick: () => setAll(true),
16357
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16358
+ className: `${GitWorkbenchPanel_module_css_default.treeIconGlyph} ${GitWorkbenchPanel_module_css_default.treeIconDown}`,
16359
+ children: "▸"
16360
+ })
16361
+ }),
16362
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
16363
+ type: "button",
16364
+ className: GitWorkbenchPanel_module_css_default.treeIcon,
16365
+ "data-gs-part": "collapse-all",
16366
+ title: t("collapseAll"),
16367
+ "aria-label": t("collapseAll"),
16368
+ onClick: () => setAll(false),
16369
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16370
+ className: GitWorkbenchPanel_module_css_default.treeIconGlyph,
16371
+ children: "▸"
16372
+ })
14768
16373
  })
14769
- })]
16374
+ ]
14770
16375
  })]
14771
16376
  }),
16377
+ filterOpen ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16378
+ className: GitWorkbenchPanel_module_css_default.treeFilter,
16379
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
16380
+ ref: filterRef,
16381
+ className: GitWorkbenchPanel_module_css_default.treeFilterInput,
16382
+ type: "text",
16383
+ value: query,
16384
+ placeholder: t("filterFilesPlaceholder"),
16385
+ "aria-label": t("filterFiles"),
16386
+ spellCheck: false,
16387
+ onChange: (event) => setQuery(event.target.value),
16388
+ onKeyDown: (event) => {
16389
+ if (event.key !== "Escape") return;
16390
+ if (query.length > 0) {
16391
+ event.stopPropagation();
16392
+ setQuery("");
16393
+ return;
16394
+ }
16395
+ event.stopPropagation();
16396
+ setFilterOpen(false);
16397
+ }
16398
+ }), query.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
16399
+ type: "button",
16400
+ className: GitWorkbenchPanel_module_css_default.treeFilterClear,
16401
+ title: t("filterFilesClear"),
16402
+ "aria-label": t("filterFilesClear"),
16403
+ onClick: () => {
16404
+ setQuery("");
16405
+ filterRef.current?.focus();
16406
+ },
16407
+ children: "×"
16408
+ }) : null]
16409
+ }) : null,
14772
16410
  loading === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
14773
16411
  className: GitWorkbenchPanel_module_css_default.treeEmpty,
14774
16412
  "data-gs-part": "tree-loading",
14775
16413
  children: t("loading")
16414
+ }) : filtering && shownFiles.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
16415
+ className: GitWorkbenchPanel_module_css_default.treeEmpty,
16416
+ "data-gs-part": "tree-no-match",
16417
+ children: t("filterNoMatch")
14776
16418
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
14777
16419
  className: GitWorkbenchPanel_module_css_default.tree,
14778
16420
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TreeChildren, {
14779
16421
  node: tree,
14780
16422
  depth: 0,
14781
16423
  active,
14782
- collapsed: effective,
16424
+ collapsed: filtering ? EMPTY_COLLAPSED : effective,
14783
16425
  onToggle: toggleOne,
14784
16426
  onSelect,
14785
16427
  onCheck,
14786
- stageLabels
16428
+ onDiscard,
16429
+ stageLabels,
16430
+ discardLabel: t("discardAction")
14787
16431
  })
14788
16432
  }),
14789
16433
  footer
@@ -14847,7 +16491,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14847
16491
  for (const child of node.dirs.values()) out.push(...filesUnder(child));
14848
16492
  return out;
14849
16493
  }
14850
- function TreeChildren({ node, depth, active, collapsed, onToggle, onSelect, onCheck, stageLabels }) {
16494
+ function TreeChildren({ node, depth, active, collapsed, onToggle, onSelect, onCheck, onDiscard, stageLabels, discardLabel }) {
14851
16495
  const dirNodes = [...node.dirs.values()].sort((a, b) => a.name.localeCompare(b.name));
14852
16496
  const fileNodes = [...node.files].sort((a, b) => basePart(a.path).localeCompare(basePart(b.path)));
14853
16497
  const checkColumn = onCheck !== void 0 ? TREE_CHECK_W : 0;
@@ -14875,6 +16519,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14875
16519
  className: `${GitWorkbenchPanel_module_css_default.chevron} ${open ? GitWorkbenchPanel_module_css_default.chevronOpen : ""}`,
14876
16520
  children: "▸"
14877
16521
  }),
16522
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PathDirGlyph, {}),
14878
16523
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
14879
16524
  className: GitWorkbenchPanel_module_css_default.treeDirName,
14880
16525
  children: dir.name
@@ -14906,7 +16551,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14906
16551
  onToggle,
14907
16552
  onSelect,
14908
16553
  onCheck,
14909
- stageLabels
16554
+ onDiscard,
16555
+ stageLabels,
16556
+ discardLabel
14910
16557
  })
14911
16558
  }) : null]
14912
16559
  }, dir.path);
@@ -14914,45 +16561,60 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14914
16561
  const check = fileCheckState(file);
14915
16562
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
14916
16563
  className: GitWorkbenchPanel_module_css_default.fileLi,
14917
- children: [onCheck !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckBox, {
14918
- state: check,
14919
- label: check === "on" ? stageLabels.unstage : stageLabels.stage,
14920
- indent,
14921
- onToggle: () => onCheck([file], check)
14922
- }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
14923
- type: "button",
14924
- className: active === file.path ? `${GitWorkbenchPanel_module_css_default.file} ${GitWorkbenchPanel_module_css_default.fileActive}` : GitWorkbenchPanel_module_css_default.file,
14925
- style: { paddingLeft: (onCheck !== void 0 ? 0 : indent) + TREE_LEAF_OFFSET },
14926
- onClick: () => onSelect(file.path),
14927
- title: file.previousPath !== void 0 ? `${file.previousPath} ${file.path}` : file.path,
14928
- children: [
14929
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
14930
- className: `${GitWorkbenchPanel_module_css_default.fileStatus} ${STATUS_BADGE[file.status]}`,
14931
- children: statusGlyph(file.status)
14932
- }),
14933
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
14934
- className: GitWorkbenchPanel_module_css_default.filePath,
14935
- children: basePart(file.path)
14936
- }),
14937
- file.binary ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
14938
- className: GitWorkbenchPanel_module_css_default.fileBinary,
14939
- children: "BIN"
14940
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
14941
- className: GitWorkbenchPanel_module_css_default.fileCounts,
14942
- children: [
14943
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
14944
- className: GitWorkbenchPanel_module_css_default.fileCountAdd,
14945
- children: file.addedLines > 0 ? `+${file.addedLines}` : ""
14946
- }),
14947
- " ",
14948
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
14949
- className: GitWorkbenchPanel_module_css_default.fileCountDel,
14950
- children: file.deletedLines > 0 ? `−${file.deletedLines}` : ""
14951
- })
14952
- ]
14953
- })
14954
- ]
14955
- })]
16564
+ children: [
16565
+ onCheck !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckBox, {
16566
+ state: check,
16567
+ label: check === "on" ? stageLabels.unstage : stageLabels.stage,
16568
+ indent,
16569
+ onToggle: () => onCheck([file], check)
16570
+ }) : null,
16571
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
16572
+ type: "button",
16573
+ className: active === file.path ? `${GitWorkbenchPanel_module_css_default.file} ${GitWorkbenchPanel_module_css_default.fileActive}` : GitWorkbenchPanel_module_css_default.file,
16574
+ style: { paddingLeft: (onCheck !== void 0 ? 0 : indent) + TREE_LEAF_OFFSET },
16575
+ onClick: () => onSelect(file.path),
16576
+ title: file.previousPath !== void 0 ? `${file.previousPath} → ${file.path}` : file.path,
16577
+ children: [
16578
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PathFileGlyph, {}),
16579
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16580
+ className: GitWorkbenchPanel_module_css_default.filePath,
16581
+ children: basePart(file.path)
16582
+ }),
16583
+ file.binary ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16584
+ className: GitWorkbenchPanel_module_css_default.fileBinary,
16585
+ children: "BIN"
16586
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
16587
+ className: GitWorkbenchPanel_module_css_default.fileCounts,
16588
+ children: [
16589
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16590
+ className: GitWorkbenchPanel_module_css_default.fileCountAdd,
16591
+ children: file.addedLines > 0 ? `+${file.addedLines}` : ""
16592
+ }),
16593
+ " ",
16594
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16595
+ className: GitWorkbenchPanel_module_css_default.fileCountDel,
16596
+ children: file.deletedLines > 0 ? `−${file.deletedLines}` : ""
16597
+ })
16598
+ ]
16599
+ }),
16600
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
16601
+ className: `${GitWorkbenchPanel_module_css_default.fileStatus} ${STATUS_BADGE[file.status]}`,
16602
+ children: statusGlyph(file.status)
16603
+ })
16604
+ ]
16605
+ }),
16606
+ onDiscard !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
16607
+ type: "button",
16608
+ className: GitWorkbenchPanel_module_css_default.fileDiscard,
16609
+ title: discardLabel,
16610
+ "aria-label": `${discardLabel ?? ""} ${file.path}`,
16611
+ onClick: (event) => {
16612
+ event.stopPropagation();
16613
+ onDiscard(file);
16614
+ },
16615
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RollbackGlyph, {})
16616
+ }) : null
16617
+ ]
14956
16618
  }, file.path);
14957
16619
  })] });
14958
16620
  }
@@ -15134,8 +16796,36 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15134
16796
  noTextDiff: "无文本差异",
15135
16797
  noCommits: "无提交历史",
15136
16798
  historyLabel: "提交历史",
16799
+ commitAuthor: "作者",
16800
+ commitCommitter: "提交者",
16801
+ commitDate: "提交时间",
16802
+ historyFilterPlaceholder: "筛选:user: 名字 / path: 路径 / after: 日期 / 关键词",
16803
+ historyNoMatch: "没有匹配的提交",
16804
+ filterClearAll: "清除全部",
16805
+ filterBy: "筛选条件",
16806
+ filterUsers: "用户",
16807
+ filterUserSearch: "搜索作者",
16808
+ filterAuthorsMore: "仅显示提交最多的 500 位作者",
16809
+ filterDate: "日期",
16810
+ filterToday: "今天",
16811
+ filterLast7: "最近 7 天",
16812
+ filterLast30: "最近 30 天",
16813
+ filterAfter: "之后",
16814
+ filterBefore: "之前",
16815
+ filterPaths: "路径",
16816
+ filterPathsMore: "文件过多,目录树已截断",
16817
+ filterPathSearch: "搜索文件或目录",
16818
+ filterCalendarSets: "日历写入",
16819
+ filterSelected: "已选 {count} 项",
16820
+ filterLocale: "zh-CN",
16821
+ allBranches: "全部分支",
15137
16822
  expandAll: "展开全部",
15138
16823
  collapseAll: "收起全部",
16824
+ filterFiles: "过滤文件",
16825
+ filterFilesPlaceholder: "过滤文件,空格分隔多个关键字",
16826
+ filterFilesClear: "清除过滤",
16827
+ filesFiltered: "{shown} / {count} 文件",
16828
+ filterNoMatch: "没有匹配的文件",
15139
16829
  noBranch: "(无分支)",
15140
16830
  copyCommit: "复制提交说明",
15141
16831
  copiedCommit: "已复制",
@@ -15169,6 +16859,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15169
16859
  "op.ok.fetch": "已获取远端信息",
15170
16860
  "op.ok.pull": "拉取完成",
15171
16861
  "op.ok.push": "推送成功",
16862
+ "op.ok.discardFile": "已撤回",
16863
+ discardAction: "撤回改动",
16864
+ discardTitle: "撤回改动?",
16865
+ discardConfirm: "撤回",
16866
+ discardCancel: "取消",
16867
+ discardBodyRestore: "{path} 将还原成上次提交时的样子。这里的 {added} 行新增、{deleted} 行删除无法找回。",
16868
+ discardBodyDelete: "{path} 从未被 git 记录过,删除后无法找回。",
16869
+ discardBodyUnrename: "撤销重命名:{path} 改回 {previousPath},改名期间的内容改动一并丢弃。",
15172
16870
  "op.fail.auth": "认证失败。凭据提示已被禁用,请先在终端里配置好凭据再重试。",
15173
16871
  "op.fail.network": "网络不可达:主机名解析失败或连接不上。检查网络与远程地址后重试。",
15174
16872
  "op.fail.no-upstream": "当前分支没有上游分支。",
@@ -15245,8 +16943,36 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15245
16943
  noTextDiff: "No text changes",
15246
16944
  noCommits: "No commit history",
15247
16945
  historyLabel: "Commit history",
16946
+ commitAuthor: "Author",
16947
+ commitCommitter: "Committer",
16948
+ commitDate: "Committed",
16949
+ historyFilterPlaceholder: "Filter: user: name / path: dir / after: date / text",
16950
+ historyNoMatch: "No matching commits",
16951
+ filterClearAll: "Clear all",
16952
+ filterBy: "Filter by",
16953
+ filterUsers: "Users",
16954
+ filterUserSearch: "Search authors",
16955
+ filterAuthorsMore: "Showing the 500 busiest authors only",
16956
+ filterDate: "Date",
16957
+ filterToday: "Today",
16958
+ filterLast7: "Last 7 days",
16959
+ filterLast30: "Last 30 days",
16960
+ filterAfter: "After",
16961
+ filterBefore: "Before",
16962
+ filterPaths: "Paths",
16963
+ filterPathsMore: "Too many files — tree truncated",
16964
+ filterPathSearch: "Search files or folders",
16965
+ filterCalendarSets: "Calendar sets",
16966
+ filterSelected: "{count} selected",
16967
+ filterLocale: "en-US",
16968
+ allBranches: "All branches",
15248
16969
  expandAll: "Expand all",
15249
16970
  collapseAll: "Collapse all",
16971
+ filterFiles: "Filter files",
16972
+ filterFilesPlaceholder: "Filter files; space-separated terms",
16973
+ filterFilesClear: "Clear filter",
16974
+ filesFiltered: "{shown} / {count} files",
16975
+ filterNoMatch: "No file matches",
15250
16976
  noBranch: "(no branch)",
15251
16977
  copyCommit: "Copy message",
15252
16978
  copiedCommit: "Copied",
@@ -15280,6 +17006,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15280
17006
  "op.ok.fetch": "Fetched",
15281
17007
  "op.ok.pull": "Pulled",
15282
17008
  "op.ok.push": "Pushed",
17009
+ "op.ok.discardFile": "Rolled back",
17010
+ discardAction: "Roll back changes",
17011
+ discardTitle: "Roll back changes?",
17012
+ discardConfirm: "Roll back",
17013
+ discardCancel: "Cancel",
17014
+ discardBodyRestore: "{path} goes back to its committed content. The {added} added and {deleted} deleted lines here cannot be recovered.",
17015
+ discardBodyDelete: "{path} was never recorded by git. Deleting it cannot be undone.",
17016
+ discardBodyUnrename: "Undo the rename: {path} goes back to {previousPath}, and content changed along the way is lost.",
15283
17017
  "op.fail.auth": "Authentication failed. Credential prompts are disabled here — set your credentials up in a terminal first.",
15284
17018
  "op.fail.network": "The network was unreachable — the host could not be resolved or the connection failed. Check connectivity and the remote URL, then retry.",
15285
17019
  "op.fail.no-upstream": "This branch has no upstream.",
@@ -15334,15 +17068,27 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15334
17068
  } }, signal);
15335
17069
  return result.ok ? result.value : null;
15336
17070
  },
15337
- fetchCommits: async (worktreePath, ref, skip, limit, signal) => {
17071
+ fetchCommits: async (worktreePath, ref, skip, limit, filter, signal) => {
15338
17072
  const result = await connection.rpc.call("/api", "gitWorkbench/commits", { args: {
15339
17073
  worktreePath: worktreePath ?? "",
15340
17074
  ref,
15341
17075
  skip,
15342
- limit
17076
+ limit,
17077
+ filter
17078
+ } }, signal);
17079
+ return result.ok ? result.value : null;
17080
+ },
17081
+ fetchAuthors: async (worktreePath, ref, signal) => {
17082
+ const result = await connection.rpc.call("/api", "gitWorkbench/authors", { args: {
17083
+ worktreePath: worktreePath ?? "",
17084
+ ref
15343
17085
  } }, signal);
15344
17086
  return result.ok ? result.value : null;
15345
17087
  },
17088
+ fetchRepoTree: async (worktreePath, signal) => {
17089
+ const result = await connection.rpc.call("/api", "gitWorkbench/repoTree", { args: { worktreePath: worktreePath ?? "" } }, signal);
17090
+ return result.ok ? result.value : null;
17091
+ },
15346
17092
  fetchCompare: async (worktreePath, base, head, signal) => {
15347
17093
  const result = await connection.rpc.call("/api", "gitWorkbench/compareRefs", { args: {
15348
17094
  worktreePath: worktreePath ?? "",
@@ -15382,6 +17128,13 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15382
17128
  const result = await connection.rpc.call("/api", "gitWorkbench/syncStatus", { args: { worktreePath: worktreePath ?? "" } }, signal);
15383
17129
  return result.ok ? result.value : null;
15384
17130
  },
17131
+ fetchDiscardPlan: async (worktreePath, path, signal) => {
17132
+ const result = await connection.rpc.call("/api", "gitWorkbench/discardPlan", { args: {
17133
+ worktreePath: worktreePath ?? "",
17134
+ path
17135
+ } }, signal);
17136
+ return result.ok ? result.value : null;
17137
+ },
15385
17138
  runGitOp: async (op, worktreePath, payload, signal) => {
15386
17139
  const result = await connection.rpc.call("/api", `gitWorkbench/${op}`, { args: {
15387
17140
  worktreePath: worktreePath ?? "",