dsh-ui-tweaks 0.10.1 → 0.10.3

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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 dsh-ui-tweaks contributors
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 dsh-ui-tweaks contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/cordis.patch.yml CHANGED
@@ -1,12 +1,12 @@
1
- # dsh-ui-tweaks bundle patch
2
- #
3
- # Declared by `dsh.bundle.patch` in package.json: when the plugin is installed
4
- # through the official CLI —
5
- #
6
- # dsh plugin --profile <name> add dsh-ui-tweaks
7
- #
8
- # — the command appends `dsh-ui-tweaks` to the profile's bundle stack and this
9
- # patch mounts the server-side plugin row.
10
- - insert:
11
- - id: ui-tweaks
12
- name: 'dsh-ui-tweaks'
1
+ # dsh-ui-tweaks bundle patch
2
+ #
3
+ # Declared by `dsh.bundle.patch` in package.json: when the plugin is installed
4
+ # through the official CLI —
5
+ #
6
+ # dsh plugin --profile <name> add dsh-ui-tweaks
7
+ #
8
+ # — the command appends `dsh-ui-tweaks` to the profile's bundle stack and this
9
+ # patch mounts the server-side plugin row.
10
+ - insert:
11
+ - id: ui-tweaks
12
+ name: 'dsh-ui-tweaks'
package/lib/client.js CHANGED
@@ -107,27 +107,27 @@ function relativeTime(ms, now, formatter) {
107
107
  return formatter.format(Math.round(diffSeconds / 86400), 'day');
108
108
  return formatter.format(Math.round(diffSeconds / 604800), 'week');
109
109
  }
110
- exports.ARCHIVE_CSS = `
111
- .dut-arc{display:grid;gap:12px;max-width:680px;padding:6px 2px 36px}
112
- .dut-arc-head{display:flex;align-items:center;gap:10px;padding:14px 16px 0}
113
- .dut-arc-head h2{margin:0;font-size:15px;font-weight:600;letter-spacing:-.01em;color:var(--dsw-alias-label-primary)}
114
- .dut-arc-count{font-size:11.5px;color:var(--dsw-alias-label-secondary);padding:2px 8px;border-radius:999px;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1)}
115
- .dut-arc-spacer{flex:1}
116
- .dut-arc-btn{display:inline-flex;align-items:center;height:28px;padding:0 12px;border-radius:999px;border:1px solid var(--dsw-alias-border-l1);background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;cursor:pointer;transition:background .15s ease,color .15s ease,border-color .15s ease}
117
- .dut-arc-btn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
118
- .dut-arc-btn:disabled{opacity:.5;cursor:default}
119
- .dut-arc-btn.dut-arc-del:hover{border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 55%,transparent);color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}
120
- .dut-arc-btn.dut-arc-confirm{border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 55%,transparent);color:var(--dsw-alias-state-error-primary);font-weight:600}
121
- .dut-arc-body{display:grid;gap:2px;margin-top:4px}
122
- .dut-arc-row{display:flex;align-items:center;gap:8px;padding:10px 16px;border-radius:12px}
123
- .dut-arc-row:hover{background:var(--dsw-alias-interactive-bg-hover)}
124
- .dut-arc-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;text-align:left;background:transparent;border:none;padding:0;cursor:default;color:var(--dsw-alias-label-primary);font:inherit}
125
- .dut-arc-title{font-size:13.5px;font-weight:600;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}
126
- .dut-arc-sub{font-size:11.5px;color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}
127
- .dut-arc-empty{padding:32px 16px;text-align:center;font-size:12.5px;color:var(--dsw-alias-label-secondary)}
128
- .dut-arc-alert{margin:8px 16px 0;padding:8px 12px;border-radius:10px;font-size:12px;line-height:1.5;background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent);color:var(--dsw-alias-state-error-primary)}
129
- .dut-arc-off{padding:20px 16px;display:grid;gap:12px}
130
- .dut-arc-off p{margin:0;font-size:12.5px;line-height:1.6;color:var(--dsw-alias-label-secondary)}
110
+ exports.ARCHIVE_CSS = `
111
+ .dut-arc{display:grid;gap:12px;max-width:680px;padding:6px 2px 36px}
112
+ .dut-arc-head{display:flex;align-items:center;gap:10px;padding:14px 16px 0}
113
+ .dut-arc-head h2{margin:0;font-size:15px;font-weight:600;letter-spacing:-.01em;color:var(--dsw-alias-label-primary)}
114
+ .dut-arc-count{font-size:11.5px;color:var(--dsw-alias-label-secondary);padding:2px 8px;border-radius:999px;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1)}
115
+ .dut-arc-spacer{flex:1}
116
+ .dut-arc-btn{display:inline-flex;align-items:center;height:28px;padding:0 12px;border-radius:999px;border:1px solid var(--dsw-alias-border-l1);background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;cursor:pointer;transition:background .15s ease,color .15s ease,border-color .15s ease}
117
+ .dut-arc-btn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
118
+ .dut-arc-btn:disabled{opacity:.5;cursor:default}
119
+ .dut-arc-btn.dut-arc-del:hover{border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 55%,transparent);color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}
120
+ .dut-arc-btn.dut-arc-confirm{border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 55%,transparent);color:var(--dsw-alias-state-error-primary);font-weight:600}
121
+ .dut-arc-body{display:grid;gap:2px;margin-top:4px}
122
+ .dut-arc-row{display:flex;align-items:center;gap:8px;padding:10px 16px;border-radius:12px}
123
+ .dut-arc-row:hover{background:var(--dsw-alias-interactive-bg-hover)}
124
+ .dut-arc-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;text-align:left;background:transparent;border:none;padding:0;cursor:default;color:var(--dsw-alias-label-primary);font:inherit}
125
+ .dut-arc-title{font-size:13.5px;font-weight:600;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}
126
+ .dut-arc-sub{font-size:11.5px;color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}
127
+ .dut-arc-empty{padding:32px 16px;text-align:center;font-size:12.5px;color:var(--dsw-alias-label-secondary)}
128
+ .dut-arc-alert{margin:8px 16px 0;padding:8px 12px;border-radius:10px;font-size:12px;line-height:1.5;background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent);color:var(--dsw-alias-state-error-primary)}
129
+ .dut-arc-off{padding:20px 16px;display:grid;gap:12px}
130
+ .dut-arc-off p{margin:0;font-size:12.5px;line-height:1.6;color:var(--dsw-alias-label-secondary)}
131
131
  `;
132
132
  /** Install the Archive stylesheet once (idempotent); returns the disposer. */
133
133
  function installArchiveStyles() {
@@ -224,6 +224,8 @@ __modules["./gitbar.js"] = function(module, exports, require, __load_) {
224
224
  Object.defineProperty(exports, "__esModule", { value: true });
225
225
  exports.GITBAR_CSS = void 0;
226
226
  exports.installGitBarStyles = installGitBarStyles;
227
+ exports.warmGitStatus = warmGitStatus;
228
+ exports.GitWarmup = GitWarmup;
227
229
  exports.BranchChipEntry = BranchChipEntry;
228
230
  exports.DiffPanel = DiffPanel;
229
231
  exports.TerminalPanel = TerminalPanel;
@@ -884,6 +886,55 @@ function statusClass(status) {
884
886
  * panel paint instantly instead of waiting for its own /status round-trip.
885
887
  */
886
888
  const snapshotCache = new Map();
889
+ // A localStorage mirror of this cache existed briefly and was retired; sweep
890
+ // away any copy an older build left behind in this browser.
891
+ try {
892
+ window.localStorage.removeItem('dsh-ui-tweaks.git.snapshots.v1');
893
+ }
894
+ catch { /* storage unavailable */ }
895
+ /** In-flight warmups keyed by target, so the dock warmup and a mounting chip
896
+ * never double-fetch the same target. */
897
+ const warmInflight = new Map();
898
+ /**
899
+ * Fetch a target's status into the shared cache WITHOUT rendering anything.
900
+ *
901
+ * The session-header chips mount only after the conversation projection
902
+ * finishes loading — seconds on large inactive sessions — so their own fetch
903
+ * would start just as late. This warmup runs from the input dock, which mounts
904
+ * immediately on session switch: by the time the header chip appears it reads
905
+ * a warm cache and paints folder+branch instantly.
906
+ */
907
+ function warmGitStatus(target) {
908
+ const key = target.session ?? target.ws ?? '';
909
+ if (key === '' || snapshotCache.has(key) || warmInflight.has(key))
910
+ return;
911
+ const flight = apiGet(`${GIT_ROUTE}/status?${targetQuery(target)}`)
912
+ .then(next => {
913
+ // An unresolved answer (host still starting up) must not poison the
914
+ // cache as a final "not a repo"; the mounting chip re-fetches anyway.
915
+ if (!next.unresolved)
916
+ snapshotCache.set(key, next);
917
+ })
918
+ .catch(() => {
919
+ // Warmup is best-effort; the mounting chip re-fetches anyway.
920
+ })
921
+ .finally(() => { warmInflight.delete(key); });
922
+ warmInflight.set(key, flight);
923
+ }
924
+ /** Input-dock seat for {@link warmGitStatus}: mounts immediately on session
925
+ * switch (long before the session header does) and kicks off the prefetch. */
926
+ function GitWarmup({ sessionId }) {
927
+ (0, react_1.useEffect)(() => {
928
+ warmGitStatus({ session: String(sessionId) });
929
+ }, [sessionId]);
930
+ return null;
931
+ }
932
+ /** Fast retry steps (ms) for the startup race: right after a restart the host
933
+ * has not materialized its session/workspace store yet, so the first /status
934
+ * answers `unresolved`. Without these the UI sat blank for a full POLL_MS. */
935
+ const RETRY_DELAYS_MS = [400, 800, 1600, 3200];
936
+ /** Upper bound on fast retries before falling back to the steady poll. */
937
+ const FAST_RETRY_MAX = 6;
887
938
  /** Load the git snapshot on session change, then poll; returns [snapshot, refresh]. */
888
939
  function useGitStatus(enabled, target) {
889
940
  const key = target.session ?? target.ws ?? '';
@@ -897,27 +948,63 @@ function useGitStatus(enabled, target) {
897
948
  // A remount (panel open) must not regress to blank when the cache is warm.
898
949
  setSnapshot(snapshotCache.get(key) ?? null);
899
950
  let cancelled = false;
900
- let timer;
901
- const refresh = async () => {
951
+ let pollTimer;
952
+ let retryTimer;
953
+ let attempt = 0;
954
+ // Whether a resolved snapshot exists for this target (cache or fetched).
955
+ // Drives the cold-start chase: fast backoff only while it is false.
956
+ let haveGood = snapshotCache.has(key);
957
+ /** Store one fetch result. An `unresolved` answer is transient — never
958
+ * cached, never regressing an already-good snapshot. Returns whether a
959
+ * resolved answer landed. */
960
+ const apply = (next) => {
961
+ if (next.unresolved === true) {
962
+ if (!cancelled && !haveGood)
963
+ setSnapshot(null);
964
+ return false;
965
+ }
966
+ haveGood = true;
967
+ attempt = 0;
968
+ snapshotCache.set(key, next);
969
+ if (!cancelled)
970
+ setSnapshot(next);
971
+ return true;
972
+ };
973
+ const refreshOnce = async () => {
902
974
  try {
903
- const next = await apiGet(`${GIT_ROUTE}/status?${targetQuery(target)}`);
904
- snapshotCache.set(key, next);
905
- if (!cancelled)
906
- setSnapshot(next);
975
+ return apply(await apiGet(`${GIT_ROUTE}/status?${targetQuery(target)}`));
907
976
  }
908
977
  catch {
909
- // Transient git failure: keep the previous snapshot.
978
+ // Transport/transient git failure: chase it too while no good snapshot
979
+ // exists; afterwards keep showing the old one until the next poll.
980
+ return haveGood;
910
981
  }
911
982
  };
912
- void refresh();
913
- timer = window.setInterval(() => {
983
+ /** Cold-start chase: short backoff instead of idling a whole poll period. */
984
+ const scheduleRetry = () => {
985
+ if (cancelled || haveGood || attempt >= FAST_RETRY_MAX)
986
+ return;
987
+ const delay = RETRY_DELAYS_MS[Math.min(attempt, RETRY_DELAYS_MS.length - 1)] ?? 3200;
988
+ attempt += 1;
989
+ retryTimer = window.setTimeout(() => {
990
+ if (cancelled)
991
+ return;
992
+ void refreshOnce().then(settled => { if (!settled)
993
+ scheduleRetry(); });
994
+ }, delay);
995
+ };
996
+ void refreshOnce().then(settled => { if (!settled)
997
+ scheduleRetry(); });
998
+ pollTimer = window.setInterval(() => {
914
999
  if (document.visibilityState === 'visible')
915
- void refresh();
1000
+ void refreshOnce();
916
1001
  }, POLL_MS);
917
1002
  return () => {
918
1003
  cancelled = true;
919
- if (timer !== undefined)
920
- clearInterval(timer);
1004
+ if (pollTimer !== undefined)
1005
+ clearInterval(pollTimer);
1006
+ if (retryTimer !== undefined)
1007
+ clearTimeout(retryTimer);
921
1008
  };
922
1009
  }, [enabled, key]);
923
1010
  const refresh = (0, react_1.useCallback)(async () => {
@@ -925,8 +1012,12 @@ function useGitStatus(enabled, target) {
925
1012
  return;
926
1013
  try {
927
1014
  const next = await apiGet(`${GIT_ROUTE}/status?${targetQuery(target)}`);
928
- snapshotCache.set(key, next);
929
- setSnapshot(next);
1015
+ // Same rule as the hook body: an unresolved answer is transient and must
1016
+ // not evict a good snapshot or enter the cache.
1017
+ if (!next.unresolved) {
1018
+ snapshotCache.set(key, next);
1019
+ setSnapshot(next);
1020
+ }
930
1021
  }
931
1022
  catch {
932
1023
  // Keep the previous snapshot on transient failures.
@@ -934,11 +1025,17 @@ function useGitStatus(enabled, target) {
934
1025
  }, [target.session, target.ws]);
935
1026
  return [snapshot, refresh];
936
1027
  }
937
- function BranchChipEntry({ sessionId, controller, t }) {
1028
+ function BranchChipEntry({ sessionId, sessionsService, controller, t }) {
938
1029
  const settingsState = (0, react_1.useSyncExternalStore)(controller.subscribe, controller.getSnapshot, controller.getSnapshot);
939
1030
  const enabled = settingsState.value?.gitBarEnabled ?? true;
940
1031
  const sessionStr = String(sessionId);
941
1032
  const target = { session: sessionStr };
1033
+ // Folder straight off the live sessions list feed (the same rows the left
1034
+ // sidebar shows) — zero network, correct from the very first paint even
1035
+ // before /status answers.
1036
+ const list = sessionsService.list;
1037
+ const subscribeList = (0, react_1.useMemo)(() => list.subscribe.bind(list), [list]);
1038
+ const feedCwd = (0, react_1.useSyncExternalStore)(subscribeList, () => list.getSnapshot().byId[sessionId]?.cwd, () => undefined);
942
1039
  const [snapshot, refresh] = useGitStatus(enabled, target);
943
1040
  const [branchOpen, setBranchOpen] = (0, react_1.useState)(false);
944
1041
  const [branches, setBranches] = (0, react_1.useState)(null);
@@ -1110,10 +1207,23 @@ function BranchChipEntry({ sessionId, controller, t }) {
1110
1207
  }, [branchOpen]);
1111
1208
  if (!enabled || sessionStr === undefined)
1112
1209
  return null;
1113
- if (snapshot === null || !snapshot.isRepo)
1210
+ // A genuine non-repo directory hides the chip entirely. An UNRESOLVED target
1211
+ // (host still materializing sessions right after a restart) is transient:
1212
+ // fall through to the folder-only paint below instead of going blank.
1213
+ if (snapshot !== null && snapshot.unresolved !== true && !snapshot.isRepo)
1114
1214
  return null;
1215
+ // While the first /status round-trip is in flight — or while the host has
1216
+ // not resolved this session yet — paint the folder alone straight off the
1217
+ // sessions-list feed (the sidebar's own rows — zero network, so it appears
1218
+ // the moment the sidebar row does); the branch capsule joins as soon as the
1219
+ // backoff chase lands a real snapshot.
1220
+ if (snapshot === null || snapshot.unresolved === true) {
1221
+ if (feedCwd === undefined || feedCwd === '')
1222
+ return null;
1223
+ return ((0, jsx_runtime_1.jsx)("span", { className: "gbar", "data-slot-plugin": "dsh-ui-tweaks-gitbar", children: (0, jsx_runtime_1.jsxs)("span", { className: "gbar-fchip", title: feedCwd, children: [(0, jsx_runtime_1.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("path", { d: "M1.5 4A1.5 1.5 0 0 1 3 2.5h3l1.5 2H13A1.5 1.5 0 0 1 14.5 6v6A1.5 1.5 0 0 1 13 13.5H3A1.5 1.5 0 0 1 1.5 12V4Z" }) }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-folder", children: basenameOf(feedCwd) })] }) }));
1224
+ }
1115
1225
  const dirty = !snapshot.clean;
1116
- return ((0, jsx_runtime_1.jsxs)("span", { className: "gbar", "data-slot-plugin": "dsh-ui-tweaks-gitbar", children: [(0, jsx_runtime_1.jsxs)("span", { className: "gbar-fchip", title: snapshot.cwd, children: [(0, jsx_runtime_1.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("path", { d: "M1.5 4A1.5 1.5 0 0 1 3 2.5h3l1.5 2H13A1.5 1.5 0 0 1 14.5 6v6A1.5 1.5 0 0 1 13 13.5H3A1.5 1.5 0 0 1 1.5 12V4Z" }) }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-folder", children: basenameOf(snapshot.cwd) })] }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-bwrap", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", ref: branchRef, className: 'gbar-chip' + (branchOpen ? ' gbar-open' : ''), onClick: toggleBranch, title: dirty ? t('dirty') : t('clean'), "aria-expanded": branchOpen, children: [(0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("circle", { cx: "4.5", cy: "3.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("circle", { cx: "4.5", cy: "12.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("circle", { cx: "12", cy: "5.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("path", { d: "M4.5 5.3v5.4" }), (0, jsx_runtime_1.jsx)("path", { d: "M12 7.3c0 3-3.5 4.8-7.5 3.4" })] }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-bname", children: snapshot.branch ?? snapshot.detachedHead ?? '—' })] }), branchOpen ? ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-pop", role: "menu", "aria-label": snapshot.branch ?? 'git', ref: branchPopRef, children: [(0, jsx_runtime_1.jsxs)("div", { className: "gbar-pop-head", children: [(0, jsx_runtime_1.jsxs)("span", { className: "gbar-curname", title: dirty ? t('dirty') : t('clean'), children: [(0, jsx_runtime_1.jsxs)("svg", { className: "gbar-bicon", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("circle", { cx: "4.5", cy: "3.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("circle", { cx: "4.5", cy: "12.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("circle", { cx: "12", cy: "5.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("path", { d: "M4.5 5.3v5.4" }), (0, jsx_runtime_1.jsx)("path", { d: "M12 7.3c0 3-3.5 4.8-7.5 3.4" })] }), (0, jsx_runtime_1.jsx)("span", { children: snapshot.branch ?? snapshot.detachedHead ?? '—' })] }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-state", children: [(0, jsx_runtime_1.jsx)("span", { className: 'gbar-dot ' + (dirty ? 'gbar-dirty' : 'gbar-clean'), "aria-hidden": true }), snapshot.ahead > 0 ? (0, jsx_runtime_1.jsxs)("span", { children: ["\u2191", snapshot.ahead] }) : null, snapshot.behind > 0 ? (0, jsx_runtime_1.jsxs)("span", { children: ["\u2193", snapshot.behind] }) : null] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-pop-body", children: [(0, jsx_runtime_1.jsxs)("div", { className: "gbar-sec", children: [t('branchLocal'), branches !== null ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-count", children: branches.local.length }) : null] }), branches === null ? ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-loading", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-spin" }), t('loading')] })) : branches.local.map(name => ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-rowwrap", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: 'gbar-row' + (name === branches.current ? ' gbar-cur' : ''), onClick: () => { pickBranch(name); }, children: [(0, jsx_runtime_1.jsxs)("svg", { className: "gbar-bicon", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("circle", { cx: "4.5", cy: "3.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("circle", { cx: "4.5", cy: "12.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("path", { d: "M4.5 5.3v5.4" }), (0, jsx_runtime_1.jsx)("path", { d: "M11.5 3.7v3a2.6 2.6 0 0 1-2.6 2.6H4.5" })] }), (0, jsx_runtime_1.jsx)("span", { children: name }), name === branches.current ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-check", "aria-hidden": true, children: "\u2713" }) : null] }), name !== branches.current && !isProtectedBranch(name) ? ((0, jsx_runtime_1.jsx)("button", { type: "button", className: 'gbar-del' + (confirmDelete === name ? ' gbar-arm' : ''), onClick: () => { deleteBranch(name); }, title: t('branchDelete'), children: confirmDelete === name ? t('branchDeleteConfirm') : ((0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("path", { d: "M2.5 4.5h11" }), (0, jsx_runtime_1.jsx)("path", { d: "M5.5 4.5V3.3c0-.44.36-.8.8-.8h3.4c.44 0 .8.36.8.8v1.2" }), (0, jsx_runtime_1.jsx)("path", { d: "M4 4.5l.6 8.2c.04.5.45.8.95.8h4.9c.5 0 .91-.3.95-.8l.6-8.2" })] })) })) : null] }, name))), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-sec", children: [t('branchRemote'), branches !== null ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-count", children: branches.remote.length }) : null] }), branches?.remote.map(name => ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-rowwrap", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: 'gbar-row' + (name === branches.current ? ' gbar-cur' : ''), onClick: () => { pickBranch(name); }, children: [(0, jsx_runtime_1.jsx)("svg", { className: "gbar-bicon", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("path", { d: "M5.2 13a3.2 3.2 0 1 1 .5-6.36 4 4 0 0 1 7.75 1.06 2.65 2.65 0 0 1-.55 5.3H5.2Z" }) }), (0, jsx_runtime_1.jsx)("span", { children: shortBranch(name) }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-rm", children: name.split('/')[0] })] }), !isProtectedBranch(shortBranch(name)) ? ((0, jsx_runtime_1.jsx)("button", { type: "button", className: 'gbar-del' + (confirmDelete === name ? ' gbar-arm' : ''), onClick: () => { deleteRemoteBranch(name); }, title: t('branchRemoteDelete'), children: confirmDelete === name ? t('branchDeleteConfirm') : ((0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("path", { d: "M2.5 4.5h11" }), (0, jsx_runtime_1.jsx)("path", { d: "M5.5 4.5V3.3c0-.44.36-.8.8-.8h3.4c.44 0 .8.36.8.8v1.2" }), (0, jsx_runtime_1.jsx)("path", { d: "M4 4.5l.6 8.2c.04.5.45.8.95.8h4.9c.5 0 .91-.3.95-.8l.6-8.2" })] })) })) : null] }, name)))] }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-actions", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-act", onClick: openNewBranch, children: [(0, jsx_runtime_1.jsx)("svg", { viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("path", { d: "M7.4 2.6a1.2 1.2 0 1 1 2.2 0l3.2 1.6a1.2 1.2 0 1 1-1.1 2.1l-2.3-1.2a2.6 2.6 0 0 1-1.1.8l.6 4.2a1.2 1.2 0 1 1-1.7.2l-.6-4.2a2.6 2.6 0 0 1-1.2-.7l-2.9 1.5a1.2 1.2 0 1 1-1.1-2.1l2.9-1.5a2.6 2.6 0 0 1 .2-1.5l-3.2-1.6a1.2 1.2 0 1 1 1.1-2.1z" }) }), t('branchNew')] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-act", onClick: openGraph, children: [(0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("path", { d: "M3 1.5v3.4a4.4 4.4 0 0 0 4.4 4.4h5.1" }), (0, jsx_runtime_1.jsx)("path", { d: "M13 1.5v4.9a3.2 3.2 0 0 1-3.2 3.2H3" }), (0, jsx_runtime_1.jsx)("circle", { cx: "3", cy: "1.5", r: "1.2", fill: "currentColor", stroke: "none" }), (0, jsx_runtime_1.jsx)("circle", { cx: "13", cy: "12", r: "1.2", fill: "currentColor", stroke: "none" })] }), t('branchGraph')] })] })] })) : null] }), newBranchOpen ? (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)("div", { className: "gbar-modal-wrap", onMouseDown: event => { if (event.target === event.currentTarget)
1226
+ return ((0, jsx_runtime_1.jsxs)("span", { className: "gbar", "data-slot-plugin": "dsh-ui-tweaks-gitbar", children: [(0, jsx_runtime_1.jsxs)("span", { className: "gbar-fchip", title: feedCwd ?? snapshot.cwd, children: [(0, jsx_runtime_1.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("path", { d: "M1.5 4A1.5 1.5 0 0 1 3 2.5h3l1.5 2H13A1.5 1.5 0 0 1 14.5 6v6A1.5 1.5 0 0 1 13 13.5H3A1.5 1.5 0 0 1 1.5 12V4Z" }) }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-folder", children: basenameOf(feedCwd ?? snapshot.cwd) })] }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-bwrap", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", ref: branchRef, className: 'gbar-chip' + (branchOpen ? ' gbar-open' : ''), onClick: toggleBranch, title: dirty ? t('dirty') : t('clean'), "aria-expanded": branchOpen, children: [(0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("circle", { cx: "4.5", cy: "3.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("circle", { cx: "4.5", cy: "12.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("circle", { cx: "12", cy: "5.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("path", { d: "M4.5 5.3v5.4" }), (0, jsx_runtime_1.jsx)("path", { d: "M12 7.3c0 3-3.5 4.8-7.5 3.4" })] }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-bname", children: snapshot.branch ?? snapshot.detachedHead ?? '—' })] }), branchOpen ? ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-pop", role: "menu", "aria-label": snapshot.branch ?? 'git', ref: branchPopRef, children: [(0, jsx_runtime_1.jsxs)("div", { className: "gbar-pop-head", children: [(0, jsx_runtime_1.jsxs)("span", { className: "gbar-curname", title: dirty ? t('dirty') : t('clean'), children: [(0, jsx_runtime_1.jsxs)("svg", { className: "gbar-bicon", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("circle", { cx: "4.5", cy: "3.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("circle", { cx: "4.5", cy: "12.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("circle", { cx: "12", cy: "5.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("path", { d: "M4.5 5.3v5.4" }), (0, jsx_runtime_1.jsx)("path", { d: "M12 7.3c0 3-3.5 4.8-7.5 3.4" })] }), (0, jsx_runtime_1.jsx)("span", { children: snapshot.branch ?? snapshot.detachedHead ?? '—' })] }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-state", children: [(0, jsx_runtime_1.jsx)("span", { className: 'gbar-dot ' + (dirty ? 'gbar-dirty' : 'gbar-clean'), "aria-hidden": true }), snapshot.ahead > 0 ? (0, jsx_runtime_1.jsxs)("span", { children: ["\u2191", snapshot.ahead] }) : null, snapshot.behind > 0 ? (0, jsx_runtime_1.jsxs)("span", { children: ["\u2193", snapshot.behind] }) : null] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-pop-body", children: [(0, jsx_runtime_1.jsxs)("div", { className: "gbar-sec", children: [t('branchLocal'), branches !== null ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-count", children: branches.local.length }) : null] }), branches === null ? ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-loading", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-spin" }), t('loading')] })) : branches.local.map(name => ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-rowwrap", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: 'gbar-row' + (name === branches.current ? ' gbar-cur' : ''), onClick: () => { pickBranch(name); }, children: [(0, jsx_runtime_1.jsxs)("svg", { className: "gbar-bicon", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("circle", { cx: "4.5", cy: "3.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("circle", { cx: "4.5", cy: "12.5", r: "1.8" }), (0, jsx_runtime_1.jsx)("path", { d: "M4.5 5.3v5.4" }), (0, jsx_runtime_1.jsx)("path", { d: "M11.5 3.7v3a2.6 2.6 0 0 1-2.6 2.6H4.5" })] }), (0, jsx_runtime_1.jsx)("span", { children: name }), name === branches.current ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-check", "aria-hidden": true, children: "\u2713" }) : null] }), name !== branches.current && !isProtectedBranch(name) ? ((0, jsx_runtime_1.jsx)("button", { type: "button", className: 'gbar-del' + (confirmDelete === name ? ' gbar-arm' : ''), onClick: () => { deleteBranch(name); }, title: t('branchDelete'), children: confirmDelete === name ? t('branchDeleteConfirm') : ((0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("path", { d: "M2.5 4.5h11" }), (0, jsx_runtime_1.jsx)("path", { d: "M5.5 4.5V3.3c0-.44.36-.8.8-.8h3.4c.44 0 .8.36.8.8v1.2" }), (0, jsx_runtime_1.jsx)("path", { d: "M4 4.5l.6 8.2c.04.5.45.8.95.8h4.9c.5 0 .91-.3.95-.8l.6-8.2" })] })) })) : null] }, name))), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-sec", children: [t('branchRemote'), branches !== null ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-count", children: branches.remote.length }) : null] }), branches?.remote.map(name => ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-rowwrap", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: 'gbar-row' + (name === branches.current ? ' gbar-cur' : ''), onClick: () => { pickBranch(name); }, children: [(0, jsx_runtime_1.jsx)("svg", { className: "gbar-bicon", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("path", { d: "M5.2 13a3.2 3.2 0 1 1 .5-6.36 4 4 0 0 1 7.75 1.06 2.65 2.65 0 0 1-.55 5.3H5.2Z" }) }), (0, jsx_runtime_1.jsx)("span", { children: shortBranch(name) }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-rm", children: name.split('/')[0] })] }), !isProtectedBranch(shortBranch(name)) ? ((0, jsx_runtime_1.jsx)("button", { type: "button", className: 'gbar-del' + (confirmDelete === name ? ' gbar-arm' : ''), onClick: () => { deleteRemoteBranch(name); }, title: t('branchRemoteDelete'), children: confirmDelete === name ? t('branchDeleteConfirm') : ((0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("path", { d: "M2.5 4.5h11" }), (0, jsx_runtime_1.jsx)("path", { d: "M5.5 4.5V3.3c0-.44.36-.8.8-.8h3.4c.44 0 .8.36.8.8v1.2" }), (0, jsx_runtime_1.jsx)("path", { d: "M4 4.5l.6 8.2c.04.5.45.8.95.8h4.9c.5 0 .91-.3.95-.8l.6-8.2" })] })) })) : null] }, name)))] }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-actions", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-act", onClick: openNewBranch, children: [(0, jsx_runtime_1.jsx)("svg", { viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("path", { d: "M7.4 2.6a1.2 1.2 0 1 1 2.2 0l3.2 1.6a1.2 1.2 0 1 1-1.1 2.1l-2.3-1.2a2.6 2.6 0 0 1-1.1.8l.6 4.2a1.2 1.2 0 1 1-1.7.2l-.6-4.2a2.6 2.6 0 0 1-1.2-.7l-2.9 1.5a1.2 1.2 0 1 1-1.1-2.1l2.9-1.5a2.6 2.6 0 0 1 .2-1.5l-3.2-1.6a1.2 1.2 0 1 1 1.1-2.1z" }) }), t('branchNew')] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-act", onClick: openGraph, children: [(0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("path", { d: "M3 1.5v3.4a4.4 4.4 0 0 0 4.4 4.4h5.1" }), (0, jsx_runtime_1.jsx)("path", { d: "M13 1.5v4.9a3.2 3.2 0 0 1-3.2 3.2H3" }), (0, jsx_runtime_1.jsx)("circle", { cx: "3", cy: "1.5", r: "1.2", fill: "currentColor", stroke: "none" }), (0, jsx_runtime_1.jsx)("circle", { cx: "13", cy: "12", r: "1.2", fill: "currentColor", stroke: "none" })] }), t('branchGraph')] })] })] })) : null] }), newBranchOpen ? (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)("div", { className: "gbar-modal-wrap", onMouseDown: event => { if (event.target === event.currentTarget)
1117
1227
  setNewBranchOpen(false); }, children: (0, jsx_runtime_1.jsxs)("div", { className: "gbar-modal", role: "dialog", "aria-label": t('branchNew'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "gbar-head", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-title", children: t('branchNew') }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-branch", children: snapshot.branch ?? snapshot.detachedHead ?? '—' }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-x", onClick: () => { setNewBranchOpen(false); }, "aria-label": "\u2715", children: "\u2715" })] }), (0, jsx_runtime_1.jsx)("input", { value: newBranchName, onChange: event => { setNewBranchName(event.target.value); }, onKeyDown: event => { if (event.key === 'Enter')
1118
1228
  createBranch(); }, placeholder: t('branchNewPlaceholder'), "aria-label": t('branchNew'), autoFocus: true }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-baserow", children: [(0, jsx_runtime_1.jsx)("label", { className: "gbar-baselabel", htmlFor: "gbar-base-dlg", children: t('branchFrom') }), (0, jsx_runtime_1.jsxs)("select", { id: "gbar-base-dlg", className: "gbar-base", value: baseBranch, onChange: event => { setBaseBranch(event.target.value); }, "aria-label": t('branchFrom'), children: [(0, jsx_runtime_1.jsx)("option", { value: "", children: t('branchFromHead') }), branches?.local.map(name => (0, jsx_runtime_1.jsx)("option", { value: name, children: name }, name)), branches?.remote.map(name => (0, jsx_runtime_1.jsx)("option", { value: name, children: name }, name))] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-pushrow", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: 'gbar-chk' + (pushToRemote ? '' : ' gbar-off'), onClick: () => { setPushToRemote(value => !value); }, "aria-label": t('branchPushRemote'), children: pushToRemote ? '✓' : '✕' }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-pushlabel", children: t('branchPushRemote') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-foot", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-btn gbar-ghost", onClick: () => { setNewBranchOpen(false); }, children: t('branchCancel') }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-btn gbar-primary", onClick: createBranch, disabled: busy !== null || newBranchName.trim() === '', children: [busy === 'create' || busy === 'create-push' ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-spin" }) : null, " ", t('branchCreate')] })] })] }) }), document.body) : null, graphOpen ? (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)("div", { className: "gbar-modal-wrap", onMouseDown: event => { if (event.target === event.currentTarget)
1119
1229
  setGraphOpen(false); }, children: (0, jsx_runtime_1.jsxs)("div", { className: "gbar-modal gbar-graph-modal", role: "dialog", "aria-label": t('graphTitle'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "gbar-head", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-title", children: t('graphTitle') }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-branch", children: snapshot.branch ?? snapshot.detachedHead ?? '—' }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-spacer" }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-x gbar-refresh", onClick: fetchGraph, "aria-label": t('branchRefresh'), title: t('branchRefresh'), disabled: graphBusy, children: graphBusy ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-spin" }) : ((0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("path", { d: "M13.4 8a5.4 5.4 0 1 1-1.6-3.8" }), (0, jsx_runtime_1.jsx)("path", { d: "M13.4 1.5v3h-3" })] })) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-x", onClick: () => { setGraphOpen(false); }, "aria-label": "\u2715", children: "\u2715" })] }), graph === null ? ((0, jsx_runtime_1.jsx)("div", { className: "gbar-graph-empty", children: graphBusy ? t('loading') : t('noChanges') })) : graph.commits.length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "gbar-graph-empty", children: t('noChanges') })) : ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-graph-table", role: "table", "aria-label": t('graphTitle'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "gbar-graph-row gbar-graph-head", role: "row", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-c-hash", role: "columnheader", children: t('graphColCommit') }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-c-subject", role: "columnheader", children: t('graphColSubject') }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-c-author", role: "columnheader", children: t('graphColAuthor') }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-c-date", role: "columnheader", children: t('graphColDate') })] }), graph.commits.map(commit => ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-graph-row", role: "row", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-c-hash", role: "cell", children: (0, jsx_runtime_1.jsx)("code", { className: "gbar-hash", children: commit.hash }) }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-c-subject", role: "cell", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-subject", children: commit.subject }), commit.refs !== '' ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-refs", children: commit.refs }) : null] }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-c-author", role: "cell", children: commit.author }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-c-date", role: "cell", title: commit.date, children: commit.dateRelative })] }, commit.fullHash)))] }))] }) }), document.body) : null, notice !== null ? (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)("div", { className: 'gbar-notice gbar-' + notice.kind, role: "status", children: notice.text }), document.body) : null] }));
@@ -3026,8 +3136,19 @@ function apply(ctx) {
3026
3136
  id: 'gitbar-branch',
3027
3137
  order: 10,
3028
3138
  locale: NS,
3029
- inject: () => ({ controller }),
3139
+ inject: () => ({ controller, sessionsService: ctx.sessions }),
3030
3140
  }, gitbar_tsx_1.BranchChipEntry));
3141
+ // Warmup: the header chips mount only after the conversation projection
3142
+ // finishes loading (seconds on large inactive sessions). The input dock
3143
+ // mounts immediately on session switch, so a null-rendering seat there
3144
+ // prefetches the status into the shared cache right away — the chips then
3145
+ // paint folder+branch from the warm cache the moment they appear.
3146
+ ctx.slots.inject('conversation.input.dock', () => ctx.slots.register({
3147
+ name: 'conversation.input.dock',
3148
+ id: 'gitbar-warmup',
3149
+ order: 41,
3150
+ inject: () => ({}),
3151
+ }, gitbar_tsx_1.GitWarmup));
3031
3152
  ctx.slots.inject('conversation.session.header.utilities', () => ctx.slots.register({
3032
3153
  name: 'conversation.session.header.utilities',
3033
3154
  id: 'gitbar-utils',
@@ -3230,63 +3351,63 @@ function linesToRecord(text, separator) {
3230
3351
  function recordToLines(record, separator) {
3231
3352
  return Object.entries(record).map(([key, value]) => `${key}${separator}${value}`).join('\n');
3232
3353
  }
3233
- exports.MCP_CSS = `
3234
- .dut-mcp{display:grid;gap:12px;max-width:680px;padding:6px 2px 36px}
3235
- .dut-mcp-head{display:flex;align-items:center;gap:10px;padding:14px 16px 0}
3236
- .dut-mcp-head h2{margin:0;font-size:15px;font-weight:600;letter-spacing:-.01em;color:var(--dsw-alias-label-primary)}
3237
- .dut-mcp-count{font-size:11.5px;color:var(--dsw-alias-label-secondary);padding:2px 8px;border-radius:999px;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1)}
3238
- .dut-mcp-spacer{flex:1}
3239
- .dut-mcp-btn{display:inline-flex;align-items:center;height:28px;padding:0 12px;border-radius:999px;border:1px solid var(--dsw-alias-border-l1);background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;cursor:pointer;transition:background .15s ease,color .15s ease,border-color .15s ease}
3240
- .dut-mcp-btn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
3241
- .dut-mcp-btn:disabled{opacity:.5;cursor:default}
3242
- .dut-mcp-btn.dut-mcp-del:hover{border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 55%,transparent);color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}
3243
- .dut-mcp-btn.dut-mcp-confirm{border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 55%,transparent);color:var(--dsw-alias-state-error-primary);font-weight:600}
3244
- .dut-mcp-body{display:grid;gap:2px;margin-top:4px}
3245
- .dut-mcp-row{display:grid;gap:6px;padding:10px 16px;border-radius:12px}
3246
- .dut-mcp-row:hover{background:var(--dsw-alias-interactive-bg-hover)}
3247
- .dut-mcp-row-main{display:flex;align-items:center;gap:8px;min-width:0}
3248
- .dut-mcp-name{font-size:13.5px;font-weight:600;color:var(--dsw-alias-label-primary);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}
3249
- .dut-mcp-badge{flex:none;font-size:11px;line-height:1;padding:4px 9px;border-radius:999px;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary)}
3250
- .dut-mcp-badge.dut-mcp-ok{background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 12%,transparent);border-color:transparent;color:var(--dsw-alias-state-success-primary)}
3251
- .dut-mcp-badge.dut-mcp-err{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 12%,transparent);border-color:transparent;color:var(--dsw-alias-state-error-primary)}
3252
- .dut-mcp-badge.dut-mcp-warn{background:color-mix(in srgb,var(--dsw-alias-state-warn-primary) 14%,transparent);border-color:transparent;color:var(--dsw-alias-state-warn-label)}
3253
- .dut-mcp-sub{font-size:11.5px;color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}
3254
- .dut-mcp-toggle{flex:none;font-size:11.5px;color:var(--dsw-alias-label-tertiary);background:transparent;border:none;padding:0;cursor:pointer;text-align:left}
3255
- .dut-mcp-toggle:hover{color:var(--dsw-alias-label-primary)}
3256
- .dut-mcp-tools{margin-left:2px;display:flex;flex-wrap:wrap;gap:4px}
3257
- .dut-mcp-tool{font-size:11px;line-height:1;padding:3px 8px;border-radius:999px;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary)}
3258
- .dut-mcp-note{margin:2px 16px 0;padding:8px 12px;border-radius:10px;font-size:11.5px;line-height:1.55;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1)}
3259
- .dut-mcp-empty{padding:32px 16px;text-align:center;font-size:12.5px;color:var(--dsw-alias-label-secondary)}
3260
- .dut-mcp-alert{margin:8px 16px 0;padding:8px 12px;border-radius:10px;font-size:12px;line-height:1.5;background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent);color:var(--dsw-alias-state-error-primary)}
3261
- .dut-mcp-notice{margin:8px 16px 0;padding:8px 12px;border-radius:10px;font-size:12px;line-height:1.5;background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 12%,transparent);color:var(--dsw-alias-state-success-primary)}
3262
- .dut-mcp-off{padding:20px 16px;display:grid;gap:12px}
3263
- .dut-mcp-off p{margin:0;font-size:12.5px;line-height:1.6;color:var(--dsw-alias-label-secondary)}
3264
- .dut-mcp-overlay{z-index:1100;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}
3265
- .dut-mcp-mask{background:var(--dsw-alias-bg-mask-1);backdrop-filter:var(--dsw-mask-blur);position:absolute;inset:0}
3266
- .dut-mcp-panel{z-index:1;background:var(--dsw-alias-bg-layer-2);box-sizing:border-box;width:720px;max-width:calc(100vw - 48px);height:min(700px,100vh - 48px);box-shadow:var(--dsw-shadow-lv3);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:20px;display:flex;flex-direction:column;overflow:hidden}
3267
- .dut-mcp-panel-head{box-sizing:border-box;flex:none;display:flex;align-items:center;gap:10px;height:52px;padding:0 12px 0 20px}
3268
- .dut-mcp-panel-head h2{margin:0;font-size:16px;font-weight:600;letter-spacing:-.01em;color:var(--dsw-alias-label-primary)}
3269
- .dut-mcp-panel-close{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-primary);background:transparent;border:none;border-radius:28px;display:inline-flex;justify-content:center;align-items:center;padding:0;font-size:13px}
3270
- .dut-mcp-panel-close:hover{background:var(--dsw-alias-interactive-bg-hover)}
3271
- .dut-mcp-tabs{flex:none;display:inline-flex;padding:3px;gap:3px;border:1px solid var(--dsw-alias-border-l1);border-radius:10px;background:var(--dsw-alias-bg-layer-2);margin:0 20px 10px;align-self:flex-start}
3272
- .dut-mcp-tabs button{border:none;border-radius:7px;padding:5px 14px;background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12.5px;cursor:pointer}
3273
- .dut-mcp-tabs button.dut-mcp-tab-on{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);color:var(--dsw-alias-state-business-primary);font-weight:600}
3274
- .dut-mcp-form{flex:1;min-height:0;overflow-y:auto;padding:0 20px 20px;display:grid;gap:12px;align-content:start}
3275
- .dut-mcp-field{display:grid;gap:6px}
3276
- .dut-mcp-field>span{font-size:12px;font-weight:600;color:var(--dsw-alias-label-primary)}
3277
- .dut-mcp-field small{font-size:11px;line-height:1.5;color:var(--dsw-alias-label-tertiary)}
3278
- .dut-mcp-input{box-sizing:border-box;width:100%;height:34px;padding:0 10px;border-radius:9px;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;font-size:13px}
3279
- .dut-mcp-input:focus{outline:none;border-color:color-mix(in srgb,var(--dsw-alias-state-business-primary) 55%,transparent)}
3280
- .dut-mcp-input:disabled{opacity:.55;cursor:not-allowed}
3281
- textarea.dut-mcp-input{height:auto;min-height:72px;padding:8px 10px;line-height:1.5;resize:vertical;font-family:var(--dsw-font-markdown-code-block-font-family, Consolas, monospace);font-size:12px}
3282
- textarea.dut-mcp-input-lg{min-height:120px}
3283
- textarea.dut-mcp-yaml{min-height:320px}
3284
- .dut-mcp-row2{display:grid;grid-template-columns:1fr 1fr;gap:12px;align-items:start}
3285
- .dut-mcp-field .dut-seg{width:fit-content}
3286
- .dut-mcp-row2 .dut-seg{height:34px;box-sizing:border-box;align-items:center}
3287
- .dut-mcp-row2 .dut-seg button{flex:none;white-space:nowrap;padding:0 16px;height:26px}
3288
- .dut-mcp-foot{flex:none;display:flex;align-items:center;gap:8px;justify-content:flex-end;padding:12px 20px 16px;border-top:1px solid var(--dsw-alias-border-l1)}
3289
- .dut-mcp-error{margin:0 20px 10px;padding:8px 12px;border-radius:10px;font-size:12px;line-height:1.5;background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent);color:var(--dsw-alias-state-error-primary)}
3354
+ exports.MCP_CSS = `
3355
+ .dut-mcp{display:grid;gap:12px;max-width:680px;padding:6px 2px 36px}
3356
+ .dut-mcp-head{display:flex;align-items:center;gap:10px;padding:14px 16px 0}
3357
+ .dut-mcp-head h2{margin:0;font-size:15px;font-weight:600;letter-spacing:-.01em;color:var(--dsw-alias-label-primary)}
3358
+ .dut-mcp-count{font-size:11.5px;color:var(--dsw-alias-label-secondary);padding:2px 8px;border-radius:999px;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1)}
3359
+ .dut-mcp-spacer{flex:1}
3360
+ .dut-mcp-btn{display:inline-flex;align-items:center;height:28px;padding:0 12px;border-radius:999px;border:1px solid var(--dsw-alias-border-l1);background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;cursor:pointer;transition:background .15s ease,color .15s ease,border-color .15s ease}
3361
+ .dut-mcp-btn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
3362
+ .dut-mcp-btn:disabled{opacity:.5;cursor:default}
3363
+ .dut-mcp-btn.dut-mcp-del:hover{border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 55%,transparent);color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}
3364
+ .dut-mcp-btn.dut-mcp-confirm{border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 55%,transparent);color:var(--dsw-alias-state-error-primary);font-weight:600}
3365
+ .dut-mcp-body{display:grid;gap:2px;margin-top:4px}
3366
+ .dut-mcp-row{display:grid;gap:6px;padding:10px 16px;border-radius:12px}
3367
+ .dut-mcp-row:hover{background:var(--dsw-alias-interactive-bg-hover)}
3368
+ .dut-mcp-row-main{display:flex;align-items:center;gap:8px;min-width:0}
3369
+ .dut-mcp-name{font-size:13.5px;font-weight:600;color:var(--dsw-alias-label-primary);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}
3370
+ .dut-mcp-badge{flex:none;font-size:11px;line-height:1;padding:4px 9px;border-radius:999px;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary)}
3371
+ .dut-mcp-badge.dut-mcp-ok{background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 12%,transparent);border-color:transparent;color:var(--dsw-alias-state-success-primary)}
3372
+ .dut-mcp-badge.dut-mcp-err{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 12%,transparent);border-color:transparent;color:var(--dsw-alias-state-error-primary)}
3373
+ .dut-mcp-badge.dut-mcp-warn{background:color-mix(in srgb,var(--dsw-alias-state-warn-primary) 14%,transparent);border-color:transparent;color:var(--dsw-alias-state-warn-label)}
3374
+ .dut-mcp-sub{font-size:11.5px;color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}
3375
+ .dut-mcp-toggle{flex:none;font-size:11.5px;color:var(--dsw-alias-label-tertiary);background:transparent;border:none;padding:0;cursor:pointer;text-align:left}
3376
+ .dut-mcp-toggle:hover{color:var(--dsw-alias-label-primary)}
3377
+ .dut-mcp-tools{margin-left:2px;display:flex;flex-wrap:wrap;gap:4px}
3378
+ .dut-mcp-tool{font-size:11px;line-height:1;padding:3px 8px;border-radius:999px;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary)}
3379
+ .dut-mcp-note{margin:2px 16px 0;padding:8px 12px;border-radius:10px;font-size:11.5px;line-height:1.55;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1)}
3380
+ .dut-mcp-empty{padding:32px 16px;text-align:center;font-size:12.5px;color:var(--dsw-alias-label-secondary)}
3381
+ .dut-mcp-alert{margin:8px 16px 0;padding:8px 12px;border-radius:10px;font-size:12px;line-height:1.5;background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent);color:var(--dsw-alias-state-error-primary)}
3382
+ .dut-mcp-notice{margin:8px 16px 0;padding:8px 12px;border-radius:10px;font-size:12px;line-height:1.5;background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 12%,transparent);color:var(--dsw-alias-state-success-primary)}
3383
+ .dut-mcp-off{padding:20px 16px;display:grid;gap:12px}
3384
+ .dut-mcp-off p{margin:0;font-size:12.5px;line-height:1.6;color:var(--dsw-alias-label-secondary)}
3385
+ .dut-mcp-overlay{z-index:1100;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}
3386
+ .dut-mcp-mask{background:var(--dsw-alias-bg-mask-1);backdrop-filter:var(--dsw-mask-blur);position:absolute;inset:0}
3387
+ .dut-mcp-panel{z-index:1;background:var(--dsw-alias-bg-layer-2);box-sizing:border-box;width:720px;max-width:calc(100vw - 48px);height:min(700px,100vh - 48px);box-shadow:var(--dsw-shadow-lv3);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:20px;display:flex;flex-direction:column;overflow:hidden}
3388
+ .dut-mcp-panel-head{box-sizing:border-box;flex:none;display:flex;align-items:center;gap:10px;height:52px;padding:0 12px 0 20px}
3389
+ .dut-mcp-panel-head h2{margin:0;font-size:16px;font-weight:600;letter-spacing:-.01em;color:var(--dsw-alias-label-primary)}
3390
+ .dut-mcp-panel-close{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-primary);background:transparent;border:none;border-radius:28px;display:inline-flex;justify-content:center;align-items:center;padding:0;font-size:13px}
3391
+ .dut-mcp-panel-close:hover{background:var(--dsw-alias-interactive-bg-hover)}
3392
+ .dut-mcp-tabs{flex:none;display:inline-flex;padding:3px;gap:3px;border:1px solid var(--dsw-alias-border-l1);border-radius:10px;background:var(--dsw-alias-bg-layer-2);margin:0 20px 10px;align-self:flex-start}
3393
+ .dut-mcp-tabs button{border:none;border-radius:7px;padding:5px 14px;background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12.5px;cursor:pointer}
3394
+ .dut-mcp-tabs button.dut-mcp-tab-on{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);color:var(--dsw-alias-state-business-primary);font-weight:600}
3395
+ .dut-mcp-form{flex:1;min-height:0;overflow-y:auto;padding:0 20px 20px;display:grid;gap:12px;align-content:start}
3396
+ .dut-mcp-field{display:grid;gap:6px}
3397
+ .dut-mcp-field>span{font-size:12px;font-weight:600;color:var(--dsw-alias-label-primary)}
3398
+ .dut-mcp-field small{font-size:11px;line-height:1.5;color:var(--dsw-alias-label-tertiary)}
3399
+ .dut-mcp-input{box-sizing:border-box;width:100%;height:34px;padding:0 10px;border-radius:9px;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;font-size:13px}
3400
+ .dut-mcp-input:focus{outline:none;border-color:color-mix(in srgb,var(--dsw-alias-state-business-primary) 55%,transparent)}
3401
+ .dut-mcp-input:disabled{opacity:.55;cursor:not-allowed}
3402
+ textarea.dut-mcp-input{height:auto;min-height:72px;padding:8px 10px;line-height:1.5;resize:vertical;font-family:var(--dsw-font-markdown-code-block-font-family, Consolas, monospace);font-size:12px}
3403
+ textarea.dut-mcp-input-lg{min-height:120px}
3404
+ textarea.dut-mcp-yaml{min-height:320px}
3405
+ .dut-mcp-row2{display:grid;grid-template-columns:1fr 1fr;gap:12px;align-items:start}
3406
+ .dut-mcp-field .dut-seg{width:fit-content}
3407
+ .dut-mcp-row2 .dut-seg{height:34px;box-sizing:border-box;align-items:center}
3408
+ .dut-mcp-row2 .dut-seg button{flex:none;white-space:nowrap;padding:0 16px;height:26px}
3409
+ .dut-mcp-foot{flex:none;display:flex;align-items:center;gap:8px;justify-content:flex-end;padding:12px 20px 16px;border-top:1px solid var(--dsw-alias-border-l1)}
3410
+ .dut-mcp-error{margin:0 20px 10px;padding:8px 12px;border-radius:10px;font-size:12px;line-height:1.5;background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent);color:var(--dsw-alias-state-error-primary)}
3290
3411
  `;
3291
3412
  /** Install the MCP stylesheet once (idempotent); returns the disposer. */
3292
3413
  function installMcpStyles() {
@@ -4376,28 +4497,28 @@ const WHALE_VIEW_H = 17.04;
4376
4497
  // ---------------------------------------------------------------------------
4377
4498
  // Styles — resident (translucent, still) vs working (opaque, swimming).
4378
4499
  // ---------------------------------------------------------------------------
4379
- exports.WHALE_CSS = `
4380
- .duwi-row{box-sizing:border-box;width:100%;max-width:calc(var(--dsh-composer-card-max-width) + 2 * var(--dsh-composer-side-clearance, 0px));margin:0 auto;padding:0 calc(var(--dsh-composer-side-clearance, 0px) + 14px) 0 var(--dsh-composer-side-clearance, 0px);display:flex;align-items:flex-end;justify-content:flex-end;height:27px;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
4381
- .duwi-stack{display:flex;flex-direction:column;align-items:center;transform:translateY(6px)}
4382
- .duwi-whale{display:block;color:var(--dsw-alias-label-primary);transform-origin:50% 60%;pointer-events:auto;cursor:pointer}
4383
- .duwi-row.duwi-swim .duwi-whale,.duwi-whale:hover{animation:duwi-swim 1.9s ease-in-out infinite}
4384
- .duwi-waves{display:block;width:26px;height:9px;margin-top:-3px;overflow:hidden}
4385
- .duwi-wave-back{stroke:#3d8bfd;opacity:.35}
4386
- .duwi-wave-front{stroke:#3d8bfd;opacity:.8}
4387
- .duwi-wave-front,.duwi-wave-back{animation:duwi-drift-front 1.9s linear infinite}
4388
- .duwi-wave-back{animation-duration:3.4s;animation-direction:reverse}
4389
- @keyframes duwi-swim{
4390
- 0%,100%{transform:translateY(0) rotate(-4deg)}
4391
- 50%{transform:translateY(-3.5px) rotate(4deg)}
4392
- }
4393
- @keyframes duwi-drift-front{
4394
- from{transform:translateX(0)}
4395
- to{transform:translateX(-8px)}
4396
- }
4397
- @media (prefers-reduced-motion:reduce){
4398
- .duwi-row.duwi-swim .duwi-whale,.duwi-whale:hover{animation:none}
4399
- .duwi-wave-front,.duwi-wave-back{animation:none}
4400
- }
4500
+ exports.WHALE_CSS = `
4501
+ .duwi-row{box-sizing:border-box;width:100%;max-width:calc(var(--dsh-composer-card-max-width) + 2 * var(--dsh-composer-side-clearance, 0px));margin:0 auto;padding:0 calc(var(--dsh-composer-side-clearance, 0px) + 14px) 0 var(--dsh-composer-side-clearance, 0px);display:flex;align-items:flex-end;justify-content:flex-end;height:27px;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
4502
+ .duwi-stack{display:flex;flex-direction:column;align-items:center;transform:translateY(6px)}
4503
+ .duwi-whale{display:block;color:var(--dsw-alias-label-primary);transform-origin:50% 60%;pointer-events:auto;cursor:pointer}
4504
+ .duwi-row.duwi-swim .duwi-whale,.duwi-whale:hover{animation:duwi-swim 1.9s ease-in-out infinite}
4505
+ .duwi-waves{display:block;width:26px;height:9px;margin-top:-3px;overflow:hidden}
4506
+ .duwi-wave-back{stroke:#3d8bfd;opacity:.35}
4507
+ .duwi-wave-front{stroke:#3d8bfd;opacity:.8}
4508
+ .duwi-wave-front,.duwi-wave-back{animation:duwi-drift-front 1.9s linear infinite}
4509
+ .duwi-wave-back{animation-duration:3.4s;animation-direction:reverse}
4510
+ @keyframes duwi-swim{
4511
+ 0%,100%{transform:translateY(0) rotate(-4deg)}
4512
+ 50%{transform:translateY(-3.5px) rotate(4deg)}
4513
+ }
4514
+ @keyframes duwi-drift-front{
4515
+ from{transform:translateX(0)}
4516
+ to{transform:translateX(-8px)}
4517
+ }
4518
+ @media (prefers-reduced-motion:reduce){
4519
+ .duwi-row.duwi-swim .duwi-whale,.duwi-whale:hover{animation:none}
4520
+ .duwi-wave-front,.duwi-wave-back{animation:none}
4521
+ }
4401
4522
  `;
4402
4523
  /** Idempotent installer for the indicator styles (same pattern as the other features). */
4403
4524
  function installWhaleStyles() {