dsh-vscode-workbench 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -4487,9 +4487,13 @@ Please report this to https://github.com/markedjs/marked.`, e) {
4487
4487
  }, []);
4488
4488
  return dark;
4489
4489
  }
4490
- function Tree({ sessionId, path, depth, expanded, selected, onToggle, onOpen, onChange }) {
4490
+ function Tree({ sessionId, path, depth, expanded, selected, selectedDirectory, statuses, onToggle, onSelectDirectory, onOpen, onChange, onUpload }) {
4491
4491
  const [rows, setRows] = (0, react.useState)([]);
4492
4492
  const [error, setError] = (0, react.useState)();
4493
+ const [dropTarget, setDropTarget] = (0, react.useState)(false);
4494
+ const [context, setContext] = (0, react.useState)();
4495
+ const [renaming, setRenaming] = (0, react.useState)();
4496
+ const [pendingDelete, setPendingDelete] = (0, react.useState)();
4493
4497
  const load = (0, react.useCallback)(() => {
4494
4498
  api("fs.list", {
4495
4499
  sessionId,
@@ -4502,72 +4506,223 @@ Please report this to https://github.com/markedjs/marked.`, e) {
4502
4506
  window.addEventListener("dvw-files-changed", handler);
4503
4507
  return () => window.removeEventListener("dvw-files-changed", handler);
4504
4508
  }, [load]);
4505
- const menu = async (entry) => {
4506
- const action = prompt(`操作 ${entry.name}: rename / delete / new-file / new-folder`);
4509
+ (0, react.useEffect)(() => {
4510
+ if (context === void 0) return;
4511
+ const close = () => setContext(void 0);
4512
+ const escape = (event) => {
4513
+ if (event.key === "Escape") close();
4514
+ };
4515
+ window.addEventListener("pointerdown", close);
4516
+ window.addEventListener("keydown", escape);
4517
+ return () => {
4518
+ window.removeEventListener("pointerdown", close);
4519
+ window.removeEventListener("keydown", escape);
4520
+ };
4521
+ }, [context]);
4522
+ (0, react.useEffect)(() => {
4523
+ if (pendingDelete === void 0) return;
4524
+ const escape = (event) => {
4525
+ if (event.key === "Escape") setPendingDelete(void 0);
4526
+ };
4527
+ window.addEventListener("keydown", escape);
4528
+ return () => window.removeEventListener("keydown", escape);
4529
+ }, [pendingDelete]);
4530
+ const rename = async (entry) => {
4531
+ const value = renaming?.path === entry.path ? renaming.value.trim() : "";
4532
+ setRenaming(void 0);
4533
+ if (value === "" || value === entry.name) return;
4507
4534
  try {
4508
- if (action === "rename") {
4509
- const name = prompt("新名称", entry.name);
4510
- if (name) await api("fs.rename", {
4511
- sessionId,
4512
- path: entry.path,
4513
- nextPath: [...entry.path.split("/").slice(0, -1), name].filter(Boolean).join("/")
4514
- });
4515
- }
4516
- if (action === "delete" && confirm(`确定删除 ${entry.path}?`)) await api("fs.delete", {
4535
+ await api("fs.rename", {
4536
+ sessionId,
4537
+ path: entry.path,
4538
+ nextPath: renamedPath(entry.path, value)
4539
+ });
4540
+ load();
4541
+ onChange();
4542
+ } catch (error) {
4543
+ alert(error instanceof Error ? error.message : String(error));
4544
+ }
4545
+ };
4546
+ const remove = async () => {
4547
+ if (pendingDelete === void 0) return;
4548
+ const entry = pendingDelete;
4549
+ setPendingDelete(void 0);
4550
+ try {
4551
+ await api("fs.delete", {
4517
4552
  sessionId,
4518
4553
  path: entry.path
4519
4554
  });
4520
- if (action === "new-file" || action === "new-folder") {
4521
- const name = prompt("名称");
4522
- if (name) await api("fs.create", {
4523
- sessionId,
4524
- path: `${entry.kind === "directory" ? entry.path : entry.path.split("/").slice(0, -1).join("/")}/${name}`.replace(/^\//, ""),
4525
- kind: action === "new-folder" ? "directory" : "file"
4526
- });
4527
- }
4528
4555
  load();
4529
4556
  onChange();
4530
4557
  } catch (error) {
4531
4558
  alert(error instanceof Error ? error.message : String(error));
4532
4559
  }
4533
4560
  };
4534
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4535
- className: "dvw-error",
4536
- children: error
4537
- }), rows.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4538
- className: "dvw-tree-row",
4539
- "data-selected": selected === row.path,
4540
- style: { paddingLeft: 6 + depth * 13 },
4541
- onClick: () => row.kind === "directory" ? onToggle(row.path) : onOpen(row.path),
4542
- onContextMenu: (event) => {
4543
- event.preventDefault();
4544
- menu(row);
4545
- },
4546
- children: [
4547
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4548
- className: "dvw-chevron",
4549
- children: row.kind === "directory" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: expanded.has(row.path) ? "chevron-down" : "chevron-right" })
4550
- }),
4551
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
4552
- name: row.kind === "directory" ? expanded.has(row.path) ? "folder-opened" : "folder" : fileIcon(row.name),
4553
- className: `dvw-file-icon ${row.kind === "directory" ? "folder" : ""}`
4554
- }),
4555
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: row.name })
4556
- ]
4557
- }), row.kind === "directory" && expanded.has(row.path) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tree, {
4558
- sessionId,
4559
- path: row.path,
4560
- depth: depth + 1,
4561
- expanded,
4562
- selected,
4563
- onToggle,
4564
- onOpen,
4565
- onChange
4566
- })] }, row.path))] });
4561
+ const drop = (event, directory) => {
4562
+ event.preventDefault();
4563
+ event.stopPropagation();
4564
+ setDropTarget(false);
4565
+ if (event.dataTransfer.files.length > 0) onUpload(directory, event.dataTransfer.files);
4566
+ };
4567
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
4568
+ error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4569
+ className: "dvw-error",
4570
+ children: error
4571
+ }),
4572
+ rows.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4573
+ className: "dvw-tree-row",
4574
+ "data-dvw-upload-directory": row.kind === "directory" ? row.path : void 0,
4575
+ "data-selected": selected === row.path || selectedDirectory === row.path,
4576
+ "data-drop-target": dropTarget && row.kind === "directory",
4577
+ style: { paddingLeft: 6 + depth * 13 },
4578
+ onClick: () => row.kind === "directory" ? (onSelectDirectory(row.path), onToggle(row.path)) : onOpen(row.path),
4579
+ onContextMenu: (event) => {
4580
+ event.preventDefault();
4581
+ if (row.kind === "directory") onSelectDirectory(row.path);
4582
+ setContext({
4583
+ entry: row,
4584
+ x: event.clientX,
4585
+ y: event.clientY
4586
+ });
4587
+ },
4588
+ onDragEnter: (event) => {
4589
+ if (row.kind === "directory" && event.dataTransfer.types.includes("Files")) {
4590
+ event.preventDefault();
4591
+ event.stopPropagation();
4592
+ setDropTarget(true);
4593
+ }
4594
+ },
4595
+ onDragOver: (event) => {
4596
+ if (row.kind === "directory" && event.dataTransfer.types.includes("Files")) {
4597
+ event.preventDefault();
4598
+ event.stopPropagation();
4599
+ setDropTarget(true);
4600
+ }
4601
+ },
4602
+ onDragLeave: () => setDropTarget(false),
4603
+ onDrop: (event) => row.kind === "directory" && drop(event, row.path),
4604
+ children: [
4605
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4606
+ className: "dvw-chevron",
4607
+ children: row.kind === "directory" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: expanded.has(row.path) ? "chevron-down" : "chevron-right" })
4608
+ }),
4609
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
4610
+ name: row.kind === "directory" ? expanded.has(row.path) ? "folder-opened" : "folder" : fileIcon(row.name),
4611
+ className: `dvw-file-icon ${row.kind === "directory" ? "folder" : ""}`
4612
+ }),
4613
+ renaming?.path === row.path ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
4614
+ className: "dvw-tree-rename",
4615
+ value: renaming.value,
4616
+ autoFocus: true,
4617
+ onClick: (event) => event.stopPropagation(),
4618
+ onChange: (event) => setRenaming({
4619
+ path: row.path,
4620
+ value: event.target.value
4621
+ }),
4622
+ onKeyDown: (event) => {
4623
+ if (event.key === "Enter") rename(row);
4624
+ if (event.key === "Escape") setRenaming(void 0);
4625
+ },
4626
+ onBlur: () => setRenaming(void 0)
4627
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4628
+ className: "dvw-tree-name",
4629
+ children: row.name
4630
+ }),
4631
+ row.kind === "file" && statuses.has(row.path) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4632
+ className: "dvw-tree-status",
4633
+ "data-status": statuses.get(row.path),
4634
+ children: statuses.get(row.path)
4635
+ })
4636
+ ]
4637
+ }), row.kind === "directory" && expanded.has(row.path) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tree, {
4638
+ sessionId,
4639
+ path: row.path,
4640
+ depth: depth + 1,
4641
+ expanded,
4642
+ selected,
4643
+ selectedDirectory,
4644
+ statuses,
4645
+ onToggle,
4646
+ onSelectDirectory,
4647
+ onOpen,
4648
+ onChange,
4649
+ onUpload
4650
+ })] }, row.path)),
4651
+ context && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4652
+ className: "dvw-context-menu",
4653
+ role: "menu",
4654
+ style: {
4655
+ left: context.x,
4656
+ top: context.y
4657
+ },
4658
+ onPointerDown: (event) => event.stopPropagation(),
4659
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
4660
+ role: "menuitem",
4661
+ onClick: () => {
4662
+ setRenaming({
4663
+ path: context.entry.path,
4664
+ value: context.entry.name
4665
+ });
4666
+ setContext(void 0);
4667
+ },
4668
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "edit" }), "重命名"]
4669
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
4670
+ className: "dvw-context-delete",
4671
+ role: "menuitem",
4672
+ onClick: () => {
4673
+ setPendingDelete(context.entry);
4674
+ setContext(void 0);
4675
+ },
4676
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "trash" }), "删除"]
4677
+ })]
4678
+ }),
4679
+ pendingDelete && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4680
+ className: "dvw-confirm-backdrop",
4681
+ role: "presentation",
4682
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
4683
+ className: "dvw-confirm",
4684
+ role: "alertdialog",
4685
+ "aria-modal": "true",
4686
+ "aria-labelledby": "dvw-delete-title",
4687
+ "aria-describedby": "dvw-delete-message",
4688
+ children: [
4689
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h2", {
4690
+ id: "dvw-delete-title",
4691
+ children: ["删除 ", pendingDelete.kind === "directory" ? "文件夹" : "文件"]
4692
+ }),
4693
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
4694
+ id: "dvw-delete-message",
4695
+ children: [
4696
+ "是否删除“",
4697
+ pendingDelete.name,
4698
+ "”?"
4699
+ ]
4700
+ }),
4701
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4702
+ className: "dvw-confirm-note",
4703
+ children: "此操作无法撤销。"
4704
+ }),
4705
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4706
+ autoFocus: true,
4707
+ onClick: () => setPendingDelete(void 0),
4708
+ children: "取消"
4709
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4710
+ className: "dvw-danger-button",
4711
+ onClick: () => void remove(),
4712
+ children: "删除"
4713
+ })] })
4714
+ ]
4715
+ })
4716
+ })
4717
+ ] });
4567
4718
  }
4568
4719
  function Explorer(props) {
4569
4720
  const [expanded, setExpanded] = (0, react.useState)(/* @__PURE__ */ new Set());
4570
4721
  const [revision, setRevision] = (0, react.useState)(0);
4722
+ const [statuses, setStatuses] = (0, react.useState)(/* @__PURE__ */ new Map());
4723
+ const [dropTarget, setDropTarget] = (0, react.useState)(false);
4724
+ const [selectedDirectory, setSelectedDirectory] = (0, react.useState)("");
4725
+ const picker = (0, react.useRef)(null);
4571
4726
  (0, react.useEffect)(() => {
4572
4727
  if (props.cwd) try {
4573
4728
  setExpanded(new Set(JSON.parse(localStorage.getItem(`dvw:tree:${props.cwd}`) ?? "[]")));
@@ -4578,6 +4733,15 @@ Please report this to https://github.com/markedjs/marked.`, e) {
4578
4733
  (0, react.useEffect)(() => {
4579
4734
  if (props.cwd) localStorage.setItem(`dvw:tree:${props.cwd}`, JSON.stringify([...expanded]));
4580
4735
  }, [props.cwd, expanded]);
4736
+ const refreshStatus = (0, react.useCallback)(() => {
4737
+ api("git.status", { sessionId: props.sessionId }).then((status) => setStatuses(new Map(status.changes.map((change) => [change.path, gitStatusCode(change)])))).catch(() => setStatuses(/* @__PURE__ */ new Map()));
4738
+ }, [props.sessionId]);
4739
+ (0, react.useEffect)(() => {
4740
+ refreshStatus();
4741
+ const handler = () => refreshStatus();
4742
+ window.addEventListener("dvw-files-changed", handler);
4743
+ return () => window.removeEventListener("dvw-files-changed", handler);
4744
+ }, [refreshStatus]);
4581
4745
  const create = async (kind) => {
4582
4746
  const path = prompt(kind === "file" ? "新文件路径" : "新目录路径");
4583
4747
  if (!path) return;
@@ -4593,11 +4757,111 @@ Please report this to https://github.com/markedjs/marked.`, e) {
4593
4757
  alert(String(error));
4594
4758
  }
4595
4759
  };
4760
+ const upload = (0, react.useCallback)(async (directory, files) => {
4761
+ try {
4762
+ await Promise.all([...files].map(async (file) => {
4763
+ const query = new URLSearchParams({
4764
+ sessionId: props.sessionId,
4765
+ directory,
4766
+ name: file.name
4767
+ });
4768
+ const response = await fetch(`/dsh-vscode/upload?${query}`, {
4769
+ method: "POST",
4770
+ headers: { "content-type": file.type || "application/octet-stream" },
4771
+ body: file
4772
+ });
4773
+ const answer = await response.json();
4774
+ if (!response.ok || !answer.ok) throw new Error(answer.error?.message ?? "upload failed");
4775
+ }));
4776
+ setRevision((value) => value + 1);
4777
+ window.dispatchEvent(new Event("dvw-files-changed"));
4778
+ } catch (error) {
4779
+ alert(error instanceof Error ? error.message : String(error));
4780
+ }
4781
+ }, [props.sessionId]);
4782
+ (0, react.useEffect)(() => {
4783
+ let activeTarget;
4784
+ const filesDragged = (event) => Array.from(event.dataTransfer?.types ?? []).includes("Files");
4785
+ const targetDirectory = (event) => event.target instanceof Element ? event.target.closest("[data-dvw-upload-directory]") : null;
4786
+ const clearTarget = () => {
4787
+ activeTarget?.removeAttribute("data-dvw-native-drop-target");
4788
+ activeTarget = void 0;
4789
+ };
4790
+ const intercept = (event) => {
4791
+ if (!filesDragged(event)) return;
4792
+ const target = targetDirectory(event);
4793
+ if (!target) return;
4794
+ event.preventDefault();
4795
+ event.stopImmediatePropagation();
4796
+ if (event.type === "dragleave") {
4797
+ if (!(event.relatedTarget instanceof Node && target.contains(event.relatedTarget))) clearTarget();
4798
+ return;
4799
+ }
4800
+ clearTarget();
4801
+ activeTarget = target;
4802
+ target.dataset.dvwNativeDropTarget = "true";
4803
+ if (event.type === "drop" && event.dataTransfer?.files.length) {
4804
+ const files = event.dataTransfer.files;
4805
+ clearTarget();
4806
+ window.dispatchEvent(new CustomEvent("dvw-upload-files", { detail: {
4807
+ directory: target.dataset.dvwUploadDirectory ?? "",
4808
+ files
4809
+ } }));
4810
+ }
4811
+ };
4812
+ document.addEventListener("dragenter", intercept, true);
4813
+ document.addEventListener("dragover", intercept, true);
4814
+ document.addEventListener("dragleave", intercept, true);
4815
+ document.addEventListener("drop", intercept, true);
4816
+ const uploadFiles = (event) => {
4817
+ const detail = event.detail;
4818
+ if (detail?.files?.length) upload(detail.directory, detail.files);
4819
+ };
4820
+ window.addEventListener("dvw-upload-files", uploadFiles);
4821
+ return () => {
4822
+ clearTarget();
4823
+ document.removeEventListener("dragenter", intercept, true);
4824
+ document.removeEventListener("dragover", intercept, true);
4825
+ document.removeEventListener("dragleave", intercept, true);
4826
+ document.removeEventListener("drop", intercept, true);
4827
+ window.removeEventListener("dvw-upload-files", uploadFiles);
4828
+ };
4829
+ }, [upload]);
4830
+ const drop = (event) => {
4831
+ event.preventDefault();
4832
+ setDropTarget(false);
4833
+ if (event.dataTransfer.files.length > 0) upload("", event.dataTransfer.files);
4834
+ };
4835
+ const destination = uploadDestination(selectedDirectory);
4836
+ const treeDrag = (event) => {
4837
+ if (event.dataTransfer.types.includes("Files")) {
4838
+ event.preventDefault();
4839
+ event.stopPropagation();
4840
+ setDropTarget(true);
4841
+ }
4842
+ };
4596
4843
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4597
4844
  className: "dvw-side-head",
4598
4845
  children: ["资源管理器", /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4599
4846
  className: "dvw-toolbar",
4600
4847
  children: [
4848
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
4849
+ ref: picker,
4850
+ className: "dvw-file-picker",
4851
+ type: "file",
4852
+ accept: "*/*",
4853
+ multiple: true,
4854
+ onChange: (event) => {
4855
+ if (event.currentTarget.files) upload(destination, event.currentTarget.files);
4856
+ event.currentTarget.value = "";
4857
+ }
4858
+ }),
4859
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4860
+ className: "dvw-icon",
4861
+ title: `上传文件到 ${destination || "工作区根目录"}`,
4862
+ onClick: () => picker.current?.click(),
4863
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "cloud-upload" })
4864
+ }),
4601
4865
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4602
4866
  className: "dvw-icon",
4603
4867
  title: "新建文件",
@@ -4623,22 +4887,45 @@ Please report this to https://github.com/markedjs/marked.`, e) {
4623
4887
  })]
4624
4888
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4625
4889
  className: "dvw-tree",
4890
+ "data-dvw-upload-directory": "",
4891
+ "data-drop-target": dropTarget,
4892
+ onDragEnter: treeDrag,
4893
+ onDragOver: treeDrag,
4894
+ onDragLeave: () => setDropTarget(false),
4895
+ onDrop: drop,
4626
4896
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tree, {
4627
4897
  sessionId: props.sessionId,
4628
4898
  path: "",
4629
4899
  depth: 0,
4630
4900
  expanded,
4631
4901
  selected: props.selected,
4902
+ selectedDirectory,
4903
+ statuses,
4632
4904
  onToggle: (path) => setExpanded((current) => {
4633
4905
  const next = new Set(current);
4634
4906
  next.has(path) ? next.delete(path) : next.add(path);
4635
4907
  return next;
4636
4908
  }),
4909
+ onSelectDirectory: setSelectedDirectory,
4637
4910
  onOpen: props.onOpen,
4638
- onChange: () => setRevision((x) => x + 1)
4911
+ onChange: () => setRevision((x) => x + 1),
4912
+ onUpload: (directory, files) => void upload(directory, files)
4639
4913
  })
4640
4914
  }, revision)] });
4641
4915
  }
4916
+ /** Return the workspace-relative directory used by the file picker. */
4917
+ function uploadDestination(selectedDirectory) {
4918
+ return selectedDirectory ?? "";
4919
+ }
4920
+ /** Replace the final path component while preserving its workspace-relative directory. */
4921
+ function renamedPath(path, name) {
4922
+ return [...path.split("/").slice(0, -1), name].filter(Boolean).join("/");
4923
+ }
4924
+ function gitStatusCode(change) {
4925
+ if (change.untracked) return "A";
4926
+ const code = change.worktree !== "." ? change.worktree : change.index;
4927
+ return code === "?" ? "A" : code;
4928
+ }
4642
4929
  function MarkdownOutline({ headings, onClose, onHeading }) {
4643
4930
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
4644
4931
  className: "dvw-outline dvw-editor-outline",
@@ -5267,15 +5554,12 @@ Please report this to https://github.com/markedjs/marked.`, e) {
5267
5554
  ] })
5268
5555
  ] });
5269
5556
  }
5270
- function Launcher({ wide, service }) {
5271
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
5557
+ function Launcher({ service }) {
5558
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5272
5559
  className: "dvw-launch",
5273
5560
  title: "打开 VS Code 工作台",
5274
5561
  onClick: () => service.show(),
5275
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
5276
- name: "files",
5277
- className: "dvw-launch-icon"
5278
- }), wide && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "VS Code 工作台" })]
5562
+ children: "VS Code 工作台"
5279
5563
  });
5280
5564
  }
5281
5565
  function Workbench({ service, useSessions }) {
@@ -5489,6 +5773,14 @@ Please report this to https://github.com/markedjs/marked.`, e) {
5489
5773
  } : tab));
5490
5774
  window.setTimeout(() => window.dispatchEvent(new CustomEvent("dvw-markdown-heading", { detail: index })), 50);
5491
5775
  };
5776
+ const suppressAttachmentDrop = (event) => {
5777
+ if (!event.dataTransfer.types.includes("Files")) return;
5778
+ const target = event.target;
5779
+ if (!(target instanceof Element && target.closest(".dvw-tree") !== null)) {
5780
+ event.preventDefault();
5781
+ event.stopPropagation();
5782
+ }
5783
+ };
5492
5784
  if (!snapshot.visible) return null;
5493
5785
  if (sessionId === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5494
5786
  className: "dvw-overlay",
@@ -5522,6 +5814,9 @@ Please report this to https://github.com/markedjs/marked.`, e) {
5522
5814
  },
5523
5815
  role: "dialog",
5524
5816
  "aria-label": "VS Code 工作台",
5817
+ onDragEnterCapture: suppressAttachmentDrop,
5818
+ onDragOverCapture: suppressAttachmentDrop,
5819
+ onDropCapture: suppressAttachmentDrop,
5525
5820
  children: [
5526
5821
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DshConversationPanel, {
5527
5822
  visible: chatVisible && !settingsOpen,
@@ -5999,20 +6294,20 @@ Please report this to https://github.com/markedjs/marked.`, e) {
5999
6294
  const CSS = String.raw`
6000
6295
  @font-face{font-family:codicon;font-display:block;src:url('/dsh-vscode/codicons/codicon.ttf') format('truetype')}
6001
6296
  .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}
6002
- .codicon-add:before{content:"\ea60"}.codicon-git-branch:before,.codicon-source-control:before{content:"\ea68"}.codicon-search:before{content:"\ea6d"}.codicon-close:before{content:"\ea76"}.codicon-close-all:before{content:"\eac1"}.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"}
6297
+ .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"}
6003
6298
  .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"}
6004
- .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-launch-icon{width:22px;font-size:19px}
6299
+ .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}}
6005
6300
  .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}
6006
6301
  body[data-ds-dark-theme] .dvw-overlay,.dvw-overlay[data-dvw-theme=dark]{color-scheme:dark}
6007
6302
  .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}
6008
6303
  .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}
6009
- .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:7px;height:100%;z-index:4;cursor:ew-resize;transform:translateX(3px);touch-action:none}.dvw-side-resizer:hover,.dvw-side-resizer:active{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-tree,.dvw-results,.dvw-git{overflow:auto;flex:1}.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]{background:var(--dvw-active)}.dvw-chevron{width:16px;text-align:center;color:var(--dvw-text-3)}.dvw-file-icon{width:18px;color:var(--dvw-text-2)}.dvw-file-icon.folder{color:var(--dvw-accent)}
6304
+ .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:7px;height:100%;z-index:4;cursor:ew-resize;transform:translateX(3px);touch-action:none}.dvw-side-resizer:hover,.dvw-side-resizer:active{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;text-align:center;color:var(--dvw-text-3)}.dvw-file-icon{width:18px;color:var(--dvw-text-2)}.dvw-file-icon.folder{color:var(--dvw-accent)}.dvw-tree-name{overflow:hidden;text-overflow:ellipsis}.dvw-tree-rename{min-width:0;flex:1;height:20px;border:1px solid var(--dvw-accent);background:var(--dvw-surface-1);color:var(--dvw-text);font:inherit;outline:0}.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)}
6010
6305
  .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)}
6011
6306
  .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}
6012
6307
  .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}
6013
6308
  .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)}
6014
6309
  .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}
6015
- .dvw-sidebar-launcher-mount{flex:none;padding:4px 8px 6px;border-bottom:1px solid var(--dvw-border-soft)}.dvw-sidebar-launcher-mount .dvw-launch{color:var(--dsw-alias-label-primary,#333)}body[data-ds-dark-theme] .dvw-sidebar-launcher-mount .dvw-launch{color:var(--dsw-alias-label-primary,#ddd)}.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}
6310
+ .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}
6016
6311
  .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)}
6017
6312
  .dvw-sidebar-launcher-mount{border-bottom:1px solid var(--dsw-alias-border-l3,#e5e7eb)}.dvw-outline-toggle{margin-right:auto}.dvw-outline-toggle[data-active=true]{background:var(--dvw-active);color:var(--dvw-text)}.dvw-editor-outline{position:absolute;z-index:2;top:36px;bottom:0;left:0;width:240px;max-height:none;background:var(--dvw-surface-1);border-right:1px solid var(--dvw-border);border-bottom:0}.dvw-editor[data-outline=true] .dvw-editor-body{left:240px}.dvw-diff-preview-switch{margin-right:auto;display:flex;gap:4px}.dvw-commit-files{position:relative;padding-top:1px;padding-right:0;padding-bottom:5px}.dvw-graph-continuation{position:absolute;top:0;bottom:0;left:7px;height:100%;pointer-events:none}.dvw-commit-file-list{position:relative;min-width:0}.dvw-overlay button:focus-visible,.dvw-overlay input:focus-visible,.dvw-overlay select:focus-visible{outline:1px solid var(--dvw-accent);outline-offset:-1px}@media(max-width:800px){.dvw-overlay{grid-template-columns:44px var(--dvw-side-width) minmax(0,1fr)}.dvw-editor-outline{width:210px}.dvw-editor[data-outline=true] .dvw-editor-body{left:210px}}
6018
6313
  .dvw-overlay[data-dvw-chat=true]{grid-template-columns:48px var(--dvw-side-width) minmax(0,1fr) var(--dvw-chat-width)}
@@ -6030,6 +6325,8 @@ body[data-ds-dark-theme] .dvw-overlay,.dvw-overlay[data-dvw-theme=dark]{color-sc
6030
6325
  .dvw-chat-toggle{position:absolute;z-index:5;top:6px;right:6px;border:1px solid var(--dvw-border);background:var(--dvw-base)}
6031
6326
  .dvw-overlay:not([data-dvw-chat=true]) .dvw-tabs{padding-right:36px}
6032
6327
  [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}
6328
+ .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)}
6329
+ .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)}
6033
6330
  .dvw-settings-backdrop{position:absolute;inset:0;z-index:30;display:grid;place-items:center;padding:24px;background:rgba(0,0,0,.34);backdrop-filter:blur(2px)}
6034
6331
  .dvw-settings{width:min(720px,calc(100vw - 48px));max-height:min(720px,calc(100vh - 48px));display:flex;flex-direction:column;border:1px solid var(--dvw-border);border-radius:10px;background:var(--dvw-surface-1);box-shadow:0 16px 50px rgba(0,0,0,.32);overflow:hidden}
6035
6332
  .dvw-settings>header{height:44px;flex:none;display:flex;align-items:center;justify-content:space-between;padding:0 10px 0 14px;border-bottom:1px solid var(--dvw-border);font-size:14px;font-weight:600}.dvw-settings>header>span{display:flex;align-items:center;gap:8px}
@@ -6075,33 +6372,18 @@ body[data-ds-dark-theme] .dvw-overlay,.dvw-overlay[data-dvw-theme=dark]{color-sc
6075
6372
  useSessions
6076
6373
  }, sessionId ?? "no-session");
6077
6374
  };
6078
- const Footer = ({ service, wide }) => {
6079
- const marker = (0, react.useRef)(null);
6375
+ const Footer = ({ service }) => {
6080
6376
  const [target, setTarget] = (0, react.useState)();
6377
+ const [visible, setVisible] = (0, react.useState)(() => service.getSnapshot().visible);
6081
6378
  (0, react.useLayoutEffect)(() => {
6082
- let container = marker.current?.parentElement;
6083
- while (container?.previousElementSibling === null) container = container.parentElement;
6084
- const region = container?.previousElementSibling;
6085
- if (!(region instanceof HTMLElement)) {
6086
- setTarget(null);
6087
- return;
6088
- }
6089
6379
  const mount = document.createElement("div");
6090
- mount.className = "dvw-sidebar-launcher-mount";
6091
- region.prepend(mount);
6380
+ mount.className = "dvw-launcher-mount";
6381
+ document.body.append(mount);
6092
6382
  setTarget(mount);
6093
6383
  return () => mount.remove();
6094
6384
  }, []);
6095
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6096
- ref: marker,
6097
- hidden: true
6098
- }), target === void 0 ? null : target === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Launcher, {
6099
- service,
6100
- wide
6101
- }) : (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Launcher, {
6102
- service,
6103
- wide
6104
- }), target)] });
6385
+ (0, react.useEffect)(() => service.subscribe(() => setVisible(service.getSnapshot().visible)), [service]);
6386
+ return target === void 0 || visible ? null : (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Launcher, { service }), target);
6105
6387
  };
6106
6388
  const inject = ["slots"];
6107
6389
  function apply(ctx) {