@surf-kit/agent 0.1.1 → 0.2.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.
Files changed (74) hide show
  1. package/README.md +19 -1
  2. package/dist/agent-BNSmiexZ.d.cts +44 -0
  3. package/dist/agent-BNSmiexZ.d.ts +44 -0
  4. package/dist/agent-identity/index.cjs +157 -0
  5. package/dist/agent-identity/index.cjs.map +1 -0
  6. package/dist/agent-identity/index.d.cts +35 -0
  7. package/dist/agent-identity/index.d.ts +35 -0
  8. package/dist/agent-identity/index.js +127 -0
  9. package/dist/agent-identity/index.js.map +1 -0
  10. package/dist/chat/index.cjs +1281 -0
  11. package/dist/chat/index.cjs.map +1 -0
  12. package/dist/chat/index.d.cts +72 -0
  13. package/dist/chat/index.d.ts +72 -0
  14. package/dist/chat/index.js +1239 -0
  15. package/dist/chat/index.js.map +1 -0
  16. package/dist/chat--OifhIRe.d.ts +24 -0
  17. package/dist/chat-ChYl2XjV.d.cts +24 -0
  18. package/dist/confidence/index.cjs +253 -0
  19. package/dist/confidence/index.cjs.map +1 -0
  20. package/dist/confidence/index.d.cts +40 -0
  21. package/dist/confidence/index.d.ts +40 -0
  22. package/dist/confidence/index.js +222 -0
  23. package/dist/confidence/index.js.map +1 -0
  24. package/dist/feedback/index.cjs +186 -0
  25. package/dist/feedback/index.cjs.map +1 -0
  26. package/dist/feedback/index.d.cts +27 -0
  27. package/dist/feedback/index.d.ts +27 -0
  28. package/dist/feedback/index.js +157 -0
  29. package/dist/feedback/index.js.map +1 -0
  30. package/dist/{hooks-B8CSeOsn.d.cts → hooks-BGs8-4GK.d.ts} +4 -99
  31. package/dist/{hooks-B8CSeOsn.d.ts → hooks-DLfF18IU.d.cts} +4 -99
  32. package/dist/hooks.d.cts +4 -1
  33. package/dist/hooks.d.ts +4 -1
  34. package/dist/index-BazLnae1.d.cts +67 -0
  35. package/dist/index-BazLnae1.d.ts +67 -0
  36. package/dist/index.cjs +889 -144
  37. package/dist/index.cjs.map +1 -1
  38. package/dist/index.d.cts +15 -321
  39. package/dist/index.d.ts +15 -321
  40. package/dist/index.js +879 -142
  41. package/dist/index.js.map +1 -1
  42. package/dist/layouts/index.cjs +1588 -0
  43. package/dist/layouts/index.cjs.map +1 -0
  44. package/dist/layouts/index.d.cts +46 -0
  45. package/dist/layouts/index.d.ts +46 -0
  46. package/dist/layouts/index.js +1548 -0
  47. package/dist/layouts/index.js.map +1 -0
  48. package/dist/mcp/index.cjs +522 -0
  49. package/dist/mcp/index.cjs.map +1 -0
  50. package/dist/mcp/index.d.cts +2 -0
  51. package/dist/mcp/index.d.ts +2 -0
  52. package/dist/mcp/index.js +492 -0
  53. package/dist/mcp/index.js.map +1 -0
  54. package/dist/response/index.cjs +519 -0
  55. package/dist/response/index.cjs.map +1 -0
  56. package/dist/response/index.d.cts +44 -0
  57. package/dist/response/index.d.ts +44 -0
  58. package/dist/response/index.js +478 -0
  59. package/dist/response/index.js.map +1 -0
  60. package/dist/sources/index.cjs +243 -0
  61. package/dist/sources/index.cjs.map +1 -0
  62. package/dist/sources/index.d.cts +44 -0
  63. package/dist/sources/index.d.ts +44 -0
  64. package/dist/sources/index.js +212 -0
  65. package/dist/sources/index.js.map +1 -0
  66. package/dist/streaming/index.cjs +531 -0
  67. package/dist/streaming/index.cjs.map +1 -0
  68. package/dist/streaming/index.d.cts +81 -0
  69. package/dist/streaming/index.d.ts +81 -0
  70. package/dist/streaming/index.js +495 -0
  71. package/dist/streaming/index.js.map +1 -0
  72. package/dist/streaming-DbQxScpi.d.ts +39 -0
  73. package/dist/streaming-DfT22A0z.d.cts +39 -0
  74. package/package.json +62 -17
package/dist/index.js CHANGED
@@ -583,7 +583,7 @@ function FollowUpChips({ suggestions, onSelect, className }) {
583
583
  return /* @__PURE__ */ jsx5(
584
584
  "div",
585
585
  {
586
- className: `flex gap-2 overflow-x-auto py-1 ${className ?? ""}`,
586
+ className: twMerge3("flex flex-wrap gap-2 py-1", className),
587
587
  role: "group",
588
588
  "aria-label": "Follow-up suggestions",
589
589
  "data-testid": "follow-up-chips",
@@ -593,9 +593,9 @@ function FollowUpChips({ suggestions, onSelect, className }) {
593
593
  type: "button",
594
594
  onClick: () => onSelect(suggestion),
595
595
  className: twMerge3(
596
- "px-4 py-1.5 rounded-full text-sm shrink-0 whitespace-nowrap",
597
- "border border-border bg-surface text-text-primary",
598
- "hover:bg-surface-raised hover:border-interactive hover:text-text-primary",
596
+ "px-4 py-1.5 rounded-full text-sm whitespace-nowrap",
597
+ "border border-border bg-transparent text-text-secondary",
598
+ "hover:bg-accent/10 hover:border-interactive hover:text-text-primary",
599
599
  "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
600
600
  "transition-all duration-200"
601
601
  ),
@@ -698,6 +698,7 @@ function MessageBubble({
698
698
  showSources = true,
699
699
  showConfidence = true,
700
700
  showVerification = true,
701
+ animated = true,
701
702
  className
702
703
  }) {
703
704
  const isUser = message.role === "user";
@@ -707,7 +708,16 @@ function MessageBubble({
707
708
  {
708
709
  "data-message-id": message.id,
709
710
  className: twMerge4("flex w-full justify-end", className),
710
- children: /* @__PURE__ */ jsx7("div", { className: "max-w-[75%] rounded-[18px] rounded-br-[4px] px-4 py-2.5 bg-accent text-white whitespace-pre-wrap text-sm leading-relaxed", children: message.content })
711
+ children: /* @__PURE__ */ jsx7(
712
+ "div",
713
+ {
714
+ className: twMerge4(
715
+ "max-w-[70%] rounded-[18px] rounded-br-[4px] px-4 py-2.5 bg-accent text-brand-cream break-words whitespace-pre-wrap text-sm leading-relaxed",
716
+ animated && "motion-safe:animate-slideFromRight"
717
+ ),
718
+ children: message.content
719
+ }
720
+ )
711
721
  }
712
722
  );
713
723
  }
@@ -717,16 +727,25 @@ function MessageBubble({
717
727
  "data-message-id": message.id,
718
728
  className: twMerge4("flex w-full flex-col items-start gap-1.5", className),
719
729
  children: [
720
- showAgent && message.agent && /* @__PURE__ */ jsx7("div", { className: "text-[11px] font-medium uppercase tracking-[0.08em] text-text-secondary px-1", children: message.agent.replace("_agent", "").replace("_", " ") }),
721
- /* @__PURE__ */ jsx7("div", { className: "max-w-[88%] rounded-[18px] rounded-tl-[4px] px-4 py-3 bg-surface-raised border border-border", children: message.response ? /* @__PURE__ */ jsx7(
722
- AgentResponse,
730
+ showAgent && message.agent && /* @__PURE__ */ jsx7("div", { className: "text-[11px] font-semibold uppercase tracking-[0.08em] text-text-muted px-1", children: message.agent.replace("_agent", "").replace("_", " ") }),
731
+ /* @__PURE__ */ jsx7(
732
+ "div",
723
733
  {
724
- response: message.response,
725
- showSources,
726
- showConfidence,
727
- showVerification
734
+ className: twMerge4(
735
+ "max-w-[88%] rounded-[18px] rounded-tl-[4px] px-4 py-3 bg-surface border border-border",
736
+ animated && "motion-safe:animate-springFromLeft"
737
+ ),
738
+ children: message.response ? /* @__PURE__ */ jsx7(
739
+ AgentResponse,
740
+ {
741
+ response: message.response,
742
+ showSources,
743
+ showConfidence,
744
+ showVerification
745
+ }
746
+ ) : /* @__PURE__ */ jsx7(ResponseMessage, { content: message.content })
728
747
  }
729
- ) : /* @__PURE__ */ jsx7(ResponseMessage, { content: message.content }) })
748
+ )
730
749
  ]
731
750
  }
732
751
  );
@@ -780,12 +799,20 @@ function MessageComposer({
780
799
  const [value, setValue] = useState2("");
781
800
  const textareaRef = useRef3(null);
782
801
  const canSend = value.trim().length > 0 && !isLoading;
802
+ const resetHeight = useCallback2(() => {
803
+ const el = textareaRef.current;
804
+ if (el) {
805
+ el.style.height = "auto";
806
+ el.style.overflowY = "hidden";
807
+ }
808
+ }, []);
783
809
  const handleSend = useCallback2(() => {
784
810
  if (!canSend) return;
785
811
  onSend(value.trim());
786
812
  setValue("");
813
+ resetHeight();
787
814
  textareaRef.current?.focus();
788
- }, [canSend, onSend, value]);
815
+ }, [canSend, onSend, value, resetHeight]);
789
816
  const handleKeyDown = useCallback2(
790
817
  (e) => {
791
818
  if (e.key === "Enter" && !e.shiftKey) {
@@ -795,11 +822,22 @@ function MessageComposer({
795
822
  },
796
823
  [handleSend]
797
824
  );
825
+ const handleChange = useCallback2(
826
+ (e) => {
827
+ setValue(e.target.value);
828
+ const el = e.target;
829
+ el.style.height = "auto";
830
+ const capped = Math.min(el.scrollHeight, 128);
831
+ el.style.height = `${capped}px`;
832
+ el.style.overflowY = el.scrollHeight > 128 ? "auto" : "hidden";
833
+ },
834
+ []
835
+ );
798
836
  return /* @__PURE__ */ jsxs7(
799
837
  "div",
800
838
  {
801
839
  className: twMerge6(
802
- "flex items-end gap-3 border-t border-border px-4 py-3 bg-canvas",
840
+ "flex items-end gap-3 shrink-0 border-t border-border px-4 py-3",
803
841
  className
804
842
  ),
805
843
  children: [
@@ -808,16 +846,17 @@ function MessageComposer({
808
846
  {
809
847
  ref: textareaRef,
810
848
  value,
811
- onChange: (e) => setValue(e.target.value),
849
+ onChange: handleChange,
812
850
  onKeyDown: handleKeyDown,
813
851
  placeholder,
814
852
  rows: 1,
815
853
  disabled: isLoading,
816
854
  className: twMerge6(
817
- "flex-1 resize-none rounded-xl border border-border bg-surface",
855
+ "flex-1 resize-none rounded-xl border border-border bg-surface/80",
818
856
  "px-4 py-2.5 text-sm text-text-primary placeholder:text-text-muted",
819
857
  "focus:border-transparent focus:ring-2 focus:ring-accent/40 focus:outline-none",
820
858
  "disabled:opacity-50 disabled:cursor-not-allowed",
859
+ "overflow-hidden",
821
860
  "transition-all duration-200"
822
861
  ),
823
862
  style: { colorScheme: "dark" },
@@ -836,7 +875,7 @@ function MessageComposer({
836
875
  "text-sm font-semibold text-white shrink-0",
837
876
  "transition-all duration-200",
838
877
  "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
839
- value.trim() && !isLoading ? "bg-accent hover:bg-accent-hover hover:scale-[1.02] active:scale-[0.98]" : "bg-accent/30 text-text-muted cursor-not-allowed"
878
+ value.trim() && !isLoading ? "bg-accent hover:bg-accent-hover hover:scale-[1.02] hover:shadow-glow-cyan active:scale-[0.98]" : "bg-accent/30 text-text-muted cursor-not-allowed"
840
879
  ),
841
880
  children: "Send"
842
881
  }
@@ -852,6 +891,7 @@ import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
852
891
  function WelcomeScreen({
853
892
  title = "Welcome",
854
893
  message = "How can I help you today?",
894
+ icon,
855
895
  suggestedQuestions = [],
856
896
  onQuestionSelect,
857
897
  className
@@ -860,7 +900,7 @@ function WelcomeScreen({
860
900
  "div",
861
901
  {
862
902
  className: twMerge7(
863
- "flex flex-1 flex-col items-center justify-center gap-8 p-8 text-center",
903
+ "flex flex-1 flex-col items-center justify-center gap-8 p-8 text-center motion-safe:animate-fadeUp",
864
904
  className
865
905
  ),
866
906
  children: [
@@ -869,12 +909,12 @@ function WelcomeScreen({
869
909
  {
870
910
  className: "w-14 h-14 rounded-2xl bg-accent/10 border border-border flex items-center justify-center pulse-glow",
871
911
  "aria-hidden": "true",
872
- children: /* @__PURE__ */ jsx10("span", { className: "text-2xl", children: "\u2726" })
912
+ children: icon ?? /* @__PURE__ */ jsx10("span", { className: "text-2xl", children: "\u2726" })
873
913
  }
874
914
  ),
875
915
  /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-2", children: [
876
- title && /* @__PURE__ */ jsx10("h2", { className: "text-2xl font-semibold text-text-primary", children: title }),
877
- /* @__PURE__ */ jsx10("p", { className: "text-text-secondary text-base leading-relaxed max-w-sm", children: message })
916
+ title && /* @__PURE__ */ jsx10("h2", { className: "text-3xl font-bold text-text-primary", children: title }),
917
+ /* @__PURE__ */ jsx10("p", { className: "text-text-secondary text-base leading-relaxed max-w-md", children: message })
878
918
  ] }),
879
919
  suggestedQuestions.length > 0 && /* @__PURE__ */ jsx10(
880
920
  "div",
@@ -889,8 +929,8 @@ function WelcomeScreen({
889
929
  onClick: () => onQuestionSelect?.(question),
890
930
  className: twMerge7(
891
931
  "px-4 py-2 rounded-full text-sm",
892
- "border border-border bg-surface text-text-primary",
893
- "hover:bg-surface-raised hover:border-interactive hover:text-text-primary",
932
+ "border border-border bg-transparent text-text-secondary",
933
+ "hover:bg-accent/10 hover:border-interactive hover:text-text-primary",
894
934
  "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
895
935
  "transition-colors duration-200"
896
936
  ),
@@ -975,11 +1015,11 @@ function useCharacterDrain(target, msPerChar = 15) {
975
1015
  import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
976
1016
  var phaseLabels = {
977
1017
  idle: "",
978
- waiting: "Waiting",
979
- thinking: "Thinking",
980
- retrieving: "Searching",
981
- generating: "Writing",
982
- verifying: "Verifying"
1018
+ waiting: "Waiting...",
1019
+ thinking: "Thinking...",
1020
+ retrieving: "Searching...",
1021
+ generating: "Writing...",
1022
+ verifying: "Verifying..."
983
1023
  };
984
1024
  function StreamingMessage({
985
1025
  stream,
@@ -1003,27 +1043,29 @@ function StreamingMessage({
1003
1043
  stream.active && stream.phase !== "idle" && "Response started",
1004
1044
  !stream.active && stream.content && "Response complete"
1005
1045
  ] }),
1006
- showPhases && stream.active && stream.phase !== "idle" && /* @__PURE__ */ jsxs9(
1007
- "div",
1008
- {
1009
- className: "flex items-center gap-2 mb-2 text-sm text-text-secondary",
1010
- "data-testid": "phase-indicator",
1011
- children: [
1012
- /* @__PURE__ */ jsx11("span", { "aria-hidden": "true", children: /* @__PURE__ */ jsx11(Spinner, { size: "sm" }) }),
1013
- /* @__PURE__ */ jsx11("span", { children: phaseLabel })
1014
- ]
1015
- }
1016
- ),
1017
- /* @__PURE__ */ jsxs9("div", { className: "text-text-primary whitespace-pre-wrap", children: [
1018
- displayedContent,
1019
- stream.active && /* @__PURE__ */ jsx11(
1020
- "span",
1046
+ /* @__PURE__ */ jsxs9("div", { className: "max-w-[88%] px-4 py-3 rounded-[18px] rounded-tl-[4px] bg-surface border border-border motion-safe:animate-springFromLeft", children: [
1047
+ showPhases && stream.active && stream.phase !== "idle" && /* @__PURE__ */ jsxs9(
1048
+ "div",
1021
1049
  {
1022
- className: "inline-block w-0.5 h-4 bg-accent align-text-bottom animate-pulse ml-0.5",
1023
- "aria-hidden": "true",
1024
- "data-testid": "streaming-cursor"
1050
+ className: "flex items-center gap-2 mb-2 text-sm text-text-secondary",
1051
+ "data-testid": "phase-indicator",
1052
+ children: [
1053
+ /* @__PURE__ */ jsx11("span", { "aria-hidden": "true", children: /* @__PURE__ */ jsx11(Spinner, { size: "sm" }) }),
1054
+ /* @__PURE__ */ jsx11("span", { children: phaseLabel })
1055
+ ]
1025
1056
  }
1026
- )
1057
+ ),
1058
+ /* @__PURE__ */ jsxs9("div", { className: "text-sm leading-relaxed text-text-primary whitespace-pre-wrap", children: [
1059
+ displayedContent,
1060
+ stream.active && /* @__PURE__ */ jsx11(
1061
+ "span",
1062
+ {
1063
+ className: "inline-block w-0.5 h-4 bg-accent align-text-bottom animate-pulse ml-0.5",
1064
+ "aria-hidden": "true",
1065
+ "data-testid": "streaming-cursor"
1066
+ }
1067
+ )
1068
+ ] })
1027
1069
  ] })
1028
1070
  ] });
1029
1071
  }
@@ -1542,7 +1584,7 @@ function ThinkingIndicator({ label = "Thinking...", className }) {
1542
1584
  "span",
1543
1585
  {
1544
1586
  role: "status",
1545
- className: `inline-flex items-center gap-2 text-sm ${className ?? ""}`,
1587
+ className: `inline-flex items-center gap-2 text-sm motion-safe:animate-fadeSlideUpSm ${className ?? ""}`,
1546
1588
  "data-testid": "thinking-indicator",
1547
1589
  children: [
1548
1590
  /* @__PURE__ */ jsx25("span", { className: "text-text-secondary", children: label }),
@@ -1690,9 +1732,210 @@ function TypewriterText({
1690
1732
  ] });
1691
1733
  }
1692
1734
 
1693
- // src/chat/ConversationList/ConversationList.tsx
1735
+ // src/streaming/TypingIndicator/TypingIndicator.tsx
1694
1736
  import { twMerge as twMerge9 } from "tailwind-merge";
1737
+ import { useReducedMotion as useReducedMotion2 } from "@surf-kit/hooks";
1695
1738
  import { jsx as jsx30, jsxs as jsxs27 } from "react/jsx-runtime";
1739
+ var bounceKeyframes = `
1740
+ @keyframes typing-bounce {
1741
+ 0%, 80%, 100% { transform: translateY(0); }
1742
+ 40% { transform: translateY(-6px); }
1743
+ }
1744
+ `;
1745
+ function TypingIndicator({
1746
+ label,
1747
+ dotCount = 3,
1748
+ className
1749
+ }) {
1750
+ const reducedMotion = useReducedMotion2();
1751
+ return /* @__PURE__ */ jsxs27(
1752
+ "span",
1753
+ {
1754
+ role: "status",
1755
+ "aria-label": label ?? "typing",
1756
+ className: twMerge9("inline-flex items-center gap-2", className),
1757
+ "data-testid": "typing-indicator",
1758
+ children: [
1759
+ !reducedMotion && /* @__PURE__ */ jsx30("style", { children: bounceKeyframes }),
1760
+ label && /* @__PURE__ */ jsx30("span", { className: "text-sm text-text-secondary", children: label }),
1761
+ /* @__PURE__ */ jsx30("span", { className: "flex gap-1", "data-testid": "typing-dots", children: Array.from({ length: dotCount }, (_, i) => /* @__PURE__ */ jsx30(
1762
+ "span",
1763
+ {
1764
+ className: "w-2 h-2 rounded-full bg-text-secondary",
1765
+ style: reducedMotion ? void 0 : {
1766
+ animation: "typing-bounce 1.4s infinite ease-in-out",
1767
+ animationDelay: `${i * 160}ms`
1768
+ }
1769
+ },
1770
+ i
1771
+ )) })
1772
+ ]
1773
+ }
1774
+ );
1775
+ }
1776
+
1777
+ // src/streaming/TextGlimmer/TextGlimmer.tsx
1778
+ import { twMerge as twMerge10 } from "tailwind-merge";
1779
+ import { useReducedMotion as useReducedMotion3 } from "@surf-kit/hooks";
1780
+ import { jsx as jsx31, jsxs as jsxs28 } from "react/jsx-runtime";
1781
+ var shimmerKeyframes = `
1782
+ @keyframes text-shimmer {
1783
+ 0% { background-position: 200% 0; }
1784
+ 100% { background-position: -200% 0; }
1785
+ }
1786
+ `;
1787
+ var widthPattern = ["100%", "90%", "60%"];
1788
+ function TextGlimmer({ lines = 3, className }) {
1789
+ const reducedMotion = useReducedMotion3();
1790
+ return /* @__PURE__ */ jsxs28(
1791
+ "div",
1792
+ {
1793
+ role: "status",
1794
+ "aria-label": "Loading",
1795
+ className: twMerge10("flex flex-col gap-2", className),
1796
+ "data-testid": "text-glimmer",
1797
+ children: [
1798
+ !reducedMotion && /* @__PURE__ */ jsx31("style", { children: shimmerKeyframes }),
1799
+ Array.from({ length: lines }, (_, i) => /* @__PURE__ */ jsx31(
1800
+ "div",
1801
+ {
1802
+ className: "h-3 rounded bg-surface-raised",
1803
+ style: {
1804
+ width: widthPattern[i % widthPattern.length],
1805
+ ...reducedMotion ? void 0 : {
1806
+ backgroundImage: "linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent)",
1807
+ backgroundSize: "200% 100%",
1808
+ animation: "text-shimmer 1.5s infinite ease-in-out"
1809
+ }
1810
+ },
1811
+ "data-testid": "glimmer-line"
1812
+ },
1813
+ i
1814
+ ))
1815
+ ]
1816
+ }
1817
+ );
1818
+ }
1819
+
1820
+ // src/streaming/StreamingList/StreamingList.tsx
1821
+ import { twMerge as twMerge11 } from "tailwind-merge";
1822
+ import { useReducedMotion as useReducedMotion4 } from "@surf-kit/hooks";
1823
+ import { jsx as jsx32, jsxs as jsxs29 } from "react/jsx-runtime";
1824
+ var fadeSlideInKeyframes = `
1825
+ @keyframes fadeSlideIn {
1826
+ from { opacity: 0; transform: translateY(8px); }
1827
+ to { opacity: 1; transform: translateY(0); }
1828
+ }
1829
+ `;
1830
+ function StreamingList({
1831
+ items,
1832
+ renderItem,
1833
+ isStreaming = false,
1834
+ className,
1835
+ emptyMessage
1836
+ }) {
1837
+ const reducedMotion = useReducedMotion4();
1838
+ if (items.length === 0 && !isStreaming) {
1839
+ return emptyMessage ? /* @__PURE__ */ jsx32("p", { className: twMerge11("text-sm text-text-secondary", className), "data-testid": "streaming-list-empty", children: emptyMessage }) : null;
1840
+ }
1841
+ return /* @__PURE__ */ jsxs29(
1842
+ "ul",
1843
+ {
1844
+ "aria-live": "polite",
1845
+ className: twMerge11("list-none p-0 m-0", className),
1846
+ "data-testid": "streaming-list",
1847
+ children: [
1848
+ !reducedMotion && /* @__PURE__ */ jsx32("style", { children: fadeSlideInKeyframes }),
1849
+ items.map((item, index) => /* @__PURE__ */ jsx32(
1850
+ "li",
1851
+ {
1852
+ style: reducedMotion ? void 0 : { animation: "fadeSlideIn 0.3s ease-out" },
1853
+ "data-testid": "streaming-list-item",
1854
+ children: renderItem(item, index)
1855
+ },
1856
+ index
1857
+ )),
1858
+ isStreaming && /* @__PURE__ */ jsx32("li", { "data-testid": "streaming-list-loading", children: /* @__PURE__ */ jsx32(TypingIndicator, {}) })
1859
+ ]
1860
+ }
1861
+ );
1862
+ }
1863
+
1864
+ // src/streaming/StreamingStructure/StreamingStructure.tsx
1865
+ import { twMerge as twMerge12 } from "tailwind-merge";
1866
+ import { useReducedMotion as useReducedMotion5 } from "@surf-kit/hooks";
1867
+ import { jsx as jsx33, jsxs as jsxs30 } from "react/jsx-runtime";
1868
+ var fadeSlideInKeyframes2 = `
1869
+ @keyframes fadeSlideIn {
1870
+ from { opacity: 0; transform: translateY(8px); }
1871
+ to { opacity: 1; transform: translateY(0); }
1872
+ }
1873
+ `;
1874
+ function renderValue(value, reducedMotion) {
1875
+ if (value === null) {
1876
+ return /* @__PURE__ */ jsx33("span", { className: "italic text-text-secondary", children: "null" });
1877
+ }
1878
+ if (value === void 0) {
1879
+ return /* @__PURE__ */ jsx33("span", { className: "italic text-text-secondary", children: "undefined" });
1880
+ }
1881
+ if (Array.isArray(value)) {
1882
+ return /* @__PURE__ */ jsx33("ol", { className: "list-decimal pl-4 m-0", children: value.map((item, i) => /* @__PURE__ */ jsx33("li", { className: "text-text-secondary text-sm", children: renderValue(item, reducedMotion) }, i)) });
1883
+ }
1884
+ if (typeof value === "object") {
1885
+ return renderNestedDl(value, reducedMotion);
1886
+ }
1887
+ return String(value);
1888
+ }
1889
+ function renderNestedDl(data, reducedMotion) {
1890
+ const entries = Object.entries(data);
1891
+ return /* @__PURE__ */ jsx33("dl", { className: "pl-4 m-0", "data-testid": "streaming-structure-nested", children: entries.map(([key, value]) => /* @__PURE__ */ jsxs30(
1892
+ "div",
1893
+ {
1894
+ style: reducedMotion ? void 0 : { animation: "fadeSlideIn 0.3s ease-out" },
1895
+ children: [
1896
+ /* @__PURE__ */ jsx33("dt", { className: "font-medium text-text-primary text-sm", children: key }),
1897
+ /* @__PURE__ */ jsx33("dd", { className: "text-text-secondary text-sm ml-0 mb-3", children: renderValue(value, reducedMotion) })
1898
+ ]
1899
+ },
1900
+ key
1901
+ )) });
1902
+ }
1903
+ function StreamingStructure({
1904
+ data,
1905
+ isStreaming = false,
1906
+ className
1907
+ }) {
1908
+ const reducedMotion = useReducedMotion5();
1909
+ const entries = Object.entries(data);
1910
+ return /* @__PURE__ */ jsxs30(
1911
+ "dl",
1912
+ {
1913
+ "aria-live": "polite",
1914
+ className: twMerge12("m-0", className),
1915
+ "data-testid": "streaming-structure",
1916
+ children: [
1917
+ !reducedMotion && /* @__PURE__ */ jsx33("style", { children: fadeSlideInKeyframes2 }),
1918
+ entries.map(([key, value]) => /* @__PURE__ */ jsxs30(
1919
+ "div",
1920
+ {
1921
+ style: reducedMotion ? void 0 : { animation: "fadeSlideIn 0.3s ease-out" },
1922
+ "data-testid": "streaming-structure-entry",
1923
+ children: [
1924
+ /* @__PURE__ */ jsx33("dt", { className: "font-medium text-text-primary text-sm", children: key }),
1925
+ /* @__PURE__ */ jsx33("dd", { className: "text-text-secondary text-sm ml-0 mb-3", children: renderValue(value, reducedMotion) })
1926
+ ]
1927
+ },
1928
+ key
1929
+ )),
1930
+ isStreaming && /* @__PURE__ */ jsx33("div", { "data-testid": "streaming-structure-loading", children: /* @__PURE__ */ jsx33(TextGlimmer, { lines: 1 }) })
1931
+ ]
1932
+ }
1933
+ );
1934
+ }
1935
+
1936
+ // src/chat/ConversationList/ConversationList.tsx
1937
+ import { twMerge as twMerge13 } from "tailwind-merge";
1938
+ import { jsx as jsx34, jsxs as jsxs31 } from "react/jsx-runtime";
1696
1939
  function ConversationList({
1697
1940
  conversations,
1698
1941
  activeId,
@@ -1701,13 +1944,13 @@ function ConversationList({
1701
1944
  onNew,
1702
1945
  className
1703
1946
  }) {
1704
- return /* @__PURE__ */ jsxs27(
1947
+ return /* @__PURE__ */ jsxs31(
1705
1948
  "nav",
1706
1949
  {
1707
1950
  "aria-label": "Conversation list",
1708
- className: twMerge9("flex flex-col h-full bg-canvas", className),
1951
+ className: twMerge13("flex flex-col h-full bg-canvas", className),
1709
1952
  children: [
1710
- onNew && /* @__PURE__ */ jsx30("div", { className: "p-3 border-b border-border", children: /* @__PURE__ */ jsx30(
1953
+ onNew && /* @__PURE__ */ jsx34("div", { className: "p-3 border-b border-border", children: /* @__PURE__ */ jsx34(
1711
1954
  "button",
1712
1955
  {
1713
1956
  type: "button",
@@ -1716,19 +1959,19 @@ function ConversationList({
1716
1959
  children: "New conversation"
1717
1960
  }
1718
1961
  ) }),
1719
- /* @__PURE__ */ jsxs27("ul", { role: "list", className: "flex-1 overflow-y-auto", children: [
1962
+ /* @__PURE__ */ jsxs31("ul", { role: "list", className: "flex-1 overflow-y-auto", children: [
1720
1963
  conversations.map((conversation) => {
1721
1964
  const isActive = conversation.id === activeId;
1722
- return /* @__PURE__ */ jsxs27(
1965
+ return /* @__PURE__ */ jsxs31(
1723
1966
  "li",
1724
1967
  {
1725
- className: twMerge9(
1968
+ className: twMerge13(
1726
1969
  "flex items-start border-b border-border transition-colors duration-200",
1727
1970
  "hover:bg-surface",
1728
1971
  isActive && "bg-surface-raised border-l-2 border-l-accent"
1729
1972
  ),
1730
1973
  children: [
1731
- /* @__PURE__ */ jsxs27(
1974
+ /* @__PURE__ */ jsxs31(
1732
1975
  "button",
1733
1976
  {
1734
1977
  type: "button",
@@ -1736,19 +1979,19 @@ function ConversationList({
1736
1979
  "aria-current": isActive ? "true" : void 0,
1737
1980
  className: "flex-1 min-w-0 text-left px-4 py-3",
1738
1981
  children: [
1739
- /* @__PURE__ */ jsx30("div", { className: "text-sm font-medium text-brand-cream truncate", children: conversation.title }),
1740
- /* @__PURE__ */ jsx30("div", { className: "text-xs text-brand-cream/40 truncate mt-0.5 leading-relaxed", children: conversation.lastMessage })
1982
+ /* @__PURE__ */ jsx34("div", { className: "text-sm font-medium text-brand-cream truncate", children: conversation.title }),
1983
+ /* @__PURE__ */ jsx34("div", { className: "text-xs text-brand-cream/40 truncate mt-0.5 leading-relaxed", children: conversation.lastMessage })
1741
1984
  ]
1742
1985
  }
1743
1986
  ),
1744
- onDelete && /* @__PURE__ */ jsx30(
1987
+ onDelete && /* @__PURE__ */ jsx34(
1745
1988
  "button",
1746
1989
  {
1747
1990
  type: "button",
1748
1991
  onClick: () => onDelete(conversation.id),
1749
1992
  "aria-label": `Delete ${conversation.title}`,
1750
1993
  className: "shrink-0 p-1.5 m-2 rounded-lg text-brand-cream/25 hover:text-brand-watermelon hover:bg-brand-watermelon/10 transition-colors duration-200",
1751
- children: /* @__PURE__ */ jsxs27(
1994
+ children: /* @__PURE__ */ jsxs31(
1752
1995
  "svg",
1753
1996
  {
1754
1997
  xmlns: "http://www.w3.org/2000/svg",
@@ -1762,8 +2005,8 @@ function ConversationList({
1762
2005
  strokeLinejoin: "round",
1763
2006
  "aria-hidden": "true",
1764
2007
  children: [
1765
- /* @__PURE__ */ jsx30("polyline", { points: "3 6 5 6 21 6" }),
1766
- /* @__PURE__ */ jsx30("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
2008
+ /* @__PURE__ */ jsx34("polyline", { points: "3 6 5 6 21 6" }),
2009
+ /* @__PURE__ */ jsx34("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
1767
2010
  ]
1768
2011
  }
1769
2012
  )
@@ -1774,7 +2017,7 @@ function ConversationList({
1774
2017
  conversation.id
1775
2018
  );
1776
2019
  }),
1777
- conversations.length === 0 && /* @__PURE__ */ jsx30("li", { className: "px-4 py-8 text-center", children: /* @__PURE__ */ jsx30("span", { className: "text-sm text-brand-cream/30 font-body", children: "No conversations yet" }) })
2020
+ conversations.length === 0 && /* @__PURE__ */ jsx34("li", { className: "px-4 py-8 text-center", children: /* @__PURE__ */ jsx34("span", { className: "text-sm text-brand-cream/30 font-body", children: "No conversations yet" }) })
1778
2021
  ] })
1779
2022
  ]
1780
2023
  }
@@ -1782,9 +2025,9 @@ function ConversationList({
1782
2025
  }
1783
2026
 
1784
2027
  // src/layouts/AgentFullPage/AgentFullPage.tsx
1785
- import { twMerge as twMerge10 } from "tailwind-merge";
2028
+ import { twMerge as twMerge14 } from "tailwind-merge";
1786
2029
  import { useState as useState7, useCallback as useCallback3 } from "react";
1787
- import { Fragment, jsx as jsx31, jsxs as jsxs28 } from "react/jsx-runtime";
2030
+ import { Fragment, jsx as jsx35, jsxs as jsxs32 } from "react/jsx-runtime";
1788
2031
  function AgentFullPage({
1789
2032
  endpoint,
1790
2033
  title = "Chat",
@@ -1804,14 +2047,14 @@ function AgentFullPage({
1804
2047
  },
1805
2048
  [onConversationSelect]
1806
2049
  );
1807
- return /* @__PURE__ */ jsxs28(
2050
+ return /* @__PURE__ */ jsxs32(
1808
2051
  "div",
1809
2052
  {
1810
- className: twMerge10("flex h-screen w-full overflow-hidden bg-brand-dark", className),
2053
+ className: twMerge14("flex h-screen w-full overflow-hidden bg-brand-dark", className),
1811
2054
  "data-testid": "agent-full-page",
1812
2055
  children: [
1813
- showConversationList && /* @__PURE__ */ jsxs28(Fragment, { children: [
1814
- sidebarOpen && /* @__PURE__ */ jsx31(
2056
+ showConversationList && /* @__PURE__ */ jsxs32(Fragment, { children: [
2057
+ sidebarOpen && /* @__PURE__ */ jsx35(
1815
2058
  "div",
1816
2059
  {
1817
2060
  className: "fixed inset-0 bg-brand-dark/80 backdrop-blur-sm z-30 md:hidden",
@@ -1819,10 +2062,10 @@ function AgentFullPage({
1819
2062
  "data-testid": "sidebar-overlay"
1820
2063
  }
1821
2064
  ),
1822
- /* @__PURE__ */ jsx31(
2065
+ /* @__PURE__ */ jsx35(
1823
2066
  "aside",
1824
2067
  {
1825
- className: twMerge10(
2068
+ className: twMerge14(
1826
2069
  "bg-brand-dark border-r border-brand-gold/15 w-72 shrink-0 flex-col z-40",
1827
2070
  // Desktop: always visible
1828
2071
  "hidden md:flex",
@@ -1830,7 +2073,7 @@ function AgentFullPage({
1830
2073
  sidebarOpen && "fixed inset-y-0 left-0 flex md:relative"
1831
2074
  ),
1832
2075
  "aria-label": "Conversations sidebar",
1833
- children: /* @__PURE__ */ jsx31(
2076
+ children: /* @__PURE__ */ jsx35(
1834
2077
  ConversationList,
1835
2078
  {
1836
2079
  conversations,
@@ -1843,15 +2086,15 @@ function AgentFullPage({
1843
2086
  }
1844
2087
  )
1845
2088
  ] }),
1846
- /* @__PURE__ */ jsxs28("div", { className: "flex-1 flex flex-col min-w-0 bg-brand-dark", children: [
1847
- showConversationList && /* @__PURE__ */ jsx31("div", { className: "md:hidden flex items-center border-b border-brand-gold/15 px-3 py-2 bg-brand-dark-panel/60 backdrop-blur-sm", children: /* @__PURE__ */ jsx31(
2089
+ /* @__PURE__ */ jsxs32("div", { className: "flex-1 flex flex-col min-w-0 bg-brand-dark", children: [
2090
+ showConversationList && /* @__PURE__ */ jsx35("div", { className: "md:hidden flex items-center border-b border-brand-gold/15 px-3 py-2 bg-brand-dark-panel/60 backdrop-blur-sm", children: /* @__PURE__ */ jsx35(
1848
2091
  "button",
1849
2092
  {
1850
2093
  type: "button",
1851
2094
  onClick: () => setSidebarOpen(true),
1852
2095
  "aria-label": "Open conversations sidebar",
1853
2096
  className: "p-2 rounded-xl text-brand-cream/60 hover:text-brand-cream hover:bg-brand-dark-panel transition-colors duration-200",
1854
- children: /* @__PURE__ */ jsxs28(
2097
+ children: /* @__PURE__ */ jsxs32(
1855
2098
  "svg",
1856
2099
  {
1857
2100
  xmlns: "http://www.w3.org/2000/svg",
@@ -1865,15 +2108,15 @@ function AgentFullPage({
1865
2108
  strokeLinejoin: "round",
1866
2109
  "aria-hidden": "true",
1867
2110
  children: [
1868
- /* @__PURE__ */ jsx31("line", { x1: "3", y1: "12", x2: "21", y2: "12" }),
1869
- /* @__PURE__ */ jsx31("line", { x1: "3", y1: "6", x2: "21", y2: "6" }),
1870
- /* @__PURE__ */ jsx31("line", { x1: "3", y1: "18", x2: "21", y2: "18" })
2111
+ /* @__PURE__ */ jsx35("line", { x1: "3", y1: "12", x2: "21", y2: "12" }),
2112
+ /* @__PURE__ */ jsx35("line", { x1: "3", y1: "6", x2: "21", y2: "6" }),
2113
+ /* @__PURE__ */ jsx35("line", { x1: "3", y1: "18", x2: "21", y2: "18" })
1871
2114
  ]
1872
2115
  }
1873
2116
  )
1874
2117
  }
1875
2118
  ) }),
1876
- /* @__PURE__ */ jsx31(
2119
+ /* @__PURE__ */ jsx35(
1877
2120
  AgentChat,
1878
2121
  {
1879
2122
  endpoint,
@@ -1888,9 +2131,9 @@ function AgentFullPage({
1888
2131
  }
1889
2132
 
1890
2133
  // src/layouts/AgentPanel/AgentPanel.tsx
1891
- import { twMerge as twMerge11 } from "tailwind-merge";
2134
+ import { twMerge as twMerge15 } from "tailwind-merge";
1892
2135
  import { useRef as useRef6, useEffect as useEffect5 } from "react";
1893
- import { jsx as jsx32, jsxs as jsxs29 } from "react/jsx-runtime";
2136
+ import { jsx as jsx36, jsxs as jsxs33 } from "react/jsx-runtime";
1894
2137
  function AgentPanel({
1895
2138
  endpoint,
1896
2139
  isOpen,
@@ -1910,16 +2153,16 @@ function AgentPanel({
1910
2153
  return () => document.removeEventListener("keydown", handleKeyDown);
1911
2154
  }, [isOpen, onClose]);
1912
2155
  const widthStyle = typeof width === "number" ? `${width}px` : width;
1913
- return /* @__PURE__ */ jsxs29(
2156
+ return /* @__PURE__ */ jsxs33(
1914
2157
  "div",
1915
2158
  {
1916
- className: twMerge11("fixed inset-0 z-50", !isOpen && "pointer-events-none"),
2159
+ className: twMerge15("fixed inset-0 z-50", !isOpen && "pointer-events-none"),
1917
2160
  "aria-hidden": !isOpen,
1918
2161
  children: [
1919
- /* @__PURE__ */ jsx32(
2162
+ /* @__PURE__ */ jsx36(
1920
2163
  "div",
1921
2164
  {
1922
- className: twMerge11(
2165
+ className: twMerge15(
1923
2166
  "fixed inset-0 transition-opacity duration-300",
1924
2167
  isOpen ? "opacity-100 bg-brand-dark/70 backdrop-blur-sm pointer-events-auto" : "opacity-0 pointer-events-none"
1925
2168
  ),
@@ -1927,7 +2170,7 @@ function AgentPanel({
1927
2170
  "data-testid": "panel-backdrop"
1928
2171
  }
1929
2172
  ),
1930
- /* @__PURE__ */ jsxs29(
2173
+ /* @__PURE__ */ jsxs33(
1931
2174
  "div",
1932
2175
  {
1933
2176
  ref: panelRef,
@@ -1935,30 +2178,30 @@ function AgentPanel({
1935
2178
  "aria-label": title,
1936
2179
  "aria-modal": isOpen ? "true" : void 0,
1937
2180
  style: { width: widthStyle, maxWidth: "100vw" },
1938
- className: twMerge11(
2181
+ className: twMerge15(
1939
2182
  "fixed top-0 h-full flex flex-col z-50 bg-brand-dark shadow-card",
1940
2183
  "transition-transform duration-300 ease-in-out",
1941
2184
  side === "left" ? `left-0 border-r border-brand-gold/15 ${isOpen ? "translate-x-0" : "-translate-x-full"}` : `right-0 border-l border-brand-gold/15 ${isOpen ? "translate-x-0" : "translate-x-full"}`,
1942
2185
  className
1943
2186
  ),
1944
2187
  children: [
1945
- /* @__PURE__ */ jsxs29("div", { className: "flex items-center justify-between border-b border-brand-gold/15 px-5 py-3.5 bg-brand-dark-panel/60 backdrop-blur-sm shrink-0", children: [
1946
- /* @__PURE__ */ jsx32("h2", { className: "text-base font-display font-semibold text-brand-cream", children: title }),
1947
- /* @__PURE__ */ jsx32(
2188
+ /* @__PURE__ */ jsxs33("div", { className: "flex items-center justify-between border-b border-brand-gold/15 px-5 py-3.5 bg-brand-dark-panel/60 backdrop-blur-sm shrink-0", children: [
2189
+ /* @__PURE__ */ jsx36("h2", { className: "text-base font-display font-semibold text-brand-cream", children: title }),
2190
+ /* @__PURE__ */ jsx36(
1948
2191
  "button",
1949
2192
  {
1950
2193
  type: "button",
1951
2194
  onClick: onClose,
1952
2195
  "aria-label": "Close panel",
1953
2196
  className: "rounded-xl p-2 text-brand-cream/40 hover:text-brand-cream/80 hover:bg-brand-cream/5 transition-colors duration-200",
1954
- children: /* @__PURE__ */ jsxs29("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
1955
- /* @__PURE__ */ jsx32("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1956
- /* @__PURE__ */ jsx32("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
2197
+ children: /* @__PURE__ */ jsxs33("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
2198
+ /* @__PURE__ */ jsx36("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
2199
+ /* @__PURE__ */ jsx36("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1957
2200
  ] })
1958
2201
  }
1959
2202
  )
1960
2203
  ] }),
1961
- /* @__PURE__ */ jsx32(
2204
+ /* @__PURE__ */ jsx36(
1962
2205
  AgentChat,
1963
2206
  {
1964
2207
  endpoint,
@@ -1977,9 +2220,9 @@ function AgentPanel({
1977
2220
  }
1978
2221
 
1979
2222
  // src/layouts/AgentWidget/AgentWidget.tsx
1980
- import { twMerge as twMerge12 } from "tailwind-merge";
2223
+ import { twMerge as twMerge16 } from "tailwind-merge";
1981
2224
  import { useState as useState8, useCallback as useCallback4 } from "react";
1982
- import { jsx as jsx33, jsxs as jsxs30 } from "react/jsx-runtime";
2225
+ import { jsx as jsx37, jsxs as jsxs34 } from "react/jsx-runtime";
1983
2226
  function AgentWidget({
1984
2227
  endpoint,
1985
2228
  position = "bottom-right",
@@ -1994,14 +2237,14 @@ function AgentWidget({
1994
2237
  const positionClasses = position === "bottom-left" ? "left-4 bottom-4" : "right-4 bottom-4";
1995
2238
  const popoverPositionClasses = position === "bottom-left" ? "left-4 bottom-20" : "right-4 bottom-20";
1996
2239
  const popoverOrigin = position === "bottom-left" ? "origin-bottom-left" : "origin-bottom-right";
1997
- return /* @__PURE__ */ jsxs30("div", { className, children: [
1998
- /* @__PURE__ */ jsxs30(
2240
+ return /* @__PURE__ */ jsxs34("div", { className, children: [
2241
+ /* @__PURE__ */ jsxs34(
1999
2242
  "div",
2000
2243
  {
2001
2244
  role: "dialog",
2002
2245
  "aria-label": title,
2003
2246
  "aria-hidden": !isOpen,
2004
- className: twMerge12(
2247
+ className: twMerge16(
2005
2248
  "fixed z-50 flex flex-col",
2006
2249
  "w-[min(400px,calc(100vw-2rem))] h-[min(600px,calc(100vh-6rem))]",
2007
2250
  "rounded-2xl overflow-hidden border border-brand-gold/15",
@@ -2012,23 +2255,23 @@ function AgentWidget({
2012
2255
  isOpen ? "opacity-100 scale-100 pointer-events-auto translate-y-0" : "opacity-0 scale-95 pointer-events-none translate-y-2"
2013
2256
  ),
2014
2257
  children: [
2015
- /* @__PURE__ */ jsxs30("div", { className: "flex items-center justify-between px-4 py-2.5 bg-brand-dark-panel/80 border-b border-brand-gold/15 shrink-0", children: [
2016
- /* @__PURE__ */ jsx33("h2", { className: "text-sm font-display font-semibold text-brand-cream", children: title }),
2017
- /* @__PURE__ */ jsx33(
2258
+ /* @__PURE__ */ jsxs34("div", { className: "flex items-center justify-between px-4 py-2.5 bg-brand-dark-panel/80 border-b border-brand-gold/15 shrink-0", children: [
2259
+ /* @__PURE__ */ jsx37("h2", { className: "text-sm font-display font-semibold text-brand-cream", children: title }),
2260
+ /* @__PURE__ */ jsx37(
2018
2261
  "button",
2019
2262
  {
2020
2263
  type: "button",
2021
2264
  onClick: () => setIsOpen(false),
2022
2265
  "aria-label": "Minimize chat",
2023
2266
  className: "rounded-lg p-1.5 text-brand-cream/40 hover:text-brand-cream/70 transition-colors duration-200",
2024
- children: /* @__PURE__ */ jsxs30("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
2025
- /* @__PURE__ */ jsx33("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
2026
- /* @__PURE__ */ jsx33("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
2267
+ children: /* @__PURE__ */ jsxs34("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
2268
+ /* @__PURE__ */ jsx37("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
2269
+ /* @__PURE__ */ jsx37("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
2027
2270
  ] })
2028
2271
  }
2029
2272
  )
2030
2273
  ] }),
2031
- /* @__PURE__ */ jsx33(
2274
+ /* @__PURE__ */ jsx37(
2032
2275
  AgentChat,
2033
2276
  {
2034
2277
  endpoint,
@@ -2041,14 +2284,14 @@ function AgentWidget({
2041
2284
  ]
2042
2285
  }
2043
2286
  ),
2044
- /* @__PURE__ */ jsx33(
2287
+ /* @__PURE__ */ jsx37(
2045
2288
  "button",
2046
2289
  {
2047
2290
  type: "button",
2048
2291
  onClick: toggle,
2049
2292
  "aria-label": isOpen ? "Close chat" : triggerLabel,
2050
2293
  "aria-expanded": isOpen,
2051
- className: twMerge12(
2294
+ className: twMerge16(
2052
2295
  "fixed z-50 flex items-center justify-center w-14 h-14 rounded-full",
2053
2296
  "bg-brand-blue text-brand-cream shadow-glow-cyan",
2054
2297
  "hover:bg-brand-cyan hover:shadow-glow-cyan hover:scale-105",
@@ -2056,29 +2299,29 @@ function AgentWidget({
2056
2299
  "transition-all duration-200",
2057
2300
  positionClasses
2058
2301
  ),
2059
- children: isOpen ? /* @__PURE__ */ jsxs30("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
2060
- /* @__PURE__ */ jsx33("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
2061
- /* @__PURE__ */ jsx33("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
2062
- ] }) : /* @__PURE__ */ jsx33("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx33("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) })
2302
+ children: isOpen ? /* @__PURE__ */ jsxs34("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
2303
+ /* @__PURE__ */ jsx37("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
2304
+ /* @__PURE__ */ jsx37("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
2305
+ ] }) : /* @__PURE__ */ jsx37("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx37("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) })
2063
2306
  }
2064
2307
  )
2065
2308
  ] });
2066
2309
  }
2067
2310
 
2068
2311
  // src/layouts/AgentEmbed/AgentEmbed.tsx
2069
- import { twMerge as twMerge13 } from "tailwind-merge";
2070
- import { jsx as jsx34 } from "react/jsx-runtime";
2312
+ import { twMerge as twMerge17 } from "tailwind-merge";
2313
+ import { jsx as jsx38 } from "react/jsx-runtime";
2071
2314
  function AgentEmbed({
2072
2315
  endpoint,
2073
2316
  title = "Chat",
2074
2317
  className
2075
2318
  }) {
2076
- return /* @__PURE__ */ jsx34(
2319
+ return /* @__PURE__ */ jsx38(
2077
2320
  "div",
2078
2321
  {
2079
- className: twMerge13("w-full h-full min-h-0", className),
2322
+ className: twMerge17("w-full h-full min-h-0", className),
2080
2323
  "data-testid": "agent-embed",
2081
- children: /* @__PURE__ */ jsx34(
2324
+ children: /* @__PURE__ */ jsx38(
2082
2325
  AgentChat,
2083
2326
  {
2084
2327
  endpoint,
@@ -2090,9 +2333,495 @@ function AgentEmbed({
2090
2333
  );
2091
2334
  }
2092
2335
 
2093
- // src/feedback/ThumbsFeedback/ThumbsFeedback.tsx
2336
+ // src/mcp/MCPToolCall/MCPToolCall.tsx
2337
+ import { cva } from "class-variance-authority";
2338
+ import { twMerge as twMerge18 } from "tailwind-merge";
2339
+ import { Badge as Badge7, Spinner as Spinner4 } from "@surf-kit/core";
2340
+ import { jsx as jsx39, jsxs as jsxs35 } from "react/jsx-runtime";
2341
+ var statusBadgeIntent = {
2342
+ pending: "default",
2343
+ running: "info",
2344
+ success: "success",
2345
+ error: "error"
2346
+ };
2347
+ var statusLabel = {
2348
+ pending: "Pending",
2349
+ running: "Running",
2350
+ success: "Success",
2351
+ error: "Error"
2352
+ };
2353
+ var container = cva(
2354
+ "rounded-lg border text-sm",
2355
+ {
2356
+ variants: {
2357
+ status: {
2358
+ pending: "border-neutral-200 bg-neutral-50",
2359
+ running: "border-sky-200 bg-sky-50",
2360
+ success: "border-status-success-subtle bg-status-success-subtle/30",
2361
+ error: "border-status-error-subtle bg-status-error-subtle/30"
2362
+ }
2363
+ },
2364
+ defaultVariants: { status: "pending" }
2365
+ }
2366
+ );
2367
+ function formatDuration(start, end) {
2368
+ if (!start || !end) return null;
2369
+ const ms = end.getTime() - start.getTime();
2370
+ if (ms < 1e3) return `${ms}ms`;
2371
+ return `${(ms / 1e3).toFixed(1)}s`;
2372
+ }
2373
+ function formatValue(value) {
2374
+ if (typeof value === "string") return value;
2375
+ return JSON.stringify(value, null, 2);
2376
+ }
2377
+ function MCPToolCall({ call, isExpanded = false, onToggleExpand, className }) {
2378
+ const duration = formatDuration(call.startedAt, call.completedAt);
2379
+ return /* @__PURE__ */ jsxs35(
2380
+ "div",
2381
+ {
2382
+ className: twMerge18(container({ status: call.status }), className),
2383
+ "data-testid": "mcp-tool-call",
2384
+ children: [
2385
+ /* @__PURE__ */ jsxs35(
2386
+ "button",
2387
+ {
2388
+ type: "button",
2389
+ className: "flex w-full items-center justify-between gap-2 px-3 py-2",
2390
+ onClick: onToggleExpand,
2391
+ "aria-expanded": isExpanded,
2392
+ "data-testid": "mcp-tool-call-header",
2393
+ children: [
2394
+ /* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2 min-w-0", children: [
2395
+ /* @__PURE__ */ jsx39("span", { className: "font-medium text-text-primary truncate", "data-testid": "mcp-tool-name", children: call.name }),
2396
+ call.serverName && /* @__PURE__ */ jsx39("span", { className: "text-xs text-text-secondary truncate", children: call.serverName })
2397
+ ] }),
2398
+ /* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2 shrink-0", children: [
2399
+ call.status === "running" && /* @__PURE__ */ jsx39("span", { "aria-hidden": "true", children: /* @__PURE__ */ jsx39(Spinner4, { size: "sm" }) }),
2400
+ /* @__PURE__ */ jsx39(
2401
+ Badge7,
2402
+ {
2403
+ intent: statusBadgeIntent[call.status],
2404
+ size: "sm",
2405
+ role: "status",
2406
+ "aria-label": `Status: ${statusLabel[call.status]}`,
2407
+ "data-testid": "mcp-tool-status",
2408
+ children: statusLabel[call.status]
2409
+ }
2410
+ ),
2411
+ duration && /* @__PURE__ */ jsx39("span", { className: "text-xs text-text-secondary", "data-testid": "mcp-tool-duration", children: duration }),
2412
+ /* @__PURE__ */ jsx39(
2413
+ "svg",
2414
+ {
2415
+ className: `h-4 w-4 text-text-secondary transition-transform ${isExpanded ? "rotate-180" : ""}`,
2416
+ viewBox: "0 0 20 20",
2417
+ fill: "currentColor",
2418
+ "aria-hidden": "true",
2419
+ children: /* @__PURE__ */ jsx39(
2420
+ "path",
2421
+ {
2422
+ fillRule: "evenodd",
2423
+ d: "M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z",
2424
+ clipRule: "evenodd"
2425
+ }
2426
+ )
2427
+ }
2428
+ )
2429
+ ] })
2430
+ ]
2431
+ }
2432
+ ),
2433
+ isExpanded && /* @__PURE__ */ jsxs35("div", { className: "border-t border-inherit px-3 py-2 space-y-3", "data-testid": "mcp-tool-call-body", children: [
2434
+ Object.keys(call.arguments).length > 0 && /* @__PURE__ */ jsxs35("div", { children: [
2435
+ /* @__PURE__ */ jsx39("h4", { className: "text-xs font-medium text-text-secondary mb-1", children: "Arguments" }),
2436
+ /* @__PURE__ */ jsx39("dl", { className: "space-y-1", "data-testid": "mcp-tool-arguments", children: Object.entries(call.arguments).map(([key, value]) => /* @__PURE__ */ jsxs35("div", { className: "flex gap-2", children: [
2437
+ /* @__PURE__ */ jsxs35("dt", { className: "text-xs font-mono text-text-secondary shrink-0", children: [
2438
+ key,
2439
+ ":"
2440
+ ] }),
2441
+ /* @__PURE__ */ jsx39("dd", { className: "text-xs font-mono text-text-primary break-all", children: formatValue(value) })
2442
+ ] }, key)) })
2443
+ ] }),
2444
+ call.result !== void 0 && /* @__PURE__ */ jsxs35("div", { children: [
2445
+ /* @__PURE__ */ jsx39("h4", { className: "text-xs font-medium text-text-secondary mb-1", children: "Result" }),
2446
+ /* @__PURE__ */ jsx39(
2447
+ "pre",
2448
+ {
2449
+ className: "text-xs font-mono text-text-primary bg-neutral-100 rounded p-2 overflow-x-auto whitespace-pre-wrap",
2450
+ "data-testid": "mcp-tool-result",
2451
+ children: typeof call.result === "string" ? call.result : JSON.stringify(call.result, null, 2)
2452
+ }
2453
+ )
2454
+ ] }),
2455
+ call.error && /* @__PURE__ */ jsxs35("div", { children: [
2456
+ /* @__PURE__ */ jsx39("h4", { className: "text-xs font-medium text-status-error mb-1", children: "Error" }),
2457
+ /* @__PURE__ */ jsx39(
2458
+ "p",
2459
+ {
2460
+ className: "text-xs text-status-error bg-status-error-subtle/30 rounded p-2",
2461
+ "data-testid": "mcp-tool-error",
2462
+ children: call.error
2463
+ }
2464
+ )
2465
+ ] })
2466
+ ] })
2467
+ ]
2468
+ }
2469
+ );
2470
+ }
2471
+
2472
+ // src/mcp/MCPResourceView/MCPResourceView.tsx
2473
+ import { twMerge as twMerge19 } from "tailwind-merge";
2474
+ import { jsx as jsx40, jsxs as jsxs36 } from "react/jsx-runtime";
2475
+ function isImageMime(mime) {
2476
+ return !!mime && mime.startsWith("image/");
2477
+ }
2478
+ function isTextMime(mime) {
2479
+ if (!mime) return true;
2480
+ return mime.startsWith("text/") || mime === "application/json" || mime === "application/xml" || mime === "application/javascript" || mime === "application/typescript";
2481
+ }
2482
+ function isUrlContent(content) {
2483
+ if (typeof content !== "string") return false;
2484
+ return /^https?:\/\//.test(content.trim());
2485
+ }
2486
+ function MCPResourceView({ resource, className }) {
2487
+ const { uri, name, mimeType, description, content } = resource;
2488
+ return /* @__PURE__ */ jsxs36(
2489
+ "div",
2490
+ {
2491
+ className: twMerge19("rounded-lg border border-border bg-surface p-3 text-sm", className),
2492
+ "data-testid": "mcp-resource-view",
2493
+ children: [
2494
+ /* @__PURE__ */ jsxs36("div", { className: "mb-2", children: [
2495
+ /* @__PURE__ */ jsx40("span", { className: "font-medium text-text-primary", "data-testid": "mcp-resource-name", children: name }),
2496
+ /* @__PURE__ */ jsx40(
2497
+ "span",
2498
+ {
2499
+ className: "ml-2 text-xs text-text-secondary font-mono truncate",
2500
+ "data-testid": "mcp-resource-uri",
2501
+ children: uri
2502
+ }
2503
+ )
2504
+ ] }),
2505
+ description && /* @__PURE__ */ jsx40("p", { className: "text-xs text-text-secondary mb-2", "data-testid": "mcp-resource-description", children: description }),
2506
+ content !== void 0 && /* @__PURE__ */ jsx40("div", { "data-testid": "mcp-resource-content", children: isImageMime(mimeType) && typeof content === "string" ? /* @__PURE__ */ jsx40(
2507
+ "img",
2508
+ {
2509
+ src: content,
2510
+ alt: name,
2511
+ className: "max-w-full rounded",
2512
+ "data-testid": "mcp-resource-image"
2513
+ }
2514
+ ) : isUrlContent(content) ? /* @__PURE__ */ jsx40(
2515
+ "a",
2516
+ {
2517
+ href: typeof content === "string" ? content.trim() : void 0,
2518
+ target: "_blank",
2519
+ rel: "noopener noreferrer",
2520
+ className: "text-sm text-interactive-primary hover:underline break-all",
2521
+ "data-testid": "mcp-resource-link",
2522
+ children: typeof content === "string" ? content.trim() : ""
2523
+ }
2524
+ ) : isTextMime(mimeType) ? /* @__PURE__ */ jsx40(
2525
+ "pre",
2526
+ {
2527
+ className: "text-xs font-mono text-text-primary bg-neutral-100 rounded p-2 overflow-x-auto whitespace-pre-wrap",
2528
+ "data-testid": "mcp-resource-code",
2529
+ children: typeof content === "string" ? content : "[Binary data]"
2530
+ }
2531
+ ) : /* @__PURE__ */ jsxs36("p", { className: "text-xs text-text-secondary italic", children: [
2532
+ "Unsupported content type: ",
2533
+ mimeType
2534
+ ] }) })
2535
+ ]
2536
+ }
2537
+ );
2538
+ }
2539
+
2540
+ // src/mcp/MCPServerStatus/MCPServerStatus.tsx
2094
2541
  import { useState as useState9 } from "react";
2095
- import { jsx as jsx35, jsxs as jsxs31 } from "react/jsx-runtime";
2542
+ import { cva as cva2 } from "class-variance-authority";
2543
+ import { twMerge as twMerge20 } from "tailwind-merge";
2544
+ import { jsx as jsx41, jsxs as jsxs37 } from "react/jsx-runtime";
2545
+ var statusDot = cva2("inline-block h-2 w-2 rounded-full shrink-0", {
2546
+ variants: {
2547
+ status: {
2548
+ connected: "bg-status-success",
2549
+ disconnected: "bg-neutral-400",
2550
+ error: "bg-status-error"
2551
+ }
2552
+ },
2553
+ defaultVariants: { status: "disconnected" }
2554
+ });
2555
+ var statusLabel2 = {
2556
+ connected: "Connected",
2557
+ disconnected: "Disconnected",
2558
+ error: "Error"
2559
+ };
2560
+ function formatLastPing(date) {
2561
+ if (!date) return null;
2562
+ return date.toLocaleTimeString();
2563
+ }
2564
+ function MCPServerStatus({ server, className }) {
2565
+ const [showTools, setShowTools] = useState9(false);
2566
+ const [showResources, setShowResources] = useState9(false);
2567
+ const lastPing = formatLastPing(server.lastPing);
2568
+ return /* @__PURE__ */ jsxs37(
2569
+ "div",
2570
+ {
2571
+ className: twMerge20("rounded-lg border border-border bg-surface p-3 text-sm", className),
2572
+ "data-testid": "mcp-server-status",
2573
+ children: [
2574
+ /* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-2 mb-1", children: [
2575
+ /* @__PURE__ */ jsx41(
2576
+ "span",
2577
+ {
2578
+ className: statusDot({ status: server.status }),
2579
+ role: "status",
2580
+ "aria-label": statusLabel2[server.status],
2581
+ "data-testid": "mcp-server-status-dot"
2582
+ }
2583
+ ),
2584
+ /* @__PURE__ */ jsx41("span", { className: "font-medium text-text-primary", "data-testid": "mcp-server-name", children: server.name }),
2585
+ server.version && /* @__PURE__ */ jsxs37("span", { className: "text-xs text-text-secondary", "data-testid": "mcp-server-version", children: [
2586
+ "v",
2587
+ server.version
2588
+ ] })
2589
+ ] }),
2590
+ lastPing && /* @__PURE__ */ jsxs37("p", { className: "text-xs text-text-secondary ml-4 mb-2", "data-testid": "mcp-server-last-ping", children: [
2591
+ "Last ping: ",
2592
+ lastPing
2593
+ ] }),
2594
+ server.tools.length > 0 && /* @__PURE__ */ jsxs37("div", { className: "mt-2", children: [
2595
+ /* @__PURE__ */ jsxs37(
2596
+ "button",
2597
+ {
2598
+ type: "button",
2599
+ className: "flex items-center gap-1 text-xs font-medium text-text-secondary hover:text-text-primary w-full",
2600
+ onClick: () => setShowTools((prev) => !prev),
2601
+ "aria-expanded": showTools,
2602
+ "data-testid": "mcp-server-tools-toggle",
2603
+ children: [
2604
+ /* @__PURE__ */ jsx41(
2605
+ "svg",
2606
+ {
2607
+ className: `h-3 w-3 transition-transform ${showTools ? "rotate-90" : ""}`,
2608
+ viewBox: "0 0 20 20",
2609
+ fill: "currentColor",
2610
+ "aria-hidden": "true",
2611
+ children: /* @__PURE__ */ jsx41(
2612
+ "path",
2613
+ {
2614
+ fillRule: "evenodd",
2615
+ d: "M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z",
2616
+ clipRule: "evenodd"
2617
+ }
2618
+ )
2619
+ }
2620
+ ),
2621
+ "Tools (",
2622
+ server.tools.length,
2623
+ ")"
2624
+ ]
2625
+ }
2626
+ ),
2627
+ showTools && /* @__PURE__ */ jsx41("ul", { className: "mt-1 ml-4 space-y-1", "data-testid": "mcp-server-tools-list", children: server.tools.map((tool) => /* @__PURE__ */ jsxs37("li", { className: "text-xs text-text-primary", children: [
2628
+ /* @__PURE__ */ jsx41("span", { className: "font-mono", children: tool.name }),
2629
+ tool.description && /* @__PURE__ */ jsxs37("span", { className: "text-text-secondary ml-1", children: [
2630
+ "\u2014 ",
2631
+ tool.description
2632
+ ] })
2633
+ ] }, tool.name)) })
2634
+ ] }),
2635
+ server.resources.length > 0 && /* @__PURE__ */ jsxs37("div", { className: "mt-2", children: [
2636
+ /* @__PURE__ */ jsxs37(
2637
+ "button",
2638
+ {
2639
+ type: "button",
2640
+ className: "flex items-center gap-1 text-xs font-medium text-text-secondary hover:text-text-primary w-full",
2641
+ onClick: () => setShowResources((prev) => !prev),
2642
+ "aria-expanded": showResources,
2643
+ "data-testid": "mcp-server-resources-toggle",
2644
+ children: [
2645
+ /* @__PURE__ */ jsx41(
2646
+ "svg",
2647
+ {
2648
+ className: `h-3 w-3 transition-transform ${showResources ? "rotate-90" : ""}`,
2649
+ viewBox: "0 0 20 20",
2650
+ fill: "currentColor",
2651
+ "aria-hidden": "true",
2652
+ children: /* @__PURE__ */ jsx41(
2653
+ "path",
2654
+ {
2655
+ fillRule: "evenodd",
2656
+ d: "M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z",
2657
+ clipRule: "evenodd"
2658
+ }
2659
+ )
2660
+ }
2661
+ ),
2662
+ "Resources (",
2663
+ server.resources.length,
2664
+ ")"
2665
+ ]
2666
+ }
2667
+ ),
2668
+ showResources && /* @__PURE__ */ jsx41("ul", { className: "mt-1 ml-4 space-y-1", "data-testid": "mcp-server-resources-list", children: server.resources.map((res) => /* @__PURE__ */ jsxs37("li", { className: "text-xs text-text-primary", children: [
2669
+ /* @__PURE__ */ jsx41("span", { className: "font-mono", children: res.name }),
2670
+ /* @__PURE__ */ jsxs37("span", { className: "text-text-secondary ml-1", children: [
2671
+ "(",
2672
+ res.uri,
2673
+ ")"
2674
+ ] })
2675
+ ] }, res.uri)) })
2676
+ ] })
2677
+ ]
2678
+ }
2679
+ );
2680
+ }
2681
+
2682
+ // src/mcp/MCPApprovalDialog/MCPApprovalDialog.tsx
2683
+ import { useRef as useRef7, useEffect as useEffect6 } from "react";
2684
+ import { cva as cva3 } from "class-variance-authority";
2685
+ import { twMerge as twMerge21 } from "tailwind-merge";
2686
+ import { useDialog, FocusScope } from "react-aria";
2687
+ import { Button as Button2, Badge as Badge8 } from "@surf-kit/core";
2688
+ import { jsx as jsx42, jsxs as jsxs38 } from "react/jsx-runtime";
2689
+ var riskBadgeIntent = {
2690
+ low: "success",
2691
+ medium: "warning",
2692
+ high: "error"
2693
+ };
2694
+ var riskLabel = {
2695
+ low: "Low Risk",
2696
+ medium: "Medium Risk",
2697
+ high: "High Risk"
2698
+ };
2699
+ var riskBorder = cva3("relative bg-surface rounded-xl shadow-xl border p-6 outline-none w-full max-w-lg", {
2700
+ variants: {
2701
+ risk: {
2702
+ low: "border-status-success-subtle",
2703
+ medium: "border-status-warning-subtle",
2704
+ high: "border-status-error-subtle"
2705
+ }
2706
+ },
2707
+ defaultVariants: { risk: "low" }
2708
+ });
2709
+ function formatValue2(value) {
2710
+ if (typeof value === "string") return value;
2711
+ return JSON.stringify(value, null, 2);
2712
+ }
2713
+ function MCPApprovalDialog({
2714
+ call,
2715
+ riskLevel = "low",
2716
+ onApprove,
2717
+ onDeny,
2718
+ isOpen,
2719
+ className
2720
+ }) {
2721
+ const ref = useRef7(null);
2722
+ const { dialogProps, titleProps } = useDialog({ role: "alertdialog" }, ref);
2723
+ useEffect6(() => {
2724
+ if (!isOpen) return;
2725
+ const handleKeyDown = (e) => {
2726
+ if (e.key === "Escape") {
2727
+ e.preventDefault();
2728
+ e.stopPropagation();
2729
+ }
2730
+ };
2731
+ document.addEventListener("keydown", handleKeyDown, true);
2732
+ return () => document.removeEventListener("keydown", handleKeyDown, true);
2733
+ }, [isOpen]);
2734
+ if (!isOpen) return null;
2735
+ return /* @__PURE__ */ jsx42(
2736
+ "div",
2737
+ {
2738
+ className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50",
2739
+ "data-testid": "mcp-approval-overlay",
2740
+ children: /* @__PURE__ */ jsx42(FocusScope, { contain: true, restoreFocus: true, autoFocus: true, children: /* @__PURE__ */ jsxs38(
2741
+ "div",
2742
+ {
2743
+ ...dialogProps,
2744
+ ref,
2745
+ className: twMerge21(riskBorder({ risk: riskLevel }), className),
2746
+ "data-testid": "mcp-approval-dialog",
2747
+ children: [
2748
+ /* @__PURE__ */ jsxs38("div", { className: "flex items-center justify-between mb-4", children: [
2749
+ /* @__PURE__ */ jsx42(
2750
+ "h2",
2751
+ {
2752
+ ...titleProps,
2753
+ className: "text-lg font-semibold text-text-primary",
2754
+ "data-testid": "mcp-approval-title",
2755
+ children: "Tool Approval Required"
2756
+ }
2757
+ ),
2758
+ /* @__PURE__ */ jsx42(
2759
+ Badge8,
2760
+ {
2761
+ intent: riskBadgeIntent[riskLevel],
2762
+ size: "sm",
2763
+ "data-testid": "mcp-approval-risk-badge",
2764
+ children: riskLabel[riskLevel]
2765
+ }
2766
+ )
2767
+ ] }),
2768
+ /* @__PURE__ */ jsxs38("div", { className: "space-y-3 text-sm", children: [
2769
+ /* @__PURE__ */ jsxs38("div", { children: [
2770
+ /* @__PURE__ */ jsx42("h3", { className: "text-xs font-medium text-text-secondary mb-1", children: "Tool" }),
2771
+ /* @__PURE__ */ jsx42("p", { className: "font-mono text-text-primary", "data-testid": "mcp-approval-tool-name", children: call.name }),
2772
+ call.serverName && /* @__PURE__ */ jsxs38("p", { className: "text-xs text-text-secondary mt-0.5", "data-testid": "mcp-approval-server", children: [
2773
+ "Server: ",
2774
+ call.serverName
2775
+ ] })
2776
+ ] }),
2777
+ Object.keys(call.arguments).length > 0 && /* @__PURE__ */ jsxs38("div", { children: [
2778
+ /* @__PURE__ */ jsx42("h3", { className: "text-xs font-medium text-text-secondary mb-1", children: "Arguments" }),
2779
+ /* @__PURE__ */ jsx42(
2780
+ "dl",
2781
+ {
2782
+ className: "space-y-1 bg-neutral-100 rounded p-2",
2783
+ "data-testid": "mcp-approval-arguments",
2784
+ children: Object.entries(call.arguments).map(([key, value]) => /* @__PURE__ */ jsxs38("div", { className: "flex gap-2", children: [
2785
+ /* @__PURE__ */ jsxs38("dt", { className: "text-xs font-mono text-text-secondary shrink-0", children: [
2786
+ key,
2787
+ ":"
2788
+ ] }),
2789
+ /* @__PURE__ */ jsx42("dd", { className: "text-xs font-mono text-text-primary break-all", children: formatValue2(value) })
2790
+ ] }, key))
2791
+ }
2792
+ )
2793
+ ] })
2794
+ ] }),
2795
+ /* @__PURE__ */ jsxs38("div", { className: "mt-6 flex justify-end gap-3", children: [
2796
+ /* @__PURE__ */ jsx42(
2797
+ Button2,
2798
+ {
2799
+ intent: "secondary",
2800
+ onPress: onDeny,
2801
+ "aria-label": "Deny tool execution",
2802
+ children: "Deny"
2803
+ }
2804
+ ),
2805
+ /* @__PURE__ */ jsx42(
2806
+ Button2,
2807
+ {
2808
+ intent: "primary",
2809
+ onPress: onApprove,
2810
+ "aria-label": "Approve tool execution",
2811
+ children: "Approve"
2812
+ }
2813
+ )
2814
+ ] })
2815
+ ]
2816
+ }
2817
+ ) })
2818
+ }
2819
+ );
2820
+ }
2821
+
2822
+ // src/feedback/ThumbsFeedback/ThumbsFeedback.tsx
2823
+ import { useState as useState10 } from "react";
2824
+ import { jsx as jsx43, jsxs as jsxs39 } from "react/jsx-runtime";
2096
2825
  function ThumbsFeedback({
2097
2826
  messageId,
2098
2827
  onFeedback,
@@ -2100,7 +2829,7 @@ function ThumbsFeedback({
2100
2829
  onNegative,
2101
2830
  className
2102
2831
  }) {
2103
- const [selected, setSelected] = useState9(state);
2832
+ const [selected, setSelected] = useState10(state);
2104
2833
  const handleClick = (rating) => {
2105
2834
  setSelected(rating);
2106
2835
  onFeedback(messageId, rating);
@@ -2108,7 +2837,7 @@ function ThumbsFeedback({
2108
2837
  onNegative();
2109
2838
  }
2110
2839
  };
2111
- return /* @__PURE__ */ jsxs31(
2840
+ return /* @__PURE__ */ jsxs39(
2112
2841
  "div",
2113
2842
  {
2114
2843
  className: `inline-flex items-center gap-0.5 ${className ?? ""}`,
@@ -2116,7 +2845,7 @@ function ThumbsFeedback({
2116
2845
  "aria-label": "Rate this response",
2117
2846
  "data-testid": "thumbs-feedback",
2118
2847
  children: [
2119
- /* @__PURE__ */ jsx35(
2848
+ /* @__PURE__ */ jsx43(
2120
2849
  "button",
2121
2850
  {
2122
2851
  type: "button",
@@ -2125,7 +2854,7 @@ function ThumbsFeedback({
2125
2854
  "aria-pressed": selected === "positive",
2126
2855
  className: `p-1.5 rounded-md transition-colors duration-200 ${selected === "positive" ? "text-brand-cyan bg-brand-cyan/15" : "text-brand-cream/30 hover:text-brand-cyan hover:bg-brand-cyan/10"}`,
2127
2856
  "data-testid": "thumbs-up",
2128
- children: /* @__PURE__ */ jsxs31(
2857
+ children: /* @__PURE__ */ jsxs39(
2129
2858
  "svg",
2130
2859
  {
2131
2860
  width: "16",
@@ -2138,14 +2867,14 @@ function ThumbsFeedback({
2138
2867
  strokeLinejoin: "round",
2139
2868
  "aria-hidden": "true",
2140
2869
  children: [
2141
- /* @__PURE__ */ jsx35("path", { d: "M7 10v12" }),
2142
- /* @__PURE__ */ jsx35("path", { d: "M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2h0a3.13 3.13 0 0 1 3 3.88Z" })
2870
+ /* @__PURE__ */ jsx43("path", { d: "M7 10v12" }),
2871
+ /* @__PURE__ */ jsx43("path", { d: "M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2h0a3.13 3.13 0 0 1 3 3.88Z" })
2143
2872
  ]
2144
2873
  }
2145
2874
  )
2146
2875
  }
2147
2876
  ),
2148
- /* @__PURE__ */ jsx35(
2877
+ /* @__PURE__ */ jsx43(
2149
2878
  "button",
2150
2879
  {
2151
2880
  type: "button",
@@ -2154,7 +2883,7 @@ function ThumbsFeedback({
2154
2883
  "aria-pressed": selected === "negative",
2155
2884
  className: `p-1.5 rounded-md transition-colors duration-200 ${selected === "negative" ? "text-brand-watermelon bg-brand-watermelon/15" : "text-brand-cream/30 hover:text-brand-watermelon hover:bg-brand-watermelon/10"}`,
2156
2885
  "data-testid": "thumbs-down",
2157
- children: /* @__PURE__ */ jsxs31(
2886
+ children: /* @__PURE__ */ jsxs39(
2158
2887
  "svg",
2159
2888
  {
2160
2889
  width: "16",
@@ -2167,8 +2896,8 @@ function ThumbsFeedback({
2167
2896
  strokeLinejoin: "round",
2168
2897
  "aria-hidden": "true",
2169
2898
  children: [
2170
- /* @__PURE__ */ jsx35("path", { d: "M17 14V2" }),
2171
- /* @__PURE__ */ jsx35("path", { d: "M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22h0a3.13 3.13 0 0 1-3-3.88Z" })
2899
+ /* @__PURE__ */ jsx43("path", { d: "M17 14V2" }),
2900
+ /* @__PURE__ */ jsx43("path", { d: "M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22h0a3.13 3.13 0 0 1-3-3.88Z" })
2172
2901
  ]
2173
2902
  }
2174
2903
  )
@@ -2180,17 +2909,17 @@ function ThumbsFeedback({
2180
2909
  }
2181
2910
 
2182
2911
  // src/feedback/FeedbackDialog/FeedbackDialog.tsx
2183
- import { useState as useState10 } from "react";
2184
- import { Dialog, Button as Button2, TextArea } from "@surf-kit/core";
2185
- import { Fragment as Fragment2, jsx as jsx36, jsxs as jsxs32 } from "react/jsx-runtime";
2912
+ import { useState as useState11 } from "react";
2913
+ import { Dialog, Button as Button3, TextArea } from "@surf-kit/core";
2914
+ import { Fragment as Fragment2, jsx as jsx44, jsxs as jsxs40 } from "react/jsx-runtime";
2186
2915
  function FeedbackDialog({ isOpen, onClose, onSubmit, className }) {
2187
- const [comment, setComment] = useState10("");
2916
+ const [comment, setComment] = useState11("");
2188
2917
  const handleSubmit = () => {
2189
2918
  onSubmit(comment);
2190
2919
  setComment("");
2191
2920
  onClose();
2192
2921
  };
2193
- return /* @__PURE__ */ jsx36(
2922
+ return /* @__PURE__ */ jsx44(
2194
2923
  Dialog,
2195
2924
  {
2196
2925
  isOpen,
@@ -2198,11 +2927,11 @@ function FeedbackDialog({ isOpen, onClose, onSubmit, className }) {
2198
2927
  title: "Share your feedback",
2199
2928
  size: "sm",
2200
2929
  className,
2201
- footer: /* @__PURE__ */ jsxs32(Fragment2, { children: [
2202
- /* @__PURE__ */ jsx36(Button2, { intent: "ghost", onPress: onClose, children: "Cancel" }),
2203
- /* @__PURE__ */ jsx36(Button2, { intent: "primary", onPress: handleSubmit, isDisabled: comment.trim().length === 0, children: "Submit" })
2930
+ footer: /* @__PURE__ */ jsxs40(Fragment2, { children: [
2931
+ /* @__PURE__ */ jsx44(Button3, { intent: "ghost", onPress: onClose, children: "Cancel" }),
2932
+ /* @__PURE__ */ jsx44(Button3, { intent: "primary", onPress: handleSubmit, isDisabled: comment.trim().length === 0, children: "Submit" })
2204
2933
  ] }),
2205
- children: /* @__PURE__ */ jsx36(
2934
+ children: /* @__PURE__ */ jsx44(
2206
2935
  TextArea,
2207
2936
  {
2208
2937
  label: "What could be improved?",
@@ -2218,10 +2947,10 @@ function FeedbackDialog({ isOpen, onClose, onSubmit, className }) {
2218
2947
  }
2219
2948
 
2220
2949
  // src/feedback/FeedbackConfirmation/FeedbackConfirmation.tsx
2221
- import { jsx as jsx37 } from "react/jsx-runtime";
2950
+ import { jsx as jsx45 } from "react/jsx-runtime";
2222
2951
  function FeedbackConfirmation({ variant = "inline", className }) {
2223
2952
  if (variant === "toast") {
2224
- return /* @__PURE__ */ jsx37(
2953
+ return /* @__PURE__ */ jsx45(
2225
2954
  "div",
2226
2955
  {
2227
2956
  role: "status",
@@ -2231,7 +2960,7 @@ function FeedbackConfirmation({ variant = "inline", className }) {
2231
2960
  }
2232
2961
  );
2233
2962
  }
2234
- return /* @__PURE__ */ jsx37(
2963
+ return /* @__PURE__ */ jsx45(
2235
2964
  "span",
2236
2965
  {
2237
2966
  role: "status",
@@ -2259,6 +2988,10 @@ export {
2259
2988
  FeedbackConfirmation,
2260
2989
  FeedbackDialog,
2261
2990
  FollowUpChips,
2991
+ MCPApprovalDialog,
2992
+ MCPResourceView,
2993
+ MCPServerStatus,
2994
+ MCPToolCall,
2262
2995
  MessageBubble,
2263
2996
  MessageComposer,
2264
2997
  MessageThread,
@@ -2270,12 +3003,16 @@ export {
2270
3003
  SourceDrawer,
2271
3004
  SourceInline,
2272
3005
  SourceList,
3006
+ StreamingList,
2273
3007
  StreamingMessage,
3008
+ StreamingStructure,
2274
3009
  StructuredResponse,
3010
+ TextGlimmer,
2275
3011
  ThinkingIndicator,
2276
3012
  ThumbsFeedback,
2277
3013
  ToolExecution,
2278
3014
  TypewriterText,
3015
+ TypingIndicator,
2279
3016
  VerificationBadge,
2280
3017
  VerificationDetail,
2281
3018
  VerificationProgress,