dsh-vscode-workbench 0.2.0 → 0.2.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/lib/client.js CHANGED
@@ -46,6 +46,7 @@ window.__ModuleLoader__.load({
46
46
  //#endregion
47
47
  let react = require("react");
48
48
  let react_jsx_runtime = require("react/jsx-runtime");
49
+ let react_dom = require("react-dom");
49
50
  //#region src/client/service.ts
50
51
  const SNAPSHOT_KEY = "dvw:workbench:snapshot:v1";
51
52
  const DEFAULT_SNAPSHOT = {
@@ -7408,6 +7409,61 @@ window.__ModuleLoader__.load({
7408
7409
  });
7409
7410
  }
7410
7411
  //#endregion
7412
+ //#region src/client/api.ts
7413
+ var ApiError = class extends Error {
7414
+ code;
7415
+ constructor(code, message) {
7416
+ super(message);
7417
+ this.code = code;
7418
+ }
7419
+ };
7420
+ /** Back off while DSH publishes the current session after startup; every view shares this retry. */
7421
+ function sessionRetryDelay(error, attempt) {
7422
+ if (!(error instanceof ApiError) || error.code !== "session-not-found" || attempt >= 10) return void 0;
7423
+ return Math.min(250 * (attempt + 1), 1e3);
7424
+ }
7425
+ function wait(ms, signal) {
7426
+ return new Promise((resolve, reject) => {
7427
+ const abort = () => {
7428
+ clearTimeout(timer);
7429
+ reject(signal?.reason ?? /* @__PURE__ */ new Error("aborted"));
7430
+ };
7431
+ const timer = setTimeout(() => {
7432
+ signal?.removeEventListener("abort", abort);
7433
+ resolve();
7434
+ }, ms);
7435
+ if (signal?.aborted === true) {
7436
+ abort();
7437
+ return;
7438
+ }
7439
+ signal?.addEventListener("abort", abort, { once: true });
7440
+ });
7441
+ }
7442
+ async function request$2(method, body, signal) {
7443
+ const response = await fetch(`/dsh-vscode/api/${method}`, {
7444
+ method: "POST",
7445
+ headers: { "content-type": "application/json" },
7446
+ body: JSON.stringify(body),
7447
+ signal
7448
+ });
7449
+ const answer = await response.json();
7450
+ if (!response.ok || !answer.ok) throw new ApiError(answer.error?.code ?? "request-failed", answer.error?.message ?? `request failed (${response.status})`);
7451
+ return answer.value;
7452
+ }
7453
+ async function api(method, body, signal) {
7454
+ return withSessionRetry(() => request$2(method, body, signal), signal);
7455
+ }
7456
+ /** Retry an operation while DSH is still publishing the selected session. */
7457
+ async function withSessionRetry(operation, signal) {
7458
+ for (let attempt = 0;; attempt++) try {
7459
+ return await operation();
7460
+ } catch (error) {
7461
+ const delay = sessionRetryDelay(error, attempt);
7462
+ if (delay === void 0) throw error;
7463
+ await wait(delay, signal);
7464
+ }
7465
+ }
7466
+ //#endregion
7411
7467
  //#region src/client/websocket.ts
7412
7468
  const WEB_PAGE_PROTOCOLS = /* @__PURE__ */ new Set([
7413
7469
  "http:",
@@ -7457,7 +7513,7 @@ window.__ModuleLoader__.load({
7457
7513
  }
7458
7514
  //#endregion
7459
7515
  //#region src/client/terminal.ts
7460
- async function request$2(method, body) {
7516
+ async function request$1(method, body) {
7461
7517
  const response = await fetch(`/dsh-vscode-terminal/api/${method}`, {
7462
7518
  method: "POST",
7463
7519
  headers: { "content-type": "application/json" },
@@ -7470,7 +7526,7 @@ window.__ModuleLoader__.load({
7470
7526
  } catch {
7471
7527
  throw new Error(`terminal request returned invalid JSON (${response.status})`);
7472
7528
  }
7473
- if (!response.ok || answer.ok !== true) throw new Error(answer.error?.message ?? "terminal request failed");
7529
+ if (!response.ok || answer.ok !== true) throw new ApiError(answer.error?.code ?? "terminal-request-failed", answer.error?.message ?? "terminal request failed");
7474
7530
  return answer.value;
7475
7531
  }
7476
7532
  var SocketConnection = class {
@@ -7559,23 +7615,25 @@ window.__ModuleLoader__.load({
7559
7615
  });
7560
7616
  try {
7561
7617
  this.set({
7562
- terminals: await request$2("list", { sessionId: this.sessionId }),
7618
+ terminals: await withSessionRetry(() => request$1("list", { sessionId: this.sessionId })),
7563
7619
  loading: false
7564
7620
  });
7621
+ return true;
7565
7622
  } catch (error) {
7566
7623
  this.set({
7567
7624
  ...this.snapshot,
7568
7625
  loading: false,
7569
7626
  error: error instanceof Error ? error.message : String(error)
7570
7627
  });
7628
+ return false;
7571
7629
  }
7572
7630
  }
7573
7631
  async create(title) {
7574
7632
  try {
7575
- const terminal = await request$2("create", {
7633
+ const terminal = await withSessionRetry(() => request$1("create", {
7576
7634
  sessionId: this.sessionId,
7577
7635
  ...title === void 0 ? {} : { title }
7578
- });
7636
+ }));
7579
7637
  await this.refresh();
7580
7638
  return terminal;
7581
7639
  } catch (error) {
@@ -7588,18 +7646,18 @@ window.__ModuleLoader__.load({
7588
7646
  }
7589
7647
  }
7590
7648
  async close(id) {
7591
- await request$2("close", {
7649
+ await withSessionRetry(() => request$1("close", {
7592
7650
  sessionId: this.sessionId,
7593
7651
  id
7594
- });
7652
+ }));
7595
7653
  await this.refresh();
7596
7654
  }
7597
7655
  async rename(id, title) {
7598
- await request$2("rename", {
7656
+ await withSessionRetry(() => request$1("rename", {
7599
7657
  sessionId: this.sessionId,
7600
7658
  id,
7601
7659
  title
7602
- });
7660
+ }));
7603
7661
  await this.refresh();
7604
7662
  }
7605
7663
  connect(id) {
@@ -7755,11 +7813,11 @@ window.__ModuleLoader__.load({
7755
7813
  const [sideWidth, setSideWidth] = (0, react.useState)(220);
7756
7814
  (0, react.useEffect)(() => {
7757
7815
  let cancelled = false;
7758
- workspace.refresh().then(() => {
7759
- if (!cancelled && workspace.getSnapshot().terminals.length === 0) workspace.create().then((value) => {
7816
+ workspace.refresh().then((ready) => {
7817
+ if (!cancelled && ready && workspace.getSnapshot().terminals.length === 0) workspace.create().then((value) => {
7760
7818
  if (!cancelled) setActive(value.id);
7761
7819
  }).catch(() => void 0);
7762
- }).catch(() => void 0);
7820
+ });
7763
7821
  return () => {
7764
7822
  cancelled = true;
7765
7823
  };
@@ -7934,57 +7992,6 @@ window.__ModuleLoader__.load({
7934
7992
  });
7935
7993
  }
7936
7994
  //#endregion
7937
- //#region src/client/api.ts
7938
- var ApiError = class extends Error {
7939
- code;
7940
- constructor(code, message) {
7941
- super(message);
7942
- this.code = code;
7943
- }
7944
- };
7945
- /** Back off while DSH publishes the current session after startup; every view shares this retry. */
7946
- function sessionRetryDelay(error, attempt) {
7947
- if (!(error instanceof ApiError) || error.code !== "session-not-found" || attempt >= 10) return void 0;
7948
- return Math.min(250 * (attempt + 1), 1e3);
7949
- }
7950
- function wait(ms, signal) {
7951
- return new Promise((resolve, reject) => {
7952
- const abort = () => {
7953
- clearTimeout(timer);
7954
- reject(signal?.reason ?? /* @__PURE__ */ new Error("aborted"));
7955
- };
7956
- const timer = setTimeout(() => {
7957
- signal?.removeEventListener("abort", abort);
7958
- resolve();
7959
- }, ms);
7960
- if (signal?.aborted === true) {
7961
- abort();
7962
- return;
7963
- }
7964
- signal?.addEventListener("abort", abort, { once: true });
7965
- });
7966
- }
7967
- async function request$1(method, body, signal) {
7968
- const response = await fetch(`/dsh-vscode/api/${method}`, {
7969
- method: "POST",
7970
- headers: { "content-type": "application/json" },
7971
- body: JSON.stringify(body),
7972
- signal
7973
- });
7974
- const answer = await response.json();
7975
- if (!response.ok || !answer.ok) throw new ApiError(answer.error?.code ?? "request-failed", answer.error?.message ?? `request failed (${response.status})`);
7976
- return answer.value;
7977
- }
7978
- async function api(method, body, signal) {
7979
- for (let attempt = 0;; attempt++) try {
7980
- return await request$1(method, body, signal);
7981
- } catch (error) {
7982
- const delay = sessionRetryDelay(error, attempt);
7983
- if (delay === void 0) throw error;
7984
- await wait(delay, signal);
7985
- }
7986
- }
7987
- //#endregion
7988
7995
  //#region node_modules/.pnpm/vscode-icons-js@11.6.1/node_modules/vscode-icons-js/dist/generated/FileExtensions1ToIcon.js
7989
7996
  var require_FileExtensions1ToIcon = /* @__PURE__ */ __commonJSMin(((exports) => {
7990
7997
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -14134,6 +14141,18 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14134
14141
  horizontalScrollbarSize: 10
14135
14142
  }
14136
14143
  };
14144
+ /** macOS reports Control-click as a secondary click, so Monaco only navigates with Cmd-click there. */
14145
+ function isMacPlatform(userAgent = navigator.userAgent) {
14146
+ return /Macintosh|Mac OS X/.test(userAgent);
14147
+ }
14148
+ /**
14149
+ * Whether a mouse press should jump to the definition. On macOS, Control-click is a common
14150
+ * Windows/Linux habit but arrives as a context-menu gesture (sometimes as a right-button
14151
+ * press); treat it as Cmd-click instead.
14152
+ */
14153
+ function isMacDefinitionClick(event) {
14154
+ return (event.button === 0 || event.button === 2) && event.ctrlKey && !event.metaKey;
14155
+ }
14137
14156
  /** Monaco theme aligned with the workbench dark palette. */
14138
14157
  const DARK_THEME = "dvw-dark";
14139
14158
  const DARK_RULES = [
@@ -14225,6 +14244,36 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14225
14244
  "scrollbarSlider.hoverBackground": "#646464b3",
14226
14245
  "scrollbarSlider.activeBackground": "#bfbfbf66"
14227
14246
  };
14247
+ /** Eye-care palette: the editor shares the workbench's warm yellow surface. */
14248
+ const EYE_THEME = "dvw-eyecare";
14249
+ const EYE_COLORS = {
14250
+ "editor.background": "#f7ebc8",
14251
+ "editor.foreground": "#3b3324",
14252
+ "editorLineNumber.foreground": "#92856a",
14253
+ "editorLineNumber.activeForeground": "#5c4a2a",
14254
+ "editor.selectionBackground": "#e6d294",
14255
+ "editor.inactiveSelectionBackground": "#ecdcae",
14256
+ "editor.lineHighlightBackground": "#efe1b4",
14257
+ "editorCursor.foreground": "#6b5320",
14258
+ "editorWidget.background": "#f7ebc8",
14259
+ "editorWidget.border": "#e0cf9f",
14260
+ "editorSuggestWidget.background": "#f7ebc8",
14261
+ "editorSuggestWidget.border": "#e0cf9f",
14262
+ "editorSuggestWidget.selectedBackground": "#f0e0ae",
14263
+ "editorHoverWidget.background": "#f7ebc8",
14264
+ "editorHoverWidget.border": "#e0cf9f",
14265
+ "editorGutter.background": "#f7ebc8",
14266
+ "diffEditor.insertedTextBackground": "#b7d7a8aa",
14267
+ "diffEditor.removedTextBackground": "#e8b4ad88",
14268
+ "diffEditor.border": "#e0cf9f",
14269
+ "diffEditor.diagonalFill": "#eadcb6",
14270
+ "scrollbarSlider.background": "#92856a55",
14271
+ "scrollbarSlider.hoverBackground": "#92856a88",
14272
+ "scrollbarSlider.activeBackground": "#5c4a2a66"
14273
+ };
14274
+ function monacoThemeFor(theme) {
14275
+ return theme === "dark" ? DARK_THEME : theme === "eyecare" ? EYE_THEME : "vs";
14276
+ }
14228
14277
  function defineWorkbenchThemes(monaco) {
14229
14278
  monaco.editor.defineTheme(DARK_THEME, {
14230
14279
  base: "vs-dark",
@@ -14232,6 +14281,12 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14232
14281
  rules: DARK_RULES,
14233
14282
  colors: DARK_COLORS
14234
14283
  });
14284
+ monaco.editor.defineTheme(EYE_THEME, {
14285
+ base: "vs",
14286
+ inherit: true,
14287
+ rules: [],
14288
+ colors: EYE_COLORS
14289
+ });
14235
14290
  }
14236
14291
  /**
14237
14292
  * Bootstrap source for Monaco's AMD web workers. Workers resolve module paths against their own
@@ -14291,7 +14346,8 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14291
14346
  automaticLayout: true,
14292
14347
  readOnly: true,
14293
14348
  renderSideBySide: props.mode === "split",
14294
- theme: props.theme === "dark" ? DARK_THEME : "vs",
14349
+ useInlineViewWhenSpaceIsLimited: false,
14350
+ theme: monacoThemeFor(props.theme),
14295
14351
  fontSize: props.fontSize ?? 14,
14296
14352
  ...WORKBENCH_EDITOR_CHROME,
14297
14353
  originalEditable: false,
@@ -14319,13 +14375,17 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14319
14375
  if (value.modified.getValue() !== props.modified) value.modified.setValue(props.modified);
14320
14376
  }, [props.original, props.modified]);
14321
14377
  (0, react.useEffect)(() => {
14322
- editor.current?.updateOptions({ renderSideBySide: props.mode === "split" });
14378
+ const value = editor.current;
14379
+ if (value === void 0) return;
14380
+ value.updateOptions({ renderSideBySide: props.mode === "split" });
14381
+ const frame = requestAnimationFrame(() => value.layout());
14382
+ return () => cancelAnimationFrame(frame);
14323
14383
  }, [props.mode]);
14324
14384
  (0, react.useEffect)(() => {
14325
14385
  editor.current?.updateOptions({ fontSize: props.fontSize ?? 14 });
14326
14386
  }, [props.fontSize]);
14327
14387
  (0, react.useEffect)(() => {
14328
- if (window.monaco !== void 0) window.monaco.editor.setTheme(props.theme === "dark" ? DARK_THEME : "vs");
14388
+ if (window.monaco !== void 0) window.monaco.editor.setTheme(monacoThemeFor(props.theme));
14329
14389
  }, [props.theme]);
14330
14390
  return error === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
14331
14391
  className: "dvw-diff dvw-monaco-diff",
@@ -14383,6 +14443,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14383
14443
  const root = (0, react.useRef)(null);
14384
14444
  const editor = (0, react.useRef)();
14385
14445
  const decorations = (0, react.useRef)();
14446
+ const cleanupListeners = (0, react.useRef)(void 0);
14386
14447
  const latest = (0, react.useRef)(props);
14387
14448
  latest.current = props;
14388
14449
  const [error, setError] = (0, react.useState)();
@@ -14435,7 +14496,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14435
14496
  const instance = monaco.editor.create(root.current, {
14436
14497
  model: null,
14437
14498
  automaticLayout: true,
14438
- theme: props.theme === "dark" ? DARK_THEME : "vs",
14499
+ theme: monacoThemeFor(props.theme),
14439
14500
  fontSize: props.fontSize ?? 14,
14440
14501
  ...WORKBENCH_EDITOR_CHROME,
14441
14502
  wordWrap: "off"
@@ -14451,10 +14512,41 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14451
14512
  keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyMod.Alt | monaco.KeyCode.KeyK],
14452
14513
  run: () => latest.current.onAddToDsh?.(editorSelection(instance))
14453
14514
  });
14515
+ const mac = isMacPlatform();
14516
+ let jumpedAt = -Infinity;
14517
+ const jumpToDefinition = (clientX, clientY) => {
14518
+ const position = instance.getTargetAtClientPoint(clientX, clientY)?.position;
14519
+ if (position === null || position === void 0) return false;
14520
+ jumpedAt = performance.now();
14521
+ instance.setPosition(position);
14522
+ instance.focus();
14523
+ instance.trigger("dvw.definitionClick", "editor.action.revealDefinition", null);
14524
+ return true;
14525
+ };
14526
+ const onMouseDown = (event) => {
14527
+ if (!mac || !isMacDefinitionClick(event)) return;
14528
+ event.preventDefault();
14529
+ event.stopPropagation();
14530
+ jumpToDefinition(event.clientX, event.clientY);
14531
+ };
14532
+ const onContextMenu = (event) => {
14533
+ if (!mac || !event.ctrlKey || event.metaKey) return;
14534
+ event.preventDefault();
14535
+ event.stopPropagation();
14536
+ if (performance.now() - jumpedAt > 500) jumpToDefinition(event.clientX, event.clientY);
14537
+ };
14538
+ root.current.addEventListener("mousedown", onMouseDown, true);
14539
+ root.current.addEventListener("contextmenu", onContextMenu, true);
14540
+ cleanupListeners.current = () => {
14541
+ root.current?.removeEventListener("mousedown", onMouseDown, true);
14542
+ root.current?.removeEventListener("contextmenu", onContextMenu, true);
14543
+ };
14454
14544
  attach(monaco, instance);
14455
14545
  }).catch((error) => setError(error instanceof Error ? error.message : String(error)));
14456
14546
  return () => {
14457
14547
  disposed = true;
14548
+ cleanupListeners.current?.();
14549
+ cleanupListeners.current = void 0;
14458
14550
  const instance = editor.current;
14459
14551
  const model = instance?.getModel();
14460
14552
  const state = instance?.saveViewState();
@@ -14473,7 +14565,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14473
14565
  if (model !== null && model !== void 0 && model.getValue() !== props.value) model.setValue(props.value);
14474
14566
  }, [props.value]);
14475
14567
  (0, react.useEffect)(() => {
14476
- if (window.monaco !== void 0) window.monaco.editor.setTheme(props.theme === "dark" ? DARK_THEME : "vs");
14568
+ if (window.monaco !== void 0) window.monaco.editor.setTheme(monacoThemeFor(props.theme));
14477
14569
  }, [props.theme]);
14478
14570
  (0, react.useEffect)(() => {
14479
14571
  editor.current?.updateOptions({ fontSize: props.fontSize ?? 14 });
@@ -14574,18 +14666,18 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14574
14666
  //#endregion
14575
14667
  //#region src/client/DshMark.tsx
14576
14668
  /** Bundled DSH fish logo — self-contained, no dependence on host DOM. */
14577
- const WHALE_VIEWBOX = "0 0 23.16 17.04";
14578
- const WHALE_PATH = "M22.9168 1.43018C22.6713 1.31018 22.5658 1.53918 22.4223 1.65519C22.3733 1.69269 22.3318 1.74169 22.2903 1.78669C21.9317 2.1697 21.5127 2.42121 20.9657 2.39121C20.1657 2.34621 19.4827 2.59771 18.8787 3.20973C18.7502 2.45521 18.3236 2.0047 17.6746 1.71569C17.3351 1.56568 16.9916 1.41518 16.7536 1.08867C16.5876 0.856163 16.5421 0.597155 16.4591 0.341647C16.4061 0.187643 16.3536 0.0301382 16.1761 0.00363739C15.9836 -0.0263635 15.9081 0.135141 15.8326 0.270145C15.5306 0.822162 15.4136 1.43018 15.4251 2.0462C15.4516 3.43174 16.0366 4.53527 17.1991 5.3203C17.3311 5.4103 17.3651 5.5003 17.3236 5.63181C17.2441 5.90231 17.1501 6.16482 17.0671 6.43533C17.0141 6.60784 16.9351 6.64584 16.7501 6.57033C16.1121 6.30383 15.5611 5.90931 15.074 5.4328C14.2475 4.63328 13.5 3.75075 12.568 3.05973C12.349 2.89822 12.13 2.74822 11.9034 2.60522C10.9524 1.68169 12.028 0.923165 12.277 0.833162C12.5375 0.739159 12.3675 0.41615 11.5259 0.42015C10.6844 0.42365 9.91439 0.705658 8.93286 1.08117C8.78935 1.13767 8.63835 1.17867 8.48384 1.21267C7.59332 1.04367 6.66829 1.00617 5.70226 1.11517C3.88321 1.31768 2.43016 2.1777 1.36213 3.64575C0.0790928 5.4103 -0.222916 7.41536 0.146595 9.50642C0.535106 11.7105 1.66014 13.535 3.38869 14.9616C5.18125 16.4406 7.24581 17.1657 9.60138 17.0266C11.0319 16.9441 12.6245 16.7526 14.421 15.2321C14.874 15.4576 15.3496 15.5476 16.1381 15.6151C16.7456 15.6716 17.3306 15.5851 17.7836 15.4911C18.4931 15.3411 18.4441 14.6841 18.1876 14.5636C16.1081 13.595 16.5646 13.9891 16.1496 13.67C17.2061 12.42 18.8202 10.1979 19.3182 7.17235C19.3672 6.83834 19.4297 6.36783 19.4222 6.09732C19.4182 5.93231 19.4562 5.86831 19.6447 5.84931C20.1657 5.78931 20.6712 5.64681 21.1357 5.3913C22.4833 4.65528 23.0268 3.44624 23.1548 1.9972C23.1738 1.77569 23.1508 1.54668 22.9168 1.43018ZM11.1749 14.4736C9.15936 12.889 8.18184 12.3675 7.77832 12.39C7.40081 12.4125 7.46881 12.8445 7.55182 13.126C7.63882 13.404 7.75182 13.5955 7.91033 13.8396C8.01983 14.0011 8.09533 14.2411 7.80083 14.4216C7.15181 14.8231 6.02327 14.2866 5.97027 14.2601C4.65673 13.4865 3.5587 12.4655 2.78467 11.069C2.03715 9.72493 1.60314 8.28289 1.53164 6.74384C1.51264 6.37233 1.62214 6.24082 1.99215 6.17332C2.47916 6.08332 2.98118 6.06432 3.46769 6.13582C5.52476 6.43633 7.27581 7.35586 8.74385 8.8129C9.58188 9.64243 10.2159 10.634 10.8689 11.6025C11.5634 12.631 12.3105 13.611 13.262 14.4146C13.598 14.6961 13.866 14.9101 14.1225 15.0681C13.349 15.1546 12.058 15.1731 11.1749 14.4746L11.1749 14.4736ZM12.141 8.25988C12.141 8.09488 12.273 7.96338 12.439 7.96338C12.4765 7.96338 12.5105 7.97088 12.541 7.98188C12.5825 7.99688 12.6205 8.01938 12.6505 8.05338C12.7035 8.10588 12.7335 8.18088 12.7335 8.25988C12.7335 8.42489 12.6015 8.55639 12.4355 8.55639C12.2695 8.55639 12.141 8.42489 12.141 8.25988ZM15.1415 9.79893C14.949 9.87793 14.7565 9.94544 14.5715 9.95294C14.2845 9.96794 13.9715 9.85143 13.8015 9.70893C13.5375 9.48742 13.3485 9.36342 13.2695 8.97691C13.2355 8.8119 13.2545 8.55639 13.2845 8.40989C13.3525 8.09438 13.277 7.89187 13.0545 7.70787C12.8735 7.55786 12.643 7.51636 12.39 7.51636C12.2955 7.51636 12.209 7.47486 12.1445 7.44136C12.039 7.38886 11.9519 7.25735 12.035 7.09585C12.0615 7.04335 12.19 6.91584 12.22 6.89334C12.5635 6.69784 12.9595 6.76184 13.326 6.90834C13.6655 7.04735 13.9225 7.30236 14.292 7.66287C14.6695 8.09838 14.7375 8.21838 14.9525 8.54539C15.1225 8.8009 15.277 9.06341 15.3831 9.36392C15.4471 9.55142 15.3641 9.70493 15.1415 9.79893Z";
14669
+ const DSH_MARK_VIEWBOX = "0 0 23.16 17.04";
14670
+ const DSH_MARK_PATH = "M22.9168 1.43018C22.6713 1.31018 22.5658 1.53918 22.4223 1.65519C22.3733 1.69269 22.3318 1.74169 22.2903 1.78669C21.9317 2.1697 21.5127 2.42121 20.9657 2.39121C20.1657 2.34621 19.4827 2.59771 18.8787 3.20973C18.7502 2.45521 18.3236 2.0047 17.6746 1.71569C17.3351 1.56568 16.9916 1.41518 16.7536 1.08867C16.5876 0.856163 16.5421 0.597155 16.4591 0.341647C16.4061 0.187643 16.3536 0.0301382 16.1761 0.00363739C15.9836 -0.0263635 15.9081 0.135141 15.8326 0.270145C15.5306 0.822162 15.4136 1.43018 15.4251 2.0462C15.4516 3.43174 16.0366 4.53527 17.1991 5.3203C17.3311 5.4103 17.3651 5.5003 17.3236 5.63181C17.2441 5.90231 17.1501 6.16482 17.0671 6.43533C17.0141 6.60784 16.9351 6.64584 16.7501 6.57033C16.1121 6.30383 15.5611 5.90931 15.074 5.4328C14.2475 4.63328 13.5 3.75075 12.568 3.05973C12.349 2.89822 12.13 2.74822 11.9034 2.60522C10.9524 1.68169 12.028 0.923165 12.277 0.833162C12.5375 0.739159 12.3675 0.41615 11.5259 0.42015C10.6844 0.42365 9.91439 0.705658 8.93286 1.08117C8.78935 1.13767 8.63835 1.17867 8.48384 1.21267C7.59332 1.04367 6.66829 1.00617 5.70226 1.11517C3.88321 1.31768 2.43016 2.1777 1.36213 3.64575C0.0790928 5.4103 -0.222916 7.41536 0.146595 9.50642C0.535106 11.7105 1.66014 13.535 3.38869 14.9616C5.18125 16.4406 7.24581 17.1657 9.60138 17.0266C11.0319 16.9441 12.6245 16.7526 14.421 15.2321C14.874 15.4576 15.3496 15.5476 16.1381 15.6151C16.7456 15.6716 17.3306 15.5851 17.7836 15.4911C18.4931 15.3411 18.4441 14.6841 18.1876 14.5636C16.1081 13.595 16.5646 13.9891 16.1496 13.67C17.2061 12.42 18.8202 10.1979 19.3182 7.17235C19.3672 6.83834 19.4297 6.36783 19.4222 6.09732C19.4182 5.93231 19.4562 5.86831 19.6447 5.84931C20.1657 5.78931 20.6712 5.64681 21.1357 5.3913C22.4833 4.65528 23.0268 3.44624 23.1548 1.9972C23.1738 1.77569 23.1508 1.54668 22.9168 1.43018ZM11.1749 14.4736C9.15936 12.889 8.18184 12.3675 7.77832 12.39C7.40081 12.4125 7.46881 12.8445 7.55182 13.126C7.63882 13.404 7.75182 13.5955 7.91033 13.8396C8.01983 14.0011 8.09533 14.2411 7.80083 14.4216C7.15181 14.8231 6.02327 14.2866 5.97027 14.2601C4.65673 13.4865 3.5587 12.4655 2.78467 11.069C2.03715 9.72493 1.60314 8.28289 1.53164 6.74384C1.51264 6.37233 1.62214 6.24082 1.99215 6.17332C2.47916 6.08332 2.98118 6.06432 3.46769 6.13582C5.52476 6.43633 7.27581 7.35586 8.74385 8.8129C9.58188 9.64243 10.2159 10.634 10.8689 11.6025C11.5634 12.631 12.3105 13.611 13.262 14.4146C13.598 14.6961 13.866 14.9101 14.1225 15.0681C13.349 15.1546 12.058 15.1731 11.1749 14.4746L11.1749 14.4736ZM12.141 8.25988C12.141 8.09488 12.273 7.96338 12.439 7.96338C12.4765 7.96338 12.5105 7.97088 12.541 7.98188C12.5825 7.99688 12.6205 8.01938 12.6505 8.05338C12.7035 8.10588 12.7335 8.18088 12.7335 8.25988C12.7335 8.42489 12.6015 8.55639 12.4355 8.55639C12.2695 8.55639 12.141 8.42489 12.141 8.25988ZM15.1415 9.79893C14.949 9.87793 14.7565 9.94544 14.5715 9.95294C14.2845 9.96794 13.9715 9.85143 13.8015 9.70893C13.5375 9.48742 13.3485 9.36342 13.2695 8.97691C13.2355 8.8119 13.2545 8.55639 13.2845 8.40989C13.3525 8.09438 13.277 7.89187 13.0545 7.70787C12.8735 7.55786 12.643 7.51636 12.39 7.51636C12.2955 7.51636 12.209 7.47486 12.1445 7.44136C12.039 7.38886 11.9519 7.25735 12.035 7.09585C12.0615 7.04335 12.19 6.91584 12.22 6.89334C12.5635 6.69784 12.9595 6.76184 13.326 6.90834C13.6655 7.04735 13.9225 7.30236 14.292 7.66287C14.6695 8.09838 14.7375 8.21838 14.9525 8.54539C15.1225 8.8009 15.277 9.06341 15.3831 9.36392C15.4471 9.55142 15.3641 9.70493 15.1415 9.79893Z";
14579
14671
  function DshMark({ size = 18 }) {
14580
14672
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
14581
14673
  className: "dvw-dsh-mark",
14582
14674
  width: size,
14583
14675
  height: size * 17.04 / 23.16,
14584
- viewBox: WHALE_VIEWBOX,
14676
+ viewBox: DSH_MARK_VIEWBOX,
14585
14677
  fill: "none",
14586
14678
  "aria-hidden": "true",
14587
14679
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
14588
- d: WHALE_PATH,
14680
+ d: DSH_MARK_PATH,
14589
14681
  fill: "currentColor"
14590
14682
  })
14591
14683
  });
@@ -14608,16 +14700,26 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14608
14700
  function toggleActivityHidden(hidden, id) {
14609
14701
  return hidden.includes(id) ? hidden.filter((value) => value !== id) : [...hidden, id];
14610
14702
  }
14611
- /** VS Code-style activity bar: pointer drag with a floating ghost and live reordering, right-click hide. */
14703
+ /**
14704
+ * VS Code-style activity bar: every view can be dragged into a new slot while `fixed` actions stay pinned on
14705
+ * top and `bottom` actions stay pinned at the foot. Reordering is computed from pointer position so it keeps
14706
+ * working when the DOM shifts under a fast drag.
14707
+ */
14612
14708
  function ActivityBar({ views, fixed, bottom = [], order, hidden, onOrderChange, onHiddenChange }) {
14613
14709
  const [menu, setMenu] = (0, react.useState)();
14614
14710
  const drag = (0, react.useRef)();
14711
+ const draggingRef = (0, react.useRef)(false);
14615
14712
  const nodes = (0, react.useRef)(/* @__PURE__ */ new Map());
14616
14713
  const flip = (0, react.useRef)();
14617
- const suppressClick = (0, react.useRef)(false);
14714
+ const didDrag = (0, react.useRef)(false);
14618
14715
  const [draggingId, setDraggingId] = (0, react.useState)();
14619
14716
  const [ghost, setGhost] = (0, react.useState)();
14620
14717
  const [preview, setPreview] = (0, react.useState)();
14718
+ const previewRef = (0, react.useRef)();
14719
+ const orderRef = (0, react.useRef)(order);
14720
+ const visibleRef = (0, react.useRef)([]);
14721
+ previewRef.current = preview;
14722
+ orderRef.current = order;
14621
14723
  (0, react.useEffect)(() => {
14622
14724
  if (menu === void 0) return;
14623
14725
  const close = () => setMenu(void 0);
@@ -14635,6 +14737,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14635
14737
  const before = flip.current;
14636
14738
  flip.current = void 0;
14637
14739
  if (before === void 0) return;
14740
+ if (draggingRef.current) return;
14638
14741
  for (const [id, element] of nodes.current) {
14639
14742
  const previous = before.get(id);
14640
14743
  if (previous === void 0) continue;
@@ -14647,69 +14750,97 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14647
14750
  }
14648
14751
  });
14649
14752
  const visible = views.filter((view) => !hidden.includes(view.id));
14650
- const currentOrder = preview ?? order;
14651
- const ordered = currentOrder.flatMap((id) => visible.filter((view) => view.id === id));
14753
+ visibleRef.current = visible;
14754
+ const ordered = (preview ?? order).flatMap((id) => visible.filter((view) => view.id === id));
14652
14755
  const toggled = (id) => onHiddenChange(toggleActivityHidden(hidden, id));
14653
14756
  const target = menu?.target === void 0 ? void 0 : views.find((view) => view.id === menu.target);
14654
14757
  const capturePositions = () => {
14655
14758
  flip.current = new Map([...nodes.current].map(([id, element]) => [id, element.getBoundingClientRect().top]));
14656
14759
  };
14657
- const beginDrag = (event, id) => {
14658
- if (event.button !== 0) return;
14659
- drag.current = {
14660
- id,
14661
- x: event.clientX,
14662
- y: event.clientY,
14663
- active: false
14664
- };
14665
- event.currentTarget.setPointerCapture?.(event.pointerId);
14666
- };
14667
- const moveDrag = (event, id) => {
14760
+ const moveDrag = (clientX, clientY) => {
14668
14761
  const state = drag.current;
14669
- if (state === void 0 || state.id !== id) return;
14762
+ if (state === void 0) return;
14670
14763
  if (!state.active) {
14671
- if (Math.abs(event.clientX - state.x) + Math.abs(event.clientY - state.y) < 5) return;
14764
+ if (Math.abs(clientX - state.x) + Math.abs(clientY - state.y) < 5) return;
14672
14765
  state.active = true;
14673
- setDraggingId(id);
14766
+ draggingRef.current = true;
14767
+ setDraggingId(state.id);
14674
14768
  }
14675
14769
  setGhost({
14676
- x: event.clientX,
14677
- y: event.clientY
14770
+ x: clientX,
14771
+ y: clientY
14678
14772
  });
14679
- const element = document.elementFromPoint(event.clientX, event.clientY)?.closest("[data-act-id]");
14680
- if (element === null || element === void 0) return;
14681
- const targetId = element.dataset.actId;
14682
- if (targetId === void 0 || targetId === id || !visible.some((view) => view.id === targetId)) return;
14683
- const rect = element.getBoundingClientRect();
14684
- const ids = currentOrder.filter((value) => visible.some((view) => view.id === value));
14685
- const index = ids.indexOf(targetId);
14686
- if (index < 0) return;
14687
- const next = moveActivity(currentOrder, id, event.clientY > rect.top + rect.height / 2 ? ids[index + 1] : targetId);
14688
- if (next.join("|") === currentOrder.join("|")) return;
14773
+ const base = previewRef.current ?? orderRef.current;
14774
+ const visibleIds = new Set(visibleRef.current.map((view) => view.id));
14775
+ const slots = base.filter((id) => visibleIds.has(id) && id !== state.id);
14776
+ let index = 0;
14777
+ for (const id of slots) {
14778
+ const element = nodes.current.get(id);
14779
+ if (element === void 0) continue;
14780
+ const rect = element.getBoundingClientRect();
14781
+ if (clientY > rect.top + rect.height / 2) index += 1;
14782
+ }
14783
+ const next = moveActivity(base, state.id, slots[index]);
14784
+ if (next.join("|") === base.join("|")) return;
14689
14785
  capturePositions();
14786
+ previewRef.current = next;
14690
14787
  setPreview(next);
14691
14788
  };
14692
- const endDrag = (event) => {
14789
+ const endDrag = () => {
14693
14790
  const state = drag.current;
14694
14791
  drag.current = void 0;
14695
14792
  if (state?.active) {
14696
- suppressClick.current = true;
14697
- window.setTimeout(() => {
14698
- suppressClick.current = false;
14699
- }, 0);
14700
- if (preview !== void 0) onOrderChange(preview);
14793
+ didDrag.current = true;
14794
+ const next = previewRef.current;
14795
+ if (next !== void 0) onOrderChange(next);
14701
14796
  }
14702
- event.currentTarget.releasePointerCapture?.(event.pointerId);
14797
+ draggingRef.current = false;
14798
+ previewRef.current = void 0;
14703
14799
  setDraggingId(void 0);
14704
14800
  setGhost(void 0);
14705
14801
  setPreview(void 0);
14706
14802
  };
14707
14803
  const cancelDrag = () => {
14708
14804
  drag.current = void 0;
14805
+ draggingRef.current = false;
14806
+ previewRef.current = void 0;
14709
14807
  setDraggingId(void 0);
14710
14808
  setGhost(void 0);
14711
14809
  setPreview(void 0);
14712
14810
  };
14811
+ const handlers = (0, react.useRef)({
14812
+ moveDrag,
14813
+ endDrag,
14814
+ cancelDrag
14815
+ });
14816
+ handlers.current = {
14817
+ moveDrag,
14818
+ endDrag,
14819
+ cancelDrag
14820
+ };
14821
+ (0, react.useEffect)(() => {
14822
+ const move = (event) => handlers.current.moveDrag(event.clientX, event.clientY);
14823
+ const up = () => handlers.current.endDrag();
14824
+ const cancel = () => handlers.current.cancelDrag();
14825
+ window.addEventListener("pointermove", move);
14826
+ window.addEventListener("pointerup", up);
14827
+ window.addEventListener("pointercancel", cancel);
14828
+ return () => {
14829
+ window.removeEventListener("pointermove", move);
14830
+ window.removeEventListener("pointerup", up);
14831
+ window.removeEventListener("pointercancel", cancel);
14832
+ };
14833
+ }, []);
14834
+ const beginDrag = (event, id) => {
14835
+ if (event.button !== 0) return;
14836
+ didDrag.current = false;
14837
+ drag.current = {
14838
+ id,
14839
+ x: event.clientX,
14840
+ y: event.clientY,
14841
+ active: false
14842
+ };
14843
+ };
14713
14844
  const renderView = (view) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
14714
14845
  ref: (element) => {
14715
14846
  if (element === null) nodes.current.delete(view.id);
@@ -14722,11 +14853,12 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14722
14853
  disabled: view.disabled,
14723
14854
  title: view.label,
14724
14855
  onPointerDown: (event) => beginDrag(event, view.id),
14725
- onPointerMove: (event) => moveDrag(event, view.id),
14726
- onPointerUp: (event) => endDrag(event),
14727
- onPointerCancel: cancelDrag,
14728
14856
  onClick: () => {
14729
- if (!suppressClick.current) view.onActivate();
14857
+ if (didDrag.current) {
14858
+ didDrag.current = false;
14859
+ return;
14860
+ }
14861
+ view.onActivate();
14730
14862
  },
14731
14863
  onContextMenu: (event) => {
14732
14864
  event.preventDefault();
@@ -14750,10 +14882,6 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14750
14882
  });
14751
14883
  },
14752
14884
  children: [
14753
- ordered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
14754
- className: "dvw-activity-empty",
14755
- "aria-hidden": "true"
14756
- }) : ordered.map(renderView),
14757
14885
  fixed.map((view) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
14758
14886
  className: "dvw-act",
14759
14887
  "data-act-id": view.id,
@@ -14763,6 +14891,10 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14763
14891
  onClick: view.onActivate,
14764
14892
  children: view.icon
14765
14893
  }, view.id)),
14894
+ ordered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
14895
+ className: "dvw-activity-empty",
14896
+ "aria-hidden": "true"
14897
+ }) : ordered.map(renderView),
14766
14898
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
14767
14899
  className: "dvw-activity-bottom",
14768
14900
  children: bottom.map((view) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
@@ -14837,7 +14969,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14837
14969
  //#endregion
14838
14970
  //#region src/client/WorkspaceSwitcher.tsx
14839
14971
  /** Centered switcher: existing workspaces, their sessions, and a new-workspace action. */
14840
- function WorkspaceSwitcher({ choices, activeSessionId, unavailable, busy, error, onCreate, onSwitch, onOpenWorkspace, onClose }) {
14972
+ function WorkspaceSwitcher({ choices, activeSessionId, unavailable, busy, error, theme, onCreate, onSwitch, onOpenWorkspace, onClose }) {
14841
14973
  const current = choices.find((workspace) => workspace.sessions.some((session) => session.id === activeSessionId))?.id;
14842
14974
  const [expanded, setExpanded] = (0, react.useState)(current ?? choices[0]?.id);
14843
14975
  (0, react.useEffect)(() => {
@@ -14847,98 +14979,102 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14847
14979
  window.addEventListener("keydown", escape);
14848
14980
  return () => window.removeEventListener("keydown", escape);
14849
14981
  }, [onClose]);
14850
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
14851
- className: "dvw-confirm-backdrop",
14852
- role: "presentation",
14853
- onMouseDown: onClose,
14854
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
14855
- className: "dvw-workspace-switcher",
14856
- role: "dialog",
14857
- "aria-modal": "true",
14858
- "aria-label": "打开工作区",
14859
- onMouseDown: (event) => event.stopPropagation(),
14860
- children: [
14861
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", { children: "打开工作区" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
14862
- className: "dvw-icon",
14863
- title: "关闭",
14864
- onClick: onClose,
14865
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "close" })
14866
- })] }),
14867
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
14868
- className: "dvw-workspace-list",
14869
- children: unavailable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
14870
- className: "dvw-workspace-empty",
14871
- children: "无法读取 DSH 的工作区列表,请重启 DSH 后再试。"
14872
- }) : choices.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
14873
- className: "dvw-workspace-empty",
14874
- children: "还没有工作区,先新建一个。"
14875
- }) : choices.map((workspace) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
14876
- className: "dvw-workspace-group",
14877
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
14878
- className: "dvw-workspace-row",
14879
- "data-expanded": expanded === workspace.id,
14880
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
14881
- className: "dvw-workspace-toggle",
14882
- "aria-expanded": expanded === workspace.id,
14883
- onClick: () => setExpanded((value) => value === workspace.id ? void 0 : workspace.id),
14884
- children: [
14885
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "folder-opened" }),
14886
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
14887
- className: "dvw-workspace-title",
14888
- children: workspace.title
14889
- }),
14890
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
14891
- className: "dvw-workspace-path",
14892
- children: workspace.path
14893
- }),
14894
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: expanded === workspace.id ? "chevron-down" : "chevron-right" })
14895
- ]
14896
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
14897
- className: "dvw-icon dvw-workspace-enter",
14898
- title: "进入此工作区",
14899
- onClick: () => onOpenWorkspace(workspace.id),
14900
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "arrow-right" })
14982
+ return (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
14983
+ className: "dvw-overlay dvw-workspace-layer",
14984
+ "data-dvw-theme": theme,
14985
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
14986
+ className: "dvw-workspace-backdrop",
14987
+ role: "presentation",
14988
+ onMouseDown: onClose,
14989
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
14990
+ className: "dvw-workspace-switcher",
14991
+ role: "dialog",
14992
+ "aria-modal": "true",
14993
+ "aria-label": "打开工作区",
14994
+ onMouseDown: (event) => event.stopPropagation(),
14995
+ children: [
14996
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", { children: "打开工作区" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
14997
+ className: "dvw-icon",
14998
+ title: "关闭",
14999
+ onClick: onClose,
15000
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "close" })
15001
+ })] }),
15002
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
15003
+ className: "dvw-workspace-list",
15004
+ children: unavailable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
15005
+ className: "dvw-workspace-empty",
15006
+ children: "无法读取 DSH 的工作区列表,请重启 DSH 后再试。"
15007
+ }) : choices.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
15008
+ className: "dvw-workspace-empty",
15009
+ children: "还没有工作区,先新建一个。"
15010
+ }) : choices.map((workspace) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
15011
+ className: "dvw-workspace-group",
15012
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
15013
+ className: "dvw-workspace-row",
15014
+ "data-expanded": expanded === workspace.id,
15015
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
15016
+ className: "dvw-workspace-toggle",
15017
+ "aria-expanded": expanded === workspace.id,
15018
+ onClick: () => setExpanded((value) => value === workspace.id ? void 0 : workspace.id),
15019
+ children: [
15020
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "folder-opened" }),
15021
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
15022
+ className: "dvw-workspace-title",
15023
+ children: workspace.title
15024
+ }),
15025
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
15026
+ className: "dvw-workspace-path",
15027
+ children: workspace.path
15028
+ }),
15029
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: expanded === workspace.id ? "chevron-down" : "chevron-right" })
15030
+ ]
15031
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
15032
+ className: "dvw-icon dvw-workspace-enter",
15033
+ title: "进入此工作区",
15034
+ onClick: () => onOpenWorkspace(workspace.id),
15035
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "arrow-right" })
15036
+ })]
15037
+ }), expanded === workspace.id && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
15038
+ className: "dvw-workspace-sessions",
15039
+ children: workspace.sessions.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
15040
+ className: "dvw-workspace-empty",
15041
+ children: "此工作区还没有会话"
15042
+ }) : workspace.sessions.map((session) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
15043
+ className: "dvw-workspace-session",
15044
+ "data-active": session.id === activeSessionId,
15045
+ onClick: () => onSwitch(session.id),
15046
+ children: [
15047
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "comment-discussion" }),
15048
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
15049
+ className: "dvw-workspace-session-title",
15050
+ children: session.title
15051
+ }),
15052
+ session.id === activeSessionId && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
15053
+ className: "dvw-workspace-current",
15054
+ children: "当前"
15055
+ })
15056
+ ]
15057
+ }, session.id))
14901
15058
  })]
14902
- }), expanded === workspace.id && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
14903
- className: "dvw-workspace-sessions",
14904
- children: workspace.sessions.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
14905
- className: "dvw-workspace-empty",
14906
- children: "此工作区还没有会话"
14907
- }) : workspace.sessions.map((session) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
14908
- className: "dvw-workspace-session",
14909
- "data-active": session.id === activeSessionId,
14910
- onClick: () => onSwitch(session.id),
14911
- children: [
14912
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "comment-discussion" }),
14913
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
14914
- className: "dvw-workspace-session-title",
14915
- children: session.title
14916
- }),
14917
- session.id === activeSessionId && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
14918
- className: "dvw-workspace-current",
14919
- children: "当前"
14920
- })
14921
- ]
14922
- }, session.id))
14923
- })]
14924
- }, workspace.id))
14925
- }),
14926
- error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
14927
- className: "dvw-workspace-error",
14928
- children: error
14929
- }),
14930
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
14931
- className: "dvw-primary-button",
14932
- disabled: busy,
14933
- onClick: onCreate,
14934
- children: busy ? "正在打开…" : "新建工作区…"
14935
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
14936
- onClick: onClose,
14937
- children: "取消"
14938
- })] })
14939
- ]
15059
+ }, workspace.id))
15060
+ }),
15061
+ error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
15062
+ className: "dvw-workspace-error",
15063
+ children: error
15064
+ }),
15065
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
15066
+ className: "dvw-primary-button",
15067
+ disabled: busy,
15068
+ onClick: onCreate,
15069
+ children: busy ? "正在打开…" : "新建工作区…"
15070
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
15071
+ onClick: onClose,
15072
+ children: "取消"
15073
+ })] })
15074
+ ]
15075
+ })
14940
15076
  })
14941
- });
15077
+ }), document.body);
14942
15078
  }
14943
15079
  //#endregion
14944
15080
  //#region src/client/lsp.ts
@@ -15336,53 +15472,6 @@ Please report this to https://github.com/markedjs/marked.`, e) {
15336
15472
  for (const id of [...this.connections.keys()]) this.stop(id);
15337
15473
  }
15338
15474
  };
15339
- /** Language server that handles a workspace path, derived from its extension or well-known filename. */
15340
- function languageServerIdForPath(path) {
15341
- const name = path.split("/").at(-1)?.toLowerCase() ?? "";
15342
- if (name === "dockerfile" || name.startsWith("dockerfile.")) return "dockerfile";
15343
- const extension = name.includes(".") ? name.split(".").at(-1) : void 0;
15344
- if (extension === void 0) return void 0;
15345
- if ([
15346
- "ts",
15347
- "tsx",
15348
- "js",
15349
- "jsx",
15350
- "mjs",
15351
- "cjs",
15352
- "mts",
15353
- "cts"
15354
- ].includes(extension)) return "typescript";
15355
- if (extension === "py" || extension === "pyi") return "python";
15356
- if (extension === "php") return "php";
15357
- if ([
15358
- "sh",
15359
- "bash",
15360
- "zsh",
15361
- "ksh"
15362
- ].includes(extension)) return "shell";
15363
- if (extension === "yaml" || extension === "yml") return "yaml";
15364
- if (extension === "json" || extension === "jsonc") return "json";
15365
- if ([
15366
- "css",
15367
- "scss",
15368
- "less"
15369
- ].includes(extension)) return "css";
15370
- if (extension === "html" || extension === "htm") return "html";
15371
- if (extension === "go") return "go";
15372
- if (extension === "rs") return "rust";
15373
- if ([
15374
- "c",
15375
- "h",
15376
- "cc",
15377
- "cpp",
15378
- "cxx",
15379
- "hpp",
15380
- "hxx"
15381
- ].includes(extension)) return "cpp";
15382
- if (extension === "java") return "java";
15383
- if (extension === "cs") return "csharp";
15384
- if (extension === "lua") return "lua";
15385
- }
15386
15475
  /** True for the add-to-DSH chord; Monaco binds it separately, so this covers the Explorer. */
15387
15476
  function isAddToDshShortcut(event) {
15388
15477
  return !event.isComposing && (event.ctrlKey || event.metaKey) && event.altKey && !event.shiftKey && event.code === "KeyK";
@@ -49679,6 +49768,12 @@ section.${c}>footer { z-index: 1; }
49679
49768
  };
49680
49769
  //#endregion
49681
49770
  //#region src/client/Workbench.tsx
49771
+ const MARKDOWN_DEFAULT_VIEW_KEY = "dvw:markdown-default-view";
49772
+ /** Keep persisted or dragged widths inside the range the DSH composer can lay out cleanly. */
49773
+ function clampChatWidth(width) {
49774
+ if (!Number.isFinite(width)) return 440;
49775
+ return Math.max(440, Math.min(720, Math.round(width)));
49776
+ }
49682
49777
  /** Calculate a panel width from a horizontal pointer movement. */
49683
49778
  function resizedPanelWidth(startWidth, startX, nextX, direction, min, max) {
49684
49779
  return Math.max(min, Math.min(max, Math.round(startWidth + (nextX - startX) * direction)));
@@ -49751,6 +49846,14 @@ section.${c}>footer { z-index: 1; }
49751
49846
  }
49752
49847
  });
49753
49848
  }
49849
+ /** Read the saved Markdown default without depending on browser storage during unit tests. */
49850
+ function markdownDefaultView() {
49851
+ try {
49852
+ return localStorage.getItem("dvw:markdown-default-view") === "source" ? "source" : "preview";
49853
+ } catch {
49854
+ return "preview";
49855
+ }
49856
+ }
49754
49857
  function unloadedTab(path) {
49755
49858
  return {
49756
49859
  instance: Symbol(path),
@@ -49763,7 +49866,7 @@ section.${c}>footer { z-index: 1; }
49763
49866
  tooLarge: false,
49764
49867
  dirty: false,
49765
49868
  loaded: false,
49766
- preview: /\.md$/i.test(path)
49869
+ preview: /\.md$/i.test(path) ? markdownDefaultView() === "preview" : void 0
49767
49870
  };
49768
49871
  }
49769
49872
  function WorkbenchTitlebar({ name }) {
@@ -50932,6 +51035,8 @@ section.${c}>footer { z-index: 1; }
50932
51035
  const [branches, setBranches] = (0, react.useState)([]);
50933
51036
  const [newBranch, setNewBranch] = (0, react.useState)("");
50934
51037
  const [branchError, setBranchError] = (0, react.useState)();
51038
+ const [generating, setGenerating] = (0, react.useState)(false);
51039
+ const [commitMenu, setCommitMenu] = (0, react.useState)(false);
50935
51040
  const refresh = (0, react.useCallback)(() => {
50936
51041
  Promise.all([api("git.status", { sessionId: props.sessionId }), api("git.action", {
50937
51042
  sessionId: props.sessionId,
@@ -50988,6 +51093,19 @@ section.${c}>footer { z-index: 1; }
50988
51093
  window.removeEventListener("keydown", escape);
50989
51094
  };
50990
51095
  }, [branchMenu]);
51096
+ (0, react.useEffect)(() => {
51097
+ if (!commitMenu) return;
51098
+ const close = () => setCommitMenu(false);
51099
+ const escape = (event) => {
51100
+ if (event.key === "Escape") close();
51101
+ };
51102
+ window.addEventListener("pointerdown", close);
51103
+ window.addEventListener("keydown", escape);
51104
+ return () => {
51105
+ window.removeEventListener("pointerdown", close);
51106
+ window.removeEventListener("keydown", escape);
51107
+ };
51108
+ }, [commitMenu]);
50991
51109
  const openBranchMenu = async () => {
50992
51110
  if (branchMenu) {
50993
51111
  setBranchMenu(false);
@@ -51084,6 +51202,23 @@ section.${c}>footer { z-index: 1; }
51084
51202
  setBusy(false);
51085
51203
  }
51086
51204
  };
51205
+ const generateMessage = async () => {
51206
+ if (generating) return;
51207
+ setGenerating(true);
51208
+ setError(void 0);
51209
+ try {
51210
+ const result = await api("git.commitMessage", {
51211
+ sessionId: props.sessionId,
51212
+ detail: props.preferences.detail,
51213
+ language: props.preferences.language
51214
+ });
51215
+ setMessage(result.message);
51216
+ } catch (error) {
51217
+ setError(error instanceof ApiError ? error.message : String(error));
51218
+ } finally {
51219
+ setGenerating(false);
51220
+ }
51221
+ };
51087
51222
  const staged = status?.changes.filter((change) => change.index !== "." && change.index !== "?") ?? [];
51088
51223
  const changed = status?.changes.filter((change) => change.worktree !== "." || change.untracked) ?? [];
51089
51224
  const renderChange = (change, group) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -51217,19 +51352,89 @@ section.${c}>footer { z-index: 1; }
51217
51352
  }),
51218
51353
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
51219
51354
  className: "dvw-commit",
51220
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
51221
- className: "dvw-input",
51222
- value: message,
51223
- onChange: (event) => setMessage(event.target.value),
51224
- onKeyDown: (event) => {
51225
- if (event.ctrlKey && event.key === "Enter" && message.trim()) action("commit", void 0, message).then(() => setMessage(""));
51226
- },
51227
- placeholder: `消息 (Ctrl+Enter 在“${status.branch}”提交)`
51228
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
51229
- className: "dvw-commit-button",
51230
- disabled: busy || !message.trim(),
51231
- onClick: () => void action("commit", void 0, message).then(() => setMessage("")),
51232
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "check" }), " 提交"]
51355
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
51356
+ className: "dvw-commit-box",
51357
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
51358
+ className: "dvw-textarea dvw-commit-input",
51359
+ rows: 1,
51360
+ value: message,
51361
+ onChange: (event) => setMessage(event.target.value),
51362
+ onKeyDown: (event) => {
51363
+ if ((event.ctrlKey || event.metaKey) && event.key === "Enter" && message.trim()) action("commit", void 0, message).then(() => setMessage(""));
51364
+ },
51365
+ placeholder: `消息 (${isMacPlatform() ? "⌘" : "Ctrl+"}Enter 在“${status.branch}”提交)`
51366
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
51367
+ className: "dvw-commit-ai",
51368
+ disabled: busy || generating || status.changes.length === 0,
51369
+ title: generating ? "正在生成提交信息" : "根据当前更改生成提交信息",
51370
+ "aria-label": "生成提交信息",
51371
+ onClick: () => void generateMessage(),
51372
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "sparkle" })
51373
+ })]
51374
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
51375
+ className: "dvw-commit-actions",
51376
+ children: [
51377
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
51378
+ className: "dvw-commit-button",
51379
+ disabled: busy || !message.trim() || status.changes.length === 0,
51380
+ title: "提交暂存的更改",
51381
+ onClick: () => void action("commit", void 0, message).then(() => setMessage("")),
51382
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "check" }), " 提交"]
51383
+ }),
51384
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
51385
+ className: "dvw-commit-more",
51386
+ disabled: busy || !message.trim() || status.changes.length === 0,
51387
+ "aria-haspopup": "menu",
51388
+ "aria-expanded": commitMenu,
51389
+ title: "更多提交操作",
51390
+ "aria-label": "更多提交操作",
51391
+ onClick: () => setCommitMenu((value) => !value),
51392
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "chevron-down" })
51393
+ }),
51394
+ commitMenu && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
51395
+ className: "dvw-commit-menu",
51396
+ role: "menu",
51397
+ onPointerDown: (event) => event.stopPropagation(),
51398
+ children: [
51399
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
51400
+ role: "menuitem",
51401
+ onClick: () => {
51402
+ setCommitMenu(false);
51403
+ action("commit", void 0, message).then(() => setMessage(""));
51404
+ },
51405
+ children: "提交"
51406
+ }),
51407
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
51408
+ role: "menuitem",
51409
+ onClick: () => {
51410
+ setCommitMenu(false);
51411
+ action("commit.amend", void 0, message).then(() => setMessage(""));
51412
+ },
51413
+ children: "提交(修改)"
51414
+ }),
51415
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
51416
+ className: "dvw-commit-menu-sep",
51417
+ role: "separator"
51418
+ }),
51419
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
51420
+ role: "menuitem",
51421
+ onClick: () => {
51422
+ setCommitMenu(false);
51423
+ action("commit", void 0, message).then(() => action("push")).then(() => setMessage(""));
51424
+ },
51425
+ children: "提交和推送"
51426
+ }),
51427
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
51428
+ role: "menuitem",
51429
+ onClick: () => {
51430
+ setCommitMenu(false);
51431
+ action("commit", void 0, message).then(() => action("sync")).then(() => setMessage(""));
51432
+ },
51433
+ children: "提交和同步"
51434
+ })
51435
+ ]
51436
+ })
51437
+ ]
51233
51438
  })]
51234
51439
  }),
51235
51440
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -51376,14 +51581,12 @@ section.${c}>footer { z-index: 1; }
51376
51581
  const [primarySideVisible, setPrimarySideVisible] = (0, react.useState)(() => localStorage.getItem("dvw:primary-side-visible") !== "closed");
51377
51582
  const [statusVisible, setStatusVisible] = (0, react.useState)(() => localStorage.getItem("dvw:status-bar-visible") === "open");
51378
51583
  const [settingsOpen, setSettingsOpen] = (0, react.useState)(false);
51379
- const [chatWidth, setChatWidth] = (0, react.useState)(() => Math.max(400, Math.min(720, Math.round(Number(localStorage.getItem("dvw:dsh-chat-width")) || 420))));
51584
+ const [chatWidth, setChatWidth] = (0, react.useState)(() => clampChatWidth(Number(localStorage.getItem("dvw:dsh-chat-width")) || 440));
51380
51585
  const [chatVisible, setChatVisible] = (0, react.useState)(() => localStorage.getItem("dvw:dsh-chat-visible") !== "closed");
51381
51586
  const [outlineVisible, setOutlineVisible] = (0, react.useState)(() => localStorage.getItem("dvw:outline") !== "closed");
51382
51587
  const [tsIntellisense, setTsIntellisense] = (0, react.useState)(tsIntellisenseEnabled);
51383
51588
  const [tsIndex, setTsIndex] = (0, react.useState)({ state: "idle" });
51384
51589
  const [lspServers, setLspServers] = (0, react.useState)([]);
51385
- const [lspPrompt, setLspPrompt] = (0, react.useState)();
51386
- const dismissedLsp = (0, react.useRef)(/* @__PURE__ */ new Set());
51387
51590
  const [lspBusy, setLspBusy] = (0, react.useState)();
51388
51591
  const [lspError, setLspError] = (0, react.useState)("");
51389
51592
  const lspManager = (0, react.useRef)();
@@ -51394,6 +51597,7 @@ section.${c}>footer { z-index: 1; }
51394
51597
  const [tabMenu, setTabMenu] = (0, react.useState)();
51395
51598
  const tabsRef = (0, react.useRef)(tabs);
51396
51599
  tabsRef.current = tabs;
51600
+ const [settingsSection, setSettingsSection] = (0, react.useState)("appearance");
51397
51601
  const tabListRef = (0, react.useRef)(null);
51398
51602
  const workspaceRequests = (0, react.useRef)(new WorkspaceRequestScope());
51399
51603
  const loadedWorkspaceCwd = (0, react.useRef)();
@@ -51401,10 +51605,26 @@ section.${c}>footer { z-index: 1; }
51401
51605
  const dshDark = useDshDarkTheme();
51402
51606
  const [theme, setTheme] = (0, react.useState)(() => {
51403
51607
  const saved = localStorage.getItem("dvw:theme");
51404
- return saved === "dark" || saved === "light" ? saved : "dsh";
51608
+ return saved === "dark" || saved === "light" || saved === "white" || saved === "eyecare" ? saved : "dsh";
51609
+ });
51610
+ const [markdownView, setMarkdownView] = (0, react.useState)(() => markdownDefaultView());
51611
+ const [commitDetail, setCommitDetail] = (0, react.useState)(() => {
51612
+ const saved = localStorage.getItem("dvw:commit-detail");
51613
+ return saved === "concise" || saved === "detailed" ? saved : "standard";
51614
+ });
51615
+ const [commitLanguage, setCommitLanguage] = (0, react.useState)(() => {
51616
+ const saved = localStorage.getItem("dvw:commit-language");
51617
+ return saved === "zh" || saved === "en" ? saved : "auto";
51405
51618
  });
51406
51619
  const colorScheme = theme === "dsh" ? dshDark ? "dark" : "light" : theme;
51620
+ const commitPreferences = (0, react.useMemo)(() => ({
51621
+ detail: commitDetail,
51622
+ language: commitLanguage
51623
+ }), [commitDetail, commitLanguage]);
51407
51624
  (0, react.useEffect)(() => localStorage.setItem("dvw:theme", theme), [theme]);
51625
+ (0, react.useEffect)(() => localStorage.setItem(MARKDOWN_DEFAULT_VIEW_KEY, markdownView), [markdownView]);
51626
+ (0, react.useEffect)(() => localStorage.setItem("dvw:commit-detail", commitDetail), [commitDetail]);
51627
+ (0, react.useEffect)(() => localStorage.setItem("dvw:commit-language", commitLanguage), [commitLanguage]);
51408
51628
  (0, react.useEffect)(() => {
51409
51629
  if (!snapshot.visible || theme === "dsh") return;
51410
51630
  const body = document.body;
@@ -51412,7 +51632,7 @@ section.${c}>footer { z-index: 1; }
51412
51632
  const wasDark = body.hasAttribute("data-ds-dark-theme");
51413
51633
  const previousColorScheme = root.style.colorScheme;
51414
51634
  body.toggleAttribute("data-ds-dark-theme", theme === "dark");
51415
- root.style.colorScheme = theme;
51635
+ root.style.colorScheme = theme === "dark" ? "dark" : "light";
51416
51636
  return () => {
51417
51637
  body.toggleAttribute("data-ds-dark-theme", wasDark);
51418
51638
  if (previousColorScheme === "") root.style.removeProperty("color-scheme");
@@ -51482,7 +51702,7 @@ section.${c}>footer { z-index: 1; }
51482
51702
  line,
51483
51703
  column,
51484
51704
  highlight,
51485
- preview: line !== void 0 ? false : void 0
51705
+ ...line !== void 0 ? { preview: false } : {}
51486
51706
  }]);
51487
51707
  setActive(path);
51488
51708
  };
@@ -51707,51 +51927,6 @@ section.${c}>footer { z-index: 1; }
51707
51927
  const openRef = (0, react.useRef)(open);
51708
51928
  openRef.current = open;
51709
51929
  const openPath = (0, react.useCallback)((path, line, column, highlight) => openRef.current(path, line, column, highlight), []);
51710
- (0, react.useEffect)(() => {
51711
- if (active === void 0 || active.startsWith("diff:")) return;
51712
- const id = languageServerIdForPath(active);
51713
- if (id === void 0 || dismissedLsp.current.has(id)) return;
51714
- if (id === "typescript") {
51715
- if (!tsIntellisense) setLspPrompt({
51716
- id: "typescript",
51717
- name: "TypeScript / JavaScript",
51718
- builtin: true,
51719
- installable: true
51720
- });
51721
- return;
51722
- }
51723
- const server = lspServers.find((value) => value.id === id);
51724
- if (server === void 0 || server.installed) return;
51725
- setLspPrompt({
51726
- id: server.id,
51727
- name: server.name,
51728
- builtin: false,
51729
- installable: server.installable,
51730
- hint: server.hint
51731
- });
51732
- }, [
51733
- active,
51734
- lspServers,
51735
- tsIntellisense
51736
- ]);
51737
- const dismissLspPrompt = () => {
51738
- if (lspPrompt !== void 0) dismissedLsp.current.add(lspPrompt.id);
51739
- setLspPrompt(void 0);
51740
- };
51741
- const installLspPrompt = async () => {
51742
- const prompt = lspPrompt;
51743
- if (prompt === void 0) return;
51744
- setLspPrompt(void 0);
51745
- if (prompt.builtin) {
51746
- setTsIntellisense(true);
51747
- return;
51748
- }
51749
- if (!prompt.installable) {
51750
- setSettingsOpen(true);
51751
- return;
51752
- }
51753
- await changeLsp(prompt.id, "install");
51754
- };
51755
51930
  const [switcherOpen, setSwitcherOpen] = (0, react.useState)(false);
51756
51931
  const [switcherChoices, setSwitcherChoices] = (0, react.useState)([]);
51757
51932
  const [switcherBusy, setSwitcherBusy] = (0, react.useState)(false);
@@ -51845,6 +52020,13 @@ section.${c}>footer { z-index: 1; }
51845
52020
  workspace,
51846
52021
  refreshLsp
51847
52022
  ]);
52023
+ (0, react.useEffect)(() => {
52024
+ if (settingsOpen && settingsSection === "language") refreshLsp();
52025
+ }, [
52026
+ settingsOpen,
52027
+ settingsSection,
52028
+ refreshLsp
52029
+ ]);
51848
52030
  (0, react.useEffect)(() => () => {
51849
52031
  lspManager.current?.dispose();
51850
52032
  }, []);
@@ -51855,18 +52037,12 @@ section.${c}>footer { z-index: 1; }
51855
52037
  }, [tsIntellisense]);
51856
52038
  (0, react.useEffect)(() => {
51857
52039
  if (!snapshot.visible || sessionId === void 0 || workspace === void 0) return;
51858
- if (!tsIntellisense) {
51859
- if (window.monaco !== void 0) disposeTypeScriptProject(window.monaco);
51860
- setTsIndex({ state: "idle" });
51861
- return;
51862
- }
51863
52040
  let cancelled = false;
51864
- const cwd = workspace.cwd;
51865
- const disposables = [];
52041
+ let disposable;
51866
52042
  loadMonaco().then((monaco) => {
51867
52043
  if (cancelled) return;
51868
- setTsIndex({ state: "loading" });
51869
- disposables.push(monaco.editor.registerEditorOpener({ openCodeEditor: (_source, resource, selection) => {
52044
+ const cwd = workspace.cwd;
52045
+ disposable = monaco.editor.registerEditorOpener({ openCodeEditor: (_source, resource, selection) => {
51870
52046
  const path = workspacePathFromModel(cwd, resource.toString());
51871
52047
  if (path === void 0) return false;
51872
52048
  const position = selection === void 0 ? void 0 : "startLineNumber" in selection ? {
@@ -51878,7 +52054,31 @@ section.${c}>footer { z-index: 1; }
51878
52054
  };
51879
52055
  openPath(path, position?.line, position?.column);
51880
52056
  return true;
51881
- } }));
52057
+ } });
52058
+ });
52059
+ return () => {
52060
+ cancelled = true;
52061
+ disposable?.dispose();
52062
+ };
52063
+ }, [
52064
+ snapshot.visible,
52065
+ sessionId,
52066
+ workspace,
52067
+ openPath
52068
+ ]);
52069
+ (0, react.useEffect)(() => {
52070
+ if (!snapshot.visible || sessionId === void 0 || workspace === void 0) return;
52071
+ if (!tsIntellisense) {
52072
+ if (window.monaco !== void 0) disposeTypeScriptProject(window.monaco);
52073
+ setTsIndex({ state: "idle" });
52074
+ return;
52075
+ }
52076
+ let cancelled = false;
52077
+ const cwd = workspace.cwd;
52078
+ const disposables = [];
52079
+ loadMonaco().then((monaco) => {
52080
+ if (cancelled) return;
52081
+ setTsIndex({ state: "loading" });
51882
52082
  const changed = (event) => {
51883
52083
  const paths = event.detail;
51884
52084
  if (Array.isArray(paths)) refreshIndexedFiles(monaco, sessionId, cwd, paths);
@@ -51905,8 +52105,7 @@ section.${c}>footer { z-index: 1; }
51905
52105
  snapshot.visible,
51906
52106
  sessionId,
51907
52107
  workspace,
51908
- tsIntellisense,
51909
- openPath
52108
+ tsIntellisense
51910
52109
  ]);
51911
52110
  const openDiff = (0, react.useCallback)((path, diff, title, diffSourcePath) => {
51912
52111
  const key = `diff:${path}`;
@@ -52044,6 +52243,7 @@ section.${c}>footer { z-index: 1; }
52044
52243
  if (sessionId === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
52045
52244
  className: "dvw-overlay",
52046
52245
  "data-dvw-theme": colorScheme,
52246
+ "data-dvw-theme-name": theme,
52047
52247
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkbenchTitlebar, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
52048
52248
  className: "dvw-empty",
52049
52249
  style: { gridColumn: "1/4" },
@@ -52064,6 +52264,7 @@ section.${c}>footer { z-index: 1; }
52064
52264
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
52065
52265
  className: "dvw-overlay",
52066
52266
  "data-dvw-theme": colorScheme,
52267
+ "data-dvw-theme-name": theme,
52067
52268
  "data-dvw-chat": chatVisible || void 0,
52068
52269
  "data-dvw-primary-side": primarySideVisible || void 0,
52069
52270
  "data-dvw-status": statusVisible || void 0,
@@ -52096,9 +52297,9 @@ section.${c}>footer { z-index: 1; }
52096
52297
  className: "dvw-chat-resizer",
52097
52298
  label: "拖动调整 DSH 对话栏宽度",
52098
52299
  width: chatWidth,
52099
- min: 400,
52300
+ min: 440,
52100
52301
  max: 720,
52101
- defaultWidth: 420,
52302
+ defaultWidth: 440,
52102
52303
  direction: -1,
52103
52304
  hideBelow: 200,
52104
52305
  onHide: () => setChatVisible(false),
@@ -52116,40 +52317,13 @@ section.${c}>footer { z-index: 1; }
52116
52317
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "dvw-chat-body" })
52117
52318
  ]
52118
52319
  }),
52119
- lspPrompt !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
52120
- className: "dvw-confirm-backdrop",
52121
- role: "presentation",
52122
- onMouseDown: dismissLspPrompt,
52123
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
52124
- className: "dvw-confirm",
52125
- role: "alertdialog",
52126
- "aria-modal": "true",
52127
- "aria-label": "语言未安装",
52128
- onMouseDown: (event) => event.stopPropagation(),
52129
- children: [
52130
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", { children: "语言未安装" }),
52131
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", { children: [lspPrompt.name, " 的语言服务尚未安装。"] }),
52132
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
52133
- className: "dvw-confirm-note",
52134
- children: lspPrompt.installable ? "安装后才能使用转到定义、查找引用、Peek、智能补全和签名帮助。" : lspPrompt.hint ?? "该语言服务器需要手动安装。"
52135
- }),
52136
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
52137
- onClick: dismissLspPrompt,
52138
- children: "以后再说"
52139
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
52140
- className: "dvw-primary-button",
52141
- onClick: () => void installLspPrompt(),
52142
- children: lspPrompt.installable ? "安装" : "打开设置"
52143
- })] })
52144
- ]
52145
- })
52146
- }),
52147
52320
  switcherOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkspaceSwitcher, {
52148
52321
  choices: switcherChoices,
52149
52322
  activeSessionId: sessionId,
52150
52323
  unavailable: navigation?.available === false,
52151
52324
  busy: switcherBusy,
52152
52325
  error: switcherError,
52326
+ theme: colorScheme,
52153
52327
  onCreate: () => void createWorkspace(),
52154
52328
  onSwitch: switchSession,
52155
52329
  onOpenWorkspace: enterWorkspace,
@@ -52172,7 +52346,38 @@ section.${c}>footer { z-index: 1; }
52172
52346
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "close" })
52173
52347
  })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
52174
52348
  className: "dvw-settings-body",
52349
+ "data-section": settingsSection,
52175
52350
  children: [
52351
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("nav", {
52352
+ className: "dvw-settings-nav",
52353
+ "aria-label": "设置分类",
52354
+ children: [
52355
+ [
52356
+ "appearance",
52357
+ "外观",
52358
+ "color-mode"
52359
+ ],
52360
+ [
52361
+ "layout",
52362
+ "布局",
52363
+ "layout-sidebar-right"
52364
+ ],
52365
+ [
52366
+ "commit",
52367
+ "提交信息",
52368
+ "sparkle"
52369
+ ],
52370
+ [
52371
+ "language",
52372
+ "语言智能",
52373
+ "code"
52374
+ ]
52375
+ ].map(([value, label, icon]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
52376
+ "data-active": settingsSection === value,
52377
+ onClick: () => setSettingsSection(value),
52378
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: icon }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label })]
52379
+ }, value))
52380
+ }),
52176
52381
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", { children: [
52177
52382
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: "外观" }),
52178
52383
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", { children: "颜色主题" }),
@@ -52181,7 +52386,9 @@ section.${c}>footer { z-index: 1; }
52181
52386
  children: [
52182
52387
  ["dsh", "跟随 DSH"],
52183
52388
  ["dark", "深色"],
52184
- ["light", "浅色"]
52389
+ ["light", "浅色"],
52390
+ ["white", "纯白"],
52391
+ ["eyecare", "护眼"]
52185
52392
  ].map(([value, label]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
52186
52393
  "data-active": theme === value,
52187
52394
  onClick: () => setTheme(value),
@@ -52244,14 +52451,62 @@ section.${c}>footer { z-index: 1; }
52244
52451
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "DSH 对话栏宽度" }),
52245
52452
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
52246
52453
  type: "range",
52247
- min: "400",
52248
- max: "720",
52454
+ min: 440,
52455
+ max: 720,
52249
52456
  step: "1",
52250
52457
  value: Math.round(chatWidth),
52251
- onChange: (event) => setChatWidth(Math.max(400, Math.round(Number(event.target.value))))
52458
+ onChange: (event) => setChatWidth(clampChatWidth(Number(event.target.value)))
52252
52459
  }),
52253
52460
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("output", { children: [chatWidth, "px"] })
52254
52461
  ]
52462
+ }),
52463
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
52464
+ className: "dvw-setting-choice",
52465
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "Markdown 默认视图" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
52466
+ className: "dvw-setting-segment",
52467
+ children: [["preview", "预览"], ["source", "源码"]].map(([value, label]) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
52468
+ "data-active": markdownView === value,
52469
+ onClick: () => setMarkdownView(value),
52470
+ children: label
52471
+ }, value))
52472
+ })]
52473
+ })
52474
+ ] }),
52475
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", { children: [
52476
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: "提交信息" }),
52477
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
52478
+ className: "dvw-setting-choice",
52479
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "详细程度" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
52480
+ className: "dvw-setting-segment",
52481
+ children: [
52482
+ ["concise", "简洁"],
52483
+ ["standard", "标准"],
52484
+ ["detailed", "详细"]
52485
+ ].map(([value, label]) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
52486
+ "data-active": commitDetail === value,
52487
+ onClick: () => setCommitDetail(value),
52488
+ children: label
52489
+ }, value))
52490
+ })]
52491
+ }),
52492
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
52493
+ className: "dvw-setting-choice",
52494
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "语言" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
52495
+ className: "dvw-setting-segment",
52496
+ children: [
52497
+ ["auto", "跟随最近提交"],
52498
+ ["zh", "中文"],
52499
+ ["en", "English"]
52500
+ ].map(([value, label]) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
52501
+ "data-active": commitLanguage === value,
52502
+ onClick: () => setCommitLanguage(value),
52503
+ children: label
52504
+ }, value))
52505
+ })]
52506
+ }),
52507
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
52508
+ className: "dvw-setting-hint",
52509
+ children: "详细模式会生成标题和 2–4 条说明;简洁模式限制标题长度,标准模式保持单行约定式提交。"
52255
52510
  })
52256
52511
  ] }),
52257
52512
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", { children: [
@@ -52266,19 +52521,39 @@ section.${c}>footer { z-index: 1; }
52266
52521
  }),
52267
52522
  lspServers.map((server) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
52268
52523
  className: "dvw-setting-extension",
52269
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: server.name }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [server.installed ? "已安装" : server.installable ? "点击安装" : "需要手动安装", !server.installed && server.hint ? ` · ${server.hint}` : ""] })] }), server.installable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
52524
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: server.name }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
52525
+ className: "dvw-lsp-status",
52526
+ children: [
52527
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
52528
+ className: "dvw-lsp-chip",
52529
+ "data-installed": server.language === void 0 || server.language.installed,
52530
+ "data-action": server.language !== void 0 && !server.language.installed,
52531
+ children: server.language === void 0 ? "语言:无需安装" : server.language.installed ? "语言:已安装" : "安装语言"
52532
+ }),
52533
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
52534
+ className: "dvw-lsp-chip",
52535
+ "data-installed": server.installed,
52536
+ children: server.installed ? "LSP:已安装" : "LSP:未安装"
52537
+ }),
52538
+ !server.installed && server.hint !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
52539
+ className: "dvw-lsp-hint",
52540
+ children: server.hint
52541
+ })
52542
+ ]
52543
+ })] }), server.language !== void 0 && !server.language.installed ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
52544
+ disabled: true,
52545
+ title: "先安装语言工具链,再安装 LSP",
52546
+ children: "等待"
52547
+ }) : server.installable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
52270
52548
  disabled: lspBusy === server.id,
52271
52549
  className: server.installed ? void 0 : "dvw-primary-button",
52272
52550
  onClick: () => void changeLsp(server.id, server.installed ? "uninstall" : "install"),
52273
- children: lspBusy === server.id ? "处理中…" : server.installed ? "卸载" : "安装"
52274
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
52275
- onClick: () => void refreshLsp(),
52276
- children: "重新检测"
52551
+ children: lspBusy === server.id ? "处理中…" : server.installed ? "卸载 LSP" : "安装 LSP"
52277
52552
  })]
52278
52553
  }, server.id)),
52279
52554
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
52280
52555
  className: "dvw-setting-hint",
52281
- children: "每种语言使用该生态里最活跃的语言服务器,安装只写入本插件的私有目录。安装后在编辑器中 F12 转到定义、Shift+F12 查找引用、Alt+F12 速览、Ctrl+Space 补全,并显示诊断。"
52556
+ children: "每种语言使用该生态里最活跃的语言服务器;能自动安装的会装进本插件的私有目录,需要手动安装的会分别检查语言工具链和服务器本身。"
52282
52557
  }),
52283
52558
  lspError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
52284
52559
  className: "dvw-setting-hint",
@@ -52323,7 +52598,7 @@ section.${c}>footer { z-index: 1; }
52323
52598
  {
52324
52599
  id: "chat",
52325
52600
  label: chatVisible ? "关闭 DSH 对话栏 (Ctrl+Alt+B)" : "显示 DSH 对话栏 (Ctrl+Alt+B)",
52326
- icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DshMark, { size: 18 }),
52601
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DshMark, { size: 22 }),
52327
52602
  active: chatVisible,
52328
52603
  onActivate: () => setChatVisible((value) => !value)
52329
52604
  }
@@ -52372,6 +52647,7 @@ section.${c}>footer { z-index: 1; }
52372
52647
  " ",
52373
52648
  snapshot.view === "git" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GitView, {
52374
52649
  sessionId,
52650
+ preferences: commitPreferences,
52375
52651
  onDiff: openDiff
52376
52652
  })
52377
52653
  ]
@@ -52745,6 +53021,8 @@ section.${c}>footer { z-index: 1; }
52745
53021
  }
52746
53022
  //#endregion
52747
53023
  //#region src/client/styles.ts
53024
+ /** The bundled DSH whale as a CSS mask, so the empty state stays in sync with the logo component. */
53025
+ const DSH_MARK_MASK = `url("data:image/svg+xml,${encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="${DSH_MARK_VIEWBOX}"><path d="${DSH_MARK_PATH}" fill="#000"/></svg>`)}")`;
52748
53026
  const CSS$1 = String.raw`
52749
53027
  @font-face{font-family:codicon;font-display:block;src:url('/dsh-vscode/codicons/codicon.ttf') format('truetype')}
52750
53028
  :root{--dvw-titlebar-height:0px}html[data-platform=darwin]{--dvw-titlebar-height:var(--dsh-frame-top-clearance,48px)}html[data-windows-titlebar]{--dvw-titlebar-height:var(--dsh-frame-top-clearance,40px)}
@@ -52754,6 +53032,7 @@ section.${c}>footer { z-index: 1; }
52754
53032
  .dvw-overlay{--dvw-side-width:210px;--dvw-graph-ref:#3794ff;--dvw-base:var(--dsw-alias-bg-base,#181818);--dvw-surface-1:var(--dsw-alias-bg-layer-1,#1e1e1e);--dvw-surface-2:var(--dsw-alias-bg-layer-2,#252526);--dvw-surface-3:var(--dsw-alias-bg-layer-3,#2d2d30);--dvw-side:var(--dvw-surface-1);--dvw-tab-active:var(--dvw-surface-2);--dvw-gutter:var(--dvw-base);--dvw-text:var(--dsw-alias-label-primary,#ccc);--dvw-text-2:var(--dsw-alias-label-secondary,#aaa);--dvw-text-3:var(--dsw-alias-label-tertiary,#858585);--dvw-border:var(--dsw-alias-border-l2,#333);--dvw-border-soft:var(--dsw-alias-border-l3,#292929);--dvw-hover:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.08));--dvw-active:var(--dsw-alias-interactive-bg-active,rgba(255,255,255,.14));--dvw-accent:var(--dsw-alias-state-business-primary,#3b82f6);--dvw-error:var(--dsw-alias-state-error-primary,#f48771);--dvw-success:var(--dsw-alias-state-success-primary,#73c991);--dvw-warn:var(--dsw-alias-state-warn-primary,#d7ba7d);position:absolute;inset:0;z-index:100;display:grid;grid-template-columns:48px var(--dvw-side-width) minmax(0,1fr);grid-template-rows:minmax(0,1fr) auto 30px;box-sizing:border-box;padding-top:calc(var(--dvw-titlebar-height) + 6px);background:var(--dvw-gutter);color:var(--dvw-text);pointer-events:auto;font:13px/1.4 var(--dsw-font-family,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif);overflow:hidden;color-scheme:light}
52755
53033
  .dvw-titlebar{display:none}html[data-platform=darwin] .dvw-titlebar{position:absolute;top:0;right:0;left:0;z-index:6;display:flex;align-items:center;gap:8px;height:var(--dvw-titlebar-height);padding:0 12px 0 84px;border-bottom:1px solid var(--dvw-border-soft);background:var(--dvw-base);color:var(--dvw-text-3);font-size:12px;-webkit-app-region:drag;user-select:none}.dvw-titlebar strong{flex:none;font-weight:600;color:var(--dvw-text-2)}.dvw-titlebar span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
52756
53034
  html[data-windows-titlebar] .dvw-overlay{top:var(--dvw-titlebar-height);padding-top:6px}
53035
+ html[data-platform=darwin] .dvw-overlay{padding-top:var(--dvw-titlebar-height)}
52757
53036
  body[data-ds-dark-theme] .dvw-overlay,.dvw-overlay[data-dvw-theme=dark]{color-scheme:dark}
52758
53037
  .dvw-overlay[data-dvw-theme=dark]{--dvw-base:#191a1b;--dvw-surface-1:#121314;--dvw-surface-2:#202122;--dvw-surface-3:#252526;--dvw-side:#191a1b;--dvw-tab-active:#2a2b2c;--dvw-gutter:#191a1b;--dvw-graph-ref:#3794ff;--dvw-text:#bfbfbf;--dvw-text-2:#8c8c8c;--dvw-text-3:#6e6e6e;--dvw-border:#2a2b2c;--dvw-border-soft:#242526;--dvw-hover:#ffffff12;--dvw-active:#ffffff1f;--dvw-accent:#307e9f;--dvw-error:#e06c75;--dvw-success:#98c379;--dvw-warn:#e5c07b}
52759
53038
  .dvw-overlay[data-dvw-theme=light]{--dvw-base:#f9fafb;--dvw-surface-1:#fff;--dvw-surface-2:#fff;--dvw-surface-3:#fff;--dvw-side:#f9fafb;--dvw-tab-active:#e8e8e8;--dvw-gutter:#f9fafb;--dvw-graph-ref:#0063d3;--dvw-text:#1f1f1f;--dvw-text-2:#616161;--dvw-text-3:#8a8a8a;--dvw-border:#e5e5e5;--dvw-border-soft:#ececec;--dvw-hover:#0000000d;--dvw-active:#00000014;--dvw-accent:#0078d4;--dvw-error:#e51400;--dvw-success:#388a34;--dvw-warn:#bf8803;color-scheme:light}
@@ -52761,7 +53040,7 @@ body[data-ds-dark-theme] .dvw-overlay,.dvw-overlay[data-dvw-theme=dark]{color-sc
52761
53040
  .dvw-main{grid-column:3;grid-row:1;position:relative;display:flex;min-width:0;min-height:0;flex-direction:column;background:var(--dvw-surface-1);border-left:1px solid var(--dvw-border);border-top:1px solid var(--dvw-border);border-right:1px solid var(--dvw-border);border-bottom:1px solid var(--dvw-border);border-radius:8px;margin-left:4px;overflow:hidden}.dvw-tabs{height:35px;background:linear-gradient(to top,var(--dvw-border) 0 1px,var(--dvw-base) 1px 100%);display:flex;overflow:hidden}.dvw-tabs[data-empty]{display:none}.dvw-tab{position:relative;height:35px;margin:0;min-width:110px;max-width:260px;border:0;border-right:1px solid var(--dvw-border-soft);border-radius:8px 8px 0 0;background:transparent;color:var(--dvw-text-2);padding:0 8px 0 12px;display:flex;align-items:center;gap:6px;cursor:pointer;flex:none;white-space:nowrap}.dvw-tab:hover{background:var(--dvw-hover)}.dvw-tab[data-active=true]{background:var(--dvw-surface-1);color:var(--dvw-text);border-top:1px solid var(--dvw-border);border-right:1px solid var(--dvw-border)}.dvw-tab-icon{width:16px;height:16px;flex:none;object-fit:contain}.dvw-tab-close{width:16px;height:16px;flex:none;display:grid;place-items:center;border-radius:3px;opacity:0}.dvw-tab-close:hover{background:var(--dvw-hover);color:var(--dvw-text)}.dvw-tab[data-active=true] .dvw-tab-close,.dvw-tab:hover .dvw-tab-close{opacity:1}.dvw-tab-name{overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0;text-align:left;white-space:nowrap}.dvw-editor{position:relative;flex:1;min-height:0}.dvw-editor-toolbar{position:absolute;z-index:3;top:0;right:0;left:0;height:35px;display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:0 10px;border-bottom:1px solid var(--dvw-border-soft);background:var(--dvw-surface-1)}.dvw-editor-body{position:absolute;inset:0;min-height:0}.dvw-editor-body[data-toolbar=true]{top:35px}.dvw-mode-button{height:27px;padding:0 10px;display:flex;align-items:center;gap:6px;border:1px solid transparent;border-radius:5px;background:transparent;color:var(--dvw-text-2);cursor:pointer}.dvw-mode-button:hover{background:var(--dvw-hover)}.dvw-mode-button[data-active=true]{border-color:var(--dvw-border);background:var(--dvw-active);color:var(--dvw-text)}.dvw-empty{height:100%;display:grid;place-items:center;color:var(--dvw-text-3);text-align:center}.dvw-empty strong{font-size:24px;color:var(--dvw-text-2)}.dvw-message{padding:12px;color:var(--dvw-warn)}.dvw-message button{margin-left:10px;padding:2px 10px;border:1px solid var(--dvw-border);border-radius:4px;background:var(--dvw-surface-2);color:var(--dvw-text);font:inherit;cursor:pointer}.dvw-message button:hover{background:var(--dvw-hover)}
52762
53041
  .dvw-bottom-resizer{height:4px;cursor:ns-resize}.dvw-bottom-resizer:hover{background:var(--dvw-accent)}.dvw-bottom-reveal{position:absolute;left:0;right:0;bottom:0;height:6px;z-index:4;cursor:ns-resize}.dvw-bottom-reveal::after{content:"";position:absolute;left:0;right:0;bottom:0;height:2px;background:transparent}.dvw-bottom-reveal:hover::after{background:var(--dvw-accent)}.dvw-bottom{grid-column:3;grid-row:2;height:260px;min-height:120px;border-top:1px solid var(--dvw-border);border-left:1px solid var(--dvw-border);border-right:1px solid var(--dvw-border);border-bottom:1px solid var(--dvw-border);border-radius:8px;margin-top:4px;margin-left:4px;background:var(--dvw-base);display:flex;flex-direction:column}.dvw-bottom-head{height:35px;display:flex;align-items:center;gap:14px;padding:0 12px}.dvw-bottom-title{border:0;border-bottom:1px solid var(--dvw-text);background:transparent;color:var(--dvw-text);height:35px}.dvw-bottom-body{flex:1;min-height:0}.dvw-status{grid-column:1/4;grid-row:3;background:var(--dvw-base);color:var(--dvw-text);display:flex;align-items:center;padding:6px 8px 0;gap:18px;font-size:12px}.dvw-theme-control{position:relative;margin-left:auto}.dvw-theme-trigger{height:22px;min-width:112px;display:flex;align-items:center;gap:7px;padding:0 8px;border:0;border-radius:5px;background:color-mix(in srgb,#000 17%,transparent);color:#fff;cursor:pointer}.dvw-theme-trigger:hover{background:color-mix(in srgb,#000 27%,transparent)}.dvw-theme-orb{width:13px;height:13px;border:2px solid #fff;border-radius:50%;background:linear-gradient(90deg,#191a1b 50%,#fff 50%)}.dvw-theme-orb.dark{background:#191a1b}.dvw-theme-orb.light{background:#fff}.dvw-theme-menu{position:absolute;right:0;bottom:29px;width:224px;padding:6px;border:1px solid var(--dvw-border);border-radius:10px;background:var(--dvw-surface-3);box-shadow:0 10px 35px rgba(0,0,0,.28);color:var(--dvw-text)}.dvw-theme-menu button{width:100%;min-height:48px;border:0;border-radius:7px;background:transparent;color:inherit;display:grid;grid-template-columns:30px 1fr 20px;align-items:center;text-align:left;padding:6px;cursor:pointer}.dvw-theme-menu button:hover,.dvw-theme-menu button[aria-checked=true]{background:var(--dvw-hover)}.dvw-theme-menu strong,.dvw-theme-menu small{display:block}.dvw-theme-menu small{color:var(--dvw-text-3);margin-top:2px}.dvw-theme-swatch{width:22px;height:22px;border-radius:6px;border:1px solid var(--dvw-border);background:linear-gradient(135deg,#191a1b 0 50%,#fff 50%)}.dvw-theme-swatch.dark{background:#191a1b}.dvw-theme-swatch.light{background:#fff}
52763
53042
  .dvw-search-form{padding:8px;display:grid;gap:6px}.dvw-input,.dvw-textarea,.dvw-select{width:100%;border:1px solid var(--dvw-border);border-radius:2px;background:var(--dvw-surface-2);color:var(--dvw-text);padding:3px 7px;outline:none}.dvw-input:focus,.dvw-textarea:focus,.dvw-select:focus{border-color:var(--dvw-accent)}.dvw-options{display:flex;align-items:center;gap:8px;font-size:11px}.dvw-result-file{height:22px;display:flex;align-items:center;gap:4px;padding:0 8px;font-weight:600}.dvw-result{height:22px;align-items:center;padding:0 8px 0 20px;cursor:pointer;display:flex;gap:8px}.dvw-result:hover{background:var(--dvw-hover)}.dvw-line{color:var(--dvw-text-3);min-width:30px;text-align:right}.dvw-preview{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dvw-search-hit{background:color-mix(in srgb,var(--dvw-accent) 28%,transparent);border-radius:2px}
52764
- .dvw-git-head{padding:7px 10px;border-bottom:1px solid var(--dvw-border);display:flex;align-items:center;gap:8px;position:relative}.dvw-branch{min-width:0;border:0;background:transparent;color:var(--dvw-text);font:inherit;font-weight:600;display:flex;align-items:center;gap:5px;cursor:pointer}.dvw-branch-caret{margin-left:2px;font-size:14px;color:var(--dvw-text-3)}.dvw-branch-menu{position:absolute;z-index:12;top:calc(100% + 2px);left:6px;right:6px;padding:4px;border:1px solid var(--dvw-border);border-radius:8px;background:var(--dvw-surface-2);box-shadow:0 10px 28px rgba(0,0,0,.28);color:var(--dvw-text)}.dvw-branch-current{padding:4px 8px;color:var(--dvw-text-3);font-size:11px}.dvw-branch-list{max-height:min(300px,45vh);overflow:auto}.dvw-branch-list button{width:100%;height:26px;display:flex;align-items:center;gap:6px;border:0;border-radius:4px;background:transparent;color:var(--dvw-text);padding:0 8px;text-align:left;font:inherit;cursor:pointer}.dvw-branch-list button:hover{background:var(--dvw-hover)}.dvw-branch-list button[data-active=true]{background:var(--dvw-active)}.dvw-branch-list button span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dvw-branch-worktree{margin-left:auto;flex:none;padding:1px 5px;border-radius:8px;background:var(--dvw-surface-3);color:var(--dvw-text-3);font-size:10px;line-height:14px}.dvw-branch-create{display:flex;gap:4px;align-items:center;margin-top:4px;padding-top:6px;border-top:1px solid var(--dvw-border-soft)}.dvw-branch-create .dvw-input{flex:1;min-width:0}.dvw-branch-create-button{flex:none;width:24px;min-width:24px;height:24px;border:1px solid var(--dvw-border);border-radius:4px}.dvw-commit{display:grid;grid-template-columns:1fr auto;gap:6px;padding:9px}.dvw-commit .dvw-input{grid-column:1/3}.dvw-commit-button{grid-column:1/3;height:31px;border:0;border-radius:6px;background:color-mix(in srgb,var(--dvw-accent) 24%,var(--dvw-surface-2));color:var(--dvw-text);display:flex;align-items:center;justify-content:center;gap:7px;cursor:pointer}.dvw-commit-button:hover{background:color-mix(in srgb,var(--dvw-accent) 34%,var(--dvw-surface-2))}.dvw-commit-button:disabled{opacity:.45;cursor:default}.dvw-group-head{height:30px;display:flex;align-items:center;gap:5px;padding:0 6px 0 9px;font-weight:600;position:sticky;top:0;background:var(--dvw-side);z-index:1}.dvw-group-head:hover{background:var(--dvw-hover)}.dvw-group-head .dvw-count{margin-left:auto;min-width:20px;height:20px;border-radius:10px;display:grid;place-items:center;background:var(--dvw-surface-3);color:var(--dvw-text-2);font-size:11px}.dvw-change{display:flex;align-items:center;height:22px;padding:0 5px 0 19px;gap:5px;cursor:pointer}.dvw-change:hover{background:var(--dvw-hover)}.dvw-change .dvw-icon{opacity:0}.dvw-change:hover .dvw-icon,.dvw-change:focus-within .dvw-icon{opacity:1}.dvw-change-path{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.dvw-badge{font-size:11px;color:var(--dvw-warn)}.dvw-graph{border-top:1px solid var(--dvw-border-soft);margin-top:8px;padding-top:3px}.dvw-graph-list{padding-bottom:8px}.dvw-graph-row{width:100%;height:38px;border:0;background:transparent;color:var(--dvw-text);display:flex;align-items:center;padding:0 7px;text-align:left;cursor:pointer;overflow:hidden}.dvw-graph-row:hover{background:var(--dvw-hover)}.dvw-graph-svg{flex:none;align-self:stretch}.dvw-graph-line{fill:none;stroke-width:1px;stroke-linecap:round;vector-effect:non-scaling-stroke}.dvw-graph-node{stroke:var(--dvw-side);stroke-width:2px;fill:var(--dvw-side)}.dvw-graph-copy{display:flex;min-width:0;flex:1;flex-direction:column;justify-content:center}.dvw-graph-subject{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dvw-graph-meta{font-size:11px;color:var(--dvw-text-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dvw-ref{max-width:82px;margin-left:4px;padding:1px 5px;border:1px solid color-mix(in srgb,var(--dvw-accent) 50%,transparent);border-radius:9px;color:var(--dvw-accent);font-size:10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dvw-error{padding:8px;color:var(--dvw-error);white-space:pre-wrap}.dvw-diff{margin:0;height:100%;overflow:auto;padding:8px 0;background:var(--dvw-surface-1);font:12px/1.5 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;white-space:pre}.dvw-diff-line{display:block;min-height:18px;padding:0 14px}.dvw-diff-line.add{background:color-mix(in srgb,var(--dvw-success) 15%,transparent);color:var(--dvw-success)}.dvw-diff-line.remove{background:color-mix(in srgb,var(--dvw-error) 13%,transparent);color:var(--dvw-error)}.dvw-diff-line.hunk{background:color-mix(in srgb,var(--dvw-accent) 12%,transparent);color:var(--dvw-accent)}.dvw-diff-line.meta{color:var(--dvw-text-3)}.dvw-diff-empty{padding:24px;color:var(--dvw-text-3)}
53043
+ .dvw-git-head{padding:7px 10px;border-bottom:1px solid var(--dvw-border);display:flex;align-items:center;gap:8px;position:relative}.dvw-branch{min-width:0;border:0;background:transparent;color:var(--dvw-text);font:inherit;font-weight:600;display:flex;align-items:center;gap:5px;cursor:pointer}.dvw-branch-caret{margin-left:2px;font-size:14px;color:var(--dvw-text-3)}.dvw-branch-menu{position:absolute;z-index:12;top:calc(100% + 2px);left:6px;right:6px;padding:4px;border:1px solid var(--dvw-border);border-radius:8px;background:var(--dvw-surface-2);box-shadow:0 10px 28px rgba(0,0,0,.28);color:var(--dvw-text)}.dvw-branch-current{padding:4px 8px;color:var(--dvw-text-3);font-size:11px}.dvw-branch-list{max-height:min(300px,45vh);overflow:auto}.dvw-branch-list button{width:100%;height:26px;display:flex;align-items:center;gap:6px;border:0;border-radius:4px;background:transparent;color:var(--dvw-text);padding:0 8px;text-align:left;font:inherit;cursor:pointer}.dvw-branch-list button:hover{background:var(--dvw-hover)}.dvw-branch-list button[data-active=true]{background:var(--dvw-active)}.dvw-branch-list button span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dvw-branch-worktree{margin-left:auto;flex:none;padding:1px 5px;border-radius:8px;background:var(--dvw-surface-3);color:var(--dvw-text-3);font-size:10px;line-height:14px}.dvw-branch-create{display:flex;gap:4px;align-items:center;margin-top:4px;padding-top:6px;border-top:1px solid var(--dvw-border-soft)}.dvw-branch-create .dvw-input{flex:1;min-width:0}.dvw-branch-create-button{flex:none;width:24px;min-width:24px;height:24px;border:1px solid var(--dvw-border);border-radius:4px}.dvw-commit{display:flex;flex-direction:column;gap:6px;padding:9px}.dvw-commit-actions{display:grid;grid-template-columns:1fr auto;gap:6px}.dvw-commit-button{height:31px;border:0;border-radius:6px;background:color-mix(in srgb,var(--dvw-accent) 24%,var(--dvw-surface-2));color:var(--dvw-text);display:flex;align-items:center;justify-content:center;gap:7px;cursor:pointer}.dvw-commit-button:hover{background:color-mix(in srgb,var(--dvw-accent) 34%,var(--dvw-surface-2))}.dvw-commit-button:disabled{opacity:.45;cursor:default}.dvw-commit-ai{height:31px;border:1px solid var(--dvw-border);border-radius:6px;background:var(--dvw-surface-2);color:var(--dvw-text-2);display:flex;align-items:center;justify-content:center;gap:6px;font:inherit;cursor:pointer}.dvw-commit-ai:hover:not(:disabled){background:var(--dvw-hover);color:var(--dvw-text)}.dvw-commit-ai:disabled{opacity:.45;cursor:default}.dvw-group-head{height:30px;display:flex;align-items:center;gap:5px;padding:0 6px 0 9px;font-weight:600;position:sticky;top:0;background:var(--dvw-side);z-index:1}.dvw-group-head:hover{background:var(--dvw-hover)}.dvw-group-head .dvw-count{margin-left:auto;min-width:20px;height:20px;border-radius:10px;display:grid;place-items:center;background:var(--dvw-surface-3);color:var(--dvw-text-2);font-size:11px}.dvw-change{display:flex;align-items:center;height:22px;padding:0 5px 0 19px;gap:5px;cursor:pointer}.dvw-change:hover{background:var(--dvw-hover)}.dvw-change .dvw-icon{opacity:0}.dvw-change:hover .dvw-icon,.dvw-change:focus-within .dvw-icon{opacity:1}.dvw-change-path{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.dvw-badge{font-size:11px;color:var(--dvw-warn)}.dvw-graph{border-top:1px solid var(--dvw-border-soft);margin-top:8px;padding-top:3px}.dvw-graph-list{padding-bottom:8px}.dvw-graph-row{width:100%;height:38px;border:0;background:transparent;color:var(--dvw-text);display:flex;align-items:center;padding:0 7px;text-align:left;cursor:pointer;overflow:hidden}.dvw-graph-row:hover{background:var(--dvw-hover)}.dvw-graph-svg{flex:none;align-self:stretch}.dvw-graph-line{fill:none;stroke-width:1px;stroke-linecap:round;vector-effect:non-scaling-stroke}.dvw-graph-node{stroke:var(--dvw-side);stroke-width:2px;fill:var(--dvw-side)}.dvw-graph-copy{display:flex;min-width:0;flex:1;flex-direction:column;justify-content:center}.dvw-graph-subject{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dvw-graph-meta{font-size:11px;color:var(--dvw-text-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dvw-ref{max-width:82px;margin-left:4px;padding:1px 5px;border:1px solid color-mix(in srgb,var(--dvw-accent) 50%,transparent);border-radius:9px;color:var(--dvw-accent);font-size:10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dvw-error{padding:8px;color:var(--dvw-error);white-space:pre-wrap}.dvw-diff{margin:0;height:100%;overflow:auto;padding:8px 0;background:var(--dvw-surface-1);font:12px/1.5 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;white-space:pre}.dvw-diff-line{display:block;min-height:18px;padding:0 14px}.dvw-diff-line.add{background:color-mix(in srgb,var(--dvw-success) 15%,transparent);color:var(--dvw-success)}.dvw-diff-line.remove{background:color-mix(in srgb,var(--dvw-error) 13%,transparent);color:var(--dvw-error)}.dvw-diff-line.hunk{background:color-mix(in srgb,var(--dvw-accent) 12%,transparent);color:var(--dvw-accent)}.dvw-diff-line.meta{color:var(--dvw-text-3)}.dvw-diff-empty{padding:24px;color:var(--dvw-text-3)}
52765
53044
  .dvw-tab-list{display:flex;min-width:0;flex:1;overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;scrollbar-width:none}.dvw-tab-list::-webkit-scrollbar{display:none}.dvw-monaco-diff{position:absolute;inset:0}.dvw-diff-toolbar{justify-content:flex-end}.dvw-group-head{gap:2px;padding-left:2px}.dvw-group-toggle{min-width:0;height:30px;flex:1;border:0;border-radius:5px;background:transparent;color:var(--dvw-text);font:inherit;font-weight:600;display:flex;align-items:center;gap:5px;padding:0 7px;cursor:pointer;text-align:left}.dvw-group-toggle:hover{background:var(--dvw-hover)}.dvw-graph-entry[data-expanded=true]{background:color-mix(in srgb,var(--dvw-accent) 5%,transparent)}.dvw-commit-files{padding:1px 0 5px 26px}.dvw-commit-file{width:100%;height:22px;border:0;background:transparent;color:var(--dvw-text);display:flex;align-items:center;gap:6px;padding:0 7px;text-align:left;cursor:pointer}.dvw-commit-file:hover{background:var(--dvw-hover)}.dvw-commit-file-name{white-space:nowrap}.dvw-commit-file-dir{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dvw-text-3);font-size:11px}
52766
53045
  .dvw-outline{flex:none;max-height:38%;display:flex;flex-direction:column;border-bottom:1px solid var(--dvw-border)}.dvw-outline-head{height:30px;display:flex;align-items:center;justify-content:space-between;padding:0 5px 0 10px;font-weight:600}.dvw-outline-head>span{display:flex;align-items:center;gap:6px}.dvw-outline-list{overflow:auto;padding-bottom:5px}.dvw-outline-item{display:block;width:100%;height:22px;border:0;background:transparent;color:var(--dvw-text-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left;cursor:pointer}.dvw-outline-item:hover{background:var(--dvw-hover);color:var(--dvw-text)}.dvw-image-preview{position:absolute;inset:0;overflow:auto;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;padding:24px;background:repeating-conic-gradient(var(--dvw-surface-2) 0 25%,var(--dvw-surface-1) 0 50%) 0/20px 20px}.dvw-image-preview img{max-width:100%;max-height:calc(100% - 32px);object-fit:contain;box-shadow:0 4px 24px rgba(0,0,0,.22)}.dvw-image-preview span{max-width:100%;padding:3px 8px;border-radius:5px;background:var(--dvw-surface-1);color:var(--dvw-text-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
52767
53046
  .dvw-pdf-preview{position:absolute;inset:0;display:flex;min-height:0;flex-direction:column;background:var(--dvw-base);color:var(--dvw-text)}.dvw-pdf-toolbar{height:30px;flex:none;display:flex;align-items:center;justify-content:center;gap:2px;padding:0 8px;border-bottom:1px solid var(--dvw-border);background:var(--dvw-surface-1);font-variant-numeric:tabular-nums}.dvw-pdf-toolbar .dvw-icon{font-size:18px}.dvw-pdf-zoom{min-width:52px;height:24px;border:0;border-radius:4px;background:var(--dvw-active);color:var(--dvw-text);font:inherit;cursor:pointer}.dvw-pdf-zoom:hover{background:var(--dvw-hover)}.dvw-pdf-separator{width:1px;height:18px;margin:0 4px;background:var(--dvw-border)}.dvw-pdf-page{min-height:0;flex:1;overflow:auto;display:flex;justify-content:center;padding:8px;background:var(--dvw-base)}.dvw-pdf-page canvas{flex:none;background:#fff;box-shadow:0 2px 12px rgba(0,0,0,.28)}.dvw-sheet-preview{position:absolute;inset:0;display:flex;min-height:0;flex-direction:column;background:var(--dvw-base);color:var(--dvw-text)}.dvw-sheet-tabs{flex:none;display:flex;gap:2px;padding:6px 8px;overflow:auto;border-bottom:1px solid var(--dvw-border)}.dvw-sheet-tabs button{height:24px;padding:0 10px;border:0;border-radius:3px;background:transparent;color:var(--dvw-text-2);font:inherit;cursor:pointer;white-space:nowrap}.dvw-sheet-tabs button:hover{background:var(--dvw-hover)}.dvw-sheet-tabs button[data-active=true]{background:var(--dvw-active);color:var(--dvw-text)}.dvw-sheet-scroll{flex:1;min-height:0;overflow:auto;padding:10px}.dvw-sheet-table{border-collapse:collapse;font-size:12px}.dvw-sheet-table td{max-width:360px;padding:2px 8px;border:1px solid var(--dvw-border);white-space:pre;overflow:hidden;text-overflow:ellipsis}.dvw-sheet-table tr:first-child td{background:var(--dvw-hover);font-weight:600}.dvw-slides-preview{position:absolute;inset:0;overflow:auto;padding:16px;background:var(--dvw-base)}.dvw-docx-preview{position:absolute;inset:0;overflow:auto;padding:28px;background:var(--dvw-base);color:#222}.dvw-docx-preview .docx-wrapper{margin:auto;background:#fff;box-shadow:0 2px 12px rgba(0,0,0,.2)}.dvw-document-error,.dvw-document-download{height:100%;display:grid;place-content:center;justify-items:center;gap:12px;padding:24px;color:var(--dvw-text-2);text-align:center}.dvw-document-download a{color:var(--dvw-accent);text-decoration:none}.dvw-document-download a:hover{text-decoration:underline}
@@ -52789,6 +53068,7 @@ body[data-ds-dark-theme] .dvw-overlay,.dvw-overlay[data-dvw-theme=dark]{color-sc
52789
53068
  .dvw-side-resizer::after,.dvw-chat-resizer::after{background:transparent;left:3px;width:4px}
52790
53069
  .dvw-side-resizer:hover::after,.dvw-side-resizer:focus-visible::after,.dvw-side-resizer[data-dragging=true]::after,.dvw-chat-resizer:hover::after,.dvw-chat-resizer:focus-visible::after,.dvw-chat-resizer[data-dragging=true]::after{background:var(--dvw-accent)}
52791
53070
  [data-dvw-conversation-panel]{position:fixed!important;top:calc(var(--dvw-titlebar-height) + 6px)!important;right:4px!important;bottom:var(--dvw-status-height,30px)!important;left:auto!important;width:calc(var(--dvw-chat-width) - 8px)!important;height:auto!important;min-width:0!important;z-index:21!important;border:1px solid var(--dsw-alias-border-l2)!important;border-radius:8px!important;overflow:hidden!important;box-shadow:none!important}
53071
+ html[data-platform=darwin] [data-dvw-conversation-panel]{top:var(--dvw-titlebar-height)!important}
52792
53072
  body[data-dvw-palette=light] [data-dvw-conversation-panel]{--dsw-alias-bg-base:#f9fafb;--dsw-specific-sidebar-fill:#f9fafb;--dsw-alias-border-l2:#e5e5e5;background:#f9fafb!important}body[data-dvw-palette=dark] [data-dvw-conversation-panel]{--dsw-alias-bg-base:#191a1b;--dsw-specific-sidebar-fill:#191a1b;--dsw-alias-bg-layer-1:#202122;--dsw-alias-bg-layer-2:#252526;--dsw-alias-bg-layer-3:#2a2b2c;--dsw-alias-label-primary:#bfbfbf;--dsw-alias-label-secondary:#8c8c8c;--dsw-alias-label-tertiary:#6e6e6e;--dsw-alias-border-l2:#2a2b2c;--dsw-alias-border-l3:#303132;--dsw-alias-interactive-bg-hover:#ffffff12;--dsw-alias-interactive-bg-active:#ffffff1f}
52793
53073
  body[data-dvw-workbench-active] [data-sidebar-right-expand],body[data-dvw-conversation-active] [data-sidebar-right-expand]{display:none!important}
52794
53074
  body[data-dvw-workbench-active] [data-shell-leading]{display:none!important}
@@ -52808,10 +53088,126 @@ body[data-dvw-workbench-active] [data-sidebar-toggle]{display:none!important}
52808
53088
  .dvw-settings-body{overflow:auto;padding:8px 20px 20px}.dvw-settings-body section+section{margin-top:20px;padding-top:12px;border-top:1px solid var(--dvw-border-soft)}.dvw-settings-body h3{margin:8px 0 12px;font-size:13px}.dvw-settings-body>section>label:not(.dvw-setting-check):not(.dvw-setting-range){display:block;margin-bottom:7px;color:var(--dvw-text-2);font-size:12px}
52809
53089
  .dvw-settings-themes{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.dvw-settings-themes button{height:56px;display:grid;grid-template-columns:28px 1fr 18px;align-items:center;gap:7px;padding:0 9px;border:1px solid var(--dvw-border);border-radius:7px;background:var(--dvw-base);color:var(--dvw-text);text-align:left;cursor:pointer}.dvw-settings-themes button:hover{background:var(--dvw-hover)}.dvw-settings-themes button[data-active=true]{border-color:var(--dvw-accent);background:color-mix(in srgb,var(--dvw-accent) 10%,var(--dvw-base))}
52810
53090
  .dvw-setting-check{height:36px;display:flex;align-items:center;gap:9px;border-bottom:1px solid var(--dvw-border-soft);cursor:pointer}.dvw-setting-check input{accent-color:var(--dvw-accent)}.dvw-setting-range{display:grid;grid-template-columns:145px 1fr 52px;align-items:center;gap:10px;min-height:42px}.dvw-setting-range input{accent-color:var(--dvw-accent)}.dvw-setting-range output{text-align:right;color:var(--dvw-text-3);font-variant-numeric:tabular-nums}
52811
- @media(max-width:900px){.dvw-overlay[data-dvw-chat=true]{grid-template-columns:44px min(210px,var(--dvw-side-width)) minmax(0,1fr) min(400px,var(--dvw-chat-width))}[data-dvw-conversation-panel]{width:min(400px,var(--dvw-chat-width))!important}}
53091
+ .dvw-setting-choice{display:grid;grid-template-columns:145px 1fr;align-items:center;gap:10px;min-height:42px}.dvw-setting-choice>span{color:var(--dvw-text-2);font-size:12px}.dvw-setting-segment{display:inline-flex;justify-self:start;padding:2px;border:1px solid var(--dvw-border);border-radius:6px;background:var(--dvw-base)}.dvw-setting-segment button{min-width:64px;height:26px;border:0;border-radius:4px;background:transparent;color:var(--dvw-text-2);font:inherit;font-size:12px;cursor:pointer}.dvw-setting-segment button:hover{background:var(--dvw-hover);color:var(--dvw-text)}.dvw-setting-segment button[data-active=true]{background:var(--dvw-active);color:var(--dvw-text)}
53092
+ @media(max-width:900px){.dvw-overlay[data-dvw-chat=true]{--dvw-chat-effective:max(440px,min(var(--dvw-chat-width),calc(100vw - 254px)));grid-template-columns:44px min(210px,var(--dvw-side-width),max(0px,calc(100vw - 164px - var(--dvw-chat-effective)))) minmax(0,1fr) var(--dvw-chat-effective)}.dvw-overlay[data-dvw-chat=true] .dvw-status{padding-right:calc(var(--dvw-chat-effective) + 8px)}.dvw-chat-resizer{right:calc(var(--dvw-chat-effective) - 5px)}[data-dvw-conversation-panel]{width:calc(max(440px,min(var(--dvw-chat-width),calc(100vw - 254px))) - 8px)!important}}
52812
53093
  .dvw-setting-textarea{width:100%;min-height:84px;resize:vertical;padding:8px 10px;border:1px solid var(--dvw-border);border-radius:6px;background:var(--dvw-base);color:var(--dvw-text);font:12px/1.5 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
52813
53094
  .dvw-setting-textarea:focus{outline:none;border-color:var(--dvw-accent)}
52814
53095
  .dvw-setting-extension{display:flex;align-items:center;gap:12px;padding:10px 12px;border:1px solid var(--dvw-border);border-radius:7px;background:var(--dvw-base)}.dvw-setting-extension>div{min-width:0;flex:1;display:flex;flex-direction:column;gap:2px}.dvw-setting-extension span{color:var(--dvw-text-3);font-size:12px}.dvw-setting-extension button{height:26px;padding:0 14px;border:1px solid var(--dvw-border);border-radius:4px;background:transparent;color:var(--dvw-text);font:inherit;cursor:pointer}.dvw-setting-extension button:hover{background:var(--dvw-hover)}.dvw-setting-extension button.dvw-primary-button{border-color:var(--dvw-accent);background:var(--dvw-accent);color:#fff}.dvw-setting-hint{margin:8px 0 0;color:var(--dvw-text-3);font-size:11px;line-height:1.5}
53096
+ /* Slightly larger explorer rows for comfortable reading without shrinking the file list. */
53097
+ .dvw-tree-row{height:24px;font-size:13px}
53098
+ /* Keep a single focus surface: hovering another row clears the selected row's fill. */
53099
+ .dvw-tree:has(.dvw-tree-row:hover) .dvw-tree-row[data-selected=true]:not(:hover){background:transparent}
53100
+ .dvw-chevron{width:18px}
53101
+ .dvw-file-icon{width:18px;height:18px}
53102
+ .dvw-tree-rename,.dvw-tree-create-input{height:22px}
53103
+ /* Branded empty state: a soft accent tile with the DSH whale. */
53104
+ .dvw-empty>div{position:relative}
53105
+ .dvw-empty>div::before{content:"";display:block;width:96px;height:96px;margin:0 auto 20px;border-radius:24px;background:color-mix(in srgb,var(--dvw-accent) 12%,var(--dvw-surface-1))}
53106
+ .dvw-empty>div::after{content:"";position:absolute;top:26px;left:50%;width:60px;height:44px;transform:translateX(-50%);background:var(--dvw-accent);-webkit-mask:${DSH_MARK_MASK} center/contain no-repeat;mask:${DSH_MARK_MASK} center/contain no-repeat}
53107
+ /* Activity bar glyphs sized like VS Code's 24px icons in a 48px slot. */
53108
+ .dvw-act::before{width:40px;height:40px;border-radius:8px}
53109
+ /* Host styles set the codicon base size later in the cascade, so the rail needs the extra weight. */
53110
+ .dvw-act .codicon,.dvw-activity-ghost .codicon{font-size:20px!important}
53111
+ /* Inline SVGs otherwise sit on the text baseline and drift against the font glyphs. */
53112
+ .dvw-act svg,.dvw-activity-ghost svg{display:block}
53113
+ /* VS Code-like tab shape: rounded shoulders on the active tab blending into the editor, no separators between tabs. */
53114
+ .dvw-tab{border-radius:10px 10px 0 0;border-right:0}
53115
+ .dvw-tabs{background:color-mix(in srgb,var(--dvw-text) 4%,var(--dvw-base))}
53116
+ .dvw-tab[data-active=true]{border-top:0;border-right-color:transparent}
53117
+ .dvw-tab[data-active=true]::before,.dvw-tab[data-active=true]::after{content:"";position:absolute;bottom:0;width:10px;height:10px;background:var(--dvw-surface-1);pointer-events:none}
53118
+ .dvw-tab[data-active=true]::before{left:-10px;-webkit-mask:radial-gradient(circle 10px at 0 0,transparent 9px,#000 9.6px);mask:radial-gradient(circle 10px at 0 0,transparent 9px,#000 9.6px)}
53119
+ .dvw-tab[data-active=true]::after{right:-10px;-webkit-mask:radial-gradient(circle 10px at 100% 0,transparent 9px,#000 9.6px);mask:radial-gradient(circle 10px at 100% 0,transparent 9px,#000 9.6px)}
53120
+ .dvw-commit-box{position:relative;display:flex;align-items:stretch}
53121
+ .dvw-commit-input{width:100%;min-height:30px;max-height:96px;field-sizing:content;resize:none;padding:5px 32px 5px 8px;line-height:18px}
53122
+ .dvw-commit-ai{position:absolute;right:4px;top:50%;transform:translateY(-50%);width:24px;min-width:24px;height:24px;border:0;background:transparent;color:var(--dvw-text-3)}
53123
+ .dvw-commit-ai:hover:not(:disabled){background:var(--dvw-hover);color:var(--dvw-text)}
53124
+ /* VS Code-style split commit button: primary action plus a narrow dropdown for commit variants. */
53125
+ .dvw-commit .dvw-commit-actions{display:flex;gap:0;position:relative}
53126
+ .dvw-commit .dvw-commit-button{flex:1;min-width:0;height:30px;border:0;border-radius:6px 0 0 6px;background:var(--dvw-accent);color:#fff;display:flex;align-items:center;justify-content:center;gap:7px;font:inherit;cursor:pointer}
53127
+ .dvw-commit .dvw-commit-button:hover:not(:disabled){background:color-mix(in srgb,var(--dvw-accent) 88%,#fff)}
53128
+ .dvw-commit .dvw-commit-button:disabled{opacity:.45;cursor:default}
53129
+ .dvw-commit .dvw-commit-more{flex:none;width:30px;height:30px;border:0;border-left:1px solid rgba(255,255,255,.3);border-radius:0 6px 6px 0;background:var(--dvw-accent);color:#fff;display:grid;place-items:center;cursor:pointer}
53130
+ .dvw-commit .dvw-commit-more:hover:not(:disabled){background:color-mix(in srgb,var(--dvw-accent) 88%,#fff)}
53131
+ .dvw-commit .dvw-commit-more:disabled{opacity:.45;cursor:default}
53132
+ .dvw-commit .dvw-commit-menu{position:absolute;z-index:12;top:calc(100% + 4px);right:0;min-width:180px;padding:4px;border:1px solid var(--dvw-border);border-radius:8px;background:var(--dvw-surface-2);box-shadow:0 10px 28px rgba(0,0,0,.28)}
53133
+ .dvw-commit .dvw-commit-menu button{width:100%;height:26px;border:0;border-radius:4px;background:transparent;color:var(--dvw-text);padding:0 8px;text-align:left;font:inherit;cursor:pointer}
53134
+ .dvw-commit .dvw-commit-menu button:hover{background:var(--dvw-hover)}
53135
+ /* Pure-white theme: every chrome surface uses the editor's white background. */
53136
+ .dvw-overlay[data-dvw-theme=white]{--dvw-base:#fff;--dvw-surface-1:#fff;--dvw-surface-2:#fff;--dvw-surface-3:#fff;--dvw-side:#fff;--dvw-tab-active:#fff;--dvw-gutter:#fff;--dvw-graph-ref:#0063d3;--dvw-text:#171717;--dvw-text-2:#5c5c5c;--dvw-text-3:#8c8c8c;--dvw-border:#e2e2e2;--dvw-border-soft:#efefef;--dvw-hover:#0000000c;--dvw-active:#00000014;--dvw-accent:#0066cc;--dvw-error:#d13438;--dvw-success:#2e7d32;--dvw-warn:#8a6100;color-scheme:light}
53137
+ .dvw-overlay[data-dvw-theme=white] .dvw-tabs{background:#fff}
53138
+ .dvw-overlay[data-dvw-theme=white] .dvw-act[data-active=true]::before{background:#00000010}
53139
+ /* Eye-care theme: a warm paper-yellow surface shared by every panel and the editor. */
53140
+ .dvw-overlay[data-dvw-theme=eyecare]{--dvw-base:#f7ebc8;--dvw-surface-1:#f7ebc8;--dvw-surface-2:#f7ebc8;--dvw-surface-3:#f7ebc8;--dvw-side:#f7ebc8;--dvw-tab-active:#ecdcae;--dvw-gutter:#f7ebc8;--dvw-graph-ref:#9c6b1e;--dvw-text:#3b3324;--dvw-text-2:#6b604a;--dvw-text-3:#92856a;--dvw-border:#e0cf9f;--dvw-border-soft:#eadcb6;--dvw-hover:#0000000c;--dvw-active:#00000014;--dvw-accent:#9c6b1e;--dvw-error:#b03a2e;--dvw-success:#4c7a34;--dvw-warn:#8a5a00;color-scheme:light}
53141
+ .dvw-overlay[data-dvw-theme=eyecare] .dvw-tabs{background:#f7ebc8}
53142
+ .dvw-overlay[data-dvw-theme=eyecare] .dvw-act[data-active=true]::before{background:#00000016}
53143
+ .dvw-theme-swatch.white{background:#fff}
53144
+ .dvw-theme-swatch.eyecare{background:#f7ebc8}
53145
+ .dvw-settings-themes{grid-template-columns:repeat(auto-fit,minmax(108px,1fr))}
53146
+ body[data-dvw-palette=white] [data-dvw-conversation-panel]{--dsw-alias-bg-base:#fff;--dsw-specific-sidebar-fill:#fff;--dsw-alias-bg-layer-1:#fff;--dsw-alias-bg-layer-2:#fff;--dsw-alias-bg-layer-3:#fff;--dsw-alias-border-l2:#e2e2e2;--dsw-alias-border-l3:#efefef;background:#fff!important}
53147
+ body[data-dvw-palette=eyecare] [data-dvw-conversation-panel]{--dsw-alias-bg-base:#f7ebc8;--dsw-specific-sidebar-fill:#f7ebc8;--dsw-alias-bg-layer-1:#f7ebc8;--dsw-alias-bg-layer-2:#f1e2b8;--dsw-alias-bg-layer-3:#ecdcae;--dsw-alias-bg-layer-4:#ecdcae;--dsw-specific-input-major:#f7ebc8;--dsw-specific-login-input:#f1e2b8;--dsw-menu-surface-fill:#f7ebc8;--dsw-alias-label-primary:#3b3324;--dsw-alias-label-secondary:#6b604a;--dsw-alias-label-tertiary:#92856a;--dsw-alias-border-l2:#e0cf9f;--dsw-alias-border-l3:#eadcb6;--dsw-alias-interactive-bg-hover:#0000000c;--dsw-alias-interactive-bg-active:#00000014;background:#f7ebc8!important}
53148
+ /* Settings dialog: left navigation rail with aligned label/control rows, mirroring DSH settings. */
53149
+ .dvw-settings{width:min(880px,calc(100vw - 40px));height:min(680px,calc(100vh - 40px));max-height:none;border-radius:18px}
53150
+ .dvw-settings>header{height:52px;padding:0 14px 0 20px;font-size:15px}
53151
+ .dvw-settings-body{flex:1;min-height:0;display:grid;grid-template-columns:190px minmax(0,1fr);gap:0;padding:0;overflow:hidden}
53152
+ .dvw-settings-nav{grid-column:1;display:flex;flex-direction:column;gap:4px;padding:12px 10px;border-right:1px solid var(--dvw-border-soft);background:var(--dvw-surface-1);overflow:auto}
53153
+ .dvw-settings-nav button{height:36px;border:0;border-radius:11px;background:transparent;color:var(--dvw-text-2);display:flex;align-items:center;gap:10px;padding:0 12px;font:inherit;text-align:left;cursor:pointer}
53154
+ .dvw-settings-nav button .codicon{font-size:16px}
53155
+ .dvw-settings-nav button:hover{background:var(--dvw-hover);color:var(--dvw-text)}
53156
+ .dvw-settings-nav button[data-active=true]{background:var(--dvw-active);color:var(--dvw-text);font-weight:600}
53157
+ .dvw-settings-body>section{grid-column:2;min-height:0;overflow:auto;padding:20px 26px 30px;border-left:0}
53158
+ .dvw-settings-body>section+section{margin-top:0;padding-top:20px;border-top:0}
53159
+ .dvw-settings-body[data-section=appearance]>section:not(:nth-of-type(1)){display:none}
53160
+ .dvw-settings-body[data-section=layout]>section:not(:nth-of-type(2)){display:none}
53161
+ .dvw-settings-body[data-section=commit]>section:not(:nth-of-type(3)){display:none}
53162
+ .dvw-settings-body[data-section=language]>section:not(:nth-of-type(4)){display:none}
53163
+ .dvw-settings-body h3{margin:0 0 4px;font-size:16px;font-weight:600}
53164
+ .dvw-settings-body>section>label:not(.dvw-setting-check):not(.dvw-setting-range){display:block;margin:14px 0 9px;color:var(--dvw-text-2);font-size:12px}
53165
+ .dvw-setting-range{display:grid;grid-template-columns:minmax(0,1fr) minmax(140px,240px) 48px;align-items:center;gap:16px;min-height:52px;border-bottom:1px solid var(--dvw-border-soft)}
53166
+ .dvw-setting-range>span{color:var(--dvw-text);font-size:13px;font-weight:500}
53167
+ .dvw-setting-range output{text-align:right;color:var(--dvw-text-3);font-variant-numeric:tabular-nums}
53168
+ .dvw-setting-choice{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:16px;min-height:52px;border-bottom:1px solid var(--dvw-border-soft)}
53169
+ .dvw-setting-choice>span{color:var(--dvw-text);font-size:13px;font-weight:500}
53170
+ .dvw-setting-check{height:auto;min-height:52px;display:flex;flex-direction:row-reverse;align-items:center;justify-content:space-between;gap:16px;border-bottom:1px solid var(--dvw-border-soft);cursor:pointer;font-size:13px;font-weight:500}
53171
+ .dvw-setting-check input{appearance:none;flex:none;width:38px;height:22px;margin:0;border-radius:11px;background:color-mix(in srgb,var(--dvw-text) 22%,transparent);position:relative;cursor:pointer;transition:background .15s}
53172
+ .dvw-setting-check input::after{content:"";position:absolute;top:3px;left:3px;width:16px;height:16px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.25);transition:transform .15s}
53173
+ .dvw-setting-check input:checked{background:var(--dvw-accent)}
53174
+ .dvw-setting-check input:checked::after{transform:translateX(16px)}
53175
+ .dvw-settings-themes{grid-template-columns:repeat(5,minmax(0,1fr));gap:8px;margin:12px 0 10px}
53176
+ .dvw-settings-themes button{position:relative;height:86px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:9px;padding:10px;text-align:center;border-radius:14px;background:var(--dvw-base)}
53177
+ .dvw-settings-themes button[data-active=true]{border-color:var(--dvw-accent);box-shadow:inset 0 0 0 1px var(--dvw-accent);background:color-mix(in srgb,var(--dvw-accent) 8%,var(--dvw-base))}
53178
+ .dvw-settings-themes .dvw-theme-swatch{width:26px;height:26px;border-radius:8px;flex:none}
53179
+ .dvw-settings-themes button>.codicon{position:absolute;top:8px;right:8px;font-size:13px;color:var(--dvw-accent)}
53180
+ .dvw-settings-body .dvw-setting-extension{border:0;border-bottom:1px solid var(--dvw-border-soft);border-radius:0;background:transparent;padding:14px 0}
53181
+ .dvw-settings-body .dvw-setting-extension strong{font-size:13px}
53182
+ .dvw-settings-body .dvw-setting-extension button{height:28px;border-radius:9px;padding:0 16px;background:var(--dvw-surface-3)}
53183
+ .dvw-settings-body .dvw-setting-extension button.dvw-primary-button{border-color:var(--dvw-accent);background:var(--dvw-accent);color:#fff}
53184
+ .dvw-setting-extension .dvw-lsp-status{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;margin-top:2px}
53185
+ .dvw-setting-extension .dvw-lsp-chip{padding:1px 8px;border:1px solid var(--dvw-border);border-radius:999px;font-size:11px;line-height:18px;color:var(--dvw-text-3)}
53186
+ .dvw-setting-extension .dvw-lsp-chip[data-installed=true]{border-color:color-mix(in srgb,var(--dvw-success) 42%,transparent);color:var(--dvw-success)}
53187
+ .dvw-setting-extension .dvw-lsp-chip[data-action=true]{border-color:color-mix(in srgb,var(--dvw-accent) 45%,transparent);color:var(--dvw-accent)}
53188
+ .dvw-setting-extension .dvw-lsp-hint{flex-basis:100%;font-size:11px;line-height:1.45;color:var(--dvw-text-3)}
53189
+ .dvw-setting-extension button:disabled{opacity:.55;cursor:default}
53190
+ .dvw-settings .dvw-setting-segment{border-radius:10px;padding:3px}
53191
+ .dvw-settings .dvw-setting-segment button{border-radius:7px}
53192
+ .dvw-settings .dvw-icon{border-radius:9px}
53193
+ /* Monaco owns diff scrolling; an outer scroller changes the width as scrollbars appear and makes split mode oscillate. */
53194
+ .dvw-editor{min-width:0;overflow:hidden}
53195
+ .dvw-editor-body{min-width:0;overflow:hidden}
53196
+ .dvw-monaco-diff{height:auto;min-width:0;min-height:0;margin:0;padding:0;overflow:hidden;white-space:normal}
53197
+ /* Keep the workspace switcher in the same elevated surface family as workbench settings. */
53198
+ .dvw-workspace-layer{position:fixed!important;inset:0!important;z-index:1000!important;display:block!important;padding:0!important;background:transparent!important;overflow:hidden!important}
53199
+ .dvw-workspace-backdrop{position:absolute;inset:0;z-index:50;display:grid;place-items:center;padding:24px;background:rgba(0,0,0,.34);backdrop-filter:blur(3px)}
53200
+ .dvw-workspace-switcher{width:min(640px,calc(100vw - 48px));height:min(680px,calc(100vh - 48px));max-height:none;border-radius:18px;overflow:hidden;box-shadow:0 16px 50px rgba(0,0,0,.32)}
53201
+ .dvw-workspace-switcher>header{height:52px;padding:0 12px 0 20px;font-size:15px}
53202
+ .dvw-workspace-list{padding:10px}
53203
+ .dvw-workspace-row{border-radius:11px}
53204
+ .dvw-workspace-toggle{height:40px;padding:0 12px}
53205
+ .dvw-workspace-sessions{gap:3px;padding:4px 0 8px 32px}
53206
+ .dvw-workspace-session{height:34px;padding:0 12px;border-radius:11px}
53207
+ .dvw-workspace-switcher>footer{padding:12px 16px}
53208
+ .dvw-workspace-switcher>footer button{height:32px;border-radius:9px;padding:0 16px}
53209
+ .dvw-workspace-switcher .dvw-icon{border-radius:9px}
53210
+ @media(max-width:760px){.dvw-settings-body{grid-template-columns:1fr;grid-template-rows:auto minmax(0,1fr)}.dvw-settings-nav{grid-column:1;grid-row:1;flex-direction:row;border-right:0;border-bottom:1px solid var(--dvw-border-soft);padding:8px}.dvw-settings-nav button{flex:none}.dvw-settings-body>section{grid-column:1;grid-row:2;padding:16px 18px 24px}}
52815
53211
  `;
52816
53212
  function installStyles() {
52817
53213
  const id = "dsh-vscode-workbench/styles";