dsh-vscode-workbench 0.1.11 → 0.1.14

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
@@ -7471,6 +7471,54 @@ window.__ModuleLoader__.load({
7471
7471
  return "file";
7472
7472
  }
7473
7473
  //#endregion
7474
+ //#region src/client/websocket.ts
7475
+ const WEB_PAGE_PROTOCOLS = /* @__PURE__ */ new Set([
7476
+ "http:",
7477
+ "https:",
7478
+ "blob:",
7479
+ "data:",
7480
+ "about:",
7481
+ "filesystem:"
7482
+ ]);
7483
+ /** Parse a shell-published base only when it is a credential-free HTTP(S) origin. */
7484
+ function networkBase(value) {
7485
+ if (typeof value !== "string" || value === "") return void 0;
7486
+ let url;
7487
+ try {
7488
+ url = new URL(value);
7489
+ } catch {
7490
+ return;
7491
+ }
7492
+ if (url.protocol !== "http:" && url.protocol !== "https:") return void 0;
7493
+ if (url.username !== "" || url.password !== "" || url.host === "") return void 0;
7494
+ return {
7495
+ protocol: url.protocol,
7496
+ host: url.host
7497
+ };
7498
+ }
7499
+ /** Read the Host origin published by the DSH Desktop shell before application boot. */
7500
+ function transportStreamBaseUrl(globals = globalThis) {
7501
+ const transport = globals.__DSH_TRANSPORT__;
7502
+ return typeof transport?.streamBaseUrl === "string" ? transport.streamBaseUrl : void 0;
7503
+ }
7504
+ /**
7505
+ * Resolve an absolute workbench route to a WebSocket URL.
7506
+ *
7507
+ * Network pages keep their own origin. Application-delivered pages such as
7508
+ * `dsh-app://app/` have no WebSocket transport of their own, so they must use
7509
+ * the local Host origin published by the desktop shell.
7510
+ */
7511
+ function websocketUrl(path, location = globalThis.location, streamBaseUrl = transportStreamBaseUrl()) {
7512
+ const route = path.startsWith("/") ? path : `/${path}`;
7513
+ if (WEB_PAGE_PROTOCOLS.has(location.protocol)) {
7514
+ if (location.host === "") return void 0;
7515
+ return `${location.protocol === "https:" ? "wss" : "ws"}://${location.host}${route}`;
7516
+ }
7517
+ const base = networkBase(streamBaseUrl);
7518
+ if (base === void 0) return void 0;
7519
+ return `${base.protocol === "https:" ? "wss" : "ws"}://${base.host}${route}`;
7520
+ }
7521
+ //#endregion
7474
7522
  //#region src/client/terminal.ts
7475
7523
  async function request(method, body) {
7476
7524
  const response = await fetch(`/dsh-vscode-terminal/api/${method}`, {
@@ -7491,14 +7539,23 @@ window.__ModuleLoader__.load({
7491
7539
  var SocketConnection = class {
7492
7540
  socket;
7493
7541
  listeners = /* @__PURE__ */ new Set();
7542
+ errorListeners = /* @__PURE__ */ new Set();
7543
+ closed = false;
7494
7544
  queue = [];
7495
7545
  constructor(sessionId, id) {
7496
- const protocol = location.protocol === "https:" ? "wss" : "ws";
7497
- this.socket = new WebSocket(`${protocol}://${location.host}/dsh-vscode-terminal/ws?sessionId=${encodeURIComponent(sessionId)}&id=${encodeURIComponent(id)}`);
7546
+ const url = websocketUrl(`/dsh-vscode-terminal/ws?sessionId=${encodeURIComponent(sessionId)}&id=${encodeURIComponent(id)}`);
7547
+ if (url === void 0) throw new Error("无法连接终端:桌面端没有发布本地 Host 地址");
7548
+ this.socket = new WebSocket(url);
7498
7549
  this.socket.onopen = () => {
7499
7550
  for (const value of this.queue) this.socket.send(value);
7500
7551
  this.queue = [];
7501
7552
  };
7553
+ this.socket.onerror = () => {
7554
+ for (const listener of this.errorListeners) listener("终端 WebSocket 连接失败");
7555
+ };
7556
+ this.socket.onclose = () => {
7557
+ if (!this.closed) for (const listener of this.errorListeners) listener("终端 WebSocket 连接已断开");
7558
+ };
7502
7559
  this.socket.onmessage = (event) => {
7503
7560
  try {
7504
7561
  const value = JSON.parse(String(event.data));
@@ -7530,12 +7587,17 @@ window.__ModuleLoader__.load({
7530
7587
  });
7531
7588
  }
7532
7589
  close() {
7590
+ this.closed = true;
7533
7591
  this.socket.close();
7534
7592
  }
7535
7593
  subscribe(listener) {
7536
7594
  this.listeners.add(listener);
7537
7595
  return () => this.listeners.delete(listener);
7538
7596
  }
7597
+ subscribeError(listener) {
7598
+ this.errorListeners.add(listener);
7599
+ return () => this.errorListeners.delete(listener);
7600
+ }
7539
7601
  };
7540
7602
  /** Identify automatic terminal-emulator replies that must not be echoed during replay. */
7541
7603
  function isTerminalProtocolReply(data) {
@@ -7572,12 +7634,21 @@ window.__ModuleLoader__.load({
7572
7634
  }
7573
7635
  }
7574
7636
  async create(title) {
7575
- const terminal = await request("create", {
7576
- sessionId: this.sessionId,
7577
- ...title === void 0 ? {} : { title }
7578
- });
7579
- await this.refresh();
7580
- return terminal;
7637
+ try {
7638
+ const terminal = await request("create", {
7639
+ sessionId: this.sessionId,
7640
+ ...title === void 0 ? {} : { title }
7641
+ });
7642
+ await this.refresh();
7643
+ return terminal;
7644
+ } catch (error) {
7645
+ this.set({
7646
+ ...this.snapshot,
7647
+ loading: false,
7648
+ error: error instanceof Error ? error.message : String(error)
7649
+ });
7650
+ throw error;
7651
+ }
7581
7652
  }
7582
7653
  async close(id) {
7583
7654
  await request("close", {
@@ -7643,7 +7714,14 @@ window.__ModuleLoader__.load({
7643
7714
  const fit = new import_addon_fit.FitAddon();
7644
7715
  terminal.loadAddon(fit);
7645
7716
  terminal.open(root.current);
7646
- const connection = workspace.connect(id);
7717
+ let connection;
7718
+ try {
7719
+ connection = workspace.connect(id);
7720
+ } catch (exception) {
7721
+ setError(exception instanceof Error ? exception.message : String(exception));
7722
+ terminal.dispose();
7723
+ return;
7724
+ }
7647
7725
  const output = connection.subscribe((value) => {
7648
7726
  if (value.replay) {
7649
7727
  replaying.current = true;
@@ -7655,6 +7733,7 @@ window.__ModuleLoader__.load({
7655
7733
  }, 250);
7656
7734
  });
7657
7735
  });
7736
+ const connectionError = connection.subscribeError(setError);
7658
7737
  const input = terminal.onData((data) => {
7659
7738
  if (!replaying.current || !isTerminalProtocolReply(data)) connection.write(data);
7660
7739
  });
@@ -7675,6 +7754,7 @@ window.__ModuleLoader__.load({
7675
7754
  terminalRef.current = void 0;
7676
7755
  clearTimeout(replayGuard.current);
7677
7756
  observer.disconnect();
7757
+ connectionError();
7678
7758
  input.dispose();
7679
7759
  resize.dispose();
7680
7760
  output();
@@ -7712,8 +7792,8 @@ window.__ModuleLoader__.load({
7712
7792
  workspace.refresh().then(() => {
7713
7793
  if (!cancelled && workspace.getSnapshot().terminals.length === 0) workspace.create().then((value) => {
7714
7794
  if (!cancelled) setActive(value.id);
7715
- });
7716
- });
7795
+ }).catch(() => void 0);
7796
+ }).catch(() => void 0);
7717
7797
  return () => {
7718
7798
  cancelled = true;
7719
7799
  };
@@ -7723,7 +7803,7 @@ window.__ModuleLoader__.load({
7723
7803
  }, [snapshot.terminals, active]);
7724
7804
  (0, react.useEffect)(() => {
7725
7805
  const create = () => {
7726
- workspace.create().then((value) => setActive(value.id));
7806
+ workspace.create().then((value) => setActive(value.id)).catch(() => void 0);
7727
7807
  };
7728
7808
  window.addEventListener("dvw-terminal-new", create);
7729
7809
  return () => window.removeEventListener("dvw-terminal-new", create);
@@ -7756,7 +7836,7 @@ window.__ModuleLoader__.load({
7756
7836
  workspace.create().then((value) => {
7757
7837
  setSplit((current) => [...current?.includes(first) ? current : [first], value.id]);
7758
7838
  setActive(value.id);
7759
- });
7839
+ }).catch(() => void 0);
7760
7840
  };
7761
7841
  const shown = (split ?? (active === void 0 ? [] : [active])).filter((id) => snapshot.terminals.some((value) => value.id === id));
7762
7842
  const selectTerminal = (id) => {
@@ -12086,6 +12166,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
12086
12166
  attached?.style.setProperty("--dvw-status-height", `${statusHeight}px`);
12087
12167
  };
12088
12168
  attach();
12169
+ document.body.setAttribute("data-dvw-conversation-active", "");
12089
12170
  const observer = new MutationObserver(attach);
12090
12171
  observer.observe(document.body, {
12091
12172
  childList: true,
@@ -12093,6 +12174,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
12093
12174
  });
12094
12175
  return () => {
12095
12176
  observer.disconnect();
12177
+ document.body.removeAttribute("data-dvw-conversation-active");
12096
12178
  attached?.removeAttribute("data-dvw-conversation-panel");
12097
12179
  attached?.style.removeProperty("--dvw-chat-width");
12098
12180
  attached?.style.removeProperty("--dvw-status-height");
@@ -46216,6 +46298,11 @@ section.${c}>footer { z-index: 1; }
46216
46298
  function resizedPanelWidth(startWidth, startX, nextX, direction, min, max) {
46217
46299
  return Math.max(min, Math.min(max, Math.round(startWidth + (nextX - startX) * direction)));
46218
46300
  }
46301
+ /** Retry a workspace lookup that raced the Host publishing its session after startup. */
46302
+ function workspaceRetryDelay(error, attempt) {
46303
+ if (!(error instanceof ApiError) || error.code !== "session-not-found" || attempt >= 10) return void 0;
46304
+ return Math.min(250 * (attempt + 1), 1e3);
46305
+ }
46219
46306
  function PanelResizer({ className, label, width, min, max, defaultWidth, direction, onWidth }) {
46220
46307
  const [dragging, setDragging] = (0, react.useState)(false);
46221
46308
  const stopDragging = (0, react.useRef)(() => {});
@@ -46281,6 +46368,7 @@ section.${c}>footer { z-index: 1; }
46281
46368
  }
46282
46369
  function unloadedTab(path) {
46283
46370
  return {
46371
+ instance: Symbol(path),
46284
46372
  path,
46285
46373
  content: "",
46286
46374
  draft: "",
@@ -46293,6 +46381,12 @@ section.${c}>footer { z-index: 1; }
46293
46381
  preview: /\.md$/i.test(path)
46294
46382
  };
46295
46383
  }
46384
+ function WorkbenchTitlebar({ name }) {
46385
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
46386
+ className: "dvw-titlebar",
46387
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: "DSH Workbench" }), name !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: name })]
46388
+ });
46389
+ }
46296
46390
  /** Restore tab headers without reading their file contents. */
46297
46391
  function restoreTabPaths(paths) {
46298
46392
  return [...new Set(paths)].map(unloadedTab);
@@ -46310,6 +46404,12 @@ section.${c}>footer { z-index: 1; }
46310
46404
  const path = tab.title ?? tab.diffSourcePath ?? tab.path.replace(/^diff:/, "");
46311
46405
  return path.split(/[\\/]/).at(-1) ?? path;
46312
46406
  }
46407
+ /** Return the horizontal scroll offset that keeps an active tab inside the tab strip. */
46408
+ function tabScrollLeft(scrollLeft, viewport, tab) {
46409
+ if (tab.left < viewport.left) return scrollLeft - (viewport.left - tab.left);
46410
+ if (tab.right > viewport.right) return scrollLeft + (tab.right - viewport.right);
46411
+ return scrollLeft;
46412
+ }
46313
46413
  /** Invoke `fn` at most once per `ms` after the latest call, always running the freshest callback. */
46314
46414
  function useDebouncedCallback(fn, ms) {
46315
46415
  const fnRef = (0, react.useRef)(fn);
@@ -46345,13 +46445,16 @@ section.${c}>footer { z-index: 1; }
46345
46445
  api("fs.list", {
46346
46446
  sessionId,
46347
46447
  path
46348
- }).then(setRows).catch((error) => setError(String(error)));
46448
+ }).then((value) => {
46449
+ setRows(value);
46450
+ setError(void 0);
46451
+ }).catch((error) => setError(String(error)));
46349
46452
  }, [sessionId, path]);
46350
46453
  (0, react.useEffect)(load, [load]);
46351
46454
  (0, react.useEffect)(() => {
46352
46455
  const handler = (event) => {
46353
46456
  const paths = event.detail;
46354
- if (paths === void 0 || directoryAffected(path, paths)) load();
46457
+ if (!Array.isArray(paths) || directoryAffected(path, paths)) load();
46355
46458
  };
46356
46459
  window.addEventListener("dvw-files-changed", handler);
46357
46460
  return () => window.removeEventListener("dvw-files-changed", handler);
@@ -47507,15 +47610,18 @@ section.${c}>footer { z-index: 1; }
47507
47610
  const [panelHeight, setPanelHeight] = (0, react.useState)(260);
47508
47611
  const [sideWidth, setSideWidth] = (0, react.useState)(210);
47509
47612
  const [primarySideVisible, setPrimarySideVisible] = (0, react.useState)(() => localStorage.getItem("dvw:primary-side-visible") !== "closed");
47510
- const [statusVisible, setStatusVisible] = (0, react.useState)(() => localStorage.getItem("dvw:status-visible") !== "closed");
47613
+ const [statusVisible, setStatusVisible] = (0, react.useState)(() => localStorage.getItem("dvw:status-bar-visible") === "open");
47511
47614
  const [settingsOpen, setSettingsOpen] = (0, react.useState)(false);
47512
47615
  const [chatWidth, setChatWidth] = (0, react.useState)(() => Math.max(400, Math.min(720, Math.round(Number(localStorage.getItem("dvw:dsh-chat-width")) || 420))));
47513
47616
  const [chatVisible, setChatVisible] = (0, react.useState)(() => localStorage.getItem("dvw:dsh-chat-visible") !== "closed");
47514
47617
  const [outlineVisible, setOutlineVisible] = (0, react.useState)(() => localStorage.getItem("dvw:outline") !== "closed");
47618
+ const [watchIgnores, setWatchIgnores] = (0, react.useState)(() => localStorage.getItem("dvw:watch-ignore") ?? "");
47619
+ const [appliedWatchIgnores, setAppliedWatchIgnores] = (0, react.useState)(() => localStorage.getItem("dvw:watch-ignore") ?? "");
47515
47620
  const tabsRef = (0, react.useRef)(tabs);
47516
47621
  tabsRef.current = tabs;
47622
+ const tabListRef = (0, react.useRef)(null);
47517
47623
  const workspaceRequests = (0, react.useRef)(new WorkspaceRequestScope());
47518
- const loadingTabs = (0, react.useRef)(/* @__PURE__ */ new Set());
47624
+ const loadingTabs = (0, react.useRef)(/* @__PURE__ */ new Map());
47519
47625
  const dshDark = useDshDarkTheme();
47520
47626
  const [theme, setTheme] = (0, react.useState)(() => {
47521
47627
  const saved = localStorage.getItem("dvw:theme");
@@ -47527,7 +47633,17 @@ section.${c}>footer { z-index: 1; }
47527
47633
  (0, react.useEffect)(() => localStorage.setItem("dvw:dsh-chat-visible", chatVisible ? "open" : "closed"), [chatVisible]);
47528
47634
  (0, react.useEffect)(() => localStorage.setItem("dvw:dsh-chat-width", String(Math.round(chatWidth))), [chatWidth]);
47529
47635
  (0, react.useEffect)(() => localStorage.setItem("dvw:primary-side-visible", primarySideVisible ? "open" : "closed"), [primarySideVisible]);
47530
- (0, react.useEffect)(() => localStorage.setItem("dvw:status-visible", statusVisible ? "open" : "closed"), [statusVisible]);
47636
+ (0, react.useEffect)(() => localStorage.setItem("dvw:status-bar-visible", statusVisible ? "open" : "closed"), [statusVisible]);
47637
+ (0, react.useEffect)(() => localStorage.setItem("dvw:watch-ignore", watchIgnores), [watchIgnores]);
47638
+ (0, react.useEffect)(() => {
47639
+ const timer = setTimeout(() => setAppliedWatchIgnores(watchIgnores), 400);
47640
+ return () => clearTimeout(timer);
47641
+ }, [watchIgnores]);
47642
+ (0, react.useEffect)(() => {
47643
+ if (!snapshot.visible) return;
47644
+ document.body.setAttribute("data-dvw-workbench-active", "");
47645
+ return () => document.body.removeAttribute("data-dvw-workbench-active");
47646
+ }, [snapshot.visible]);
47531
47647
  (0, react.useEffect)(() => {
47532
47648
  if (!snapshot.visible) return;
47533
47649
  const onKey = (event) => {
@@ -47552,7 +47668,7 @@ section.${c}>footer { z-index: 1; }
47552
47668
  setActive(path);
47553
47669
  };
47554
47670
  (0, react.useEffect)(() => {
47555
- if (!snapshot.visible || sessionId === void 0) return;
47671
+ if (sessionId === void 0) return;
47556
47672
  const epoch = workspaceRequests.current.begin();
47557
47673
  const cleared = resetWorkspaceDocuments();
47558
47674
  loadingTabs.current.clear();
@@ -47562,114 +47678,190 @@ section.${c}>footer { z-index: 1; }
47562
47678
  setActive(cleared.active);
47563
47679
  setError(cleared.error);
47564
47680
  const controller = new AbortController();
47565
- api("workspace", { sessionId }, controller.signal).then((value) => {
47566
- if (!workspaceRequests.current.isCurrent(epoch)) return;
47567
- setWorkspace(value);
47568
- const saved = localStorage.getItem(`dvw:${value.cwd}`);
47569
- if (saved) try {
47570
- const parsed = JSON.parse(saved);
47571
- if (parsed.view) service.show(parsed.view);
47572
- if (typeof parsed.panelHeight === "number") setPanelHeight(parsed.panelHeight);
47573
- if (typeof parsed.sideWidth === "number") setSideWidth(Math.max(210, Math.min(640, Math.round(parsed.sideWidth))));
47574
- const restored = restoreTabPaths(parsed.paths ?? []);
47681
+ const load = async () => {
47682
+ for (let attempt = 0;; attempt++) try {
47683
+ const value = await api("workspace", { sessionId }, controller.signal);
47684
+ if (!workspaceRequests.current.isCurrent(epoch)) return;
47685
+ setWorkspace(value);
47686
+ let restored = [];
47687
+ let selected;
47688
+ try {
47689
+ const parsed = JSON.parse(localStorage.getItem(`dvw:${value.cwd}`) ?? "{}");
47690
+ if (parsed.view && service.getSnapshot().visible) service.show(parsed.view);
47691
+ if (typeof parsed.panelHeight === "number") setPanelHeight(parsed.panelHeight);
47692
+ if (typeof parsed.sideWidth === "number") setSideWidth(Math.max(210, Math.min(640, Math.round(parsed.sideWidth))));
47693
+ restored = restoreTabPaths(parsed.paths ?? []);
47694
+ selected = parsed.active;
47695
+ const drafts = JSON.parse(localStorage.getItem(`dvw:drafts:${sessionId}:${value.cwd}`) ?? "[]");
47696
+ if (Array.isArray(drafts)) for (const draft of drafts) {
47697
+ if (!draft || typeof draft.path !== "string" || typeof draft.content !== "string" || typeof draft.draft !== "string" || typeof draft.revision !== "string" || draft.path.startsWith("diff:")) continue;
47698
+ const tab = {
47699
+ ...unloadedTab(draft.path),
47700
+ content: draft.content,
47701
+ draft: draft.draft,
47702
+ revision: draft.revision,
47703
+ dirty: draft.draft !== draft.content,
47704
+ loaded: true
47705
+ };
47706
+ restored = [...restored.filter((row) => row.path !== tab.path), tab];
47707
+ }
47708
+ } catch {}
47575
47709
  setTabs(restored);
47576
- setActive(restored.some((tab) => tab.path === parsed.active) ? parsed.active : restored.at(-1)?.path);
47577
- } catch {}
47578
- }).catch((error) => {
47579
- if (!controller.signal.aborted && workspaceRequests.current.isCurrent(epoch)) setError(String(error));
47580
- });
47710
+ setActive(restored.some((tab) => tab.path === selected) ? selected : restored.at(-1)?.path);
47711
+ return;
47712
+ } catch (error) {
47713
+ if (controller.signal.aborted || !workspaceRequests.current.isCurrent(epoch)) return;
47714
+ const delay = workspaceRetryDelay(error, attempt);
47715
+ if (delay === void 0) {
47716
+ setError(String(error));
47717
+ return;
47718
+ }
47719
+ await new Promise((resolve) => setTimeout(resolve, delay));
47720
+ if (controller.signal.aborted || !workspaceRequests.current.isCurrent(epoch)) return;
47721
+ }
47722
+ };
47723
+ load();
47581
47724
  return () => {
47582
47725
  controller.abort();
47583
47726
  loadingTabs.current.clear();
47584
47727
  workspaceRequests.current.invalidate(epoch);
47585
47728
  };
47586
- }, [snapshot.visible, sessionId]);
47729
+ }, [sessionId, cwd]);
47587
47730
  (0, react.useEffect)(() => {
47588
- if (workspace) localStorage.setItem(`dvw:${workspace.cwd}`, JSON.stringify({
47589
- view: snapshot.view,
47590
- paths: tabs.filter((t) => !t.path.startsWith("diff:")).map((t) => t.path),
47591
- active,
47592
- panelHeight,
47593
- sideWidth
47594
- }));
47731
+ if (!workspace || sessionId === void 0) return;
47732
+ try {
47733
+ localStorage.setItem(`dvw:${workspace.cwd}`, JSON.stringify({
47734
+ view: snapshot.view,
47735
+ paths: tabs.filter((t) => !t.path.startsWith("diff:")).map((t) => t.path),
47736
+ active,
47737
+ panelHeight,
47738
+ sideWidth
47739
+ }));
47740
+ localStorage.setItem(`dvw:drafts:${sessionId}:${workspace.cwd}`, JSON.stringify(tabs.filter((tab) => tab.dirty).map(({ path, content, draft, revision }) => ({
47741
+ path,
47742
+ content,
47743
+ draft,
47744
+ revision
47745
+ }))));
47746
+ } catch {
47747
+ setError("无法保存工作区草稿,请在离开页面前保存文件。");
47748
+ }
47595
47749
  }, [
47596
47750
  workspace,
47751
+ sessionId,
47597
47752
  snapshot.view,
47598
47753
  tabs,
47599
47754
  active,
47600
47755
  panelHeight,
47601
47756
  sideWidth
47602
47757
  ]);
47603
- (0, react.useEffect)(() => {
47604
- if (!snapshot.visible || sessionId === void 0) return;
47605
- const protocol = location.protocol === "https:" ? "wss" : "ws";
47606
- const ws = new WebSocket(`${protocol}://${location.host}/dsh-vscode/ws/files?sessionId=${encodeURIComponent(sessionId)}`);
47607
- ws.onmessage = (event) => {
47608
- let paths = [];
47609
- try {
47610
- paths = JSON.parse(String(event.data)).paths ?? [];
47611
- } catch {}
47612
- window.dispatchEvent(new CustomEvent("dvw-files-changed", { detail: paths }));
47613
- setTabs((current) => current.map((tab) => tab.dirty ? {
47614
- ...tab,
47615
- external: true
47616
- } : tab));
47617
- };
47618
- return () => ws.close();
47619
- }, [snapshot.visible, sessionId]);
47620
- (0, react.useEffect)(() => {
47621
- if (sessionId === void 0 || active === void 0) return;
47622
- const tab = tabsRef.current.find((row) => row.path === active);
47623
- if (tab === void 0 || tab.loaded !== false || loadingTabs.current.has(active)) return;
47758
+ const loadTab = (0, react.useCallback)((path) => {
47759
+ if (sessionId === void 0) return;
47624
47760
  const epoch = workspaceRequests.current.current();
47625
- loadingTabs.current.add(active);
47626
- const documentPreview = documentPreviewKind(active);
47627
- if (documentPreview !== void 0) {
47628
- const documentUrl = `/dsh-vscode/file?sessionId=${encodeURIComponent(sessionId)}&path=${encodeURIComponent(active)}`;
47629
- setTabs((rows) => rows.map((row) => row.path === active ? {
47630
- ...row,
47631
- loaded: true,
47632
- documentPreview,
47633
- documentUrl
47634
- } : row));
47635
- loadingTabs.current.delete(active);
47636
- return;
47637
- }
47638
- if (/\.(?:avif|bmp|gif|ico|jpe?g|png|svg|webp)$/i.test(active)) {
47639
- const imageUrl = `/dsh-vscode/file?sessionId=${encodeURIComponent(sessionId)}&path=${encodeURIComponent(active)}`;
47640
- setTabs((rows) => rows.map((row) => row.path === active ? {
47761
+ const token = Symbol(path);
47762
+ loadingTabs.current.set(path, token);
47763
+ const current = () => workspaceRequests.current.isCurrent(epoch) && loadingTabs.current.get(path) === token;
47764
+ const documentPreview = documentPreviewKind(path);
47765
+ const image = /\.(?:avif|bmp|gif|ico|jpe?g|png|svg|webp)$/i.test(path);
47766
+ if (documentPreview !== void 0 || image) {
47767
+ const url = `/dsh-vscode/file?sessionId=${encodeURIComponent(sessionId)}&path=${encodeURIComponent(path)}&v=${Date.now()}`;
47768
+ setTabs((rows) => rows.map((row) => row.path === path ? {
47641
47769
  ...row,
47642
47770
  loaded: true,
47643
- imageUrl
47771
+ ...image ? { imageUrl: url } : {
47772
+ documentPreview,
47773
+ documentUrl: url
47774
+ }
47644
47775
  } : row));
47645
- loadingTabs.current.delete(active);
47776
+ loadingTabs.current.delete(path);
47646
47777
  return;
47647
47778
  }
47648
47779
  api("fs.read", {
47649
47780
  sessionId,
47650
- path: active
47781
+ path
47651
47782
  }).then((doc) => {
47652
- if (!workspaceRequests.current.isCurrent(epoch)) return;
47783
+ if (!current()) return;
47653
47784
  if (doc.binary || doc.tooLarge) {
47654
- setTabs((rows) => rows.filter((row) => row.path !== active));
47655
- setActive((current) => current === active ? void 0 : current);
47656
- setError(doc.binary ? "二进制文件不能在文本编辑器中打开" : `文件超过 5 MiB:${active}`);
47785
+ setTabs((rows) => rows.map((row) => row.path === path ? {
47786
+ ...row,
47787
+ loaded: true,
47788
+ ...row.dirty ? {} : {
47789
+ binary: doc.binary,
47790
+ tooLarge: doc.tooLarge
47791
+ },
47792
+ external: true
47793
+ } : row));
47657
47794
  return;
47658
47795
  }
47659
- setTabs((rows) => rows.map((row) => row.path === active ? {
47796
+ setTabs((rows) => rows.map((row) => row.path !== path ? row : row.dirty ? {
47797
+ ...row,
47798
+ external: row.revision !== doc.revision
47799
+ } : {
47660
47800
  ...row,
47661
47801
  ...doc,
47662
47802
  draft: doc.content,
47663
- loaded: true
47664
- } : row));
47803
+ loaded: true,
47804
+ external: false
47805
+ }));
47665
47806
  }).catch((error) => {
47666
- if (workspaceRequests.current.isCurrent(epoch)) setError(String(error));
47667
- }).finally(() => loadingTabs.current.delete(active));
47807
+ if (current()) setError(String(error));
47808
+ }).finally(() => {
47809
+ if (current()) loadingTabs.current.delete(path);
47810
+ });
47811
+ }, [sessionId]);
47812
+ (0, react.useEffect)(() => {
47813
+ if (!snapshot.visible || sessionId === void 0 || workspace === void 0) return;
47814
+ const query = new URLSearchParams({ sessionId });
47815
+ const ignores = appliedWatchIgnores.trim();
47816
+ if (ignores !== "") query.set("ignore", ignores);
47817
+ const url = websocketUrl(`/dsh-vscode/ws/files?${query.toString()}`);
47818
+ if (url === void 0) return;
47819
+ const ws = new WebSocket(url);
47820
+ let closed = false;
47821
+ const refresh = (paths) => {
47822
+ if (closed) return;
47823
+ window.dispatchEvent(new CustomEvent("dvw-files-changed", { detail: paths }));
47824
+ for (const tab of tabsRef.current) {
47825
+ if (tab.path.startsWith("diff:") || tab.loaded === false) continue;
47826
+ if (paths === void 0 || paths.some((path) => tab.path === path || tab.path.startsWith(`${path}/`))) loadTab(tab.path);
47827
+ }
47828
+ };
47829
+ ws.onopen = () => refresh();
47830
+ ws.onmessage = (event) => {
47831
+ try {
47832
+ const value = JSON.parse(String(event.data));
47833
+ if (Array.isArray(value.paths) && value.paths.every((path) => typeof path === "string")) refresh(value.paths);
47834
+ } catch {}
47835
+ };
47836
+ return () => {
47837
+ closed = true;
47838
+ ws.close();
47839
+ };
47840
+ }, [
47841
+ snapshot.visible,
47842
+ sessionId,
47843
+ workspace,
47844
+ loadTab,
47845
+ appliedWatchIgnores
47846
+ ]);
47847
+ (0, react.useEffect)(() => {
47848
+ if (sessionId === void 0 || active === void 0 || workspace === void 0) return;
47849
+ if (tabsRef.current.find((row) => row.path === active)?.loaded === false && !loadingTabs.current.has(active)) loadTab(active);
47668
47850
  }, [
47669
47851
  active,
47670
47852
  sessionId,
47671
- tabs
47853
+ workspace,
47854
+ tabs,
47855
+ loadTab
47672
47856
  ]);
47857
+ (0, react.useEffect)(() => {
47858
+ const list = tabListRef.current;
47859
+ const selected = list?.querySelector(".dvw-tab[data-active=\"true\"]");
47860
+ if (list === null || selected === null || selected === void 0) return;
47861
+ const listRect = list.getBoundingClientRect();
47862
+ const tabRect = selected.getBoundingClientRect();
47863
+ list.scrollLeft = tabScrollLeft(list.scrollLeft, listRect, tabRect);
47864
+ }, [active, tabs.length]);
47673
47865
  const open = (path, line, column) => {
47674
47866
  if (sessionId !== void 0) openForWorkspace(path, line, column);
47675
47867
  };
@@ -47678,8 +47870,12 @@ section.${c}>footer { z-index: 1; }
47678
47870
  window.addEventListener("dvw-open-workspace-path", listener);
47679
47871
  return () => window.removeEventListener("dvw-open-workspace-path", listener);
47680
47872
  }, [sessionId, tabs]);
47873
+ const savingTabs = (0, react.useRef)(/* @__PURE__ */ new Set());
47681
47874
  const save = async (tab) => {
47682
- if (sessionId === void 0 || !tab.dirty) return;
47875
+ if (sessionId === void 0 || !tab.dirty || savingTabs.current.has(tab.path)) return;
47876
+ const epoch = workspaceRequests.current.current();
47877
+ savingTabs.current.add(tab.path);
47878
+ loadingTabs.current.delete(tab.path);
47683
47879
  try {
47684
47880
  const doc = await api("fs.save", {
47685
47881
  sessionId,
@@ -47687,27 +47883,34 @@ section.${c}>footer { z-index: 1; }
47687
47883
  content: tab.draft,
47688
47884
  revision: tab.revision
47689
47885
  });
47690
- setTabs((rows) => rows.map((row) => row.path === tab.path ? {
47886
+ if (!workspaceRequests.current.isCurrent(epoch)) return;
47887
+ loadingTabs.current.delete(tab.path);
47888
+ setTabs((rows) => rows.map((row) => row.path === tab.path && row.instance === tab.instance ? {
47691
47889
  ...row,
47692
47890
  ...doc,
47693
- draft: doc.content,
47694
- dirty: false,
47891
+ draft: row.draft,
47892
+ dirty: row.draft !== doc.content,
47695
47893
  external: false
47696
47894
  } : row));
47697
47895
  } catch (error) {
47698
- setError(String(error));
47896
+ if (workspaceRequests.current.isCurrent(epoch)) setError(String(error));
47897
+ } finally {
47898
+ savingTabs.current.delete(tab.path);
47699
47899
  }
47700
47900
  };
47701
47901
  const close = (tab) => {
47702
47902
  if (tab.dirty && !confirm(`${tab.path} 有未保存更改,确定关闭?`)) return;
47903
+ loadingTabs.current.delete(tab.path);
47703
47904
  setTabs((rows) => rows.filter((row) => row.path !== tab.path));
47704
47905
  if (active === tab.path) setActive(tabs.filter((row) => row.path !== tab.path).at(-1)?.path);
47705
47906
  };
47706
47907
  const closeAll = () => {
47707
47908
  const dirty = tabs.filter((tab) => tab.dirty);
47708
47909
  if (dirty.length > 0 && !confirm(`有 ${dirty.length} 个文件包含未保存更改,确定全部关闭?`)) return;
47910
+ loadingTabs.current.clear();
47709
47911
  setTabs([]);
47710
47912
  setActive(void 0);
47913
+ setError(void 0);
47711
47914
  };
47712
47915
  const activeTab = tabs.find((tab) => tab.path === active);
47713
47916
  const Panel = panels.find((panel) => panel.id === snapshot.bottomPanel)?.component;
@@ -47737,10 +47940,10 @@ section.${c}>footer { z-index: 1; }
47737
47940
  }
47738
47941
  };
47739
47942
  if (!snapshot.visible) return null;
47740
- if (sessionId === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
47943
+ if (sessionId === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
47741
47944
  className: "dvw-overlay",
47742
47945
  "data-dvw-theme": theme === "dsh" ? void 0 : theme,
47743
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
47946
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkbenchTitlebar, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
47744
47947
  className: "dvw-empty",
47745
47948
  style: { gridColumn: "1/4" },
47746
47949
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
@@ -47751,7 +47954,7 @@ section.${c}>footer { z-index: 1; }
47751
47954
  children: "返回 DSH"
47752
47955
  })
47753
47956
  ] })
47754
- })
47957
+ })]
47755
47958
  });
47756
47959
  const markdown = activeTab !== void 0 && !activeTab.path.startsWith("diff:") && /\.md$/i.test(activeTab.path);
47757
47960
  const diffMarkdown = activeTab?.diff !== void 0 && /\.md$/i.test(activeTab.diffSourcePath ?? "");
@@ -47773,6 +47976,7 @@ section.${c}>footer { z-index: 1; }
47773
47976
  onDragOverCapture: suppressAttachmentDrop,
47774
47977
  onDropCapture: suppressAttachmentDrop,
47775
47978
  children: [
47979
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkbenchTitlebar, { name: workspace?.name }),
47776
47980
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DshConversationPanel, {
47777
47981
  visible: chatVisible && !settingsOpen,
47778
47982
  width: chatWidth,
@@ -47831,82 +48035,101 @@ section.${c}>footer { z-index: 1; }
47831
48035
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "close" })
47832
48036
  })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
47833
48037
  className: "dvw-settings-body",
47834
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", { children: [
47835
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: "外观" }),
47836
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", { children: "颜色主题" }),
47837
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
47838
- className: "dvw-settings-themes",
47839
- children: [
47840
- ["dsh", "跟随 DSH"],
47841
- ["dark", "深色"],
47842
- ["light", "浅色"]
47843
- ].map(([value, label]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
47844
- "data-active": theme === value,
47845
- onClick: () => setTheme(value),
48038
+ children: [
48039
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", { children: [
48040
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: "外观" }),
48041
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", { children: "颜色主题" }),
48042
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
48043
+ className: "dvw-settings-themes",
48044
+ children: [
48045
+ ["dsh", "跟随 DSH"],
48046
+ ["dark", "深色"],
48047
+ ["light", "浅色"]
48048
+ ].map(([value, label]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
48049
+ "data-active": theme === value,
48050
+ onClick: () => setTheme(value),
48051
+ children: [
48052
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: `dvw-theme-swatch ${value}` }),
48053
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label }),
48054
+ theme === value && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "check" })
48055
+ ]
48056
+ }, value))
48057
+ })
48058
+ ] }),
48059
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", { children: [
48060
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: "布局" }),
48061
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
48062
+ className: "dvw-setting-check",
48063
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
48064
+ type: "checkbox",
48065
+ checked: primarySideVisible,
48066
+ onChange: (event) => setPrimarySideVisible(event.target.checked)
48067
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "显示左侧视图" })]
48068
+ }),
48069
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
48070
+ className: "dvw-setting-check",
48071
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
48072
+ type: "checkbox",
48073
+ checked: chatVisible,
48074
+ onChange: (event) => setChatVisible(event.target.checked)
48075
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "显示 DSH 对话栏" })]
48076
+ }),
48077
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
48078
+ className: "dvw-setting-check",
48079
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
48080
+ type: "checkbox",
48081
+ checked: statusVisible,
48082
+ onChange: (event) => setStatusVisible(event.target.checked)
48083
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "显示底部状态栏" })]
48084
+ }),
48085
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
48086
+ className: "dvw-setting-range",
47846
48087
  children: [
47847
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: `dvw-theme-swatch ${value}` }),
47848
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label }),
47849
- theme === value && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "check" })
48088
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "左侧视图宽度" }),
48089
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
48090
+ type: "range",
48091
+ min: "210",
48092
+ max: "640",
48093
+ step: "1",
48094
+ value: Math.round(sideWidth),
48095
+ onChange: (event) => setSideWidth(Math.round(Number(event.target.value)))
48096
+ }),
48097
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("output", { children: [sideWidth, "px"] })
47850
48098
  ]
47851
- }, value))
47852
- })
47853
- ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", { children: [
47854
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: "布局" }),
47855
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
47856
- className: "dvw-setting-check",
47857
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
47858
- type: "checkbox",
47859
- checked: primarySideVisible,
47860
- onChange: (event) => setPrimarySideVisible(event.target.checked)
47861
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "显示左侧视图" })]
47862
- }),
47863
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
47864
- className: "dvw-setting-check",
47865
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
47866
- type: "checkbox",
47867
- checked: chatVisible,
47868
- onChange: (event) => setChatVisible(event.target.checked)
47869
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "显示 DSH 对话栏" })]
47870
- }),
47871
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
47872
- className: "dvw-setting-check",
47873
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
47874
- type: "checkbox",
47875
- checked: statusVisible,
47876
- onChange: (event) => setStatusVisible(event.target.checked)
47877
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "显示底部状态栏" })]
47878
- }),
47879
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
47880
- className: "dvw-setting-range",
47881
- children: [
47882
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "左侧视图宽度" }),
47883
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
47884
- type: "range",
47885
- min: "210",
47886
- max: "640",
47887
- step: "1",
47888
- value: Math.round(sideWidth),
47889
- onChange: (event) => setSideWidth(Math.round(Number(event.target.value)))
47890
- }),
47891
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("output", { children: [sideWidth, "px"] })
47892
- ]
47893
- }),
47894
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
47895
- className: "dvw-setting-range",
47896
- children: [
47897
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "DSH 对话栏宽度" }),
47898
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
47899
- type: "range",
47900
- min: "400",
47901
- max: "720",
47902
- step: "1",
47903
- value: Math.round(chatWidth),
47904
- onChange: (event) => setChatWidth(Math.max(400, Math.round(Number(event.target.value))))
47905
- }),
47906
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("output", { children: [chatWidth, "px"] })
47907
- ]
47908
- })
47909
- ] })]
48099
+ }),
48100
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
48101
+ className: "dvw-setting-range",
48102
+ children: [
48103
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "DSH 对话栏宽度" }),
48104
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
48105
+ type: "range",
48106
+ min: "400",
48107
+ max: "720",
48108
+ step: "1",
48109
+ value: Math.round(chatWidth),
48110
+ onChange: (event) => setChatWidth(Math.max(400, Math.round(Number(event.target.value))))
48111
+ }),
48112
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("output", { children: [chatWidth, "px"] })
48113
+ ]
48114
+ })
48115
+ ] }),
48116
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", { children: [
48117
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: "文件监听" }),
48118
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", { children: "自动刷新排除项(每行一个目录名或相对路径)" }),
48119
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
48120
+ className: "dvw-setting-textarea",
48121
+ rows: 4,
48122
+ spellCheck: false,
48123
+ placeholder: "vendor\nthird_part/libs/boost",
48124
+ value: watchIgnores,
48125
+ onChange: (event) => setWatchIgnores(event.target.value)
48126
+ }),
48127
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
48128
+ className: "dvw-setting-hint",
48129
+ children: "默认已跳过 node_modules、vendor、third_party、build、dist 等大目录;修改后会自动重新连接监听。"
48130
+ })
48131
+ ] })
48132
+ ]
47910
48133
  })]
47911
48134
  })
47912
48135
  }),
@@ -47961,9 +48184,9 @@ section.${c}>footer { z-index: 1; }
47961
48184
  className: "dvw-side",
47962
48185
  "data-side-width": sideWidth,
47963
48186
  children: [
47964
- snapshot.view === "explorer" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Explorer, {
48187
+ snapshot.view === "explorer" && workspace !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Explorer, {
47965
48188
  sessionId,
47966
- cwd: workspace?.cwd,
48189
+ cwd: workspace.cwd,
47967
48190
  selected: active,
47968
48191
  onOpen: (path) => void open(path)
47969
48192
  }),
@@ -48012,6 +48235,7 @@ section.${c}>footer { z-index: 1; }
48012
48235
  className: "dvw-tabs",
48013
48236
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
48014
48237
  className: "dvw-tab-list",
48238
+ ref: tabListRef,
48015
48239
  children: tabs.map((tab) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
48016
48240
  className: "dvw-tab",
48017
48241
  "data-active": tab.path === active,
@@ -48164,6 +48388,12 @@ section.${c}>footer { z-index: 1; }
48164
48388
  source: activeTab.draft,
48165
48389
  sessionId,
48166
48390
  path: activeTab.path
48391
+ }) : activeTab.binary || activeTab.tooLarge ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
48392
+ className: "dvw-message",
48393
+ children: activeTab.binary ? "二进制文件不能在文本编辑器中打开" : `文件超过 5 MiB:${activeTab.path}`
48394
+ }) : activeTab.loaded === false ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
48395
+ className: "dvw-message",
48396
+ children: "正在加载文件…"
48167
48397
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MonacoEditor, {
48168
48398
  uri: `${workspace?.cwd ?? ""}/${activeTab.path}`,
48169
48399
  value: activeTab.draft,
@@ -48257,20 +48487,23 @@ section.${c}>footer { z-index: 1; }
48257
48487
  //#region src/client/styles.ts
48258
48488
  const CSS$1 = String.raw`
48259
48489
  @font-face{font-family:codicon;font-display:block;src:url('/dsh-vscode/codicons/codicon.ttf') format('truetype')}
48490
+ :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)}
48260
48491
  .codicon{display:inline-block;font:normal normal normal 16px/1 codicon;text-align:center;text-decoration:none;text-rendering:auto;-webkit-font-smoothing:antialiased;user-select:none}
48261
48492
  .codicon-add:before{content:"\ea60"}.codicon-git-branch:before,.codicon-source-control:before{content:"\ea68"}.codicon-search:before{content:"\ea6d"}.codicon-edit:before{content:"\ea73"}.codicon-close:before{content:"\ea76"}.codicon-close-all:before{content:"\eac1"}.codicon-cloud-upload:before{content:"\eac3"}.codicon-file:before{content:"\ea7b"}.codicon-new-file:before{content:"\ea7f"}.codicon-new-folder:before{content:"\ea80"}.codicon-folder:before{content:"\ea83"}.codicon-trash:before{content:"\ea81"}.codicon-code:before{content:"\eac4"}.codicon-check:before{content:"\eab2"}.codicon-chevron-down:before{content:"\eab4"}.codicon-chevron-right:before{content:"\eab6"}.codicon-color-mode:before{content:"\eac6"}.codicon-diff:before,.codicon-diff-sidebyside:before{content:"\eae1"}.codicon-diff-single:before{content:"\ec22"}.codicon-discard:before{content:"\eae2"}.codicon-file-code:before{content:"\eae9"}.codicon-file-media:before{content:"\eaea"}.codicon-file-pdf:before{content:"\eaeb"}.codicon-file-zip:before{content:"\eaef"}.codicon-files:before{content:"\eaf0"}.codicon-folder-opened:before{content:"\eaf7"}.codicon-git-commit:before{content:"\eafc"}.codicon-graph:before{content:"\eb03"}.codicon-home:before{content:"\eb06"}.codicon-list-tree:before{content:"\eb86"}.codicon-preview:before{content:"\eb2f"}.codicon-refresh:before{content:"\eb37"}.codicon-remove:before{content:"\eb3b"}.codicon-check-all:before{content:"\ebb1"}
48262
48493
  .codicon-layout-sidebar-right:before{content:"\ebf4"}.codicon-layout-sidebar-right-off:before{content:"\ec00"}.codicon-settings:before{content:"\eb51"}.codicon-sparkle:before{content:"\ec10"}.codicon-split-horizontal:before{content:"\eb56"}.codicon-terminal:before{content:"\ea85"}
48263
48494
  .dvw-launch{display:flex;align-items:center;gap:10px;width:100%;height:36px;padding:0 9px;border:0;border-radius:8px;background:transparent;color:var(--dsw-alias-label-secondary,#aaa);cursor:pointer;font:inherit}.dvw-launch:hover{background:var(--dsw-alias-interactive-bg-hover,#292929);color:var(--dsw-alias-label-primary,#fff)}.dvw-launcher-mount{position:fixed;z-index:20;right:16px;bottom:16px}.dvw-launcher-mount .dvw-launch{width:auto;height:32px;padding:0 12px;justify-content:center;border:1px solid var(--dsw-alias-border-l3,#e5e7eb);border-radius:6px;background:var(--dsw-alias-bg-layer-1,#fff);box-shadow:0 1px 2px rgba(0,0,0,.06);color:var(--dsw-alias-label-primary,#333)}body[data-ds-dark-theme] .dvw-launcher-mount .dvw-launch{color:var(--dsw-alias-label-primary,#ddd)}@media(max-width:640px){.dvw-launcher-mount{right:8px;bottom:8px}.dvw-launcher-mount .dvw-launch{height:30px;padding:0 10px;font-size:12px}}
48264
- .dvw-overlay{--dvw-side-width:210px;--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-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 24px;background:var(--dvw-base);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}
48495
+ .dvw-overlay{--dvw-side-width:210px;--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-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 24px;box-sizing:border-box;padding-top:var(--dvw-titlebar-height);background:var(--dvw-base);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}
48496
+ .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}
48497
+ html[data-windows-titlebar] .dvw-overlay{top:var(--dvw-titlebar-height);padding-top:0}
48265
48498
  body[data-ds-dark-theme] .dvw-overlay,.dvw-overlay[data-dvw-theme=dark]{color-scheme:dark}
48266
48499
  .dvw-overlay[data-dvw-theme=dark]{--dvw-base:#151517;--dvw-surface-1:#232324;--dvw-surface-2:#2c2c2e;--dvw-surface-3:#353638;--dvw-text:#f9fafb;--dvw-text-2:#cfd3d6;--dvw-text-3:#adb2b8;--dvw-border:#ffffff1f;--dvw-border-soft:#ffffff29;--dvw-hover:#ffffff14;--dvw-active:#ffffff24;--dvw-accent:#679efe;--dvw-error:#f25a5a;--dvw-success:#22c55e;--dvw-warn:#f59e0b}
48267
48500
  .dvw-overlay[data-dvw-theme=light]{--dvw-base:#fff;--dvw-surface-1:#fff;--dvw-surface-2:#fff;--dvw-surface-3:#fff;--dvw-text:#0f1115;--dvw-text-2:#61666b;--dvw-text-3:#81858c;--dvw-border:#0000001a;--dvw-border-soft:#0000001f;--dvw-hover:#2631480f;--dvw-active:#2631481a;--dvw-accent:#4176e6;--dvw-error:#ec1313;--dvw-success:#22c55e;--dvw-warn:#f59e0b;color-scheme:light}
48268
48501
  .dvw-overlay *{box-sizing:border-box}.dvw-activity{grid-row:1/3;background:var(--dvw-base);border-right:1px solid var(--dvw-border-soft);display:flex;flex-direction:column;align-items:center}.dvw-act{width:48px;height:48px;border:0;border-left:2px solid transparent;background:transparent;color:var(--dvw-text-3);font-size:22px;cursor:pointer}.dvw-act:hover,.dvw-act[data-active=true]{color:var(--dvw-text)}.dvw-act[data-active=true]{border-left-color:var(--dvw-accent)}.dvw-act.dsh{margin-top:auto}.dvw-side{grid-column:2;grid-row:1/3;min-width:0;width:100%;background:var(--dvw-surface-1);border-right:1px solid var(--dvw-border);display:flex;flex-direction:column}.dvw-side-resizer{grid-column:2;grid-row:1/3;justify-self:end;width:4px;height:100%;z-index:4;cursor:ew-resize;transform:translateX(2px);touch-action:none}.dvw-side-resizer:hover,.dvw-side-resizer:focus-visible,.dvw-side-resizer[data-dragging=true]{background:var(--dvw-accent)}.dvw-side-head{height:36px;display:flex;align-items:center;padding:0 12px;text-transform:uppercase;font-size:11px;letter-spacing:.4px}.dvw-toolbar{margin-left:auto;display:flex;gap:2px}.dvw-icon{border:0;background:transparent;color:var(--dvw-text-2);border-radius:4px;min-width:24px;height:24px;display:inline-grid;place-items:center;cursor:pointer}.dvw-icon:hover{background:var(--dvw-hover);color:var(--dvw-text)}.dvw-icon:disabled{opacity:.45;cursor:default}.dvw-file-picker{display:none}.dvw-tree,.dvw-results,.dvw-git{overflow:auto;flex:1}.dvw-tree[data-drop-target=true]{outline:1px dashed var(--dvw-accent);outline-offset:-3px}.dvw-tree-row{display:flex;align-items:center;height:24px;padding-right:6px;cursor:pointer;white-space:nowrap}.dvw-tree-row:hover{background:var(--dvw-hover)}.dvw-tree-row[data-selected=true],.dvw-tree-row[data-drop-target=true]{background:var(--dvw-active)}.dvw-chevron{width:16px;flex:none;text-align:center;color:var(--dvw-text-3)}.dvw-file-icon{width:18px;flex:none;color:var(--dvw-text-2)}.dvw-file-icon.folder{color:var(--dvw-accent)}.dvw-tree-name{overflow:hidden;text-overflow:ellipsis}.dvw-tree-rename,.dvw-tree-create-input{min-width:0;flex:1;height:20px;border:1px solid var(--dvw-accent);border-radius:0;background:var(--dvw-surface-1);color:var(--dvw-text);padding:0 3px;font:inherit;letter-spacing:0;outline:0}.dvw-tree-create-row{cursor:text}.dvw-tree-create-row:hover{background:transparent}.dvw-tree-create-input::placeholder{color:var(--dvw-text-3)}.dvw-tree-create-input[aria-invalid=true]{border-color:var(--dvw-error)}.dvw-tree-create-error{min-height:20px;padding-top:2px;padding-right:6px;padding-bottom:3px;color:var(--dvw-error);font-size:11px;line-height:15px;white-space:normal;overflow-wrap:anywhere}.dvw-tree-status{margin-left:auto;padding-left:6px;font-size:11px;font-weight:600;color:var(--dvw-warn)}.dvw-tree-status[data-status=M]{color:var(--dvw-warn)}.dvw-tree-status[data-status=A]{color:var(--dvw-success)}.dvw-tree-status[data-status=D]{color:var(--dvw-error)}.dvw-context-menu{position:fixed;z-index:40;min-width:148px;padding:4px;border:1px solid var(--dvw-border);border-radius:5px;background:var(--dvw-surface-3);box-shadow:0 6px 20px rgba(0,0,0,.3)}.dvw-context-menu button{width:100%;height:28px;border:0;border-radius:3px;background:transparent;color:var(--dvw-text);display:flex;align-items:center;gap:8px;padding:0 8px;text-align:left;font:inherit;cursor:pointer}.dvw-context-menu button:hover{background:var(--dvw-hover)}.dvw-context-menu .dvw-context-delete{color:var(--dvw-error)}
48269
- .dvw-main{grid-column:3;grid-row:1;display:flex;min-width:0;min-height:0;flex-direction:column;background:var(--dvw-surface-1)}.dvw-tabs{height:36px;background:var(--dvw-base);display:flex;overflow-x:auto}.dvw-tab{height:36px;min-width:110px;max-width:260px;border:0;border-right:1px solid var(--dvw-border-soft);background:var(--dvw-base);color:var(--dvw-text-2);padding:0 8px 0 12px;display:flex;align-items:center;gap:8px;cursor:pointer}.dvw-tab[data-active=true]{background:var(--dvw-surface-1);color:var(--dvw-text);border-top:1px solid var(--dvw-accent)}.dvw-tab-name{overflow:hidden;text-overflow:ellipsis;flex:1;text-align:left}.dvw-editor{position:relative;flex:1;min-height:0}.dvw-editor-toolbar{position:absolute;z-index:3;top:0;right:0;left:0;height:36px;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:36px}.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)}
48502
+ .dvw-main{grid-column:3;grid-row:1;display:flex;min-width:0;min-height:0;flex-direction:column;background:var(--dvw-surface-1)}.dvw-tabs{height:36px;background:var(--dvw-base);display:flex;overflow:hidden}.dvw-tab{height:36px;min-width:110px;max-width:260px;border:0;border-right:1px solid var(--dvw-border-soft);background:var(--dvw-base);color:var(--dvw-text-2);padding:0 8px 0 12px;display:flex;align-items:center;gap:8px;cursor:pointer;flex:none;overflow:hidden;white-space:nowrap}.dvw-tab[data-active=true]{background:var(--dvw-surface-1);color:var(--dvw-text);border-top:1px solid var(--dvw-accent)}.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:36px;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:36px}.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)}
48270
48503
  .dvw-bottom{grid-column:3;grid-row:2;height:260px;min-height:120px;border-top:1px solid var(--dvw-border);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-accent);color:#fff;display:flex;align-items:center;padding:0 8px;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,#17181c 50%,#fff 50%)}.dvw-theme-orb.dark{background:#17181c}.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,#17181c 0 50%,#fff 50%)}.dvw-theme-swatch.dark{background:#17181c}.dvw-theme-swatch.light{background:#fff}
48271
48504
  .dvw-search-form{padding:8px;display:grid;gap:6px}.dvw-input,.dvw-textarea,.dvw-select{width:100%;border:1px solid var(--dvw-border);background:var(--dvw-surface-2);color:var(--dvw-text);padding:5px 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{padding:5px 8px;font-weight:600}.dvw-result{padding:4px 8px 4px 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}
48272
48505
  .dvw-git-head{padding:7px 10px;border-bottom:1px solid var(--dvw-border);display:flex;align-items:center;gap:8px}.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-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;border-radius:5px;font-weight:600;position:sticky;top:0;background:var(--dvw-surface-1);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;min-height:28px;padding:3px 5px 3px 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-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)}
48273
- .dvw-tabs{overflow:hidden}.dvw-tab-list{display:flex;min-width:0;flex:1;overflow-x:auto}.dvw-tab-actions{flex:none;width:42px;display:grid;place-items:center;padding:0 6px;background:var(--dvw-base)}.dvw-close-all{border:1px solid var(--dvw-border);background:var(--dvw-base)}.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:27px;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}
48506
+ .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-tab-actions{flex:none;width:42px;display:grid;place-items:center;padding:0 6px;border-left:1px solid var(--dvw-border-soft);background:var(--dvw-base)}.dvw-close-all{border:1px solid var(--dvw-border);background:var(--dvw-base)}.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:27px;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}
48274
48507
  .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:25px;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}
48275
48508
  .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-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}
48276
48509
  .dvw-markdown{height:100%;overflow:auto;padding:28px clamp(24px,6vw,80px) 60px;color:var(--dvw-text);font-size:15px;line-height:1.65}.dvw-markdown>*:first-child{margin-top:0}.dvw-markdown h1,.dvw-markdown h2{padding-bottom:.3em;border-bottom:1px solid var(--dvw-border)}.dvw-markdown h1{font-size:2em}.dvw-markdown h2{font-size:1.5em}.dvw-markdown h3{font-size:1.25em}.dvw-markdown a{color:var(--dvw-accent)}.dvw-markdown code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;background:var(--dvw-surface-2);border-radius:4px;padding:.15em .35em}.dvw-markdown pre{overflow:auto;padding:14px;border:1px solid var(--dvw-border-soft);border-radius:7px;background:var(--dvw-base)}.dvw-markdown pre code{padding:0;background:transparent}.dvw-markdown blockquote{margin-left:0;padding-left:14px;border-left:3px solid var(--dvw-border);color:var(--dvw-text-2)}.dvw-markdown table{border-collapse:collapse;display:block;overflow:auto}.dvw-markdown th,.dvw-markdown td{padding:6px 12px;border:1px solid var(--dvw-border)}.dvw-markdown tr:nth-child(2n){background:var(--dvw-hover)}.dvw-markdown img{max-width:100%}.dvw-markdown hr{border:0;border-top:1px solid var(--dvw-border)}
@@ -48285,11 +48518,11 @@ body[data-ds-dark-theme] .dvw-overlay,.dvw-overlay[data-dvw-theme=dark]{color-sc
48285
48518
  .dvw-chat-head{height:36px;display:flex;align-items:center;justify-content:space-between;padding:0 6px 0 12px;border-bottom:1px solid var(--dvw-border);background:var(--dvw-base);font-weight:600}
48286
48519
  .dvw-chat-head>span{display:flex;align-items:center;gap:7px}.dvw-chat-body{height:calc(100% - 36px);background:var(--dvw-base)}
48287
48520
  .dvw-dsh-mark{display:block}
48288
- .dvw-chat-resizer{position:fixed;top:36px;right:calc(var(--dvw-chat-width) - 2px);bottom:0;width:4px;z-index:4;cursor:ew-resize;touch-action:none}
48521
+ .dvw-chat-resizer{position:fixed;top:var(--dvw-titlebar-height);right:calc(var(--dvw-chat-width) - 2px);bottom:0;width:4px;z-index:4;cursor:ew-resize;touch-action:none}
48289
48522
  .dvw-chat-resizer:hover,.dvw-chat-resizer:focus-visible,.dvw-chat-resizer[data-dragging=true]{background:var(--dvw-accent)}
48290
48523
  .dvw-side-resizer,.dvw-chat-resizer{width:10px;cursor:ew-resize;touch-action:none;background:transparent}
48291
48524
  .dvw-side-resizer{position:relative;transform:translateX(5px);z-index:22}
48292
- .dvw-chat-resizer{position:fixed;top:36px;right:calc(var(--dvw-chat-width) - 5px);z-index:22}
48525
+ .dvw-chat-resizer{position:fixed;top:var(--dvw-titlebar-height);right:calc(var(--dvw-chat-width) - 5px);z-index:22}
48293
48526
  .dvw-side-resizer::after,.dvw-chat-resizer::after{content:"";position:absolute;top:0;bottom:0;left:4px;width:2px;background:var(--dvw-border)}
48294
48527
  .dvw-chat-resizer::after{left:1px;width:6px}
48295
48528
  .dvw-side-resizer:hover,.dvw-side-resizer:focus-visible,.dvw-side-resizer[data-dragging=true],.dvw-chat-resizer:hover,.dvw-chat-resizer:focus-visible,.dvw-chat-resizer[data-dragging=true]{background:transparent}
@@ -48299,7 +48532,10 @@ body[data-ds-dark-theme] .dvw-overlay,.dvw-overlay[data-dvw-theme=dark]{color-sc
48299
48532
  .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)}
48300
48533
  .dvw-chat-toggle{position:absolute;z-index:5;top:6px;right:6px;border:1px solid var(--dvw-border);background:var(--dvw-base)}
48301
48534
  .dvw-overlay:not([data-dvw-chat=true]) .dvw-tabs{padding-right:36px}
48302
- [data-dvw-conversation-panel]{position:fixed!important;top:36px!important;right:0!important;bottom:var(--dvw-status-height,24px)!important;left:auto!important;width:var(--dvw-chat-width)!important;height:auto!important;min-width:0!important;z-index:21!important;border-left:1px solid var(--dsw-alias-border-l2)!important;box-shadow:none!important}
48535
+ [data-dvw-conversation-panel]{position:fixed!important;top:var(--dvw-titlebar-height)!important;right:0!important;bottom:var(--dvw-status-height,24px)!important;left:auto!important;width:var(--dvw-chat-width)!important;height:auto!important;min-width:0!important;z-index:21!important;border-left:1px solid var(--dsw-alias-border-l2)!important;box-shadow:none!important}
48536
+ body[data-dvw-workbench-active] [data-sidebar-right-expand],body[data-dvw-conversation-active] [data-sidebar-right-expand]{display:none!important}
48537
+ body[data-dvw-workbench-active] [data-shell-leading]{display:none!important}
48538
+ body[data-dvw-workbench-active] [data-sidebar-toggle]{display:none!important}
48303
48539
  .dvw-confirm-backdrop{position:fixed;z-index:50;inset:0;display:grid;place-items:center;padding:24px;background:rgba(0,0,0,.38)}.dvw-confirm{width:min(380px,calc(100vw - 48px));border:1px solid var(--dvw-border);border-radius:7px;background:var(--dvw-surface-1);box-shadow:0 12px 36px rgba(0,0,0,.34);padding:18px}.dvw-confirm h2{margin:0 0 12px;font-size:15px}.dvw-confirm p{margin:0;color:var(--dvw-text)}.dvw-confirm-note{margin-top:8px!important;color:var(--dvw-text-3)!important;font-size:12px}.dvw-confirm footer{display:flex;justify-content:flex-end;gap:8px;margin-top:20px}.dvw-confirm footer button{height:28px;border:1px solid var(--dvw-border);border-radius:4px;background:var(--dvw-surface-2);color:var(--dvw-text);padding:0 12px;font:inherit;cursor:pointer}.dvw-confirm footer button:hover{background:var(--dvw-hover)}.dvw-confirm footer .dvw-danger-button{border-color:color-mix(in srgb,var(--dvw-error) 65%,var(--dvw-border));background:var(--dvw-error);color:#fff}.dvw-confirm footer .dvw-danger-button:hover{background:color-mix(in srgb,var(--dvw-error) 82%,#000)}
48304
48540
  .dvw-tree[data-dvw-native-drop-target=true]{outline:1px dashed var(--dvw-accent);outline-offset:-3px}.dvw-tree-row[data-dvw-native-drop-target=true]{background:var(--dvw-active)}
48305
48541
  .dvw-act:disabled{opacity:.4;cursor:not-allowed}
@@ -48316,6 +48552,9 @@ body[data-ds-dark-theme] .dvw-overlay,.dvw-overlay[data-dvw-theme=dark]{color-sc
48316
48552
  .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))}
48317
48553
  .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}
48318
48554
  @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}}
48555
+ .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}
48556
+ .dvw-setting-textarea:focus{outline:none;border-color:var(--dvw-accent)}
48557
+ .dvw-setting-hint{margin:8px 0 0;color:var(--dvw-text-3);font-size:11px;line-height:1.5}
48319
48558
  `;
48320
48559
  function installStyles() {
48321
48560
  const id = "dsh-vscode-workbench/styles";