@leanmcp/ui 0.1.0 → 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.
package/dist/index.mjs CHANGED
@@ -1,53 +1,41 @@
1
- import 'reflect-metadata';
2
- import React7, { forwardRef, useState, useEffect, useCallback, createContext, useContext, useMemo, useRef } from 'react';
3
- import { PostMessageTransport, App } from '@modelcontextprotocol/ext-apps';
1
+ import { __name } from './chunk-WORZ46KI.mjs';
2
+ export { UIApp, getUIAppMetadata, getUIAppUri } from './chunk-WORZ46KI.mjs';
3
+ import * as React25 from 'react';
4
+ import React25__default, { forwardRef, Component, useState, useRef, useCallback, useEffect, createContext, useContext, useMemo } from 'react';
5
+ import { applyDocumentTheme, applyHostStyleVariables, PostMessageTransport, App } from '@modelcontextprotocol/ext-apps';
6
+ export { App, PostMessageTransport } from '@modelcontextprotocol/ext-apps';
7
+ import { XIcon, ChevronDownIcon, CheckIcon, ChevronUpIcon, Loader2, SearchIcon, Search, X, AlertCircle, RefreshCw, ChevronLeft, ChevronRight, WifiOff, CircleIcon, ChevronRightIcon, Check, ArrowUpDown, ArrowUp, ArrowDown, Loader2Icon, OctagonXIcon, TriangleAlertIcon, InfoIcon, CircleCheckIcon } from 'lucide-react';
8
+ import { useTheme } from 'next-themes';
9
+ import { toast, Toaster as Toaster$1 } from 'sonner';
4
10
  import { Slot } from '@radix-ui/react-slot';
11
+ import { cva } from 'class-variance-authority';
5
12
  import { clsx } from 'clsx';
13
+ import { twMerge } from 'tailwind-merge';
14
+ import * as DialogPrimitive from '@radix-ui/react-dialog';
15
+ import * as SelectPrimitive from '@radix-ui/react-select';
16
+ import { Command as Command$1 } from 'cmdk';
17
+ import * as PopoverPrimitive from '@radix-ui/react-popover';
18
+ import * as LabelPrimitive from '@radix-ui/react-label';
19
+ import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
20
+ import * as SliderPrimitive from '@radix-ui/react-slider';
21
+ import * as SwitchPrimitive from '@radix-ui/react-switch';
22
+ import * as ProgressPrimitive from '@radix-ui/react-progress';
23
+ import { useFormContext, useFormState, FormProvider, Controller } from 'react-hook-form';
24
+ import * as TabsPrimitive2 from '@radix-ui/react-tabs';
25
+ import * as SeparatorPrimitive from '@radix-ui/react-separator';
26
+ import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
27
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
28
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
6
29
  import { useReactTable, getFilteredRowModel, getSortedRowModel, getCoreRowModel, flexRender } from '@tanstack/react-table';
7
- import { Chart as Chart$1, CategoryScale, LinearScale, PointElement, LineElement, BarElement, ArcElement, Title, Tooltip, Legend } from 'chart.js';
30
+ import { Chart as Chart$1, CategoryScale, LinearScale, PointElement, LineElement, BarElement, ArcElement, Title, Tooltip as Tooltip$1, Legend } from 'chart.js';
8
31
  import { Chart as Chart$2 } from 'react-chartjs-2';
9
32
  import { Highlight, themes } from 'prism-react-renderer';
33
+ export { AppBridge } from '@modelcontextprotocol/ext-apps/app-bridge';
10
34
 
11
- var __defProp = Object.defineProperty;
12
- var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
13
- var UI_APP_COMPONENT_KEY = "ui:app:component";
14
- var UI_APP_URI_KEY = "ui:app:uri";
15
- var UI_APP_OPTIONS_KEY = "ui:app:options";
16
- function UIApp(options) {
17
- return (target, propertyKey, descriptor) => {
18
- const methodName = String(propertyKey);
19
- const className = target.constructor.name.toLowerCase().replace("service", "");
20
- const uri = options.uri ?? `ui://${className}/${methodName}`;
21
- Reflect.defineMetadata(UI_APP_COMPONENT_KEY, options.component, descriptor.value);
22
- Reflect.defineMetadata(UI_APP_URI_KEY, uri, descriptor.value);
23
- Reflect.defineMetadata(UI_APP_OPTIONS_KEY, options, descriptor.value);
24
- const existingMeta = Reflect.getMetadata("tool:meta", descriptor.value) || {};
25
- Reflect.defineMetadata("tool:meta", {
26
- ...existingMeta,
27
- "ui/resourceUri": uri
28
- }, descriptor.value);
29
- return descriptor;
30
- };
31
- }
32
- __name(UIApp, "UIApp");
33
- function getUIAppMetadata(target) {
34
- const component = Reflect.getMetadata(UI_APP_COMPONENT_KEY, target);
35
- if (!component) return void 0;
36
- return {
37
- component,
38
- uri: Reflect.getMetadata(UI_APP_URI_KEY, target),
39
- ...Reflect.getMetadata(UI_APP_OPTIONS_KEY, target)
40
- };
41
- }
42
- __name(getUIAppMetadata, "getUIAppMetadata");
43
- function getUIAppUri(target) {
44
- return Reflect.getMetadata(UI_APP_URI_KEY, target);
45
- }
46
- __name(getUIAppUri, "getUIAppUri");
47
35
  var McpAppContext = /* @__PURE__ */ createContext(null);
48
36
  function AppProvider({ appInfo, capabilities = {}, options = {
49
37
  autoResize: true
50
- }, children }) {
38
+ }, onTeardown, children }) {
51
39
  const [app, setApp] = useState(null);
52
40
  const [isConnected, setIsConnected] = useState(false);
53
41
  const [error, setError] = useState(null);
@@ -55,6 +43,18 @@ function AppProvider({ appInfo, capabilities = {}, options = {
55
43
  const [toolInput, setToolInput] = useState(null);
56
44
  const [toolInputPartial, setToolInputPartial] = useState(null);
57
45
  const [toolResult, setToolResult] = useState(null);
46
+ const [toolCancelled, setToolCancelled] = useState({
47
+ cancelled: false
48
+ });
49
+ const stylesApplied = useRef(false);
50
+ const applyHostStyles = useCallback((context) => {
51
+ if (context.theme) {
52
+ applyDocumentTheme(context.theme);
53
+ }
54
+ if (context.styles?.variables) {
55
+ applyHostStyleVariables(context.styles.variables);
56
+ }
57
+ }, []);
58
58
  useEffect(() => {
59
59
  let mounted = true;
60
60
  let appInstance = null;
@@ -65,6 +65,9 @@ function AppProvider({ appInfo, capabilities = {}, options = {
65
65
  appInstance.ontoolinput = (params) => {
66
66
  if (mounted) {
67
67
  setToolInput(params.arguments);
68
+ setToolCancelled({
69
+ cancelled: false
70
+ });
68
71
  }
69
72
  };
70
73
  appInstance.ontoolinputpartial = (params) => {
@@ -77,19 +80,42 @@ function AppProvider({ appInfo, capabilities = {}, options = {
77
80
  setToolResult(params);
78
81
  }
79
82
  };
83
+ appInstance.ontoolcancelled = (params) => {
84
+ if (mounted) {
85
+ setToolCancelled({
86
+ cancelled: true,
87
+ reason: params.reason
88
+ });
89
+ }
90
+ };
80
91
  appInstance.onhostcontextchanged = (params) => {
81
92
  if (mounted) {
82
93
  setHostContext((prev) => ({
83
94
  ...prev,
84
95
  ...params
85
96
  }));
97
+ applyHostStyles(params);
86
98
  }
87
99
  };
100
+ if (onTeardown) {
101
+ appInstance.onteardown = async () => {
102
+ await onTeardown();
103
+ return {};
104
+ };
105
+ }
88
106
  await appInstance.connect(transport);
89
107
  if (mounted) {
90
108
  setApp(appInstance);
91
109
  setIsConnected(true);
92
110
  setError(null);
111
+ const initialContext = appInstance.getHostContext();
112
+ if (initialContext) {
113
+ setHostContext(initialContext);
114
+ if (!stylesApplied.current) {
115
+ applyHostStyles(initialContext);
116
+ stylesApplied.current = true;
117
+ }
118
+ }
93
119
  }
94
120
  } catch (err) {
95
121
  if (mounted) {
@@ -108,12 +134,17 @@ function AppProvider({ appInfo, capabilities = {}, options = {
108
134
  };
109
135
  }, [
110
136
  appInfo.name,
111
- appInfo.version
137
+ appInfo.version,
138
+ applyHostStyles,
139
+ onTeardown
112
140
  ]);
113
141
  const callTool = useCallback(async (name, args = {}) => {
114
142
  if (!app) {
115
143
  throw new Error("Not connected to host");
116
144
  }
145
+ setToolCancelled({
146
+ cancelled: false
147
+ });
117
148
  const result = await app.callServerTool({
118
149
  name,
119
150
  arguments: args
@@ -157,12 +188,24 @@ function AppProvider({ appInfo, capabilities = {}, options = {
157
188
  window.open(url, "_blank", "noopener,noreferrer");
158
189
  return;
159
190
  }
160
- await app.sendOpenLink({
191
+ await app.openLink({
161
192
  url
162
193
  });
163
194
  }, [
164
195
  app
165
196
  ]);
197
+ const requestDisplayMode = useCallback(async (mode) => {
198
+ if (!app) {
199
+ console.warn("[AppProvider] Not connected - cannot request display mode");
200
+ return "inline";
201
+ }
202
+ const result = await app.requestDisplayMode({
203
+ mode
204
+ });
205
+ return result.mode;
206
+ }, [
207
+ app
208
+ ]);
166
209
  const value = {
167
210
  app,
168
211
  isConnected,
@@ -171,15 +214,17 @@ function AppProvider({ appInfo, capabilities = {}, options = {
171
214
  toolInput,
172
215
  toolInputPartial,
173
216
  toolResult,
217
+ toolCancelled,
174
218
  callTool,
175
219
  sendMessage,
176
220
  sendLog,
177
- openLink
221
+ openLink,
222
+ requestDisplayMode
178
223
  };
179
224
  const theme = hostContext.theme ?? "light";
180
- return /* @__PURE__ */ React7.createElement(McpAppContext.Provider, {
225
+ return /* @__PURE__ */ React25__default.createElement(McpAppContext.Provider, {
181
226
  value
182
- }, /* @__PURE__ */ React7.createElement("div", {
227
+ }, /* @__PURE__ */ React25__default.createElement("div", {
183
228
  className: "lui-root",
184
229
  "data-theme": theme
185
230
  }, children));
@@ -193,6 +238,9 @@ var ssrDefaultContext = {
193
238
  toolInput: null,
194
239
  toolInputPartial: null,
195
240
  toolResult: null,
241
+ toolCancelled: {
242
+ cancelled: false
243
+ },
196
244
  callTool: /* @__PURE__ */ __name(async () => {
197
245
  throw new Error("callTool not available during SSR");
198
246
  }, "callTool"),
@@ -204,7 +252,11 @@ var ssrDefaultContext = {
204
252
  }, "sendLog"),
205
253
  openLink: /* @__PURE__ */ __name(async () => {
206
254
  console.warn("openLink not available during SSR");
207
- }, "openLink")
255
+ }, "openLink"),
256
+ requestDisplayMode: /* @__PURE__ */ __name(async () => {
257
+ console.warn("requestDisplayMode not available during SSR");
258
+ return "inline";
259
+ }, "requestDisplayMode")
208
260
  };
209
261
  function useMcpApp() {
210
262
  const context = useContext(McpAppContext);
@@ -214,311 +266,2598 @@ function useMcpApp() {
214
266
  return context;
215
267
  }
216
268
  __name(useMcpApp, "useMcpApp");
217
- function useTool(toolName) {
269
+ var DEFAULT_CONTEXT = {
270
+ resultDisplay: {
271
+ display: "none"
272
+ },
273
+ showLoading: true
274
+ };
275
+ var ToolContext = /* @__PURE__ */ createContext(DEFAULT_CONTEXT);
276
+ function ToolProvider({ defaults = {}, children }) {
277
+ const parentContext = useContext(ToolContext);
278
+ const value = useMemo(() => ({
279
+ resultDisplay: defaults.resultDisplay ?? parentContext.resultDisplay,
280
+ onError: defaults.onError ?? parentContext.onError,
281
+ showLoading: defaults.showLoading ?? parentContext.showLoading
282
+ }), [
283
+ defaults,
284
+ parentContext
285
+ ]);
286
+ return /* @__PURE__ */ React25.createElement(ToolContext.Provider, {
287
+ value
288
+ }, children);
289
+ }
290
+ __name(ToolProvider, "ToolProvider");
291
+ function useToolContext() {
292
+ return useContext(ToolContext);
293
+ }
294
+ __name(useToolContext, "useToolContext");
295
+ var Toaster = /* @__PURE__ */ __name(({ ...props }) => {
296
+ const { theme = "system" } = useTheme();
297
+ return /* @__PURE__ */ React25__default.createElement(Toaster$1, {
298
+ theme,
299
+ className: "toaster group",
300
+ icons: {
301
+ success: /* @__PURE__ */ React25__default.createElement(CircleCheckIcon, {
302
+ className: "size-4"
303
+ }),
304
+ info: /* @__PURE__ */ React25__default.createElement(InfoIcon, {
305
+ className: "size-4"
306
+ }),
307
+ warning: /* @__PURE__ */ React25__default.createElement(TriangleAlertIcon, {
308
+ className: "size-4"
309
+ }),
310
+ error: /* @__PURE__ */ React25__default.createElement(OctagonXIcon, {
311
+ className: "size-4"
312
+ }),
313
+ loading: /* @__PURE__ */ React25__default.createElement(Loader2Icon, {
314
+ className: "size-4 animate-spin"
315
+ })
316
+ },
317
+ style: {
318
+ "--normal-bg": "var(--popover)",
319
+ "--normal-text": "var(--popover-foreground)",
320
+ "--normal-border": "var(--border)",
321
+ "--border-radius": "var(--radius)"
322
+ },
323
+ ...props
324
+ });
325
+ }, "Toaster");
326
+ function cn(...inputs) {
327
+ return twMerge(clsx(inputs));
328
+ }
329
+ __name(cn, "cn");
330
+
331
+ // src/components/ui/button.tsx
332
+ var buttonVariants = cva("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", {
333
+ variants: {
334
+ variant: {
335
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
336
+ destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
337
+ outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
338
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
339
+ ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
340
+ link: "text-primary underline-offset-4 hover:underline"
341
+ },
342
+ size: {
343
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
344
+ sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
345
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
346
+ icon: "size-9",
347
+ "icon-sm": "size-8",
348
+ "icon-lg": "size-10"
349
+ }
350
+ },
351
+ defaultVariants: {
352
+ variant: "default",
353
+ size: "default"
354
+ }
355
+ });
356
+ function Button({ className, variant = "default", size = "default", asChild = false, ...props }) {
357
+ const Comp = asChild ? Slot : "button";
358
+ return /* @__PURE__ */ React25.createElement(Comp, {
359
+ "data-slot": "button",
360
+ "data-variant": variant,
361
+ "data-size": size,
362
+ className: cn(buttonVariants({
363
+ variant,
364
+ size,
365
+ className
366
+ })),
367
+ ...props
368
+ });
369
+ }
370
+ __name(Button, "Button");
371
+ function Dialog({ ...props }) {
372
+ return /* @__PURE__ */ React25.createElement(DialogPrimitive.Root, {
373
+ "data-slot": "dialog",
374
+ ...props
375
+ });
376
+ }
377
+ __name(Dialog, "Dialog");
378
+ function DialogTrigger({ ...props }) {
379
+ return /* @__PURE__ */ React25.createElement(DialogPrimitive.Trigger, {
380
+ "data-slot": "dialog-trigger",
381
+ ...props
382
+ });
383
+ }
384
+ __name(DialogTrigger, "DialogTrigger");
385
+ function DialogPortal({ ...props }) {
386
+ return /* @__PURE__ */ React25.createElement(DialogPrimitive.Portal, {
387
+ "data-slot": "dialog-portal",
388
+ ...props
389
+ });
390
+ }
391
+ __name(DialogPortal, "DialogPortal");
392
+ function DialogClose({ ...props }) {
393
+ return /* @__PURE__ */ React25.createElement(DialogPrimitive.Close, {
394
+ "data-slot": "dialog-close",
395
+ ...props
396
+ });
397
+ }
398
+ __name(DialogClose, "DialogClose");
399
+ function DialogOverlay({ className, ...props }) {
400
+ return /* @__PURE__ */ React25.createElement(DialogPrimitive.Overlay, {
401
+ "data-slot": "dialog-overlay",
402
+ className: cn("data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50", className),
403
+ ...props
404
+ });
405
+ }
406
+ __name(DialogOverlay, "DialogOverlay");
407
+ function DialogContent({ className, children, showCloseButton = true, ...props }) {
408
+ return /* @__PURE__ */ React25.createElement(DialogPortal, {
409
+ "data-slot": "dialog-portal"
410
+ }, /* @__PURE__ */ React25.createElement(DialogOverlay, null), /* @__PURE__ */ React25.createElement(DialogPrimitive.Content, {
411
+ "data-slot": "dialog-content",
412
+ className: cn("bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 outline-none sm:max-w-lg", className),
413
+ ...props
414
+ }, children, showCloseButton && /* @__PURE__ */ React25.createElement(DialogPrimitive.Close, {
415
+ "data-slot": "dialog-close",
416
+ className: "ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
417
+ }, /* @__PURE__ */ React25.createElement(XIcon, null), /* @__PURE__ */ React25.createElement("span", {
418
+ className: "sr-only"
419
+ }, "Close"))));
420
+ }
421
+ __name(DialogContent, "DialogContent");
422
+ function DialogHeader({ className, ...props }) {
423
+ return /* @__PURE__ */ React25.createElement("div", {
424
+ "data-slot": "dialog-header",
425
+ className: cn("flex flex-col gap-2 text-center sm:text-left", className),
426
+ ...props
427
+ });
428
+ }
429
+ __name(DialogHeader, "DialogHeader");
430
+ function DialogFooter({ className, ...props }) {
431
+ return /* @__PURE__ */ React25.createElement("div", {
432
+ "data-slot": "dialog-footer",
433
+ className: cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className),
434
+ ...props
435
+ });
436
+ }
437
+ __name(DialogFooter, "DialogFooter");
438
+ function DialogTitle({ className, ...props }) {
439
+ return /* @__PURE__ */ React25.createElement(DialogPrimitive.Title, {
440
+ "data-slot": "dialog-title",
441
+ className: cn("text-lg leading-none font-semibold", className),
442
+ ...props
443
+ });
444
+ }
445
+ __name(DialogTitle, "DialogTitle");
446
+ function DialogDescription({ className, ...props }) {
447
+ return /* @__PURE__ */ React25.createElement(DialogPrimitive.Description, {
448
+ "data-slot": "dialog-description",
449
+ className: cn("text-muted-foreground text-sm", className),
450
+ ...props
451
+ });
452
+ }
453
+ __name(DialogDescription, "DialogDescription");
454
+ function extractResultData(result) {
455
+ if ("structuredContent" in result && result.structuredContent) {
456
+ return result.structuredContent;
457
+ }
458
+ if (result.content && result.content.length > 0) {
459
+ const textContent = result.content.filter((c) => c.type === "text").map((c) => c.text).join("");
460
+ if (textContent) {
461
+ try {
462
+ return JSON.parse(textContent);
463
+ } catch {
464
+ return textContent;
465
+ }
466
+ }
467
+ }
468
+ return result;
469
+ }
470
+ __name(extractResultData, "extractResultData");
471
+ function useTool(toolName, options = {}) {
218
472
  const { callTool } = useMcpApp();
219
- const [loading, setLoading] = useState(false);
473
+ const [state, setState] = useState("idle");
220
474
  const [result, setResult] = useState(null);
221
475
  const [error, setError] = useState(null);
222
- const call = useCallback(async (args = {}) => {
223
- setLoading(true);
476
+ const abortControllerRef = useRef(null);
477
+ const lastArgsRef = useRef(void 0);
478
+ const retryCountRef = useRef(0);
479
+ const { defaultArgs, transform, retry, onStart, onSuccess, onError, onComplete } = options;
480
+ const retryConfig = typeof retry === "number" ? {
481
+ count: retry,
482
+ delay: 1e3
483
+ } : retry ?? {
484
+ count: 0,
485
+ delay: 1e3
486
+ };
487
+ const executeCall = useCallback(async (args) => {
488
+ const mergedArgs = {
489
+ ...defaultArgs,
490
+ ...args
491
+ };
492
+ lastArgsRef.current = mergedArgs;
493
+ abortControllerRef.current = new AbortController();
494
+ setState("loading");
224
495
  setError(null);
496
+ onStart?.();
225
497
  try {
226
- const response = await callTool(toolName, args);
227
- const data = response?.structuredContent ?? response;
498
+ const response = await callTool(toolName, mergedArgs);
499
+ if (abortControllerRef.current?.signal.aborted) {
500
+ throw new Error("Tool call aborted");
501
+ }
502
+ let data;
503
+ if (transform) {
504
+ data = transform(response);
505
+ } else {
506
+ data = extractResultData(response);
507
+ }
508
+ setState("success");
228
509
  setResult(data);
510
+ retryCountRef.current = 0;
511
+ onSuccess?.(data);
512
+ onComplete?.();
229
513
  return data;
230
514
  } catch (err) {
231
515
  const error2 = err instanceof Error ? err : new Error(String(err));
516
+ if (retryCountRef.current < retryConfig.count) {
517
+ retryCountRef.current++;
518
+ await new Promise((resolve) => setTimeout(resolve, retryConfig.delay));
519
+ return executeCall(args);
520
+ }
521
+ setState("error");
232
522
  setError(error2);
523
+ retryCountRef.current = 0;
524
+ onError?.(error2);
525
+ onComplete?.();
233
526
  throw error2;
234
- } finally {
235
- setLoading(false);
236
527
  }
237
528
  }, [
238
529
  callTool,
239
- toolName
530
+ toolName,
531
+ defaultArgs,
532
+ transform,
533
+ retryConfig,
534
+ onStart,
535
+ onSuccess,
536
+ onError,
537
+ onComplete
538
+ ]);
539
+ const call = useCallback(async (args) => {
540
+ retryCountRef.current = 0;
541
+ return executeCall(args);
542
+ }, [
543
+ executeCall
544
+ ]);
545
+ const mutate = useCallback(async (args) => {
546
+ return call(args);
547
+ }, [
548
+ call
240
549
  ]);
241
550
  const reset = useCallback(() => {
551
+ setState("idle");
242
552
  setResult(null);
243
553
  setError(null);
554
+ retryCountRef.current = 0;
555
+ abortControllerRef.current?.abort();
556
+ }, []);
557
+ const retryCall = useCallback(async () => {
558
+ if (lastArgsRef.current === void 0 && !defaultArgs) {
559
+ return null;
560
+ }
561
+ retryCountRef.current = 0;
562
+ return executeCall(lastArgsRef.current);
563
+ }, [
564
+ executeCall,
565
+ defaultArgs
566
+ ]);
567
+ const abort = useCallback(() => {
568
+ abortControllerRef.current?.abort();
569
+ setState("idle");
244
570
  }, []);
245
571
  return {
246
572
  call,
573
+ mutate,
574
+ state,
575
+ loading: state === "loading",
576
+ result,
577
+ error,
578
+ reset,
579
+ retry: retryCall,
580
+ abort
581
+ };
582
+ }
583
+ __name(useTool, "useTool");
584
+ function ToolButton({ tool, args = {}, resultDisplay = "none", renderResult, resultDuration = 3e3, successMessage, errorMessage, onToolStart, onToolSuccess, onToolError, onToolComplete, loadingText, loadingIcon, disableWhileLoading = true, confirm, children, className, variant = "default", size = "default", disabled, asChild = false, ...props }) {
585
+ const toolConfig = typeof tool === "string" ? {
586
+ name: tool
587
+ } : tool;
588
+ const mergedArgs = {
589
+ ...toolConfig.args,
590
+ ...args
591
+ };
592
+ const { call, state, loading, result, error, reset } = useTool(toolConfig.name, {
593
+ defaultArgs: mergedArgs,
594
+ transform: toolConfig.transform,
595
+ onStart: onToolStart,
596
+ onSuccess: onToolSuccess,
597
+ onError: onToolError,
598
+ onComplete: onToolComplete
599
+ });
600
+ const [showConfirm, setShowConfirm] = useState(false);
601
+ const [showResult, setShowResult] = useState(false);
602
+ const buttonState = {
247
603
  loading,
604
+ state,
248
605
  result,
249
606
  error,
250
- reset
607
+ hasResult: result !== null || error !== null
608
+ };
609
+ const executeCall = useCallback(async () => {
610
+ try {
611
+ const res = await call();
612
+ if (resultDisplay === "toast") {
613
+ const message = typeof successMessage === "function" ? successMessage(res) : successMessage ?? "Success";
614
+ toast.success(message);
615
+ } else if (resultDisplay === "inline") {
616
+ setShowResult(true);
617
+ setTimeout(() => setShowResult(false), resultDuration);
618
+ }
619
+ } catch (err) {
620
+ if (resultDisplay === "toast") {
621
+ const message = typeof errorMessage === "function" ? errorMessage(err instanceof Error ? err : new Error(String(err))) : errorMessage ?? (err instanceof Error ? err.message : "An error occurred");
622
+ toast.error(message);
623
+ } else if (resultDisplay === "inline") {
624
+ setShowResult(true);
625
+ setTimeout(() => setShowResult(false), resultDuration);
626
+ }
627
+ }
628
+ }, [
629
+ call,
630
+ resultDisplay,
631
+ successMessage,
632
+ errorMessage,
633
+ resultDuration
634
+ ]);
635
+ const handleClick = useCallback(() => {
636
+ if (confirm) {
637
+ setShowConfirm(true);
638
+ } else {
639
+ executeCall();
640
+ }
641
+ }, [
642
+ confirm,
643
+ executeCall
644
+ ]);
645
+ const handleConfirm = useCallback(() => {
646
+ setShowConfirm(false);
647
+ executeCall();
648
+ }, [
649
+ executeCall
650
+ ]);
651
+ const confirmConfig = typeof confirm === "object" ? confirm : {
652
+ title: "Confirm Action",
653
+ description: "Are you sure you want to proceed?",
654
+ confirmText: "Confirm",
655
+ cancelText: "Cancel"
251
656
  };
657
+ const renderChildren = /* @__PURE__ */ __name(() => {
658
+ if (typeof children === "function") {
659
+ return children(buttonState);
660
+ }
661
+ if (loading) {
662
+ return /* @__PURE__ */ React25.createElement(React25.Fragment, null, loadingIcon ?? /* @__PURE__ */ React25.createElement(Loader2, {
663
+ className: "animate-spin"
664
+ }), loadingText && /* @__PURE__ */ React25.createElement("span", null, loadingText), !loadingText && children);
665
+ }
666
+ if (showResult && resultDisplay === "inline") {
667
+ if (error) {
668
+ return /* @__PURE__ */ React25.createElement(React25.Fragment, null, /* @__PURE__ */ React25.createElement(X, {
669
+ className: "text-destructive"
670
+ }), /* @__PURE__ */ React25.createElement("span", null, error.message));
671
+ }
672
+ if (renderResult) {
673
+ return renderResult(result);
674
+ }
675
+ return /* @__PURE__ */ React25.createElement(React25.Fragment, null, /* @__PURE__ */ React25.createElement(Check, {
676
+ className: "text-success"
677
+ }), /* @__PURE__ */ React25.createElement("span", null, "Done"));
678
+ }
679
+ return children;
680
+ }, "renderChildren");
681
+ return /* @__PURE__ */ React25.createElement(React25.Fragment, null, /* @__PURE__ */ React25.createElement(Button, {
682
+ type: "button",
683
+ variant,
684
+ size,
685
+ className: cn(className),
686
+ disabled: disabled || disableWhileLoading && loading,
687
+ onClick: handleClick,
688
+ asChild,
689
+ ...props
690
+ }, renderChildren()), confirm && /* @__PURE__ */ React25.createElement(Dialog, {
691
+ open: showConfirm,
692
+ onOpenChange: setShowConfirm
693
+ }, /* @__PURE__ */ React25.createElement(DialogContent, null, /* @__PURE__ */ React25.createElement(DialogHeader, null, /* @__PURE__ */ React25.createElement(DialogTitle, null, confirmConfig.title), confirmConfig.description && /* @__PURE__ */ React25.createElement(DialogDescription, null, confirmConfig.description)), /* @__PURE__ */ React25.createElement(DialogFooter, null, /* @__PURE__ */ React25.createElement(Button, {
694
+ variant: "outline",
695
+ onClick: /* @__PURE__ */ __name(() => setShowConfirm(false), "onClick")
696
+ }, confirmConfig.cancelText ?? "Cancel"), /* @__PURE__ */ React25.createElement(Button, {
697
+ variant: confirmConfig.confirmVariant ?? (variant === "destructive" ? "destructive" : "default"),
698
+ onClick: handleConfirm
699
+ }, confirmConfig.confirmText ?? "Confirm")))));
700
+ }
701
+ __name(ToolButton, "ToolButton");
702
+ function Select({ ...props }) {
703
+ return /* @__PURE__ */ React25.createElement(SelectPrimitive.Root, {
704
+ "data-slot": "select",
705
+ ...props
706
+ });
707
+ }
708
+ __name(Select, "Select");
709
+ function SelectGroup({ ...props }) {
710
+ return /* @__PURE__ */ React25.createElement(SelectPrimitive.Group, {
711
+ "data-slot": "select-group",
712
+ ...props
713
+ });
714
+ }
715
+ __name(SelectGroup, "SelectGroup");
716
+ function SelectValue({ ...props }) {
717
+ return /* @__PURE__ */ React25.createElement(SelectPrimitive.Value, {
718
+ "data-slot": "select-value",
719
+ ...props
720
+ });
721
+ }
722
+ __name(SelectValue, "SelectValue");
723
+ function SelectTrigger({ className, size = "default", children, ...props }) {
724
+ return /* @__PURE__ */ React25.createElement(SelectPrimitive.Trigger, {
725
+ "data-slot": "select-trigger",
726
+ "data-size": size,
727
+ className: cn("border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className),
728
+ ...props
729
+ }, children, /* @__PURE__ */ React25.createElement(SelectPrimitive.Icon, {
730
+ asChild: true
731
+ }, /* @__PURE__ */ React25.createElement(ChevronDownIcon, {
732
+ className: "size-4 opacity-50"
733
+ })));
734
+ }
735
+ __name(SelectTrigger, "SelectTrigger");
736
+ function SelectContent({ className, children, position = "item-aligned", align = "center", ...props }) {
737
+ return /* @__PURE__ */ React25.createElement(SelectPrimitive.Portal, null, /* @__PURE__ */ React25.createElement(SelectPrimitive.Content, {
738
+ "data-slot": "select-content",
739
+ className: cn("bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md", position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", className),
740
+ position,
741
+ align,
742
+ ...props
743
+ }, /* @__PURE__ */ React25.createElement(SelectScrollUpButton, null), /* @__PURE__ */ React25.createElement(SelectPrimitive.Viewport, {
744
+ className: cn("p-1", position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1")
745
+ }, children), /* @__PURE__ */ React25.createElement(SelectScrollDownButton, null)));
746
+ }
747
+ __name(SelectContent, "SelectContent");
748
+ function SelectLabel({ className, ...props }) {
749
+ return /* @__PURE__ */ React25.createElement(SelectPrimitive.Label, {
750
+ "data-slot": "select-label",
751
+ className: cn("text-muted-foreground px-2 py-1.5 text-xs", className),
752
+ ...props
753
+ });
754
+ }
755
+ __name(SelectLabel, "SelectLabel");
756
+ function SelectItem({ className, children, ...props }) {
757
+ return /* @__PURE__ */ React25.createElement(SelectPrimitive.Item, {
758
+ "data-slot": "select-item",
759
+ className: cn("focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2", className),
760
+ ...props
761
+ }, /* @__PURE__ */ React25.createElement("span", {
762
+ "data-slot": "select-item-indicator",
763
+ className: "absolute right-2 flex size-3.5 items-center justify-center"
764
+ }, /* @__PURE__ */ React25.createElement(SelectPrimitive.ItemIndicator, null, /* @__PURE__ */ React25.createElement(CheckIcon, {
765
+ className: "size-4"
766
+ }))), /* @__PURE__ */ React25.createElement(SelectPrimitive.ItemText, null, children));
767
+ }
768
+ __name(SelectItem, "SelectItem");
769
+ function SelectSeparator({ className, ...props }) {
770
+ return /* @__PURE__ */ React25.createElement(SelectPrimitive.Separator, {
771
+ "data-slot": "select-separator",
772
+ className: cn("bg-border pointer-events-none -mx-1 my-1 h-px", className),
773
+ ...props
774
+ });
775
+ }
776
+ __name(SelectSeparator, "SelectSeparator");
777
+ function SelectScrollUpButton({ className, ...props }) {
778
+ return /* @__PURE__ */ React25.createElement(SelectPrimitive.ScrollUpButton, {
779
+ "data-slot": "select-scroll-up-button",
780
+ className: cn("flex cursor-default items-center justify-center py-1", className),
781
+ ...props
782
+ }, /* @__PURE__ */ React25.createElement(ChevronUpIcon, {
783
+ className: "size-4"
784
+ }));
785
+ }
786
+ __name(SelectScrollUpButton, "SelectScrollUpButton");
787
+ function SelectScrollDownButton({ className, ...props }) {
788
+ return /* @__PURE__ */ React25.createElement(SelectPrimitive.ScrollDownButton, {
789
+ "data-slot": "select-scroll-down-button",
790
+ className: cn("flex cursor-default items-center justify-center py-1", className),
791
+ ...props
792
+ }, /* @__PURE__ */ React25.createElement(ChevronDownIcon, {
793
+ className: "size-4"
794
+ }));
795
+ }
796
+ __name(SelectScrollDownButton, "SelectScrollDownButton");
797
+ function ToolSelect({ onSelectTool, argName = "value", additionalArgs = {}, optionsTool, optionsArgs = {}, transformOptions, options: staticOptions = [], placeholder = "Select an option", loadingPlaceholder = "Loading...", emptyMessage = "No options available", value: controlledValue, defaultValue, onValueChange, onOptionsLoaded, onSelectionSuccess, onSelectionError, showSuccessToast = false, successMessage, className, disabled = false }) {
798
+ const [fetchedOptions, setFetchedOptions] = useState([]);
799
+ const [internalValue, setInternalValue] = useState(defaultValue ?? "");
800
+ const optionsToolConfig = optionsTool ? typeof optionsTool === "string" ? {
801
+ name: optionsTool
802
+ } : optionsTool : null;
803
+ const selectToolConfig = onSelectTool ? typeof onSelectTool === "string" ? {
804
+ name: onSelectTool
805
+ } : onSelectTool : null;
806
+ const optionsHook = useTool(optionsToolConfig?.name ?? "", {
807
+ defaultArgs: {
808
+ ...optionsToolConfig?.args,
809
+ ...optionsArgs
810
+ }
811
+ });
812
+ const selectHook = useTool(selectToolConfig?.name ?? "", {
813
+ onSuccess: /* @__PURE__ */ __name((result) => {
814
+ onSelectionSuccess?.(result);
815
+ if (showSuccessToast) {
816
+ const message = typeof successMessage === "function" ? successMessage(result) : successMessage ?? "Selection saved";
817
+ toast.success(message);
818
+ }
819
+ }, "onSuccess"),
820
+ onError: onSelectionError
821
+ });
822
+ useEffect(() => {
823
+ if (optionsToolConfig) {
824
+ optionsHook.call().then((result) => {
825
+ const options = transformOptions ? transformOptions(result) : result;
826
+ setFetchedOptions(options);
827
+ onOptionsLoaded?.(options);
828
+ }).catch(() => {
829
+ });
830
+ }
831
+ }, [
832
+ optionsToolConfig?.name
833
+ ]);
834
+ const allOptions = [
835
+ ...staticOptions,
836
+ ...fetchedOptions
837
+ ];
838
+ const value = controlledValue ?? internalValue;
839
+ const handleValueChange = useCallback((newValue) => {
840
+ setInternalValue(newValue);
841
+ onValueChange?.(newValue);
842
+ if (selectToolConfig) {
843
+ selectHook.call({
844
+ [argName]: newValue,
845
+ ...additionalArgs
846
+ });
847
+ }
848
+ }, [
849
+ onValueChange,
850
+ selectToolConfig,
851
+ argName,
852
+ additionalArgs,
853
+ selectHook
854
+ ]);
855
+ const isLoading = optionsHook.loading || selectHook.loading;
856
+ const hasError = optionsHook.error || selectHook.error;
857
+ return /* @__PURE__ */ React25.createElement(Select, {
858
+ value,
859
+ onValueChange: handleValueChange,
860
+ disabled: disabled || isLoading
861
+ }, /* @__PURE__ */ React25.createElement(SelectTrigger, {
862
+ className: cn("w-full", className)
863
+ }, isLoading ? /* @__PURE__ */ React25.createElement("div", {
864
+ className: "flex items-center gap-2"
865
+ }, /* @__PURE__ */ React25.createElement(Loader2, {
866
+ className: "h-4 w-4 animate-spin"
867
+ }), /* @__PURE__ */ React25.createElement("span", {
868
+ className: "text-muted-foreground"
869
+ }, optionsHook.loading ? loadingPlaceholder : "Saving...")) : /* @__PURE__ */ React25.createElement(SelectValue, {
870
+ placeholder
871
+ })), /* @__PURE__ */ React25.createElement(SelectContent, null, allOptions.length === 0 ? /* @__PURE__ */ React25.createElement("div", {
872
+ className: "py-6 text-center text-sm text-muted-foreground"
873
+ }, hasError ? "Error loading options" : emptyMessage) : allOptions.map((option) => /* @__PURE__ */ React25.createElement(SelectItem, {
874
+ key: option.value,
875
+ value: option.value,
876
+ disabled: option.disabled
877
+ }, /* @__PURE__ */ React25.createElement("div", {
878
+ className: "flex items-center gap-2"
879
+ }, option.icon, /* @__PURE__ */ React25.createElement("div", null, /* @__PURE__ */ React25.createElement("div", null, option.label), option.description && /* @__PURE__ */ React25.createElement("div", {
880
+ className: "text-xs text-muted-foreground"
881
+ }, option.description)))))));
882
+ }
883
+ __name(ToolSelect, "ToolSelect");
884
+ function Input({ className, type, ...props }) {
885
+ return /* @__PURE__ */ React25.createElement("input", {
886
+ type,
887
+ "data-slot": "input",
888
+ className: cn("file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]", "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", className),
889
+ ...props
890
+ });
891
+ }
892
+ __name(Input, "Input");
893
+ function Command({ className, ...props }) {
894
+ return /* @__PURE__ */ React25.createElement(Command$1, {
895
+ "data-slot": "command",
896
+ className: cn("bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md", className),
897
+ ...props
898
+ });
899
+ }
900
+ __name(Command, "Command");
901
+ function CommandDialog({ title = "Command Palette", description = "Search for a command to run...", children, className, showCloseButton = true, ...props }) {
902
+ return /* @__PURE__ */ React25.createElement(Dialog, props, /* @__PURE__ */ React25.createElement(DialogHeader, {
903
+ className: "sr-only"
904
+ }, /* @__PURE__ */ React25.createElement(DialogTitle, null, title), /* @__PURE__ */ React25.createElement(DialogDescription, null, description)), /* @__PURE__ */ React25.createElement(DialogContent, {
905
+ className: cn("overflow-hidden p-0", className),
906
+ showCloseButton
907
+ }, /* @__PURE__ */ React25.createElement(Command, {
908
+ className: "[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5"
909
+ }, children)));
910
+ }
911
+ __name(CommandDialog, "CommandDialog");
912
+ function CommandInput({ className, ...props }) {
913
+ return /* @__PURE__ */ React25.createElement("div", {
914
+ "data-slot": "command-input-wrapper",
915
+ className: "flex h-9 items-center gap-2 border-b px-3"
916
+ }, /* @__PURE__ */ React25.createElement(SearchIcon, {
917
+ className: "size-4 shrink-0 opacity-50"
918
+ }), /* @__PURE__ */ React25.createElement(Command$1.Input, {
919
+ "data-slot": "command-input",
920
+ className: cn("placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50", className),
921
+ ...props
922
+ }));
923
+ }
924
+ __name(CommandInput, "CommandInput");
925
+ function CommandList({ className, ...props }) {
926
+ return /* @__PURE__ */ React25.createElement(Command$1.List, {
927
+ "data-slot": "command-list",
928
+ className: cn("max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto", className),
929
+ ...props
930
+ });
931
+ }
932
+ __name(CommandList, "CommandList");
933
+ function CommandEmpty({ ...props }) {
934
+ return /* @__PURE__ */ React25.createElement(Command$1.Empty, {
935
+ "data-slot": "command-empty",
936
+ className: "py-6 text-center text-sm",
937
+ ...props
938
+ });
939
+ }
940
+ __name(CommandEmpty, "CommandEmpty");
941
+ function CommandGroup({ className, ...props }) {
942
+ return /* @__PURE__ */ React25.createElement(Command$1.Group, {
943
+ "data-slot": "command-group",
944
+ className: cn("text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium", className),
945
+ ...props
946
+ });
947
+ }
948
+ __name(CommandGroup, "CommandGroup");
949
+ function CommandSeparator({ className, ...props }) {
950
+ return /* @__PURE__ */ React25.createElement(Command$1.Separator, {
951
+ "data-slot": "command-separator",
952
+ className: cn("bg-border -mx-1 h-px", className),
953
+ ...props
954
+ });
955
+ }
956
+ __name(CommandSeparator, "CommandSeparator");
957
+ function CommandItem({ className, ...props }) {
958
+ return /* @__PURE__ */ React25.createElement(Command$1.Item, {
959
+ "data-slot": "command-item",
960
+ className: cn("data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className),
961
+ ...props
962
+ });
963
+ }
964
+ __name(CommandItem, "CommandItem");
965
+ function CommandShortcut({ className, ...props }) {
966
+ return /* @__PURE__ */ React25.createElement("span", {
967
+ "data-slot": "command-shortcut",
968
+ className: cn("text-muted-foreground ml-auto text-xs tracking-widest", className),
969
+ ...props
970
+ });
971
+ }
972
+ __name(CommandShortcut, "CommandShortcut");
973
+ function Popover({ ...props }) {
974
+ return /* @__PURE__ */ React25.createElement(PopoverPrimitive.Root, {
975
+ "data-slot": "popover",
976
+ ...props
977
+ });
978
+ }
979
+ __name(Popover, "Popover");
980
+ function PopoverTrigger({ ...props }) {
981
+ return /* @__PURE__ */ React25.createElement(PopoverPrimitive.Trigger, {
982
+ "data-slot": "popover-trigger",
983
+ ...props
984
+ });
985
+ }
986
+ __name(PopoverTrigger, "PopoverTrigger");
987
+ function PopoverContent({ className, align = "center", sideOffset = 4, ...props }) {
988
+ return /* @__PURE__ */ React25.createElement(PopoverPrimitive.Portal, null, /* @__PURE__ */ React25.createElement(PopoverPrimitive.Content, {
989
+ "data-slot": "popover-content",
990
+ align,
991
+ sideOffset,
992
+ className: cn("bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden", className),
993
+ ...props
994
+ }));
995
+ }
996
+ __name(PopoverContent, "PopoverContent");
997
+ function PopoverAnchor({ ...props }) {
998
+ return /* @__PURE__ */ React25.createElement(PopoverPrimitive.Anchor, {
999
+ "data-slot": "popover-anchor",
1000
+ ...props
1001
+ });
1002
+ }
1003
+ __name(PopoverAnchor, "PopoverAnchor");
1004
+
1005
+ // src/mcp/ToolInput.tsx
1006
+ function ToolInput({ searchTool, debounce = 300, minChars = 1, argName = "query", additionalArgs = {}, autocomplete = false, transformSuggestions, onSuggestionSelect, emptyMessage = "No results found", value: controlledValue, onChange, onSearchResults, onSearchError, showSearchIcon = true, showClearButton = true, showLoadingIndicator = true, className, placeholder = "Search...", disabled, ...props }) {
1007
+ const [internalValue, setInternalValue] = useState("");
1008
+ const [suggestions, setSuggestions] = useState([]);
1009
+ const [isOpen, setIsOpen] = useState(false);
1010
+ const debounceRef = useRef(null);
1011
+ const inputRef = useRef(null);
1012
+ const toolConfig = searchTool ? typeof searchTool === "string" ? {
1013
+ name: searchTool
1014
+ } : searchTool : null;
1015
+ const { call, loading, error, reset } = useTool(toolConfig?.name ?? "", {
1016
+ defaultArgs: {
1017
+ ...toolConfig?.args,
1018
+ ...additionalArgs
1019
+ },
1020
+ onSuccess: /* @__PURE__ */ __name((result) => {
1021
+ onSearchResults?.(result);
1022
+ if (autocomplete && transformSuggestions) {
1023
+ const suggestions2 = transformSuggestions(result);
1024
+ setSuggestions(suggestions2);
1025
+ if (suggestions2.length > 0) {
1026
+ setIsOpen(true);
1027
+ }
1028
+ }
1029
+ }, "onSuccess"),
1030
+ onError: onSearchError
1031
+ });
1032
+ const value = controlledValue ?? internalValue;
1033
+ const handleChange = useCallback((e) => {
1034
+ const newValue = e.target.value;
1035
+ setInternalValue(newValue);
1036
+ onChange?.(newValue);
1037
+ if (debounceRef.current) {
1038
+ clearTimeout(debounceRef.current);
1039
+ }
1040
+ if (newValue.length < minChars) {
1041
+ setSuggestions([]);
1042
+ setIsOpen(false);
1043
+ return;
1044
+ }
1045
+ if (toolConfig) {
1046
+ debounceRef.current = setTimeout(() => {
1047
+ call({
1048
+ [argName]: newValue
1049
+ });
1050
+ }, debounce);
1051
+ }
1052
+ }, [
1053
+ onChange,
1054
+ minChars,
1055
+ toolConfig,
1056
+ argName,
1057
+ debounce,
1058
+ call
1059
+ ]);
1060
+ const handleClear = useCallback(() => {
1061
+ setInternalValue("");
1062
+ onChange?.("");
1063
+ setSuggestions([]);
1064
+ setIsOpen(false);
1065
+ reset();
1066
+ inputRef.current?.focus();
1067
+ }, [
1068
+ onChange,
1069
+ reset
1070
+ ]);
1071
+ const handleSelect = useCallback((suggestion) => {
1072
+ setInternalValue(suggestion.label);
1073
+ onChange?.(suggestion.label);
1074
+ setIsOpen(false);
1075
+ onSuggestionSelect?.(suggestion);
1076
+ }, [
1077
+ onChange,
1078
+ onSuggestionSelect
1079
+ ]);
1080
+ useEffect(() => {
1081
+ return () => {
1082
+ if (debounceRef.current) {
1083
+ clearTimeout(debounceRef.current);
1084
+ }
1085
+ };
1086
+ }, []);
1087
+ const inputElement = /* @__PURE__ */ React25.createElement("div", {
1088
+ className: cn("relative", className)
1089
+ }, showSearchIcon && /* @__PURE__ */ React25.createElement(Search, {
1090
+ className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground"
1091
+ }), /* @__PURE__ */ React25.createElement(Input, {
1092
+ ref: inputRef,
1093
+ value,
1094
+ onChange: handleChange,
1095
+ placeholder,
1096
+ disabled,
1097
+ className: cn(showSearchIcon && "pl-9", (showClearButton || showLoadingIndicator) && "pr-9"),
1098
+ ...props
1099
+ }), /* @__PURE__ */ React25.createElement("div", {
1100
+ className: "absolute right-3 top-1/2 -translate-y-1/2 flex items-center gap-1"
1101
+ }, showLoadingIndicator && loading && /* @__PURE__ */ React25.createElement(Loader2, {
1102
+ className: "h-4 w-4 animate-spin text-muted-foreground"
1103
+ }), showClearButton && value && !loading && /* @__PURE__ */ React25.createElement("button", {
1104
+ type: "button",
1105
+ onClick: handleClear,
1106
+ className: "h-4 w-4 text-muted-foreground hover:text-foreground transition-colors"
1107
+ }, /* @__PURE__ */ React25.createElement(X, {
1108
+ className: "h-4 w-4"
1109
+ }))));
1110
+ if (!autocomplete) {
1111
+ return inputElement;
1112
+ }
1113
+ return /* @__PURE__ */ React25.createElement(Popover, {
1114
+ open: isOpen,
1115
+ onOpenChange: setIsOpen
1116
+ }, /* @__PURE__ */ React25.createElement(PopoverTrigger, {
1117
+ asChild: true
1118
+ }, inputElement), /* @__PURE__ */ React25.createElement(PopoverContent, {
1119
+ className: "p-0 w-[var(--radix-popover-trigger-width)]",
1120
+ align: "start",
1121
+ onOpenAutoFocus: /* @__PURE__ */ __name((e) => e.preventDefault(), "onOpenAutoFocus")
1122
+ }, /* @__PURE__ */ React25.createElement(Command, null, /* @__PURE__ */ React25.createElement(CommandList, null, /* @__PURE__ */ React25.createElement(CommandEmpty, null, emptyMessage), /* @__PURE__ */ React25.createElement(CommandGroup, null, suggestions.map((suggestion) => /* @__PURE__ */ React25.createElement(CommandItem, {
1123
+ key: suggestion.value,
1124
+ value: suggestion.value,
1125
+ onSelect: /* @__PURE__ */ __name(() => handleSelect(suggestion), "onSelect")
1126
+ }, /* @__PURE__ */ React25.createElement("div", {
1127
+ className: "flex items-center gap-2"
1128
+ }, suggestion.icon, /* @__PURE__ */ React25.createElement("div", null, /* @__PURE__ */ React25.createElement("div", null, suggestion.label), suggestion.description && /* @__PURE__ */ React25.createElement("div", {
1129
+ className: "text-xs text-muted-foreground"
1130
+ }, suggestion.description))))))))));
1131
+ }
1132
+ __name(ToolInput, "ToolInput");
1133
+ function Label2({ className, ...props }) {
1134
+ return /* @__PURE__ */ React25.createElement(LabelPrimitive.Root, {
1135
+ "data-slot": "label",
1136
+ className: cn("flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50", className),
1137
+ ...props
1138
+ });
1139
+ }
1140
+ __name(Label2, "Label");
1141
+ function Textarea({ className, ...props }) {
1142
+ return /* @__PURE__ */ React25.createElement("textarea", {
1143
+ "data-slot": "textarea",
1144
+ className: cn("border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", className),
1145
+ ...props
1146
+ });
1147
+ }
1148
+ __name(Textarea, "Textarea");
1149
+ function Checkbox({ className, ...props }) {
1150
+ return /* @__PURE__ */ React25.createElement(CheckboxPrimitive.Root, {
1151
+ "data-slot": "checkbox",
1152
+ className: cn("peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50", className),
1153
+ ...props
1154
+ }, /* @__PURE__ */ React25.createElement(CheckboxPrimitive.Indicator, {
1155
+ "data-slot": "checkbox-indicator",
1156
+ className: "grid place-content-center text-current transition-none"
1157
+ }, /* @__PURE__ */ React25.createElement(CheckIcon, {
1158
+ className: "size-3.5"
1159
+ })));
1160
+ }
1161
+ __name(Checkbox, "Checkbox");
1162
+ function Slider({ className, defaultValue, value, min = 0, max = 100, ...props }) {
1163
+ const _values = React25.useMemo(() => Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [
1164
+ min,
1165
+ max
1166
+ ], [
1167
+ value,
1168
+ defaultValue,
1169
+ min,
1170
+ max
1171
+ ]);
1172
+ return /* @__PURE__ */ React25.createElement(SliderPrimitive.Root, {
1173
+ "data-slot": "slider",
1174
+ defaultValue,
1175
+ value,
1176
+ min,
1177
+ max,
1178
+ className: cn("relative flex w-full touch-none items-center select-none data-[disabled]:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col", className),
1179
+ ...props
1180
+ }, /* @__PURE__ */ React25.createElement(SliderPrimitive.Track, {
1181
+ "data-slot": "slider-track",
1182
+ className: cn("bg-muted relative grow overflow-hidden rounded-full data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5")
1183
+ }, /* @__PURE__ */ React25.createElement(SliderPrimitive.Range, {
1184
+ "data-slot": "slider-range",
1185
+ className: cn("bg-primary absolute data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full")
1186
+ })), Array.from({
1187
+ length: _values.length
1188
+ }, (_, index) => /* @__PURE__ */ React25.createElement(SliderPrimitive.Thumb, {
1189
+ "data-slot": "slider-thumb",
1190
+ key: index,
1191
+ className: "border-primary ring-ring/50 block size-4 shrink-0 rounded-full border bg-white shadow-sm transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50"
1192
+ })));
1193
+ }
1194
+ __name(Slider, "Slider");
1195
+ function Switch({ className, ...props }) {
1196
+ return /* @__PURE__ */ React25.createElement(SwitchPrimitive.Root, {
1197
+ "data-slot": "switch",
1198
+ className: cn("peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50", className),
1199
+ ...props
1200
+ }, /* @__PURE__ */ React25.createElement(SwitchPrimitive.Thumb, {
1201
+ "data-slot": "switch-thumb",
1202
+ className: cn("bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0")
1203
+ }));
1204
+ }
1205
+ __name(Switch, "Switch");
1206
+ var alertVariants = cva("relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current", {
1207
+ variants: {
1208
+ variant: {
1209
+ default: "bg-card text-card-foreground",
1210
+ destructive: "text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90"
1211
+ }
1212
+ },
1213
+ defaultVariants: {
1214
+ variant: "default"
1215
+ }
1216
+ });
1217
+ function Alert({ className, variant, ...props }) {
1218
+ return /* @__PURE__ */ React25.createElement("div", {
1219
+ "data-slot": "alert",
1220
+ role: "alert",
1221
+ className: cn(alertVariants({
1222
+ variant
1223
+ }), className),
1224
+ ...props
1225
+ });
1226
+ }
1227
+ __name(Alert, "Alert");
1228
+ function AlertTitle({ className, ...props }) {
1229
+ return /* @__PURE__ */ React25.createElement("div", {
1230
+ "data-slot": "alert-title",
1231
+ className: cn("col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight", className),
1232
+ ...props
1233
+ });
1234
+ }
1235
+ __name(AlertTitle, "AlertTitle");
1236
+ function AlertDescription({ className, ...props }) {
1237
+ return /* @__PURE__ */ React25.createElement("div", {
1238
+ "data-slot": "alert-description",
1239
+ className: cn("text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed", className),
1240
+ ...props
1241
+ });
1242
+ }
1243
+ __name(AlertDescription, "AlertDescription");
1244
+ function ToolForm({ toolName, fields: manualFields, autoSchema = false, submitText = "Submit", loadingText, onSuccess, onError, showResult = false, showSuccessToast = false, successMessage, resetOnSuccess = false, className, layout = "vertical" }) {
1245
+ const { app, isConnected } = useMcpApp();
1246
+ const { call, loading, result, error, reset } = useTool(toolName, {
1247
+ onSuccess: /* @__PURE__ */ __name((result2) => {
1248
+ onSuccess?.(result2);
1249
+ if (showSuccessToast) {
1250
+ const message = typeof successMessage === "function" ? successMessage(result2) : successMessage ?? "Form submitted successfully";
1251
+ toast.success(message);
1252
+ }
1253
+ if (resetOnSuccess) {
1254
+ resetForm();
1255
+ }
1256
+ }, "onSuccess"),
1257
+ onError
1258
+ });
1259
+ const [fields, setFields] = useState(manualFields ?? []);
1260
+ const [schemaLoading, setSchemaLoading] = useState(autoSchema);
1261
+ const [formData, setFormData] = useState({});
1262
+ const initializeFormData = /* @__PURE__ */ __name((fields2) => {
1263
+ const initial = {};
1264
+ fields2.forEach((field) => {
1265
+ if (field.defaultValue !== void 0) {
1266
+ initial[field.name] = field.defaultValue;
1267
+ } else if (field.type === "checkbox" || field.type === "switch") {
1268
+ initial[field.name] = false;
1269
+ } else if (field.type === "number" || field.type === "slider") {
1270
+ initial[field.name] = field.min ?? 0;
1271
+ } else {
1272
+ initial[field.name] = "";
1273
+ }
1274
+ });
1275
+ setFormData(initial);
1276
+ }, "initializeFormData");
1277
+ const resetForm = /* @__PURE__ */ __name(() => {
1278
+ initializeFormData(fields);
1279
+ reset();
1280
+ }, "resetForm");
1281
+ useEffect(() => {
1282
+ if (autoSchema && app && isConnected) {
1283
+ setSchemaLoading(true);
1284
+ const fetchSchema = /* @__PURE__ */ __name(async () => {
1285
+ try {
1286
+ console.warn("[ToolForm] Auto-schema not fully implemented, use manual fields");
1287
+ if (manualFields) {
1288
+ setFields(manualFields);
1289
+ initializeFormData(manualFields);
1290
+ }
1291
+ } catch (err) {
1292
+ console.error("[ToolForm] Failed to fetch schema:", err);
1293
+ } finally {
1294
+ setSchemaLoading(false);
1295
+ }
1296
+ }, "fetchSchema");
1297
+ fetchSchema();
1298
+ } else if (manualFields) {
1299
+ setFields(manualFields);
1300
+ initializeFormData(manualFields);
1301
+ }
1302
+ }, [
1303
+ autoSchema,
1304
+ app,
1305
+ isConnected,
1306
+ manualFields,
1307
+ toolName
1308
+ ]);
1309
+ const handleSubmit = /* @__PURE__ */ __name(async (e) => {
1310
+ e.preventDefault();
1311
+ const args = {};
1312
+ fields.forEach((field) => {
1313
+ let value = formData[field.name];
1314
+ if (field.type === "number" || field.type === "slider") {
1315
+ value = Number(value);
1316
+ }
1317
+ args[field.name] = value;
1318
+ });
1319
+ await call(args);
1320
+ }, "handleSubmit");
1321
+ const handleChange = /* @__PURE__ */ __name((name, value) => {
1322
+ setFormData((prev) => ({
1323
+ ...prev,
1324
+ [name]: value
1325
+ }));
1326
+ }, "handleChange");
1327
+ const renderField = /* @__PURE__ */ __name((field) => {
1328
+ const value = formData[field.name];
1329
+ switch (field.type) {
1330
+ case "textarea":
1331
+ return /* @__PURE__ */ React25.createElement(Textarea, {
1332
+ id: field.name,
1333
+ placeholder: field.placeholder,
1334
+ value: value ?? "",
1335
+ onChange: /* @__PURE__ */ __name((e) => handleChange(field.name, e.target.value), "onChange"),
1336
+ disabled: field.disabled || loading,
1337
+ required: field.required
1338
+ });
1339
+ case "select":
1340
+ return /* @__PURE__ */ React25.createElement(Select, {
1341
+ value: value ?? "",
1342
+ onValueChange: /* @__PURE__ */ __name((v) => handleChange(field.name, v), "onValueChange"),
1343
+ disabled: field.disabled || loading
1344
+ }, /* @__PURE__ */ React25.createElement(SelectTrigger, null, /* @__PURE__ */ React25.createElement(SelectValue, {
1345
+ placeholder: field.placeholder ?? "Select..."
1346
+ })), /* @__PURE__ */ React25.createElement(SelectContent, null, field.options?.map((option) => /* @__PURE__ */ React25.createElement(SelectItem, {
1347
+ key: option.value,
1348
+ value: option.value
1349
+ }, option.label))));
1350
+ case "checkbox":
1351
+ return /* @__PURE__ */ React25.createElement("div", {
1352
+ className: "flex items-center space-x-2"
1353
+ }, /* @__PURE__ */ React25.createElement(Checkbox, {
1354
+ id: field.name,
1355
+ checked: value ?? false,
1356
+ onCheckedChange: /* @__PURE__ */ __name((checked) => handleChange(field.name, checked), "onCheckedChange"),
1357
+ disabled: field.disabled || loading
1358
+ }), /* @__PURE__ */ React25.createElement("label", {
1359
+ htmlFor: field.name,
1360
+ className: "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
1361
+ }, field.label));
1362
+ case "switch":
1363
+ return /* @__PURE__ */ React25.createElement("div", {
1364
+ className: "flex items-center space-x-2"
1365
+ }, /* @__PURE__ */ React25.createElement(Switch, {
1366
+ id: field.name,
1367
+ checked: value ?? false,
1368
+ onCheckedChange: /* @__PURE__ */ __name((checked) => handleChange(field.name, checked), "onCheckedChange"),
1369
+ disabled: field.disabled || loading
1370
+ }), /* @__PURE__ */ React25.createElement(Label2, {
1371
+ htmlFor: field.name
1372
+ }, field.label));
1373
+ case "slider":
1374
+ return /* @__PURE__ */ React25.createElement("div", {
1375
+ className: "space-y-2"
1376
+ }, /* @__PURE__ */ React25.createElement("div", {
1377
+ className: "flex justify-between text-sm"
1378
+ }, /* @__PURE__ */ React25.createElement("span", null, field.min ?? 0), /* @__PURE__ */ React25.createElement("span", null, value ?? field.min ?? 0), /* @__PURE__ */ React25.createElement("span", null, field.max ?? 100)), /* @__PURE__ */ React25.createElement(Slider, {
1379
+ value: [
1380
+ value ?? field.min ?? 0
1381
+ ],
1382
+ onValueChange: /* @__PURE__ */ __name(([v]) => handleChange(field.name, v), "onValueChange"),
1383
+ min: field.min ?? 0,
1384
+ max: field.max ?? 100,
1385
+ step: field.step ?? 1,
1386
+ disabled: field.disabled || loading
1387
+ }));
1388
+ case "number":
1389
+ return /* @__PURE__ */ React25.createElement(Input, {
1390
+ id: field.name,
1391
+ type: "number",
1392
+ placeholder: field.placeholder,
1393
+ value: value ?? "",
1394
+ onChange: /* @__PURE__ */ __name((e) => handleChange(field.name, e.target.value), "onChange"),
1395
+ min: field.min,
1396
+ max: field.max,
1397
+ step: field.step,
1398
+ disabled: field.disabled || loading,
1399
+ required: field.required
1400
+ });
1401
+ default:
1402
+ return /* @__PURE__ */ React25.createElement(Input, {
1403
+ id: field.name,
1404
+ type: field.type ?? "text",
1405
+ placeholder: field.placeholder,
1406
+ value: value ?? "",
1407
+ onChange: /* @__PURE__ */ __name((e) => handleChange(field.name, e.target.value), "onChange"),
1408
+ disabled: field.disabled || loading,
1409
+ required: field.required
1410
+ });
1411
+ }
1412
+ }, "renderField");
1413
+ if (schemaLoading) {
1414
+ return /* @__PURE__ */ React25.createElement("div", {
1415
+ className: "flex items-center justify-center p-8"
1416
+ }, /* @__PURE__ */ React25.createElement(Loader2, {
1417
+ className: "h-6 w-6 animate-spin text-muted-foreground"
1418
+ }));
1419
+ }
1420
+ return /* @__PURE__ */ React25.createElement("form", {
1421
+ className: cn("space-y-4", className),
1422
+ onSubmit: handleSubmit
1423
+ }, /* @__PURE__ */ React25.createElement("div", {
1424
+ className: cn("space-y-4", layout === "horizontal" && "grid grid-cols-2 gap-4")
1425
+ }, fields.map((field) => /* @__PURE__ */ React25.createElement("div", {
1426
+ key: field.name,
1427
+ className: "space-y-2"
1428
+ }, field.type !== "checkbox" && field.type !== "switch" && /* @__PURE__ */ React25.createElement(Label2, {
1429
+ htmlFor: field.name
1430
+ }, field.label, field.required && /* @__PURE__ */ React25.createElement("span", {
1431
+ className: "text-destructive ml-1"
1432
+ }, "*")), renderField(field), field.description && /* @__PURE__ */ React25.createElement("p", {
1433
+ className: "text-sm text-muted-foreground"
1434
+ }, field.description)))), /* @__PURE__ */ React25.createElement("div", {
1435
+ className: "flex items-center gap-2"
1436
+ }, /* @__PURE__ */ React25.createElement(Button, {
1437
+ type: "submit",
1438
+ disabled: loading
1439
+ }, loading ? /* @__PURE__ */ React25.createElement(React25.Fragment, null, /* @__PURE__ */ React25.createElement(Loader2, {
1440
+ className: "h-4 w-4 animate-spin mr-2"
1441
+ }), loadingText ?? "Submitting...") : submitText)), error && /* @__PURE__ */ React25.createElement(Alert, {
1442
+ variant: "destructive"
1443
+ }, /* @__PURE__ */ React25.createElement(AlertDescription, null, error.message)), showResult && result !== null && /* @__PURE__ */ React25.createElement("div", {
1444
+ className: "rounded-md bg-muted p-4"
1445
+ }, /* @__PURE__ */ React25.createElement("pre", {
1446
+ className: "text-sm overflow-auto"
1447
+ }, JSON.stringify(result, null, 2))));
1448
+ }
1449
+ __name(ToolForm, "ToolForm");
1450
+ function useResource(uri, options = {}) {
1451
+ const { app, isConnected } = useMcpApp();
1452
+ const { refreshInterval, subscribe = false, transform, skip = false } = options;
1453
+ const [data, setData] = useState(null);
1454
+ const [loading, setLoading] = useState(!skip);
1455
+ const [error, setError] = useState(null);
1456
+ const [lastUpdated, setLastUpdated] = useState(null);
1457
+ const intervalRef = useRef(null);
1458
+ const mountedRef = useRef(true);
1459
+ const fetchResource = useCallback(async () => {
1460
+ if (!app || !isConnected) {
1461
+ throw new Error("Not connected to MCP host");
1462
+ }
1463
+ setLoading(true);
1464
+ setError(null);
1465
+ try {
1466
+ const result = await app.readResource?.({
1467
+ uri
1468
+ });
1469
+ if (!result) {
1470
+ throw new Error("readResource not supported by host");
1471
+ }
1472
+ let resourceData;
1473
+ if (result.contents && result.contents.length > 0) {
1474
+ const content = result.contents[0];
1475
+ if (content.text) {
1476
+ try {
1477
+ resourceData = JSON.parse(content.text);
1478
+ } catch {
1479
+ resourceData = content.text;
1480
+ }
1481
+ } else if (content.blob) {
1482
+ resourceData = content.blob;
1483
+ } else {
1484
+ resourceData = content;
1485
+ }
1486
+ } else {
1487
+ resourceData = result;
1488
+ }
1489
+ if (transform) {
1490
+ resourceData = transform(resourceData);
1491
+ }
1492
+ if (mountedRef.current) {
1493
+ setData(resourceData);
1494
+ setLastUpdated(/* @__PURE__ */ new Date());
1495
+ setLoading(false);
1496
+ }
1497
+ return resourceData;
1498
+ } catch (err) {
1499
+ const error2 = err instanceof Error ? err : new Error(String(err));
1500
+ if (mountedRef.current) {
1501
+ setError(error2);
1502
+ setLoading(false);
1503
+ }
1504
+ throw error2;
1505
+ }
1506
+ }, [
1507
+ app,
1508
+ isConnected,
1509
+ uri,
1510
+ transform
1511
+ ]);
1512
+ const refresh = useCallback(async () => {
1513
+ return fetchResource();
1514
+ }, [
1515
+ fetchResource
1516
+ ]);
1517
+ useEffect(() => {
1518
+ mountedRef.current = true;
1519
+ if (!skip && isConnected) {
1520
+ fetchResource().catch(() => {
1521
+ });
1522
+ }
1523
+ return () => {
1524
+ mountedRef.current = false;
1525
+ };
1526
+ }, [
1527
+ uri,
1528
+ isConnected,
1529
+ skip,
1530
+ fetchResource
1531
+ ]);
1532
+ useEffect(() => {
1533
+ if (refreshInterval && refreshInterval > 0 && isConnected && !skip) {
1534
+ intervalRef.current = setInterval(() => {
1535
+ fetchResource().catch(() => {
1536
+ });
1537
+ }, refreshInterval);
1538
+ }
1539
+ return () => {
1540
+ if (intervalRef.current) {
1541
+ clearInterval(intervalRef.current);
1542
+ intervalRef.current = null;
1543
+ }
1544
+ };
1545
+ }, [
1546
+ refreshInterval,
1547
+ isConnected,
1548
+ skip,
1549
+ fetchResource
1550
+ ]);
1551
+ useEffect(() => {
1552
+ if (subscribe) {
1553
+ console.warn("[useResource] Subscription support not yet implemented");
1554
+ }
1555
+ }, [
1556
+ subscribe
1557
+ ]);
1558
+ return {
1559
+ data,
1560
+ loading,
1561
+ error,
1562
+ refresh,
1563
+ lastUpdated
1564
+ };
1565
+ }
1566
+ __name(useResource, "useResource");
1567
+ function Skeleton({ className, ...props }) {
1568
+ return /* @__PURE__ */ React25__default.createElement("div", {
1569
+ "data-slot": "skeleton",
1570
+ className: cn("bg-accent animate-pulse rounded-md", className),
1571
+ ...props
1572
+ });
1573
+ }
1574
+ __name(Skeleton, "Skeleton");
1575
+
1576
+ // src/mcp/ResourceView.tsx
1577
+ function DefaultLoading() {
1578
+ return /* @__PURE__ */ React25.createElement("div", {
1579
+ className: "flex flex-col gap-3 p-4"
1580
+ }, /* @__PURE__ */ React25.createElement(Skeleton, {
1581
+ className: "h-4 w-3/4"
1582
+ }), /* @__PURE__ */ React25.createElement(Skeleton, {
1583
+ className: "h-4 w-1/2"
1584
+ }), /* @__PURE__ */ React25.createElement(Skeleton, {
1585
+ className: "h-20 w-full"
1586
+ }));
1587
+ }
1588
+ __name(DefaultLoading, "DefaultLoading");
1589
+ function DefaultError({ error, onRetry }) {
1590
+ return /* @__PURE__ */ React25.createElement(Alert, {
1591
+ variant: "destructive"
1592
+ }, /* @__PURE__ */ React25.createElement(AlertCircle, {
1593
+ className: "h-4 w-4"
1594
+ }), /* @__PURE__ */ React25.createElement(AlertTitle, null, "Error loading resource"), /* @__PURE__ */ React25.createElement(AlertDescription, {
1595
+ className: "flex flex-col gap-2"
1596
+ }, /* @__PURE__ */ React25.createElement("span", null, error.message), /* @__PURE__ */ React25.createElement(Button, {
1597
+ variant: "outline",
1598
+ size: "sm",
1599
+ onClick: onRetry,
1600
+ className: "w-fit"
1601
+ }, /* @__PURE__ */ React25.createElement(RefreshCw, {
1602
+ className: "h-4 w-4 mr-2"
1603
+ }), "Retry")));
1604
+ }
1605
+ __name(DefaultError, "DefaultError");
1606
+ function ResourceView({ uri, refreshInterval, subscribe, transform, loading: loadingContent, error: errorContent, children, className, skip = false }) {
1607
+ const { data, loading, error, refresh, lastUpdated } = useResource(uri, {
1608
+ refreshInterval,
1609
+ subscribe,
1610
+ transform,
1611
+ skip
1612
+ });
1613
+ const meta = {
1614
+ uri,
1615
+ refresh,
1616
+ lastUpdated,
1617
+ isRefreshing: loading && data !== null
1618
+ };
1619
+ if (loading && data === null) {
1620
+ if (loadingContent) {
1621
+ return /* @__PURE__ */ React25.createElement("div", {
1622
+ className
1623
+ }, loadingContent);
1624
+ }
1625
+ return /* @__PURE__ */ React25.createElement("div", {
1626
+ className: cn("flex items-center justify-center p-8", className)
1627
+ }, /* @__PURE__ */ React25.createElement(Loader2, {
1628
+ className: "h-8 w-8 animate-spin text-muted-foreground"
1629
+ }));
1630
+ }
1631
+ if (error && data === null) {
1632
+ if (errorContent) {
1633
+ if (typeof errorContent === "function") {
1634
+ return /* @__PURE__ */ React25.createElement("div", {
1635
+ className
1636
+ }, errorContent(error, refresh));
1637
+ }
1638
+ return /* @__PURE__ */ React25.createElement("div", {
1639
+ className
1640
+ }, errorContent);
1641
+ }
1642
+ return /* @__PURE__ */ React25.createElement("div", {
1643
+ className
1644
+ }, /* @__PURE__ */ React25.createElement(DefaultError, {
1645
+ error,
1646
+ onRetry: refresh
1647
+ }));
1648
+ }
1649
+ if (data !== null) {
1650
+ return /* @__PURE__ */ React25.createElement("div", {
1651
+ className
1652
+ }, children(data, meta));
1653
+ }
1654
+ return /* @__PURE__ */ React25.createElement("div", {
1655
+ className
1656
+ }, loadingContent ?? /* @__PURE__ */ React25.createElement(DefaultLoading, null));
1657
+ }
1658
+ __name(ResourceView, "ResourceView");
1659
+ function useToolStream(options = {}) {
1660
+ const { toolInputPartial, toolInput, toolResult } = useMcpApp();
1661
+ const { onPartial, onComplete } = options;
1662
+ const [partial, setPartial] = useState(null);
1663
+ const [complete, setComplete] = useState(null);
1664
+ const [isStreaming, setIsStreaming] = useState(false);
1665
+ const [isComplete, setIsComplete] = useState(false);
1666
+ useEffect(() => {
1667
+ if (toolInputPartial) {
1668
+ setPartial(toolInputPartial);
1669
+ setIsStreaming(true);
1670
+ setIsComplete(false);
1671
+ onPartial?.(toolInputPartial);
1672
+ }
1673
+ }, [
1674
+ toolInputPartial,
1675
+ onPartial
1676
+ ]);
1677
+ useEffect(() => {
1678
+ if (toolInput) {
1679
+ setComplete(toolInput);
1680
+ setIsStreaming(false);
1681
+ setIsComplete(true);
1682
+ onComplete?.(toolInput);
1683
+ }
1684
+ }, [
1685
+ toolInput,
1686
+ onComplete
1687
+ ]);
1688
+ useEffect(() => {
1689
+ if (toolResult && !toolResult.isError) {
1690
+ setIsStreaming(false);
1691
+ setIsComplete(true);
1692
+ }
1693
+ }, [
1694
+ toolResult
1695
+ ]);
1696
+ return {
1697
+ partial,
1698
+ complete,
1699
+ isStreaming,
1700
+ isComplete
1701
+ };
1702
+ }
1703
+ __name(useToolStream, "useToolStream");
1704
+ function Progress({ className, value, ...props }) {
1705
+ return /* @__PURE__ */ React25.createElement(ProgressPrimitive.Root, {
1706
+ "data-slot": "progress",
1707
+ className: cn("bg-primary/20 relative h-2 w-full overflow-hidden rounded-full", className),
1708
+ ...props
1709
+ }, /* @__PURE__ */ React25.createElement(ProgressPrimitive.Indicator, {
1710
+ "data-slot": "progress-indicator",
1711
+ className: "bg-primary h-full w-full flex-1 transition-all",
1712
+ style: {
1713
+ transform: `translateX(-${100 - (value || 0)}%)`
1714
+ }
1715
+ }));
1716
+ }
1717
+ __name(Progress, "Progress");
1718
+
1719
+ // src/mcp/StreamingContent.tsx
1720
+ function StreamingContent({ fallback, showProgress = false, progress: externalProgress, onPartial, onComplete, children, className, streamingStyle = "opacity" }) {
1721
+ const { partial, complete, isStreaming, isComplete } = useToolStream({
1722
+ onPartial,
1723
+ onComplete
1724
+ });
1725
+ const data = complete ?? partial;
1726
+ if (!data) {
1727
+ if (fallback) {
1728
+ return /* @__PURE__ */ React25.createElement("div", {
1729
+ className
1730
+ }, fallback);
1731
+ }
1732
+ return /* @__PURE__ */ React25.createElement("div", {
1733
+ className: cn("flex items-center justify-center p-8", className)
1734
+ }, /* @__PURE__ */ React25.createElement(Loader2, {
1735
+ className: "h-6 w-6 animate-spin text-muted-foreground"
1736
+ }));
1737
+ }
1738
+ const streamingClasses = cn(streamingStyle === "opacity" && isStreaming && "opacity-70", streamingStyle === "blur" && isStreaming && "blur-[1px]");
1739
+ return /* @__PURE__ */ React25.createElement("div", {
1740
+ className: cn("relative", className)
1741
+ }, showProgress && isStreaming && /* @__PURE__ */ React25.createElement("div", {
1742
+ className: "absolute top-0 left-0 right-0 z-10"
1743
+ }, externalProgress !== void 0 ? /* @__PURE__ */ React25.createElement(Progress, {
1744
+ value: externalProgress,
1745
+ className: "h-1"
1746
+ }) : /* @__PURE__ */ React25.createElement("div", {
1747
+ className: "h-1 bg-primary/20 overflow-hidden"
1748
+ }, /* @__PURE__ */ React25.createElement("div", {
1749
+ className: "h-full w-1/3 bg-primary animate-[shimmer_1s_infinite]"
1750
+ }))), isStreaming && /* @__PURE__ */ React25.createElement("div", {
1751
+ className: "absolute top-2 right-2 z-10"
1752
+ }, /* @__PURE__ */ React25.createElement("div", {
1753
+ className: "flex items-center gap-1 px-2 py-1 rounded-full bg-muted text-muted-foreground text-xs"
1754
+ }, /* @__PURE__ */ React25.createElement(Loader2, {
1755
+ className: "h-3 w-3 animate-spin"
1756
+ }), /* @__PURE__ */ React25.createElement("span", null, "Streaming..."))), /* @__PURE__ */ React25.createElement("div", {
1757
+ className: cn("transition-all duration-200", streamingClasses)
1758
+ }, children(data, isComplete)));
1759
+ }
1760
+ __name(StreamingContent, "StreamingContent");
1761
+ function Table({ className, ...props }) {
1762
+ return /* @__PURE__ */ React25.createElement("div", {
1763
+ "data-slot": "table-container",
1764
+ className: "relative w-full overflow-x-auto"
1765
+ }, /* @__PURE__ */ React25.createElement("table", {
1766
+ "data-slot": "table",
1767
+ className: cn("w-full caption-bottom text-sm", className),
1768
+ ...props
1769
+ }));
1770
+ }
1771
+ __name(Table, "Table");
1772
+ function TableHeader({ className, ...props }) {
1773
+ return /* @__PURE__ */ React25.createElement("thead", {
1774
+ "data-slot": "table-header",
1775
+ className: cn("[&_tr]:border-b", className),
1776
+ ...props
1777
+ });
1778
+ }
1779
+ __name(TableHeader, "TableHeader");
1780
+ function TableBody({ className, ...props }) {
1781
+ return /* @__PURE__ */ React25.createElement("tbody", {
1782
+ "data-slot": "table-body",
1783
+ className: cn("[&_tr:last-child]:border-0", className),
1784
+ ...props
1785
+ });
1786
+ }
1787
+ __name(TableBody, "TableBody");
1788
+ function TableFooter({ className, ...props }) {
1789
+ return /* @__PURE__ */ React25.createElement("tfoot", {
1790
+ "data-slot": "table-footer",
1791
+ className: cn("bg-muted/50 border-t font-medium [&>tr]:last:border-b-0", className),
1792
+ ...props
1793
+ });
1794
+ }
1795
+ __name(TableFooter, "TableFooter");
1796
+ function TableRow({ className, ...props }) {
1797
+ return /* @__PURE__ */ React25.createElement("tr", {
1798
+ "data-slot": "table-row",
1799
+ className: cn("hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors", className),
1800
+ ...props
1801
+ });
1802
+ }
1803
+ __name(TableRow, "TableRow");
1804
+ function TableHead({ className, ...props }) {
1805
+ return /* @__PURE__ */ React25.createElement("th", {
1806
+ "data-slot": "table-head",
1807
+ className: cn("text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]", className),
1808
+ ...props
1809
+ });
1810
+ }
1811
+ __name(TableHead, "TableHead");
1812
+ function TableCell({ className, ...props }) {
1813
+ return /* @__PURE__ */ React25.createElement("td", {
1814
+ "data-slot": "table-cell",
1815
+ className: cn("p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]", className),
1816
+ ...props
1817
+ });
1818
+ }
1819
+ __name(TableCell, "TableCell");
1820
+ function TableCaption({ className, ...props }) {
1821
+ return /* @__PURE__ */ React25.createElement("caption", {
1822
+ "data-slot": "table-caption",
1823
+ className: cn("text-muted-foreground mt-4 text-sm", className),
1824
+ ...props
1825
+ });
1826
+ }
1827
+ __name(TableCaption, "TableCaption");
1828
+ function getNestedValue(obj, path) {
1829
+ return path.split(".").reduce((current, key) => {
1830
+ if (current && typeof current === "object" && key in current) {
1831
+ return current[key];
1832
+ }
1833
+ return void 0;
1834
+ }, obj);
1835
+ }
1836
+ __name(getNestedValue, "getNestedValue");
1837
+ function ToolDataGrid({ dataTool, columns, transformData, rowActions = [], pagination = true, pageSizes = [
1838
+ 10,
1839
+ 25,
1840
+ 50,
1841
+ 100
1842
+ ], defaultPageSize = 10, defaultSort, refreshInterval, showRefresh = true, onDataLoaded, onError, onRowClick, getRowKey, emptyContent, loadingContent, className }) {
1843
+ const toolConfig = typeof dataTool === "string" ? {
1844
+ name: dataTool
1845
+ } : dataTool;
1846
+ const [data, setData] = useState({
1847
+ rows: [],
1848
+ total: 0
1849
+ });
1850
+ const [paginationState, setPaginationState] = useState({
1851
+ page: 1,
1852
+ pageSize: defaultPageSize
1853
+ });
1854
+ const [sortState, setSortState] = useState(defaultSort ?? {
1855
+ column: null,
1856
+ direction: "asc"
1857
+ });
1858
+ const { call, loading, error } = useTool(toolConfig.name, {
1859
+ defaultArgs: toolConfig.args,
1860
+ onSuccess: /* @__PURE__ */ __name((result) => {
1861
+ const gridData = transformData ? transformData(result) : result;
1862
+ setData(gridData);
1863
+ onDataLoaded?.(gridData);
1864
+ }, "onSuccess"),
1865
+ onError
1866
+ });
1867
+ const fetchData = useCallback(() => {
1868
+ const args = {};
1869
+ if (pagination) {
1870
+ args.page = paginationState.page;
1871
+ args.pageSize = paginationState.pageSize;
1872
+ args.offset = (paginationState.page - 1) * paginationState.pageSize;
1873
+ args.limit = paginationState.pageSize;
1874
+ }
1875
+ if (sortState.column) {
1876
+ args.sortBy = sortState.column;
1877
+ args.sortDirection = sortState.direction;
1878
+ args.sort = `${sortState.column}:${sortState.direction}`;
1879
+ }
1880
+ call(args);
1881
+ }, [
1882
+ call,
1883
+ pagination,
1884
+ paginationState,
1885
+ sortState
1886
+ ]);
1887
+ const initialFetchDone = React25.useRef(false);
1888
+ const prevStateRef = React25.useRef({
1889
+ pagination: paginationState,
1890
+ sort: sortState
1891
+ });
1892
+ useEffect(() => {
1893
+ if (!initialFetchDone.current) {
1894
+ initialFetchDone.current = true;
1895
+ fetchData();
1896
+ return;
1897
+ }
1898
+ const prevState = prevStateRef.current;
1899
+ const stateChanged = prevState.pagination.page !== paginationState.page || prevState.pagination.pageSize !== paginationState.pageSize || prevState.sort.column !== sortState.column || prevState.sort.direction !== sortState.direction;
1900
+ if (stateChanged) {
1901
+ prevStateRef.current = {
1902
+ pagination: paginationState,
1903
+ sort: sortState
1904
+ };
1905
+ fetchData();
1906
+ }
1907
+ }, [
1908
+ fetchData,
1909
+ paginationState,
1910
+ sortState
1911
+ ]);
1912
+ useEffect(() => {
1913
+ if (refreshInterval && refreshInterval > 0) {
1914
+ const interval = setInterval(fetchData, refreshInterval);
1915
+ return () => clearInterval(interval);
1916
+ }
1917
+ }, [
1918
+ refreshInterval,
1919
+ fetchData
1920
+ ]);
1921
+ const handleSort = useCallback((column) => {
1922
+ setSortState((prev) => ({
1923
+ column,
1924
+ direction: prev.column === column && prev.direction === "asc" ? "desc" : "asc"
1925
+ }));
1926
+ }, []);
1927
+ const handlePageChange = useCallback((page) => {
1928
+ setPaginationState((prev) => ({
1929
+ ...prev,
1930
+ page
1931
+ }));
1932
+ }, []);
1933
+ const handlePageSizeChange = useCallback((pageSize) => {
1934
+ setPaginationState({
1935
+ page: 1,
1936
+ pageSize: parseInt(pageSize, 10)
1937
+ });
1938
+ }, []);
1939
+ const totalPages = Math.ceil(data.total / paginationState.pageSize);
1940
+ const canPreviousPage = paginationState.page > 1;
1941
+ const canNextPage = paginationState.page < totalPages;
1942
+ const getSortIcon = /* @__PURE__ */ __name((column) => {
1943
+ if (sortState.column !== column) {
1944
+ return /* @__PURE__ */ React25.createElement(ArrowUpDown, {
1945
+ className: "h-4 w-4"
1946
+ });
1947
+ }
1948
+ return sortState.direction === "asc" ? /* @__PURE__ */ React25.createElement(ArrowUp, {
1949
+ className: "h-4 w-4"
1950
+ }) : /* @__PURE__ */ React25.createElement(ArrowDown, {
1951
+ className: "h-4 w-4"
1952
+ });
1953
+ }, "getSortIcon");
1954
+ const renderLoading = /* @__PURE__ */ __name(() => {
1955
+ if (loadingContent) return loadingContent;
1956
+ return /* @__PURE__ */ React25.createElement("div", {
1957
+ className: "space-y-2"
1958
+ }, Array.from({
1959
+ length: 5
1960
+ }).map((_, i) => /* @__PURE__ */ React25.createElement(Skeleton, {
1961
+ key: i,
1962
+ className: "h-12 w-full"
1963
+ })));
1964
+ }, "renderLoading");
1965
+ const renderEmpty = /* @__PURE__ */ __name(() => {
1966
+ if (emptyContent) return emptyContent;
1967
+ return /* @__PURE__ */ React25.createElement("div", {
1968
+ className: "flex flex-col items-center justify-center py-12 text-muted-foreground"
1969
+ }, /* @__PURE__ */ React25.createElement("p", {
1970
+ className: "text-lg"
1971
+ }, "No data found"), /* @__PURE__ */ React25.createElement(Button, {
1972
+ variant: "ghost",
1973
+ size: "sm",
1974
+ onClick: fetchData,
1975
+ className: "mt-2"
1976
+ }, /* @__PURE__ */ React25.createElement(RefreshCw, {
1977
+ className: "h-4 w-4 mr-2"
1978
+ }), "Refresh"));
1979
+ }, "renderEmpty");
1980
+ return /* @__PURE__ */ React25.createElement("div", {
1981
+ className: cn("space-y-4", className)
1982
+ }, showRefresh && /* @__PURE__ */ React25.createElement("div", {
1983
+ className: "flex items-center justify-end gap-2"
1984
+ }, /* @__PURE__ */ React25.createElement(Button, {
1985
+ variant: "outline",
1986
+ size: "sm",
1987
+ onClick: fetchData,
1988
+ disabled: loading
1989
+ }, loading ? /* @__PURE__ */ React25.createElement(Loader2, {
1990
+ className: "h-4 w-4 animate-spin"
1991
+ }) : /* @__PURE__ */ React25.createElement(RefreshCw, {
1992
+ className: "h-4 w-4"
1993
+ }), /* @__PURE__ */ React25.createElement("span", {
1994
+ className: "ml-2"
1995
+ }, "Refresh"))), /* @__PURE__ */ React25.createElement("div", {
1996
+ className: "rounded-md border"
1997
+ }, loading && data.rows.length === 0 ? /* @__PURE__ */ React25.createElement("div", {
1998
+ className: "p-4"
1999
+ }, renderLoading()) : data.rows.length === 0 ? renderEmpty() : /* @__PURE__ */ React25.createElement(Table, null, /* @__PURE__ */ React25.createElement(TableHeader, null, /* @__PURE__ */ React25.createElement(TableRow, null, columns.map((column) => /* @__PURE__ */ React25.createElement(TableHead, {
2000
+ key: column.key,
2001
+ style: {
2002
+ width: column.width
2003
+ },
2004
+ className: cn(column.align === "center" && "text-center", column.align === "right" && "text-right", column.hideMobile && "hidden md:table-cell")
2005
+ }, column.sortable ? /* @__PURE__ */ React25.createElement(Button, {
2006
+ variant: "ghost",
2007
+ size: "sm",
2008
+ onClick: /* @__PURE__ */ __name(() => handleSort(column.key), "onClick"),
2009
+ className: "-ml-3"
2010
+ }, column.header, getSortIcon(column.key)) : column.header)), rowActions.length > 0 && /* @__PURE__ */ React25.createElement(TableHead, {
2011
+ className: "w-[100px]"
2012
+ }, "Actions"))), /* @__PURE__ */ React25.createElement(TableBody, null, data.rows.map((row, index) => {
2013
+ const key = getRowKey?.(row, index) ?? String(index);
2014
+ return /* @__PURE__ */ React25.createElement(TableRow, {
2015
+ key,
2016
+ onClick: /* @__PURE__ */ __name(() => onRowClick?.(row, index), "onClick"),
2017
+ className: onRowClick ? "cursor-pointer" : void 0
2018
+ }, columns.map((column) => {
2019
+ const value = getNestedValue(row, column.key);
2020
+ return /* @__PURE__ */ React25.createElement(TableCell, {
2021
+ key: column.key,
2022
+ className: cn(column.align === "center" && "text-center", column.align === "right" && "text-right", column.hideMobile && "hidden md:table-cell")
2023
+ }, column.render ? column.render(value, row, index) : String(value ?? ""));
2024
+ }), rowActions.length > 0 && /* @__PURE__ */ React25.createElement(TableCell, null, /* @__PURE__ */ React25.createElement("div", {
2025
+ className: "flex items-center gap-1"
2026
+ }, rowActions.filter((action) => !action.hidden?.(row)).map((action, actionIndex) => /* @__PURE__ */ React25.createElement(RowActionButton, {
2027
+ key: actionIndex,
2028
+ action,
2029
+ row,
2030
+ onRefresh: fetchData
2031
+ })))));
2032
+ })))), pagination && data.total > 0 && /* @__PURE__ */ React25.createElement("div", {
2033
+ className: "flex items-center justify-between"
2034
+ }, /* @__PURE__ */ React25.createElement("div", {
2035
+ className: "text-sm text-muted-foreground"
2036
+ }, "Showing ", (paginationState.page - 1) * paginationState.pageSize + 1, " to", " ", Math.min(paginationState.page * paginationState.pageSize, data.total), " of", " ", data.total, " results"), /* @__PURE__ */ React25.createElement("div", {
2037
+ className: "flex items-center gap-4"
2038
+ }, /* @__PURE__ */ React25.createElement("div", {
2039
+ className: "flex items-center gap-2"
2040
+ }, /* @__PURE__ */ React25.createElement("span", {
2041
+ className: "text-sm text-muted-foreground"
2042
+ }, "Rows per page"), /* @__PURE__ */ React25.createElement(Select, {
2043
+ value: String(paginationState.pageSize),
2044
+ onValueChange: handlePageSizeChange
2045
+ }, /* @__PURE__ */ React25.createElement(SelectTrigger, {
2046
+ className: "w-[70px]"
2047
+ }, /* @__PURE__ */ React25.createElement(SelectValue, null)), /* @__PURE__ */ React25.createElement(SelectContent, null, pageSizes.map((size) => /* @__PURE__ */ React25.createElement(SelectItem, {
2048
+ key: size,
2049
+ value: String(size)
2050
+ }, size))))), /* @__PURE__ */ React25.createElement("div", {
2051
+ className: "flex items-center gap-2"
2052
+ }, /* @__PURE__ */ React25.createElement(Button, {
2053
+ variant: "outline",
2054
+ size: "sm",
2055
+ onClick: /* @__PURE__ */ __name(() => handlePageChange(paginationState.page - 1), "onClick"),
2056
+ disabled: !canPreviousPage || loading
2057
+ }, /* @__PURE__ */ React25.createElement(ChevronLeft, {
2058
+ className: "h-4 w-4"
2059
+ })), /* @__PURE__ */ React25.createElement("span", {
2060
+ className: "text-sm"
2061
+ }, "Page ", paginationState.page, " of ", totalPages), /* @__PURE__ */ React25.createElement(Button, {
2062
+ variant: "outline",
2063
+ size: "sm",
2064
+ onClick: /* @__PURE__ */ __name(() => handlePageChange(paginationState.page + 1), "onClick"),
2065
+ disabled: !canNextPage || loading
2066
+ }, /* @__PURE__ */ React25.createElement(ChevronRight, {
2067
+ className: "h-4 w-4"
2068
+ }))))));
2069
+ }
2070
+ __name(ToolDataGrid, "ToolDataGrid");
2071
+ function RowActionButton({ action, row, onRefresh }) {
2072
+ const toolConfig = typeof action.tool === "string" ? {
2073
+ name: action.tool
2074
+ } : action.tool;
2075
+ const args = action.getArgs?.(row) ?? {
2076
+ id: row.id
2077
+ };
2078
+ const { call, loading } = useTool(toolConfig.name, {
2079
+ onSuccess: /* @__PURE__ */ __name((result) => {
2080
+ action.onSuccess?.(result, row);
2081
+ toast.success("Action completed");
2082
+ onRefresh();
2083
+ }, "onSuccess"),
2084
+ onError: /* @__PURE__ */ __name((error) => {
2085
+ toast.error(error.message);
2086
+ }, "onError")
2087
+ });
2088
+ const handleClick = useCallback((e) => {
2089
+ e.stopPropagation();
2090
+ call(args);
2091
+ }, [
2092
+ call,
2093
+ args
2094
+ ]);
2095
+ return /* @__PURE__ */ React25.createElement(Button, {
2096
+ variant: action.variant ?? "ghost",
2097
+ size: "sm",
2098
+ onClick: handleClick,
2099
+ disabled: loading
2100
+ }, loading ? /* @__PURE__ */ React25.createElement(Loader2, {
2101
+ className: "h-3 w-3 animate-spin"
2102
+ }) : /* @__PURE__ */ React25.createElement(React25.Fragment, null, action.icon, /* @__PURE__ */ React25.createElement("span", {
2103
+ className: action.icon ? "ml-1" : ""
2104
+ }, action.label)));
2105
+ }
2106
+ __name(RowActionButton, "RowActionButton");
2107
+ var Button2 = /* @__PURE__ */ forwardRef(({ className, variant = "primary", size = "md", loading = false, disabled, asChild = false, leftIcon, rightIcon, children, ...props }, ref) => {
2108
+ const Comp = asChild ? Slot : "button";
2109
+ return /* @__PURE__ */ React25__default.createElement(Comp, {
2110
+ ref,
2111
+ className: clsx("lui-button", `lui-button--${variant}`, `lui-button--${size}`, loading && "lui-button--loading", className),
2112
+ disabled: disabled || loading,
2113
+ ...props
2114
+ }, loading && /* @__PURE__ */ React25__default.createElement("span", {
2115
+ className: "lui-button__spinner",
2116
+ "aria-hidden": "true"
2117
+ }, /* @__PURE__ */ React25__default.createElement("svg", {
2118
+ viewBox: "0 0 24 24",
2119
+ fill: "none",
2120
+ className: "lui-spinner-icon"
2121
+ }, /* @__PURE__ */ React25__default.createElement("circle", {
2122
+ cx: "12",
2123
+ cy: "12",
2124
+ r: "10",
2125
+ stroke: "currentColor",
2126
+ strokeWidth: "3",
2127
+ strokeLinecap: "round",
2128
+ strokeDasharray: "32",
2129
+ strokeDashoffset: "12"
2130
+ }))), leftIcon && !loading && /* @__PURE__ */ React25__default.createElement("span", {
2131
+ className: "lui-button__icon"
2132
+ }, leftIcon), /* @__PURE__ */ React25__default.createElement("span", {
2133
+ className: "lui-button__content"
2134
+ }, children), rightIcon && /* @__PURE__ */ React25__default.createElement("span", {
2135
+ className: "lui-button__icon"
2136
+ }, rightIcon));
2137
+ });
2138
+ Button2.displayName = "Button";
2139
+
2140
+ // src/mcp/ActionButton.tsx
2141
+ function ActionButton({ toolName, toolArgs = {}, onToolSuccess, onToolError, showResult = false, renderResult, children, ...buttonProps }) {
2142
+ const { call, loading, result, error } = useTool(toolName);
2143
+ const [hasResult, setHasResult] = useState(false);
2144
+ const handleClick = /* @__PURE__ */ __name(async () => {
2145
+ try {
2146
+ const res = await call(toolArgs);
2147
+ setHasResult(true);
2148
+ onToolSuccess?.(res);
2149
+ } catch (err) {
2150
+ onToolError?.(err instanceof Error ? err : new Error(String(err)));
2151
+ }
2152
+ }, "handleClick");
2153
+ return /* @__PURE__ */ React25__default.createElement("div", {
2154
+ className: "lui-action-button-wrapper"
2155
+ }, /* @__PURE__ */ React25__default.createElement(Button2, {
2156
+ ...buttonProps,
2157
+ loading,
2158
+ onClick: handleClick
2159
+ }, children), showResult && hasResult && result !== null && /* @__PURE__ */ React25__default.createElement("div", {
2160
+ className: "lui-action-button-result"
2161
+ }, renderResult ? renderResult(result) : /* @__PURE__ */ React25__default.createElement("pre", null, JSON.stringify(result, null, 2))), error && /* @__PURE__ */ React25__default.createElement("div", {
2162
+ className: "lui-action-button-error"
2163
+ }, error.message));
2164
+ }
2165
+ __name(ActionButton, "ActionButton");
2166
+ function DefaultLoading2() {
2167
+ return /* @__PURE__ */ React25.createElement("div", {
2168
+ className: "flex items-center justify-center p-8"
2169
+ }, /* @__PURE__ */ React25.createElement(Loader2, {
2170
+ className: "h-6 w-6 animate-spin text-muted-foreground"
2171
+ }));
2172
+ }
2173
+ __name(DefaultLoading2, "DefaultLoading");
2174
+ function DefaultDisconnected() {
2175
+ return /* @__PURE__ */ React25.createElement(Alert, null, /* @__PURE__ */ React25.createElement(WifiOff, {
2176
+ className: "h-4 w-4"
2177
+ }), /* @__PURE__ */ React25.createElement(AlertDescription, null, "Waiting for connection to MCP host..."));
2178
+ }
2179
+ __name(DefaultDisconnected, "DefaultDisconnected");
2180
+ function DefaultError2({ error }) {
2181
+ return /* @__PURE__ */ React25.createElement(Alert, {
2182
+ variant: "destructive"
2183
+ }, /* @__PURE__ */ React25.createElement(AlertCircle, {
2184
+ className: "h-4 w-4"
2185
+ }), /* @__PURE__ */ React25.createElement(AlertDescription, null, "Connection error: ", error.message));
2186
+ }
2187
+ __name(DefaultError2, "DefaultError");
2188
+ function RequireConnection({ loading: loadingContent, error: errorContent, disconnected: disconnectedContent, children, className }) {
2189
+ const { isConnected, error, app } = useMcpApp();
2190
+ if (!app && !error && !isConnected) {
2191
+ if (loadingContent) {
2192
+ return /* @__PURE__ */ React25.createElement("div", {
2193
+ className
2194
+ }, loadingContent);
2195
+ }
2196
+ return /* @__PURE__ */ React25.createElement("div", {
2197
+ className
2198
+ }, /* @__PURE__ */ React25.createElement(DefaultLoading2, null));
2199
+ }
2200
+ if (error) {
2201
+ if (errorContent) {
2202
+ if (typeof errorContent === "function") {
2203
+ return /* @__PURE__ */ React25.createElement("div", {
2204
+ className
2205
+ }, errorContent(error));
2206
+ }
2207
+ return /* @__PURE__ */ React25.createElement("div", {
2208
+ className
2209
+ }, errorContent);
2210
+ }
2211
+ return /* @__PURE__ */ React25.createElement("div", {
2212
+ className
2213
+ }, /* @__PURE__ */ React25.createElement(DefaultError2, {
2214
+ error
2215
+ }));
2216
+ }
2217
+ if (!isConnected) {
2218
+ if (disconnectedContent) {
2219
+ return /* @__PURE__ */ React25.createElement("div", {
2220
+ className
2221
+ }, disconnectedContent);
2222
+ }
2223
+ if (loadingContent) {
2224
+ return /* @__PURE__ */ React25.createElement("div", {
2225
+ className
2226
+ }, loadingContent);
2227
+ }
2228
+ return /* @__PURE__ */ React25.createElement("div", {
2229
+ className
2230
+ }, /* @__PURE__ */ React25.createElement(DefaultDisconnected, null));
2231
+ }
2232
+ return /* @__PURE__ */ React25.createElement(React25.Fragment, null, children);
2233
+ }
2234
+ __name(RequireConnection, "RequireConnection");
2235
+ function DefaultFallback({ error, onRetry }) {
2236
+ return /* @__PURE__ */ React25.createElement(Alert, {
2237
+ variant: "destructive"
2238
+ }, /* @__PURE__ */ React25.createElement(AlertCircle, {
2239
+ className: "h-4 w-4"
2240
+ }), /* @__PURE__ */ React25.createElement(AlertTitle, null, "Something went wrong"), /* @__PURE__ */ React25.createElement(AlertDescription, {
2241
+ className: "flex flex-col gap-3"
2242
+ }, /* @__PURE__ */ React25.createElement("p", {
2243
+ className: "text-sm"
2244
+ }, error.message), /* @__PURE__ */ React25.createElement(Button, {
2245
+ variant: "outline",
2246
+ size: "sm",
2247
+ onClick: onRetry,
2248
+ className: "w-fit"
2249
+ }, /* @__PURE__ */ React25.createElement(RefreshCw, {
2250
+ className: "h-4 w-4 mr-2"
2251
+ }), "Try Again")));
2252
+ }
2253
+ __name(DefaultFallback, "DefaultFallback");
2254
+ var ToolErrorBoundary = class extends Component {
2255
+ static {
2256
+ __name(this, "ToolErrorBoundary");
2257
+ }
2258
+ constructor(props) {
2259
+ super(props);
2260
+ this.state = {
2261
+ hasError: false,
2262
+ error: null
2263
+ };
2264
+ }
2265
+ static getDerivedStateFromError(error) {
2266
+ return {
2267
+ hasError: true,
2268
+ error
2269
+ };
2270
+ }
2271
+ componentDidCatch(error, errorInfo) {
2272
+ this.props.onError?.(error, errorInfo);
2273
+ }
2274
+ componentDidUpdate(prevProps) {
2275
+ if (this.state.hasError && this.props.resetKeys && prevProps.resetKeys && this.props.resetKeys.some((key, index) => key !== prevProps.resetKeys?.[index])) {
2276
+ this.reset();
2277
+ }
2278
+ }
2279
+ reset = /* @__PURE__ */ __name(() => {
2280
+ this.setState({
2281
+ hasError: false,
2282
+ error: null
2283
+ });
2284
+ }, "reset");
2285
+ render() {
2286
+ const { hasError, error } = this.state;
2287
+ const { fallback, children } = this.props;
2288
+ if (hasError && error) {
2289
+ if (fallback) {
2290
+ if (typeof fallback === "function") {
2291
+ return fallback(error, this.reset);
2292
+ }
2293
+ return fallback;
2294
+ }
2295
+ return /* @__PURE__ */ React25.createElement(DefaultFallback, {
2296
+ error,
2297
+ onRetry: this.reset
2298
+ });
2299
+ }
2300
+ return children;
2301
+ }
2302
+ };
2303
+ function useMessage() {
2304
+ const { sendMessage: appSendMessage, isConnected } = useMcpApp();
2305
+ const [sending, setSending] = useState(false);
2306
+ const [error, setError] = useState(null);
2307
+ const send = useCallback(async (text) => {
2308
+ if (!isConnected) {
2309
+ console.warn("[useMessage] Not connected to host");
2310
+ return;
2311
+ }
2312
+ setSending(true);
2313
+ setError(null);
2314
+ try {
2315
+ await appSendMessage(text);
2316
+ } catch (err) {
2317
+ const error2 = err instanceof Error ? err : new Error(String(err));
2318
+ setError(error2);
2319
+ throw error2;
2320
+ } finally {
2321
+ setSending(false);
2322
+ }
2323
+ }, [
2324
+ appSendMessage,
2325
+ isConnected
2326
+ ]);
2327
+ const sendContent = useCallback(async (content) => {
2328
+ if (!isConnected) {
2329
+ console.warn("[useMessage] Not connected to host");
2330
+ return;
2331
+ }
2332
+ setSending(true);
2333
+ setError(null);
2334
+ try {
2335
+ const textContent = content.filter((c) => c.type === "text").map((c) => c.text).join("\n");
2336
+ await appSendMessage(textContent);
2337
+ } catch (err) {
2338
+ const error2 = err instanceof Error ? err : new Error(String(err));
2339
+ setError(error2);
2340
+ throw error2;
2341
+ } finally {
2342
+ setSending(false);
2343
+ }
2344
+ }, [
2345
+ appSendMessage,
2346
+ isConnected
2347
+ ]);
2348
+ const requestTool = useCallback(async (toolName, args) => {
2349
+ let message = `Please call the "${toolName}" tool`;
2350
+ if (args && Object.keys(args).length > 0) {
2351
+ message += ` with arguments: ${JSON.stringify(args)}`;
2352
+ }
2353
+ await send(message);
2354
+ }, [
2355
+ send
2356
+ ]);
2357
+ return {
2358
+ send,
2359
+ sendContent,
2360
+ requestTool,
2361
+ sending,
2362
+ error
2363
+ };
2364
+ }
2365
+ __name(useMessage, "useMessage");
2366
+
2367
+ // src/mcp/useHostContext.ts
2368
+ function useHostContext() {
2369
+ const { hostContext } = useMcpApp();
2370
+ return {
2371
+ theme: hostContext.theme ?? "light",
2372
+ displayMode: hostContext.displayMode ?? "inline",
2373
+ availableDisplayModes: hostContext.availableDisplayModes ?? [],
2374
+ viewport: hostContext.viewport ?? null,
2375
+ locale: hostContext.locale ?? null,
2376
+ timeZone: hostContext.timeZone ?? null,
2377
+ platform: hostContext.platform ?? null,
2378
+ userAgent: hostContext.userAgent ?? null,
2379
+ deviceCapabilities: hostContext.deviceCapabilities ?? null,
2380
+ safeAreaInsets: hostContext.safeAreaInsets ?? null,
2381
+ styles: hostContext.styles ?? null,
2382
+ rawContext: hostContext
2383
+ };
2384
+ }
2385
+ __name(useHostContext, "useHostContext");
2386
+
2387
+ // src/mcp/useToolResult.ts
2388
+ function useToolResult() {
2389
+ const { toolResult } = useMcpApp();
2390
+ let result = null;
2391
+ let textContent = null;
2392
+ if (toolResult) {
2393
+ if ("structuredContent" in toolResult && toolResult.structuredContent) {
2394
+ result = toolResult.structuredContent;
2395
+ }
2396
+ if (!result && toolResult.content) {
2397
+ const textItem = toolResult.content.find((c) => c.type === "text");
2398
+ if (textItem) {
2399
+ textContent = textItem.text;
2400
+ try {
2401
+ result = JSON.parse(textItem.text);
2402
+ } catch {
2403
+ }
2404
+ }
2405
+ }
2406
+ }
2407
+ return {
2408
+ result,
2409
+ rawResult: toolResult,
2410
+ hasResult: toolResult !== null,
2411
+ textContent
2412
+ };
2413
+ }
2414
+ __name(useToolResult, "useToolResult");
2415
+
2416
+ // src/mcp/useToolInput.ts
2417
+ function useToolInput() {
2418
+ const { toolInput } = useMcpApp();
2419
+ return {
2420
+ input: toolInput,
2421
+ hasInput: toolInput !== null
2422
+ };
2423
+ }
2424
+ __name(useToolInput, "useToolInput");
2425
+
2426
+ // src/mcp/useToolInputPartial.ts
2427
+ function useToolInputPartial() {
2428
+ const { toolInputPartial } = useMcpApp();
2429
+ return {
2430
+ partialArgs: toolInputPartial,
2431
+ isStreaming: toolInputPartial !== null
2432
+ };
2433
+ }
2434
+ __name(useToolInputPartial, "useToolInputPartial");
2435
+ function useToolSubscription(toolName, options = {}) {
2436
+ const { interval = 1e4, enabled = true, args = {} } = options;
2437
+ const toolHook = useTool(toolName);
2438
+ const intervalRef = useRef(null);
2439
+ const [isPolling, setIsPolling] = useState(false);
2440
+ const stop = useCallback(() => {
2441
+ if (intervalRef.current) {
2442
+ clearInterval(intervalRef.current);
2443
+ intervalRef.current = null;
2444
+ }
2445
+ setIsPolling(false);
2446
+ }, []);
2447
+ const start = useCallback(() => {
2448
+ stop();
2449
+ setIsPolling(true);
2450
+ toolHook.call(args).catch(() => {
2451
+ });
2452
+ intervalRef.current = setInterval(() => {
2453
+ toolHook.call(args).catch(() => {
2454
+ });
2455
+ }, interval);
2456
+ }, [
2457
+ toolHook.call,
2458
+ args,
2459
+ interval,
2460
+ stop
2461
+ ]);
2462
+ const refresh = useCallback(async () => {
2463
+ return toolHook.call(args);
2464
+ }, [
2465
+ toolHook.call,
2466
+ args
2467
+ ]);
2468
+ useEffect(() => {
2469
+ if (enabled) {
2470
+ start();
2471
+ }
2472
+ return () => stop();
2473
+ }, [
2474
+ enabled,
2475
+ start,
2476
+ stop
2477
+ ]);
2478
+ return {
2479
+ result: toolHook.result,
2480
+ loading: toolHook.loading,
2481
+ error: toolHook.error,
2482
+ start,
2483
+ stop,
2484
+ isPolling,
2485
+ refresh
2486
+ };
2487
+ }
2488
+ __name(useToolSubscription, "useToolSubscription");
2489
+
2490
+ // src/types/mcp-types.ts
2491
+ function normalizeToolBinding(tool) {
2492
+ if (typeof tool === "string") {
2493
+ return {
2494
+ name: tool
2495
+ };
2496
+ }
2497
+ return tool;
2498
+ }
2499
+ __name(normalizeToolBinding, "normalizeToolBinding");
2500
+ var DEFAULT_RESULT_CONFIG = {
2501
+ display: "none",
2502
+ autoDismiss: 5e3
2503
+ };
2504
+ var INITIAL_TOOL_STATE = {
2505
+ state: "idle",
2506
+ loading: false,
2507
+ result: null,
2508
+ error: null,
2509
+ hasResult: false
2510
+ };
2511
+ function CardTitle({ className, ...props }) {
2512
+ return /* @__PURE__ */ React25.createElement("div", {
2513
+ "data-slot": "card-title",
2514
+ className: cn("leading-none font-semibold", className),
2515
+ ...props
2516
+ });
2517
+ }
2518
+ __name(CardTitle, "CardTitle");
2519
+ function CardDescription({ className, ...props }) {
2520
+ return /* @__PURE__ */ React25.createElement("div", {
2521
+ "data-slot": "card-description",
2522
+ className: cn("text-muted-foreground text-sm", className),
2523
+ ...props
2524
+ });
2525
+ }
2526
+ __name(CardDescription, "CardDescription");
2527
+ var Form = FormProvider;
2528
+ var FormFieldContext = /* @__PURE__ */ React25.createContext({});
2529
+ var FormField = /* @__PURE__ */ __name(({ ...props }) => {
2530
+ return /* @__PURE__ */ React25.createElement(FormFieldContext.Provider, {
2531
+ value: {
2532
+ name: props.name
2533
+ }
2534
+ }, /* @__PURE__ */ React25.createElement(Controller, props));
2535
+ }, "FormField");
2536
+ var useFormField = /* @__PURE__ */ __name(() => {
2537
+ const fieldContext = React25.useContext(FormFieldContext);
2538
+ const itemContext = React25.useContext(FormItemContext);
2539
+ const { getFieldState } = useFormContext();
2540
+ const formState = useFormState({
2541
+ name: fieldContext.name
2542
+ });
2543
+ const fieldState = getFieldState(fieldContext.name, formState);
2544
+ if (!fieldContext) {
2545
+ throw new Error("useFormField should be used within <FormField>");
2546
+ }
2547
+ const { id } = itemContext;
2548
+ return {
2549
+ id,
2550
+ name: fieldContext.name,
2551
+ formItemId: `${id}-form-item`,
2552
+ formDescriptionId: `${id}-form-item-description`,
2553
+ formMessageId: `${id}-form-item-message`,
2554
+ ...fieldState
2555
+ };
2556
+ }, "useFormField");
2557
+ var FormItemContext = /* @__PURE__ */ React25.createContext({});
2558
+ function FormItem({ className, ...props }) {
2559
+ const id = React25.useId();
2560
+ return /* @__PURE__ */ React25.createElement(FormItemContext.Provider, {
2561
+ value: {
2562
+ id
2563
+ }
2564
+ }, /* @__PURE__ */ React25.createElement("div", {
2565
+ "data-slot": "form-item",
2566
+ className: cn("grid gap-2", className),
2567
+ ...props
2568
+ }));
2569
+ }
2570
+ __name(FormItem, "FormItem");
2571
+ function FormLabel({ className, ...props }) {
2572
+ const { error, formItemId } = useFormField();
2573
+ return /* @__PURE__ */ React25.createElement(Label2, {
2574
+ "data-slot": "form-label",
2575
+ "data-error": !!error,
2576
+ className: cn("data-[error=true]:text-destructive", className),
2577
+ htmlFor: formItemId,
2578
+ ...props
2579
+ });
2580
+ }
2581
+ __name(FormLabel, "FormLabel");
2582
+ function FormControl({ ...props }) {
2583
+ const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
2584
+ return /* @__PURE__ */ React25.createElement(Slot, {
2585
+ "data-slot": "form-control",
2586
+ id: formItemId,
2587
+ "aria-describedby": !error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`,
2588
+ "aria-invalid": !!error,
2589
+ ...props
2590
+ });
2591
+ }
2592
+ __name(FormControl, "FormControl");
2593
+ function FormDescription({ className, ...props }) {
2594
+ const { formDescriptionId } = useFormField();
2595
+ return /* @__PURE__ */ React25.createElement("p", {
2596
+ "data-slot": "form-description",
2597
+ id: formDescriptionId,
2598
+ className: cn("text-muted-foreground text-sm", className),
2599
+ ...props
2600
+ });
2601
+ }
2602
+ __name(FormDescription, "FormDescription");
2603
+ function FormMessage({ className, ...props }) {
2604
+ const { error, formMessageId } = useFormField();
2605
+ const body = error ? String(error?.message ?? "") : props.children;
2606
+ if (!body) {
2607
+ return null;
2608
+ }
2609
+ return /* @__PURE__ */ React25.createElement("p", {
2610
+ "data-slot": "form-message",
2611
+ id: formMessageId,
2612
+ className: cn("text-destructive text-sm", className),
2613
+ ...props
2614
+ }, body);
2615
+ }
2616
+ __name(FormMessage, "FormMessage");
2617
+ var badgeVariants = cva("inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", {
2618
+ variants: {
2619
+ variant: {
2620
+ default: "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
2621
+ secondary: "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
2622
+ destructive: "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
2623
+ outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground"
2624
+ }
2625
+ },
2626
+ defaultVariants: {
2627
+ variant: "default"
2628
+ }
2629
+ });
2630
+ function Badge({ className, variant, asChild = false, ...props }) {
2631
+ const Comp = asChild ? Slot : "span";
2632
+ return /* @__PURE__ */ React25.createElement(Comp, {
2633
+ "data-slot": "badge",
2634
+ className: cn(badgeVariants({
2635
+ variant
2636
+ }), className),
2637
+ ...props
2638
+ });
2639
+ }
2640
+ __name(Badge, "Badge");
2641
+ function TabsList({ className, ...props }) {
2642
+ return /* @__PURE__ */ React25.createElement(TabsPrimitive2.List, {
2643
+ "data-slot": "tabs-list",
2644
+ className: cn("bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]", className),
2645
+ ...props
2646
+ });
2647
+ }
2648
+ __name(TabsList, "TabsList");
2649
+ function TabsTrigger({ className, ...props }) {
2650
+ return /* @__PURE__ */ React25.createElement(TabsPrimitive2.Trigger, {
2651
+ "data-slot": "tabs-trigger",
2652
+ className: cn("data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className),
2653
+ ...props
2654
+ });
2655
+ }
2656
+ __name(TabsTrigger, "TabsTrigger");
2657
+ function TabsContent({ className, ...props }) {
2658
+ return /* @__PURE__ */ React25.createElement(TabsPrimitive2.Content, {
2659
+ "data-slot": "tabs-content",
2660
+ className: cn("flex-1 outline-none", className),
2661
+ ...props
2662
+ });
2663
+ }
2664
+ __name(TabsContent, "TabsContent");
2665
+ function Separator2({ className, orientation = "horizontal", decorative = true, ...props }) {
2666
+ return /* @__PURE__ */ React25.createElement(SeparatorPrimitive.Root, {
2667
+ "data-slot": "separator",
2668
+ decorative,
2669
+ orientation,
2670
+ className: cn("bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px", className),
2671
+ ...props
2672
+ });
2673
+ }
2674
+ __name(Separator2, "Separator");
2675
+ function ScrollArea({ className, children, ...props }) {
2676
+ return /* @__PURE__ */ React25.createElement(ScrollAreaPrimitive.Root, {
2677
+ "data-slot": "scroll-area",
2678
+ className: cn("relative", className),
2679
+ ...props
2680
+ }, /* @__PURE__ */ React25.createElement(ScrollAreaPrimitive.Viewport, {
2681
+ "data-slot": "scroll-area-viewport",
2682
+ className: "focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1"
2683
+ }, children), /* @__PURE__ */ React25.createElement(ScrollBar, null), /* @__PURE__ */ React25.createElement(ScrollAreaPrimitive.Corner, null));
2684
+ }
2685
+ __name(ScrollArea, "ScrollArea");
2686
+ function ScrollBar({ className, orientation = "vertical", ...props }) {
2687
+ return /* @__PURE__ */ React25.createElement(ScrollAreaPrimitive.ScrollAreaScrollbar, {
2688
+ "data-slot": "scroll-area-scrollbar",
2689
+ orientation,
2690
+ className: cn("flex touch-none p-px transition-colors select-none", orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent", orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent", className),
2691
+ ...props
2692
+ }, /* @__PURE__ */ React25.createElement(ScrollAreaPrimitive.ScrollAreaThumb, {
2693
+ "data-slot": "scroll-area-thumb",
2694
+ className: "bg-border relative flex-1 rounded-full"
2695
+ }));
2696
+ }
2697
+ __name(ScrollBar, "ScrollBar");
2698
+ function DropdownMenu({ ...props }) {
2699
+ return /* @__PURE__ */ React25.createElement(DropdownMenuPrimitive.Root, {
2700
+ "data-slot": "dropdown-menu",
2701
+ ...props
2702
+ });
2703
+ }
2704
+ __name(DropdownMenu, "DropdownMenu");
2705
+ function DropdownMenuPortal({ ...props }) {
2706
+ return /* @__PURE__ */ React25.createElement(DropdownMenuPrimitive.Portal, {
2707
+ "data-slot": "dropdown-menu-portal",
2708
+ ...props
2709
+ });
2710
+ }
2711
+ __name(DropdownMenuPortal, "DropdownMenuPortal");
2712
+ function DropdownMenuTrigger({ ...props }) {
2713
+ return /* @__PURE__ */ React25.createElement(DropdownMenuPrimitive.Trigger, {
2714
+ "data-slot": "dropdown-menu-trigger",
2715
+ ...props
2716
+ });
252
2717
  }
253
- __name(useTool, "useTool");
254
-
255
- // src/mcp/useToolResult.ts
256
- function useToolResult() {
257
- const { toolResult } = useMcpApp();
258
- let result = null;
259
- let textContent = null;
260
- if (toolResult) {
261
- if ("structuredContent" in toolResult && toolResult.structuredContent) {
262
- result = toolResult.structuredContent;
263
- }
264
- if (!result && toolResult.content) {
265
- const textItem = toolResult.content.find((c) => c.type === "text");
266
- if (textItem) {
267
- textContent = textItem.text;
268
- try {
269
- result = JSON.parse(textItem.text);
270
- } catch {
271
- }
272
- }
273
- }
274
- }
275
- return {
276
- result,
277
- rawResult: toolResult,
278
- hasResult: toolResult !== null,
279
- textContent
280
- };
2718
+ __name(DropdownMenuTrigger, "DropdownMenuTrigger");
2719
+ function DropdownMenuContent({ className, sideOffset = 4, ...props }) {
2720
+ return /* @__PURE__ */ React25.createElement(DropdownMenuPrimitive.Portal, null, /* @__PURE__ */ React25.createElement(DropdownMenuPrimitive.Content, {
2721
+ "data-slot": "dropdown-menu-content",
2722
+ sideOffset,
2723
+ className: cn("bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md", className),
2724
+ ...props
2725
+ }));
281
2726
  }
282
- __name(useToolResult, "useToolResult");
283
-
284
- // src/mcp/useToolInput.ts
285
- function useToolInput() {
286
- const { toolInput } = useMcpApp();
287
- return {
288
- input: toolInput,
289
- hasInput: toolInput !== null
290
- };
2727
+ __name(DropdownMenuContent, "DropdownMenuContent");
2728
+ function DropdownMenuGroup({ ...props }) {
2729
+ return /* @__PURE__ */ React25.createElement(DropdownMenuPrimitive.Group, {
2730
+ "data-slot": "dropdown-menu-group",
2731
+ ...props
2732
+ });
291
2733
  }
292
- __name(useToolInput, "useToolInput");
293
-
294
- // src/mcp/useToolInputPartial.ts
295
- function useToolInputPartial() {
296
- const { toolInputPartial } = useMcpApp();
297
- return {
298
- partialArgs: toolInputPartial,
299
- isStreaming: toolInputPartial !== null
300
- };
2734
+ __name(DropdownMenuGroup, "DropdownMenuGroup");
2735
+ function DropdownMenuItem({ className, inset, variant = "default", ...props }) {
2736
+ return /* @__PURE__ */ React25.createElement(DropdownMenuPrimitive.Item, {
2737
+ "data-slot": "dropdown-menu-item",
2738
+ "data-inset": inset,
2739
+ "data-variant": variant,
2740
+ className: cn("focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className),
2741
+ ...props
2742
+ });
301
2743
  }
302
- __name(useToolInputPartial, "useToolInputPartial");
303
-
304
- // src/mcp/useHostContext.ts
305
- function useHostContext() {
306
- const { hostContext } = useMcpApp();
307
- return {
308
- theme: hostContext.theme ?? "light",
309
- displayMode: hostContext.displayMode ?? "inline",
310
- viewport: hostContext.viewport ?? null,
311
- locale: hostContext.locale ?? null,
312
- timeZone: hostContext.timeZone ?? null,
313
- platform: hostContext.platform ?? null,
314
- rawContext: hostContext
315
- };
2744
+ __name(DropdownMenuItem, "DropdownMenuItem");
2745
+ function DropdownMenuCheckboxItem({ className, children, checked, ...props }) {
2746
+ return /* @__PURE__ */ React25.createElement(DropdownMenuPrimitive.CheckboxItem, {
2747
+ "data-slot": "dropdown-menu-checkbox-item",
2748
+ className: cn("focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className),
2749
+ checked,
2750
+ ...props
2751
+ }, /* @__PURE__ */ React25.createElement("span", {
2752
+ className: "pointer-events-none absolute left-2 flex size-3.5 items-center justify-center"
2753
+ }, /* @__PURE__ */ React25.createElement(DropdownMenuPrimitive.ItemIndicator, null, /* @__PURE__ */ React25.createElement(CheckIcon, {
2754
+ className: "size-4"
2755
+ }))), children);
316
2756
  }
317
- __name(useHostContext, "useHostContext");
318
- var Button = /* @__PURE__ */ forwardRef(({ className, variant = "primary", size = "md", loading = false, disabled, asChild = false, leftIcon, rightIcon, children, ...props }, ref) => {
319
- const Comp = asChild ? Slot : "button";
320
- return /* @__PURE__ */ React7.createElement(Comp, {
321
- ref,
322
- className: clsx("lui-button", `lui-button--${variant}`, `lui-button--${size}`, loading && "lui-button--loading", className),
323
- disabled: disabled || loading,
2757
+ __name(DropdownMenuCheckboxItem, "DropdownMenuCheckboxItem");
2758
+ function DropdownMenuRadioGroup({ ...props }) {
2759
+ return /* @__PURE__ */ React25.createElement(DropdownMenuPrimitive.RadioGroup, {
2760
+ "data-slot": "dropdown-menu-radio-group",
324
2761
  ...props
325
- }, loading && /* @__PURE__ */ React7.createElement("span", {
326
- className: "lui-button__spinner",
327
- "aria-hidden": "true"
328
- }, /* @__PURE__ */ React7.createElement("svg", {
329
- viewBox: "0 0 24 24",
330
- fill: "none",
331
- className: "lui-spinner-icon"
332
- }, /* @__PURE__ */ React7.createElement("circle", {
333
- cx: "12",
334
- cy: "12",
335
- r: "10",
336
- stroke: "currentColor",
337
- strokeWidth: "3",
338
- strokeLinecap: "round",
339
- strokeDasharray: "32",
340
- strokeDashoffset: "12"
341
- }))), leftIcon && !loading && /* @__PURE__ */ React7.createElement("span", {
342
- className: "lui-button__icon"
343
- }, leftIcon), /* @__PURE__ */ React7.createElement("span", {
344
- className: "lui-button__content"
345
- }, children), rightIcon && /* @__PURE__ */ React7.createElement("span", {
346
- className: "lui-button__icon"
347
- }, rightIcon));
348
- });
349
- Button.displayName = "Button";
350
-
351
- // src/mcp/ActionButton.tsx
352
- function ActionButton({ toolName, toolArgs = {}, onToolSuccess, onToolError, showResult = false, renderResult, children, ...buttonProps }) {
353
- const { call, loading, result, error } = useTool(toolName);
354
- const [hasResult, setHasResult] = useState(false);
355
- const handleClick = /* @__PURE__ */ __name(async () => {
356
- try {
357
- const res = await call(toolArgs);
358
- setHasResult(true);
359
- onToolSuccess?.(res);
360
- } catch (err) {
361
- onToolError?.(err instanceof Error ? err : new Error(String(err)));
362
- }
363
- }, "handleClick");
364
- return /* @__PURE__ */ React7.createElement("div", {
365
- className: "lui-action-button-wrapper"
366
- }, /* @__PURE__ */ React7.createElement(Button, {
367
- ...buttonProps,
368
- loading,
369
- onClick: handleClick
370
- }, children), showResult && hasResult && result !== null && /* @__PURE__ */ React7.createElement("div", {
371
- className: "lui-action-button-result"
372
- }, renderResult ? renderResult(result) : /* @__PURE__ */ React7.createElement("pre", null, JSON.stringify(result, null, 2))), error && /* @__PURE__ */ React7.createElement("div", {
373
- className: "lui-action-button-error"
374
- }, error.message));
2762
+ });
375
2763
  }
376
- __name(ActionButton, "ActionButton");
377
- var Input = /* @__PURE__ */ forwardRef(({ className, label, helperText, error, size = "md", leftElement, rightElement, fullWidth = false, id, ...props }, ref) => {
378
- const inputId = id || `input-${Math.random().toString(36).substr(2, 9)}`;
379
- const hasError = Boolean(error);
380
- return /* @__PURE__ */ React7.createElement("div", {
381
- className: clsx("lui-input-wrapper", fullWidth && "lui-input-wrapper--full-width", className)
382
- }, label && /* @__PURE__ */ React7.createElement("label", {
383
- htmlFor: inputId,
384
- className: "lui-input-label"
385
- }, label), /* @__PURE__ */ React7.createElement("div", {
386
- className: clsx("lui-input-container", `lui-input-container--${size}`, hasError && "lui-input-container--error", leftElement && "lui-input-container--has-left", rightElement && "lui-input-container--has-right")
387
- }, leftElement && /* @__PURE__ */ React7.createElement("span", {
388
- className: "lui-input-element lui-input-element--left"
389
- }, leftElement), /* @__PURE__ */ React7.createElement("input", {
390
- ref,
391
- id: inputId,
392
- className: "lui-input",
393
- "aria-invalid": hasError,
394
- "aria-describedby": error ? `${inputId}-error` : helperText ? `${inputId}-helper` : void 0,
2764
+ __name(DropdownMenuRadioGroup, "DropdownMenuRadioGroup");
2765
+ function DropdownMenuRadioItem({ className, children, ...props }) {
2766
+ return /* @__PURE__ */ React25.createElement(DropdownMenuPrimitive.RadioItem, {
2767
+ "data-slot": "dropdown-menu-radio-item",
2768
+ className: cn("focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className),
2769
+ ...props
2770
+ }, /* @__PURE__ */ React25.createElement("span", {
2771
+ className: "pointer-events-none absolute left-2 flex size-3.5 items-center justify-center"
2772
+ }, /* @__PURE__ */ React25.createElement(DropdownMenuPrimitive.ItemIndicator, null, /* @__PURE__ */ React25.createElement(CircleIcon, {
2773
+ className: "size-2 fill-current"
2774
+ }))), children);
2775
+ }
2776
+ __name(DropdownMenuRadioItem, "DropdownMenuRadioItem");
2777
+ function DropdownMenuLabel({ className, inset, ...props }) {
2778
+ return /* @__PURE__ */ React25.createElement(DropdownMenuPrimitive.Label, {
2779
+ "data-slot": "dropdown-menu-label",
2780
+ "data-inset": inset,
2781
+ className: cn("px-2 py-1.5 text-sm font-medium data-[inset]:pl-8", className),
395
2782
  ...props
396
- }), rightElement && /* @__PURE__ */ React7.createElement("span", {
397
- className: "lui-input-element lui-input-element--right"
398
- }, rightElement)), (error || helperText) && /* @__PURE__ */ React7.createElement("p", {
399
- id: error ? `${inputId}-error` : `${inputId}-helper`,
400
- className: clsx("lui-input-message", error && "lui-input-message--error")
401
- }, error || helperText));
402
- });
403
- Input.displayName = "Input";
404
- function ToolForm({ toolName, fields, submitText = "Submit", onSuccess, onError, showResult = false, className }) {
405
- const { call, loading, result, error } = useTool(toolName);
406
- const [formData, setFormData] = useState(() => {
407
- const initial = {};
408
- fields.forEach((field) => {
409
- if (field.defaultValue !== void 0) {
410
- initial[field.name] = field.defaultValue;
411
- }
412
- });
413
- return initial;
414
2783
  });
415
- const handleSubmit = /* @__PURE__ */ __name(async (e) => {
416
- e.preventDefault();
417
- const args = {};
418
- fields.forEach((field) => {
419
- const value = formData[field.name];
420
- if (field.type === "number" && value !== void 0) {
421
- args[field.name] = Number(value);
422
- } else {
423
- args[field.name] = value;
424
- }
425
- });
426
- try {
427
- const res = await call(args);
428
- onSuccess?.(res);
429
- } catch (err) {
430
- onError?.(err instanceof Error ? err : new Error(String(err)));
431
- }
432
- }, "handleSubmit");
433
- const handleChange = /* @__PURE__ */ __name((name, value) => {
434
- setFormData((prev) => ({
435
- ...prev,
436
- [name]: value
437
- }));
438
- }, "handleChange");
439
- return /* @__PURE__ */ React7.createElement("form", {
440
- className: clsx("lui-tool-form", className),
441
- onSubmit: handleSubmit
442
- }, /* @__PURE__ */ React7.createElement("div", {
443
- className: "lui-tool-form-fields"
444
- }, fields.map((field) => /* @__PURE__ */ React7.createElement("div", {
445
- key: field.name,
446
- className: "lui-tool-form-field"
447
- }, field.type === "textarea" ? /* @__PURE__ */ React7.createElement("div", {
448
- className: "lui-input-wrapper lui-input-wrapper--full-width"
449
- }, /* @__PURE__ */ React7.createElement("label", {
450
- className: "lui-input-label"
451
- }, field.label), /* @__PURE__ */ React7.createElement("textarea", {
452
- className: "lui-tool-form-textarea",
453
- name: field.name,
454
- placeholder: field.placeholder,
455
- required: field.required,
456
- value: formData[field.name] ?? "",
457
- onChange: /* @__PURE__ */ __name((e) => handleChange(field.name, e.target.value), "onChange")
458
- }), field.helperText && /* @__PURE__ */ React7.createElement("p", {
459
- className: "lui-input-message"
460
- }, field.helperText)) : /* @__PURE__ */ React7.createElement(Input, {
461
- fullWidth: true,
462
- label: field.label,
463
- type: field.type ?? "text",
464
- name: field.name,
465
- placeholder: field.placeholder,
466
- required: field.required,
467
- helperText: field.helperText,
468
- value: formData[field.name] ?? "",
469
- onChange: /* @__PURE__ */ __name((e) => handleChange(field.name, e.target.value), "onChange")
470
- })))), /* @__PURE__ */ React7.createElement("div", {
471
- className: "lui-tool-form-actions"
472
- }, /* @__PURE__ */ React7.createElement(Button, {
473
- type: "submit",
474
- loading
475
- }, submitText)), error && /* @__PURE__ */ React7.createElement("div", {
476
- className: "lui-tool-form-error"
477
- }, error.message), showResult && result !== null && /* @__PURE__ */ React7.createElement("div", {
478
- className: "lui-tool-form-result"
479
- }, /* @__PURE__ */ React7.createElement("pre", null, JSON.stringify(result, null, 2))));
480
2784
  }
481
- __name(ToolForm, "ToolForm");
482
- var Card = /* @__PURE__ */ forwardRef(({ className, variant = "default", padding = "md", interactive = false, children, ...props }, ref) => {
483
- return /* @__PURE__ */ React7.createElement("div", {
484
- ref,
485
- className: clsx("lui-card", `lui-card--${variant}`, `lui-card--padding-${padding}`, interactive && "lui-card--interactive", className),
2785
+ __name(DropdownMenuLabel, "DropdownMenuLabel");
2786
+ function DropdownMenuSeparator({ className, ...props }) {
2787
+ return /* @__PURE__ */ React25.createElement(DropdownMenuPrimitive.Separator, {
2788
+ "data-slot": "dropdown-menu-separator",
2789
+ className: cn("bg-border -mx-1 my-1 h-px", className),
486
2790
  ...props
487
- }, children);
488
- });
489
- Card.displayName = "Card";
490
- var CardHeader = /* @__PURE__ */ forwardRef(({ className, title, description, action, children, ...props }, ref) => {
491
- return /* @__PURE__ */ React7.createElement("div", {
492
- ref,
493
- className: clsx("lui-card-header", className),
2791
+ });
2792
+ }
2793
+ __name(DropdownMenuSeparator, "DropdownMenuSeparator");
2794
+ function DropdownMenuShortcut({ className, ...props }) {
2795
+ return /* @__PURE__ */ React25.createElement("span", {
2796
+ "data-slot": "dropdown-menu-shortcut",
2797
+ className: cn("text-muted-foreground ml-auto text-xs tracking-widest", className),
494
2798
  ...props
495
- }, (title || description) && /* @__PURE__ */ React7.createElement("div", {
496
- className: "lui-card-header__text"
497
- }, title && /* @__PURE__ */ React7.createElement("h3", {
498
- className: "lui-card-header__title"
499
- }, title), description && /* @__PURE__ */ React7.createElement("p", {
500
- className: "lui-card-header__description"
501
- }, description)), action && /* @__PURE__ */ React7.createElement("div", {
502
- className: "lui-card-header__action"
503
- }, action), children);
504
- });
505
- CardHeader.displayName = "CardHeader";
506
- var CardContent = /* @__PURE__ */ forwardRef(({ className, children, ...props }, ref) => {
507
- return /* @__PURE__ */ React7.createElement("div", {
508
- ref,
509
- className: clsx("lui-card-content", className),
2799
+ });
2800
+ }
2801
+ __name(DropdownMenuShortcut, "DropdownMenuShortcut");
2802
+ function DropdownMenuSub({ ...props }) {
2803
+ return /* @__PURE__ */ React25.createElement(DropdownMenuPrimitive.Sub, {
2804
+ "data-slot": "dropdown-menu-sub",
510
2805
  ...props
511
- }, children);
512
- });
513
- CardContent.displayName = "CardContent";
514
- var CardFooter = /* @__PURE__ */ forwardRef(({ className, children, ...props }, ref) => {
515
- return /* @__PURE__ */ React7.createElement("div", {
516
- ref,
517
- className: clsx("lui-card-footer", className),
2806
+ });
2807
+ }
2808
+ __name(DropdownMenuSub, "DropdownMenuSub");
2809
+ function DropdownMenuSubTrigger({ className, inset, children, ...props }) {
2810
+ return /* @__PURE__ */ React25.createElement(DropdownMenuPrimitive.SubTrigger, {
2811
+ "data-slot": "dropdown-menu-sub-trigger",
2812
+ "data-inset": inset,
2813
+ className: cn("focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className),
518
2814
  ...props
519
- }, children);
520
- });
521
- CardFooter.displayName = "CardFooter";
2815
+ }, children, /* @__PURE__ */ React25.createElement(ChevronRightIcon, {
2816
+ className: "ml-auto size-4"
2817
+ }));
2818
+ }
2819
+ __name(DropdownMenuSubTrigger, "DropdownMenuSubTrigger");
2820
+ function DropdownMenuSubContent({ className, ...props }) {
2821
+ return /* @__PURE__ */ React25.createElement(DropdownMenuPrimitive.SubContent, {
2822
+ "data-slot": "dropdown-menu-sub-content",
2823
+ className: cn("bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg", className),
2824
+ ...props
2825
+ });
2826
+ }
2827
+ __name(DropdownMenuSubContent, "DropdownMenuSubContent");
2828
+ function TooltipProvider({ delayDuration = 0, ...props }) {
2829
+ return /* @__PURE__ */ React25.createElement(TooltipPrimitive.Provider, {
2830
+ "data-slot": "tooltip-provider",
2831
+ delayDuration,
2832
+ ...props
2833
+ });
2834
+ }
2835
+ __name(TooltipProvider, "TooltipProvider");
2836
+ function Tooltip({ ...props }) {
2837
+ return /* @__PURE__ */ React25.createElement(TooltipProvider, null, /* @__PURE__ */ React25.createElement(TooltipPrimitive.Root, {
2838
+ "data-slot": "tooltip",
2839
+ ...props
2840
+ }));
2841
+ }
2842
+ __name(Tooltip, "Tooltip");
2843
+ function TooltipTrigger({ ...props }) {
2844
+ return /* @__PURE__ */ React25.createElement(TooltipPrimitive.Trigger, {
2845
+ "data-slot": "tooltip-trigger",
2846
+ ...props
2847
+ });
2848
+ }
2849
+ __name(TooltipTrigger, "TooltipTrigger");
2850
+ function TooltipContent({ className, sideOffset = 0, children, ...props }) {
2851
+ return /* @__PURE__ */ React25.createElement(TooltipPrimitive.Portal, null, /* @__PURE__ */ React25.createElement(TooltipPrimitive.Content, {
2852
+ "data-slot": "tooltip-content",
2853
+ sideOffset,
2854
+ className: cn("bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance", className),
2855
+ ...props
2856
+ }, children, /* @__PURE__ */ React25.createElement(TooltipPrimitive.Arrow, {
2857
+ className: "bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]"
2858
+ })));
2859
+ }
2860
+ __name(TooltipContent, "TooltipContent");
522
2861
  function DataGrid({ data, columns, searchable = false, searchPlaceholder = "Search...", onRowClick, loading = false, emptyMessage = "No data", className }) {
523
2862
  const [sorting, setSorting] = useState([]);
524
2863
  const [globalFilter, setGlobalFilter] = useState("");
@@ -545,50 +2884,50 @@ function DataGrid({ data, columns, searchable = false, searchPlaceholder = "Sear
545
2884
  getSortedRowModel: getSortedRowModel(),
546
2885
  getFilteredRowModel: getFilteredRowModel()
547
2886
  });
548
- return /* @__PURE__ */ React7.createElement("div", {
2887
+ return /* @__PURE__ */ React25__default.createElement("div", {
549
2888
  className: clsx("lui-datagrid", className)
550
- }, searchable && /* @__PURE__ */ React7.createElement("div", {
2889
+ }, searchable && /* @__PURE__ */ React25__default.createElement("div", {
551
2890
  className: "lui-datagrid-search"
552
- }, /* @__PURE__ */ React7.createElement("input", {
2891
+ }, /* @__PURE__ */ React25__default.createElement("input", {
553
2892
  type: "text",
554
2893
  value: globalFilter,
555
2894
  onChange: /* @__PURE__ */ __name((e) => setGlobalFilter(e.target.value), "onChange"),
556
2895
  placeholder: searchPlaceholder,
557
2896
  className: "lui-datagrid-search-input"
558
- })), /* @__PURE__ */ React7.createElement("div", {
2897
+ })), /* @__PURE__ */ React25__default.createElement("div", {
559
2898
  className: "lui-datagrid-container"
560
- }, /* @__PURE__ */ React7.createElement("table", {
2899
+ }, /* @__PURE__ */ React25__default.createElement("table", {
561
2900
  className: "lui-datagrid-table"
562
- }, /* @__PURE__ */ React7.createElement("thead", null, table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ React7.createElement("tr", {
2901
+ }, /* @__PURE__ */ React25__default.createElement("thead", null, table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ React25__default.createElement("tr", {
563
2902
  key: headerGroup.id
564
- }, headerGroup.headers.map((header) => /* @__PURE__ */ React7.createElement("th", {
2903
+ }, headerGroup.headers.map((header) => /* @__PURE__ */ React25__default.createElement("th", {
565
2904
  key: header.id,
566
2905
  className: clsx("lui-datagrid-th", header.column.getCanSort() && "lui-datagrid-th--sortable"),
567
2906
  onClick: header.column.getToggleSortingHandler(),
568
2907
  style: {
569
2908
  width: header.column.getSize()
570
2909
  }
571
- }, /* @__PURE__ */ React7.createElement("div", {
2910
+ }, /* @__PURE__ */ React25__default.createElement("div", {
572
2911
  className: "lui-datagrid-th-content"
573
- }, flexRender(header.column.columnDef.header, header.getContext()), header.column.getIsSorted() && /* @__PURE__ */ React7.createElement("span", {
2912
+ }, flexRender(header.column.columnDef.header, header.getContext()), header.column.getIsSorted() && /* @__PURE__ */ React25__default.createElement("span", {
574
2913
  className: "lui-datagrid-sort-icon"
575
- }, header.column.getIsSorted() === "asc" ? "\u2191" : "\u2193"))))))), /* @__PURE__ */ React7.createElement("tbody", null, loading ? /* @__PURE__ */ React7.createElement("tr", null, /* @__PURE__ */ React7.createElement("td", {
2914
+ }, header.column.getIsSorted() === "asc" ? "\u2191" : "\u2193"))))))), /* @__PURE__ */ React25__default.createElement("tbody", null, loading ? /* @__PURE__ */ React25__default.createElement("tr", null, /* @__PURE__ */ React25__default.createElement("td", {
576
2915
  colSpan: columns.length,
577
2916
  className: "lui-datagrid-loading"
578
- }, "Loading...")) : table.getRowModel().rows.length === 0 ? /* @__PURE__ */ React7.createElement("tr", null, /* @__PURE__ */ React7.createElement("td", {
2917
+ }, "Loading...")) : table.getRowModel().rows.length === 0 ? /* @__PURE__ */ React25__default.createElement("tr", null, /* @__PURE__ */ React25__default.createElement("td", {
579
2918
  colSpan: columns.length,
580
2919
  className: "lui-datagrid-empty"
581
- }, emptyMessage)) : table.getRowModel().rows.map((row) => /* @__PURE__ */ React7.createElement("tr", {
2920
+ }, emptyMessage)) : table.getRowModel().rows.map((row) => /* @__PURE__ */ React25__default.createElement("tr", {
582
2921
  key: row.id,
583
2922
  className: clsx("lui-datagrid-row", onRowClick && "lui-datagrid-row--clickable"),
584
2923
  onClick: /* @__PURE__ */ __name(() => onRowClick?.(row.original), "onClick")
585
- }, row.getVisibleCells().map((cell) => /* @__PURE__ */ React7.createElement("td", {
2924
+ }, row.getVisibleCells().map((cell) => /* @__PURE__ */ React25__default.createElement("td", {
586
2925
  key: cell.id,
587
2926
  className: "lui-datagrid-td"
588
2927
  }, flexRender(cell.column.columnDef.cell, cell.getContext())))))))));
589
2928
  }
590
2929
  __name(DataGrid, "DataGrid");
591
- Chart$1.register(CategoryScale, LinearScale, PointElement, LineElement, BarElement, ArcElement, Title, Tooltip, Legend);
2930
+ Chart$1.register(CategoryScale, LinearScale, PointElement, LineElement, BarElement, ArcElement, Title, Tooltip$1, Legend);
592
2931
  function Chart({ type, data, options, height = 300, width = "100%", className }) {
593
2932
  const defaultOptions = {
594
2933
  responsive: true,
@@ -641,13 +2980,13 @@ function Chart({ type, data, options, height = 300, width = "100%", className })
641
2980
  ...options?.plugins
642
2981
  }
643
2982
  };
644
- return /* @__PURE__ */ React7.createElement("div", {
2983
+ return /* @__PURE__ */ React25__default.createElement("div", {
645
2984
  className: clsx("lui-chart", className),
646
2985
  style: {
647
2986
  height,
648
2987
  width
649
2988
  }
650
- }, /* @__PURE__ */ React7.createElement(Chart$2, {
2989
+ }, /* @__PURE__ */ React25__default.createElement(Chart$2, {
651
2990
  type,
652
2991
  data,
653
2992
  options: mergedOptions
@@ -656,99 +2995,176 @@ function Chart({ type, data, options, height = 300, width = "100%", className })
656
2995
  __name(Chart, "Chart");
657
2996
  function AppShell({ header, sidebar, footer, sidebarPosition = "left", sidebarWidth = 240, autoResize = true, padding = "md", className, children, ...props }) {
658
2997
  const containerRef = useRef(null);
2998
+ const { app } = useMcpApp();
659
2999
  useEffect(() => {
660
3000
  if (!autoResize || !containerRef.current) return;
661
- const resizeObserver = new ResizeObserver((entries) => {
662
- for (const entry of entries) {
663
- const { height } = entry.contentRect;
664
- window.parent.postMessage({
665
- type: "resize",
666
- height: Math.ceil(height)
667
- }, "*");
668
- }
669
- });
3001
+ if (!app) return;
3002
+ let lastWidth = 0;
3003
+ let lastHeight = 0;
3004
+ let scheduled = false;
3005
+ const sendSizeChanged = /* @__PURE__ */ __name(() => {
3006
+ if (scheduled) return;
3007
+ scheduled = true;
3008
+ requestAnimationFrame(() => {
3009
+ scheduled = false;
3010
+ if (!containerRef.current) return;
3011
+ const rect = containerRef.current.getBoundingClientRect();
3012
+ const width = Math.ceil(rect.width);
3013
+ const height = Math.ceil(rect.height);
3014
+ if (width !== lastWidth || height !== lastHeight) {
3015
+ lastWidth = width;
3016
+ lastHeight = height;
3017
+ app.sendSizeChanged({
3018
+ width,
3019
+ height
3020
+ });
3021
+ }
3022
+ });
3023
+ }, "sendSizeChanged");
3024
+ const resizeObserver = new ResizeObserver(sendSizeChanged);
670
3025
  resizeObserver.observe(containerRef.current);
3026
+ sendSizeChanged();
671
3027
  return () => {
672
3028
  resizeObserver.disconnect();
673
3029
  };
674
3030
  }, [
675
- autoResize
3031
+ autoResize,
3032
+ app
676
3033
  ]);
677
3034
  const sidebarStyle = {
678
3035
  width: typeof sidebarWidth === "number" ? `${sidebarWidth}px` : sidebarWidth,
679
3036
  flexShrink: 0
680
3037
  };
681
- return /* @__PURE__ */ React7.createElement("div", {
3038
+ return /* @__PURE__ */ React25__default.createElement("div", {
682
3039
  ref: containerRef,
683
3040
  className: clsx("lui-app-shell", `lui-app-shell--padding-${padding}`, className),
684
3041
  ...props
685
- }, header && /* @__PURE__ */ React7.createElement("header", {
3042
+ }, header && /* @__PURE__ */ React25__default.createElement("header", {
686
3043
  className: "lui-app-shell-header"
687
- }, header), /* @__PURE__ */ React7.createElement("div", {
3044
+ }, header), /* @__PURE__ */ React25__default.createElement("div", {
688
3045
  className: "lui-app-shell-body"
689
- }, sidebar && sidebarPosition === "left" && /* @__PURE__ */ React7.createElement("aside", {
3046
+ }, sidebar && sidebarPosition === "left" && /* @__PURE__ */ React25__default.createElement("aside", {
690
3047
  className: "lui-app-shell-sidebar",
691
3048
  style: sidebarStyle
692
- }, sidebar), /* @__PURE__ */ React7.createElement("main", {
3049
+ }, sidebar), /* @__PURE__ */ React25__default.createElement("main", {
693
3050
  className: "lui-app-shell-main"
694
- }, children), sidebar && sidebarPosition === "right" && /* @__PURE__ */ React7.createElement("aside", {
3051
+ }, children), sidebar && sidebarPosition === "right" && /* @__PURE__ */ React25__default.createElement("aside", {
695
3052
  className: "lui-app-shell-sidebar",
696
3053
  style: sidebarStyle
697
- }, sidebar)), footer && /* @__PURE__ */ React7.createElement("footer", {
3054
+ }, sidebar)), footer && /* @__PURE__ */ React25__default.createElement("footer", {
698
3055
  className: "lui-app-shell-footer"
699
3056
  }, footer));
700
3057
  }
701
3058
  __name(AppShell, "AppShell");
3059
+ function Tabs2({ tabs, defaultValue, value, onValueChange, children, className }) {
3060
+ const defaultTab = defaultValue || tabs[0]?.value;
3061
+ return /* @__PURE__ */ React25__default.createElement(TabsPrimitive2.Root, {
3062
+ className: clsx("lui-tabs", className),
3063
+ defaultValue: defaultTab,
3064
+ value,
3065
+ onValueChange
3066
+ }, /* @__PURE__ */ React25__default.createElement(TabsPrimitive2.List, {
3067
+ className: "lui-tabs-list"
3068
+ }, tabs.map((tab) => /* @__PURE__ */ React25__default.createElement(TabsPrimitive2.Trigger, {
3069
+ key: tab.value,
3070
+ value: tab.value,
3071
+ disabled: tab.disabled,
3072
+ className: "lui-tabs-trigger"
3073
+ }, tab.label))), children);
3074
+ }
3075
+ __name(Tabs2, "Tabs");
3076
+ function TabContent({ value, children, className }) {
3077
+ return /* @__PURE__ */ React25__default.createElement(TabsPrimitive2.Content, {
3078
+ value,
3079
+ className: clsx("lui-tabs-content", className)
3080
+ }, children);
3081
+ }
3082
+ __name(TabContent, "TabContent");
3083
+ function Modal({ open, defaultOpen, onOpenChange, title, description, children, className, trigger }) {
3084
+ return /* @__PURE__ */ React25__default.createElement(DialogPrimitive.Root, {
3085
+ open,
3086
+ defaultOpen,
3087
+ onOpenChange
3088
+ }, trigger && /* @__PURE__ */ React25__default.createElement(DialogPrimitive.Trigger, {
3089
+ asChild: true
3090
+ }, trigger), /* @__PURE__ */ React25__default.createElement(DialogPrimitive.Portal, null, /* @__PURE__ */ React25__default.createElement(DialogPrimitive.Overlay, {
3091
+ className: "lui-modal-overlay"
3092
+ }), /* @__PURE__ */ React25__default.createElement(DialogPrimitive.Content, {
3093
+ className: clsx("lui-modal-content", className)
3094
+ }, title && /* @__PURE__ */ React25__default.createElement(DialogPrimitive.Title, {
3095
+ className: "lui-modal-title"
3096
+ }, title), description && /* @__PURE__ */ React25__default.createElement(DialogPrimitive.Description, {
3097
+ className: "lui-modal-description"
3098
+ }, description), children, /* @__PURE__ */ React25__default.createElement(DialogPrimitive.Close, {
3099
+ className: "lui-modal-close",
3100
+ "aria-label": "Close"
3101
+ }, /* @__PURE__ */ React25__default.createElement(CloseIcon, null)))));
3102
+ }
3103
+ __name(Modal, "Modal");
3104
+ function CloseIcon() {
3105
+ return /* @__PURE__ */ React25__default.createElement("svg", {
3106
+ width: "14",
3107
+ height: "14",
3108
+ viewBox: "0 0 14 14",
3109
+ fill: "none"
3110
+ }, /* @__PURE__ */ React25__default.createElement("path", {
3111
+ d: "M3.5 3.5L10.5 10.5M10.5 3.5L3.5 10.5",
3112
+ stroke: "currentColor",
3113
+ strokeWidth: "1.5",
3114
+ strokeLinecap: "round"
3115
+ }));
3116
+ }
3117
+ __name(CloseIcon, "CloseIcon");
702
3118
  function CodeBlock({ code, language = "text", showLineNumbers = false, copyable = true, className }) {
703
- const [copied, setCopied] = React7.useState(false);
3119
+ const [copied, setCopied] = React25__default.useState(false);
704
3120
  const handleCopy = /* @__PURE__ */ __name(async () => {
705
3121
  await navigator.clipboard.writeText(code);
706
3122
  setCopied(true);
707
3123
  setTimeout(() => setCopied(false), 2e3);
708
3124
  }, "handleCopy");
709
- return /* @__PURE__ */ React7.createElement("div", {
3125
+ return /* @__PURE__ */ React25__default.createElement("div", {
710
3126
  className: clsx("lui-code-block", className)
711
- }, copyable && /* @__PURE__ */ React7.createElement("button", {
3127
+ }, copyable && /* @__PURE__ */ React25__default.createElement("button", {
712
3128
  type: "button",
713
3129
  className: "lui-code-block-copy",
714
3130
  onClick: handleCopy,
715
3131
  "aria-label": copied ? "Copied!" : "Copy code"
716
- }, copied ? /* @__PURE__ */ React7.createElement("svg", {
3132
+ }, copied ? /* @__PURE__ */ React25__default.createElement("svg", {
717
3133
  viewBox: "0 0 24 24",
718
3134
  fill: "none",
719
3135
  stroke: "currentColor",
720
3136
  strokeWidth: "2"
721
- }, /* @__PURE__ */ React7.createElement("polyline", {
3137
+ }, /* @__PURE__ */ React25__default.createElement("polyline", {
722
3138
  points: "20,6 9,17 4,12"
723
- })) : /* @__PURE__ */ React7.createElement("svg", {
3139
+ })) : /* @__PURE__ */ React25__default.createElement("svg", {
724
3140
  viewBox: "0 0 24 24",
725
3141
  fill: "none",
726
3142
  stroke: "currentColor",
727
3143
  strokeWidth: "2"
728
- }, /* @__PURE__ */ React7.createElement("rect", {
3144
+ }, /* @__PURE__ */ React25__default.createElement("rect", {
729
3145
  x: "9",
730
3146
  y: "9",
731
3147
  width: "13",
732
3148
  height: "13",
733
3149
  rx: "2",
734
3150
  ry: "2"
735
- }), /* @__PURE__ */ React7.createElement("path", {
3151
+ }), /* @__PURE__ */ React25__default.createElement("path", {
736
3152
  d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"
737
- }))), /* @__PURE__ */ React7.createElement(Highlight, {
3153
+ }))), /* @__PURE__ */ React25__default.createElement(Highlight, {
738
3154
  theme: themes.nightOwl,
739
3155
  code: code.trim(),
740
3156
  language
741
- }, ({ className: hlClassName, style, tokens, getLineProps, getTokenProps }) => /* @__PURE__ */ React7.createElement("pre", {
3157
+ }, ({ className: hlClassName, style, tokens, getLineProps, getTokenProps }) => /* @__PURE__ */ React25__default.createElement("pre", {
742
3158
  className: clsx("lui-code-block-pre", hlClassName),
743
3159
  style
744
- }, tokens.map((line, i) => /* @__PURE__ */ React7.createElement("div", {
3160
+ }, tokens.map((line, i) => /* @__PURE__ */ React25__default.createElement("div", {
745
3161
  key: i,
746
3162
  ...getLineProps({
747
3163
  line
748
3164
  })
749
- }, showLineNumbers && /* @__PURE__ */ React7.createElement("span", {
3165
+ }, showLineNumbers && /* @__PURE__ */ React25__default.createElement("span", {
750
3166
  className: "lui-code-block-line-number"
751
- }, i + 1), line.map((token, key) => /* @__PURE__ */ React7.createElement("span", {
3167
+ }, i + 1), line.map((token, key) => /* @__PURE__ */ React25__default.createElement("span", {
752
3168
  key,
753
3169
  ...getTokenProps({
754
3170
  token
@@ -756,7 +3172,74 @@ function CodeBlock({ code, language = "text", showLineNumbers = false, copyable
756
3172
  })))))));
757
3173
  }
758
3174
  __name(CodeBlock, "CodeBlock");
3175
+ var Card2 = /* @__PURE__ */ forwardRef(({ className, variant = "default", padding = "md", interactive = false, children, ...props }, ref) => {
3176
+ return /* @__PURE__ */ React25__default.createElement("div", {
3177
+ ref,
3178
+ className: clsx("lui-card", `lui-card--${variant}`, `lui-card--padding-${padding}`, interactive && "lui-card--interactive", className),
3179
+ ...props
3180
+ }, children);
3181
+ });
3182
+ Card2.displayName = "Card";
3183
+ var CardHeader2 = /* @__PURE__ */ forwardRef(({ className, title, description, action, children, ...props }, ref) => {
3184
+ return /* @__PURE__ */ React25__default.createElement("div", {
3185
+ ref,
3186
+ className: clsx("lui-card-header", className),
3187
+ ...props
3188
+ }, (title || description) && /* @__PURE__ */ React25__default.createElement("div", {
3189
+ className: "lui-card-header__text"
3190
+ }, title && /* @__PURE__ */ React25__default.createElement("h3", {
3191
+ className: "lui-card-header__title"
3192
+ }, title), description && /* @__PURE__ */ React25__default.createElement("p", {
3193
+ className: "lui-card-header__description"
3194
+ }, description)), action && /* @__PURE__ */ React25__default.createElement("div", {
3195
+ className: "lui-card-header__action"
3196
+ }, action), children);
3197
+ });
3198
+ CardHeader2.displayName = "CardHeader";
3199
+ var CardContent2 = /* @__PURE__ */ forwardRef(({ className, children, ...props }, ref) => {
3200
+ return /* @__PURE__ */ React25__default.createElement("div", {
3201
+ ref,
3202
+ className: clsx("lui-card-content", className),
3203
+ ...props
3204
+ }, children);
3205
+ });
3206
+ CardContent2.displayName = "CardContent";
3207
+ var CardFooter2 = /* @__PURE__ */ forwardRef(({ className, children, ...props }, ref) => {
3208
+ return /* @__PURE__ */ React25__default.createElement("div", {
3209
+ ref,
3210
+ className: clsx("lui-card-footer", className),
3211
+ ...props
3212
+ }, children);
3213
+ });
3214
+ CardFooter2.displayName = "CardFooter";
3215
+ var Input2 = /* @__PURE__ */ forwardRef(({ className, label, helperText, error, size = "md", leftElement, rightElement, fullWidth = false, id, ...props }, ref) => {
3216
+ const inputId = id || `input-${Math.random().toString(36).substr(2, 9)}`;
3217
+ const hasError = Boolean(error);
3218
+ return /* @__PURE__ */ React25__default.createElement("div", {
3219
+ className: clsx("lui-input-wrapper", fullWidth && "lui-input-wrapper--full-width", className)
3220
+ }, label && /* @__PURE__ */ React25__default.createElement("label", {
3221
+ htmlFor: inputId,
3222
+ className: "lui-input-label"
3223
+ }, label), /* @__PURE__ */ React25__default.createElement("div", {
3224
+ className: clsx("lui-input-container", `lui-input-container--${size}`, hasError && "lui-input-container--error", leftElement && "lui-input-container--has-left", rightElement && "lui-input-container--has-right")
3225
+ }, leftElement && /* @__PURE__ */ React25__default.createElement("span", {
3226
+ className: "lui-input-element lui-input-element--left"
3227
+ }, leftElement), /* @__PURE__ */ React25__default.createElement("input", {
3228
+ ref,
3229
+ id: inputId,
3230
+ className: "lui-input",
3231
+ "aria-invalid": hasError,
3232
+ "aria-describedby": error ? `${inputId}-error` : helperText ? `${inputId}-helper` : void 0,
3233
+ ...props
3234
+ }), rightElement && /* @__PURE__ */ React25__default.createElement("span", {
3235
+ className: "lui-input-element lui-input-element--right"
3236
+ }, rightElement)), (error || helperText) && /* @__PURE__ */ React25__default.createElement("p", {
3237
+ id: error ? `${inputId}-error` : `${inputId}-helper`,
3238
+ className: clsx("lui-input-message", error && "lui-input-message--error")
3239
+ }, error || helperText));
3240
+ });
3241
+ Input2.displayName = "Input";
759
3242
 
760
- export { ActionButton, AppProvider, AppShell, Button, Card, CardContent, CardFooter, CardHeader, Chart, CodeBlock, DataGrid, Input, ToolForm, UIApp, getUIAppMetadata, getUIAppUri, useHostContext, useMcpApp, useTool, useToolInput, useToolInputPartial, useToolResult };
3243
+ export { ActionButton, Alert, AlertDescription, AlertTitle, AppProvider, AppShell, Badge, Button2 as Button, Card2 as Card, CardContent2 as CardContent, CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle, Chart, Checkbox, CodeBlock, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, DEFAULT_RESULT_CONFIG, DataGrid, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, INITIAL_TOOL_STATE, Input2 as Input, Label2 as Label, Modal, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, RequireConnection, ResourceView, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator2 as Separator, Skeleton, Slider, StreamingContent, Switch, TabContent, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs2 as Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toaster, ToolButton, ToolDataGrid, ToolErrorBoundary, ToolForm, ToolInput, ToolProvider, ToolSelect, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, badgeVariants, buttonVariants, cn, normalizeToolBinding, useFormField, useHostContext, useMcpApp, useMessage, useResource, useTool, useToolContext, useToolInput, useToolInputPartial, useToolResult, useToolStream, useToolSubscription };
761
3244
  //# sourceMappingURL=index.mjs.map
762
3245
  //# sourceMappingURL=index.mjs.map