@blade-hq/agent-kit 0.5.22 → 0.5.23

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.
@@ -2,11 +2,15 @@ import {
2
2
  CardJSON,
3
3
  cardRegistry
4
4
  } from "./chunk-2UP7MG3J.js";
5
+ import {
6
+ getSessionFilePath,
7
+ resolveSessionFilePreviewTarget
8
+ } from "./chunk-NWKF2VEC.js";
5
9
  import {
6
10
  formatToolName,
7
11
  getAuthedUrl,
8
12
  useUiStore
9
- } from "./chunk-CCMNSYPI.js";
13
+ } from "./chunk-B4RZNR3L.js";
10
14
  import {
11
15
  cn,
12
16
  copyToClipboard
@@ -155,7 +159,7 @@ async function loadCodeHighlighter() {
155
159
  html,
156
160
  javascript,
157
161
  json,
158
- jsx8,
162
+ jsx9,
159
163
  markdown,
160
164
  python,
161
165
  rust,
@@ -173,7 +177,7 @@ async function loadCodeHighlighter() {
173
177
  html.default,
174
178
  javascript.default,
175
179
  json.default,
176
- jsx8.default,
180
+ jsx9.default,
177
181
  markdown.default,
178
182
  python.default,
179
183
  rust.default,
@@ -372,12 +376,12 @@ function CardCodeBlock({ className, children, node, ...props }) {
372
376
 
373
377
  // src/react/components/markdown/MarkdownContent.tsx
374
378
  import { mermaid } from "@streamdown/mermaid";
375
- import { Check as Check2, Copy as Copy2, Download, X as X2 } from "lucide-react";
379
+ import { Check as Check2, Copy as Copy2, Download as Download2, X as X2 } from "lucide-react";
376
380
  import {
377
381
  useEffect as useEffect3,
378
382
  useMemo as useMemo2,
379
383
  useRef,
380
- useState as useState3
384
+ useState as useState4
381
385
  } from "react";
382
386
  import { createPortal as createPortal2 } from "react-dom";
383
387
  import { Streamdown } from "streamdown";
@@ -492,15 +496,152 @@ function ExternalLinkDialog({ isOpen, onClose, onConfirm, url }) {
492
496
  );
493
497
  }
494
498
 
495
- // src/react/components/markdown/MarkdownContent.tsx
499
+ // src/react/components/markdown/FileCardComponent.tsx
500
+ import {
501
+ Archive,
502
+ Download,
503
+ File,
504
+ FileCode2,
505
+ FileSpreadsheet,
506
+ FileText,
507
+ Film,
508
+ Image,
509
+ Loader2,
510
+ Music
511
+ } from "lucide-react";
512
+ import { useState as useState3 } from "react";
496
513
  import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
514
+ var IMAGE_EXTS = /* @__PURE__ */ new Set(["png", "jpg", "jpeg", "gif", "svg", "webp", "ico", "bmp"]);
515
+ var SHEET_EXTS = /* @__PURE__ */ new Set(["xlsx", "xls", "xlsm", "xlsb", "csv"]);
516
+ var TEXT_EXTS = /* @__PURE__ */ new Set(["txt", "md", "markdown", "pdf", "doc", "docx", "rtf"]);
517
+ var CODE_EXTS = /* @__PURE__ */ new Set(["js", "jsx", "ts", "tsx", "py", "go", "json", "yaml", "yml", "html", "css"]);
518
+ var VIDEO_EXTS = /* @__PURE__ */ new Set(["mp4", "webm", "mov", "mkv", "avi"]);
519
+ var AUDIO_EXTS = /* @__PURE__ */ new Set(["mp3", "wav", "ogg", "m4a", "flac"]);
520
+ var ARCHIVE_EXTS = /* @__PURE__ */ new Set(["zip", "tar", "gz", "tgz", "rar", "7z"]);
521
+ function stringValue(value) {
522
+ return typeof value === "string" ? value : void 0;
523
+ }
524
+ function decodeAttribute(value) {
525
+ if (!value) return "";
526
+ try {
527
+ return decodeURIComponent(value);
528
+ } catch {
529
+ return value;
530
+ }
531
+ }
532
+ function isSafeRelPath(p) {
533
+ if (!p || p.startsWith("/")) return false;
534
+ const segments = p.split("/");
535
+ return segments.every((s) => s !== ".." && s !== ".");
536
+ }
537
+ function basename(path) {
538
+ return path.split("/").filter(Boolean).pop() || path;
539
+ }
540
+ function getExt(name) {
541
+ return name.split(".").pop()?.toLowerCase() ?? "";
542
+ }
543
+ function getFileIcon(name) {
544
+ const ext = getExt(name);
545
+ if (IMAGE_EXTS.has(ext)) return Image;
546
+ if (SHEET_EXTS.has(ext)) return FileSpreadsheet;
547
+ if (TEXT_EXTS.has(ext)) return FileText;
548
+ if (CODE_EXTS.has(ext)) return FileCode2;
549
+ if (VIDEO_EXTS.has(ext)) return Film;
550
+ if (AUDIO_EXTS.has(ext)) return Music;
551
+ if (ARCHIVE_EXTS.has(ext)) return Archive;
552
+ return File;
553
+ }
554
+ function FileCardComponent({
555
+ node,
556
+ "data-rel-path": dataRelPathAttribute,
557
+ "data-name": dataNameAttribute,
558
+ dataRelPath,
559
+ dataName,
560
+ className,
561
+ ...props
562
+ }) {
563
+ const nodeProperties = node && typeof node === "object" && "properties" in node ? node.properties : void 0;
564
+ const relPath = decodeAttribute(
565
+ dataRelPathAttribute ?? dataRelPath ?? stringValue(nodeProperties?.["data-rel-path"]) ?? stringValue(nodeProperties?.dataRelPath)
566
+ );
567
+ const name = decodeAttribute(
568
+ dataNameAttribute ?? dataName ?? stringValue(nodeProperties?.["data-name"]) ?? stringValue(nodeProperties?.dataName)
569
+ ) || basename(relPath);
570
+ const { sessionId } = useCardContext();
571
+ const [opening, setOpening] = useState3(false);
572
+ const Icon = getFileIcon(name);
573
+ const disabled = !sessionId || !relPath || !isSafeRelPath(relPath);
574
+ const handleOpen = async () => {
575
+ if (disabled || opening) return;
576
+ setOpening(true);
577
+ try {
578
+ const target = await resolveSessionFilePreviewTarget(sessionId, relPath, name);
579
+ const uiStore = useUiStore.getState();
580
+ uiStore.pushArtifact(target);
581
+ uiStore.setActiveRightTab("preview");
582
+ } finally {
583
+ setOpening(false);
584
+ }
585
+ };
586
+ const handleDownload = (event) => {
587
+ event.stopPropagation();
588
+ if (disabled) return;
589
+ const a = document.createElement("a");
590
+ a.href = getAuthedUrl(getSessionFilePath(sessionId, relPath));
591
+ a.download = name;
592
+ a.click();
593
+ };
594
+ return /* @__PURE__ */ jsxs4(
595
+ "span",
596
+ {
597
+ ...props,
598
+ className: cn("not-prose my-2 flex max-w-full items-stretch", className),
599
+ children: [
600
+ /* @__PURE__ */ jsxs4(
601
+ "button",
602
+ {
603
+ type: "button",
604
+ onClick: handleOpen,
605
+ disabled: disabled || opening,
606
+ className: "flex min-w-0 flex-1 items-center gap-3 rounded-l-lg border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-3 py-2.5 text-left text-[hsl(var(--card-foreground))] shadow-sm transition-colors hover:border-[hsl(var(--primary))]/45 hover:bg-[hsl(var(--accent))]/45 focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] focus:outline-none disabled:cursor-not-allowed disabled:opacity-60",
607
+ "aria-label": `\u6253\u5F00\u6587\u4EF6\uFF1A${name}`,
608
+ children: [
609
+ /* @__PURE__ */ jsx5("span", { className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-md bg-[hsl(var(--muted))] text-[hsl(var(--primary))]", children: opening ? /* @__PURE__ */ jsx5(Loader2, { size: 18, className: "animate-spin" }) : /* @__PURE__ */ jsx5(Icon, { size: 18 }) }),
610
+ /* @__PURE__ */ jsxs4("span", { className: "min-w-0 flex-1", children: [
611
+ /* @__PURE__ */ jsx5("span", { className: "block truncate text-sm font-medium leading-5", children: name }),
612
+ /* @__PURE__ */ jsx5("span", { className: "block truncate text-xs leading-4 text-[hsl(var(--muted-foreground))]", children: "\u70B9\u51FB\u9884\u89C8\u6587\u4EF6" })
613
+ ] })
614
+ ]
615
+ }
616
+ ),
617
+ /* @__PURE__ */ jsx5(
618
+ "button",
619
+ {
620
+ type: "button",
621
+ onClick: handleDownload,
622
+ disabled,
623
+ className: "flex w-11 shrink-0 items-center justify-center rounded-r-lg border border-l-0 border-[hsl(var(--border))] bg-[hsl(var(--card))] text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))] focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] focus:outline-none disabled:cursor-not-allowed disabled:opacity-60",
624
+ "aria-label": `\u4E0B\u8F7D\u6587\u4EF6\uFF1A${name}`,
625
+ title: "\u4E0B\u8F7D",
626
+ children: /* @__PURE__ */ jsx5(Download, { size: 16 })
627
+ }
628
+ )
629
+ ]
630
+ }
631
+ );
632
+ }
633
+
634
+ // src/react/components/markdown/MarkdownContent.tsx
635
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
497
636
  var LINK_SAFETY_CONFIG = {
498
637
  enabled: true,
499
- renderModal: (props) => /* @__PURE__ */ jsx5(ExternalLinkDialog, { ...props })
638
+ renderModal: (props) => /* @__PURE__ */ jsx6(ExternalLinkDialog, { ...props })
500
639
  };
501
640
  var STREAMDOWN_PLUGINS = { mermaid };
502
641
  var SYSTEM_REMINDER_TAG = "system-reminder";
503
642
  var TOOL_CALL_TAG = "blade-malformed-tool-call";
643
+ var FILE_CARD_TAG = "blade-file-card";
644
+ var AGENT_WORKSPACE_DIR_NAME = "\u667A\u80FD\u52A9\u624B\u5DE5\u4F5C\u7A7A\u95F4";
504
645
  var HIDDEN_SYSTEM_REMINDER_TAGS = {
505
646
  [SYSTEM_REMINDER_TAG]: []
506
647
  };
@@ -526,14 +667,14 @@ function InlineToolCallBlock({
526
667
  node,
527
668
  children
528
669
  }) || extractText(children).trim();
529
- const [open, setOpen] = useState3(false);
530
- return /* @__PURE__ */ jsxs4(
670
+ const [open, setOpen] = useState4(false);
671
+ return /* @__PURE__ */ jsxs5(
531
672
  "span",
532
673
  {
533
674
  ...props,
534
675
  className: "not-prose relative inline-flex align-baseline",
535
676
  children: [
536
- /* @__PURE__ */ jsx5(
677
+ /* @__PURE__ */ jsx6(
537
678
  "button",
538
679
  {
539
680
  type: "button",
@@ -545,7 +686,7 @@ function InlineToolCallBlock({
545
686
  }
546
687
  ),
547
688
  open ? createPortal2(
548
- /* @__PURE__ */ jsx5(
689
+ /* @__PURE__ */ jsx6(
549
690
  "div",
550
691
  {
551
692
  className: "fixed inset-0 z-[70] flex items-center justify-center bg-black/10 p-6",
@@ -561,26 +702,26 @@ function InlineToolCallBlock({
561
702
  setOpen(false);
562
703
  }
563
704
  },
564
- children: /* @__PURE__ */ jsxs4(
705
+ children: /* @__PURE__ */ jsxs5(
565
706
  "div",
566
707
  {
567
708
  className: "m-0 flex max-h-[min(520px,calc(100vh-48px))] w-[min(760px,calc(100vw-48px))] flex-col overflow-hidden rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--popover))] text-left text-[13px] leading-6 text-[hsl(var(--popover-foreground))] shadow-xl",
568
709
  "aria-label": "\u6298\u53E0\u7684\u5185\u5BB9",
569
710
  children: [
570
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center justify-between gap-3 border-b border-[hsl(var(--border))] px-4 py-2", children: [
571
- /* @__PURE__ */ jsx5("span", { className: "text-xs font-medium text-[hsl(var(--muted-foreground))]", children: "\u6298\u53E0\u7684\u5185\u5BB9" }),
572
- /* @__PURE__ */ jsx5(
711
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between gap-3 border-b border-[hsl(var(--border))] px-4 py-2", children: [
712
+ /* @__PURE__ */ jsx6("span", { className: "text-xs font-medium text-[hsl(var(--muted-foreground))]", children: "\u6298\u53E0\u7684\u5185\u5BB9" }),
713
+ /* @__PURE__ */ jsx6(
573
714
  "button",
574
715
  {
575
716
  type: "button",
576
717
  onClick: () => setOpen(false),
577
718
  className: "inline-flex h-6 w-6 items-center justify-center rounded-md text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))] focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] focus:outline-none",
578
719
  "aria-label": "\u5173\u95ED\u6298\u53E0\u7684\u5185\u5BB9",
579
- children: /* @__PURE__ */ jsx5(X2, { size: 14, "aria-hidden": "true" })
720
+ children: /* @__PURE__ */ jsx6(X2, { size: 14, "aria-hidden": "true" })
580
721
  }
581
722
  )
582
723
  ] }),
583
- /* @__PURE__ */ jsx5("pre", { className: "m-0 overflow-auto px-4 py-3 font-mono text-[12px] leading-5 whitespace-pre-wrap text-[hsl(var(--popover-foreground))]", children: rawText || children })
724
+ /* @__PURE__ */ jsx6("pre", { className: "m-0 overflow-auto px-4 py-3 font-mono text-[12px] leading-5 whitespace-pre-wrap text-[hsl(var(--popover-foreground))]", children: rawText || children })
584
725
  ]
585
726
  }
586
727
  )
@@ -610,19 +751,19 @@ function resolveCollapsedContent({
610
751
  children
611
752
  }) {
612
753
  const nodeProperties = node && typeof node === "object" && "properties" in node ? node.properties : void 0;
613
- const key = dataKeyAttribute ?? dataKey ?? stringValue(nodeProperties?.["data-key"]) ?? stringValue(nodeProperties?.dataKey) ?? extractText(children).trim();
754
+ const key = dataKeyAttribute ?? dataKey ?? stringValue2(nodeProperties?.["data-key"]) ?? stringValue2(nodeProperties?.dataKey) ?? extractText(children).trim();
614
755
  const cached = key ? malformedToolCallContent.get(key) : void 0;
615
756
  if (cached) return cached;
616
- const raw = dataRawAttribute ?? dataRaw ?? stringValue(nodeProperties?.["data-raw"]) ?? stringValue(nodeProperties?.dataRaw) ?? "";
757
+ const raw = dataRawAttribute ?? dataRaw ?? stringValue2(nodeProperties?.["data-raw"]) ?? stringValue2(nodeProperties?.dataRaw) ?? "";
617
758
  return decodeCollapsedContent(raw) || extractText(children).trim();
618
759
  }
619
- function stringValue(value) {
760
+ function stringValue2(value) {
620
761
  return typeof value === "string" ? value : void 0;
621
762
  }
622
763
  function CodeBlockPre({ children, node: _node, ...props }) {
623
764
  const preRef = useRef(null);
624
- const [copied, setCopied] = useState3(false);
625
- const [hasCodeNode, setHasCodeNode] = useState3(false);
765
+ const [copied, setCopied] = useState4(false);
766
+ const [hasCodeNode, setHasCodeNode] = useState4(false);
626
767
  useEffect3(() => {
627
768
  setHasCodeNode(!!preRef.current?.querySelector("code"));
628
769
  }, []);
@@ -646,10 +787,10 @@ function CodeBlockPre({ children, node: _node, ...props }) {
646
787
  a.click();
647
788
  URL.revokeObjectURL(url);
648
789
  };
649
- return /* @__PURE__ */ jsxs4("div", { className: "relative group", children: [
650
- /* @__PURE__ */ jsx5("pre", { ref: preRef, ...props, children }),
651
- hasCodeNode && /* @__PURE__ */ jsxs4("div", { className: "absolute top-2 right-2 flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity", children: [
652
- /* @__PURE__ */ jsxs4(
790
+ return /* @__PURE__ */ jsxs5("div", { className: "relative group", children: [
791
+ /* @__PURE__ */ jsx6("pre", { ref: preRef, ...props, children }),
792
+ hasCodeNode && /* @__PURE__ */ jsxs5("div", { className: "absolute top-2 right-2 flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity", children: [
793
+ /* @__PURE__ */ jsxs5(
653
794
  "button",
654
795
  {
655
796
  type: "button",
@@ -659,20 +800,20 @@ function CodeBlockPre({ children, node: _node, ...props }) {
659
800
  copied ? "text-[hsl(var(--primary))]" : "text-[hsl(var(--muted-foreground))] hover:text-[hsl(var(--foreground))] hover:bg-[hsl(var(--accent))]"
660
801
  ),
661
802
  children: [
662
- copied ? /* @__PURE__ */ jsx5(Check2, { size: 12 }) : /* @__PURE__ */ jsx5(Copy2, { size: 12 }),
663
- /* @__PURE__ */ jsx5("span", { children: copied ? "\u5DF2\u590D\u5236" : "\u590D\u5236" })
803
+ copied ? /* @__PURE__ */ jsx6(Check2, { size: 12 }) : /* @__PURE__ */ jsx6(Copy2, { size: 12 }),
804
+ /* @__PURE__ */ jsx6("span", { children: copied ? "\u5DF2\u590D\u5236" : "\u590D\u5236" })
664
805
  ]
665
806
  }
666
807
  ),
667
- /* @__PURE__ */ jsxs4(
808
+ /* @__PURE__ */ jsxs5(
668
809
  "button",
669
810
  {
670
811
  type: "button",
671
812
  onClick: handleDownload,
672
813
  className: "flex items-center gap-1 rounded-md px-1.5 py-0.5 text-[11px] transition-colors text-[hsl(var(--muted-foreground))] hover:text-[hsl(var(--foreground))] hover:bg-[hsl(var(--accent))]",
673
814
  children: [
674
- /* @__PURE__ */ jsx5(Download, { size: 12 }),
675
- /* @__PURE__ */ jsx5("span", { children: "\u4E0B\u8F7D" })
815
+ /* @__PURE__ */ jsx6(Download2, { size: 12 }),
816
+ /* @__PURE__ */ jsx6("span", { children: "\u4E0B\u8F7D" })
676
817
  ]
677
818
  }
678
819
  )
@@ -694,6 +835,7 @@ function decodeMarkdownPath(src) {
694
835
  }
695
836
  }
696
837
  var MARKDOWN_IMAGE_PATTERN = /!\[((?:\\.|[^\]\\])*)\]\(\s*(?:<([^>\n]+)>|([^\s)]+))(\s+(?:"[^"]*"|'[^']*'|\([^)]*\)))?\s*\)/g;
838
+ var MEDIA_LINE_RE = /^[ \t]*[`"']?MEDIA:[ \t]*(\S+?)[`"']?[ \t]*$/gm;
697
839
  function resolveSessionImageMarkdown(children, sessionId) {
698
840
  return children.replace(
699
841
  MARKDOWN_IMAGE_PATTERN,
@@ -709,6 +851,40 @@ function resolveSessionImageMarkdown(children, sessionId) {
709
851
  }
710
852
  );
711
853
  }
854
+ function stripWorkspacePrefix(path, sessionId) {
855
+ const sessionRoot = `/root/${AGENT_WORKSPACE_DIR_NAME}/${sessionId}`;
856
+ if (path === sessionRoot || path === `${sessionRoot}/`) {
857
+ return null;
858
+ }
859
+ let relPath;
860
+ if (path.startsWith(`${sessionRoot}/`)) {
861
+ relPath = path.slice(sessionRoot.length + 1);
862
+ } else if (!path.startsWith("/")) {
863
+ relPath = path.replace(/^\.\//, "");
864
+ } else {
865
+ return null;
866
+ }
867
+ if (!relPath || relPath.startsWith("../") || relPath.includes("/../")) {
868
+ return null;
869
+ }
870
+ return relPath;
871
+ }
872
+ function basename2(path) {
873
+ return path.split("/").filter(Boolean).pop() || path;
874
+ }
875
+ function escapeAttribute(value) {
876
+ return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
877
+ }
878
+ function collapseMediaTags(children, sessionId) {
879
+ return children.replace(MEDIA_LINE_RE, (match, absPath) => {
880
+ const relPath = stripWorkspacePrefix(absPath, sessionId);
881
+ if (!relPath) {
882
+ return match;
883
+ }
884
+ const name = basename2(relPath);
885
+ return `<${FILE_CARD_TAG} data-rel-path="${encodeURIComponent(relPath)}" data-name="${escapeAttribute(name)}"></${FILE_CARD_TAG}>`;
886
+ });
887
+ }
712
888
  function collapseInlineToolCalls(children) {
713
889
  return children.replace(
714
890
  TOOL_CALL_BLOCK_RE,
@@ -747,7 +923,8 @@ function MarkdownContent({
747
923
  () => {
748
924
  if (typeof children !== "string") return children;
749
925
  const withResolvedImages = sessionId ? resolveSessionImageMarkdown(children, sessionId) : children;
750
- return collapseInlineToolCalls(withResolvedImages);
926
+ const withMediaCards = sessionId ? collapseMediaTags(withResolvedImages, sessionId) : withResolvedImages;
927
+ return collapseInlineToolCalls(withMediaCards);
751
928
  },
752
929
  [children, sessionId]
753
930
  );
@@ -755,7 +932,8 @@ function MarkdownContent({
755
932
  () => ({
756
933
  ...allowedTags ?? {},
757
934
  ...HIDDEN_SYSTEM_REMINDER_TAGS,
758
- [TOOL_CALL_TAG]: ["data-key", "data-raw"]
935
+ [TOOL_CALL_TAG]: ["data-key", "data-raw"],
936
+ [FILE_CARD_TAG]: ["data-rel-path", "data-name"]
759
937
  }),
760
938
  [allowedTags]
761
939
  );
@@ -765,7 +943,8 @@ function MarkdownContent({
765
943
  pre: CodeBlockPre,
766
944
  ...components ?? {},
767
945
  ...HIDDEN_SYSTEM_REMINDER_COMPONENTS,
768
- [TOOL_CALL_TAG]: InlineToolCallBlock
946
+ [TOOL_CALL_TAG]: InlineToolCallBlock,
947
+ [FILE_CARD_TAG]: FileCardComponent
769
948
  }),
770
949
  [components]
771
950
  );
@@ -776,7 +955,7 @@ function MarkdownContent({
776
955
  }),
777
956
  [plugins]
778
957
  );
779
- return /* @__PURE__ */ jsx5(
958
+ return /* @__PURE__ */ jsx6(
780
959
  Streamdown,
781
960
  {
782
961
  ...props,
@@ -791,9 +970,9 @@ function MarkdownContent({
791
970
  }
792
971
 
793
972
  // src/react/components/chat/AskUserQuestionBlock.tsx
794
- import { Check as Check3, Loader2, MessageSquareMore } from "lucide-react";
795
- import { useEffect as useEffect4, useMemo as useMemo3, useState as useState4 } from "react";
796
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
973
+ import { Check as Check3, Loader2 as Loader22, MessageSquareMore } from "lucide-react";
974
+ import { useEffect as useEffect4, useMemo as useMemo3, useState as useState5 } from "react";
975
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
797
976
  function AskUserQuestionBlock({
798
977
  data,
799
978
  answered,
@@ -802,10 +981,10 @@ function AskUserQuestionBlock({
802
981
  answerData,
803
982
  onAnswer
804
983
  }) {
805
- const [selections, setSelections] = useState4(/* @__PURE__ */ new Map());
806
- const [customTexts, setCustomTexts] = useState4(/* @__PURE__ */ new Map());
807
- const [usingCustom, setUsingCustom] = useState4(/* @__PURE__ */ new Set());
808
- const [submitted, setSubmitted] = useState4(false);
984
+ const [selections, setSelections] = useState5(/* @__PURE__ */ new Map());
985
+ const [customTexts, setCustomTexts] = useState5(/* @__PURE__ */ new Map());
986
+ const [usingCustom, setUsingCustom] = useState5(/* @__PURE__ */ new Set());
987
+ const [submitted, setSubmitted] = useState5(false);
809
988
  useEffect4(() => {
810
989
  if (sessionStatus === "failed" || sessionStatus === "interrupted") {
811
990
  setSubmitted(false);
@@ -903,7 +1082,7 @@ ${parts.join("\n")}`;
903
1082
  setSubmitted(true);
904
1083
  onAnswer(text, toolCallId, nextAnswerData);
905
1084
  };
906
- return /* @__PURE__ */ jsxs5(
1085
+ return /* @__PURE__ */ jsxs6(
907
1086
  "div",
908
1087
  {
909
1088
  className: cn(
@@ -911,12 +1090,12 @@ ${parts.join("\n")}`;
911
1090
  answered ? "max-w-2xl space-y-3 p-3 text-xs text-[hsl(var(--muted-foreground))] opacity-80" : "max-w-lg space-y-5 p-4 text-sm"
912
1091
  ),
913
1092
  children: [
914
- data.source_loop?.description && /* @__PURE__ */ jsxs5("div", { className: "rounded-lg bg-[hsl(var(--muted)/0.35)] px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]", children: [
1093
+ data.source_loop?.description && /* @__PURE__ */ jsxs6("div", { className: "rounded-lg bg-[hsl(var(--muted)/0.35)] px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]", children: [
915
1094
  "\u5B50\u667A\u80FD\u4F53\u300C",
916
1095
  data.source_loop.description,
917
1096
  "\u300D\u5728\u7B49\u5F85\u4F60\u7684\u56DE\u7B54"
918
1097
  ] }),
919
- data.questions.map((q, qIdx) => /* @__PURE__ */ jsx6(
1098
+ data.questions.map((q, qIdx) => /* @__PURE__ */ jsx7(
920
1099
  QuestionCard,
921
1100
  {
922
1101
  question: q,
@@ -931,7 +1110,7 @@ ${parts.join("\n")}`;
931
1110
  },
932
1111
  q.question
933
1112
  )),
934
- !answered && !submitted && onAnswer && /* @__PURE__ */ jsx6(
1113
+ !answered && !submitted && onAnswer && /* @__PURE__ */ jsx7(
935
1114
  "button",
936
1115
  {
937
1116
  type: "button",
@@ -941,14 +1120,14 @@ ${parts.join("\n")}`;
941
1120
  children: allAnswered ? "\u786E\u8BA4" : "\u8BF7\u5148\u9009\u62E9\u4E00\u4E2A\u9009\u9879"
942
1121
  }
943
1122
  ),
944
- submitted && !answered && /* @__PURE__ */ jsxs5(
1123
+ submitted && !answered && /* @__PURE__ */ jsxs6(
945
1124
  "button",
946
1125
  {
947
1126
  type: "button",
948
1127
  disabled: true,
949
1128
  className: "flex w-full items-center justify-center gap-2 rounded-lg bg-[hsl(var(--primary))] px-4 py-2 text-xs font-semibold text-[hsl(var(--primary-foreground))] opacity-80",
950
1129
  children: [
951
- /* @__PURE__ */ jsx6(Loader2, { size: 14, className: "animate-spin" }),
1130
+ /* @__PURE__ */ jsx7(Loader22, { size: 14, className: "animate-spin" }),
952
1131
  "\u786E\u8BA4\u4E2D"
953
1132
  ]
954
1133
  }
@@ -969,23 +1148,23 @@ function QuestionCard({
969
1148
  onCustomChange
970
1149
  }) {
971
1150
  const multi = question.multiSelect ?? false;
972
- return /* @__PURE__ */ jsxs5("div", { children: [
973
- /* @__PURE__ */ jsxs5("div", { className: cn("flex items-start gap-2", answered ? "mb-2" : "mb-3"), children: [
974
- /* @__PURE__ */ jsx6(
1151
+ return /* @__PURE__ */ jsxs6("div", { children: [
1152
+ /* @__PURE__ */ jsxs6("div", { className: cn("flex items-start gap-2", answered ? "mb-2" : "mb-3"), children: [
1153
+ /* @__PURE__ */ jsx7(
975
1154
  MessageSquareMore,
976
1155
  {
977
1156
  size: answered ? 12 : 13,
978
1157
  className: "mt-0.5 shrink-0 text-[hsl(var(--primary))]"
979
1158
  }
980
1159
  ),
981
- /* @__PURE__ */ jsx6(
1160
+ /* @__PURE__ */ jsx7(
982
1161
  "div",
983
1162
  {
984
1163
  className: cn(
985
1164
  "min-w-0 flex-1 font-medium text-[hsl(var(--foreground))]",
986
1165
  answered ? "text-xs" : "text-sm"
987
1166
  ),
988
- children: /* @__PURE__ */ jsx6(
1167
+ children: /* @__PURE__ */ jsx7(
989
1168
  MarkdownContent,
990
1169
  {
991
1170
  className: cn(
@@ -999,10 +1178,10 @@ function QuestionCard({
999
1178
  }
1000
1179
  )
1001
1180
  ] }),
1002
- /* @__PURE__ */ jsxs5("div", { className: cn("flex flex-col pl-5", answered ? "gap-1" : "gap-1.5"), children: [
1181
+ /* @__PURE__ */ jsxs6("div", { className: cn("flex flex-col pl-5", answered ? "gap-1" : "gap-1.5"), children: [
1003
1182
  question.options.map((opt, optIdx) => {
1004
1183
  const isSel = selected.has(optIdx);
1005
- return /* @__PURE__ */ jsxs5(
1184
+ return /* @__PURE__ */ jsxs6(
1006
1185
  "button",
1007
1186
  {
1008
1187
  type: "button",
@@ -1016,14 +1195,14 @@ function QuestionCard({
1016
1195
  answered && "cursor-default opacity-70"
1017
1196
  ),
1018
1197
  children: [
1019
- multi && /* @__PURE__ */ jsx6(
1198
+ multi && /* @__PURE__ */ jsx7(
1020
1199
  "div",
1021
1200
  {
1022
1201
  className: cn(
1023
1202
  "mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors",
1024
1203
  isSel && !answered ? "border-[hsl(var(--primary-foreground)/0.6)] bg-[hsl(var(--primary-foreground)/0.2)]" : isSel ? "border-[hsl(var(--primary)/0.45)] bg-[hsl(var(--primary)/0.12)]" : "border-[hsl(var(--border))]"
1025
1204
  ),
1026
- children: isSel && /* @__PURE__ */ jsx6(
1205
+ children: isSel && /* @__PURE__ */ jsx7(
1027
1206
  Check3,
1028
1207
  {
1029
1208
  size: 9,
@@ -1032,9 +1211,9 @@ function QuestionCard({
1032
1211
  )
1033
1212
  }
1034
1213
  ),
1035
- /* @__PURE__ */ jsxs5("div", { className: "min-w-0", children: [
1036
- /* @__PURE__ */ jsx6("div", { className: cn("font-medium", answered ? "text-xs" : "text-[13px]"), children: opt.label }),
1037
- opt.description && /* @__PURE__ */ jsx6(
1214
+ /* @__PURE__ */ jsxs6("div", { className: "min-w-0", children: [
1215
+ /* @__PURE__ */ jsx7("div", { className: cn("font-medium", answered ? "text-xs" : "text-[13px]"), children: opt.label }),
1216
+ opt.description && /* @__PURE__ */ jsx7(
1038
1217
  "div",
1039
1218
  {
1040
1219
  className: cn(
@@ -1051,7 +1230,7 @@ function QuestionCard({
1051
1230
  opt.label
1052
1231
  );
1053
1232
  }),
1054
- answered && !isCustom ? null : /* @__PURE__ */ jsxs5(
1233
+ answered && !isCustom ? null : /* @__PURE__ */ jsxs6(
1055
1234
  "div",
1056
1235
  {
1057
1236
  className: cn(
@@ -1061,8 +1240,8 @@ function QuestionCard({
1061
1240
  answered && "cursor-default opacity-70"
1062
1241
  ),
1063
1242
  children: [
1064
- /* @__PURE__ */ jsx6("span", { className: "shrink-0 text-xs text-[hsl(var(--muted-foreground))]", children: "\u5176\u4ED6\uFF1A" }),
1065
- /* @__PURE__ */ jsx6(
1243
+ /* @__PURE__ */ jsx7("span", { className: "shrink-0 text-xs text-[hsl(var(--muted-foreground))]", children: "\u5176\u4ED6\uFF1A" }),
1244
+ /* @__PURE__ */ jsx7(
1066
1245
  "input",
1067
1246
  {
1068
1247
  type: "text",
@@ -1485,8 +1664,8 @@ function extractRefs(content) {
1485
1664
 
1486
1665
  // src/react/components/plan/PlanSummaryCard.tsx
1487
1666
  import { CheckCircle2, ChevronRight, PencilLine, Play, Sparkles } from "lucide-react";
1488
- import { useMemo as useMemo4, useState as useState5 } from "react";
1489
- import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1667
+ import { useMemo as useMemo4, useState as useState6 } from "react";
1668
+ import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1490
1669
  function PlanSummaryCard({
1491
1670
  messages,
1492
1671
  sessionStatus,
@@ -1506,25 +1685,25 @@ function PlanSummaryCard({
1506
1685
  }
1507
1686
  setActiveRightTab("situation");
1508
1687
  };
1509
- return /* @__PURE__ */ jsxs6("div", { className: "flex w-full flex-col gap-4 rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card)/0.55)] p-4", children: [
1510
- /* @__PURE__ */ jsxs6(
1688
+ return /* @__PURE__ */ jsxs7("div", { className: "flex w-full flex-col gap-4 rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card)/0.55)] p-4", children: [
1689
+ /* @__PURE__ */ jsxs7(
1511
1690
  "button",
1512
1691
  {
1513
1692
  type: "button",
1514
1693
  onClick: openPlanPanel,
1515
1694
  className: "flex w-full flex-col gap-4 text-left transition-colors hover:text-[hsl(var(--foreground))]",
1516
1695
  children: [
1517
- /* @__PURE__ */ jsxs6("div", { className: "flex items-start justify-between gap-3", children: [
1518
- /* @__PURE__ */ jsxs6("div", { className: "min-w-0 space-y-2", children: [
1519
- /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]", children: [
1520
- /* @__PURE__ */ jsx7(Sparkles, { size: 12 }),
1521
- /* @__PURE__ */ jsx7("span", { children: "\u89C4\u5212\u6458\u8981" })
1696
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-start justify-between gap-3", children: [
1697
+ /* @__PURE__ */ jsxs7("div", { className: "min-w-0 space-y-2", children: [
1698
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]", children: [
1699
+ /* @__PURE__ */ jsx8(Sparkles, { size: 12 }),
1700
+ /* @__PURE__ */ jsx8("span", { children: "\u89C4\u5212\u6458\u8981" })
1522
1701
  ] }),
1523
- /* @__PURE__ */ jsx7("div", { className: "truncate text-base font-medium text-[hsl(var(--foreground))]", children: data.intent || "\u5F53\u524D\u89C4\u5212" }),
1524
- /* @__PURE__ */ jsx7("div", { className: "flex flex-wrap items-center gap-2 text-xs", children: summaryState.kind === "progress" ? /* @__PURE__ */ jsxs6(Fragment2, { children: [
1525
- /* @__PURE__ */ jsx7("span", { className: "rounded-full bg-[hsl(var(--accent))] px-2.5 py-1 text-[hsl(var(--foreground))]", children: summaryState.label }),
1526
- /* @__PURE__ */ jsx7("span", { className: "font-mono tracking-[0.25em] text-[hsl(var(--muted-foreground))]", children: summaryState.dots })
1527
- ] }) : /* @__PURE__ */ jsx7(
1702
+ /* @__PURE__ */ jsx8("div", { className: "truncate text-base font-medium text-[hsl(var(--foreground))]", children: data.intent || "\u5F53\u524D\u89C4\u5212" }),
1703
+ /* @__PURE__ */ jsx8("div", { className: "flex flex-wrap items-center gap-2 text-xs", children: summaryState.kind === "progress" ? /* @__PURE__ */ jsxs7(Fragment2, { children: [
1704
+ /* @__PURE__ */ jsx8("span", { className: "rounded-full bg-[hsl(var(--accent))] px-2.5 py-1 text-[hsl(var(--foreground))]", children: summaryState.label }),
1705
+ /* @__PURE__ */ jsx8("span", { className: "font-mono tracking-[0.25em] text-[hsl(var(--muted-foreground))]", children: summaryState.dots })
1706
+ ] }) : /* @__PURE__ */ jsx8(
1528
1707
  "span",
1529
1708
  {
1530
1709
  className: cn(
@@ -1537,7 +1716,7 @@ function PlanSummaryCard({
1537
1716
  }
1538
1717
  ) })
1539
1718
  ] }),
1540
- /* @__PURE__ */ jsx7(
1719
+ /* @__PURE__ */ jsx8(
1541
1720
  ChevronRight,
1542
1721
  {
1543
1722
  size: 16,
@@ -1546,31 +1725,31 @@ function PlanSummaryCard({
1546
1725
  }
1547
1726
  )
1548
1727
  ] }),
1549
- summaryState.kind === "complete" && /* @__PURE__ */ jsxs6("div", { className: "flex flex-wrap items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]", children: [
1550
- /* @__PURE__ */ jsxs6("span", { className: "rounded-full border border-[hsl(var(--border))] px-2.5 py-1", children: [
1728
+ summaryState.kind === "complete" && /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]", children: [
1729
+ /* @__PURE__ */ jsxs7("span", { className: "rounded-full border border-[hsl(var(--border))] px-2.5 py-1", children: [
1551
1730
  data.selectedSkills.length,
1552
1731
  " \u4E2A\u6280\u80FD"
1553
1732
  ] }),
1554
- /* @__PURE__ */ jsxs6("span", { className: "rounded-full border border-[hsl(var(--border))] px-2.5 py-1", children: [
1733
+ /* @__PURE__ */ jsxs7("span", { className: "rounded-full border border-[hsl(var(--border))] px-2.5 py-1", children: [
1555
1734
  stepCount,
1556
1735
  " \u4E2A\u6B65\u9AA4"
1557
1736
  ] }),
1558
- /* @__PURE__ */ jsxs6("span", { className: "inline-flex items-center gap-1 text-[hsl(var(--muted-foreground))]", children: [
1559
- /* @__PURE__ */ jsx7(CheckCircle2, { size: 12 }),
1737
+ /* @__PURE__ */ jsxs7("span", { className: "inline-flex items-center gap-1 text-[hsl(var(--muted-foreground))]", children: [
1738
+ /* @__PURE__ */ jsx8(CheckCircle2, { size: 12 }),
1560
1739
  "\u53F3\u4FA7\u67E5\u770B\u8BE6\u60C5"
1561
1740
  ] })
1562
1741
  ] })
1563
1742
  ]
1564
1743
  }
1565
1744
  ),
1566
- canConfirm && /* @__PURE__ */ jsx7(PlanConfirmationPanel, { onConfirmPlan })
1745
+ canConfirm && /* @__PURE__ */ jsx8(PlanConfirmationPanel, { onConfirmPlan })
1567
1746
  ] });
1568
1747
  }
1569
1748
  function PlanConfirmationPanel({
1570
1749
  onConfirmPlan
1571
1750
  }) {
1572
- const [isEditing, setIsEditing] = useState5(false);
1573
- const [revisionText, setRevisionText] = useState5("");
1751
+ const [isEditing, setIsEditing] = useState6(false);
1752
+ const [revisionText, setRevisionText] = useState6("");
1574
1753
  const submitRevision = () => {
1575
1754
  const trimmed = revisionText.trim();
1576
1755
  if (!trimmed) return;
@@ -1578,35 +1757,35 @@ function PlanConfirmationPanel({
1578
1757
  setRevisionText("");
1579
1758
  setIsEditing(false);
1580
1759
  };
1581
- return /* @__PURE__ */ jsxs6("div", { className: "space-y-3 rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--background)/0.45)] p-3", children: [
1582
- /* @__PURE__ */ jsxs6("div", { className: "flex flex-wrap gap-2", children: [
1583
- /* @__PURE__ */ jsxs6(
1760
+ return /* @__PURE__ */ jsxs7("div", { className: "space-y-3 rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--background)/0.45)] p-3", children: [
1761
+ /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap gap-2", children: [
1762
+ /* @__PURE__ */ jsxs7(
1584
1763
  "button",
1585
1764
  {
1586
1765
  type: "button",
1587
1766
  onClick: () => onConfirmPlan?.("execute"),
1588
1767
  className: "inline-flex items-center gap-1.5 rounded-lg bg-[hsl(var(--primary))] px-3 py-2 text-sm font-medium text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90",
1589
1768
  children: [
1590
- /* @__PURE__ */ jsx7(Play, { size: 14 }),
1769
+ /* @__PURE__ */ jsx8(Play, { size: 14 }),
1591
1770
  "\u5F00\u59CB\u6267\u884C"
1592
1771
  ]
1593
1772
  }
1594
1773
  ),
1595
- /* @__PURE__ */ jsxs6(
1774
+ /* @__PURE__ */ jsxs7(
1596
1775
  "button",
1597
1776
  {
1598
1777
  type: "button",
1599
1778
  onClick: () => setIsEditing((value) => !value),
1600
1779
  className: "inline-flex items-center gap-1.5 rounded-lg border border-[hsl(var(--border))] px-3 py-2 text-sm text-[hsl(var(--foreground))] transition-colors hover:bg-[hsl(var(--accent))]",
1601
1780
  children: [
1602
- /* @__PURE__ */ jsx7(PencilLine, { size: 14 }),
1781
+ /* @__PURE__ */ jsx8(PencilLine, { size: 14 }),
1603
1782
  "\u4FEE\u6539"
1604
1783
  ]
1605
1784
  }
1606
1785
  )
1607
1786
  ] }),
1608
- isEditing && /* @__PURE__ */ jsxs6("div", { className: "space-y-2", children: [
1609
- /* @__PURE__ */ jsx7(
1787
+ isEditing && /* @__PURE__ */ jsxs7("div", { className: "space-y-2", children: [
1788
+ /* @__PURE__ */ jsx8(
1610
1789
  "textarea",
1611
1790
  {
1612
1791
  value: revisionText,
@@ -1615,7 +1794,7 @@ function PlanConfirmationPanel({
1615
1794
  className: "min-h-24 w-full resize-y rounded-lg border border-[hsl(var(--border))] bg-transparent px-3 py-2 text-sm text-[hsl(var(--foreground))] outline-none placeholder:text-[hsl(var(--muted-foreground))]"
1616
1795
  }
1617
1796
  ),
1618
- /* @__PURE__ */ jsx7("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx7(
1797
+ /* @__PURE__ */ jsx8("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx8(
1619
1798
  "button",
1620
1799
  {
1621
1800
  type: "button",
@@ -1728,4 +1907,4 @@ export {
1728
1907
  PlanSummaryCard,
1729
1908
  extractLatestPlanMessages
1730
1909
  };
1731
- //# sourceMappingURL=chunk-ER4RLUJW.js.map
1910
+ //# sourceMappingURL=chunk-LI3WURWU.js.map