@surf-kit/agent 0.2.2 → 0.4.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/chat/index.cjs +733 -222
- package/dist/chat/index.cjs.map +1 -1
- package/dist/chat/index.d.cts +13 -7
- package/dist/chat/index.d.ts +13 -7
- package/dist/chat/index.js +715 -204
- package/dist/chat/index.js.map +1 -1
- package/dist/{chat-ChYl2XjV.d.cts → chat-BRY3xGg_.d.cts} +11 -2
- package/dist/{chat--OifhIRe.d.ts → chat-CcKc6OAR.d.ts} +11 -2
- package/dist/{hooks-BGs8-4GK.d.ts → hooks-BLeiVk-x.d.ts} +22 -5
- package/dist/{hooks-DLfF18IU.d.cts → hooks-CSGGLd7j.d.cts} +22 -5
- package/dist/hooks.cjs +160 -85
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.cts +3 -3
- package/dist/hooks.d.ts +3 -3
- package/dist/hooks.js +160 -85
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +794 -283
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +758 -247
- package/dist/index.js.map +1 -1
- package/dist/layouts/index.cjs +754 -243
- package/dist/layouts/index.cjs.map +1 -1
- package/dist/layouts/index.d.cts +1 -1
- package/dist/layouts/index.d.ts +1 -1
- package/dist/layouts/index.js +733 -222
- package/dist/layouts/index.js.map +1 -1
- package/dist/mcp/index.cjs +1 -1
- package/dist/mcp/index.cjs.map +1 -1
- package/dist/mcp/index.js +2 -2
- package/dist/mcp/index.js.map +1 -1
- package/dist/response/index.cjs +100 -15
- package/dist/response/index.cjs.map +1 -1
- package/dist/response/index.d.cts +2 -2
- package/dist/response/index.d.ts +2 -2
- package/dist/response/index.js +99 -14
- package/dist/response/index.js.map +1 -1
- package/dist/sources/index.cjs +30 -1
- package/dist/sources/index.cjs.map +1 -1
- package/dist/sources/index.js +30 -1
- package/dist/sources/index.js.map +1 -1
- package/dist/streaming/index.cjs +213 -93
- package/dist/streaming/index.cjs.map +1 -1
- package/dist/streaming/index.d.cts +4 -3
- package/dist/streaming/index.d.ts +4 -3
- package/dist/streaming/index.js +183 -73
- package/dist/streaming/index.js.map +1 -1
- package/dist/{streaming-DfT22A0z.d.cts → streaming-BHPXnwwo.d.cts} +3 -1
- package/dist/{streaming-DbQxScpi.d.ts → streaming-C6mbU7My.d.ts} +3 -1
- package/package.json +17 -5
package/dist/mcp/index.cjs
CHANGED
|
@@ -91,7 +91,7 @@ function MCPToolCall({ call, isExpanded = false, onToggleExpand, className }) {
|
|
|
91
91
|
call.serverName && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-xs text-text-secondary truncate", children: call.serverName })
|
|
92
92
|
] }),
|
|
93
93
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
94
|
-
call.status === "running" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_core.
|
|
94
|
+
call.status === "running" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_core.WaveLoader, { size: "sm", color: "#38bdf8" }) }),
|
|
95
95
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
96
96
|
import_core.Badge,
|
|
97
97
|
{
|
package/dist/mcp/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/mcp/index.ts","../../src/mcp/MCPToolCall/MCPToolCall.tsx","../../src/mcp/MCPResourceView/MCPResourceView.tsx","../../src/mcp/MCPServerStatus/MCPServerStatus.tsx","../../src/mcp/MCPApprovalDialog/MCPApprovalDialog.tsx"],"sourcesContent":["export { MCPToolCall } from './MCPToolCall'\nexport type { MCPToolCallProps } from './MCPToolCall'\n\nexport { MCPResourceView } from './MCPResourceView'\nexport type { MCPResourceViewProps } from './MCPResourceView'\n\nexport { MCPServerStatus } from './MCPServerStatus'\nexport type { MCPServerStatusProps } from './MCPServerStatus'\n\nexport { MCPApprovalDialog } from './MCPApprovalDialog'\nexport type { MCPApprovalDialogProps } from './MCPApprovalDialog'\n","import React from 'react'\nimport { cva } from 'class-variance-authority'\nimport { twMerge } from 'tailwind-merge'\nimport { Badge, Spinner } from '@surf-kit/core'\nimport type { MCPToolCallData, MCPToolStatus } from '../../types/mcp'\n\nexport type MCPToolCallProps = {\n call: MCPToolCallData\n isExpanded?: boolean\n onToggleExpand?: () => void\n className?: string\n}\n\nconst statusBadgeIntent: Record<MCPToolStatus, 'default' | 'info' | 'success' | 'error'> = {\n pending: 'default',\n running: 'info',\n success: 'success',\n error: 'error',\n}\n\nconst statusLabel: Record<MCPToolStatus, string> = {\n pending: 'Pending',\n running: 'Running',\n success: 'Success',\n error: 'Error',\n}\n\nconst container = cva(\n 'rounded-lg border text-sm',\n {\n variants: {\n status: {\n pending: 'border-border bg-surface',\n running: 'border-status-info-subtle bg-status-info-subtle/30',\n success: 'border-status-success-subtle bg-status-success-subtle/30',\n error: 'border-status-error-subtle bg-status-error-subtle/30',\n },\n },\n defaultVariants: { status: 'pending' },\n },\n)\n\nfunction formatDuration(start?: Date, end?: Date): string | null {\n if (!start || !end) return null\n const ms = end.getTime() - start.getTime()\n if (ms < 1000) return `${ms}ms`\n return `${(ms / 1000).toFixed(1)}s`\n}\n\nfunction formatValue(value: unknown): string {\n if (typeof value === 'string') return value\n return JSON.stringify(value, null, 2)\n}\n\nfunction MCPToolCall({ call, isExpanded = false, onToggleExpand, className }: MCPToolCallProps) {\n const duration = formatDuration(call.startedAt, call.completedAt)\n\n return (\n <div\n className={twMerge(container({ status: call.status }), className)}\n data-testid=\"mcp-tool-call\"\n >\n {/* Header */}\n <button\n type=\"button\"\n className=\"flex w-full items-center justify-between gap-2 px-3 py-2\"\n onClick={onToggleExpand}\n aria-expanded={isExpanded}\n data-testid=\"mcp-tool-call-header\"\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <span className=\"font-medium text-text-primary truncate\" data-testid=\"mcp-tool-name\">\n {call.name}\n </span>\n {call.serverName && (\n <span className=\"text-xs text-text-secondary truncate\">\n {call.serverName}\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-2 shrink-0\">\n {call.status === 'running' && (\n <span aria-hidden=\"true\">\n <Spinner size=\"sm\" />\n </span>\n )}\n <Badge\n intent={statusBadgeIntent[call.status]}\n size=\"sm\"\n role=\"status\"\n aria-label={`Status: ${statusLabel[call.status]}`}\n data-testid=\"mcp-tool-status\"\n >\n {statusLabel[call.status]}\n </Badge>\n {duration && (\n <span className=\"text-xs text-text-secondary\" data-testid=\"mcp-tool-duration\">\n {duration}\n </span>\n )}\n <svg\n className={`h-4 w-4 text-text-secondary transition-transform ${isExpanded ? 'rotate-180' : ''}`}\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </div>\n </button>\n\n {/* Expandable body */}\n {isExpanded && (\n <div className=\"border-t border-inherit px-3 py-2 space-y-3\" data-testid=\"mcp-tool-call-body\">\n {/* Arguments */}\n {Object.keys(call.arguments).length > 0 && (\n <div>\n <h4 className=\"text-xs font-medium text-text-secondary mb-1\">Arguments</h4>\n <dl className=\"space-y-1\" data-testid=\"mcp-tool-arguments\">\n {Object.entries(call.arguments).map(([key, value]) => (\n <div key={key} className=\"flex gap-2\">\n <dt className=\"text-xs font-mono text-text-secondary shrink-0\">{key}:</dt>\n <dd className=\"text-xs font-mono text-text-primary break-all\">\n {formatValue(value)}\n </dd>\n </div>\n ))}\n </dl>\n </div>\n )}\n\n {/* Result */}\n {call.result !== undefined && (\n <div>\n <h4 className=\"text-xs font-medium text-text-secondary mb-1\">Result</h4>\n <pre\n className=\"text-xs font-mono text-text-primary bg-surface-sunken rounded p-2 overflow-x-auto whitespace-pre-wrap\"\n data-testid=\"mcp-tool-result\"\n >\n {typeof call.result === 'string' ? call.result : JSON.stringify(call.result, null, 2)}\n </pre>\n </div>\n )}\n\n {/* Error */}\n {call.error && (\n <div>\n <h4 className=\"text-xs font-medium text-status-error mb-1\">Error</h4>\n <p\n className=\"text-xs text-status-error bg-status-error-subtle/30 rounded p-2\"\n data-testid=\"mcp-tool-error\"\n >\n {call.error}\n </p>\n </div>\n )}\n </div>\n )}\n </div>\n )\n}\n\nexport { MCPToolCall }\n","import React from 'react'\nimport { twMerge } from 'tailwind-merge'\nimport type { MCPResource } from '../../types/mcp'\n\nexport type MCPResourceViewProps = {\n resource: MCPResource\n className?: string\n}\n\nfunction isImageMime(mime?: string): boolean {\n return !!mime && mime.startsWith('image/')\n}\n\nfunction isTextMime(mime?: string): boolean {\n if (!mime) return true\n return (\n mime.startsWith('text/') ||\n mime === 'application/json' ||\n mime === 'application/xml' ||\n mime === 'application/javascript' ||\n mime === 'application/typescript'\n )\n}\n\nfunction isUrlContent(content?: string | Uint8Array): boolean {\n if (typeof content !== 'string') return false\n return /^https?:\\/\\//.test(content.trim())\n}\n\nfunction MCPResourceView({ resource, className }: MCPResourceViewProps) {\n const { uri, name, mimeType, description, content } = resource\n\n return (\n <div\n className={twMerge('rounded-lg border border-border bg-surface p-3 text-sm', className)}\n data-testid=\"mcp-resource-view\"\n >\n {/* Header */}\n <div className=\"mb-2\">\n <span className=\"font-medium text-text-primary\" data-testid=\"mcp-resource-name\">\n {name}\n </span>\n <span\n className=\"ml-2 text-xs text-text-secondary font-mono truncate\"\n data-testid=\"mcp-resource-uri\"\n >\n {uri}\n </span>\n </div>\n\n {description && (\n <p className=\"text-xs text-text-secondary mb-2\" data-testid=\"mcp-resource-description\">\n {description}\n </p>\n )}\n\n {/* Content rendering */}\n {content !== undefined && (\n <div data-testid=\"mcp-resource-content\">\n {isImageMime(mimeType) && typeof content === 'string' ? (\n <img\n src={content}\n alt={name}\n className=\"max-w-full rounded\"\n data-testid=\"mcp-resource-image\"\n />\n ) : isUrlContent(content) ? (\n <a\n href={typeof content === 'string' ? content.trim() : undefined}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm text-interactive-primary hover:underline break-all\"\n data-testid=\"mcp-resource-link\"\n >\n {typeof content === 'string' ? content.trim() : ''}\n </a>\n ) : isTextMime(mimeType) ? (\n <pre\n className=\"text-xs font-mono text-text-primary bg-surface-sunken rounded p-2 overflow-x-auto whitespace-pre-wrap\"\n data-testid=\"mcp-resource-code\"\n >\n {typeof content === 'string' ? content : '[Binary data]'}\n </pre>\n ) : (\n <p className=\"text-xs text-text-secondary italic\">\n Unsupported content type: {mimeType}\n </p>\n )}\n </div>\n )}\n </div>\n )\n}\n\nexport { MCPResourceView }\n","'use client'\n\nimport React, { useState } from 'react'\nimport { cva } from 'class-variance-authority'\nimport { twMerge } from 'tailwind-merge'\nimport type { MCPServerInfo } from '../../types/mcp'\n\nexport type MCPServerStatusProps = {\n server: MCPServerInfo\n className?: string\n}\n\nconst statusDot = cva('inline-block h-2 w-2 rounded-full shrink-0', {\n variants: {\n status: {\n connected: 'bg-status-success',\n disconnected: 'bg-neutral-400',\n error: 'bg-status-error',\n },\n },\n defaultVariants: { status: 'disconnected' },\n})\n\nconst statusLabel: Record<MCPServerInfo['status'], string> = {\n connected: 'Connected',\n disconnected: 'Disconnected',\n error: 'Error',\n}\n\nfunction formatLastPing(date?: Date): string | null {\n if (!date) return null\n return date.toLocaleTimeString()\n}\n\nfunction MCPServerStatus({ server, className }: MCPServerStatusProps) {\n const [showTools, setShowTools] = useState(false)\n const [showResources, setShowResources] = useState(false)\n const lastPing = formatLastPing(server.lastPing)\n\n return (\n <div\n className={twMerge('rounded-lg border border-border bg-surface p-3 text-sm', className)}\n data-testid=\"mcp-server-status\"\n >\n {/* Header */}\n <div className=\"flex items-center gap-2 mb-1\">\n <span\n className={statusDot({ status: server.status })}\n role=\"status\"\n aria-label={statusLabel[server.status]}\n data-testid=\"mcp-server-status-dot\"\n />\n <span className=\"font-medium text-text-primary\" data-testid=\"mcp-server-name\">\n {server.name}\n </span>\n {server.version && (\n <span className=\"text-xs text-text-secondary\" data-testid=\"mcp-server-version\">\n v{server.version}\n </span>\n )}\n </div>\n\n {lastPing && (\n <p className=\"text-xs text-text-secondary ml-4 mb-2\" data-testid=\"mcp-server-last-ping\">\n Last ping: {lastPing}\n </p>\n )}\n\n {/* Tools list */}\n {server.tools.length > 0 && (\n <div className=\"mt-2\">\n <button\n type=\"button\"\n className=\"flex items-center gap-1 text-xs font-medium text-text-secondary hover:text-text-primary w-full\"\n onClick={() => setShowTools((prev) => !prev)}\n aria-expanded={showTools}\n data-testid=\"mcp-server-tools-toggle\"\n >\n <svg\n className={`h-3 w-3 transition-transform ${showTools ? 'rotate-90' : ''}`}\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z\"\n clipRule=\"evenodd\"\n />\n </svg>\n Tools ({server.tools.length})\n </button>\n {showTools && (\n <ul className=\"mt-1 ml-4 space-y-1\" data-testid=\"mcp-server-tools-list\">\n {server.tools.map((tool) => (\n <li key={tool.name} className=\"text-xs text-text-primary\">\n <span className=\"font-mono\">{tool.name}</span>\n {tool.description && (\n <span className=\"text-text-secondary ml-1\">— {tool.description}</span>\n )}\n </li>\n ))}\n </ul>\n )}\n </div>\n )}\n\n {/* Resources list */}\n {server.resources.length > 0 && (\n <div className=\"mt-2\">\n <button\n type=\"button\"\n className=\"flex items-center gap-1 text-xs font-medium text-text-secondary hover:text-text-primary w-full\"\n onClick={() => setShowResources((prev) => !prev)}\n aria-expanded={showResources}\n data-testid=\"mcp-server-resources-toggle\"\n >\n <svg\n className={`h-3 w-3 transition-transform ${showResources ? 'rotate-90' : ''}`}\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z\"\n clipRule=\"evenodd\"\n />\n </svg>\n Resources ({server.resources.length})\n </button>\n {showResources && (\n <ul className=\"mt-1 ml-4 space-y-1\" data-testid=\"mcp-server-resources-list\">\n {server.resources.map((res) => (\n <li key={res.uri} className=\"text-xs text-text-primary\">\n <span className=\"font-mono\">{res.name}</span>\n <span className=\"text-text-secondary ml-1\">({res.uri})</span>\n </li>\n ))}\n </ul>\n )}\n </div>\n )}\n </div>\n )\n}\n\nexport { MCPServerStatus }\n","'use client'\n\nimport React, { useRef, useEffect } from 'react'\nimport { cva } from 'class-variance-authority'\nimport { twMerge } from 'tailwind-merge'\nimport { useDialog, FocusScope } from 'react-aria'\nimport { Button, Badge } from '@surf-kit/core'\nimport type { MCPToolCallData } from '../../types/mcp'\n\nexport type MCPApprovalDialogProps = {\n call: MCPToolCallData\n riskLevel?: 'low' | 'medium' | 'high'\n onApprove: () => void\n onDeny: () => void\n isOpen: boolean\n className?: string\n}\n\nconst riskBadgeIntent: Record<string, 'success' | 'warning' | 'error'> = {\n low: 'success',\n medium: 'warning',\n high: 'error',\n}\n\nconst riskLabel: Record<string, string> = {\n low: 'Low Risk',\n medium: 'Medium Risk',\n high: 'High Risk',\n}\n\nconst riskBorder = cva('relative bg-surface rounded-xl shadow-xl border p-6 outline-none w-full max-w-lg', {\n variants: {\n risk: {\n low: 'border-status-success-subtle',\n medium: 'border-status-warning-subtle',\n high: 'border-status-error-subtle',\n },\n },\n defaultVariants: { risk: 'low' },\n})\n\nfunction formatValue(value: unknown): string {\n if (typeof value === 'string') return value\n return JSON.stringify(value, null, 2)\n}\n\nfunction MCPApprovalDialog({\n call,\n riskLevel = 'low',\n onApprove,\n onDeny,\n isOpen,\n className,\n}: MCPApprovalDialogProps) {\n const ref = useRef<HTMLDivElement>(null)\n const { dialogProps, titleProps } = useDialog({ role: 'alertdialog' }, ref)\n\n // Block Escape key — user must explicitly approve or deny\n useEffect(() => {\n if (!isOpen) return\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault()\n e.stopPropagation()\n }\n }\n document.addEventListener('keydown', handleKeyDown, true)\n return () => document.removeEventListener('keydown', handleKeyDown, true)\n }, [isOpen])\n\n if (!isOpen) return null\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50\"\n data-testid=\"mcp-approval-overlay\"\n >\n <FocusScope contain restoreFocus autoFocus>\n <div\n {...dialogProps}\n ref={ref}\n className={twMerge(riskBorder({ risk: riskLevel }), className)}\n data-testid=\"mcp-approval-dialog\"\n >\n {/* Title */}\n <div className=\"flex items-center justify-between mb-4\">\n <h2\n {...titleProps}\n className=\"text-lg font-semibold text-text-primary\"\n data-testid=\"mcp-approval-title\"\n >\n Tool Approval Required\n </h2>\n <Badge\n intent={riskBadgeIntent[riskLevel]}\n size=\"sm\"\n data-testid=\"mcp-approval-risk-badge\"\n >\n {riskLabel[riskLevel]}\n </Badge>\n </div>\n\n {/* Tool info */}\n <div className=\"space-y-3 text-sm\">\n <div>\n <h3 className=\"text-xs font-medium text-text-secondary mb-1\">Tool</h3>\n <p className=\"font-mono text-text-primary\" data-testid=\"mcp-approval-tool-name\">\n {call.name}\n </p>\n {call.serverName && (\n <p className=\"text-xs text-text-secondary mt-0.5\" data-testid=\"mcp-approval-server\">\n Server: {call.serverName}\n </p>\n )}\n </div>\n\n {/* Arguments */}\n {Object.keys(call.arguments).length > 0 && (\n <div>\n <h3 className=\"text-xs font-medium text-text-secondary mb-1\">Arguments</h3>\n <dl\n className=\"space-y-1 bg-neutral-100 rounded p-2\"\n data-testid=\"mcp-approval-arguments\"\n >\n {Object.entries(call.arguments).map(([key, value]) => (\n <div key={key} className=\"flex gap-2\">\n <dt className=\"text-xs font-mono text-text-secondary shrink-0\">{key}:</dt>\n <dd className=\"text-xs font-mono text-text-primary break-all\">\n {formatValue(value)}\n </dd>\n </div>\n ))}\n </dl>\n </div>\n )}\n </div>\n\n {/* Actions */}\n <div className=\"mt-6 flex justify-end gap-3\">\n <Button\n intent=\"secondary\"\n onPress={onDeny}\n aria-label=\"Deny tool execution\"\n >\n Deny\n </Button>\n <Button\n intent=\"primary\"\n onPress={onApprove}\n aria-label=\"Approve tool execution\"\n >\n Approve\n </Button>\n </div>\n </div>\n </FocusScope>\n </div>\n )\n}\n\nexport { MCPApprovalDialog }\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,sCAAoB;AACpB,4BAAwB;AACxB,kBAA+B;AAmEvB;AAzDR,IAAM,oBAAqF;AAAA,EACzF,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,OAAO;AACT;AAEA,IAAM,cAA6C;AAAA,EACjD,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,OAAO;AACT;AAEA,IAAM,gBAAY;AAAA,EAChB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,QAAQ;AAAA,QACN,SAAS;AAAA,QACT,SAAS;AAAA,QACT,SAAS;AAAA,QACT,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,iBAAiB,EAAE,QAAQ,UAAU;AAAA,EACvC;AACF;AAEA,SAAS,eAAe,OAAc,KAA2B;AAC/D,MAAI,CAAC,SAAS,CAAC,IAAK,QAAO;AAC3B,QAAM,KAAK,IAAI,QAAQ,IAAI,MAAM,QAAQ;AACzC,MAAI,KAAK,IAAM,QAAO,GAAG,EAAE;AAC3B,SAAO,IAAI,KAAK,KAAM,QAAQ,CAAC,CAAC;AAClC;AAEA,SAAS,YAAY,OAAwB;AAC3C,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,SAAO,KAAK,UAAU,OAAO,MAAM,CAAC;AACtC;AAEA,SAAS,YAAY,EAAE,MAAM,aAAa,OAAO,gBAAgB,UAAU,GAAqB;AAC9F,QAAM,WAAW,eAAe,KAAK,WAAW,KAAK,WAAW;AAEhE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAW,+BAAQ,UAAU,EAAE,QAAQ,KAAK,OAAO,CAAC,GAAG,SAAS;AAAA,MAChE,eAAY;AAAA,MAGZ;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,WAAU;AAAA,YACV,SAAS;AAAA,YACT,iBAAe;AAAA,YACf,eAAY;AAAA,YAEZ;AAAA,2DAAC,SAAI,WAAU,mCACb;AAAA,4DAAC,UAAK,WAAU,0CAAyC,eAAY,iBAClE,eAAK,MACR;AAAA,gBACC,KAAK,cACJ,4CAAC,UAAK,WAAU,wCACb,eAAK,YACR;AAAA,iBAEJ;AAAA,cACA,6CAAC,SAAI,WAAU,oCACZ;AAAA,qBAAK,WAAW,aACf,4CAAC,UAAK,eAAY,QAChB,sDAAC,uBAAQ,MAAK,MAAK,GACrB;AAAA,gBAEF;AAAA,kBAAC;AAAA;AAAA,oBACC,QAAQ,kBAAkB,KAAK,MAAM;AAAA,oBACrC,MAAK;AAAA,oBACL,MAAK;AAAA,oBACL,cAAY,WAAW,YAAY,KAAK,MAAM,CAAC;AAAA,oBAC/C,eAAY;AAAA,oBAEX,sBAAY,KAAK,MAAM;AAAA;AAAA,gBAC1B;AAAA,gBACC,YACC,4CAAC,UAAK,WAAU,+BAA8B,eAAY,qBACvD,oBACH;AAAA,gBAEF;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAW,oDAAoD,aAAa,eAAe,EAAE;AAAA,oBAC7F,SAAQ;AAAA,oBACR,MAAK;AAAA,oBACL,eAAY;AAAA,oBAEZ;AAAA,sBAAC;AAAA;AAAA,wBACC,UAAS;AAAA,wBACT,GAAE;AAAA,wBACF,UAAS;AAAA;AAAA,oBACX;AAAA;AAAA,gBACF;AAAA,iBACF;AAAA;AAAA;AAAA,QACF;AAAA,QAGC,cACC,6CAAC,SAAI,WAAU,+CAA8C,eAAY,sBAEtE;AAAA,iBAAO,KAAK,KAAK,SAAS,EAAE,SAAS,KACpC,6CAAC,SACC;AAAA,wDAAC,QAAG,WAAU,gDAA+C,uBAAS;AAAA,YACtE,4CAAC,QAAG,WAAU,aAAY,eAAY,sBACnC,iBAAO,QAAQ,KAAK,SAAS,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAC9C,6CAAC,SAAc,WAAU,cACvB;AAAA,2DAAC,QAAG,WAAU,kDAAkD;AAAA;AAAA,gBAAI;AAAA,iBAAC;AAAA,cACrE,4CAAC,QAAG,WAAU,iDACX,sBAAY,KAAK,GACpB;AAAA,iBAJQ,GAKV,CACD,GACH;AAAA,aACF;AAAA,UAID,KAAK,WAAW,UACf,6CAAC,SACC;AAAA,wDAAC,QAAG,WAAU,gDAA+C,oBAAM;AAAA,YACnE;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,eAAY;AAAA,gBAEX,iBAAO,KAAK,WAAW,WAAW,KAAK,SAAS,KAAK,UAAU,KAAK,QAAQ,MAAM,CAAC;AAAA;AAAA,YACtF;AAAA,aACF;AAAA,UAID,KAAK,SACJ,6CAAC,SACC;AAAA,wDAAC,QAAG,WAAU,8CAA6C,mBAAK;AAAA,YAChE;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,eAAY;AAAA,gBAEX,eAAK;AAAA;AAAA,YACR;AAAA,aACF;AAAA,WAEJ;AAAA;AAAA;AAAA,EAEJ;AAEJ;;;ACnKA,IAAAA,yBAAwB;AAqClB,IAAAC,sBAAA;AA7BN,SAAS,YAAY,MAAwB;AAC3C,SAAO,CAAC,CAAC,QAAQ,KAAK,WAAW,QAAQ;AAC3C;AAEA,SAAS,WAAW,MAAwB;AAC1C,MAAI,CAAC,KAAM,QAAO;AAClB,SACE,KAAK,WAAW,OAAO,KACvB,SAAS,sBACT,SAAS,qBACT,SAAS,4BACT,SAAS;AAEb;AAEA,SAAS,aAAa,SAAwC;AAC5D,MAAI,OAAO,YAAY,SAAU,QAAO;AACxC,SAAO,eAAe,KAAK,QAAQ,KAAK,CAAC;AAC3C;AAEA,SAAS,gBAAgB,EAAE,UAAU,UAAU,GAAyB;AACtE,QAAM,EAAE,KAAK,MAAM,UAAU,aAAa,QAAQ,IAAI;AAEtD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAW,gCAAQ,0DAA0D,SAAS;AAAA,MACtF,eAAY;AAAA,MAGZ;AAAA,sDAAC,SAAI,WAAU,QACb;AAAA,uDAAC,UAAK,WAAU,iCAAgC,eAAY,qBACzD,gBACH;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,eAAY;AAAA,cAEX;AAAA;AAAA,UACH;AAAA,WACF;AAAA,QAEC,eACC,6CAAC,OAAE,WAAU,oCAAmC,eAAY,4BACzD,uBACH;AAAA,QAID,YAAY,UACX,6CAAC,SAAI,eAAY,wBACd,sBAAY,QAAQ,KAAK,OAAO,YAAY,WAC3C;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,KAAK;AAAA,YACL,WAAU;AAAA,YACV,eAAY;AAAA;AAAA,QACd,IACE,aAAa,OAAO,IACtB;AAAA,UAAC;AAAA;AAAA,YACC,MAAM,OAAO,YAAY,WAAW,QAAQ,KAAK,IAAI;AAAA,YACrD,QAAO;AAAA,YACP,KAAI;AAAA,YACJ,WAAU;AAAA,YACV,eAAY;AAAA,YAEX,iBAAO,YAAY,WAAW,QAAQ,KAAK,IAAI;AAAA;AAAA,QAClD,IACE,WAAW,QAAQ,IACrB;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,eAAY;AAAA,YAEX,iBAAO,YAAY,WAAW,UAAU;AAAA;AAAA,QAC3C,IAEA,8CAAC,OAAE,WAAU,sCAAqC;AAAA;AAAA,UACrB;AAAA,WAC7B,GAEJ;AAAA;AAAA;AAAA,EAEJ;AAEJ;;;AC1FA,mBAAgC;AAChC,IAAAC,mCAAoB;AACpB,IAAAC,yBAAwB;AA0ChB,IAAAC,sBAAA;AAlCR,IAAM,gBAAY,sCAAI,8CAA8C;AAAA,EAClE,UAAU;AAAA,IACR,QAAQ;AAAA,MACN,WAAW;AAAA,MACX,cAAc;AAAA,MACd,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,iBAAiB,EAAE,QAAQ,eAAe;AAC5C,CAAC;AAED,IAAMC,eAAuD;AAAA,EAC3D,WAAW;AAAA,EACX,cAAc;AAAA,EACd,OAAO;AACT;AAEA,SAAS,eAAe,MAA4B;AAClD,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,KAAK,mBAAmB;AACjC;AAEA,SAAS,gBAAgB,EAAE,QAAQ,UAAU,GAAyB;AACpE,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAS,KAAK;AAChD,QAAM,CAAC,eAAe,gBAAgB,QAAI,uBAAS,KAAK;AACxD,QAAM,WAAW,eAAe,OAAO,QAAQ;AAE/C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAW,gCAAQ,0DAA0D,SAAS;AAAA,MACtF,eAAY;AAAA,MAGZ;AAAA,sDAAC,SAAI,WAAU,gCACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,UAAU,EAAE,QAAQ,OAAO,OAAO,CAAC;AAAA,cAC9C,MAAK;AAAA,cACL,cAAYA,aAAY,OAAO,MAAM;AAAA,cACrC,eAAY;AAAA;AAAA,UACd;AAAA,UACA,6CAAC,UAAK,WAAU,iCAAgC,eAAY,mBACzD,iBAAO,MACV;AAAA,UACC,OAAO,WACN,8CAAC,UAAK,WAAU,+BAA8B,eAAY,sBAAqB;AAAA;AAAA,YAC3E,OAAO;AAAA,aACX;AAAA,WAEJ;AAAA,QAEC,YACC,8CAAC,OAAE,WAAU,yCAAwC,eAAY,wBAAuB;AAAA;AAAA,UAC1E;AAAA,WACd;AAAA,QAID,OAAO,MAAM,SAAS,KACrB,8CAAC,SAAI,WAAU,QACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,WAAU;AAAA,cACV,SAAS,MAAM,aAAa,CAAC,SAAS,CAAC,IAAI;AAAA,cAC3C,iBAAe;AAAA,cACf,eAAY;AAAA,cAEZ;AAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAW,gCAAgC,YAAY,cAAc,EAAE;AAAA,oBACvE,SAAQ;AAAA,oBACR,MAAK;AAAA,oBACL,eAAY;AAAA,oBAEZ;AAAA,sBAAC;AAAA;AAAA,wBACC,UAAS;AAAA,wBACT,GAAE;AAAA,wBACF,UAAS;AAAA;AAAA,oBACX;AAAA;AAAA,gBACF;AAAA,gBAAM;AAAA,gBACE,OAAO,MAAM;AAAA,gBAAO;AAAA;AAAA;AAAA,UAC9B;AAAA,UACC,aACC,6CAAC,QAAG,WAAU,uBAAsB,eAAY,yBAC7C,iBAAO,MAAM,IAAI,CAAC,SACjB,8CAAC,QAAmB,WAAU,6BAC5B;AAAA,yDAAC,UAAK,WAAU,aAAa,eAAK,MAAK;AAAA,YACtC,KAAK,eACJ,8CAAC,UAAK,WAAU,4BAA2B;AAAA;AAAA,cAAG,KAAK;AAAA,eAAY;AAAA,eAH1D,KAAK,IAKd,CACD,GACH;AAAA,WAEJ;AAAA,QAID,OAAO,UAAU,SAAS,KACzB,8CAAC,SAAI,WAAU,QACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,WAAU;AAAA,cACV,SAAS,MAAM,iBAAiB,CAAC,SAAS,CAAC,IAAI;AAAA,cAC/C,iBAAe;AAAA,cACf,eAAY;AAAA,cAEZ;AAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAW,gCAAgC,gBAAgB,cAAc,EAAE;AAAA,oBAC3E,SAAQ;AAAA,oBACR,MAAK;AAAA,oBACL,eAAY;AAAA,oBAEZ;AAAA,sBAAC;AAAA;AAAA,wBACC,UAAS;AAAA,wBACT,GAAE;AAAA,wBACF,UAAS;AAAA;AAAA,oBACX;AAAA;AAAA,gBACF;AAAA,gBAAM;AAAA,gBACM,OAAO,UAAU;AAAA,gBAAO;AAAA;AAAA;AAAA,UACtC;AAAA,UACC,iBACC,6CAAC,QAAG,WAAU,uBAAsB,eAAY,6BAC7C,iBAAO,UAAU,IAAI,CAAC,QACrB,8CAAC,QAAiB,WAAU,6BAC1B;AAAA,yDAAC,UAAK,WAAU,aAAa,cAAI,MAAK;AAAA,YACtC,8CAAC,UAAK,WAAU,4BAA2B;AAAA;AAAA,cAAE,IAAI;AAAA,cAAI;AAAA,eAAC;AAAA,eAF/C,IAAI,GAGb,CACD,GACH;AAAA,WAEJ;AAAA;AAAA;AAAA,EAEJ;AAEJ;;;AC/IA,IAAAC,gBAAyC;AACzC,IAAAC,mCAAoB;AACpB,IAAAC,yBAAwB;AACxB,wBAAsC;AACtC,IAAAC,eAA8B;AA+EpB,IAAAC,sBAAA;AAnEV,IAAM,kBAAmE;AAAA,EACvE,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,MAAM;AACR;AAEA,IAAM,YAAoC;AAAA,EACxC,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,MAAM;AACR;AAEA,IAAM,iBAAa,sCAAI,oFAAoF;AAAA,EACzG,UAAU;AAAA,IACR,MAAM;AAAA,MACJ,KAAK;AAAA,MACL,QAAQ;AAAA,MACR,MAAM;AAAA,IACR;AAAA,EACF;AAAA,EACA,iBAAiB,EAAE,MAAM,MAAM;AACjC,CAAC;AAED,SAASC,aAAY,OAAwB;AAC3C,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,SAAO,KAAK,UAAU,OAAO,MAAM,CAAC;AACtC;AAEA,SAAS,kBAAkB;AAAA,EACzB;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA2B;AACzB,QAAM,UAAM,sBAAuB,IAAI;AACvC,QAAM,EAAE,aAAa,WAAW,QAAI,6BAAU,EAAE,MAAM,cAAc,GAAG,GAAG;AAG1E,+BAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,UAAM,gBAAgB,CAAC,MAAqB;AAC1C,UAAI,EAAE,QAAQ,UAAU;AACtB,UAAE,eAAe;AACjB,UAAE,gBAAgB;AAAA,MACpB;AAAA,IACF;AACA,aAAS,iBAAiB,WAAW,eAAe,IAAI;AACxD,WAAO,MAAM,SAAS,oBAAoB,WAAW,eAAe,IAAI;AAAA,EAC1E,GAAG,CAAC,MAAM,CAAC;AAEX,MAAI,CAAC,OAAQ,QAAO;AAEpB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,eAAY;AAAA,MAEZ,uDAAC,gCAAW,SAAO,MAAC,cAAY,MAAC,WAAS,MACxC;AAAA,QAAC;AAAA;AAAA,UACE,GAAG;AAAA,UACJ;AAAA,UACA,eAAW,gCAAQ,WAAW,EAAE,MAAM,UAAU,CAAC,GAAG,SAAS;AAAA,UAC7D,eAAY;AAAA,UAGZ;AAAA,0DAAC,SAAI,WAAU,0CACb;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACE,GAAG;AAAA,kBACJ,WAAU;AAAA,kBACV,eAAY;AAAA,kBACb;AAAA;AAAA,cAED;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC,QAAQ,gBAAgB,SAAS;AAAA,kBACjC,MAAK;AAAA,kBACL,eAAY;AAAA,kBAEX,oBAAU,SAAS;AAAA;AAAA,cACtB;AAAA,eACF;AAAA,YAGA,8CAAC,SAAI,WAAU,qBACb;AAAA,4DAAC,SACC;AAAA,6DAAC,QAAG,WAAU,gDAA+C,kBAAI;AAAA,gBACjE,6CAAC,OAAE,WAAU,+BAA8B,eAAY,0BACpD,eAAK,MACR;AAAA,gBACC,KAAK,cACJ,8CAAC,OAAE,WAAU,sCAAqC,eAAY,uBAAsB;AAAA;AAAA,kBACzE,KAAK;AAAA,mBAChB;AAAA,iBAEJ;AAAA,cAGC,OAAO,KAAK,KAAK,SAAS,EAAE,SAAS,KACpC,8CAAC,SACC;AAAA,6DAAC,QAAG,WAAU,gDAA+C,uBAAS;AAAA,gBACtE;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAU;AAAA,oBACV,eAAY;AAAA,oBAEX,iBAAO,QAAQ,KAAK,SAAS,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAC9C,8CAAC,SAAc,WAAU,cACvB;AAAA,oEAAC,QAAG,WAAU,kDAAkD;AAAA;AAAA,wBAAI;AAAA,yBAAC;AAAA,sBACrE,6CAAC,QAAG,WAAU,iDACX,UAAAA,aAAY,KAAK,GACpB;AAAA,yBAJQ,GAKV,CACD;AAAA;AAAA,gBACH;AAAA,iBACF;AAAA,eAEJ;AAAA,YAGA,8CAAC,SAAI,WAAU,+BACb;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,QAAO;AAAA,kBACP,SAAS;AAAA,kBACT,cAAW;AAAA,kBACZ;AAAA;AAAA,cAED;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC,QAAO;AAAA,kBACP,SAAS;AAAA,kBACT,cAAW;AAAA,kBACZ;AAAA;AAAA,cAED;AAAA,eACF;AAAA;AAAA;AAAA,MACF,GACF;AAAA;AAAA,EACF;AAEJ;","names":["import_tailwind_merge","import_jsx_runtime","import_class_variance_authority","import_tailwind_merge","import_jsx_runtime","statusLabel","import_react","import_class_variance_authority","import_tailwind_merge","import_core","import_jsx_runtime","formatValue"]}
|
|
1
|
+
{"version":3,"sources":["../../src/mcp/index.ts","../../src/mcp/MCPToolCall/MCPToolCall.tsx","../../src/mcp/MCPResourceView/MCPResourceView.tsx","../../src/mcp/MCPServerStatus/MCPServerStatus.tsx","../../src/mcp/MCPApprovalDialog/MCPApprovalDialog.tsx"],"sourcesContent":["export { MCPToolCall } from './MCPToolCall'\nexport type { MCPToolCallProps } from './MCPToolCall'\n\nexport { MCPResourceView } from './MCPResourceView'\nexport type { MCPResourceViewProps } from './MCPResourceView'\n\nexport { MCPServerStatus } from './MCPServerStatus'\nexport type { MCPServerStatusProps } from './MCPServerStatus'\n\nexport { MCPApprovalDialog } from './MCPApprovalDialog'\nexport type { MCPApprovalDialogProps } from './MCPApprovalDialog'\n","import React from 'react'\nimport { cva } from 'class-variance-authority'\nimport { twMerge } from 'tailwind-merge'\nimport { Badge, WaveLoader } from '@surf-kit/core'\nimport type { MCPToolCallData, MCPToolStatus } from '../../types/mcp'\n\nexport type MCPToolCallProps = {\n call: MCPToolCallData\n isExpanded?: boolean\n onToggleExpand?: () => void\n className?: string\n}\n\nconst statusBadgeIntent: Record<MCPToolStatus, 'default' | 'info' | 'success' | 'error'> = {\n pending: 'default',\n running: 'info',\n success: 'success',\n error: 'error',\n}\n\nconst statusLabel: Record<MCPToolStatus, string> = {\n pending: 'Pending',\n running: 'Running',\n success: 'Success',\n error: 'Error',\n}\n\nconst container = cva(\n 'rounded-lg border text-sm',\n {\n variants: {\n status: {\n pending: 'border-border bg-surface',\n running: 'border-status-info-subtle bg-status-info-subtle/30',\n success: 'border-status-success-subtle bg-status-success-subtle/30',\n error: 'border-status-error-subtle bg-status-error-subtle/30',\n },\n },\n defaultVariants: { status: 'pending' },\n },\n)\n\nfunction formatDuration(start?: Date, end?: Date): string | null {\n if (!start || !end) return null\n const ms = end.getTime() - start.getTime()\n if (ms < 1000) return `${ms}ms`\n return `${(ms / 1000).toFixed(1)}s`\n}\n\nfunction formatValue(value: unknown): string {\n if (typeof value === 'string') return value\n return JSON.stringify(value, null, 2)\n}\n\nfunction MCPToolCall({ call, isExpanded = false, onToggleExpand, className }: MCPToolCallProps) {\n const duration = formatDuration(call.startedAt, call.completedAt)\n\n return (\n <div\n className={twMerge(container({ status: call.status }), className)}\n data-testid=\"mcp-tool-call\"\n >\n {/* Header */}\n <button\n type=\"button\"\n className=\"flex w-full items-center justify-between gap-2 px-3 py-2\"\n onClick={onToggleExpand}\n aria-expanded={isExpanded}\n data-testid=\"mcp-tool-call-header\"\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <span className=\"font-medium text-text-primary truncate\" data-testid=\"mcp-tool-name\">\n {call.name}\n </span>\n {call.serverName && (\n <span className=\"text-xs text-text-secondary truncate\">\n {call.serverName}\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-2 shrink-0\">\n {call.status === 'running' && (\n <span aria-hidden=\"true\">\n <WaveLoader size=\"sm\" color=\"#38bdf8\" />\n </span>\n )}\n <Badge\n intent={statusBadgeIntent[call.status]}\n size=\"sm\"\n role=\"status\"\n aria-label={`Status: ${statusLabel[call.status]}`}\n data-testid=\"mcp-tool-status\"\n >\n {statusLabel[call.status]}\n </Badge>\n {duration && (\n <span className=\"text-xs text-text-secondary\" data-testid=\"mcp-tool-duration\">\n {duration}\n </span>\n )}\n <svg\n className={`h-4 w-4 text-text-secondary transition-transform ${isExpanded ? 'rotate-180' : ''}`}\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </div>\n </button>\n\n {/* Expandable body */}\n {isExpanded && (\n <div className=\"border-t border-inherit px-3 py-2 space-y-3\" data-testid=\"mcp-tool-call-body\">\n {/* Arguments */}\n {Object.keys(call.arguments).length > 0 && (\n <div>\n <h4 className=\"text-xs font-medium text-text-secondary mb-1\">Arguments</h4>\n <dl className=\"space-y-1\" data-testid=\"mcp-tool-arguments\">\n {Object.entries(call.arguments).map(([key, value]) => (\n <div key={key} className=\"flex gap-2\">\n <dt className=\"text-xs font-mono text-text-secondary shrink-0\">{key}:</dt>\n <dd className=\"text-xs font-mono text-text-primary break-all\">\n {formatValue(value)}\n </dd>\n </div>\n ))}\n </dl>\n </div>\n )}\n\n {/* Result */}\n {call.result !== undefined && (\n <div>\n <h4 className=\"text-xs font-medium text-text-secondary mb-1\">Result</h4>\n <pre\n className=\"text-xs font-mono text-text-primary bg-surface-sunken rounded p-2 overflow-x-auto whitespace-pre-wrap\"\n data-testid=\"mcp-tool-result\"\n >\n {typeof call.result === 'string' ? call.result : JSON.stringify(call.result, null, 2)}\n </pre>\n </div>\n )}\n\n {/* Error */}\n {call.error && (\n <div>\n <h4 className=\"text-xs font-medium text-status-error mb-1\">Error</h4>\n <p\n className=\"text-xs text-status-error bg-status-error-subtle/30 rounded p-2\"\n data-testid=\"mcp-tool-error\"\n >\n {call.error}\n </p>\n </div>\n )}\n </div>\n )}\n </div>\n )\n}\n\nexport { MCPToolCall }\n","import React from 'react'\nimport { twMerge } from 'tailwind-merge'\nimport type { MCPResource } from '../../types/mcp'\n\nexport type MCPResourceViewProps = {\n resource: MCPResource\n className?: string\n}\n\nfunction isImageMime(mime?: string): boolean {\n return !!mime && mime.startsWith('image/')\n}\n\nfunction isTextMime(mime?: string): boolean {\n if (!mime) return true\n return (\n mime.startsWith('text/') ||\n mime === 'application/json' ||\n mime === 'application/xml' ||\n mime === 'application/javascript' ||\n mime === 'application/typescript'\n )\n}\n\nfunction isUrlContent(content?: string | Uint8Array): boolean {\n if (typeof content !== 'string') return false\n return /^https?:\\/\\//.test(content.trim())\n}\n\nfunction MCPResourceView({ resource, className }: MCPResourceViewProps) {\n const { uri, name, mimeType, description, content } = resource\n\n return (\n <div\n className={twMerge('rounded-lg border border-border bg-surface p-3 text-sm', className)}\n data-testid=\"mcp-resource-view\"\n >\n {/* Header */}\n <div className=\"mb-2\">\n <span className=\"font-medium text-text-primary\" data-testid=\"mcp-resource-name\">\n {name}\n </span>\n <span\n className=\"ml-2 text-xs text-text-secondary font-mono truncate\"\n data-testid=\"mcp-resource-uri\"\n >\n {uri}\n </span>\n </div>\n\n {description && (\n <p className=\"text-xs text-text-secondary mb-2\" data-testid=\"mcp-resource-description\">\n {description}\n </p>\n )}\n\n {/* Content rendering */}\n {content !== undefined && (\n <div data-testid=\"mcp-resource-content\">\n {isImageMime(mimeType) && typeof content === 'string' ? (\n <img\n src={content}\n alt={name}\n className=\"max-w-full rounded\"\n data-testid=\"mcp-resource-image\"\n />\n ) : isUrlContent(content) ? (\n <a\n href={typeof content === 'string' ? content.trim() : undefined}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm text-interactive-primary hover:underline break-all\"\n data-testid=\"mcp-resource-link\"\n >\n {typeof content === 'string' ? content.trim() : ''}\n </a>\n ) : isTextMime(mimeType) ? (\n <pre\n className=\"text-xs font-mono text-text-primary bg-surface-sunken rounded p-2 overflow-x-auto whitespace-pre-wrap\"\n data-testid=\"mcp-resource-code\"\n >\n {typeof content === 'string' ? content : '[Binary data]'}\n </pre>\n ) : (\n <p className=\"text-xs text-text-secondary italic\">\n Unsupported content type: {mimeType}\n </p>\n )}\n </div>\n )}\n </div>\n )\n}\n\nexport { MCPResourceView }\n","'use client'\n\nimport React, { useState } from 'react'\nimport { cva } from 'class-variance-authority'\nimport { twMerge } from 'tailwind-merge'\nimport type { MCPServerInfo } from '../../types/mcp'\n\nexport type MCPServerStatusProps = {\n server: MCPServerInfo\n className?: string\n}\n\nconst statusDot = cva('inline-block h-2 w-2 rounded-full shrink-0', {\n variants: {\n status: {\n connected: 'bg-status-success',\n disconnected: 'bg-neutral-400',\n error: 'bg-status-error',\n },\n },\n defaultVariants: { status: 'disconnected' },\n})\n\nconst statusLabel: Record<MCPServerInfo['status'], string> = {\n connected: 'Connected',\n disconnected: 'Disconnected',\n error: 'Error',\n}\n\nfunction formatLastPing(date?: Date): string | null {\n if (!date) return null\n return date.toLocaleTimeString()\n}\n\nfunction MCPServerStatus({ server, className }: MCPServerStatusProps) {\n const [showTools, setShowTools] = useState(false)\n const [showResources, setShowResources] = useState(false)\n const lastPing = formatLastPing(server.lastPing)\n\n return (\n <div\n className={twMerge('rounded-lg border border-border bg-surface p-3 text-sm', className)}\n data-testid=\"mcp-server-status\"\n >\n {/* Header */}\n <div className=\"flex items-center gap-2 mb-1\">\n <span\n className={statusDot({ status: server.status })}\n role=\"status\"\n aria-label={statusLabel[server.status]}\n data-testid=\"mcp-server-status-dot\"\n />\n <span className=\"font-medium text-text-primary\" data-testid=\"mcp-server-name\">\n {server.name}\n </span>\n {server.version && (\n <span className=\"text-xs text-text-secondary\" data-testid=\"mcp-server-version\">\n v{server.version}\n </span>\n )}\n </div>\n\n {lastPing && (\n <p className=\"text-xs text-text-secondary ml-4 mb-2\" data-testid=\"mcp-server-last-ping\">\n Last ping: {lastPing}\n </p>\n )}\n\n {/* Tools list */}\n {server.tools.length > 0 && (\n <div className=\"mt-2\">\n <button\n type=\"button\"\n className=\"flex items-center gap-1 text-xs font-medium text-text-secondary hover:text-text-primary w-full\"\n onClick={() => setShowTools((prev) => !prev)}\n aria-expanded={showTools}\n data-testid=\"mcp-server-tools-toggle\"\n >\n <svg\n className={`h-3 w-3 transition-transform ${showTools ? 'rotate-90' : ''}`}\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z\"\n clipRule=\"evenodd\"\n />\n </svg>\n Tools ({server.tools.length})\n </button>\n {showTools && (\n <ul className=\"mt-1 ml-4 space-y-1\" data-testid=\"mcp-server-tools-list\">\n {server.tools.map((tool) => (\n <li key={tool.name} className=\"text-xs text-text-primary\">\n <span className=\"font-mono\">{tool.name}</span>\n {tool.description && (\n <span className=\"text-text-secondary ml-1\">— {tool.description}</span>\n )}\n </li>\n ))}\n </ul>\n )}\n </div>\n )}\n\n {/* Resources list */}\n {server.resources.length > 0 && (\n <div className=\"mt-2\">\n <button\n type=\"button\"\n className=\"flex items-center gap-1 text-xs font-medium text-text-secondary hover:text-text-primary w-full\"\n onClick={() => setShowResources((prev) => !prev)}\n aria-expanded={showResources}\n data-testid=\"mcp-server-resources-toggle\"\n >\n <svg\n className={`h-3 w-3 transition-transform ${showResources ? 'rotate-90' : ''}`}\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z\"\n clipRule=\"evenodd\"\n />\n </svg>\n Resources ({server.resources.length})\n </button>\n {showResources && (\n <ul className=\"mt-1 ml-4 space-y-1\" data-testid=\"mcp-server-resources-list\">\n {server.resources.map((res) => (\n <li key={res.uri} className=\"text-xs text-text-primary\">\n <span className=\"font-mono\">{res.name}</span>\n <span className=\"text-text-secondary ml-1\">({res.uri})</span>\n </li>\n ))}\n </ul>\n )}\n </div>\n )}\n </div>\n )\n}\n\nexport { MCPServerStatus }\n","'use client'\n\nimport React, { useRef, useEffect } from 'react'\nimport { cva } from 'class-variance-authority'\nimport { twMerge } from 'tailwind-merge'\nimport { useDialog, FocusScope } from 'react-aria'\nimport { Button, Badge } from '@surf-kit/core'\nimport type { MCPToolCallData } from '../../types/mcp'\n\nexport type MCPApprovalDialogProps = {\n call: MCPToolCallData\n riskLevel?: 'low' | 'medium' | 'high'\n onApprove: () => void\n onDeny: () => void\n isOpen: boolean\n className?: string\n}\n\nconst riskBadgeIntent: Record<string, 'success' | 'warning' | 'error'> = {\n low: 'success',\n medium: 'warning',\n high: 'error',\n}\n\nconst riskLabel: Record<string, string> = {\n low: 'Low Risk',\n medium: 'Medium Risk',\n high: 'High Risk',\n}\n\nconst riskBorder = cva('relative bg-surface rounded-xl shadow-xl border p-6 outline-none w-full max-w-lg', {\n variants: {\n risk: {\n low: 'border-status-success-subtle',\n medium: 'border-status-warning-subtle',\n high: 'border-status-error-subtle',\n },\n },\n defaultVariants: { risk: 'low' },\n})\n\nfunction formatValue(value: unknown): string {\n if (typeof value === 'string') return value\n return JSON.stringify(value, null, 2)\n}\n\nfunction MCPApprovalDialog({\n call,\n riskLevel = 'low',\n onApprove,\n onDeny,\n isOpen,\n className,\n}: MCPApprovalDialogProps) {\n const ref = useRef<HTMLDivElement>(null)\n const { dialogProps, titleProps } = useDialog({ role: 'alertdialog' }, ref)\n\n // Block Escape key — user must explicitly approve or deny\n useEffect(() => {\n if (!isOpen) return\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault()\n e.stopPropagation()\n }\n }\n document.addEventListener('keydown', handleKeyDown, true)\n return () => document.removeEventListener('keydown', handleKeyDown, true)\n }, [isOpen])\n\n if (!isOpen) return null\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50\"\n data-testid=\"mcp-approval-overlay\"\n >\n <FocusScope contain restoreFocus autoFocus>\n <div\n {...dialogProps}\n ref={ref}\n className={twMerge(riskBorder({ risk: riskLevel }), className)}\n data-testid=\"mcp-approval-dialog\"\n >\n {/* Title */}\n <div className=\"flex items-center justify-between mb-4\">\n <h2\n {...titleProps}\n className=\"text-lg font-semibold text-text-primary\"\n data-testid=\"mcp-approval-title\"\n >\n Tool Approval Required\n </h2>\n <Badge\n intent={riskBadgeIntent[riskLevel]}\n size=\"sm\"\n data-testid=\"mcp-approval-risk-badge\"\n >\n {riskLabel[riskLevel]}\n </Badge>\n </div>\n\n {/* Tool info */}\n <div className=\"space-y-3 text-sm\">\n <div>\n <h3 className=\"text-xs font-medium text-text-secondary mb-1\">Tool</h3>\n <p className=\"font-mono text-text-primary\" data-testid=\"mcp-approval-tool-name\">\n {call.name}\n </p>\n {call.serverName && (\n <p className=\"text-xs text-text-secondary mt-0.5\" data-testid=\"mcp-approval-server\">\n Server: {call.serverName}\n </p>\n )}\n </div>\n\n {/* Arguments */}\n {Object.keys(call.arguments).length > 0 && (\n <div>\n <h3 className=\"text-xs font-medium text-text-secondary mb-1\">Arguments</h3>\n <dl\n className=\"space-y-1 bg-neutral-100 rounded p-2\"\n data-testid=\"mcp-approval-arguments\"\n >\n {Object.entries(call.arguments).map(([key, value]) => (\n <div key={key} className=\"flex gap-2\">\n <dt className=\"text-xs font-mono text-text-secondary shrink-0\">{key}:</dt>\n <dd className=\"text-xs font-mono text-text-primary break-all\">\n {formatValue(value)}\n </dd>\n </div>\n ))}\n </dl>\n </div>\n )}\n </div>\n\n {/* Actions */}\n <div className=\"mt-6 flex justify-end gap-3\">\n <Button\n intent=\"secondary\"\n onPress={onDeny}\n aria-label=\"Deny tool execution\"\n >\n Deny\n </Button>\n <Button\n intent=\"primary\"\n onPress={onApprove}\n aria-label=\"Approve tool execution\"\n >\n Approve\n </Button>\n </div>\n </div>\n </FocusScope>\n </div>\n )\n}\n\nexport { MCPApprovalDialog }\n"],"mappings":"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","names":["import_tailwind_merge","import_jsx_runtime","import_class_variance_authority","import_tailwind_merge","import_jsx_runtime","statusLabel","import_react","import_class_variance_authority","import_tailwind_merge","import_core","import_jsx_runtime","formatValue"]}
|
package/dist/mcp/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// src/mcp/MCPToolCall/MCPToolCall.tsx
|
|
4
4
|
import { cva } from "class-variance-authority";
|
|
5
5
|
import { twMerge } from "tailwind-merge";
|
|
6
|
-
import { Badge,
|
|
6
|
+
import { Badge, WaveLoader } from "@surf-kit/core";
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
var statusBadgeIntent = {
|
|
9
9
|
pending: "default",
|
|
@@ -63,7 +63,7 @@ function MCPToolCall({ call, isExpanded = false, onToggleExpand, className }) {
|
|
|
63
63
|
call.serverName && /* @__PURE__ */ jsx("span", { className: "text-xs text-text-secondary truncate", children: call.serverName })
|
|
64
64
|
] }),
|
|
65
65
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
66
|
-
call.status === "running" && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: /* @__PURE__ */ jsx(
|
|
66
|
+
call.status === "running" && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: /* @__PURE__ */ jsx(WaveLoader, { size: "sm", color: "#38bdf8" }) }),
|
|
67
67
|
/* @__PURE__ */ jsx(
|
|
68
68
|
Badge,
|
|
69
69
|
{
|
package/dist/mcp/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/mcp/MCPToolCall/MCPToolCall.tsx","../../src/mcp/MCPResourceView/MCPResourceView.tsx","../../src/mcp/MCPServerStatus/MCPServerStatus.tsx","../../src/mcp/MCPApprovalDialog/MCPApprovalDialog.tsx"],"sourcesContent":["import React from 'react'\nimport { cva } from 'class-variance-authority'\nimport { twMerge } from 'tailwind-merge'\nimport { Badge, Spinner } from '@surf-kit/core'\nimport type { MCPToolCallData, MCPToolStatus } from '../../types/mcp'\n\nexport type MCPToolCallProps = {\n call: MCPToolCallData\n isExpanded?: boolean\n onToggleExpand?: () => void\n className?: string\n}\n\nconst statusBadgeIntent: Record<MCPToolStatus, 'default' | 'info' | 'success' | 'error'> = {\n pending: 'default',\n running: 'info',\n success: 'success',\n error: 'error',\n}\n\nconst statusLabel: Record<MCPToolStatus, string> = {\n pending: 'Pending',\n running: 'Running',\n success: 'Success',\n error: 'Error',\n}\n\nconst container = cva(\n 'rounded-lg border text-sm',\n {\n variants: {\n status: {\n pending: 'border-border bg-surface',\n running: 'border-status-info-subtle bg-status-info-subtle/30',\n success: 'border-status-success-subtle bg-status-success-subtle/30',\n error: 'border-status-error-subtle bg-status-error-subtle/30',\n },\n },\n defaultVariants: { status: 'pending' },\n },\n)\n\nfunction formatDuration(start?: Date, end?: Date): string | null {\n if (!start || !end) return null\n const ms = end.getTime() - start.getTime()\n if (ms < 1000) return `${ms}ms`\n return `${(ms / 1000).toFixed(1)}s`\n}\n\nfunction formatValue(value: unknown): string {\n if (typeof value === 'string') return value\n return JSON.stringify(value, null, 2)\n}\n\nfunction MCPToolCall({ call, isExpanded = false, onToggleExpand, className }: MCPToolCallProps) {\n const duration = formatDuration(call.startedAt, call.completedAt)\n\n return (\n <div\n className={twMerge(container({ status: call.status }), className)}\n data-testid=\"mcp-tool-call\"\n >\n {/* Header */}\n <button\n type=\"button\"\n className=\"flex w-full items-center justify-between gap-2 px-3 py-2\"\n onClick={onToggleExpand}\n aria-expanded={isExpanded}\n data-testid=\"mcp-tool-call-header\"\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <span className=\"font-medium text-text-primary truncate\" data-testid=\"mcp-tool-name\">\n {call.name}\n </span>\n {call.serverName && (\n <span className=\"text-xs text-text-secondary truncate\">\n {call.serverName}\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-2 shrink-0\">\n {call.status === 'running' && (\n <span aria-hidden=\"true\">\n <Spinner size=\"sm\" />\n </span>\n )}\n <Badge\n intent={statusBadgeIntent[call.status]}\n size=\"sm\"\n role=\"status\"\n aria-label={`Status: ${statusLabel[call.status]}`}\n data-testid=\"mcp-tool-status\"\n >\n {statusLabel[call.status]}\n </Badge>\n {duration && (\n <span className=\"text-xs text-text-secondary\" data-testid=\"mcp-tool-duration\">\n {duration}\n </span>\n )}\n <svg\n className={`h-4 w-4 text-text-secondary transition-transform ${isExpanded ? 'rotate-180' : ''}`}\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </div>\n </button>\n\n {/* Expandable body */}\n {isExpanded && (\n <div className=\"border-t border-inherit px-3 py-2 space-y-3\" data-testid=\"mcp-tool-call-body\">\n {/* Arguments */}\n {Object.keys(call.arguments).length > 0 && (\n <div>\n <h4 className=\"text-xs font-medium text-text-secondary mb-1\">Arguments</h4>\n <dl className=\"space-y-1\" data-testid=\"mcp-tool-arguments\">\n {Object.entries(call.arguments).map(([key, value]) => (\n <div key={key} className=\"flex gap-2\">\n <dt className=\"text-xs font-mono text-text-secondary shrink-0\">{key}:</dt>\n <dd className=\"text-xs font-mono text-text-primary break-all\">\n {formatValue(value)}\n </dd>\n </div>\n ))}\n </dl>\n </div>\n )}\n\n {/* Result */}\n {call.result !== undefined && (\n <div>\n <h4 className=\"text-xs font-medium text-text-secondary mb-1\">Result</h4>\n <pre\n className=\"text-xs font-mono text-text-primary bg-surface-sunken rounded p-2 overflow-x-auto whitespace-pre-wrap\"\n data-testid=\"mcp-tool-result\"\n >\n {typeof call.result === 'string' ? call.result : JSON.stringify(call.result, null, 2)}\n </pre>\n </div>\n )}\n\n {/* Error */}\n {call.error && (\n <div>\n <h4 className=\"text-xs font-medium text-status-error mb-1\">Error</h4>\n <p\n className=\"text-xs text-status-error bg-status-error-subtle/30 rounded p-2\"\n data-testid=\"mcp-tool-error\"\n >\n {call.error}\n </p>\n </div>\n )}\n </div>\n )}\n </div>\n )\n}\n\nexport { MCPToolCall }\n","import React from 'react'\nimport { twMerge } from 'tailwind-merge'\nimport type { MCPResource } from '../../types/mcp'\n\nexport type MCPResourceViewProps = {\n resource: MCPResource\n className?: string\n}\n\nfunction isImageMime(mime?: string): boolean {\n return !!mime && mime.startsWith('image/')\n}\n\nfunction isTextMime(mime?: string): boolean {\n if (!mime) return true\n return (\n mime.startsWith('text/') ||\n mime === 'application/json' ||\n mime === 'application/xml' ||\n mime === 'application/javascript' ||\n mime === 'application/typescript'\n )\n}\n\nfunction isUrlContent(content?: string | Uint8Array): boolean {\n if (typeof content !== 'string') return false\n return /^https?:\\/\\//.test(content.trim())\n}\n\nfunction MCPResourceView({ resource, className }: MCPResourceViewProps) {\n const { uri, name, mimeType, description, content } = resource\n\n return (\n <div\n className={twMerge('rounded-lg border border-border bg-surface p-3 text-sm', className)}\n data-testid=\"mcp-resource-view\"\n >\n {/* Header */}\n <div className=\"mb-2\">\n <span className=\"font-medium text-text-primary\" data-testid=\"mcp-resource-name\">\n {name}\n </span>\n <span\n className=\"ml-2 text-xs text-text-secondary font-mono truncate\"\n data-testid=\"mcp-resource-uri\"\n >\n {uri}\n </span>\n </div>\n\n {description && (\n <p className=\"text-xs text-text-secondary mb-2\" data-testid=\"mcp-resource-description\">\n {description}\n </p>\n )}\n\n {/* Content rendering */}\n {content !== undefined && (\n <div data-testid=\"mcp-resource-content\">\n {isImageMime(mimeType) && typeof content === 'string' ? (\n <img\n src={content}\n alt={name}\n className=\"max-w-full rounded\"\n data-testid=\"mcp-resource-image\"\n />\n ) : isUrlContent(content) ? (\n <a\n href={typeof content === 'string' ? content.trim() : undefined}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm text-interactive-primary hover:underline break-all\"\n data-testid=\"mcp-resource-link\"\n >\n {typeof content === 'string' ? content.trim() : ''}\n </a>\n ) : isTextMime(mimeType) ? (\n <pre\n className=\"text-xs font-mono text-text-primary bg-surface-sunken rounded p-2 overflow-x-auto whitespace-pre-wrap\"\n data-testid=\"mcp-resource-code\"\n >\n {typeof content === 'string' ? content : '[Binary data]'}\n </pre>\n ) : (\n <p className=\"text-xs text-text-secondary italic\">\n Unsupported content type: {mimeType}\n </p>\n )}\n </div>\n )}\n </div>\n )\n}\n\nexport { MCPResourceView }\n","'use client'\n\nimport React, { useState } from 'react'\nimport { cva } from 'class-variance-authority'\nimport { twMerge } from 'tailwind-merge'\nimport type { MCPServerInfo } from '../../types/mcp'\n\nexport type MCPServerStatusProps = {\n server: MCPServerInfo\n className?: string\n}\n\nconst statusDot = cva('inline-block h-2 w-2 rounded-full shrink-0', {\n variants: {\n status: {\n connected: 'bg-status-success',\n disconnected: 'bg-neutral-400',\n error: 'bg-status-error',\n },\n },\n defaultVariants: { status: 'disconnected' },\n})\n\nconst statusLabel: Record<MCPServerInfo['status'], string> = {\n connected: 'Connected',\n disconnected: 'Disconnected',\n error: 'Error',\n}\n\nfunction formatLastPing(date?: Date): string | null {\n if (!date) return null\n return date.toLocaleTimeString()\n}\n\nfunction MCPServerStatus({ server, className }: MCPServerStatusProps) {\n const [showTools, setShowTools] = useState(false)\n const [showResources, setShowResources] = useState(false)\n const lastPing = formatLastPing(server.lastPing)\n\n return (\n <div\n className={twMerge('rounded-lg border border-border bg-surface p-3 text-sm', className)}\n data-testid=\"mcp-server-status\"\n >\n {/* Header */}\n <div className=\"flex items-center gap-2 mb-1\">\n <span\n className={statusDot({ status: server.status })}\n role=\"status\"\n aria-label={statusLabel[server.status]}\n data-testid=\"mcp-server-status-dot\"\n />\n <span className=\"font-medium text-text-primary\" data-testid=\"mcp-server-name\">\n {server.name}\n </span>\n {server.version && (\n <span className=\"text-xs text-text-secondary\" data-testid=\"mcp-server-version\">\n v{server.version}\n </span>\n )}\n </div>\n\n {lastPing && (\n <p className=\"text-xs text-text-secondary ml-4 mb-2\" data-testid=\"mcp-server-last-ping\">\n Last ping: {lastPing}\n </p>\n )}\n\n {/* Tools list */}\n {server.tools.length > 0 && (\n <div className=\"mt-2\">\n <button\n type=\"button\"\n className=\"flex items-center gap-1 text-xs font-medium text-text-secondary hover:text-text-primary w-full\"\n onClick={() => setShowTools((prev) => !prev)}\n aria-expanded={showTools}\n data-testid=\"mcp-server-tools-toggle\"\n >\n <svg\n className={`h-3 w-3 transition-transform ${showTools ? 'rotate-90' : ''}`}\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z\"\n clipRule=\"evenodd\"\n />\n </svg>\n Tools ({server.tools.length})\n </button>\n {showTools && (\n <ul className=\"mt-1 ml-4 space-y-1\" data-testid=\"mcp-server-tools-list\">\n {server.tools.map((tool) => (\n <li key={tool.name} className=\"text-xs text-text-primary\">\n <span className=\"font-mono\">{tool.name}</span>\n {tool.description && (\n <span className=\"text-text-secondary ml-1\">— {tool.description}</span>\n )}\n </li>\n ))}\n </ul>\n )}\n </div>\n )}\n\n {/* Resources list */}\n {server.resources.length > 0 && (\n <div className=\"mt-2\">\n <button\n type=\"button\"\n className=\"flex items-center gap-1 text-xs font-medium text-text-secondary hover:text-text-primary w-full\"\n onClick={() => setShowResources((prev) => !prev)}\n aria-expanded={showResources}\n data-testid=\"mcp-server-resources-toggle\"\n >\n <svg\n className={`h-3 w-3 transition-transform ${showResources ? 'rotate-90' : ''}`}\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z\"\n clipRule=\"evenodd\"\n />\n </svg>\n Resources ({server.resources.length})\n </button>\n {showResources && (\n <ul className=\"mt-1 ml-4 space-y-1\" data-testid=\"mcp-server-resources-list\">\n {server.resources.map((res) => (\n <li key={res.uri} className=\"text-xs text-text-primary\">\n <span className=\"font-mono\">{res.name}</span>\n <span className=\"text-text-secondary ml-1\">({res.uri})</span>\n </li>\n ))}\n </ul>\n )}\n </div>\n )}\n </div>\n )\n}\n\nexport { MCPServerStatus }\n","'use client'\n\nimport React, { useRef, useEffect } from 'react'\nimport { cva } from 'class-variance-authority'\nimport { twMerge } from 'tailwind-merge'\nimport { useDialog, FocusScope } from 'react-aria'\nimport { Button, Badge } from '@surf-kit/core'\nimport type { MCPToolCallData } from '../../types/mcp'\n\nexport type MCPApprovalDialogProps = {\n call: MCPToolCallData\n riskLevel?: 'low' | 'medium' | 'high'\n onApprove: () => void\n onDeny: () => void\n isOpen: boolean\n className?: string\n}\n\nconst riskBadgeIntent: Record<string, 'success' | 'warning' | 'error'> = {\n low: 'success',\n medium: 'warning',\n high: 'error',\n}\n\nconst riskLabel: Record<string, string> = {\n low: 'Low Risk',\n medium: 'Medium Risk',\n high: 'High Risk',\n}\n\nconst riskBorder = cva('relative bg-surface rounded-xl shadow-xl border p-6 outline-none w-full max-w-lg', {\n variants: {\n risk: {\n low: 'border-status-success-subtle',\n medium: 'border-status-warning-subtle',\n high: 'border-status-error-subtle',\n },\n },\n defaultVariants: { risk: 'low' },\n})\n\nfunction formatValue(value: unknown): string {\n if (typeof value === 'string') return value\n return JSON.stringify(value, null, 2)\n}\n\nfunction MCPApprovalDialog({\n call,\n riskLevel = 'low',\n onApprove,\n onDeny,\n isOpen,\n className,\n}: MCPApprovalDialogProps) {\n const ref = useRef<HTMLDivElement>(null)\n const { dialogProps, titleProps } = useDialog({ role: 'alertdialog' }, ref)\n\n // Block Escape key — user must explicitly approve or deny\n useEffect(() => {\n if (!isOpen) return\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault()\n e.stopPropagation()\n }\n }\n document.addEventListener('keydown', handleKeyDown, true)\n return () => document.removeEventListener('keydown', handleKeyDown, true)\n }, [isOpen])\n\n if (!isOpen) return null\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50\"\n data-testid=\"mcp-approval-overlay\"\n >\n <FocusScope contain restoreFocus autoFocus>\n <div\n {...dialogProps}\n ref={ref}\n className={twMerge(riskBorder({ risk: riskLevel }), className)}\n data-testid=\"mcp-approval-dialog\"\n >\n {/* Title */}\n <div className=\"flex items-center justify-between mb-4\">\n <h2\n {...titleProps}\n className=\"text-lg font-semibold text-text-primary\"\n data-testid=\"mcp-approval-title\"\n >\n Tool Approval Required\n </h2>\n <Badge\n intent={riskBadgeIntent[riskLevel]}\n size=\"sm\"\n data-testid=\"mcp-approval-risk-badge\"\n >\n {riskLabel[riskLevel]}\n </Badge>\n </div>\n\n {/* Tool info */}\n <div className=\"space-y-3 text-sm\">\n <div>\n <h3 className=\"text-xs font-medium text-text-secondary mb-1\">Tool</h3>\n <p className=\"font-mono text-text-primary\" data-testid=\"mcp-approval-tool-name\">\n {call.name}\n </p>\n {call.serverName && (\n <p className=\"text-xs text-text-secondary mt-0.5\" data-testid=\"mcp-approval-server\">\n Server: {call.serverName}\n </p>\n )}\n </div>\n\n {/* Arguments */}\n {Object.keys(call.arguments).length > 0 && (\n <div>\n <h3 className=\"text-xs font-medium text-text-secondary mb-1\">Arguments</h3>\n <dl\n className=\"space-y-1 bg-neutral-100 rounded p-2\"\n data-testid=\"mcp-approval-arguments\"\n >\n {Object.entries(call.arguments).map(([key, value]) => (\n <div key={key} className=\"flex gap-2\">\n <dt className=\"text-xs font-mono text-text-secondary shrink-0\">{key}:</dt>\n <dd className=\"text-xs font-mono text-text-primary break-all\">\n {formatValue(value)}\n </dd>\n </div>\n ))}\n </dl>\n </div>\n )}\n </div>\n\n {/* Actions */}\n <div className=\"mt-6 flex justify-end gap-3\">\n <Button\n intent=\"secondary\"\n onPress={onDeny}\n aria-label=\"Deny tool execution\"\n >\n Deny\n </Button>\n <Button\n intent=\"primary\"\n onPress={onApprove}\n aria-label=\"Approve tool execution\"\n >\n Approve\n </Button>\n </div>\n </div>\n </FocusScope>\n </div>\n )\n}\n\nexport { MCPApprovalDialog }\n"],"mappings":"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","names":["twMerge","jsx","jsxs","cva","twMerge","jsx","jsxs","statusLabel","cva","twMerge","Badge","jsx","jsxs","formatValue"]}
|
|
1
|
+
{"version":3,"sources":["../../src/mcp/MCPToolCall/MCPToolCall.tsx","../../src/mcp/MCPResourceView/MCPResourceView.tsx","../../src/mcp/MCPServerStatus/MCPServerStatus.tsx","../../src/mcp/MCPApprovalDialog/MCPApprovalDialog.tsx"],"sourcesContent":["import React from 'react'\nimport { cva } from 'class-variance-authority'\nimport { twMerge } from 'tailwind-merge'\nimport { Badge, WaveLoader } from '@surf-kit/core'\nimport type { MCPToolCallData, MCPToolStatus } from '../../types/mcp'\n\nexport type MCPToolCallProps = {\n call: MCPToolCallData\n isExpanded?: boolean\n onToggleExpand?: () => void\n className?: string\n}\n\nconst statusBadgeIntent: Record<MCPToolStatus, 'default' | 'info' | 'success' | 'error'> = {\n pending: 'default',\n running: 'info',\n success: 'success',\n error: 'error',\n}\n\nconst statusLabel: Record<MCPToolStatus, string> = {\n pending: 'Pending',\n running: 'Running',\n success: 'Success',\n error: 'Error',\n}\n\nconst container = cva(\n 'rounded-lg border text-sm',\n {\n variants: {\n status: {\n pending: 'border-border bg-surface',\n running: 'border-status-info-subtle bg-status-info-subtle/30',\n success: 'border-status-success-subtle bg-status-success-subtle/30',\n error: 'border-status-error-subtle bg-status-error-subtle/30',\n },\n },\n defaultVariants: { status: 'pending' },\n },\n)\n\nfunction formatDuration(start?: Date, end?: Date): string | null {\n if (!start || !end) return null\n const ms = end.getTime() - start.getTime()\n if (ms < 1000) return `${ms}ms`\n return `${(ms / 1000).toFixed(1)}s`\n}\n\nfunction formatValue(value: unknown): string {\n if (typeof value === 'string') return value\n return JSON.stringify(value, null, 2)\n}\n\nfunction MCPToolCall({ call, isExpanded = false, onToggleExpand, className }: MCPToolCallProps) {\n const duration = formatDuration(call.startedAt, call.completedAt)\n\n return (\n <div\n className={twMerge(container({ status: call.status }), className)}\n data-testid=\"mcp-tool-call\"\n >\n {/* Header */}\n <button\n type=\"button\"\n className=\"flex w-full items-center justify-between gap-2 px-3 py-2\"\n onClick={onToggleExpand}\n aria-expanded={isExpanded}\n data-testid=\"mcp-tool-call-header\"\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <span className=\"font-medium text-text-primary truncate\" data-testid=\"mcp-tool-name\">\n {call.name}\n </span>\n {call.serverName && (\n <span className=\"text-xs text-text-secondary truncate\">\n {call.serverName}\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-2 shrink-0\">\n {call.status === 'running' && (\n <span aria-hidden=\"true\">\n <WaveLoader size=\"sm\" color=\"#38bdf8\" />\n </span>\n )}\n <Badge\n intent={statusBadgeIntent[call.status]}\n size=\"sm\"\n role=\"status\"\n aria-label={`Status: ${statusLabel[call.status]}`}\n data-testid=\"mcp-tool-status\"\n >\n {statusLabel[call.status]}\n </Badge>\n {duration && (\n <span className=\"text-xs text-text-secondary\" data-testid=\"mcp-tool-duration\">\n {duration}\n </span>\n )}\n <svg\n className={`h-4 w-4 text-text-secondary transition-transform ${isExpanded ? 'rotate-180' : ''}`}\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </div>\n </button>\n\n {/* Expandable body */}\n {isExpanded && (\n <div className=\"border-t border-inherit px-3 py-2 space-y-3\" data-testid=\"mcp-tool-call-body\">\n {/* Arguments */}\n {Object.keys(call.arguments).length > 0 && (\n <div>\n <h4 className=\"text-xs font-medium text-text-secondary mb-1\">Arguments</h4>\n <dl className=\"space-y-1\" data-testid=\"mcp-tool-arguments\">\n {Object.entries(call.arguments).map(([key, value]) => (\n <div key={key} className=\"flex gap-2\">\n <dt className=\"text-xs font-mono text-text-secondary shrink-0\">{key}:</dt>\n <dd className=\"text-xs font-mono text-text-primary break-all\">\n {formatValue(value)}\n </dd>\n </div>\n ))}\n </dl>\n </div>\n )}\n\n {/* Result */}\n {call.result !== undefined && (\n <div>\n <h4 className=\"text-xs font-medium text-text-secondary mb-1\">Result</h4>\n <pre\n className=\"text-xs font-mono text-text-primary bg-surface-sunken rounded p-2 overflow-x-auto whitespace-pre-wrap\"\n data-testid=\"mcp-tool-result\"\n >\n {typeof call.result === 'string' ? call.result : JSON.stringify(call.result, null, 2)}\n </pre>\n </div>\n )}\n\n {/* Error */}\n {call.error && (\n <div>\n <h4 className=\"text-xs font-medium text-status-error mb-1\">Error</h4>\n <p\n className=\"text-xs text-status-error bg-status-error-subtle/30 rounded p-2\"\n data-testid=\"mcp-tool-error\"\n >\n {call.error}\n </p>\n </div>\n )}\n </div>\n )}\n </div>\n )\n}\n\nexport { MCPToolCall }\n","import React from 'react'\nimport { twMerge } from 'tailwind-merge'\nimport type { MCPResource } from '../../types/mcp'\n\nexport type MCPResourceViewProps = {\n resource: MCPResource\n className?: string\n}\n\nfunction isImageMime(mime?: string): boolean {\n return !!mime && mime.startsWith('image/')\n}\n\nfunction isTextMime(mime?: string): boolean {\n if (!mime) return true\n return (\n mime.startsWith('text/') ||\n mime === 'application/json' ||\n mime === 'application/xml' ||\n mime === 'application/javascript' ||\n mime === 'application/typescript'\n )\n}\n\nfunction isUrlContent(content?: string | Uint8Array): boolean {\n if (typeof content !== 'string') return false\n return /^https?:\\/\\//.test(content.trim())\n}\n\nfunction MCPResourceView({ resource, className }: MCPResourceViewProps) {\n const { uri, name, mimeType, description, content } = resource\n\n return (\n <div\n className={twMerge('rounded-lg border border-border bg-surface p-3 text-sm', className)}\n data-testid=\"mcp-resource-view\"\n >\n {/* Header */}\n <div className=\"mb-2\">\n <span className=\"font-medium text-text-primary\" data-testid=\"mcp-resource-name\">\n {name}\n </span>\n <span\n className=\"ml-2 text-xs text-text-secondary font-mono truncate\"\n data-testid=\"mcp-resource-uri\"\n >\n {uri}\n </span>\n </div>\n\n {description && (\n <p className=\"text-xs text-text-secondary mb-2\" data-testid=\"mcp-resource-description\">\n {description}\n </p>\n )}\n\n {/* Content rendering */}\n {content !== undefined && (\n <div data-testid=\"mcp-resource-content\">\n {isImageMime(mimeType) && typeof content === 'string' ? (\n <img\n src={content}\n alt={name}\n className=\"max-w-full rounded\"\n data-testid=\"mcp-resource-image\"\n />\n ) : isUrlContent(content) ? (\n <a\n href={typeof content === 'string' ? content.trim() : undefined}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm text-interactive-primary hover:underline break-all\"\n data-testid=\"mcp-resource-link\"\n >\n {typeof content === 'string' ? content.trim() : ''}\n </a>\n ) : isTextMime(mimeType) ? (\n <pre\n className=\"text-xs font-mono text-text-primary bg-surface-sunken rounded p-2 overflow-x-auto whitespace-pre-wrap\"\n data-testid=\"mcp-resource-code\"\n >\n {typeof content === 'string' ? content : '[Binary data]'}\n </pre>\n ) : (\n <p className=\"text-xs text-text-secondary italic\">\n Unsupported content type: {mimeType}\n </p>\n )}\n </div>\n )}\n </div>\n )\n}\n\nexport { MCPResourceView }\n","'use client'\n\nimport React, { useState } from 'react'\nimport { cva } from 'class-variance-authority'\nimport { twMerge } from 'tailwind-merge'\nimport type { MCPServerInfo } from '../../types/mcp'\n\nexport type MCPServerStatusProps = {\n server: MCPServerInfo\n className?: string\n}\n\nconst statusDot = cva('inline-block h-2 w-2 rounded-full shrink-0', {\n variants: {\n status: {\n connected: 'bg-status-success',\n disconnected: 'bg-neutral-400',\n error: 'bg-status-error',\n },\n },\n defaultVariants: { status: 'disconnected' },\n})\n\nconst statusLabel: Record<MCPServerInfo['status'], string> = {\n connected: 'Connected',\n disconnected: 'Disconnected',\n error: 'Error',\n}\n\nfunction formatLastPing(date?: Date): string | null {\n if (!date) return null\n return date.toLocaleTimeString()\n}\n\nfunction MCPServerStatus({ server, className }: MCPServerStatusProps) {\n const [showTools, setShowTools] = useState(false)\n const [showResources, setShowResources] = useState(false)\n const lastPing = formatLastPing(server.lastPing)\n\n return (\n <div\n className={twMerge('rounded-lg border border-border bg-surface p-3 text-sm', className)}\n data-testid=\"mcp-server-status\"\n >\n {/* Header */}\n <div className=\"flex items-center gap-2 mb-1\">\n <span\n className={statusDot({ status: server.status })}\n role=\"status\"\n aria-label={statusLabel[server.status]}\n data-testid=\"mcp-server-status-dot\"\n />\n <span className=\"font-medium text-text-primary\" data-testid=\"mcp-server-name\">\n {server.name}\n </span>\n {server.version && (\n <span className=\"text-xs text-text-secondary\" data-testid=\"mcp-server-version\">\n v{server.version}\n </span>\n )}\n </div>\n\n {lastPing && (\n <p className=\"text-xs text-text-secondary ml-4 mb-2\" data-testid=\"mcp-server-last-ping\">\n Last ping: {lastPing}\n </p>\n )}\n\n {/* Tools list */}\n {server.tools.length > 0 && (\n <div className=\"mt-2\">\n <button\n type=\"button\"\n className=\"flex items-center gap-1 text-xs font-medium text-text-secondary hover:text-text-primary w-full\"\n onClick={() => setShowTools((prev) => !prev)}\n aria-expanded={showTools}\n data-testid=\"mcp-server-tools-toggle\"\n >\n <svg\n className={`h-3 w-3 transition-transform ${showTools ? 'rotate-90' : ''}`}\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z\"\n clipRule=\"evenodd\"\n />\n </svg>\n Tools ({server.tools.length})\n </button>\n {showTools && (\n <ul className=\"mt-1 ml-4 space-y-1\" data-testid=\"mcp-server-tools-list\">\n {server.tools.map((tool) => (\n <li key={tool.name} className=\"text-xs text-text-primary\">\n <span className=\"font-mono\">{tool.name}</span>\n {tool.description && (\n <span className=\"text-text-secondary ml-1\">— {tool.description}</span>\n )}\n </li>\n ))}\n </ul>\n )}\n </div>\n )}\n\n {/* Resources list */}\n {server.resources.length > 0 && (\n <div className=\"mt-2\">\n <button\n type=\"button\"\n className=\"flex items-center gap-1 text-xs font-medium text-text-secondary hover:text-text-primary w-full\"\n onClick={() => setShowResources((prev) => !prev)}\n aria-expanded={showResources}\n data-testid=\"mcp-server-resources-toggle\"\n >\n <svg\n className={`h-3 w-3 transition-transform ${showResources ? 'rotate-90' : ''}`}\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z\"\n clipRule=\"evenodd\"\n />\n </svg>\n Resources ({server.resources.length})\n </button>\n {showResources && (\n <ul className=\"mt-1 ml-4 space-y-1\" data-testid=\"mcp-server-resources-list\">\n {server.resources.map((res) => (\n <li key={res.uri} className=\"text-xs text-text-primary\">\n <span className=\"font-mono\">{res.name}</span>\n <span className=\"text-text-secondary ml-1\">({res.uri})</span>\n </li>\n ))}\n </ul>\n )}\n </div>\n )}\n </div>\n )\n}\n\nexport { MCPServerStatus }\n","'use client'\n\nimport React, { useRef, useEffect } from 'react'\nimport { cva } from 'class-variance-authority'\nimport { twMerge } from 'tailwind-merge'\nimport { useDialog, FocusScope } from 'react-aria'\nimport { Button, Badge } from '@surf-kit/core'\nimport type { MCPToolCallData } from '../../types/mcp'\n\nexport type MCPApprovalDialogProps = {\n call: MCPToolCallData\n riskLevel?: 'low' | 'medium' | 'high'\n onApprove: () => void\n onDeny: () => void\n isOpen: boolean\n className?: string\n}\n\nconst riskBadgeIntent: Record<string, 'success' | 'warning' | 'error'> = {\n low: 'success',\n medium: 'warning',\n high: 'error',\n}\n\nconst riskLabel: Record<string, string> = {\n low: 'Low Risk',\n medium: 'Medium Risk',\n high: 'High Risk',\n}\n\nconst riskBorder = cva('relative bg-surface rounded-xl shadow-xl border p-6 outline-none w-full max-w-lg', {\n variants: {\n risk: {\n low: 'border-status-success-subtle',\n medium: 'border-status-warning-subtle',\n high: 'border-status-error-subtle',\n },\n },\n defaultVariants: { risk: 'low' },\n})\n\nfunction formatValue(value: unknown): string {\n if (typeof value === 'string') return value\n return JSON.stringify(value, null, 2)\n}\n\nfunction MCPApprovalDialog({\n call,\n riskLevel = 'low',\n onApprove,\n onDeny,\n isOpen,\n className,\n}: MCPApprovalDialogProps) {\n const ref = useRef<HTMLDivElement>(null)\n const { dialogProps, titleProps } = useDialog({ role: 'alertdialog' }, ref)\n\n // Block Escape key — user must explicitly approve or deny\n useEffect(() => {\n if (!isOpen) return\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault()\n e.stopPropagation()\n }\n }\n document.addEventListener('keydown', handleKeyDown, true)\n return () => document.removeEventListener('keydown', handleKeyDown, true)\n }, [isOpen])\n\n if (!isOpen) return null\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50\"\n data-testid=\"mcp-approval-overlay\"\n >\n <FocusScope contain restoreFocus autoFocus>\n <div\n {...dialogProps}\n ref={ref}\n className={twMerge(riskBorder({ risk: riskLevel }), className)}\n data-testid=\"mcp-approval-dialog\"\n >\n {/* Title */}\n <div className=\"flex items-center justify-between mb-4\">\n <h2\n {...titleProps}\n className=\"text-lg font-semibold text-text-primary\"\n data-testid=\"mcp-approval-title\"\n >\n Tool Approval Required\n </h2>\n <Badge\n intent={riskBadgeIntent[riskLevel]}\n size=\"sm\"\n data-testid=\"mcp-approval-risk-badge\"\n >\n {riskLabel[riskLevel]}\n </Badge>\n </div>\n\n {/* Tool info */}\n <div className=\"space-y-3 text-sm\">\n <div>\n <h3 className=\"text-xs font-medium text-text-secondary mb-1\">Tool</h3>\n <p className=\"font-mono text-text-primary\" data-testid=\"mcp-approval-tool-name\">\n {call.name}\n </p>\n {call.serverName && (\n <p className=\"text-xs text-text-secondary mt-0.5\" data-testid=\"mcp-approval-server\">\n Server: {call.serverName}\n </p>\n )}\n </div>\n\n {/* Arguments */}\n {Object.keys(call.arguments).length > 0 && (\n <div>\n <h3 className=\"text-xs font-medium text-text-secondary mb-1\">Arguments</h3>\n <dl\n className=\"space-y-1 bg-neutral-100 rounded p-2\"\n data-testid=\"mcp-approval-arguments\"\n >\n {Object.entries(call.arguments).map(([key, value]) => (\n <div key={key} className=\"flex gap-2\">\n <dt className=\"text-xs font-mono text-text-secondary shrink-0\">{key}:</dt>\n <dd className=\"text-xs font-mono text-text-primary break-all\">\n {formatValue(value)}\n </dd>\n </div>\n ))}\n </dl>\n </div>\n )}\n </div>\n\n {/* Actions */}\n <div className=\"mt-6 flex justify-end gap-3\">\n <Button\n intent=\"secondary\"\n onPress={onDeny}\n aria-label=\"Deny tool execution\"\n >\n Deny\n </Button>\n <Button\n intent=\"primary\"\n onPress={onApprove}\n aria-label=\"Approve tool execution\"\n >\n Approve\n </Button>\n </div>\n </div>\n </FocusScope>\n </div>\n )\n}\n\nexport { MCPApprovalDialog }\n"],"mappings":"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","names":["twMerge","jsx","jsxs","cva","twMerge","jsx","jsxs","statusLabel","cva","twMerge","Badge","jsx","jsxs","formatValue"]}
|
package/dist/response/index.cjs
CHANGED
|
@@ -43,8 +43,10 @@ module.exports = __toCommonJS(response_exports);
|
|
|
43
43
|
var import_core2 = require("@surf-kit/core");
|
|
44
44
|
|
|
45
45
|
// src/response/ResponseMessage/ResponseMessage.tsx
|
|
46
|
+
var import_react = __toESM(require("react"), 1);
|
|
46
47
|
var import_react_markdown = __toESM(require("react-markdown"), 1);
|
|
47
48
|
var import_rehype_sanitize = __toESM(require("rehype-sanitize"), 1);
|
|
49
|
+
var import_remark_gfm = __toESM(require("remark-gfm"), 1);
|
|
48
50
|
var import_tailwind_merge = require("tailwind-merge");
|
|
49
51
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
50
52
|
function normalizeMarkdownLists(content) {
|
|
@@ -67,7 +69,12 @@ function ResponseMessage({ content, className }) {
|
|
|
67
69
|
"[&_h3]:text-sm [&_h3]:font-semibold [&_h3]:text-accent [&_h3]:mt-2 [&_h3]:mb-1",
|
|
68
70
|
"[&_code]:bg-surface-raised [&_code]:text-accent [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:rounded [&_code]:text-xs [&_code]:font-mono",
|
|
69
71
|
"[&_pre]:bg-surface-raised [&_pre]:border [&_pre]:border-border [&_pre]:rounded-xl [&_pre]:p-4 [&_pre]:overflow-x-auto",
|
|
72
|
+
"[&_hr]:my-3 [&_hr]:border-border",
|
|
70
73
|
"[&_blockquote]:border-l-2 [&_blockquote]:border-border-strong [&_blockquote]:pl-4 [&_blockquote]:text-text-secondary",
|
|
74
|
+
"[&_table]:w-full [&_table]:text-sm [&_table]:border-collapse [&_table]:my-2",
|
|
75
|
+
"[&_thead]:border-b [&_thead]:border-border",
|
|
76
|
+
"[&_th]:text-left [&_th]:px-2 [&_th]:py-1.5 [&_th]:font-semibold",
|
|
77
|
+
"[&_td]:px-2 [&_td]:py-1.5 [&_td]:border-t [&_td]:border-border/50",
|
|
71
78
|
"[&_a]:text-accent [&_a]:underline-offset-2 [&_a]:hover:text-accent/80",
|
|
72
79
|
className
|
|
73
80
|
),
|
|
@@ -75,6 +82,7 @@ function ResponseMessage({ content, className }) {
|
|
|
75
82
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
76
83
|
import_react_markdown.default,
|
|
77
84
|
{
|
|
85
|
+
remarkPlugins: [import_remark_gfm.default],
|
|
78
86
|
rehypePlugins: [import_rehype_sanitize.default],
|
|
79
87
|
components: {
|
|
80
88
|
script: () => null,
|
|
@@ -82,12 +90,29 @@ function ResponseMessage({ content, className }) {
|
|
|
82
90
|
p: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "my-2", children }),
|
|
83
91
|
ul: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "my-2 list-disc pl-6", children }),
|
|
84
92
|
ol: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", { className: "my-2 list-decimal pl-6", children }),
|
|
85
|
-
li: ({ children }) =>
|
|
93
|
+
li: ({ children, ...props }) => {
|
|
94
|
+
let content2 = children;
|
|
95
|
+
if (props.ordered) {
|
|
96
|
+
content2 = import_react.default.Children.map(children, (child, i) => {
|
|
97
|
+
if (i === 0 && typeof child === "string") {
|
|
98
|
+
return child.replace(/^\d+[.)]\s*/, "");
|
|
99
|
+
}
|
|
100
|
+
return child;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { className: "my-1", children: content2 });
|
|
104
|
+
},
|
|
86
105
|
strong: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { className: "font-semibold", children }),
|
|
106
|
+
em: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("em", { className: "italic text-text-secondary", children }),
|
|
87
107
|
h1: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: "text-base font-bold mt-4 mb-2", children }),
|
|
88
108
|
h2: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "text-sm font-bold mt-3 mb-1", children }),
|
|
89
109
|
h3: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { className: "text-sm font-semibold mt-2 mb-1", children }),
|
|
90
|
-
|
|
110
|
+
hr: () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("hr", { className: "my-3 border-border" }),
|
|
111
|
+
code: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { className: "bg-surface-sunken rounded px-1 py-0.5 text-xs font-mono", children }),
|
|
112
|
+
table: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "overflow-x-auto my-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("table", { className: "w-full text-sm border-collapse", children }) }),
|
|
113
|
+
thead: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { className: "border-b border-border", children }),
|
|
114
|
+
th: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { className: "text-left px-2 py-1.5 font-semibold", children }),
|
|
115
|
+
td: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: "px-2 py-1.5 border-t border-border/50", children })
|
|
91
116
|
},
|
|
92
117
|
children: normalizeMarkdownLists(content)
|
|
93
118
|
}
|
|
@@ -97,6 +122,8 @@ function ResponseMessage({ content, className }) {
|
|
|
97
122
|
}
|
|
98
123
|
|
|
99
124
|
// src/response/StructuredResponse/StructuredResponse.tsx
|
|
125
|
+
var import_react_markdown2 = __toESM(require("react-markdown"), 1);
|
|
126
|
+
var import_rehype_sanitize2 = __toESM(require("rehype-sanitize"), 1);
|
|
100
127
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
101
128
|
function tryParse(value) {
|
|
102
129
|
if (value === void 0 || value === null) return null;
|
|
@@ -109,6 +136,25 @@ function tryParse(value) {
|
|
|
109
136
|
}
|
|
110
137
|
return value;
|
|
111
138
|
}
|
|
139
|
+
function InlineMarkdown({ text }) {
|
|
140
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
141
|
+
import_react_markdown2.default,
|
|
142
|
+
{
|
|
143
|
+
rehypePlugins: [import_rehype_sanitize2.default],
|
|
144
|
+
components: {
|
|
145
|
+
// Unwrap block-level <p> so content stays inline within its parent
|
|
146
|
+
p: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children }),
|
|
147
|
+
strong: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { className: "font-semibold", children }),
|
|
148
|
+
em: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("em", { className: "italic", children }),
|
|
149
|
+
code: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { className: "bg-surface-sunken rounded px-1 py-0.5 text-xs font-mono", children }),
|
|
150
|
+
// Prevent block elements that would break layout
|
|
151
|
+
script: () => null,
|
|
152
|
+
iframe: () => null
|
|
153
|
+
},
|
|
154
|
+
children: text
|
|
155
|
+
}
|
|
156
|
+
);
|
|
157
|
+
}
|
|
112
158
|
function renderSteps(data) {
|
|
113
159
|
const steps = tryParse(data.steps);
|
|
114
160
|
if (!steps || !Array.isArray(steps)) return null;
|
|
@@ -121,7 +167,7 @@ function renderSteps(data) {
|
|
|
121
167
|
children: i + 1
|
|
122
168
|
}
|
|
123
169
|
),
|
|
124
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-sm text-text-primary leading-relaxed", children: step })
|
|
170
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-sm text-text-primary leading-relaxed", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(InlineMarkdown, { text: step }) })
|
|
125
171
|
] }, i)) });
|
|
126
172
|
}
|
|
127
173
|
function renderTable(data) {
|
|
@@ -187,7 +233,7 @@ function renderList(data) {
|
|
|
187
233
|
title && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs font-semibold uppercase tracking-wider text-text-secondary mb-1", children: title }),
|
|
188
234
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { className: "flex flex-col gap-1.5", children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { className: "flex items-start gap-2.5", children: [
|
|
189
235
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full bg-accent", "aria-hidden": "true" }),
|
|
190
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-sm text-text-primary leading-relaxed", children: item })
|
|
236
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-sm text-text-primary leading-relaxed", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(InlineMarkdown, { text: item }) })
|
|
191
237
|
] }, i)) })
|
|
192
238
|
] });
|
|
193
239
|
}
|
|
@@ -222,7 +268,14 @@ function renderWarning(data) {
|
|
|
222
268
|
}
|
|
223
269
|
);
|
|
224
270
|
}
|
|
225
|
-
function StructuredResponse({ uiHint, data, className }) {
|
|
271
|
+
function StructuredResponse({ uiHint, data: rawData, className }) {
|
|
272
|
+
const data = typeof rawData === "string" ? (() => {
|
|
273
|
+
try {
|
|
274
|
+
return JSON.parse(rawData);
|
|
275
|
+
} catch {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
})() : rawData;
|
|
226
279
|
if (!data) return null;
|
|
227
280
|
let content;
|
|
228
281
|
switch (uiHint) {
|
|
@@ -252,7 +305,7 @@ function StructuredResponse({ uiHint, data, className }) {
|
|
|
252
305
|
}
|
|
253
306
|
|
|
254
307
|
// src/sources/SourceList/SourceList.tsx
|
|
255
|
-
var
|
|
308
|
+
var import_react2 = require("react");
|
|
256
309
|
|
|
257
310
|
// src/sources/SourceCard/SourceCard.tsx
|
|
258
311
|
var import_core = require("@surf-kit/core");
|
|
@@ -302,7 +355,36 @@ function SourceCard({ source, variant = "compact", onNavigate, className }) {
|
|
|
302
355
|
children: [
|
|
303
356
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-start justify-between gap-2", children: [
|
|
304
357
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex-1 min-w-0", children: [
|
|
305
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.
|
|
358
|
+
source.url ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
359
|
+
"a",
|
|
360
|
+
{
|
|
361
|
+
href: source.url,
|
|
362
|
+
target: "_blank",
|
|
363
|
+
rel: "noopener noreferrer",
|
|
364
|
+
className: "text-sm font-medium text-accent hover:underline truncate block",
|
|
365
|
+
onClick: (e) => e.stopPropagation(),
|
|
366
|
+
children: [
|
|
367
|
+
source.title,
|
|
368
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
369
|
+
"svg",
|
|
370
|
+
{
|
|
371
|
+
className: "inline-block ml-1 w-3 h-3 opacity-60",
|
|
372
|
+
viewBox: "0 0 24 24",
|
|
373
|
+
fill: "none",
|
|
374
|
+
stroke: "currentColor",
|
|
375
|
+
strokeWidth: "2",
|
|
376
|
+
strokeLinecap: "round",
|
|
377
|
+
strokeLinejoin: "round",
|
|
378
|
+
children: [
|
|
379
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6" }),
|
|
380
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("polyline", { points: "15 3 21 3 21 9" }),
|
|
381
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "10", y1: "14", x2: "21", y2: "3" })
|
|
382
|
+
]
|
|
383
|
+
}
|
|
384
|
+
)
|
|
385
|
+
]
|
|
386
|
+
}
|
|
387
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-sm font-medium text-text-primary truncate", children: source.title }),
|
|
306
388
|
source.section && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-[11px] font-semibold uppercase tracking-wider text-text-secondary truncate mt-0.5", children: source.section })
|
|
307
389
|
] }),
|
|
308
390
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
@@ -332,7 +414,7 @@ function SourceList({
|
|
|
332
414
|
onNavigate,
|
|
333
415
|
className
|
|
334
416
|
}) {
|
|
335
|
-
const [isExpanded, setIsExpanded] = (0,
|
|
417
|
+
const [isExpanded, setIsExpanded] = (0, import_react2.useState)(defaultExpanded);
|
|
336
418
|
if (sources.length === 0) return null;
|
|
337
419
|
const content = /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex flex-col gap-1.5", "data-testid": "source-list-items", children: sources.map((source) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
338
420
|
SourceCard,
|
|
@@ -436,13 +518,16 @@ function AgentResponse({
|
|
|
436
518
|
}) {
|
|
437
519
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `flex flex-col gap-4 ${className ?? ""}`, "data-testid": "agent-response", children: [
|
|
438
520
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ResponseMessage, { content: response.message }),
|
|
439
|
-
response.ui_hint !== "text" && response.structured_data &&
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
521
|
+
response.ui_hint !== "text" && response.structured_data && (() => {
|
|
522
|
+
const parsed = typeof response.structured_data === "string" ? (() => {
|
|
523
|
+
try {
|
|
524
|
+
return JSON.parse(response.structured_data);
|
|
525
|
+
} catch {
|
|
526
|
+
return null;
|
|
527
|
+
}
|
|
528
|
+
})() : response.structured_data;
|
|
529
|
+
return parsed ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(StructuredResponse, { uiHint: response.ui_hint, data: parsed }) : null;
|
|
530
|
+
})(),
|
|
446
531
|
(showConfidence || showVerification) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-wrap items-center gap-2 mt-1", "data-testid": "response-meta", children: [
|
|
447
532
|
showConfidence && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
448
533
|
import_core2.Badge,
|