@surf-kit/agent 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/chat/index.cjs +625 -204
  2. package/dist/chat/index.cjs.map +1 -1
  3. package/dist/chat/index.d.cts +11 -6
  4. package/dist/chat/index.d.ts +11 -6
  5. package/dist/chat/index.js +606 -185
  6. package/dist/chat/index.js.map +1 -1
  7. package/dist/{chat--OifhIRe.d.ts → chat-BIIDOGrD.d.ts} +10 -1
  8. package/dist/{chat-ChYl2XjV.d.cts → chat-CGamM7Mz.d.cts} +10 -1
  9. package/dist/{hooks-DLfF18IU.d.cts → hooks-B1NYoLLs.d.cts} +21 -5
  10. package/dist/{hooks-BGs8-4GK.d.ts → hooks-CTeEqnBQ.d.ts} +21 -5
  11. package/dist/hooks.cjs +126 -81
  12. package/dist/hooks.cjs.map +1 -1
  13. package/dist/hooks.d.cts +3 -3
  14. package/dist/hooks.d.ts +3 -3
  15. package/dist/hooks.js +126 -81
  16. package/dist/hooks.js.map +1 -1
  17. package/dist/index.cjs +686 -265
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +3 -3
  20. package/dist/index.d.ts +3 -3
  21. package/dist/index.js +645 -224
  22. package/dist/index.js.map +1 -1
  23. package/dist/layouts/index.cjs +646 -225
  24. package/dist/layouts/index.cjs.map +1 -1
  25. package/dist/layouts/index.d.cts +1 -1
  26. package/dist/layouts/index.d.ts +1 -1
  27. package/dist/layouts/index.js +622 -201
  28. package/dist/layouts/index.js.map +1 -1
  29. package/dist/mcp/index.cjs +1 -1
  30. package/dist/mcp/index.cjs.map +1 -1
  31. package/dist/mcp/index.js +2 -2
  32. package/dist/mcp/index.js.map +1 -1
  33. package/dist/response/index.cjs +66 -12
  34. package/dist/response/index.cjs.map +1 -1
  35. package/dist/response/index.d.cts +2 -2
  36. package/dist/response/index.d.ts +2 -2
  37. package/dist/response/index.js +64 -10
  38. package/dist/response/index.js.map +1 -1
  39. package/dist/sources/index.cjs +30 -1
  40. package/dist/sources/index.cjs.map +1 -1
  41. package/dist/sources/index.js +30 -1
  42. package/dist/sources/index.js.map +1 -1
  43. package/dist/streaming/index.cjs +202 -93
  44. package/dist/streaming/index.cjs.map +1 -1
  45. package/dist/streaming/index.d.cts +4 -3
  46. package/dist/streaming/index.d.ts +4 -3
  47. package/dist/streaming/index.js +172 -73
  48. package/dist/streaming/index.js.map +1 -1
  49. package/dist/{streaming-DbQxScpi.d.ts → streaming-Bx-ff2tt.d.ts} +1 -1
  50. package/dist/{streaming-DfT22A0z.d.cts → streaming-x7umFHoP.d.cts} +1 -1
  51. package/package.json +15 -4
@@ -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":"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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"]}
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, Spinner } from "@surf-kit/core";
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(Spinner, { size: "sm" }) }),
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
  {
@@ -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"]}
@@ -43,6 +43,7 @@ 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);
48
49
  var import_tailwind_merge = require("tailwind-merge");
@@ -67,6 +68,7 @@ function ResponseMessage({ content, className }) {
67
68
  "[&_h3]:text-sm [&_h3]:font-semibold [&_h3]:text-accent [&_h3]:mt-2 [&_h3]:mb-1",
68
69
  "[&_code]:bg-surface-raised [&_code]:text-accent [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:rounded [&_code]:text-xs [&_code]:font-mono",
69
70
  "[&_pre]:bg-surface-raised [&_pre]:border [&_pre]:border-border [&_pre]:rounded-xl [&_pre]:p-4 [&_pre]:overflow-x-auto",
71
+ "[&_hr]:my-3 [&_hr]:border-border",
70
72
  "[&_blockquote]:border-l-2 [&_blockquote]:border-border-strong [&_blockquote]:pl-4 [&_blockquote]:text-text-secondary",
71
73
  "[&_a]:text-accent [&_a]:underline-offset-2 [&_a]:hover:text-accent/80",
72
74
  className
@@ -82,11 +84,24 @@ function ResponseMessage({ content, className }) {
82
84
  p: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "my-2", children }),
83
85
  ul: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "my-2 list-disc pl-6", children }),
84
86
  ol: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", { className: "my-2 list-decimal pl-6", children }),
85
- li: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { className: "my-1", children }),
87
+ li: ({ children, ...props }) => {
88
+ let content2 = children;
89
+ if (props.ordered) {
90
+ content2 = import_react.default.Children.map(children, (child, i) => {
91
+ if (i === 0 && typeof child === "string") {
92
+ return child.replace(/^\d+[.)]\s*/, "");
93
+ }
94
+ return child;
95
+ });
96
+ }
97
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { className: "my-1", children: content2 });
98
+ },
86
99
  strong: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { className: "font-semibold", children }),
100
+ em: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("em", { className: "italic text-text-secondary", children }),
87
101
  h1: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: "text-base font-bold mt-4 mb-2", children }),
88
102
  h2: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "text-sm font-bold mt-3 mb-1", children }),
89
103
  h3: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { className: "text-sm font-semibold mt-2 mb-1", children }),
104
+ hr: () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("hr", { className: "my-3 border-border" }),
90
105
  code: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { className: "bg-surface-sunken rounded px-1 py-0.5 text-xs font-mono", children })
91
106
  },
92
107
  children: normalizeMarkdownLists(content)
@@ -222,7 +237,14 @@ function renderWarning(data) {
222
237
  }
223
238
  );
224
239
  }
225
- function StructuredResponse({ uiHint, data, className }) {
240
+ function StructuredResponse({ uiHint, data: rawData, className }) {
241
+ const data = typeof rawData === "string" ? (() => {
242
+ try {
243
+ return JSON.parse(rawData);
244
+ } catch {
245
+ return null;
246
+ }
247
+ })() : rawData;
226
248
  if (!data) return null;
227
249
  let content;
228
250
  switch (uiHint) {
@@ -252,7 +274,7 @@ function StructuredResponse({ uiHint, data, className }) {
252
274
  }
253
275
 
254
276
  // src/sources/SourceList/SourceList.tsx
255
- var import_react = require("react");
277
+ var import_react2 = require("react");
256
278
 
257
279
  // src/sources/SourceCard/SourceCard.tsx
258
280
  var import_core = require("@surf-kit/core");
@@ -302,7 +324,36 @@ function SourceCard({ source, variant = "compact", onNavigate, className }) {
302
324
  children: [
303
325
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-start justify-between gap-2", children: [
304
326
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex-1 min-w-0", children: [
305
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-sm font-medium text-text-primary truncate", children: source.title }),
327
+ source.url ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
328
+ "a",
329
+ {
330
+ href: source.url,
331
+ target: "_blank",
332
+ rel: "noopener noreferrer",
333
+ className: "text-sm font-medium text-accent hover:underline truncate block",
334
+ onClick: (e) => e.stopPropagation(),
335
+ children: [
336
+ source.title,
337
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
338
+ "svg",
339
+ {
340
+ className: "inline-block ml-1 w-3 h-3 opacity-60",
341
+ viewBox: "0 0 24 24",
342
+ fill: "none",
343
+ stroke: "currentColor",
344
+ strokeWidth: "2",
345
+ strokeLinecap: "round",
346
+ strokeLinejoin: "round",
347
+ children: [
348
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6" }),
349
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("polyline", { points: "15 3 21 3 21 9" }),
350
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "10", y1: "14", x2: "21", y2: "3" })
351
+ ]
352
+ }
353
+ )
354
+ ]
355
+ }
356
+ ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-sm font-medium text-text-primary truncate", children: source.title }),
306
357
  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
358
  ] }),
308
359
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
@@ -332,7 +383,7 @@ function SourceList({
332
383
  onNavigate,
333
384
  className
334
385
  }) {
335
- const [isExpanded, setIsExpanded] = (0, import_react.useState)(defaultExpanded);
386
+ const [isExpanded, setIsExpanded] = (0, import_react2.useState)(defaultExpanded);
336
387
  if (sources.length === 0) return null;
337
388
  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
389
  SourceCard,
@@ -436,13 +487,16 @@ function AgentResponse({
436
487
  }) {
437
488
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `flex flex-col gap-4 ${className ?? ""}`, "data-testid": "agent-response", children: [
438
489
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ResponseMessage, { content: response.message }),
439
- response.ui_hint !== "text" && response.structured_data && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
440
- StructuredResponse,
441
- {
442
- uiHint: response.ui_hint,
443
- data: response.structured_data
444
- }
445
- ),
490
+ response.ui_hint !== "text" && response.structured_data && (() => {
491
+ const parsed = typeof response.structured_data === "string" ? (() => {
492
+ try {
493
+ return JSON.parse(response.structured_data);
494
+ } catch {
495
+ return null;
496
+ }
497
+ })() : response.structured_data;
498
+ return parsed ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(StructuredResponse, { uiHint: response.ui_hint, data: parsed }) : null;
499
+ })(),
446
500
  (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
501
  showConfidence && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
448
502
  import_core2.Badge,