@blade-hq/agent-kit 0.4.21 → 0.5.0

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.
@@ -3,7 +3,7 @@ import {
3
3
  CollapsibleContent,
4
4
  CollapsibleTrigger,
5
5
  resolveSessionFilePreviewTarget
6
- } from "../../../chunk-47YVQZQ7.js";
6
+ } from "../../../chunk-CFZDKYT3.js";
7
7
  import {
8
8
  apiFetchText,
9
9
  copyFile,
@@ -17,7 +17,7 @@ import {
17
17
  useChatStore,
18
18
  useSessionStore,
19
19
  useUiStore
20
- } from "../../../chunk-LKNU4NUC.js";
20
+ } from "../../../chunk-C7VSMOXN.js";
21
21
  import "../../../chunk-J3XVFPOV.js";
22
22
  import "../../../chunk-ROGNJYST.js";
23
23
  import {
@@ -277,7 +277,7 @@ var GENERIC_FILE_ICON_ASSET = new URL("../../assets/file-icons/generic-file.png"
277
277
  // src/react/components/workspace/FileTree.tsx
278
278
  import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
279
279
  var ROOT_PATH = ".";
280
- var TREE_ROW_CLASS = "group flex w-full items-center gap-1 rounded px-2 py-1 text-left transition-colors hover:bg-muted/50";
280
+ var TREE_ROW_CLASS = "group flex w-full items-center gap-1.5 rounded-md px-2 py-1.5 text-left transition-colors hover:bg-muted/50";
281
281
  function FileTree2({
282
282
  sessionId,
283
283
  checkActiveSession = true,
@@ -473,6 +473,7 @@ function FolderNode({
473
473
  const queryClient = useQueryClient();
474
474
  const isExpanded = expandedDirs.has(entry.path);
475
475
  const isSelected = selectedPath === entry.path;
476
+ const isCurrentSessionDir = entry.name === sessionId;
476
477
  const renameInputRef = useRef(null);
477
478
  const [isRenaming, setIsRenaming] = useState2(false);
478
479
  const [renamingValue, setRenamingValue] = useState2(entry.name);
@@ -549,7 +550,7 @@ function FolderNode({
549
550
  ChevronRight,
550
551
  {
551
552
  className: cn(
552
- "size-4 shrink-0 text-[hsl(var(--muted-foreground))] transition-transform",
553
+ "size-5 shrink-0 text-[hsl(var(--muted-foreground))] transition-transform",
553
554
  isExpanded && "rotate-90"
554
555
  )
555
556
  }
@@ -591,7 +592,8 @@ function FolderNode({
591
592
  },
592
593
  children: [
593
594
  /* @__PURE__ */ jsx2(FileTreeIcon, { children: getFolderIcon() }),
594
- /* @__PURE__ */ jsx2(FileTreeName, { className: "min-w-0 flex-1", children: entry.name })
595
+ /* @__PURE__ */ jsx2(FileTreeName, { className: "min-w-0 flex-1", children: entry.name }),
596
+ isCurrentSessionDir ? /* @__PURE__ */ jsx2("span", { className: "shrink-0 rounded-full bg-emerald-100 px-2 py-[2px] text-[11px] font-medium leading-[14px] text-emerald-700", children: "\u5F53\u524D\u5BF9\u8BDD" }) : null
595
597
  ]
596
598
  }
597
599
  ),
@@ -631,12 +633,11 @@ function FolderNode({
631
633
  children: activeAction === "copy" ? /* @__PURE__ */ jsx2(Loader2, { size: 12, className: "animate-spin" }) : /* @__PURE__ */ jsx2(Copy, { size: 12 })
632
634
  }
633
635
  ),
634
- /* @__PURE__ */ jsx2(
636
+ onShareFile ? /* @__PURE__ */ jsx2(
635
637
  TreeActionButton,
636
638
  {
637
- disabled: activeAction !== null || !onShareFile,
639
+ disabled: activeAction !== null,
638
640
  onClick: async () => {
639
- if (!onShareFile) return;
640
641
  setActiveAction("share");
641
642
  try {
642
643
  await onShareFile(entry.path, entry.name);
@@ -647,10 +648,10 @@ function FolderNode({
647
648
  setActiveAction(null);
648
649
  }
649
650
  },
650
- title: "\u5171\u4EAB\u5230 .share",
651
+ title: "\u5171\u4EAB\u5230\u4EA7\u7269\u533A",
651
652
  children: activeAction === "share" ? /* @__PURE__ */ jsx2(Loader2, { size: 12, className: "animate-spin" }) : /* @__PURE__ */ jsx2(Link2, { size: 12 })
652
653
  }
653
- ),
654
+ ) : null,
654
655
  /* @__PURE__ */ jsx2(
655
656
  TreeActionButton,
656
657
  {
@@ -773,120 +774,130 @@ function FileNode({
773
774
  setActiveAction(null);
774
775
  }
775
776
  };
776
- return /* @__PURE__ */ jsxs2("div", { className: cn(TREE_ROW_CLASS, isSelected && "bg-muted"), children: [
777
- /* @__PURE__ */ jsx2("span", { className: "size-4 shrink-0" }),
778
- /* @__PURE__ */ jsx2(FileTreeIcon, { children: getFileIcon(entry.name) }),
779
- isRenaming ? /* @__PURE__ */ jsx2(
780
- "input",
781
- {
782
- ref: renameInputRef,
783
- value: renamingValue,
784
- className: "h-6 min-w-0 flex-1 rounded border border-[hsl(var(--border))] bg-background px-2 text-xs outline-none ring-offset-background focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))]",
785
- disabled: activeAction === "rename",
786
- onBlur: () => void finishRename(),
787
- onChange: (event) => setRenamingValue(event.target.value),
788
- onClick: (event) => event.stopPropagation(),
789
- onKeyDown: (event) => {
790
- event.stopPropagation();
791
- if (event.key === "Enter") {
792
- event.preventDefault();
793
- void finishRename();
794
- } else if (event.key === "Escape") {
795
- event.preventDefault();
796
- cancelRename();
777
+ return /* @__PURE__ */ jsxs2(
778
+ "div",
779
+ {
780
+ className: cn(TREE_ROW_CLASS, isSelected && "bg-muted"),
781
+ draggable: !isRenaming,
782
+ onDragStart: (e) => {
783
+ e.dataTransfer.setData("application/blade-file-ref", JSON.stringify({ path: entry.path, name: entry.name }));
784
+ e.dataTransfer.effectAllowed = "copy";
785
+ },
786
+ children: [
787
+ /* @__PURE__ */ jsx2("span", { className: "size-5 shrink-0" }),
788
+ /* @__PURE__ */ jsx2(FileTreeIcon, { children: getFileIcon(entry.name) }),
789
+ isRenaming ? /* @__PURE__ */ jsx2(
790
+ "input",
791
+ {
792
+ ref: renameInputRef,
793
+ value: renamingValue,
794
+ className: "h-6 min-w-0 flex-1 rounded border border-[hsl(var(--border))] bg-background px-2 text-xs outline-none ring-offset-background focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))]",
795
+ disabled: activeAction === "rename",
796
+ onBlur: () => void finishRename(),
797
+ onChange: (event) => setRenamingValue(event.target.value),
798
+ onClick: (event) => event.stopPropagation(),
799
+ onKeyDown: (event) => {
800
+ event.stopPropagation();
801
+ if (event.key === "Enter") {
802
+ event.preventDefault();
803
+ void finishRename();
804
+ } else if (event.key === "Escape") {
805
+ event.preventDefault();
806
+ cancelRename();
807
+ }
808
+ }
797
809
  }
798
- }
799
- }
800
- ) : /* @__PURE__ */ jsxs2(
801
- "button",
802
- {
803
- type: "button",
804
- className: "flex min-w-0 flex-1 cursor-pointer items-center border-none bg-transparent p-0 text-left",
805
- onClick: () => {
806
- onSelectPath(entry.path);
807
- void onOpenFile(entry.path, entry.name);
808
- },
809
- children: [
810
- /* @__PURE__ */ jsx2(FileTreeName, { className: "min-w-0 flex-1", children: entry.name }),
811
- /* @__PURE__ */ jsx2(FileTagList, { tags: entry.tags })
812
- ]
813
- }
814
- ),
815
- isOpening ? /* @__PURE__ */ jsx2(Loader2, { size: 12, className: "ml-auto shrink-0 animate-spin text-[hsl(var(--muted-foreground))]" }) : !readOnly ? /* @__PURE__ */ jsxs2(FileTreeActions, { className: "ml-auto hidden shrink-0 group-hover:flex", children: [
816
- /* @__PURE__ */ jsx2(
817
- TreeActionButton,
818
- {
819
- onClick: () => {
820
- const anchor = document.createElement("a");
821
- anchor.href = downloadUrl;
822
- anchor.download = entry.name;
823
- anchor.click();
824
- },
825
- title: "\u4E0B\u8F7D\u6587\u4EF6",
826
- children: /* @__PURE__ */ jsx2(Download, { size: 12 })
827
- }
828
- ),
829
- /* @__PURE__ */ jsx2(
830
- TreeActionButton,
831
- {
832
- disabled: activeAction !== null,
833
- onClick: () => {
834
- onSelectPath(entry.path);
835
- setRenamingValue(entry.name);
836
- setIsRenaming(true);
837
- },
838
- title: "\u91CD\u547D\u540D",
839
- children: activeAction === "rename" ? /* @__PURE__ */ jsx2(Loader2, { size: 12, className: "animate-spin" }) : /* @__PURE__ */ jsx2(Pencil, { size: 12 })
840
- }
841
- ),
842
- /* @__PURE__ */ jsx2(
843
- TreeActionButton,
844
- {
845
- disabled: activeAction !== null,
846
- onClick: () => void handleCopy(),
847
- title: "\u590D\u5236\u6587\u4EF6",
848
- children: activeAction === "copy" ? /* @__PURE__ */ jsx2(Loader2, { size: 12, className: "animate-spin" }) : /* @__PURE__ */ jsx2(Copy, { size: 12 })
849
- }
850
- ),
851
- /* @__PURE__ */ jsx2(
852
- TreeActionButton,
853
- {
854
- disabled: activeAction !== null || !onShareFile,
855
- onClick: async () => {
856
- if (!onShareFile) return;
857
- setActiveAction("share");
858
- try {
859
- await onShareFile(entry.path, entry.name);
860
- await queryClient.invalidateQueries({ queryKey: ["file-tree", sessionId] });
861
- } catch (error) {
862
- alert(getErrorMessage(error, "\u5171\u4EAB\u5931\u8D25"));
863
- } finally {
864
- setActiveAction(null);
810
+ ) : /* @__PURE__ */ jsxs2(
811
+ "button",
812
+ {
813
+ type: "button",
814
+ className: "flex min-w-0 flex-1 cursor-pointer items-center border-none bg-transparent p-0 text-left",
815
+ onClick: () => {
816
+ onSelectPath(entry.path);
817
+ void onOpenFile(entry.path, entry.name);
818
+ },
819
+ children: [
820
+ /* @__PURE__ */ jsx2(FileTreeName, { className: "min-w-0 flex-1", children: entry.name }),
821
+ /* @__PURE__ */ jsx2(FileTagList, { tags: entry.tags })
822
+ ]
823
+ }
824
+ ),
825
+ isOpening ? /* @__PURE__ */ jsx2(Loader2, { size: 12, className: "ml-auto shrink-0 animate-spin text-[hsl(var(--muted-foreground))]" }) : !readOnly ? /* @__PURE__ */ jsxs2(FileTreeActions, { className: "ml-auto hidden shrink-0 group-hover:flex", children: [
826
+ /* @__PURE__ */ jsx2(
827
+ TreeActionButton,
828
+ {
829
+ onClick: () => {
830
+ const anchor = document.createElement("a");
831
+ anchor.href = downloadUrl;
832
+ anchor.download = entry.name;
833
+ anchor.click();
834
+ },
835
+ title: "\u4E0B\u8F7D\u6587\u4EF6",
836
+ children: /* @__PURE__ */ jsx2(Download, { size: 12 })
865
837
  }
866
- },
867
- title: "\u5171\u4EAB\u5230 .share",
868
- children: activeAction === "share" ? /* @__PURE__ */ jsx2(Loader2, { size: 12, className: "animate-spin" }) : /* @__PURE__ */ jsx2(Link2, { size: 12 })
869
- }
870
- ),
871
- /* @__PURE__ */ jsx2(
872
- TreeActionButton,
873
- {
874
- disabled: activeAction !== null,
875
- onClick: () => void handleDelete(),
876
- title: "\u5220\u9664\u6587\u4EF6",
877
- children: activeAction === "delete" ? /* @__PURE__ */ jsx2(Loader2, { size: 12, className: "animate-spin" }) : /* @__PURE__ */ jsx2(Trash2, { size: 12 })
878
- }
879
- )
880
- ] }) : allowDelete ? /* @__PURE__ */ jsx2(FileTreeActions, { className: "ml-auto hidden shrink-0 group-hover:flex", children: /* @__PURE__ */ jsx2(
881
- TreeActionButton,
882
- {
883
- disabled: activeAction !== null,
884
- onClick: () => void handleDelete(),
885
- title: "\u5220\u9664\u6587\u4EF6",
886
- children: activeAction === "delete" ? /* @__PURE__ */ jsx2(Loader2, { size: 12, className: "animate-spin" }) : /* @__PURE__ */ jsx2(Trash2, { size: 12 })
887
- }
888
- ) }) : null
889
- ] });
838
+ ),
839
+ /* @__PURE__ */ jsx2(
840
+ TreeActionButton,
841
+ {
842
+ disabled: activeAction !== null,
843
+ onClick: () => {
844
+ onSelectPath(entry.path);
845
+ setRenamingValue(entry.name);
846
+ setIsRenaming(true);
847
+ },
848
+ title: "\u91CD\u547D\u540D",
849
+ children: activeAction === "rename" ? /* @__PURE__ */ jsx2(Loader2, { size: 12, className: "animate-spin" }) : /* @__PURE__ */ jsx2(Pencil, { size: 12 })
850
+ }
851
+ ),
852
+ /* @__PURE__ */ jsx2(
853
+ TreeActionButton,
854
+ {
855
+ disabled: activeAction !== null,
856
+ onClick: () => void handleCopy(),
857
+ title: "\u590D\u5236\u6587\u4EF6",
858
+ children: activeAction === "copy" ? /* @__PURE__ */ jsx2(Loader2, { size: 12, className: "animate-spin" }) : /* @__PURE__ */ jsx2(Copy, { size: 12 })
859
+ }
860
+ ),
861
+ onShareFile ? /* @__PURE__ */ jsx2(
862
+ TreeActionButton,
863
+ {
864
+ disabled: activeAction !== null,
865
+ onClick: async () => {
866
+ setActiveAction("share");
867
+ try {
868
+ await onShareFile(entry.path, entry.name);
869
+ await queryClient.invalidateQueries({ queryKey: ["file-tree", sessionId] });
870
+ } catch (error) {
871
+ alert(getErrorMessage(error, "\u5171\u4EAB\u5931\u8D25"));
872
+ } finally {
873
+ setActiveAction(null);
874
+ }
875
+ },
876
+ title: "\u5171\u4EAB\u5230\u4EA7\u7269\u533A",
877
+ children: activeAction === "share" ? /* @__PURE__ */ jsx2(Loader2, { size: 12, className: "animate-spin" }) : /* @__PURE__ */ jsx2(Link2, { size: 12 })
878
+ }
879
+ ) : null,
880
+ /* @__PURE__ */ jsx2(
881
+ TreeActionButton,
882
+ {
883
+ disabled: activeAction !== null,
884
+ onClick: () => void handleDelete(),
885
+ title: "\u5220\u9664\u6587\u4EF6",
886
+ children: activeAction === "delete" ? /* @__PURE__ */ jsx2(Loader2, { size: 12, className: "animate-spin" }) : /* @__PURE__ */ jsx2(Trash2, { size: 12 })
887
+ }
888
+ )
889
+ ] }) : allowDelete ? /* @__PURE__ */ jsx2(FileTreeActions, { className: "ml-auto hidden shrink-0 group-hover:flex", children: /* @__PURE__ */ jsx2(
890
+ TreeActionButton,
891
+ {
892
+ disabled: activeAction !== null,
893
+ onClick: () => void handleDelete(),
894
+ title: "\u5220\u9664\u6587\u4EF6",
895
+ children: activeAction === "delete" ? /* @__PURE__ */ jsx2(Loader2, { size: 12, className: "animate-spin" }) : /* @__PURE__ */ jsx2(Trash2, { size: 12 })
896
+ }
897
+ ) }) : null
898
+ ]
899
+ }
900
+ );
890
901
  }
891
902
  function LazyDirChildren({
892
903
  dirPath,
@@ -961,18 +972,40 @@ function LazyDirChildren({
961
972
  )
962
973
  ) });
963
974
  }
975
+ var TAG_STYLES = {
976
+ "AI \u751F\u6210": "bg-[hsl(var(--muted))] text-[hsl(var(--muted-foreground))]",
977
+ "\u7528\u6237\u4E0A\u4F20": "bg-[hsl(var(--muted))] text-[hsl(var(--muted-foreground))]",
978
+ \u4EA7\u7269: "bg-[hsl(var(--muted))] text-[hsl(var(--muted-foreground))]"
979
+ };
980
+ var DEFAULT_TAG_STYLE = "bg-[hsl(var(--muted))] text-[hsl(var(--muted-foreground))]";
964
981
  function FileTagList({ tags }) {
965
- if (!tags || tags.length === 0) return null;
966
- return /* @__PURE__ */ jsx2("span", { className: "ml-2 flex min-w-0 shrink-0 items-center gap-1", children: tags.map((tag) => /* @__PURE__ */ jsx2(
982
+ const normalizedTags = normalizeDisplayTags(tags);
983
+ if (normalizedTags.length === 0) return null;
984
+ return /* @__PURE__ */ jsx2("span", { className: "ml-1 flex min-w-0 shrink-0 items-center gap-1", children: normalizedTags.map((tag) => /* @__PURE__ */ jsx2(
967
985
  "span",
968
986
  {
969
- className: "max-w-20 truncate rounded border border-[hsl(var(--border))] bg-[hsl(var(--muted))] px-1.5 py-0.5 text-[10px] leading-none text-[hsl(var(--muted-foreground))]",
987
+ className: `max-w-20 truncate rounded-full px-2 py-[2px] text-[11px] font-medium leading-[14px] ${TAG_STYLES[tag] ?? DEFAULT_TAG_STYLE}`,
970
988
  title: tag,
971
989
  children: tag
972
990
  },
973
991
  tag
974
992
  )) });
975
993
  }
994
+ function normalizeDisplayTags(tags) {
995
+ if (!tags) return [];
996
+ return tags.flatMap((tag) => {
997
+ const trimmed = tag.trim();
998
+ if (!trimmed.startsWith("[") || !trimmed.endsWith("]")) {
999
+ return trimmed ? [trimmed] : [];
1000
+ }
1001
+ try {
1002
+ const parsed = JSON.parse(trimmed);
1003
+ return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string") : [trimmed];
1004
+ } catch {
1005
+ return [trimmed];
1006
+ }
1007
+ });
1008
+ }
976
1009
  function TreeActionButton({
977
1010
  children,
978
1011
  disabled = false,
@@ -1000,25 +1033,121 @@ function EmptyState({ title, description }) {
1000
1033
  ] })
1001
1034
  ] });
1002
1035
  }
1036
+ var ICO_DOC = /* @__PURE__ */ jsxs2("svg", { "aria-hidden": "true", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1037
+ /* @__PURE__ */ jsx2("path", { d: "M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z" }),
1038
+ /* @__PURE__ */ jsx2("polyline", { points: "14 2 14 8 20 8" })
1039
+ ] });
1040
+ var ICO_CODE = /* @__PURE__ */ jsxs2("svg", { "aria-hidden": "true", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1041
+ /* @__PURE__ */ jsx2("polyline", { points: "16 18 22 12 16 6" }),
1042
+ /* @__PURE__ */ jsx2("polyline", { points: "8 6 2 12 8 18" })
1043
+ ] });
1044
+ var ICO_TABLE = /* @__PURE__ */ jsxs2("svg", { "aria-hidden": "true", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1045
+ /* @__PURE__ */ jsx2("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
1046
+ /* @__PURE__ */ jsx2("path", { d: "M3 9h18" }),
1047
+ /* @__PURE__ */ jsx2("path", { d: "M3 15h18" }),
1048
+ /* @__PURE__ */ jsx2("path", { d: "M9 3v18" })
1049
+ ] });
1050
+ var ICO_SLIDES = /* @__PURE__ */ jsxs2("svg", { "aria-hidden": "true", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1051
+ /* @__PURE__ */ jsx2("rect", { x: "2", y: "3", width: "20", height: "14", rx: "2" }),
1052
+ /* @__PURE__ */ jsx2("path", { d: "M8 21h8" }),
1053
+ /* @__PURE__ */ jsx2("path", { d: "M12 17v4" })
1054
+ ] });
1055
+ var ICO_PDF = /* @__PURE__ */ jsxs2("svg", { "aria-hidden": "true", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1056
+ /* @__PURE__ */ jsx2("path", { d: "M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z" }),
1057
+ /* @__PURE__ */ jsx2("path", { d: "M8 13h8" }),
1058
+ /* @__PURE__ */ jsx2("path", { d: "M8 17h5" })
1059
+ ] });
1060
+ var ICO_IMAGE = /* @__PURE__ */ jsxs2("svg", { "aria-hidden": "true", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1061
+ /* @__PURE__ */ jsx2("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
1062
+ /* @__PURE__ */ jsx2("circle", { cx: "9", cy: "9", r: "2" }),
1063
+ /* @__PURE__ */ jsx2("path", { d: "m21 15-3.09-3.09a2 2 0 0 0-2.82 0L6 21" })
1064
+ ] });
1065
+ var ICO_AUDIO = /* @__PURE__ */ jsxs2("svg", { "aria-hidden": "true", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1066
+ /* @__PURE__ */ jsx2("path", { d: "M9 18V5l12-2v13" }),
1067
+ /* @__PURE__ */ jsx2("circle", { cx: "6", cy: "18", r: "3" }),
1068
+ /* @__PURE__ */ jsx2("circle", { cx: "18", cy: "16", r: "3" })
1069
+ ] });
1070
+ var ICO_VIDEO = /* @__PURE__ */ jsxs2("svg", { "aria-hidden": "true", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1071
+ /* @__PURE__ */ jsx2("rect", { x: "2", y: "2", width: "20", height: "20", rx: "2" }),
1072
+ /* @__PURE__ */ jsx2("path", { d: "m10 8 6 4-6 4V8z" })
1073
+ ] });
1074
+ var ICO_ARCHIVE = /* @__PURE__ */ jsxs2("svg", { "aria-hidden": "true", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1075
+ /* @__PURE__ */ jsx2("rect", { x: "2", y: "4", width: "20", height: "16", rx: "2" }),
1076
+ /* @__PURE__ */ jsx2("path", { d: "M12 4v16" }),
1077
+ /* @__PURE__ */ jsx2("path", { d: "m10 10 4 4" }),
1078
+ /* @__PURE__ */ jsx2("path", { d: "m14 10-4 4" })
1079
+ ] });
1080
+ var ICO_CONFIG = /* @__PURE__ */ jsxs2("svg", { "aria-hidden": "true", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1081
+ /* @__PURE__ */ jsx2("path", { d: "M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z" }),
1082
+ /* @__PURE__ */ jsx2("circle", { cx: "12", cy: "15", r: "2" }),
1083
+ /* @__PURE__ */ jsx2("path", { d: "M12 11v2" })
1084
+ ] });
1085
+ var ICO_TEXT = /* @__PURE__ */ jsxs2("svg", { "aria-hidden": "true", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1086
+ /* @__PURE__ */ jsx2("path", { d: "M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z" }),
1087
+ /* @__PURE__ */ jsx2("path", { d: "M8 13h8" }),
1088
+ /* @__PURE__ */ jsx2("path", { d: "M8 17h8" }),
1089
+ /* @__PURE__ */ jsx2("path", { d: "M8 9h3" })
1090
+ ] });
1091
+ var ICO_DB = /* @__PURE__ */ jsxs2("svg", { "aria-hidden": "true", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1092
+ /* @__PURE__ */ jsx2("ellipse", { cx: "12", cy: "5", rx: "9", ry: "3" }),
1093
+ /* @__PURE__ */ jsx2("path", { d: "M3 5v14a9 3 0 0 0 18 0V5" }),
1094
+ /* @__PURE__ */ jsx2("path", { d: "M3 12a9 3 0 0 0 18 0" })
1095
+ ] });
1096
+ var ICO_FOLDER = /* @__PURE__ */ jsx2("svg", { "aria-hidden": "true", width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor", opacity: "0.85", children: /* @__PURE__ */ jsx2("path", { d: "M20 6h-8l-2-2H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2z" }) });
1097
+ var ICO_DESIGN = /* @__PURE__ */ jsxs2("svg", { "aria-hidden": "true", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1098
+ /* @__PURE__ */ jsx2("path", { d: "m12 19 7-7 3 3-7 7-3-3z" }),
1099
+ /* @__PURE__ */ jsx2("path", { d: "m18 13-1.5-7.5L2 2l3.5 14.5L13 18l5-5z" }),
1100
+ /* @__PURE__ */ jsx2("path", { d: "m2 2 7.586 7.586" }),
1101
+ /* @__PURE__ */ jsx2("circle", { cx: "11", cy: "11", r: "2" })
1102
+ ] });
1103
+ var EXT_ICON = {};
1104
+ function reg(exts, icon, color) {
1105
+ for (const ext of exts) EXT_ICON[ext] = { icon, color };
1106
+ }
1107
+ reg(["py"], ICO_CODE, "text-[hsl(210,70%,58%)]");
1108
+ reg(["js", "jsx"], ICO_CODE, "text-[hsl(48,90%,50%)]");
1109
+ reg(["ts", "tsx"], ICO_CODE, "text-[hsl(210,80%,55%)]");
1110
+ reg(["go"], ICO_CODE, "text-[hsl(195,70%,50%)]");
1111
+ reg(["rs"], ICO_CODE, "text-[hsl(25,80%,55%)]");
1112
+ reg(["java", "kt"], ICO_CODE, "text-[hsl(20,85%,52%)]");
1113
+ reg(["rb"], ICO_CODE, "text-[hsl(0,70%,55%)]");
1114
+ reg(["c", "cpp", "h", "hpp"], ICO_CODE, "text-[hsl(210,60%,55%)]");
1115
+ reg(["cs"], ICO_CODE, "text-[hsl(265,55%,55%)]");
1116
+ reg(["swift"], ICO_CODE, "text-[hsl(20,90%,55%)]");
1117
+ reg(["html"], ICO_CODE, "text-[hsl(15,85%,55%)]");
1118
+ reg(["css", "scss"], ICO_CODE, "text-[hsl(210,70%,55%)]");
1119
+ reg(["vue"], ICO_CODE, "text-[hsl(153,60%,48%)]");
1120
+ reg(["svelte"], ICO_CODE, "text-[hsl(15,90%,55%)]");
1121
+ reg(["php"], ICO_CODE, "text-[hsl(240,40%,58%)]");
1122
+ reg(["sh", "zsh"], ICO_CODE, "text-[hsl(var(--muted-foreground))]");
1123
+ reg(["sql"], ICO_CODE, "text-[hsl(210,50%,55%)]");
1124
+ reg(["json", "jsonl", "ndjson"], ICO_CONFIG, "text-[hsl(158,55%,48%)]");
1125
+ reg(["yaml", "yml", "toml", "ini", "conf", "env", "lock"], ICO_CONFIG, "text-[hsl(var(--muted-foreground))]");
1126
+ reg(["xml"], ICO_CODE, "text-[hsl(25,65%,52%)]");
1127
+ reg(["db", "sqlite"], ICO_DB, "text-[hsl(210,50%,55%)]");
1128
+ reg(["parquet"], ICO_DB, "text-[hsl(158,50%,45%)]");
1129
+ reg(["doc", "docx", "odt", "rtf", "pages"], ICO_TEXT, "text-[hsl(210,65%,52%)]");
1130
+ reg(["xls", "xlsx", "csv", "tsv", "ods", "numbers"], ICO_TABLE, "text-[hsl(140,55%,42%)]");
1131
+ reg(["ppt", "pptx", "odp", "key"], ICO_SLIDES, "text-[hsl(15,80%,52%)]");
1132
+ reg(["pdf"], ICO_PDF, "text-[hsl(0,65%,50%)]");
1133
+ reg(["md", "markdown", "txt", "log", "tex", "epub"], ICO_TEXT, "text-[hsl(var(--muted-foreground))]");
1134
+ reg(["png", "jpg", "jpeg", "gif", "webp", "bmp", "ico", "heic", "heif", "avif", "tif", "tiff", "svg"], ICO_IMAGE, "text-[hsl(280,55%,58%)]");
1135
+ reg(["psd"], ICO_DESIGN, "text-[hsl(210,60%,55%)]");
1136
+ reg(["ai"], ICO_DESIGN, "text-[hsl(25,85%,52%)]");
1137
+ reg(["fig", "sketch", "xd", "blend"], ICO_DESIGN, "text-[hsl(280,50%,55%)]");
1138
+ reg(["mp3", "wav", "flac", "ogg", "aac", "aiff", "m4a", "mid"], ICO_AUDIO, "text-[hsl(330,60%,55%)]");
1139
+ reg(["mp4", "mov", "mkv", "avi", "webm", "wmv", "flv", "m4v"], ICO_VIDEO, "text-[hsl(340,65%,52%)]");
1140
+ reg(["zip", "tar", "gz", "rar", "7z", "bz2", "xz", "tgz", "dmg", "iso", "pkg"], ICO_ARCHIVE, "text-[hsl(30,50%,48%)]");
1141
+ reg(["ttf", "otf", "woff", "woff2"], ICO_DOC, "text-[hsl(var(--muted-foreground))]");
1142
+ var DEFAULT_ICON = { icon: ICO_DOC, color: "text-[hsl(var(--muted-foreground))]" };
1143
+ var FOLDER_COLOR = "text-[hsl(38,80%,55%)]";
1003
1144
  function getFileIcon(fileName) {
1004
1145
  const ext = fileName.split(".").pop()?.toLowerCase() ?? "";
1005
- const src = FILE_ICON_ASSETS[ext] ?? GENERIC_FILE_ICON_ASSET;
1006
- return /* @__PURE__ */ jsx2(FileTypeIcon, { src, alt: `${ext || "file"} \u6587\u4EF6` });
1146
+ const entry = EXT_ICON[ext] ?? DEFAULT_ICON;
1147
+ return /* @__PURE__ */ jsx2("span", { className: `flex size-5 shrink-0 items-center justify-center ${entry.color}`, children: entry.icon });
1007
1148
  }
1008
1149
  function getFolderIcon() {
1009
- return /* @__PURE__ */ jsx2(FileTypeIcon, { src: FOLDER_ICON_ASSET, alt: "\u6587\u4EF6\u5939" });
1010
- }
1011
- function FileTypeIcon({ src, alt }) {
1012
- return /* @__PURE__ */ jsx2(
1013
- "img",
1014
- {
1015
- src,
1016
- alt,
1017
- className: "size-4 shrink-0 object-contain",
1018
- draggable: false,
1019
- loading: "lazy"
1020
- }
1021
- );
1150
+ return /* @__PURE__ */ jsx2("span", { className: `flex size-5 shrink-0 items-center justify-center ${FOLDER_COLOR}`, children: ICO_FOLDER });
1022
1151
  }
1023
1152
  function getErrorMessage(error, fallback) {
1024
1153
  if (error instanceof Error && error.message) {
@@ -1090,16 +1219,25 @@ function WorkspaceFilesPanel({
1090
1219
  }
1091
1220
  }, [activeTab, inlineResources.length]);
1092
1221
  const uploadTargetDir = () => {
1093
- const candidates = Array.from(expandedDirs).filter((path) => path !== ".").filter((path) => {
1222
+ const candidates = Array.from(expandedDirs).filter((path) => path !== ".").filter((path) => path !== rootPath).filter((path) => {
1094
1223
  const parts = path.split("/").filter(Boolean);
1224
+ const rootParts = rootPath.split("/").filter(Boolean);
1225
+ const ancestorPrefix = path.startsWith("/") ? "/" : "";
1226
+ if (rootParts.length === 0 && path.startsWith("/")) {
1227
+ return false;
1228
+ }
1229
+ if (rootParts.length > 0 && !rootParts.every((part, index) => parts[index] === part)) {
1230
+ return false;
1231
+ }
1095
1232
  for (let index = 1; index < parts.length; index += 1) {
1096
- const ancestor = parts.slice(0, index).join("/");
1233
+ const ancestor = `${ancestorPrefix}${parts.slice(0, index).join("/")}`;
1234
+ if (rootParts.length > 0 && index < rootParts.length) continue;
1097
1235
  if (!expandedDirs.has(ancestor)) return false;
1098
1236
  }
1099
1237
  return true;
1100
1238
  });
1101
1239
  if (candidates.length === 0) {
1102
- return ".";
1240
+ return rootPath;
1103
1241
  }
1104
1242
  return candidates.reduce((deepestPath, currentPath) => {
1105
1243
  const deepestDepth = deepestPath.split("/").filter(Boolean).length;