xiaozhi-client 1.9.1 → 1.9.2-beta.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-ukaaLbQN.js","sources":["../../src/services/api.ts","../../src/services/websocket.ts","../../src/stores/status.ts","../../src/hooks/useRestartNotifications.ts","../../src/lib/utils.ts","../../src/components/ui/button.tsx","../../src/components/ui/input.tsx","../../src/components/ui/separator.tsx","../../src/components/ui/sheet.tsx","../../src/components/ui/skeleton.tsx","../../src/components/ui/tooltip.tsx","../../src/hooks/use-mobile.tsx","../../src/components/ui/sidebar.tsx","../../src/components/AppSidebarNav.tsx","../../src/components/AppSidebar.tsx","../../src/components/ui/badge.tsx","../../src/components/ui/alert-dialog.tsx","../../src/components/ui/dialog.tsx","../../src/stores/config.ts","../../src/components/McpEndpointSettingButton.tsx","../../src/components/ui/card.tsx","../../src/components/ui/scroll-area.tsx","../../src/components/ui/table.tsx","../../src/components/ui/tabs.tsx","../../src/utils/formatUtils.ts","../../src/components/ToolCallLogsDialog.tsx","../../src/components/ui/label.tsx","../../src/components/ui/form.tsx","../../src/stores/websocket.ts","../../src/utils/portUtils.ts","../../src/hooks/useWebSocket.ts","../../src/components/WebUrlSettingButton.tsx","../../src/components/DashboardStatusCard.tsx","../../src/components/ui/checkbox.tsx","../../src/components/ui/select.tsx","../../src/components/common/WorkflowParameterConfigDialog.tsx","../../src/utils/mcpServerUtils.ts","../../src/components/ui/textarea.tsx","../../src/components/AddMcpServerButton.tsx","../../src/services/cozeApi.ts","../../src/hooks/useCozeWorkflows.ts","../../src/components/CozeWorkflowIntegration.tsx","../../src/components/McpServerSettingButton.tsx","../../src/components/RemoveMcpServerButton.tsx","../../src/components/RestartButton.tsx","../../src/components/ui/alert.tsx","../../src/lib/schema-utils.ts","../../src/components/ToolDebugDialog.tsx","../../src/components/McpServerList.tsx","../../src/components/icons/QQ.tsx","../../src/components/icons/Github.tsx","../../src/hooks/useNPMInstall.ts","../../src/components/ui/progress.tsx","../../src/components/InstallLogDialog.tsx","../../src/components/VersionUpgradeDialog.tsx","../../src/components/VersionDisplay.tsx","../../src/components/SiteHeder.tsx","../../src/services/index.ts","../../src/hooks/useNetworkService.ts","../../src/stores/index.ts","../../src/providers/WebSocketProvider.tsx","../../src/pages/DashboardPage.tsx","../../src/components/VersionManager.tsx","../../src/pages/SettingsPage.tsx","../../src/App.tsx","../../src/main.tsx"],"sourcesContent":["/**\n * 统一的 HTTP API 客户端\n * 负责所有的配置管理、状态查询和服务控制操作\n */\n\nimport type {\n ApiErrorResponse,\n ApiSuccessResponse,\n AppConfig,\n ClientStatus,\n MCPErrorCode,\n MCPServerAddRequest,\n MCPServerConfig,\n MCPServerListResponse,\n MCPServerStatus,\n} from \"@/types\";\n\n/**\n * CustomMCPTool 接口定义\n * 对应后端的 CustomMCPTool 接口\n */\nexport interface CustomMCPTool {\n name: string;\n description: string;\n inputSchema: any;\n handler: {\n type: \"mcp\" | \"proxy\";\n platform?: \"coze\";\n config: {\n serviceName: string;\n toolName: string;\n };\n };\n stats?: {\n usageCount?: number;\n lastUsedTime?: string;\n };\n}\n\n/**\n * API 响应格式\n */\ninterface ApiResponse<T = any> {\n success: boolean;\n data?: T;\n message?: string;\n}\n\n/**\n * 服务状态接口\n */\ninterface ServiceStatus {\n running: boolean;\n mode?: string;\n pid?: number;\n}\n\n/**\n * 服务健康状态接口\n */\ninterface ServiceHealth {\n status: string;\n timestamp: number;\n uptime: number;\n memory: {\n rss: number;\n heapTotal: number;\n heapUsed: number;\n external: number;\n arrayBuffers: number;\n };\n version: string;\n}\n\n/**\n * 版本信息接口\n */\ninterface VersionInfo {\n name: string;\n version: string;\n description: string;\n author: string;\n}\n\n/**\n * 重启状态接口\n */\ninterface RestartStatus {\n status: \"restarting\" | \"completed\" | \"failed\";\n error?: string;\n timestamp: number;\n}\n\n/**\n * 接入点状态响应接口\n */\ninterface EndpointStatusResponse {\n endpoint: string;\n connected: boolean;\n initialized: boolean;\n isReconnecting: boolean;\n reconnectAttempts: number;\n nextReconnectTime?: number;\n reconnectDelay: number;\n}\n\n/**\n * 完整状态接口\n */\ninterface FullStatus {\n client: ClientStatus;\n restart?: RestartStatus;\n timestamp: number;\n}\n\n/**\n * HTTP API 客户端类\n */\nexport class ApiClient {\n private baseUrl: string;\n\n constructor(baseUrl?: string) {\n // 从当前页面 URL 推断 API 基础 URL\n if (baseUrl) {\n this.baseUrl = baseUrl;\n } else {\n const protocol = window.location.protocol;\n const hostname = window.location.hostname;\n const port = window.location.port;\n this.baseUrl = `${protocol}//${hostname}${port ? `:${port}` : \"\"}`;\n }\n }\n\n /**\n * 通用请求方法\n */\n private async request<T>(\n endpoint: string,\n options: RequestInit = {}\n ): Promise<T> {\n const url = `${this.baseUrl}${endpoint}`;\n\n const defaultOptions: RequestInit = {\n headers: {\n \"Content-Type\": \"application/json\",\n ...options.headers,\n },\n };\n\n const response = await fetch(url, { ...defaultOptions, ...options });\n\n if (!response.ok) {\n let errorMessage = `HTTP ${response.status}: ${response.statusText}`;\n\n try {\n const errorData: ApiErrorResponse = await response.json();\n errorMessage = errorData.error?.message || errorMessage;\n } catch {\n // 如果无法解析错误响应,使用默认错误消息\n }\n\n throw new Error(errorMessage);\n }\n\n return response.json();\n }\n\n // ==================== 配置管理 API ====================\n\n /**\n * 获取完整配置\n */\n async getConfig(): Promise<AppConfig> {\n const response: ApiResponse<AppConfig> = await this.request(\"/api/config\");\n if (!response.success || !response.data) {\n throw new Error(\"获取配置失败\");\n }\n return response.data;\n }\n\n /**\n * 更新配置\n */\n async updateConfig(config: AppConfig): Promise<void> {\n const response: ApiResponse = await this.request(\"/api/config\", {\n method: \"PUT\",\n body: JSON.stringify(config),\n });\n\n if (!response.success) {\n throw new Error(response.message || \"配置更新失败\");\n }\n }\n\n /**\n * 获取 MCP 端点\n */\n async getMcpEndpoint(): Promise<string> {\n const response: ApiResponse<{ endpoint: string }> = await this.request(\n \"/api/config/mcp-endpoint\"\n );\n if (!response.success || !response.data) {\n throw new Error(\"获取 MCP 端点失败\");\n }\n return response.data.endpoint;\n }\n\n /**\n * 获取 MCP 端点列表\n */\n async getMcpEndpoints(): Promise<string[]> {\n const response: ApiResponse<{ endpoints: string[] }> = await this.request(\n \"/api/config/mcp-endpoints\"\n );\n if (!response.success || !response.data) {\n throw new Error(\"获取 MCP 端点列表失败\");\n }\n return response.data.endpoints;\n }\n\n /**\n * 获取 MCP 服务配置\n */\n async getMcpServers(): Promise<Record<string, any>> {\n const response: ApiResponse<{ servers: Record<string, any> }> =\n await this.request(\"/api/config/mcp-servers\");\n if (!response.success || !response.data) {\n throw new Error(\"获取 MCP 服务配置失败\");\n }\n return response.data.servers;\n }\n\n /**\n * 获取连接配置\n */\n async getConnectionConfig(): Promise<any> {\n const response: ApiResponse<{ connection: any }> = await this.request(\n \"/api/config/connection\"\n );\n if (!response.success || !response.data) {\n throw new Error(\"获取连接配置失败\");\n }\n return response.data.connection;\n }\n\n /**\n * 重新加载配置\n */\n async reloadConfig(): Promise<AppConfig> {\n const response: ApiResponse<AppConfig> = await this.request(\n \"/api/config/reload\",\n { method: \"POST\" }\n );\n if (!response.success || !response.data) {\n throw new Error(\"重新加载配置失败\");\n }\n return response.data;\n }\n\n /**\n * 获取配置文件路径\n */\n async getConfigPath(): Promise<string> {\n const response: ApiResponse<{ path: string }> =\n await this.request(\"/api/config/path\");\n if (!response.success || !response.data) {\n throw new Error(\"获取配置文件路径失败\");\n }\n return response.data.path;\n }\n\n /**\n * 检查配置是否存在\n */\n async checkConfigExists(): Promise<boolean> {\n const response: ApiResponse<{ exists: boolean }> =\n await this.request(\"/api/config/exists\");\n if (!response.success || response.data?.exists === undefined) {\n throw new Error(\"检查配置是否存在失败\");\n }\n return response.data.exists;\n }\n\n // ==================== 状态管理 API ====================\n\n /**\n * 获取完整状态\n */\n async getStatus(): Promise<FullStatus> {\n const response: ApiResponse<FullStatus> = await this.request(\"/api/status\");\n if (!response.success || !response.data) {\n throw new Error(\"获取状态失败\");\n }\n return response.data;\n }\n\n /**\n * 获取客户端状态\n */\n async getClientStatus(): Promise<ClientStatus> {\n const response: ApiResponse<ClientStatus> =\n await this.request(\"/api/status/client\");\n if (!response.success || !response.data) {\n throw new Error(\"获取客户端状态失败\");\n }\n return response.data;\n }\n\n /**\n * 获取重启状态\n */\n async getRestartStatus(): Promise<RestartStatus | null> {\n const response: ApiResponse<RestartStatus> = await this.request(\n \"/api/status/restart\"\n );\n if (!response.success) {\n throw new Error(\"获取重启状态失败\");\n }\n return response.data || null;\n }\n\n /**\n * 检查客户端是否连接\n */\n async checkClientConnected(): Promise<boolean> {\n const response: ApiResponse<{ connected: boolean }> = await this.request(\n \"/api/status/connected\"\n );\n if (!response.success || response.data?.connected === undefined) {\n throw new Error(\"检查客户端连接失败\");\n }\n return response.data.connected;\n }\n\n /**\n * 获取最后心跳时间\n */\n async getLastHeartbeat(): Promise<number | null> {\n const response: ApiResponse<{ lastHeartbeat?: number }> =\n await this.request(\"/api/status/heartbeat\");\n if (!response.success) {\n throw new Error(\"获取最后心跳时间失败\");\n }\n return response.data?.lastHeartbeat || null;\n }\n\n /**\n * 获取活跃的 MCP 服务器列表\n */\n async getActiveMCPServers(): Promise<string[]> {\n const response: ApiResponse<{ servers: string[] }> = await this.request(\n \"/api/status/mcp-servers\"\n );\n if (!response.success || !response.data) {\n throw new Error(\"获取活跃 MCP 服务器失败\");\n }\n return response.data.servers;\n }\n\n /**\n * 更新客户端状态\n */\n async updateClientStatus(status: Partial<ClientStatus>): Promise<void> {\n const response: ApiResponse = await this.request(\"/api/status/client\", {\n method: \"PUT\",\n body: JSON.stringify(status),\n });\n\n if (!response.success) {\n throw new Error(response.message || \"更新客户端状态失败\");\n }\n }\n\n /**\n * 设置活跃的 MCP 服务器列表\n */\n async setActiveMCPServers(servers: string[]): Promise<void> {\n const response: ApiResponse = await this.request(\n \"/api/status/mcp-servers\",\n {\n method: \"PUT\",\n body: JSON.stringify({ servers }),\n }\n );\n\n if (!response.success) {\n throw new Error(response.message || \"设置活跃 MCP 服务器失败\");\n }\n }\n\n /**\n * 重置状态\n */\n async resetStatus(): Promise<void> {\n const response: ApiResponse = await this.request(\"/api/status/reset\", {\n method: \"POST\",\n });\n\n if (!response.success) {\n throw new Error(response.message || \"重置状态失败\");\n }\n }\n\n // ==================== 工具管理 API ====================\n\n /**\n * 添加自定义工具\n * 支持新的类型化格式和向后兼容的旧格式\n */\n async addCustomTool(\n workflow: any,\n customName?: string,\n customDescription?: string,\n parameterConfig?: any\n ): Promise<any>;\n\n /**\n * 添加自定义工具(新格式)\n * 支持多种工具类型:MCP 工具、Coze 工作流等\n */\n async addCustomTool(request: {\n type: \"mcp\" | \"coze\" | \"http\" | \"function\";\n data: any;\n }): Promise<any>;\n\n async addCustomTool(\n param1: any,\n customName?: string,\n customDescription?: string,\n parameterConfig?: any\n ): Promise<any> {\n // 判断是否为新格式调用\n if (typeof param1 === \"object\" && \"type\" in param1 && \"data\" in param1) {\n // 新格式:类型化请求\n const response: ApiResponse<{ tool: any }> = await this.request(\n \"/api/tools/custom\",\n {\n method: \"POST\",\n body: JSON.stringify(param1),\n }\n );\n\n if (!response.success || !response.data) {\n throw new Error(response.message || \"添加自定义工具失败\");\n }\n return response.data.tool;\n }\n // 旧格式:向后兼容\n const workflow = param1;\n const response: ApiResponse<{ tool: any }> = await this.request(\n \"/api/tools/custom\",\n {\n method: \"POST\",\n body: JSON.stringify({\n workflow,\n customName,\n customDescription,\n parameterConfig,\n }),\n }\n );\n\n if (!response.success || !response.data) {\n throw new Error(response.message || \"添加自定义工具失败\");\n }\n return response.data.tool;\n }\n\n /**\n * 更新自定义工具配置\n * @param toolName 工具名称\n * @param updateRequest 更新请求\n */\n async updateCustomTool(\n toolName: string,\n updateRequest: {\n type: \"mcp\" | \"coze\" | \"http\" | \"function\";\n data: any;\n }\n ): Promise<any> {\n const response: ApiResponse<{ tool: any }> = await this.request(\n `/api/tools/custom/${encodeURIComponent(toolName)}`,\n {\n method: \"PUT\",\n body: JSON.stringify(updateRequest),\n }\n );\n\n if (!response.success || !response.data) {\n throw new Error(response.message || \"更新自定义工具失败\");\n }\n return response.data.tool;\n }\n\n /**\n * 删除自定义工具\n */\n async removeCustomTool(toolName: string): Promise<void> {\n const response: ApiResponse = await this.request(\n `/api/tools/custom/${encodeURIComponent(toolName)}`,\n {\n method: \"DELETE\",\n }\n );\n\n if (!response.success) {\n throw new Error(response.message || \"删除自定义工具失败\");\n }\n }\n\n /**\n * 获取自定义工具列表\n */\n async getCustomTools(): Promise<any[]> {\n const response: ApiResponse<{ tools: any[] }> =\n await this.request(\"/api/tools/custom\");\n if (!response.success || !response.data) {\n throw new Error(\"获取自定义工具列表失败\");\n }\n return response.data.tools;\n }\n\n /**\n * 获取工具列表\n * 调用 /api/tools/list 端点,返回 { list: CustomMCPTool[], total: number } 格式\n * @param status 筛选状态:'enabled'(已启用)、'disabled'(未启用)、'all'(全部,默认)\n */\n async getToolsList(\n status: \"enabled\" | \"disabled\" | \"all\" = \"all\"\n ): Promise<CustomMCPTool[]> {\n // 构建查询参数\n const queryParams = new URLSearchParams();\n if (status !== \"all\") {\n queryParams.append(\"status\", status);\n }\n\n const url = `/api/tools/list${\n queryParams.toString() ? `?${queryParams.toString()}` : \"\"\n }`;\n\n const response: ApiResponse<{ list: CustomMCPTool[]; total: number }> =\n await this.request(url);\n if (!response.success || !response.data) {\n throw new Error(\"获取工具列表失败\");\n }\n return response.data.list;\n }\n\n // ==================== 服务控制 API ====================\n\n /**\n * 重启服务\n */\n async restartService(): Promise<void> {\n const response: ApiResponse = await this.request(\"/api/services/restart\", {\n method: \"POST\",\n });\n\n if (!response.success) {\n throw new Error(response.message || \"重启服务失败\");\n }\n }\n\n /**\n * 停止服务\n */\n async stopService(): Promise<void> {\n const response: ApiResponse = await this.request(\"/api/services/stop\", {\n method: \"POST\",\n });\n\n if (!response.success) {\n throw new Error(response.message || \"停止服务失败\");\n }\n }\n\n /**\n * 启动服务\n */\n async startService(): Promise<void> {\n const response: ApiResponse = await this.request(\"/api/services/start\", {\n method: \"POST\",\n });\n\n if (!response.success) {\n throw new Error(response.message || \"启动服务失败\");\n }\n }\n\n /**\n * 获取服务状态\n */\n async getServiceStatus(): Promise<ServiceStatus> {\n const response: ApiResponse<ServiceStatus> = await this.request(\n \"/api/services/status\"\n );\n if (!response.success || !response.data) {\n throw new Error(\"获取服务状态失败\");\n }\n return response.data;\n }\n\n /**\n * 获取服务健康状态\n */\n async getServiceHealth(): Promise<ServiceHealth> {\n const response: ApiResponse<ServiceHealth> = await this.request(\n \"/api/services/health\"\n );\n if (!response.success || !response.data) {\n throw new Error(\"获取服务健康状态失败\");\n }\n return response.data;\n }\n\n // ==================== 版本信息 API ====================\n\n /**\n * 获取版本信息\n */\n async getVersion(): Promise<VersionInfo> {\n const response: ApiResponse<VersionInfo> =\n await this.request(\"/api/version\");\n if (!response.success || !response.data) {\n throw new Error(\"获取版本信息失败\");\n }\n return response.data;\n }\n\n /**\n * 获取版本号(简化接口)\n */\n async getVersionSimple(): Promise<{ version: string }> {\n const response: ApiResponse<{ version: string }> = await this.request(\n \"/api/version/simple\"\n );\n if (!response.success || !response.data) {\n throw new Error(\"获取版本号失败\");\n }\n return response.data;\n }\n\n /**\n * 获取可用版本列表\n * @param type 版本类型:'stable'(正式版)、'rc'(预览版)、'beta'(测试版)、'all'(全部)\n */\n async getAvailableVersions(\n type: \"stable\" | \"rc\" | \"beta\" | \"all\" = \"stable\"\n ): Promise<{\n versions: string[];\n type: string;\n total: number;\n }> {\n // 构建查询参数\n const queryParams = new URLSearchParams();\n if (type !== \"stable\") {\n queryParams.append(\"type\", type);\n }\n\n const url = `/api/version/available${\n queryParams.toString() ? `?${queryParams.toString()}` : \"\"\n }`;\n\n const response: ApiResponse<{\n versions: string[];\n type: string;\n total: number;\n }> = await this.request(url);\n if (!response.success || !response.data) {\n throw new Error(\"获取可用版本列表失败\");\n }\n return response.data;\n }\n\n /**\n * 检查最新版本\n * 返回当前版本、最新版本以及是否有更新\n */\n async getLatestVersion(): Promise<{\n currentVersion: string;\n latestVersion: string | null;\n hasUpdate: boolean;\n error?: string;\n }> {\n const response: ApiResponse<{\n currentVersion: string;\n latestVersion: string | null;\n hasUpdate: boolean;\n error?: string;\n }> = await this.request(\"/api/version/latest\");\n\n if (!response.success || !response.data) {\n throw new Error(\"检查最新版本失败\");\n }\n\n return response.data;\n }\n\n /**\n * 清除版本缓存\n */\n async clearVersionCache(): Promise<void> {\n const response: ApiResponse = await this.request(\n \"/api/version/cache/clear\",\n {\n method: \"POST\",\n }\n );\n if (!response.success) {\n throw new Error(response.message || \"清除版本缓存失败\");\n }\n }\n\n /**\n * 更新版本\n */\n async updateVersion(version: string): Promise<any> {\n const response: ApiResponse = await this.request(\"/api/update\", {\n method: \"POST\",\n body: JSON.stringify({ version }),\n });\n\n if (!response.success) {\n throw new Error(response.message || \"版本更新失败\");\n }\n\n return response.data;\n }\n\n // ==================== 端点管理 API ====================\n\n /**\n * 获取接入点状态\n */\n async getEndpointStatus(endpoint: string): Promise<EndpointStatusResponse> {\n const response: ApiResponse<EndpointStatusResponse> = await this.request(\n \"/api/endpoint/status\",\n {\n method: \"POST\",\n body: JSON.stringify({ endpoint }),\n }\n );\n if (!response.success || !response.data) {\n throw new Error(\"获取接入点状态失败\");\n }\n return response.data;\n }\n\n /**\n * 连接接入点\n */\n async connectEndpoint(endpoint: string): Promise<void> {\n const response: ApiResponse = await this.request(\"/api/endpoint/connect\", {\n method: \"POST\",\n body: JSON.stringify({ endpoint }),\n });\n if (!response.success) {\n throw new Error(response.message || \"连接接入点失败\");\n }\n }\n\n /**\n * 断开接入点\n */\n async disconnectEndpoint(endpoint: string): Promise<void> {\n const response: ApiResponse = await this.request(\n \"/api/endpoint/disconnect\",\n { method: \"POST\", body: JSON.stringify({ endpoint }) }\n );\n if (!response.success) {\n throw new Error(response.message || \"断开接入点失败\");\n }\n }\n\n /**\n * 重连接入点\n */\n async reconnectEndpoint(endpoint: string): Promise<void> {\n const response: ApiResponse = await this.request(\n \"/api/endpoint/reconnect\",\n { method: \"POST\", body: JSON.stringify({ endpoint }) }\n );\n if (!response.success) {\n throw new Error(response.message || \"重连接入点失败\");\n }\n }\n\n /**\n * 添加新接入点\n */\n async addEndpoint(endpoint: string): Promise<EndpointStatusResponse> {\n const response: ApiResponse<EndpointStatusResponse> = await this.request(\n \"/api/endpoint/add\",\n {\n method: \"POST\",\n body: JSON.stringify({ endpoint }),\n }\n );\n if (!response.success || !response.data) {\n throw new Error(response.message || \"添加接入点失败\");\n }\n return response.data;\n }\n\n /**\n * 移除接入点\n */\n async removeEndpoint(endpoint: string): Promise<void> {\n const response: ApiResponse = await this.request(\"/api/endpoint/remove\", {\n method: \"POST\",\n body: JSON.stringify({ endpoint }),\n });\n if (!response.success) {\n throw new Error(response.message || \"移除接入点失败\");\n }\n }\n\n // ==================== MCP 服务器管理 API ====================\n\n /**\n * 添加 MCP 服务器\n * POST /api/mcp-servers\n */\n async addMCPServer(\n name: string,\n config: MCPServerConfig\n ): Promise<MCPServerStatus> {\n const requestData: MCPServerAddRequest = { name, config };\n\n const response: ApiSuccessResponse<MCPServerStatus> = await this.request(\n \"/api/mcp-servers\",\n {\n method: \"POST\",\n body: JSON.stringify(requestData),\n }\n );\n\n if (!response.success || !response.data) {\n throw new Error(response.message || \"添加 MCP 服务器失败\");\n }\n\n return response.data;\n }\n\n /**\n * 删除 MCP 服务器\n * DELETE /api/mcp-servers/:serverName\n */\n async removeMCPServer(\n serverName: string\n ): Promise<{ name: string; operation: string; affectedTools: string[] }> {\n const response: ApiSuccessResponse<{\n name: string;\n operation: string;\n affectedTools: string[];\n }> = await this.request(\n `/api/mcp-servers/${encodeURIComponent(serverName)}`,\n {\n method: \"DELETE\",\n }\n );\n\n if (!response.success || !response.data) {\n throw new Error(response.message || \"删除 MCP 服务器失败\");\n }\n\n return response.data;\n }\n\n /**\n * 获取 MCP 服务器状态\n * GET /api/mcp-servers/:serverName/status\n */\n async getMCPServerStatus(serverName: string): Promise<MCPServerStatus> {\n const response: ApiSuccessResponse<MCPServerStatus> = await this.request(\n `/api/mcp-servers/${encodeURIComponent(serverName)}/status`\n );\n\n if (!response.success || !response.data) {\n throw new Error(response.message || \"获取 MCP 服务器状态失败\");\n }\n\n return response.data;\n }\n\n /**\n * 获取所有 MCP 服务器列表\n * GET /api/mcp-servers\n */\n async listMCPServers(): Promise<MCPServerListResponse> {\n const response: ApiSuccessResponse<MCPServerListResponse> =\n await this.request(\"/api/mcp-servers\");\n\n if (!response.success || !response.data) {\n throw new Error(response.message || \"获取 MCP 服务器列表失败\");\n }\n\n return response.data;\n }\n\n /**\n * 检查 MCP 服务器是否存在\n * GET /api/mcp-servers/:serverName/exists\n */\n async checkMCPServerExists(serverName: string): Promise<boolean> {\n try {\n const response: ApiSuccessResponse<{ exists: boolean }> =\n await this.request(\n `/api/mcp-servers/${encodeURIComponent(serverName)}/exists`\n );\n\n return response.success ? response.data?.exists || false : false;\n } catch (error) {\n // 如果返回 404,说明服务器不存在\n if (error instanceof Error && error.message.includes(\"404\")) {\n return false;\n }\n throw error;\n }\n }\n\n /**\n * 更新 MCP 服务器配置\n * PUT /api/mcp-servers/:serverName\n */\n async updateMCPServer(\n serverName: string,\n config: MCPServerConfig\n ): Promise<MCPServerStatus> {\n const response: ApiSuccessResponse<MCPServerStatus> = await this.request(\n `/api/mcp-servers/${encodeURIComponent(serverName)}`,\n {\n method: \"PUT\",\n body: JSON.stringify({ config }),\n }\n );\n\n if (!response.success || !response.data) {\n throw new Error(response.message || \"更新 MCP 服务器配置失败\");\n }\n\n return response.data;\n }\n\n /**\n * 调用 MCP 工具\n * POST /api/tools/call\n */\n async callTool(\n serviceName: string,\n toolName: string,\n args: any = {}\n ): Promise<any> {\n const response: ApiResponse = await this.request(\"/api/tools/call\", {\n method: \"POST\",\n body: JSON.stringify({\n serviceName,\n toolName,\n args,\n }),\n });\n\n if (!response.success) {\n throw new Error(response.message || \"调用工具失败\");\n }\n\n return response.data;\n }\n\n /**\n * 重启 MCP 服务器\n * POST /api/mcp-servers/:serverName/restart\n */\n async restartMCPServer(serverName: string): Promise<MCPServerStatus> {\n const response: ApiSuccessResponse<MCPServerStatus> = await this.request(\n `/api/mcp-servers/${encodeURIComponent(serverName)}/restart`,\n {\n method: \"POST\",\n }\n );\n\n if (!response.success || !response.data) {\n throw new Error(response.message || \"重启 MCP 服务器失败\");\n }\n\n return response.data;\n }\n}\n\n// 创建默认的 API 客户端实例\nexport const apiClient = new ApiClient();\n\n// ==================== MCP 服务器 API 专用接口 ====================\n\n/**\n * MCP 服务器管理 API 接口\n * 提供简化的 MCP 服务器操作方法\n */\nexport const mcpServerApi = {\n /**\n * 添加 MCP 服务器\n */\n addServer: async (\n name: string,\n config: MCPServerConfig\n ): Promise<MCPServerStatus> => {\n return await apiClient.addMCPServer(name, config);\n },\n\n /**\n * 删除 MCP 服务器\n */\n removeServer: async (\n serverName: string\n ): Promise<{ name: string; operation: string; affectedTools: string[] }> => {\n return await apiClient.removeMCPServer(serverName);\n },\n\n /**\n * 获取服务器列表\n */\n listServers: async (): Promise<MCPServerListResponse> => {\n return await apiClient.listMCPServers();\n },\n\n /**\n * 获取服务器状态\n */\n getServerStatus: async (serverName: string): Promise<MCPServerStatus> => {\n return await apiClient.getMCPServerStatus(serverName);\n },\n\n /**\n * 检查服务器是否存在\n */\n serverExists: async (serverName: string): Promise<boolean> => {\n return await apiClient.checkMCPServerExists(serverName);\n },\n\n /**\n * 更新服务器配置\n */\n updateServer: async (\n serverName: string,\n config: MCPServerConfig\n ): Promise<MCPServerStatus> => {\n return await apiClient.updateMCPServer(serverName, config);\n },\n\n /**\n * 重启服务器\n */\n restartServer: async (serverName: string): Promise<MCPServerStatus> => {\n return await apiClient.restartMCPServer(serverName);\n },\n};\n\n// 导出类型\nexport type {\n ApiResponse,\n ApiErrorResponse,\n ServiceStatus,\n ServiceHealth,\n RestartStatus,\n FullStatus,\n VersionInfo,\n EndpointStatusResponse,\n MCPServerAddRequest,\n MCPServerStatus,\n MCPServerListResponse,\n ApiSuccessResponse,\n MCPErrorCode,\n};\n","/**\n * 重构后的 WebSocket 管理器\n * 特性:\n * - 严格单例模式\n * - 全局事件总线机制\n * - 完善的错误处理和重连逻辑\n * - 支持多个 store 订阅 WebSocket 事件\n */\n\nimport type { AppConfig, ClientStatus } from \"@/types/index\";\n\n/**\n * WebSocket 消息类型\n */\ninterface WebSocketMessage {\n type: string;\n data?: any;\n timestamp?: number;\n error?: {\n code: string;\n message: string;\n timestamp?: number;\n };\n}\n\n/**\n * 重启状态接口\n */\ninterface RestartStatus {\n status: \"restarting\" | \"completed\" | \"failed\";\n error?: string;\n timestamp: number;\n}\n\n/**\n * 接入点状态变更事件数据\n */\nexport interface EndpointStatusChangedEvent {\n endpoint: string;\n connected: boolean;\n operation: \"connect\" | \"disconnect\" | \"reconnect\";\n success: boolean;\n message?: string;\n timestamp: number;\n}\n\n/**\n * NPM 安装日志事件数据\n */\nexport interface NPMInstallLogEvent {\n version: string;\n installId: string;\n type: \"stdout\" | \"stderr\";\n message: string;\n timestamp: number;\n}\n\n/**\n * NPM 安装开始事件数据\n */\nexport interface NPMInstallStartedEvent {\n version: string;\n installId: string;\n timestamp: number;\n}\n\n/**\n * NPM 安装完成事件数据\n */\nexport interface NPMInstallCompletedEvent {\n version: string;\n installId: string;\n success: boolean;\n duration: number;\n timestamp: number;\n}\n\n/**\n * NPM 安装失败事件数据\n */\nexport interface NPMInstallFailedEvent {\n version: string;\n installId: string;\n error: string;\n duration: number;\n timestamp: number;\n}\n\n/**\n * 事件总线事件类型\n */\ninterface EventBusEvents {\n // 连接状态事件\n \"connection:connecting\": undefined;\n \"connection:connected\": undefined;\n \"connection:disconnected\": undefined;\n \"connection:reconnecting\": { attempt: number; maxAttempts: number };\n \"connection:error\": { error: Error; context?: string };\n\n // 数据更新事件\n \"data:configUpdate\": AppConfig;\n \"data:statusUpdate\": ClientStatus;\n \"data:restartStatus\": RestartStatus;\n\n // 接入点状态事件\n \"data:endpointStatusChanged\": EndpointStatusChangedEvent;\n\n // NPM 安装事件\n \"data:npmInstallStarted\": NPMInstallStartedEvent;\n \"data:npmInstallLog\": NPMInstallLogEvent;\n \"data:npmInstallCompleted\": NPMInstallCompletedEvent;\n \"data:npmInstallFailed\": NPMInstallFailedEvent;\n\n // 系统事件\n \"system:heartbeat\": { timestamp: number };\n \"system:message\": WebSocketMessage;\n \"system:error\": { error: Error; message?: WebSocketMessage };\n}\n\n/**\n * 事件监听器类型\n */\ntype EventListener<T = any> = (data: T) => void;\n\n/**\n * WebSocket 事件监听器类型(向后兼容)\n */\ninterface WebSocketEventListeners {\n connected: () => void;\n disconnected: () => void;\n configUpdate: (config: AppConfig) => void;\n statusUpdate: (status: ClientStatus) => void;\n restartStatus: (status: RestartStatus) => void;\n error: (error: Error) => void;\n}\n\n/**\n * WebSocket 连接状态\n */\nenum ConnectionState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n RECONNECTING = \"reconnecting\",\n}\n\n/**\n * WebSocket 管理器配置\n */\ninterface WebSocketManagerConfig {\n url?: string;\n reconnectInterval?: number;\n maxReconnectAttempts?: number;\n heartbeatInterval?: number;\n heartbeatTimeout?: number;\n}\n\n/**\n * 事件总线类 - 支持多个订阅者\n */\nclass EventBus {\n private listeners: Map<string, Set<EventListener>> = new Map();\n\n /**\n * 订阅事件\n */\n on<K extends keyof EventBusEvents>(\n event: K,\n listener: EventListener<EventBusEvents[K]>\n ): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener);\n\n // 返回取消订阅函数\n return () => {\n this.off(event, listener);\n };\n }\n\n /**\n * 取消订阅事件\n */\n off<K extends keyof EventBusEvents>(\n event: K,\n listener: EventListener<EventBusEvents[K]>\n ): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.delete(listener);\n if (eventListeners.size === 0) {\n this.listeners.delete(event);\n }\n }\n }\n\n /**\n * 发布事件\n */\n emit<K extends keyof EventBusEvents>(\n event: K,\n data: EventBusEvents[K]\n ): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n for (const listener of eventListeners) {\n try {\n listener(data);\n } catch (error) {\n console.error(`[EventBus] 事件监听器执行失败 (${event}):`, error);\n }\n }\n }\n }\n\n /**\n * 清除所有监听器\n */\n clear(): void {\n this.listeners.clear();\n }\n\n /**\n * 获取事件监听器数量\n */\n getListenerCount(event?: keyof EventBusEvents): number {\n if (event) {\n return this.listeners.get(event)?.size || 0;\n }\n return Array.from(this.listeners.values()).reduce(\n (total, listeners) => total + listeners.size,\n 0\n );\n }\n}\n\n/**\n * WebSocket 管理器类 - 严格单例模式\n */\nexport class WebSocketManager {\n private static instance: WebSocketManager | null = null;\n private static isCreating = false;\n\n private ws: WebSocket | null = null;\n private url: string;\n private state: ConnectionState = ConnectionState.DISCONNECTED;\n private eventBus: EventBus = new EventBus();\n private legacyListeners: Partial<WebSocketEventListeners> = {};\n private reconnectAttempts = 0;\n private maxReconnectAttempts: number;\n private reconnectInterval: number;\n private reconnectTimer?: NodeJS.Timeout;\n private heartbeatTimer?: NodeJS.Timeout;\n private heartbeatInterval: number;\n private heartbeatTimeout: number;\n private lastHeartbeat = 0;\n\n private constructor(config: WebSocketManagerConfig = {}) {\n this.url = config.url || this.getDefaultWebSocketUrl();\n this.maxReconnectAttempts = config.maxReconnectAttempts || 5;\n this.reconnectInterval = config.reconnectInterval || 3000;\n this.heartbeatInterval = config.heartbeatInterval || 30000; // 30秒\n this.heartbeatTimeout = config.heartbeatTimeout || 35000; // 35秒\n\n // 设置向后兼容的事件桥接\n this.setupLegacyEventBridge();\n }\n\n /**\n * 获取单例实例\n */\n static getInstance(config?: WebSocketManagerConfig): WebSocketManager {\n if (WebSocketManager.instance) {\n return WebSocketManager.instance;\n }\n\n if (WebSocketManager.isCreating) {\n throw new Error(\"[WebSocketManager] 检测到循环创建,请检查代码逻辑\");\n }\n\n WebSocketManager.isCreating = true;\n try {\n WebSocketManager.instance = new WebSocketManager(config);\n console.log(\"[WebSocketManager] 单例实例已创建\");\n return WebSocketManager.instance;\n } finally {\n WebSocketManager.isCreating = false;\n }\n }\n\n /**\n * 重置单例实例(仅用于测试)\n */\n static resetInstance(): void {\n if (WebSocketManager.instance) {\n WebSocketManager.instance.disconnect();\n WebSocketManager.instance.eventBus.clear();\n WebSocketManager.instance = null;\n console.log(\"[WebSocketManager] 单例实例已重置\");\n }\n }\n\n /**\n * 设置向后兼容的事件桥接\n */\n private setupLegacyEventBridge(): void {\n // 连接状态事件桥接\n this.eventBus.on(\"connection:connected\", () => {\n this.legacyListeners.connected?.();\n });\n\n this.eventBus.on(\"connection:disconnected\", () => {\n this.legacyListeners.disconnected?.();\n });\n\n this.eventBus.on(\"connection:error\", ({ error }) => {\n this.legacyListeners.error?.(error);\n });\n\n // 数据更新事件桥接\n this.eventBus.on(\"data:configUpdate\", (config) => {\n this.legacyListeners.configUpdate?.(config);\n });\n\n this.eventBus.on(\"data:statusUpdate\", (status) => {\n this.legacyListeners.statusUpdate?.(status);\n });\n\n this.eventBus.on(\"data:restartStatus\", (status) => {\n this.legacyListeners.restartStatus?.(status);\n });\n }\n\n /**\n * 获取默认的 WebSocket URL\n */\n private getDefaultWebSocketUrl(): string {\n // 从 localStorage 获取自定义 URL\n const savedUrl = localStorage.getItem(\"xiaozhi-ws-url\");\n if (savedUrl) {\n return savedUrl;\n }\n\n // 根据当前页面 URL 构建 WebSocket URL\n const protocol = window.location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n const hostname = window.location.hostname;\n // FIXME: 这里需要通过开发模式显式处理,否则用户如果设置5173端口,会导致强制变成9999端口\n const port = window.location.port === \"5173\" ? 9999 : window.location.port;\n return `${protocol}//${hostname}${port ? `:${port}` : \"\"}`;\n }\n\n /**\n * 连接 WebSocket\n */\n connect(): void {\n if (\n this.state === ConnectionState.CONNECTED ||\n this.state === ConnectionState.CONNECTING\n ) {\n return;\n }\n\n this.state = ConnectionState.CONNECTING;\n console.log(`[WebSocket] 连接到: ${this.url}`);\n\n // 发布连接中事件\n this.eventBus.emit(\"connection:connecting\", undefined);\n\n try {\n this.ws = new WebSocket(this.url);\n this.setupEventHandlers();\n } catch (error) {\n console.error(\"[WebSocket] 连接失败:\", error);\n this.handleConnectionError(error as Error);\n }\n }\n\n /**\n * 断开 WebSocket 连接\n */\n disconnect(): void {\n console.log(\"[WebSocket] 主动断开连接\");\n\n this.clearTimers();\n this.state = ConnectionState.DISCONNECTED;\n this.reconnectAttempts = 0;\n\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n }\n\n /**\n * 新的事件订阅方法 - 使用事件总线\n */\n subscribe<K extends keyof EventBusEvents>(\n event: K,\n listener: EventListener<EventBusEvents[K]>\n ): () => void {\n return this.eventBus.on(event, listener);\n }\n\n /**\n * 取消事件订阅\n */\n unsubscribe<K extends keyof EventBusEvents>(\n event: K,\n listener: EventListener<EventBusEvents[K]>\n ): void {\n this.eventBus.off(event, listener);\n }\n\n /**\n * 获取事件总线实例(用于高级用法)\n */\n getEventBus(): EventBus {\n return this.eventBus;\n }\n\n /**\n * 设置事件监听器(向后兼容)\n * @deprecated 使用 subscribe 方法替代\n */\n on<K extends keyof WebSocketEventListeners>(\n event: K,\n listener: WebSocketEventListeners[K]\n ): void {\n console.warn(\"[WebSocketManager] on() 方法已废弃,请使用 subscribe() 方法\");\n this.legacyListeners[event] = listener;\n }\n\n /**\n * 移除事件监听器(向后兼容)\n * @deprecated 使用 unsubscribe 方法替代\n */\n off<K extends keyof WebSocketEventListeners>(event: K): void {\n console.warn(\n \"[WebSocketManager] off() 方法已废弃,请使用 unsubscribe() 方法\"\n );\n delete this.legacyListeners[event];\n }\n\n /**\n * 获取连接状态\n */\n getState(): ConnectionState {\n return this.state;\n }\n\n /**\n * 检查是否已连接\n */\n isConnected(): boolean {\n return (\n this.state === ConnectionState.CONNECTED &&\n this.ws?.readyState === WebSocket.OPEN\n );\n }\n\n /**\n * 更新 WebSocket URL\n */\n setUrl(url: string): void {\n if (this.url !== url) {\n this.url = url;\n localStorage.setItem(\"xiaozhi-ws-url\", url);\n\n // 如果当前已连接,重新连接到新 URL\n if (this.isConnected()) {\n this.disconnect();\n setTimeout(() => this.connect(), 1000);\n }\n }\n }\n\n /**\n * 发送消息\n */\n send(message: any): boolean {\n if (!this.isConnected()) {\n console.warn(\"[WebSocket] 连接未建立,无法发送消息\");\n return false;\n }\n\n try {\n const messageStr =\n typeof message === \"string\" ? message : JSON.stringify(message);\n this.ws!.send(messageStr);\n return true;\n } catch (error) {\n console.error(\"[WebSocket] 发送消息失败:\", error);\n this.eventBus.emit(\"connection:error\", {\n error: error as Error,\n context: \"send_message\",\n });\n return false;\n }\n }\n\n /**\n * 获取当前 URL\n */\n getUrl(): string {\n return this.url;\n }\n\n /**\n * 获取连接统计信息\n */\n getConnectionStats() {\n return {\n state: this.state,\n url: this.url,\n reconnectAttempts: this.reconnectAttempts,\n maxReconnectAttempts: this.maxReconnectAttempts,\n lastHeartbeat: this.lastHeartbeat,\n eventListenerCount: this.eventBus.getListenerCount(),\n };\n }\n\n /**\n * 设置 WebSocket 事件处理器\n */\n private setupEventHandlers(): void {\n if (!this.ws) return;\n\n this.ws.onopen = () => {\n console.log(\"[WebSocket] 连接已建立\");\n this.state = ConnectionState.CONNECTED;\n this.reconnectAttempts = 0;\n this.startHeartbeat();\n\n // 发布连接成功事件\n this.eventBus.emit(\"connection:connected\", undefined);\n };\n\n this.ws.onmessage = (event) => {\n try {\n const message: WebSocketMessage = JSON.parse(event.data);\n this.handleMessage(message);\n } catch (error) {\n console.error(\"[WebSocket] 消息解析失败:\", error);\n }\n };\n\n this.ws.onclose = (event) => {\n console.log(`[WebSocket] 连接已关闭 (code: ${event.code})`);\n this.handleConnectionClose();\n };\n\n this.ws.onerror = (error) => {\n console.error(\"[WebSocket] 连接错误:\", error);\n this.handleConnectionError(new Error(\"WebSocket 连接错误\"));\n };\n }\n\n /**\n * 处理 WebSocket 消息\n */\n private handleMessage(message: WebSocketMessage): void {\n console.log(\"[WebSocket] 收到消息:\", message.type);\n\n // 发布原始消息事件\n this.eventBus.emit(\"system:message\", message);\n\n try {\n switch (message.type) {\n case \"configUpdate\":\n case \"config\":\n if (message.data) {\n this.eventBus.emit(\"data:configUpdate\", message.data);\n }\n break;\n\n case \"statusUpdate\":\n case \"status\":\n if (message.data) {\n this.eventBus.emit(\"data:statusUpdate\", message.data);\n }\n break;\n\n case \"restartStatus\":\n if (message.data) {\n this.eventBus.emit(\"data:restartStatus\", message.data);\n }\n break;\n\n case \"endpoint_status_changed\":\n if (message.data) {\n this.eventBus.emit(\"data:endpointStatusChanged\", message.data);\n }\n break;\n\n case \"npm:install:started\":\n if (message.data) {\n this.eventBus.emit(\"data:npmInstallStarted\", message.data);\n }\n break;\n\n case \"npm:install:log\":\n if (message.data) {\n this.eventBus.emit(\"data:npmInstallLog\", message.data);\n }\n break;\n\n case \"npm:install:completed\":\n if (message.data) {\n this.eventBus.emit(\"data:npmInstallCompleted\", message.data);\n }\n break;\n\n case \"npm:install:failed\":\n if (message.data) {\n this.eventBus.emit(\"data:npmInstallFailed\", message.data);\n }\n break;\n\n case \"heartbeatResponse\":\n this.lastHeartbeat = Date.now();\n this.eventBus.emit(\"system:heartbeat\", {\n timestamp: this.lastHeartbeat,\n });\n break;\n\n case \"error\": {\n const error = new Error(message.error?.message || \"服务器错误\");\n console.error(\"[WebSocket] 服务器错误:\", message.error);\n this.eventBus.emit(\"system:error\", { error, message });\n this.eventBus.emit(\"connection:error\", {\n error,\n context: \"server_error\",\n });\n break;\n }\n\n default:\n console.log(\"[WebSocket] 未处理的消息类型:\", message.type);\n }\n } catch (error) {\n console.error(\"[WebSocket] 消息处理失败:\", error);\n this.eventBus.emit(\"system:error\", {\n error: error as Error,\n message,\n });\n }\n }\n\n /**\n * 处理连接关闭\n */\n private handleConnectionClose(): void {\n this.state = ConnectionState.DISCONNECTED;\n this.clearTimers();\n\n // 发布连接断开事件\n this.eventBus.emit(\"connection:disconnected\", undefined);\n\n // 如果不是主动断开连接,尝试重连\n if (this.reconnectAttempts < this.maxReconnectAttempts) {\n this.scheduleReconnect();\n } else {\n console.error(\"[WebSocket] 达到最大重连次数,停止重连\");\n this.eventBus.emit(\"connection:error\", {\n error: new Error(\"达到最大重连次数\"),\n context: \"max_reconnect_attempts\",\n });\n }\n }\n\n /**\n * 处理连接错误\n */\n private handleConnectionError(error: Error): void {\n this.state = ConnectionState.DISCONNECTED;\n this.clearTimers();\n\n // 发布连接错误事件\n this.eventBus.emit(\"connection:error\", {\n error,\n context: \"connection_error\",\n });\n\n // 尝试重连\n if (this.reconnectAttempts < this.maxReconnectAttempts) {\n this.scheduleReconnect();\n } else {\n console.error(\"[WebSocket] 达到最大重连次数,停止重连\");\n }\n }\n\n /**\n * 安排重连\n */\n private scheduleReconnect(): void {\n this.reconnectAttempts++;\n this.state = ConnectionState.RECONNECTING;\n\n console.log(\n `[WebSocket] 安排重连 (${this.reconnectAttempts}/${this.maxReconnectAttempts}) 在 ${this.reconnectInterval}ms 后`\n );\n\n // 发布重连事件\n this.eventBus.emit(\"connection:reconnecting\", {\n attempt: this.reconnectAttempts,\n maxAttempts: this.maxReconnectAttempts,\n });\n\n this.reconnectTimer = setTimeout(() => {\n this.connect();\n }, this.reconnectInterval);\n }\n\n /**\n * 开始心跳检测\n */\n private startHeartbeat(): void {\n this.lastHeartbeat = Date.now();\n\n this.heartbeatTimer = setInterval(() => {\n if (this.isConnected()) {\n // 发送心跳消息\n this.sendHeartbeat();\n\n // 检查心跳超时\n const now = Date.now();\n if (now - this.lastHeartbeat > this.heartbeatTimeout) {\n console.warn(\"[WebSocket] 心跳超时,重新连接\");\n this.disconnect();\n this.connect();\n }\n }\n }, this.heartbeatInterval);\n }\n\n /**\n * 发送心跳消息\n */\n private sendHeartbeat(): void {\n if (this.isConnected()) {\n const heartbeatMessage = {\n type: \"clientStatus\",\n data: {\n status: \"connected\" as const,\n timestamp: Date.now(),\n },\n };\n\n this.ws?.send(JSON.stringify(heartbeatMessage));\n }\n }\n\n /**\n * 清理定时器\n */\n private clearTimers(): void {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = undefined;\n }\n }\n}\n\n// 创建默认的 WebSocket 管理器实例(使用单例模式)\nexport const webSocketManager = WebSocketManager.getInstance();\n\n// 导出类型和枚举\nexport { ConnectionState };\nexport type {\n WebSocketMessage,\n RestartStatus,\n WebSocketEventListeners,\n WebSocketManagerConfig,\n};\n","/**\n * 状态数据统一管理 Store\n *\n * 特性:\n * - 支持定时轮询和 WebSocket 实时更新\n * - 提供异步方法:getStatus()、refreshStatus()、restartService()\n * - 管理重启状态和服务状态\n * - 使用 Zustand 进行状态管理\n * - 提供选择器 hooks 优化组件渲染\n * - 集成 WebSocket 事件监听\n */\n\nimport type { ClientStatus } from \"@/types/index\";\nimport { apiClient } from \"@services/api\";\nimport { webSocketManager } from \"@services/websocket\";\nimport { create } from \"zustand\";\nimport { devtools } from \"zustand/middleware\";\nimport { useShallow } from \"zustand/react/shallow\";\n\n/**\n * 重启状态接口\n */\ninterface RestartStatus {\n status: \"restarting\" | \"completed\" | \"failed\";\n error?: string;\n timestamp: number;\n}\n\n/**\n * 服务状态接口\n */\ninterface ServiceStatus {\n running: boolean;\n mode?: string;\n pid?: number;\n}\n\n/**\n * 服务健康状态接口\n */\ninterface ServiceHealth {\n status: string;\n timestamp: number;\n uptime: number;\n memory: {\n rss: number;\n heapTotal: number;\n heapUsed: number;\n external: number;\n arrayBuffers: number;\n };\n version: string;\n}\n\n/**\n * 完整状态接口\n */\ninterface FullStatus {\n client: ClientStatus;\n restart?: RestartStatus;\n timestamp: number;\n}\n\n/**\n * 状态加载状态\n */\ninterface StatusLoadingState {\n isLoading: boolean;\n isRefreshing: boolean;\n isRestarting: boolean;\n lastUpdated: number | null;\n lastError: Error | null;\n}\n\n/**\n * 轮询配置\n */\ninterface PollingConfig {\n enabled: boolean;\n interval: number; // 毫秒\n maxRetries: number;\n currentRetries: number;\n}\n\n/**\n * 重启轮询配置\n */\ninterface RestartPollingConfig {\n enabled: boolean;\n interval: number; // 毫秒,重启检查间隔\n maxAttempts: number; // 最大检查次数\n currentAttempts: number; // 当前检查次数\n timeout: number; // 总超时时间(毫秒)\n startTime: number | null; // 开始时间戳\n}\n\n/**\n * 状态 Store 状态\n */\ninterface StatusState {\n // 状态数据\n clientStatus: ClientStatus | null;\n restartStatus: RestartStatus | null;\n serviceStatus: ServiceStatus | null;\n serviceHealth: ServiceHealth | null;\n fullStatus: FullStatus | null;\n\n // 加载状态\n loading: StatusLoadingState;\n\n // 轮询配置\n polling: PollingConfig;\n\n // 重启轮询配置\n restartPolling: RestartPollingConfig;\n\n // 状态来源追踪\n lastSource: \"http\" | \"websocket\" | \"polling\" | \"initial\" | null;\n}\n\n/**\n * 状态 Store 操作方法\n */\ninterface StatusActions {\n // 基础操作\n setClientStatus: (\n status: ClientStatus,\n source?: \"http\" | \"websocket\" | \"polling\" | \"initial\"\n ) => void;\n setRestartStatus: (\n status: RestartStatus | null,\n source?: \"http\" | \"websocket\" | \"polling\" | \"initial\"\n ) => void;\n setServiceStatus: (status: ServiceStatus) => void;\n setServiceHealth: (health: ServiceHealth) => void;\n setFullStatus: (\n status: FullStatus,\n source?: \"http\" | \"websocket\" | \"polling\" | \"initial\"\n ) => void;\n setLoading: (loading: Partial<StatusLoadingState>) => void;\n setError: (error: Error | null) => void;\n\n // 异步操作\n getStatus: () => Promise<FullStatus>;\n refreshStatus: () => Promise<FullStatus>;\n restartService: () => Promise<void>;\n getServiceStatus: () => Promise<ServiceStatus>;\n getServiceHealth: () => Promise<ServiceHealth>;\n\n // 轮询控制\n startPolling: (interval?: number) => void;\n stopPolling: () => void;\n setPollingConfig: (config: Partial<PollingConfig>) => void;\n\n // 重启轮询控制\n startRestartPolling: () => void;\n stopRestartPolling: () => void;\n setRestartPollingConfig: (config: Partial<RestartPollingConfig>) => void;\n\n // 工具方法\n reset: () => void;\n initialize: () => Promise<void>;\n}\n\n/**\n * 完整的状态 Store 接口\n */\nexport interface StatusStore extends StatusState, StatusActions {}\n\n/**\n * 初始状态\n */\nconst initialState: StatusState = {\n clientStatus: null,\n restartStatus: null,\n serviceStatus: null,\n serviceHealth: null,\n fullStatus: null,\n loading: {\n isLoading: false,\n isRefreshing: false,\n isRestarting: false,\n lastUpdated: null,\n lastError: null,\n },\n polling: {\n enabled: false,\n interval: 30000, // 30秒\n maxRetries: 3,\n currentRetries: 0,\n },\n restartPolling: {\n enabled: false,\n interval: 1000, // 1秒检查间隔\n maxAttempts: 60, // 最多检查60次(60秒)\n currentAttempts: 0,\n timeout: 60000, // 60秒总超时\n startTime: null,\n },\n lastSource: null,\n};\n\n/**\n * 轮询定时器引用\n */\nlet pollingTimer: NodeJS.Timeout | null = null;\n\n/**\n * 重启轮询定时器引用\n */\nlet restartPollingTimer: NodeJS.Timeout | null = null;\n\n/**\n * 创建状态 Store\n */\nexport const useStatusStore = create<StatusStore>()(\n devtools(\n (set, get) => ({\n ...initialState,\n\n // ==================== 基础操作 ====================\n\n setClientStatus: (status: ClientStatus, source = \"http\") => {\n console.log(`[StatusStore] 设置客户端状态,来源: ${source}`);\n set(\n (state) => ({\n clientStatus: status,\n lastSource: source,\n loading: {\n ...state.loading,\n lastUpdated: Date.now(),\n lastError: null,\n },\n }),\n false,\n \"setClientStatus\"\n );\n },\n\n setRestartStatus: (status: RestartStatus | null, source = \"http\") => {\n console.log(`[StatusStore] 设置重启状态,来源: ${source}`);\n set(\n (state) => ({\n restartStatus: status,\n lastSource: source,\n loading: {\n ...state.loading,\n lastUpdated: Date.now(),\n lastError: null,\n },\n }),\n false,\n \"setRestartStatus\"\n );\n },\n\n setServiceStatus: (status: ServiceStatus) => {\n console.log(\"[StatusStore] 设置服务状态\");\n set({ serviceStatus: status }, false, \"setServiceStatus\");\n },\n\n setServiceHealth: (health: ServiceHealth) => {\n console.log(\"[StatusStore] 设置服务健康状态\");\n set({ serviceHealth: health }, false, \"setServiceHealth\");\n },\n\n setFullStatus: (status: FullStatus, source = \"http\") => {\n console.log(`[StatusStore] 设置完整状态,来源: ${source}`);\n set(\n (state) => ({\n fullStatus: status,\n clientStatus: status.client,\n restartStatus: status.restart || null,\n lastSource: source,\n loading: {\n ...state.loading,\n lastUpdated: Date.now(),\n lastError: null,\n },\n }),\n false,\n \"setFullStatus\"\n );\n },\n\n setLoading: (loading: Partial<StatusLoadingState>) => {\n set(\n (state) => ({\n loading: { ...state.loading, ...loading },\n }),\n false,\n \"setLoading\"\n );\n },\n\n setError: (error: Error | null) => {\n set(\n (state) => ({\n loading: { ...state.loading, lastError: error },\n }),\n false,\n \"setError\"\n );\n },\n\n // ==================== 异步操作 ====================\n\n getStatus: async (): Promise<FullStatus> => {\n const { fullStatus, loading } = get();\n\n // 如果已有状态且不超过30秒,直接返回\n if (\n fullStatus &&\n loading.lastUpdated &&\n Date.now() - loading.lastUpdated < 30 * 1000\n ) {\n return fullStatus;\n }\n\n // 否则从服务器获取最新状态\n return get().refreshStatus();\n },\n\n refreshStatus: async (): Promise<FullStatus> => {\n const { setLoading, setFullStatus, setError, polling } = get();\n\n try {\n setLoading({ isRefreshing: true, lastError: null });\n console.log(\"[StatusStore] 开始刷新状态\");\n\n // 从服务器获取最新状态\n const status = await apiClient.getStatus();\n\n // 更新本地状态\n setFullStatus(status, \"http\");\n\n // 重置轮询重试计数\n if (polling.enabled) {\n get().setPollingConfig({ currentRetries: 0 });\n }\n\n console.log(\"[StatusStore] 状态刷新成功\");\n return status;\n } catch (error) {\n const err =\n error instanceof Error ? error : new Error(\"状态刷新失败\");\n console.error(\"[StatusStore] 状态刷新失败:\", err);\n setError(err);\n\n // 增加轮询重试计数\n if (polling.enabled) {\n const newRetries = polling.currentRetries + 1;\n get().setPollingConfig({ currentRetries: newRetries });\n\n // 如果达到最大重试次数,停止轮询\n if (newRetries >= polling.maxRetries) {\n console.warn(\"[StatusStore] 达到最大重试次数,停止轮询\");\n get().stopPolling();\n }\n }\n\n throw err;\n } finally {\n setLoading({ isRefreshing: false });\n }\n },\n\n restartService: async (): Promise<void> => {\n const { setLoading, setRestartStatus, setError, startRestartPolling } =\n get();\n\n try {\n setLoading({ isRestarting: true, lastError: null });\n console.log(\"[StatusStore] 开始重启服务\");\n\n // 设置重启状态\n setRestartStatus(\n {\n status: \"restarting\",\n timestamp: Date.now(),\n },\n \"http\"\n );\n\n // 调用重启 API\n await apiClient.restartService();\n\n console.log(\"[StatusStore] 服务重启请求已发送,开始重连检查\");\n\n // 启动重启后的重连检查轮询\n startRestartPolling();\n } catch (error) {\n const err =\n error instanceof Error ? error : new Error(\"服务重启失败\");\n console.error(\"[StatusStore] 服务重启失败:\", err);\n\n // 设置重启失败状态\n setRestartStatus(\n {\n status: \"failed\",\n error: err.message,\n timestamp: Date.now(),\n },\n \"http\"\n );\n\n setError(err);\n setLoading({ isRestarting: false });\n throw err;\n }\n },\n\n getServiceStatus: async (): Promise<ServiceStatus> => {\n try {\n console.log(\"[StatusStore] 获取服务状态\");\n const status = await apiClient.getServiceStatus();\n get().setServiceStatus(status);\n return status;\n } catch (error) {\n const err =\n error instanceof Error ? error : new Error(\"获取服务状态失败\");\n console.error(\"[StatusStore] 获取服务状态失败:\", err);\n get().setError(err);\n throw err;\n }\n },\n\n getServiceHealth: async (): Promise<ServiceHealth> => {\n try {\n console.log(\"[StatusStore] 获取服务健康状态\");\n const health = await apiClient.getServiceHealth();\n get().setServiceHealth(health);\n return health;\n } catch (error) {\n const err =\n error instanceof Error ? error : new Error(\"获取服务健康状态失败\");\n console.error(\"[StatusStore] 获取服务健康状态失败:\", err);\n get().setError(err);\n throw err;\n }\n },\n\n // ==================== 轮询控制 ====================\n\n startPolling: (interval = 30000) => {\n const { polling, refreshStatus } = get();\n\n if (polling.enabled) {\n console.log(\"[StatusStore] 轮询已启用,跳过启动\");\n return;\n }\n\n console.log(`[StatusStore] 启动状态轮询,间隔: ${interval}ms`);\n\n set(\n (state) => ({\n polling: {\n ...state.polling,\n enabled: true,\n interval,\n currentRetries: 0,\n },\n }),\n false,\n \"startPolling\"\n );\n\n // 立即执行一次刷新\n refreshStatus().catch((error) => {\n console.error(\"[StatusStore] 轮询初始刷新失败:\", error);\n });\n\n // 设置定时器\n pollingTimer = setInterval(() => {\n const currentState = get();\n if (!currentState.polling.enabled) {\n return;\n }\n\n refreshStatus().catch((error) => {\n console.error(\"[StatusStore] 轮询刷新失败:\", error);\n });\n }, interval);\n },\n\n stopPolling: () => {\n console.log(\"[StatusStore] 停止状态轮询\");\n\n set(\n (state) => ({\n polling: {\n ...state.polling,\n enabled: false,\n currentRetries: 0,\n },\n }),\n false,\n \"stopPolling\"\n );\n\n if (pollingTimer) {\n clearInterval(pollingTimer);\n pollingTimer = null;\n }\n },\n\n setPollingConfig: (config: Partial<PollingConfig>) => {\n set(\n (state) => ({\n polling: { ...state.polling, ...config },\n }),\n false,\n \"setPollingConfig\"\n );\n },\n\n // ==================== 重启轮询控制 ====================\n\n startRestartPolling: () => {\n const { restartPolling, refreshStatus, setRestartStatus, setLoading } =\n get();\n\n if (restartPolling.enabled) {\n console.log(\"[StatusStore] 重启轮询已启用,跳过启动\");\n return;\n }\n\n console.log(\"[StatusStore] 启动重启后重连检查轮询\");\n\n const startTime = Date.now();\n set(\n (state) => ({\n restartPolling: {\n ...state.restartPolling,\n enabled: true,\n currentAttempts: 0,\n startTime,\n },\n }),\n false,\n \"startRestartPolling\"\n );\n\n // 设置定时器进行重连检查\n restartPollingTimer = setInterval(async () => {\n const currentState = get();\n const { restartPolling: currentRestartPolling } = currentState;\n\n if (!currentRestartPolling.enabled) {\n return;\n }\n\n const elapsed = Date.now() - (currentRestartPolling.startTime || 0);\n const attempts = currentRestartPolling.currentAttempts + 1;\n\n console.log(\n `[StatusStore] 重启重连检查 (第 ${attempts} 次,已用时 ${Math.round(elapsed / 1000)}s)`\n );\n\n try {\n // 尝试获取状态以检查服务是否重连成功\n const status = await refreshStatus();\n\n // 检查是否重连成功\n const isReconnected = status.client?.status === \"connected\";\n\n if (isReconnected) {\n console.log(\"[StatusStore] 服务重连成功,停止重启轮询\");\n\n // 设置重启完成状态\n setRestartStatus(\n {\n status: \"completed\",\n timestamp: Date.now(),\n },\n \"polling\"\n );\n\n // 停止重启轮询和loading状态\n currentState.stopRestartPolling();\n setLoading({ isRestarting: false });\n return;\n }\n\n // 更新尝试次数\n currentState.setRestartPollingConfig({ currentAttempts: attempts });\n\n // 检查是否超时或达到最大尝试次数\n if (\n elapsed >= currentRestartPolling.timeout ||\n attempts >= currentRestartPolling.maxAttempts\n ) {\n console.warn(\"[StatusStore] 重启重连检查超时或达到最大尝试次数\");\n\n // 设置重启失败状态\n setRestartStatus(\n {\n status: \"failed\",\n error: \"重连超时,服务可能未成功重启\",\n timestamp: Date.now(),\n },\n \"polling\"\n );\n\n // 停止重启轮询和loading状态\n currentState.stopRestartPolling();\n setLoading({ isRestarting: false });\n }\n } catch (error) {\n console.log(\n `[StatusStore] 重启重连检查失败 (第 ${attempts} 次):`,\n error\n );\n\n // 更新尝试次数\n currentState.setRestartPollingConfig({ currentAttempts: attempts });\n\n // 检查是否超时或达到最大尝试次数\n if (\n elapsed >= currentRestartPolling.timeout ||\n attempts >= currentRestartPolling.maxAttempts\n ) {\n console.error(\"[StatusStore] 重启重连检查超时或达到最大尝试次数\");\n\n // 设置重启失败状态\n setRestartStatus(\n {\n status: \"failed\",\n error: \"重连超时,服务可能未成功重启\",\n timestamp: Date.now(),\n },\n \"polling\"\n );\n\n // 停止重启轮询和loading状态\n currentState.stopRestartPolling();\n setLoading({ isRestarting: false });\n }\n }\n }, restartPolling.interval);\n },\n\n stopRestartPolling: () => {\n console.log(\"[StatusStore] 停止重启轮询\");\n\n set(\n (state) => ({\n restartPolling: {\n ...state.restartPolling,\n enabled: false,\n currentAttempts: 0,\n startTime: null,\n },\n }),\n false,\n \"stopRestartPolling\"\n );\n\n if (restartPollingTimer) {\n clearInterval(restartPollingTimer);\n restartPollingTimer = null;\n }\n },\n\n setRestartPollingConfig: (config: Partial<RestartPollingConfig>) => {\n set(\n (state) => ({\n restartPolling: { ...state.restartPolling, ...config },\n }),\n false,\n \"setRestartPollingConfig\"\n );\n },\n\n // ==================== 工具方法 ====================\n\n reset: () => {\n console.log(\"[StatusStore] 重置状态\");\n\n // 停止所有轮询\n get().stopPolling();\n get().stopRestartPolling();\n\n // 重置状态\n set(initialState, false, \"reset\");\n },\n\n initialize: async (): Promise<void> => {\n const { setLoading, refreshStatus } = get();\n\n try {\n setLoading({ isLoading: true });\n console.log(\"[StatusStore] 初始化状态 Store\");\n\n // 设置 WebSocket 事件监听\n webSocketManager.subscribe(\"data:statusUpdate\", (status) => {\n console.log(\"[StatusStore] 收到 WebSocket 状态更新\");\n get().setClientStatus(status, \"websocket\");\n });\n\n webSocketManager.subscribe(\"data:restartStatus\", (status) => {\n console.log(\"[StatusStore] 收到 WebSocket 重启状态更新\");\n get().setRestartStatus(status, \"websocket\");\n });\n\n // 获取初始状态\n await refreshStatus();\n\n // 启动轮询(可选)\n // get().startPolling();\n\n console.log(\"[StatusStore] 状态 Store 初始化完成\");\n } catch (error) {\n console.error(\"[StatusStore] 状态 Store 初始化失败:\", error);\n throw error;\n } finally {\n setLoading({ isLoading: false });\n }\n },\n }),\n {\n name: \"status-store\",\n }\n )\n);\n\n// ==================== 选择器 Hooks ====================\n\n/**\n * 获取客户端状态\n */\nexport const useClientStatus = () =>\n useStatusStore((state) => state.clientStatus);\n\n/**\n * 获取重启状态\n */\nexport const useRestartStatus = () =>\n useStatusStore((state) => state.restartStatus);\n\n/**\n * 获取服务状态\n */\nexport const useServiceStatus = () =>\n useStatusStore((state) => state.serviceStatus);\n\n/**\n * 获取服务健康状态\n */\nexport const useServiceHealth = () =>\n useStatusStore((state) => state.serviceHealth);\n\n/**\n * 获取完整状态\n */\nexport const useFullStatus = () => useStatusStore((state) => state.fullStatus);\n\n/**\n * 获取状态加载状态\n */\nexport const useStatusLoading = () => useStatusStore((state) => state.loading);\n\n/**\n * 获取状态是否正在加载\n */\nexport const useStatusIsLoading = () =>\n useStatusStore(\n (state) => state.loading.isLoading || state.loading.isRefreshing\n );\n\n/**\n * 获取状态是否正在重启\n */\nexport const useStatusIsRestarting = () =>\n useStatusStore((state) => state.loading.isRestarting);\n\n/**\n * 获取状态错误\n */\nexport const useStatusError = () =>\n useStatusStore((state) => state.loading.lastError);\n\n/**\n * 获取轮询配置\n */\nexport const usePollingConfig = () => useStatusStore((state) => state.polling);\n\n/**\n * 获取轮询是否启用\n */\nexport const usePollingEnabled = () =>\n useStatusStore((state) => state.polling.enabled);\n\n/**\n * 获取重启轮询状态\n */\nexport const useRestartPollingStatus = () =>\n useStatusStore((state) => state.restartPolling);\n\n/**\n * 获取状态来源\n */\nexport const useStatusSource = () =>\n useStatusStore((state) => state.lastSource);\n\n/**\n * 获取连接状态(从客户端状态中提取)\n */\nexport const useConnectionStatus = () =>\n useStatusStore((state) => state.clientStatus?.status === \"connected\");\n\n/**\n * 获取 MCP 端点(从客户端状态中提取)\n */\nexport const useStatusMcpEndpoint = () =>\n useStatusStore((state) => state.clientStatus?.mcpEndpoint);\n\n/**\n * 获取活跃的 MCP 服务器(从客户端状态中提取)\n */\nexport const useActiveMcpServers = () =>\n useStatusStore((state) => state.clientStatus?.activeMCPServers || []);\n\n/**\n * 获取最后心跳时间(从客户端状态中提取)\n */\nexport const useLastHeartbeat = () =>\n useStatusStore((state) => state.clientStatus?.lastHeartbeat);\n\n// ==================== 复合选择器 ====================\n\n/**\n * 获取状态数据和加载状态\n */\nexport const useStatusWithLoading = () =>\n useStatusStore(\n useShallow((state) => ({\n clientStatus: state.clientStatus,\n restartStatus: state.restartStatus,\n fullStatus: state.fullStatus,\n isLoading: state.loading.isLoading || state.loading.isRefreshing,\n isRestarting: state.loading.isRestarting,\n error: state.loading.lastError,\n }))\n );\n\n/**\n * 获取服务相关状态\n */\nexport const useServiceInfo = () =>\n useStatusStore(\n useShallow((state) => ({\n status: state.serviceStatus,\n health: state.serviceHealth,\n isRestarting: state.loading.isRestarting,\n restartStatus: state.restartStatus,\n }))\n );\n\n/**\n * 获取连接相关信息\n */\nexport const useConnectionInfo = () =>\n useStatusStore(\n useShallow((state) => ({\n connected: state.clientStatus?.status === \"connected\",\n endpoint: state.clientStatus?.mcpEndpoint,\n activeServers: state.clientStatus?.activeMCPServers || [],\n lastHeartbeat: state.clientStatus?.lastHeartbeat,\n }))\n );\n\n// ==================== 操作方法 Hooks ====================\n\n/**\n * 获取状态操作方法\n */\nexport const useStatusActions = () =>\n useStatusStore(\n useShallow((state) => ({\n getStatus: state.getStatus,\n refreshStatus: state.refreshStatus,\n restartService: state.restartService,\n getServiceStatus: state.getServiceStatus,\n getServiceHealth: state.getServiceHealth,\n startPolling: state.startPolling,\n stopPolling: state.stopPolling,\n setPollingConfig: state.setPollingConfig,\n startRestartPolling: state.startRestartPolling,\n stopRestartPolling: state.stopRestartPolling,\n setRestartPollingConfig: state.setRestartPollingConfig,\n reset: state.reset,\n initialize: state.initialize,\n }))\n );\n\n/**\n * 获取轮询控制方法\n */\nexport const usePollingActions = () =>\n useStatusStore(\n useShallow((state) => ({\n startPolling: state.startPolling,\n stopPolling: state.stopPolling,\n setPollingConfig: state.setPollingConfig,\n enabled: state.polling.enabled,\n interval: state.polling.interval,\n }))\n );\n","/**\n * 重启通知管理 Hook\n *\n * 职责:\n * - 监听重启状态变化\n * - 在适当时机显示 toast 通知\n * - 避免重复通知\n * - 提供一致的用户体验\n */\n\nimport { useRestartPollingStatus, useRestartStatus } from \"@/stores/status\";\nimport { useEffect, useRef } from \"react\";\nimport { toast } from \"sonner\";\n\n/**\n * 重启通知管理 Hook\n *\n * 使用方式:\n * 1. 在应用的根组件或布局组件中调用\n * 2. 自动监听重启状态变化并显示相应通知\n * 3. 确保全局只有一个实例在运行\n */\nexport function useRestartNotifications() {\n const restartStatus = useRestartStatus();\n const restartPollingStatus = useRestartPollingStatus();\n\n // 使用 ref 来跟踪已显示的通知,避免重复\n const lastNotifiedStatus = useRef<string | null>(null);\n const lastNotifiedTimestamp = useRef<number | null>(null);\n\n useEffect(() => {\n if (!restartStatus) {\n return;\n }\n\n const { status, timestamp, error } = restartStatus;\n\n // 避免重复通知:检查状态和时间戳是否已经通知过\n if (\n lastNotifiedStatus.current === status &&\n lastNotifiedTimestamp.current === timestamp\n ) {\n return;\n }\n\n // 更新已通知的状态\n lastNotifiedStatus.current = status;\n lastNotifiedTimestamp.current = timestamp;\n\n switch (status) {\n case \"restarting\":\n // 重启开始时的通知(可选,根据需要启用)\n toast.info(\"正在重启服务...\", {\n id: \"restart-status-progress\", // 使用固定ID避免重复\n description: \"请耐心等待\",\n duration: 0,\n });\n break;\n\n case \"completed\": {\n // 重启成功通知\n const successMessage = restartPollingStatus.enabled\n ? `服务重启成功!重连检查完成 (${restartPollingStatus.currentAttempts}次检查)`\n : \"服务重启成功!\";\n\n toast.dismiss(\"restart-status-progress\");\n toast.success(successMessage, {\n id: \"restart-status-success\", // 替换之前的通知\n description: \"服务已恢复正常运行\",\n });\n break;\n }\n\n case \"failed\": {\n // 重启失败通知\n const failureMessage = error || \"服务重启失败\";\n const description = restartPollingStatus.enabled\n ? `重连检查超时 (${restartPollingStatus.currentAttempts}/${restartPollingStatus.maxAttempts}次)`\n : \"请检查服务状态或稍后重试\";\n\n toast.dismiss(\"restart-status-progress\");\n toast.error(failureMessage, {\n id: \"restart-status-failed\", // 替换之前的通知\n description,\n });\n break;\n }\n }\n }, [restartStatus, restartPollingStatus]);\n\n // 清理函数:组件卸载时清理状态\n useEffect(() => {\n return () => {\n lastNotifiedStatus.current = null;\n lastNotifiedTimestamp.current = null;\n };\n }, []);\n}\n\n/**\n * 重启通知提供者组件\n *\n * 使用方式:在应用根组件中使用\n * <RestartNotificationProvider />\n */\nexport function RestartNotificationProvider() {\n useRestartNotifications();\n return null; // 这是一个纯逻辑组件,不渲染任何内容\n}\n","import type { ClassValue } from \"clsx\";\nimport { clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import { Slot } from \"@radix-ui/react-slot\";\nimport { type VariantProps, cva } from \"class-variance-authority\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\n outline:\n \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-10 px-4 py-2\",\n sm: \"h-9 rounded-md px-3\",\n lg: \"h-11 rounded-md px-8\",\n icon: \"h-10 w-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean;\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n className={cn(buttonVariants({ variant, size, className }))}\n ref={ref}\n {...props}\n />\n );\n }\n);\nButton.displayName = \"Button\";\n\nexport { Button, buttonVariants };\n","import * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst Input = React.forwardRef<HTMLInputElement, React.ComponentProps<\"input\">>(\n ({ className, type, ...props }, ref) => {\n return (\n <input\n type={type}\n className={cn(\n \"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm\",\n className\n )}\n ref={ref}\n data-1p-ignore\n {...props}\n />\n );\n }\n);\nInput.displayName = \"Input\";\n\nexport { Input };\n","import * as SeparatorPrimitive from \"@radix-ui/react-separator\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst Separator = React.forwardRef<\n React.ElementRef<typeof SeparatorPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>\n>(\n (\n { className, orientation = \"horizontal\", decorative = true, ...props },\n ref\n ) => (\n <SeparatorPrimitive.Root\n ref={ref}\n decorative={decorative}\n orientation={orientation}\n className={cn(\n \"shrink-0 bg-border\",\n orientation === \"horizontal\" ? \"h-[1px] w-full\" : \"h-full w-[1px]\",\n className\n )}\n {...props}\n />\n )\n);\nSeparator.displayName = SeparatorPrimitive.Root.displayName;\n\nexport { Separator };\n","\"use client\";\n\nimport * as SheetPrimitive from \"@radix-ui/react-dialog\";\nimport { type VariantProps, cva } from \"class-variance-authority\";\nimport { X } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst Sheet = SheetPrimitive.Root;\n\nconst SheetTrigger = SheetPrimitive.Trigger;\n\nconst SheetClose = SheetPrimitive.Close;\n\nconst SheetPortal = SheetPrimitive.Portal;\n\nconst SheetOverlay = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Overlay\n className={cn(\n \"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className\n )}\n {...props}\n ref={ref}\n />\n));\nSheetOverlay.displayName = SheetPrimitive.Overlay.displayName;\n\nconst sheetVariants = cva(\n \"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500\",\n {\n variants: {\n side: {\n top: \"inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top\",\n bottom:\n \"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom\",\n left: \"inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm\",\n right:\n \"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm\",\n },\n },\n defaultVariants: {\n side: \"right\",\n },\n }\n);\n\ninterface SheetContentProps\n extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,\n VariantProps<typeof sheetVariants> {}\n\nconst SheetContent = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Content>,\n SheetContentProps\n>(({ side = \"right\", className, children, ...props }, ref) => (\n <SheetPortal>\n <SheetOverlay />\n <SheetPrimitive.Content\n ref={ref}\n className={cn(sheetVariants({ side }), className)}\n {...props}\n >\n {children}\n <SheetPrimitive.Close className=\"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary\">\n <X className=\"h-4 w-4\" />\n <span className=\"sr-only\">Close</span>\n </SheetPrimitive.Close>\n </SheetPrimitive.Content>\n </SheetPortal>\n));\nSheetContent.displayName = SheetPrimitive.Content.displayName;\n\nconst SheetHeader = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col space-y-2 text-center sm:text-left\",\n className\n )}\n {...props}\n />\n);\nSheetHeader.displayName = \"SheetHeader\";\n\nconst SheetFooter = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n className\n )}\n {...props}\n />\n);\nSheetFooter.displayName = \"SheetFooter\";\n\nconst SheetTitle = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Title\n ref={ref}\n className={cn(\"text-lg font-semibold text-foreground\", className)}\n {...props}\n />\n));\nSheetTitle.displayName = SheetPrimitive.Title.displayName;\n\nconst SheetDescription = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nSheetDescription.displayName = SheetPrimitive.Description.displayName;\n\nexport {\n Sheet,\n SheetPortal,\n SheetOverlay,\n SheetTrigger,\n SheetClose,\n SheetContent,\n SheetHeader,\n SheetFooter,\n SheetTitle,\n SheetDescription,\n};\n","import { cn } from \"@/lib/utils\";\n\nfunction Skeleton({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n className={cn(\"animate-pulse rounded-md bg-muted\", className)}\n {...props}\n />\n );\n}\n\nexport { Skeleton };\n","import * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst TooltipProvider = TooltipPrimitive.Provider;\n\nconst Tooltip = TooltipPrimitive.Root;\n\nconst TooltipTrigger = TooltipPrimitive.Trigger;\n\nconst TooltipContent = React.forwardRef<\n React.ElementRef<typeof TooltipPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n \"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin]\",\n className\n )}\n {...props}\n />\n));\nTooltipContent.displayName = TooltipPrimitive.Content.displayName;\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };\n","import * as React from \"react\";\n\nconst MOBILE_BREAKPOINT = 768;\n\nexport function useIsMobile() {\n const [isMobile, setIsMobile] = React.useState<boolean | undefined>(\n undefined\n );\n\n React.useEffect(() => {\n const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);\n const onChange = () => {\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n };\n mql.addEventListener(\"change\", onChange);\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n return () => mql.removeEventListener(\"change\", onChange);\n }, []);\n\n return !!isMobile;\n}\n","\"use client\";\n\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { type VariantProps, cva } from \"class-variance-authority\";\nimport { PanelLeft } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Separator } from \"@/components/ui/separator\";\nimport {\n Sheet,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n} from \"@/components/ui/sheet\";\nimport { Skeleton } from \"@/components/ui/skeleton\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { useIsMobile } from \"@/hooks/use-mobile\";\nimport { cn } from \"@/lib/utils\";\n\nconst SIDEBAR_COOKIE_NAME = \"sidebar_state\";\nconst SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;\nconst SIDEBAR_WIDTH = \"16rem\";\nconst SIDEBAR_WIDTH_MOBILE = \"18rem\";\nconst SIDEBAR_WIDTH_ICON = \"3rem\";\nconst SIDEBAR_KEYBOARD_SHORTCUT = \"b\";\n\ntype SidebarContextProps = {\n state: \"expanded\" | \"collapsed\";\n open: boolean;\n setOpen: (open: boolean) => void;\n openMobile: boolean;\n setOpenMobile: (open: boolean) => void;\n isMobile: boolean;\n toggleSidebar: () => void;\n};\n\nconst SidebarContext = React.createContext<SidebarContextProps | null>(null);\n\nfunction useSidebar() {\n const context = React.useContext(SidebarContext);\n if (!context) {\n throw new Error(\"useSidebar must be used within a SidebarProvider.\");\n }\n\n return context;\n}\n\nconst SidebarProvider = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\"> & {\n defaultOpen?: boolean;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n }\n>(\n (\n {\n defaultOpen = true,\n open: openProp,\n onOpenChange: setOpenProp,\n className,\n style,\n children,\n ...props\n },\n ref\n ) => {\n const isMobile = useIsMobile();\n const [openMobile, setOpenMobile] = React.useState(false);\n\n // This is the internal state of the sidebar.\n // We use openProp and setOpenProp for control from outside the component.\n const [_open, _setOpen] = React.useState(defaultOpen);\n const open = openProp ?? _open;\n const setOpen = React.useCallback(\n (value: boolean | ((value: boolean) => boolean)) => {\n const openState = typeof value === \"function\" ? value(open) : value;\n if (setOpenProp) {\n setOpenProp(openState);\n } else {\n _setOpen(openState);\n }\n\n // This sets the cookie to keep the sidebar state.\n document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;\n },\n [setOpenProp, open]\n );\n\n // Helper to toggle the sidebar.\n const toggleSidebar = React.useCallback(() => {\n return isMobile\n ? setOpenMobile((open) => !open)\n : setOpen((open) => !open);\n }, [isMobile, setOpen]);\n\n // Adds a keyboard shortcut to toggle the sidebar.\n React.useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (\n event.key === SIDEBAR_KEYBOARD_SHORTCUT &&\n (event.metaKey || event.ctrlKey)\n ) {\n event.preventDefault();\n toggleSidebar();\n }\n };\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [toggleSidebar]);\n\n // We add a state so that we can do data-state=\"expanded\" or \"collapsed\".\n // This makes it easier to style the sidebar with Tailwind classes.\n const state = open ? \"expanded\" : \"collapsed\";\n\n const contextValue = React.useMemo<SidebarContextProps>(\n () => ({\n state,\n open,\n setOpen,\n isMobile,\n openMobile,\n setOpenMobile,\n toggleSidebar,\n }),\n [state, open, setOpen, isMobile, openMobile, toggleSidebar]\n );\n\n return (\n <SidebarContext.Provider value={contextValue}>\n <TooltipProvider delayDuration={0}>\n <div\n style={\n {\n \"--sidebar-width\": SIDEBAR_WIDTH,\n \"--sidebar-width-icon\": SIDEBAR_WIDTH_ICON,\n ...style,\n } as React.CSSProperties\n }\n className={cn(\n \"group/sidebar-wrapper flex min-h-svh w-full has-[[data-variant=inset]]:bg-sidebar\",\n className\n )}\n ref={ref}\n {...props}\n >\n {children}\n </div>\n </TooltipProvider>\n </SidebarContext.Provider>\n );\n }\n);\nSidebarProvider.displayName = \"SidebarProvider\";\n\nconst Sidebar = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\"> & {\n side?: \"left\" | \"right\";\n variant?: \"sidebar\" | \"floating\" | \"inset\";\n collapsible?: \"offcanvas\" | \"icon\" | \"none\";\n }\n>(\n (\n {\n side = \"left\",\n variant = \"sidebar\",\n collapsible = \"offcanvas\",\n className,\n children,\n ...props\n },\n ref\n ) => {\n const { isMobile, state, openMobile, setOpenMobile } = useSidebar();\n\n if (collapsible === \"none\") {\n return (\n <div\n className={cn(\n \"flex h-full w-[--sidebar-width] flex-col bg-sidebar text-sidebar-foreground\",\n className\n )}\n ref={ref}\n {...props}\n >\n {children}\n </div>\n );\n }\n\n if (isMobile) {\n return (\n <Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>\n <SheetContent\n data-sidebar=\"sidebar\"\n data-mobile=\"true\"\n className=\"w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden\"\n style={\n {\n \"--sidebar-width\": SIDEBAR_WIDTH_MOBILE,\n } as React.CSSProperties\n }\n side={side}\n >\n <SheetHeader className=\"sr-only\">\n <SheetTitle>Sidebar</SheetTitle>\n <SheetDescription>Displays the mobile sidebar.</SheetDescription>\n </SheetHeader>\n <div className=\"flex h-full w-full flex-col\">{children}</div>\n </SheetContent>\n </Sheet>\n );\n }\n\n return (\n <div\n ref={ref}\n className=\"group peer hidden text-sidebar-foreground md:block\"\n data-state={state}\n data-collapsible={state === \"collapsed\" ? collapsible : \"\"}\n data-variant={variant}\n data-side={side}\n >\n {/* This is what handles the sidebar gap on desktop */}\n <div\n className={cn(\n \"relative w-[--sidebar-width] bg-transparent transition-[width] duration-200 ease-linear\",\n \"group-data-[collapsible=offcanvas]:w-0\",\n \"group-data-[side=right]:rotate-180\",\n variant === \"floating\" || variant === \"inset\"\n ? \"group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]\"\n : \"group-data-[collapsible=icon]:w-[--sidebar-width-icon]\"\n )}\n />\n <div\n className={cn(\n \"fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width] transition-[left,right,width] duration-200 ease-linear md:flex\",\n side === \"left\"\n ? \"left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]\"\n : \"right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]\",\n // Adjust the padding for floating and inset variants.\n variant === \"floating\" || variant === \"inset\"\n ? \"p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]\"\n : \"group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l\",\n className\n )}\n {...props}\n >\n <div\n data-sidebar=\"sidebar\"\n className=\"flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow\"\n >\n {children}\n </div>\n </div>\n </div>\n );\n }\n);\nSidebar.displayName = \"Sidebar\";\n\nconst SidebarTrigger = React.forwardRef<\n React.ElementRef<typeof Button>,\n React.ComponentProps<typeof Button>\n>(({ className, onClick, ...props }, ref) => {\n const { toggleSidebar } = useSidebar();\n\n return (\n <Button\n ref={ref}\n data-sidebar=\"trigger\"\n variant=\"ghost\"\n size=\"icon\"\n className={cn(\"h-7 w-7\", className)}\n onClick={(event) => {\n onClick?.(event);\n toggleSidebar();\n }}\n {...props}\n >\n <PanelLeft />\n <span className=\"sr-only\">Toggle Sidebar</span>\n </Button>\n );\n});\nSidebarTrigger.displayName = \"SidebarTrigger\";\n\nconst SidebarRail = React.forwardRef<\n HTMLButtonElement,\n React.ComponentProps<\"button\">\n>(({ className, ...props }, ref) => {\n const { toggleSidebar } = useSidebar();\n\n return (\n <button\n ref={ref}\n data-sidebar=\"rail\"\n aria-label=\"Toggle Sidebar\"\n tabIndex={-1}\n onClick={toggleSidebar}\n title=\"Toggle Sidebar\"\n className={cn(\n \"absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] hover:after:bg-sidebar-border group-data-[side=left]:-right-4 group-data-[side=right]:left-0 sm:flex\",\n \"[[data-side=left]_&]:cursor-w-resize [[data-side=right]_&]:cursor-e-resize\",\n \"[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize\",\n \"group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full group-data-[collapsible=offcanvas]:hover:bg-sidebar\",\n \"[[data-side=left][data-collapsible=offcanvas]_&]:-right-2\",\n \"[[data-side=right][data-collapsible=offcanvas]_&]:-left-2\",\n className\n )}\n {...props}\n />\n );\n});\nSidebarRail.displayName = \"SidebarRail\";\n\nconst SidebarInset = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"main\">\n>(({ className, ...props }, ref) => {\n return (\n <main\n ref={ref}\n className={cn(\n \"relative flex w-full flex-1 flex-col bg-background\",\n \"md:peer-data-[variant=inset]:m-2 md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow\",\n className\n )}\n {...props}\n />\n );\n});\nSidebarInset.displayName = \"SidebarInset\";\n\nconst SidebarInput = React.forwardRef<\n React.ElementRef<typeof Input>,\n React.ComponentProps<typeof Input>\n>(({ className, ...props }, ref) => {\n return (\n <Input\n ref={ref}\n data-sidebar=\"input\"\n className={cn(\n \"h-8 w-full bg-background shadow-none focus-visible:ring-2 focus-visible:ring-sidebar-ring\",\n className\n )}\n {...props}\n />\n );\n});\nSidebarInput.displayName = \"SidebarInput\";\n\nconst SidebarHeader = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\">\n>(({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-sidebar=\"header\"\n className={cn(\"flex flex-col gap-2 p-2\", className)}\n {...props}\n />\n );\n});\nSidebarHeader.displayName = \"SidebarHeader\";\n\nconst SidebarFooter = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\">\n>(({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-sidebar=\"footer\"\n className={cn(\"flex flex-col gap-2 p-2\", className)}\n {...props}\n />\n );\n});\nSidebarFooter.displayName = \"SidebarFooter\";\n\nconst SidebarSeparator = React.forwardRef<\n React.ElementRef<typeof Separator>,\n React.ComponentProps<typeof Separator>\n>(({ className, ...props }, ref) => {\n return (\n <Separator\n ref={ref}\n data-sidebar=\"separator\"\n className={cn(\"mx-2 w-auto bg-sidebar-border\", className)}\n {...props}\n />\n );\n});\nSidebarSeparator.displayName = \"SidebarSeparator\";\n\nconst SidebarContent = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\">\n>(({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-sidebar=\"content\"\n className={cn(\n \"flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden\",\n className\n )}\n {...props}\n />\n );\n});\nSidebarContent.displayName = \"SidebarContent\";\n\nconst SidebarGroup = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\">\n>(({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-sidebar=\"group\"\n className={cn(\"relative flex w-full min-w-0 flex-col p-2\", className)}\n {...props}\n />\n );\n});\nSidebarGroup.displayName = \"SidebarGroup\";\n\nconst SidebarGroupLabel = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\"> & { asChild?: boolean }\n>(({ className, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"div\";\n\n return (\n <Comp\n ref={ref}\n data-sidebar=\"group-label\"\n className={cn(\n \"flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 outline-none ring-sidebar-ring transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0\",\n \"group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0\",\n className\n )}\n {...props}\n />\n );\n});\nSidebarGroupLabel.displayName = \"SidebarGroupLabel\";\n\nconst SidebarGroupAction = React.forwardRef<\n HTMLButtonElement,\n React.ComponentProps<\"button\"> & { asChild?: boolean }\n>(({ className, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\";\n\n return (\n <Comp\n ref={ref}\n data-sidebar=\"group-action\"\n className={cn(\n \"absolute right-3 top-3.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0\",\n // Increases the hit area of the button on mobile.\n \"after:absolute after:-inset-2 after:md:hidden\",\n \"group-data-[collapsible=icon]:hidden\",\n className\n )}\n {...props}\n />\n );\n});\nSidebarGroupAction.displayName = \"SidebarGroupAction\";\n\nconst SidebarGroupContent = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\">\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n data-sidebar=\"group-content\"\n className={cn(\"w-full text-sm\", className)}\n {...props}\n />\n));\nSidebarGroupContent.displayName = \"SidebarGroupContent\";\n\nconst SidebarMenu = React.forwardRef<\n HTMLUListElement,\n React.ComponentProps<\"ul\">\n>(({ className, ...props }, ref) => (\n <ul\n ref={ref}\n data-sidebar=\"menu\"\n className={cn(\"flex w-full min-w-0 flex-col gap-1\", className)}\n {...props}\n />\n));\nSidebarMenu.displayName = \"SidebarMenu\";\n\nconst SidebarMenuItem = React.forwardRef<\n HTMLLIElement,\n React.ComponentProps<\"li\">\n>(({ className, ...props }, ref) => (\n <li\n ref={ref}\n data-sidebar=\"menu-item\"\n className={cn(\"group/menu-item relative\", className)}\n {...props}\n />\n));\nSidebarMenuItem.displayName = \"SidebarMenuItem\";\n\nconst sidebarMenuButtonVariants = cva(\n \"peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"hover:bg-sidebar-accent hover:text-sidebar-accent-foreground\",\n outline:\n \"bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]\",\n },\n size: {\n default: \"h-8 text-sm\",\n sm: \"h-7 text-xs\",\n lg: \"h-12 text-sm group-data-[collapsible=icon]:!p-0\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n);\n\nconst SidebarMenuButton = React.forwardRef<\n HTMLButtonElement,\n React.ComponentProps<\"button\"> & {\n asChild?: boolean;\n isActive?: boolean;\n tooltip?: string | React.ComponentProps<typeof TooltipContent>;\n } & VariantProps<typeof sidebarMenuButtonVariants>\n>(\n (\n {\n asChild = false,\n isActive = false,\n variant = \"default\",\n size = \"default\",\n tooltip,\n className,\n ...props\n },\n ref\n ) => {\n const Comp = asChild ? Slot : \"button\";\n const { isMobile, state } = useSidebar();\n\n const button = (\n <Comp\n ref={ref}\n data-sidebar=\"menu-button\"\n data-size={size}\n data-active={isActive}\n className={cn(sidebarMenuButtonVariants({ variant, size }), className)}\n {...props}\n />\n );\n\n if (!tooltip) {\n return button;\n }\n\n if (typeof tooltip === \"string\") {\n tooltip = {\n children: tooltip,\n };\n }\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>{button}</TooltipTrigger>\n <TooltipContent\n side=\"right\"\n align=\"center\"\n hidden={state !== \"collapsed\" || isMobile}\n {...tooltip}\n />\n </Tooltip>\n );\n }\n);\nSidebarMenuButton.displayName = \"SidebarMenuButton\";\n\nconst SidebarMenuAction = React.forwardRef<\n HTMLButtonElement,\n React.ComponentProps<\"button\"> & {\n asChild?: boolean;\n showOnHover?: boolean;\n }\n>(({ className, asChild = false, showOnHover = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\";\n\n return (\n <Comp\n ref={ref}\n data-sidebar=\"menu-action\"\n className={cn(\n \"absolute right-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 peer-hover/menu-button:text-sidebar-accent-foreground [&>svg]:size-4 [&>svg]:shrink-0\",\n // Increases the hit area of the button on mobile.\n \"after:absolute after:-inset-2 after:md:hidden\",\n \"peer-data-[size=sm]/menu-button:top-1\",\n \"peer-data-[size=default]/menu-button:top-1.5\",\n \"peer-data-[size=lg]/menu-button:top-2.5\",\n \"group-data-[collapsible=icon]:hidden\",\n showOnHover &&\n \"group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground md:opacity-0\",\n className\n )}\n {...props}\n />\n );\n});\nSidebarMenuAction.displayName = \"SidebarMenuAction\";\n\nconst SidebarMenuBadge = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\">\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n data-sidebar=\"menu-badge\"\n className={cn(\n \"pointer-events-none absolute right-1 flex h-5 min-w-5 select-none items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums text-sidebar-foreground\",\n \"peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground\",\n \"peer-data-[size=sm]/menu-button:top-1\",\n \"peer-data-[size=default]/menu-button:top-1.5\",\n \"peer-data-[size=lg]/menu-button:top-2.5\",\n \"group-data-[collapsible=icon]:hidden\",\n className\n )}\n {...props}\n />\n));\nSidebarMenuBadge.displayName = \"SidebarMenuBadge\";\n\nconst SidebarMenuSkeleton = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\"> & {\n showIcon?: boolean;\n }\n>(({ className, showIcon = false, ...props }, ref) => {\n // Random width between 50 to 90%.\n const width = React.useMemo(() => {\n return `${Math.floor(Math.random() * 40) + 50}%`;\n }, []);\n\n return (\n <div\n ref={ref}\n data-sidebar=\"menu-skeleton\"\n className={cn(\"flex h-8 items-center gap-2 rounded-md px-2\", className)}\n {...props}\n >\n {showIcon && (\n <Skeleton\n className=\"size-4 rounded-md\"\n data-sidebar=\"menu-skeleton-icon\"\n />\n )}\n <Skeleton\n className=\"h-4 max-w-[--skeleton-width] flex-1\"\n data-sidebar=\"menu-skeleton-text\"\n style={\n {\n \"--skeleton-width\": width,\n } as React.CSSProperties\n }\n />\n </div>\n );\n});\nSidebarMenuSkeleton.displayName = \"SidebarMenuSkeleton\";\n\nconst SidebarMenuSub = React.forwardRef<\n HTMLUListElement,\n React.ComponentProps<\"ul\">\n>(({ className, ...props }, ref) => (\n <ul\n ref={ref}\n data-sidebar=\"menu-sub\"\n className={cn(\n \"mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5\",\n \"group-data-[collapsible=icon]:hidden\",\n className\n )}\n {...props}\n />\n));\nSidebarMenuSub.displayName = \"SidebarMenuSub\";\n\nconst SidebarMenuSubItem = React.forwardRef<\n HTMLLIElement,\n React.ComponentProps<\"li\">\n>(({ ...props }, ref) => <li ref={ref} {...props} />);\nSidebarMenuSubItem.displayName = \"SidebarMenuSubItem\";\n\nconst SidebarMenuSubButton = React.forwardRef<\n HTMLAnchorElement,\n React.ComponentProps<\"a\"> & {\n asChild?: boolean;\n size?: \"sm\" | \"md\";\n isActive?: boolean;\n }\n>(({ asChild = false, size = \"md\", isActive, className, ...props }, ref) => {\n const Comp = asChild ? Slot : \"a\";\n\n return (\n <Comp\n ref={ref}\n data-sidebar=\"menu-sub-button\"\n data-size={size}\n data-active={isActive}\n className={cn(\n \"flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground outline-none ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-accent-foreground\",\n \"data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground\",\n size === \"sm\" && \"text-xs\",\n size === \"md\" && \"text-sm\",\n \"group-data-[collapsible=icon]:hidden\",\n className\n )}\n {...props}\n />\n );\n});\nSidebarMenuSubButton.displayName = \"SidebarMenuSubButton\";\n\nexport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupAction,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarInput,\n SidebarInset,\n SidebarMenu,\n SidebarMenuAction,\n SidebarMenuBadge,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSkeleton,\n SidebarMenuSub,\n SidebarMenuSubButton,\n SidebarMenuSubItem,\n SidebarProvider,\n SidebarRail,\n SidebarSeparator,\n SidebarTrigger,\n useSidebar,\n};\n","import type { LucideIcon } from \"lucide-react\";\n\nimport {\n SidebarGroup,\n SidebarGroupContent,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n} from \"@/components/ui/sidebar\";\nimport { cn } from \"@/lib/utils\";\nimport { Link, useLocation } from \"react-router-dom\";\n\nexport function AppSidebarNav({\n items,\n}: {\n items: {\n title: string;\n url: string;\n icon?: LucideIcon;\n }[];\n}) {\n const location = useLocation();\n\n return (\n <SidebarGroup>\n <SidebarGroupContent className=\"flex flex-col gap-2\">\n <SidebarMenu>\n {items.map((item) => {\n // 获取当前路径的 pathname 部分,忽略 query 参数\n const currentPathname = location.pathname;\n const isActive = currentPathname === item.url;\n\n return (\n <SidebarMenuItem key={item.title}>\n <SidebarMenuButton\n className={cn(\n \"min-w-8 duration-200 ease-linear hover:bg-primary/5\",\n isActive\n ? \"bg-primary text-primary-foreground duration-200 ease-linear hover:bg-primary/90 hover:text-primary-foreground active:bg-primary/90 active:text-primary-foreground\"\n : \"min-w-8 duration-200 ease-linear\"\n )}\n tooltip={item.title}\n asChild\n >\n <Link to={item.url}>\n {item.icon && <item.icon />}\n <span>{item.title}</span>\n </Link>\n </SidebarMenuButton>\n </SidebarMenuItem>\n );\n })}\n </SidebarMenu>\n </SidebarGroupContent>\n </SidebarGroup>\n );\n}\n","import { LayoutDashboardIcon, SettingsIcon } from \"lucide-react\";\nimport type React from \"react\";\nimport { Link } from \"react-router-dom\";\n\nimport { AppSidebarNav } from \"@/components/AppSidebarNav\";\nimport {\n Sidebar,\n SidebarContent,\n SidebarHeader,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n} from \"@/components/ui/sidebar\";\n\nconst data = {\n navMain: [\n {\n title: \"仪表板\",\n url: \"/dashboard\",\n icon: LayoutDashboardIcon,\n },\n // {\n // title: \"小智服务端\",\n // url: \"/mcp-endpoint\",\n // icon: BotIcon,\n // },\n // {\n // title: \"MCP 服务\",\n // url: \"#\",\n // icon: CableIcon,\n // },\n // {\n // title: \"烧录固件\",\n // url: \"#\",\n // icon: ZapIcon,\n // },\n // {\n // title: \"帮助文档\",\n // url: \"#\",\n // icon: BadgeQuestionMarkIcon,\n // },\n {\n title: \"全局配置\",\n url: \"/settings\",\n icon: SettingsIcon,\n },\n ],\n};\n\nexport function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {\n return (\n <Sidebar collapsible=\"offcanvas\" {...props}>\n <SidebarHeader>\n <SidebarMenu>\n <SidebarMenuItem>\n <SidebarMenuButton\n asChild\n className=\"data-[slot=sidebar-menu-button]:!p-1.5\"\n >\n <Link to=\"/\" className=\"flex items-center gap-2\">\n <span className=\"text-base font-semibold\">Xiaozhi Client</span>\n </Link>\n </SidebarMenuButton>\n </SidebarMenuItem>\n </SidebarMenu>\n </SidebarHeader>\n <SidebarContent>\n <AppSidebarNav items={data.navMain} />\n </SidebarContent>\n </Sidebar>\n );\n}\n","import { type VariantProps, cva } from \"class-variance-authority\";\nimport type * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst badgeVariants = cva(\n \"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2\",\n {\n variants: {\n variant: {\n default:\n \"border-transparent bg-primary text-primary-foreground hover:bg-primary/80\",\n secondary:\n \"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n destructive:\n \"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80\",\n outline: \"text-foreground\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\nexport interface BadgeProps\n extends React.HTMLAttributes<HTMLDivElement>,\n VariantProps<typeof badgeVariants> {}\n\nfunction Badge({ className, variant, ...props }: BadgeProps) {\n return (\n <div className={cn(badgeVariants({ variant }), className)} {...props} />\n );\n}\n\nexport { Badge, badgeVariants };\n","import * as AlertDialogPrimitive from \"@radix-ui/react-alert-dialog\";\nimport * as React from \"react\";\n\nimport { buttonVariants } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/utils\";\n\nconst AlertDialog = AlertDialogPrimitive.Root;\n\nconst AlertDialogTrigger = AlertDialogPrimitive.Trigger;\n\nconst AlertDialogPortal = AlertDialogPrimitive.Portal;\n\nconst AlertDialogOverlay = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Overlay\n className={cn(\n \"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className\n )}\n {...props}\n ref={ref}\n />\n));\nAlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;\n\nconst AlertDialogContent = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <AlertDialogPortal>\n <AlertDialogOverlay />\n <AlertDialogPrimitive.Content\n ref={ref}\n className={cn(\n \"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg\",\n className\n )}\n {...props}\n />\n </AlertDialogPortal>\n));\nAlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;\n\nconst AlertDialogHeader = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col space-y-2 text-center sm:text-left\",\n className\n )}\n {...props}\n />\n);\nAlertDialogHeader.displayName = \"AlertDialogHeader\";\n\nconst AlertDialogFooter = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n className\n )}\n {...props}\n />\n);\nAlertDialogFooter.displayName = \"AlertDialogFooter\";\n\nconst AlertDialogTitle = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Title\n ref={ref}\n className={cn(\"text-lg font-semibold\", className)}\n {...props}\n />\n));\nAlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;\n\nconst AlertDialogDescription = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nAlertDialogDescription.displayName =\n AlertDialogPrimitive.Description.displayName;\n\nconst AlertDialogAction = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Action>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Action\n ref={ref}\n className={cn(buttonVariants(), className)}\n {...props}\n />\n));\nAlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;\n\nconst AlertDialogCancel = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Cancel>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Cancel\n ref={ref}\n className={cn(\n buttonVariants({ variant: \"outline\" }),\n \"mt-2 sm:mt-0\",\n className\n )}\n {...props}\n />\n));\nAlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;\n\nexport {\n AlertDialog,\n AlertDialogPortal,\n AlertDialogOverlay,\n AlertDialogTrigger,\n AlertDialogContent,\n AlertDialogHeader,\n AlertDialogFooter,\n AlertDialogTitle,\n AlertDialogDescription,\n AlertDialogAction,\n AlertDialogCancel,\n};\n","import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { X } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst Dialog = DialogPrimitive.Root;\n\nconst DialogTrigger = DialogPrimitive.Trigger;\n\nconst DialogPortal = DialogPrimitive.Portal;\n\nconst DialogClose = DialogPrimitive.Close;\n\nconst DialogOverlay = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n className={cn(\n \"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className\n )}\n {...props}\n />\n));\nDialogOverlay.displayName = DialogPrimitive.Overlay.displayName;\n\nconst DialogContent = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>\n>(({ className, children, ...props }, ref) => (\n <DialogPortal>\n <DialogOverlay />\n <DialogPrimitive.Content\n ref={ref}\n className={cn(\n \"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg\",\n className\n )}\n {...props}\n >\n {children}\n <DialogPrimitive.Close className=\"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground\">\n <X className=\"h-4 w-4\" />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n </DialogPrimitive.Content>\n </DialogPortal>\n));\nDialogContent.displayName = DialogPrimitive.Content.displayName;\n\nconst DialogHeader = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col space-y-1.5 text-center sm:text-left\",\n className\n )}\n {...props}\n />\n);\nDialogHeader.displayName = \"DialogHeader\";\n\nconst DialogFooter = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n className\n )}\n {...props}\n />\n);\nDialogFooter.displayName = \"DialogFooter\";\n\nconst DialogTitle = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n className={cn(\n \"text-lg font-semibold leading-none tracking-tight\",\n className\n )}\n {...props}\n />\n));\nDialogTitle.displayName = DialogPrimitive.Title.displayName;\n\nconst DialogDescription = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nDialogDescription.displayName = DialogPrimitive.Description.displayName;\n\nexport {\n Dialog,\n DialogPortal,\n DialogOverlay,\n DialogClose,\n DialogTrigger,\n DialogContent,\n DialogHeader,\n DialogFooter,\n DialogTitle,\n DialogDescription,\n};\n","/**\n * 配置数据统一管理 Store\n *\n * 特性:\n * - 支持 HTTP API 和 WebSocket 双重数据源\n * - 提供异步方法:getConfig()、updateConfig()、refreshConfig()\n * - 使用 Zustand 进行状态管理\n * - 提供选择器 hooks 优化组件渲染\n * - 集成 WebSocket 事件监听\n */\n\nimport type {\n AppConfig,\n ConnectionConfig,\n MCPServerConfig,\n ModelScopeConfig,\n WebUIConfig,\n} from \"@/types/index\";\nimport { apiClient } from \"@services/api\";\nimport { webSocketManager } from \"@services/websocket\";\nimport { create } from \"zustand\";\nimport { devtools } from \"zustand/middleware\";\nimport { useShallow } from \"zustand/react/shallow\";\n\n/**\n * 配置加载状态\n */\ninterface ConfigLoadingState {\n isLoading: boolean;\n isUpdating: boolean;\n isRefreshing: boolean;\n lastUpdated: number | null;\n lastError: Error | null;\n}\n\n/**\n * 配置 Store 状态\n */\ninterface ConfigState {\n // 配置数据\n config: AppConfig | null;\n\n // 加载状态\n loading: ConfigLoadingState;\n\n // 配置来源追踪\n lastSource: \"http\" | \"websocket\" | \"initial\" | null;\n}\n\n/**\n * 配置 Store 操作方法\n */\ninterface ConfigActions {\n // 基础操作\n setConfig: (\n config: AppConfig,\n source?: \"http\" | \"websocket\" | \"initial\"\n ) => void;\n setLoading: (loading: Partial<ConfigLoadingState>) => void;\n setError: (error: Error | null) => void;\n\n // 异步操作\n getConfig: () => Promise<AppConfig>;\n updateConfig: (config: AppConfig) => Promise<void>;\n refreshConfig: () => Promise<AppConfig>;\n reloadConfig: () => Promise<AppConfig>;\n\n // 部分更新操作\n updateMcpEndpoint: (endpoint: string | string[]) => Promise<void>;\n updateMcpServers: (servers: Record<string, MCPServerConfig>) => Promise<void>;\n updateConnectionConfig: (connection: ConnectionConfig) => Promise<void>;\n updateModelScopeConfig: (modelscope: ModelScopeConfig) => Promise<void>;\n updateWebUIConfig: (webUI: WebUIConfig) => Promise<void>;\n\n // 工具方法\n reset: () => void;\n initialize: () => Promise<void>;\n}\n\n/**\n * 完整的配置 Store 接口\n */\nexport interface ConfigStore extends ConfigState, ConfigActions {}\n\n/**\n * 初始状态\n */\nconst initialState: ConfigState = {\n config: null,\n loading: {\n isLoading: false,\n isUpdating: false,\n isRefreshing: false,\n lastUpdated: null,\n lastError: null,\n },\n lastSource: null,\n};\n\n/**\n * 创建配置 Store\n */\nexport const useConfigStore = create<ConfigStore>()(\n devtools(\n (set, get) => ({\n ...initialState,\n\n // ==================== 基础操作 ====================\n\n setConfig: (config: AppConfig, source = \"http\") => {\n console.log(`[ConfigStore] 设置配置数据,来源: ${source}`);\n set(\n (state) => ({\n config,\n lastSource: source,\n loading: {\n ...state.loading,\n lastUpdated: Date.now(),\n lastError: null,\n },\n }),\n false,\n \"setConfig\"\n );\n },\n\n setLoading: (loading: Partial<ConfigLoadingState>) => {\n set(\n (state) => ({\n loading: { ...state.loading, ...loading },\n }),\n false,\n \"setLoading\"\n );\n },\n\n setError: (error: Error | null) => {\n set(\n (state) => ({\n loading: { ...state.loading, lastError: error },\n }),\n false,\n \"setError\"\n );\n },\n\n // ==================== 异步操作 ====================\n\n getConfig: async (): Promise<AppConfig> => {\n const { config, loading } = get();\n\n // 如果已有配置且不超过5分钟,直接返回\n if (\n config &&\n loading.lastUpdated &&\n Date.now() - loading.lastUpdated < 5 * 60 * 1000\n ) {\n return config;\n }\n\n // 否则从服务器获取最新配置\n return get().refreshConfig();\n },\n\n updateConfig: async (newConfig: AppConfig): Promise<void> => {\n const { setLoading, setConfig, setError } = get();\n\n try {\n setLoading({ isUpdating: true, lastError: null });\n console.log(\"[ConfigStore] 开始更新配置\");\n\n // 通过 HTTP API 更新配置\n await apiClient.updateConfig(newConfig);\n\n // 更新本地状态\n setConfig(newConfig, \"http\");\n\n console.log(\"[ConfigStore] 配置更新成功\");\n } catch (error) {\n const err =\n error instanceof Error ? error : new Error(\"配置更新失败\");\n console.error(\"[ConfigStore] 配置更新失败:\", err);\n setError(err);\n throw err;\n } finally {\n setLoading({ isUpdating: false });\n }\n },\n\n refreshConfig: async (): Promise<AppConfig> => {\n const { setLoading, setConfig, setError } = get();\n\n try {\n setLoading({ isRefreshing: true, lastError: null });\n console.log(\"[ConfigStore] 开始刷新配置\");\n\n // 从服务器获取最新配置\n const config = await apiClient.getConfig();\n\n // 更新本地状态\n setConfig(config, \"http\");\n\n console.log(\"[ConfigStore] 配置刷新成功\");\n return config;\n } catch (error) {\n const err =\n error instanceof Error ? error : new Error(\"配置刷新失败\");\n console.error(\"[ConfigStore] 配置刷新失败:\", err);\n setError(err);\n throw err;\n } finally {\n setLoading({ isRefreshing: false });\n }\n },\n\n reloadConfig: async (): Promise<AppConfig> => {\n const { setLoading, setConfig, setError } = get();\n\n try {\n setLoading({ isRefreshing: true, lastError: null });\n console.log(\"[ConfigStore] 开始重新加载配置\");\n\n // 重新加载配置文件\n const config = await apiClient.reloadConfig();\n\n // 更新本地状态\n setConfig(config, \"http\");\n\n console.log(\"[ConfigStore] 配置重新加载成功\");\n return config;\n } catch (error) {\n const err =\n error instanceof Error ? error : new Error(\"配置重新加载失败\");\n console.error(\"[ConfigStore] 配置重新加载失败:\", err);\n setError(err);\n throw err;\n } finally {\n setLoading({ isRefreshing: false });\n }\n },\n\n // ==================== 部分更新操作 ====================\n\n updateMcpEndpoint: async (endpoint: string | string[]): Promise<void> => {\n const { config, updateConfig } = get();\n if (!config) {\n throw new Error(\"配置未加载,无法更新 MCP 端点\");\n }\n\n const newConfig = { ...config, mcpEndpoint: endpoint };\n await updateConfig(newConfig);\n },\n\n updateMcpServers: async (\n servers: Record<string, MCPServerConfig>\n ): Promise<void> => {\n const { config, updateConfig } = get();\n if (!config) {\n throw new Error(\"配置未加载,无法更新 MCP 服务\");\n }\n\n const newConfig = { ...config, mcpServers: servers };\n await updateConfig(newConfig);\n },\n\n updateConnectionConfig: async (\n connection: ConnectionConfig\n ): Promise<void> => {\n const { config, updateConfig } = get();\n if (!config) {\n throw new Error(\"配置未加载,无法更新连接配置\");\n }\n\n const newConfig = { ...config, connection };\n await updateConfig(newConfig);\n },\n\n updateModelScopeConfig: async (\n modelscope: ModelScopeConfig\n ): Promise<void> => {\n const { config, updateConfig } = get();\n if (!config) {\n throw new Error(\"配置未加载,无法更新 ModelScope 配置\");\n }\n\n const newConfig = { ...config, modelscope };\n await updateConfig(newConfig);\n },\n\n updateWebUIConfig: async (webUI: WebUIConfig): Promise<void> => {\n const { config, updateConfig } = get();\n if (!config) {\n throw new Error(\"配置未加载,无法更新 Web UI 配置\");\n }\n\n const newConfig = { ...config, webUI };\n await updateConfig(newConfig);\n },\n\n // ==================== 工具方法 ====================\n\n reset: () => {\n console.log(\"[ConfigStore] 重置状态\");\n set(initialState, false, \"reset\");\n },\n\n initialize: async (): Promise<void> => {\n const { setLoading, refreshConfig } = get();\n\n try {\n setLoading({ isLoading: true });\n console.log(\"[ConfigStore] 初始化配置 Store\");\n\n // 设置 WebSocket 事件监听\n webSocketManager.subscribe(\"data:configUpdate\", (config) => {\n console.log(\"[ConfigStore] 收到 WebSocket 配置更新\");\n get().setConfig(config, \"websocket\");\n });\n\n // 获取初始配置\n await refreshConfig();\n\n console.log(\"[ConfigStore] 配置 Store 初始化完成\");\n } catch (error) {\n console.error(\"[ConfigStore] 配置 Store 初始化失败:\", error);\n throw error;\n } finally {\n setLoading({ isLoading: false });\n }\n },\n }),\n {\n name: \"config-store\",\n }\n )\n);\n\n// ==================== 选择器 Hooks ====================\n\n/**\n * 获取完整配置\n */\nexport const useConfig = () => useConfigStore((state) => state.config);\n\n/**\n * 获取配置加载状态\n */\nexport const useConfigLoading = () => useConfigStore((state) => state.loading);\n\n/**\n * 获取配置是否正在加载\n */\nexport const useConfigIsLoading = () =>\n useConfigStore(\n (state) => state.loading.isLoading || state.loading.isRefreshing\n );\n\n/**\n * 获取配置是否正在更新\n */\nexport const useConfigIsUpdating = () =>\n useConfigStore((state) => state.loading.isUpdating);\n\n/**\n * 获取配置错误\n */\nexport const useConfigError = () =>\n useConfigStore((state) => state.loading.lastError);\n\n/**\n * 获取 MCP 端点\n */\nexport const useMcpEndpoint = () =>\n useConfigStore((state) => state.config?.mcpEndpoint);\n\n/**\n * 获取 MCP 服务配置\n */\nexport const useMcpServers = () =>\n useConfigStore((state) => state.config?.mcpServers);\n\n/**\n * 获取 MCP 服务工具配置\n */\nexport const useMcpServerConfig = () =>\n useConfigStore((state) => state.config?.mcpServerConfig);\n\n/**\n * 获取连接配置\n */\nexport const useConnectionConfig = () =>\n useConfigStore((state) => state.config?.connection);\n\n/**\n * 获取 ModelScope 配置\n */\nexport const useModelScopeConfig = () =>\n useConfigStore((state) => state.config?.modelscope);\n\n/**\n * 获取 Web UI 配置\n */\nexport const useWebUIConfig = () =>\n useConfigStore((state) => state.config?.webUI);\n\n/**\n * 获取配置来源\n */\nexport const useConfigSource = () =>\n useConfigStore((state) => state.lastSource);\n\n// ==================== 复合选择器 ====================\n\n/**\n * 获取配置数据和加载状态\n */\nexport const useConfigWithLoading = () =>\n useConfigStore(\n useShallow((state) => ({\n config: state.config,\n isLoading: state.loading.isLoading || state.loading.isRefreshing,\n isUpdating: state.loading.isUpdating,\n error: state.loading.lastError,\n }))\n );\n\n/**\n * 获取 MCP 相关配置\n */\nexport const useMcpConfig = () =>\n useConfigStore(\n useShallow((state) => ({\n endpoint: state.config?.mcpEndpoint,\n servers: state.config?.mcpServers,\n serverConfig: state.config?.mcpServerConfig,\n }))\n );\n\n/**\n * 获取系统配置\n */\nexport const useSystemConfig = () =>\n useConfigStore(\n useShallow((state) => ({\n connection: state.config?.connection,\n modelscope: state.config?.modelscope,\n webUI: state.config?.webUI,\n }))\n );\n\n// ==================== 操作方法 Hooks ====================\n\n/**\n * 获取配置操作方法\n */\nexport const useConfigActions = () =>\n useConfigStore(\n useShallow((state) => ({\n getConfig: state.getConfig,\n updateConfig: state.updateConfig,\n refreshConfig: state.refreshConfig,\n reloadConfig: state.reloadConfig,\n updateMcpEndpoint: state.updateMcpEndpoint,\n updateMcpServers: state.updateMcpServers,\n updateConnectionConfig: state.updateConnectionConfig,\n updateModelScopeConfig: state.updateModelScopeConfig,\n updateWebUIConfig: state.updateWebUIConfig,\n reset: state.reset,\n initialize: state.initialize,\n }))\n );\n\n/**\n * 获取配置更新方法\n */\nexport const useConfigUpdaters = () =>\n useConfigStore(\n useShallow((state) => ({\n updateConfig: state.updateConfig,\n updateMcpEndpoint: state.updateMcpEndpoint,\n updateMcpServers: state.updateMcpServers,\n updateConnectionConfig: state.updateConnectionConfig,\n updateModelScopeConfig: state.updateModelScopeConfig,\n updateWebUIConfig: state.updateWebUIConfig,\n }))\n );\n","import { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\n\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n} from \"@/components/ui/alert-dialog\";\nimport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from \"@/components/ui/dialog\";\nimport { Input } from \"@/components/ui/input\";\nimport { type EndpointStatusResponse, apiClient } from \"@/services/api\";\nimport { webSocketManager } from \"@/services/websocket\";\nimport { useConfig, useConfigActions, useMcpEndpoint } from \"@/stores/config\";\nimport {\n BadgeInfoIcon,\n CopyIcon,\n Loader2Icon,\n PlusIcon,\n SettingsIcon,\n TrashIcon,\n WifiIcon,\n WifiOffIcon,\n} from \"lucide-react\";\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { toast } from \"sonner\";\n\n// 接入点状态接口\ninterface EndpointState {\n connected: boolean;\n isOperating: boolean;\n lastOperation: {\n type: \"connect\" | \"disconnect\" | \"reconnect\" | null;\n success: boolean;\n message: string;\n timestamp: number;\n };\n}\n\nconst sliceEndpoint = (endpoint: string) => {\n return `${endpoint.slice(0, 30)}...${endpoint.slice(-10)}`;\n};\n\n// 验证接入点格式\nconst validateEndpoint = (endpoint: string): string | null => {\n if (!endpoint.trim()) {\n return \"请输入接入点地址\";\n }\n\n // 检查是否是有效的 WebSocket URL\n if (!endpoint.startsWith(\"ws://\") && !endpoint.startsWith(\"wss://\")) {\n return \"接入点格式无效,请输入正确的WebSocket URL (ws:// 或 wss://)\";\n }\n\n // 检查是否是有效的 URL\n try {\n new URL(endpoint);\n } catch {\n return \"接入点格式无效,请输入正确的URL格式\";\n }\n\n return null; // 验证通过\n};\n\nexport function McpEndpointSettingButton() {\n const [open, setOpen] = useState(false);\n const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false);\n const [endpointToDelete, setEndpointToDelete] = useState<string>(\"\");\n const [isDeleting, setIsDeleting] = useState(false);\n const [addDialogOpen, setAddDialogOpen] = useState(false);\n const [newEndpoint, setNewEndpoint] = useState(\"\");\n const [isAdding, setIsAdding] = useState(false);\n const [validationError, setValidationError] = useState(\"\");\n\n // 接入点状态管理\n const [endpointStates, setEndpointStates] = useState<\n Record<string, EndpointState>\n >({});\n\n const config = useConfig();\n const mcpEndpoint = useMcpEndpoint();\n const { refreshConfig } = useConfigActions();\n\n // 获取接入点状态\n const fetchEndpointStatus = useCallback(\n async (endpoint: string): Promise<EndpointStatusResponse> => {\n try {\n return await apiClient.getEndpointStatus(endpoint);\n } catch (error) {\n console.error(`获取接入点状态失败: ${endpoint}`, error);\n // 返回默认状态\n return {\n endpoint,\n connected: false,\n initialized: false,\n isReconnecting: false,\n reconnectAttempts: 0,\n reconnectDelay: 0,\n };\n }\n },\n []\n );\n\n // 更新接入点状态\n const updateEndpointState = useCallback(\n (endpoint: string, updates: Partial<EndpointState>) => {\n setEndpointStates((prev) => ({\n ...prev,\n [endpoint]: {\n ...prev[endpoint],\n ...updates,\n },\n }));\n },\n []\n );\n\n // 初始化接入点状态\n const initializeEndpointStates = useCallback(\n async (endpoints: string[]) => {\n const states: Record<string, EndpointState> = {};\n\n for (const endpoint of endpoints) {\n try {\n const status = await fetchEndpointStatus(endpoint);\n states[endpoint] = {\n connected: status.connected,\n isOperating: false,\n lastOperation: {\n type: null,\n success: false,\n message: \"\",\n timestamp: 0,\n },\n };\n } catch (error) {\n states[endpoint] = {\n connected: false,\n isOperating: false,\n lastOperation: {\n type: null,\n success: false,\n message: \"\",\n timestamp: 0,\n },\n };\n }\n }\n\n setEndpointStates(states);\n },\n [fetchEndpointStatus]\n );\n\n // 连接接入点\n const handleConnect = async (endpoint: string) => {\n updateEndpointState(endpoint, { isOperating: true });\n\n try {\n await apiClient.connectEndpoint(endpoint);\n updateEndpointState(endpoint, {\n connected: true,\n isOperating: false,\n lastOperation: {\n type: \"connect\",\n success: true,\n message: \"连接成功\",\n timestamp: Date.now(),\n },\n });\n toast.success(\"接入点连接成功\");\n } catch (error) {\n updateEndpointState(endpoint, {\n isOperating: false,\n lastOperation: {\n type: \"connect\",\n success: false,\n message: error instanceof Error ? error.message : \"连接失败\",\n timestamp: Date.now(),\n },\n });\n toast.error(error instanceof Error ? error.message : \"接入点连接失败\");\n }\n };\n\n // 断开接入点\n const handleDisconnect = async (endpoint: string) => {\n updateEndpointState(endpoint, { isOperating: true });\n\n try {\n await apiClient.disconnectEndpoint(endpoint);\n updateEndpointState(endpoint, {\n connected: false,\n isOperating: false,\n lastOperation: {\n type: \"disconnect\",\n success: true,\n message: \"断开成功\",\n timestamp: Date.now(),\n },\n });\n toast.success(\"接入点断开成功\");\n } catch (error) {\n updateEndpointState(endpoint, {\n isOperating: false,\n lastOperation: {\n type: \"disconnect\",\n success: false,\n message: error instanceof Error ? error.message : \"断开失败\",\n timestamp: Date.now(),\n },\n });\n toast.error(error instanceof Error ? error.message : \"接入点断开失败\");\n }\n };\n\n // 复制接入点地址到剪贴板\n const handleCopy = async (endpoint: string) => {\n try {\n if (navigator.clipboard?.writeText) {\n await navigator.clipboard.writeText(endpoint);\n toast.success(\"接入点地址已复制到剪贴板\");\n } else {\n // 降级方案:使用传统的复制方法\n const textArea = document.createElement(\"textarea\");\n textArea.value = endpoint;\n textArea.style.position = \"fixed\";\n textArea.style.opacity = \"0\";\n document.body.appendChild(textArea);\n textArea.select();\n const successful = document.execCommand(\"copy\");\n document.body.removeChild(textArea);\n if (successful) {\n toast.success(\"接入点地址已复制到剪贴板\");\n } else {\n throw new Error(\"复制命令执行失败\");\n }\n }\n } catch (error) {\n console.error(\"复制失败:\", error);\n toast.error(\"复制失败,请手动复制\");\n }\n };\n\n // 删除接入点\n const handleDeleteEndpoint = async () => {\n setIsDeleting(true);\n try {\n // 调用后端 API 删除接入点\n await apiClient.removeEndpoint(endpointToDelete);\n\n // 刷新配置数据以更新 mcpEndpoints 列表\n await refreshConfig();\n\n // 从本地状态中移除该接入点\n setEndpointStates((prev) => {\n const newStates = { ...prev };\n delete newStates[endpointToDelete];\n return newStates;\n });\n\n toast.success(\"接入点已删除\");\n setDeleteConfirmOpen(false);\n setEndpointToDelete(\"\");\n } catch (error) {\n console.error(\"删除接入点失败:\", error);\n toast.error(error instanceof Error ? error.message : \"删除接入点失败\");\n } finally {\n setIsDeleting(false);\n }\n };\n\n // 添加新接入点\n const handleAddEndpoint = async () => {\n const error = validateEndpoint(newEndpoint);\n if (error) {\n setValidationError(error);\n return;\n }\n\n // 检查是否与现有接入点重复\n const currentEndpoints = Array.isArray(mcpEndpoint)\n ? mcpEndpoint\n : [mcpEndpoint];\n if (currentEndpoints.includes(newEndpoint)) {\n setValidationError(\"该接入点已存在\");\n return;\n }\n\n if (!config) {\n toast.error(\"配置数据未加载,请稍后重试\");\n return;\n }\n\n setIsAdding(true);\n try {\n // 调用后端 API 添加接入点\n const endpointStatus = await apiClient.addEndpoint(newEndpoint);\n\n // 刷新配置数据以更新 mcpEndpoints 列表\n await refreshConfig();\n\n // 初始化新接入点的状态\n setEndpointStates((prev) => ({\n ...prev,\n [newEndpoint]: {\n connected: endpointStatus.connected,\n isOperating: false,\n lastOperation: {\n type: null,\n success: false,\n message: \"\",\n timestamp: 0,\n },\n },\n }));\n\n toast.success(\"接入点添加成功\");\n setAddDialogOpen(false);\n setNewEndpoint(\"\");\n setValidationError(\"\");\n } catch (error) {\n console.error(\"添加接入点失败:\", error);\n toast.error(error instanceof Error ? error.message : \"添加接入点失败\");\n } finally {\n setIsAdding(false);\n }\n };\n\n // 打开添加接入点对话框\n const openAddDialog = () => {\n setNewEndpoint(\"\");\n setValidationError(\"\");\n setAddDialogOpen(true);\n };\n\n // 处理输入变化\n const handleInputChange = (value: string) => {\n setNewEndpoint(value);\n if (validationError) {\n setValidationError(\"\");\n }\n };\n\n // 打开删除确认对话框\n const openDeleteConfirm = (endpoint: string) => {\n setEndpointToDelete(endpoint);\n setDeleteConfirmOpen(true);\n };\n\n const mcpEndpoints = useMemo(() => {\n let list: string[] = [];\n if (Array.isArray(mcpEndpoint)) list = mcpEndpoint;\n if (typeof mcpEndpoint === \"string\" && mcpEndpoint.length) {\n list.push(mcpEndpoint);\n }\n return list;\n }, [mcpEndpoint]);\n\n // 当对话框打开时,初始化接入点状态\n useEffect(() => {\n if (open && mcpEndpoints.length > 0) {\n initializeEndpointStates(mcpEndpoints);\n }\n }, [open, mcpEndpoints, initializeEndpointStates]);\n\n // 实时状态同步 - 处理端点状态变更事件\n useEffect(() => {\n if (!open || mcpEndpoints.length === 0) return;\n\n // 为每个端点订阅状态变更事件\n const unsubscribers = mcpEndpoints.map((endpoint) => {\n const unsubscribe = webSocketManager.subscribe(\n \"data:endpointStatusChanged\",\n (event: any) => {\n // 只处理当前端点的事件\n if (event.endpoint === endpoint) {\n console.log(\n `[McpEndpointSettingButton] 接收到端点 ${endpoint} 状态变更:`,\n event\n );\n\n // 更新端点状态\n updateEndpointState(endpoint, {\n connected: event.connected,\n isOperating: false, // 接收到事件说明操作已完成\n lastOperation: {\n type: event.operation,\n success: event.success,\n message:\n event.message || (event.connected ? \"连接成功\" : \"断开成功\"),\n timestamp: event.timestamp,\n },\n });\n\n // 显示通知\n if (event.success) {\n toast.success(\n `端点 ${event.operation === \"connect\" ? \"连接\" : event.operation === \"disconnect\" ? \"断开\" : \"重连\"}成功`\n );\n } else {\n toast.error(\n `端点 ${event.operation === \"connect\" ? \"连接\" : event.operation === \"disconnect\" ? \"断开\" : \"重连\"}失败: ${event.message || \"未知错误\"}`\n );\n }\n }\n }\n );\n\n return unsubscribe;\n });\n\n // 清理函数\n return () => {\n for (const unsubscribe of unsubscribers) {\n unsubscribe();\n }\n };\n }, [open, mcpEndpoints, updateEndpointState]);\n\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n <DialogTrigger asChild>\n <Button variant=\"secondary\" size=\"icon\" className=\"size-8\">\n <SettingsIcon className=\"size-4\" />\n </Button>\n </DialogTrigger>\n <DialogContent className=\"min-w-[600px] max-w-[800px] max-h-[80vh] overflow-y-auto\">\n <DialogHeader className=\"mb-4\">\n <DialogTitle>配置小智服务端接入点</DialogTitle>\n <DialogDescription>\n 点击保存后,需要重启服务才会生效。\n </DialogDescription>\n </DialogHeader>\n <div className=\"flex flex-col gap-2\">\n {mcpEndpoints.map((item) => {\n const endpointState = endpointStates[item];\n const isConnected = endpointState?.connected || false;\n const isOperating = endpointState?.isOperating || false;\n\n return (\n <div\n key={item}\n className=\"flex flex-col sm:flex-row items-start sm:items-center justify-between p-4 bg-slate-50 rounded-md font-mono gap-3 transition-all duration-200 hover:bg-slate-100\"\n >\n <div className=\"flex flex-col sm:flex-row items-start sm:items-center gap-2 sm:gap-3 flex-1 min-w-0\">\n <span className=\"flex-1 text-ellipsis overflow-hidden whitespace-nowrap text-sm sm:text-base\">\n {sliceEndpoint(item)}\n </span>\n {/* 连接状态显示 */}\n <Badge\n className={`flex items-center gap-1 transition-all duration-200 text-xs sm:text-sm ${\n isConnected\n ? \"bg-green-100 text-green-800 border-green-200 hover:text-green-800 hover:border-green-200 hover:bg-green-100\"\n : \"bg-gray-100 text-gray-600 border-gray-200 hover:bg-gray-100 hover:text-gray-600 hover:border-gray-200\"\n }`}\n >\n {isOperating ? (\n <Loader2Icon className=\"size-3 animate-spin\" />\n ) : isConnected ? (\n <WifiIcon className=\"size-3\" />\n ) : (\n <WifiOffIcon className=\"size-3\" />\n )}\n {isOperating ? \"操作中\" : isConnected ? \"已连接\" : \"未连接\"}\n </Badge>\n </div>\n <div className=\"flex items-center gap-1 sm:gap-2 flex-wrap justify-end\">\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => handleCopy(item)}\n title=\"复制完整地址\"\n className=\"transition-all duration-200 hover:scale-105\"\n >\n <CopyIcon className=\"size-4\" />\n </Button>\n {/* 连接/断开按钮 */}\n {isConnected ? (\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => handleDisconnect(item)}\n title=\"断开连接\"\n disabled={isOperating}\n className=\"text-red-600 hover:text-red-700 hover:bg-red-50 transition-all duration-200 hover:scale-105 disabled:scale-100 disabled:opacity-50\"\n >\n {isOperating ? (\n <Loader2Icon className=\"size-4 animate-spin\" />\n ) : (\n <WifiOffIcon className=\"size-4\" />\n )}\n </Button>\n ) : (\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => handleConnect(item)}\n title=\"连接\"\n disabled={isOperating}\n className=\"text-green-600 hover:text-green-700 hover:bg-green-50 transition-all duration-200 hover:scale-105 disabled:scale-100 disabled:opacity-50\"\n >\n {isOperating ? (\n <Loader2Icon className=\"size-4 animate-spin\" />\n ) : (\n <WifiIcon className=\"size-4\" />\n )}\n </Button>\n )}\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => openDeleteConfirm(item)}\n title=\"删除此接入点\"\n className=\"transition-all duration-200 hover:scale-105 hover:text-red-600\"\n >\n <TrashIcon className=\"size-4 text-red-500\" />\n </Button>\n </div>\n </div>\n );\n })}\n {mcpEndpoints.length === 0 && (\n <div className=\"flex flex-col items-center flex-1 text-sm text-muted-foreground text-center justify-center gap-2\">\n <BadgeInfoIcon />\n <span>暂无接入点,请添加</span>\n </div>\n )}\n <div className=\"flex flex-col sm:flex-row items-center gap-2 mt-4\">\n <Button\n className=\"flex-1 flex items-center gap-2\"\n onClick={openAddDialog}\n >\n <PlusIcon className=\"size-4\" />\n <span className=\"text-sm sm:text-base\">添加小智服务端接入点</span>\n </Button>\n <Button\n variant=\"outline\"\n className=\"flex-1 flex items-center gap-2\"\n onClick={() =>\n window.open(\"https://xiaozhi.me/console/agents\", \"_blank\")\n }\n >\n <span className=\"text-sm sm:text-base\">打开小智服务端</span>\n </Button>\n </div>\n </div>\n </DialogContent>\n\n {/* 删除确认对话框 */}\n <AlertDialog open={deleteConfirmOpen} onOpenChange={setDeleteConfirmOpen}>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>确认删除接入点</AlertDialogTitle>\n <AlertDialogDescription>\n 确定要删除接入点 \"{sliceEndpoint(endpointToDelete)}\"\n 吗?此操作无法撤销。\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={isDeleting}>取消</AlertDialogCancel>\n <AlertDialogAction\n onClick={handleDeleteEndpoint}\n disabled={isDeleting}\n className=\"bg-destructive text-destructive-foreground hover:bg-destructive/90\"\n >\n {isDeleting ? \"删除中...\" : \"确定删除\"}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n\n {/* 添加接入点对话框 */}\n <Dialog open={addDialogOpen} onOpenChange={setAddDialogOpen}>\n <DialogContent className=\"sm:max-w-[500px]\">\n <DialogHeader>\n <DialogTitle>添加新的接入点</DialogTitle>\n <DialogDescription>请输入小智服务端接入点地址</DialogDescription>\n </DialogHeader>\n <div className=\"grid gap-4 py-4\">\n <div className=\"space-y-2\">\n <Input\n placeholder=\"请输入接入点地址,例如:wss://api.xiaozhi.me/mcp/?token=... 或 ws(s)://<hostname>:<port>\"\n value={newEndpoint}\n onChange={(e) => handleInputChange(e.target.value)}\n disabled={isAdding}\n className=\"font-mono text-sm\"\n />\n {validationError && (\n <p className=\"text-sm text-red-500\">{validationError}</p>\n )}\n </div>\n </div>\n <DialogFooter>\n <DialogClose asChild>\n <Button variant=\"outline\" disabled={isAdding}>\n 取消\n </Button>\n </DialogClose>\n <Button\n onClick={handleAddEndpoint}\n disabled={isAdding || !newEndpoint.trim()}\n >\n {isAdding ? \"添加中...\" : \"确定\"}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </Dialog>\n );\n}\n","import * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst Card = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n \"rounded-lg border bg-card text-card-foreground shadow-sm\",\n className\n )}\n {...props}\n />\n));\nCard.displayName = \"Card\";\n\nconst CardHeader = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"flex flex-col space-y-1.5 p-6\", className)}\n {...props}\n />\n));\nCardHeader.displayName = \"CardHeader\";\n\nconst CardTitle = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n \"text-2xl font-semibold leading-none tracking-tight\",\n className\n )}\n {...props}\n />\n));\nCardTitle.displayName = \"CardTitle\";\n\nconst CardDescription = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nCardDescription.displayName = \"CardDescription\";\n\nconst CardContent = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"p-6 pt-0\", className)} {...props} />\n));\nCardContent.displayName = \"CardContent\";\n\nconst CardFooter = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"flex items-center p-6 pt-0\", className)}\n {...props}\n />\n));\nCardFooter.displayName = \"CardFooter\";\n\nexport {\n Card,\n CardHeader,\n CardFooter,\n CardTitle,\n CardDescription,\n CardContent,\n};\n","import { cn } from \"@/lib/utils\";\nimport * as React from \"react\";\n\ninterface ScrollAreaProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode;\n}\n\nconst ScrollArea = React.forwardRef<HTMLDivElement, ScrollAreaProps>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"relative overflow-auto\", className)}\n {...props}\n >\n {children}\n </div>\n )\n);\nScrollArea.displayName = \"ScrollArea\";\n\nconst ScrollBar = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement> & {\n orientation?: \"vertical\" | \"horizontal\";\n }\n>(({ className, orientation = \"vertical\", ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n \"flex touch-none select-none transition-colors\",\n orientation === \"vertical\" &&\n \"h-full w-2.5 border-l border-l-transparent p-[1px]\",\n orientation === \"horizontal\" &&\n \"h-2.5 w-full border-t border-t-transparent p-[1px]\",\n className\n )}\n {...props}\n >\n <div className=\"relative flex-1 rounded-full bg-border\" />\n </div>\n));\nScrollBar.displayName = \"ScrollBar\";\n\nexport { ScrollArea, ScrollBar };\n","import * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst Table = React.forwardRef<\n HTMLTableElement,\n React.HTMLAttributes<HTMLTableElement>\n>(({ className, ...props }, ref) => (\n <div className=\"relative w-full overflow-auto\">\n <table\n ref={ref}\n className={cn(\"w-full caption-bottom text-sm\", className)}\n {...props}\n />\n </div>\n));\nTable.displayName = \"Table\";\n\nconst TableHeader = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <thead ref={ref} className={cn(\"[&_tr]:border-b\", className)} {...props} />\n));\nTableHeader.displayName = \"TableHeader\";\n\nconst TableBody = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <tbody\n ref={ref}\n className={cn(\"[&_tr:last-child]:border-0\", className)}\n {...props}\n />\n));\nTableBody.displayName = \"TableBody\";\n\nconst TableFooter = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <tfoot\n ref={ref}\n className={cn(\n \"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0\",\n className\n )}\n {...props}\n />\n));\nTableFooter.displayName = \"TableFooter\";\n\nconst TableRow = React.forwardRef<\n HTMLTableRowElement,\n React.HTMLAttributes<HTMLTableRowElement>\n>(({ className, ...props }, ref) => (\n <tr\n ref={ref}\n className={cn(\n \"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted\",\n className\n )}\n {...props}\n />\n));\nTableRow.displayName = \"TableRow\";\n\nconst TableHead = React.forwardRef<\n HTMLTableCellElement,\n React.ThHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <th\n ref={ref}\n className={cn(\n \"h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0\",\n className\n )}\n {...props}\n />\n));\nTableHead.displayName = \"TableHead\";\n\nconst TableCell = React.forwardRef<\n HTMLTableCellElement,\n React.TdHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <td\n ref={ref}\n className={cn(\"p-4 align-middle [&:has([role=checkbox])]:pr-0\", className)}\n {...props}\n />\n));\nTableCell.displayName = \"TableCell\";\n\nconst TableCaption = React.forwardRef<\n HTMLTableCaptionElement,\n React.HTMLAttributes<HTMLTableCaptionElement>\n>(({ className, ...props }, ref) => (\n <caption\n ref={ref}\n className={cn(\"mt-4 text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nTableCaption.displayName = \"TableCaption\";\n\nexport {\n Table,\n TableHeader,\n TableBody,\n TableFooter,\n TableHead,\n TableRow,\n TableCell,\n TableCaption,\n};\n","\"use client\";\n\nimport * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst Tabs = TabsPrimitive.Root;\n\nconst TabsList = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.List>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.List\n ref={ref}\n className={cn(\n \"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground\",\n className\n )}\n {...props}\n />\n));\nTabsList.displayName = TabsPrimitive.List.displayName;\n\nconst TabsTrigger = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Trigger\n ref={ref}\n className={cn(\n \"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm\",\n className\n )}\n {...props}\n />\n));\nTabsTrigger.displayName = TabsPrimitive.Trigger.displayName;\n\nconst TabsContent = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Content\n ref={ref}\n className={cn(\n \"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n className\n )}\n {...props}\n />\n));\nTabsContent.displayName = TabsPrimitive.Content.displayName;\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent };\n","/**\n * 格式化工具函数\n */\n\nimport type { ToolCallRecord } from \"@/types/index\";\n\n/**\n * 格式化时间戳为本地化字符串\n * @param timestamp 时间戳(毫秒)\n * @returns 格式化后的时间字符串\n */\nexport const formatTimestamp = (timestamp?: number): string => {\n if (!timestamp) return \"未知时间\";\n return new Date(timestamp).toLocaleString(\"zh-CN\", {\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n });\n};\n\n/**\n * 格式化持续时间为易读字符串\n * @param duration 持续时间(毫秒)\n * @returns 格式化后的持续时间字符串\n */\nexport const formatDuration = (duration?: number): string => {\n if (!duration) return \"-\";\n if (duration < 1000) return `${duration}ms`;\n return `${(duration / 1000).toFixed(1)}s`;\n};\n\n/**\n * 生成稳定的React键值\n * @param log 工具调用记录\n * @param index 索引\n * @returns 稳定的键值\n */\nexport const generateStableKey = (\n log: ToolCallRecord,\n index: number\n): string => {\n // 使用工具名、时间戳和索引组合生成稳定的键\n // 如果时间戳不存在,使用索引作为后备\n const timestamp = log.timestamp || Date.now();\n return `${log.toolName}-${timestamp}-${index}`;\n};\n\n/**\n * 格式化JSON数据为可读字符串\n * @param data 要格式化的数据\n * @returns 格式化后的JSON字符串\n */\nexport const formatJson = (data: any): string | null => {\n if (!data) return null;\n try {\n return JSON.stringify(data, null, 2);\n } catch (error) {\n return String(data);\n }\n};\n\n/**\n * 重新抛出错误的工具函数\n * @param error 错误对象\n * @returns 错误字符串\n */\nexport const formatError = (error: any): string => {\n if (typeof error === \"string\") return error;\n if (error instanceof Error) return error.message;\n return String(error);\n};\n","\"use client\";\n\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card } from \"@/components/ui/card\";\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from \"@/components/ui/dialog\";\nimport { ScrollArea } from \"@/components/ui/scroll-area\";\nimport { Separator } from \"@/components/ui/separator\";\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"@/components/ui/table\";\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"@/components/ui/tabs\";\nimport type {\n ApiResponse,\n ToolCallLogsResponse,\n ToolCallRecord,\n} from \"@/types/index\";\nimport {\n formatDuration,\n formatJson,\n formatTimestamp,\n generateStableKey,\n} from \"@/utils/formatUtils\";\nimport {\n CheckCircle,\n CheckIcon,\n Code,\n CopyIcon,\n FileText,\n Loader2,\n RefreshCw,\n RotateCwIcon,\n XCircle,\n} from \"lucide-react\";\nimport { useCallback, useEffect, useState } from \"react\";\n\nexport function ToolCallLogsDialog() {\n const [open, setOpen] = useState(false);\n const [logs, setLogs] = useState<ToolCallRecord[]>([]);\n const [loading, setLoading] = useState(false);\n const [refreshing, setRefreshing] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [selectedLog, setSelectedLog] = useState<ToolCallRecord | null>(null);\n const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);\n const [limit] = useState(50);\n const [total, setTotal] = useState(0);\n\n const fetchLogs = useCallback(\n async (isRefresh = false) => {\n if (isRefresh) {\n setRefreshing(true);\n } else {\n setLoading(true);\n }\n setError(null);\n\n try {\n await new Promise((resolve) => setTimeout(resolve, 1000));\n const response = await fetch(`/api/tool-calls/logs?limit=${limit}`);\n const data: ApiResponse<ToolCallLogsResponse> = await response.json();\n\n if (data.success && data.data) {\n setLogs(data.data.records);\n setTotal(data.data.total);\n } else {\n setError(data.error?.message || \"获取日志失败\");\n }\n } catch (err) {\n setError(\"网络请求失败\");\n console.error(\"Failed to fetch tool call logs:\", err);\n } finally {\n if (isRefresh) {\n setRefreshing(false);\n } else {\n setLoading(false);\n }\n }\n },\n [limit]\n );\n\n useEffect(() => {\n if (open) {\n fetchLogs();\n } else {\n // 关闭弹窗时清空选中状态\n setSelectedLog(null);\n setHoveredIndex(null);\n }\n }, [open, fetchLogs]);\n\n // 处理数据行悬停\n const handleRowMouseEnter = (log: ToolCallRecord, index: number) => {\n if (hoveredIndex !== index) {\n setSelectedLog(log);\n setHoveredIndex(index);\n }\n };\n\n // 处理详情面板鼠标进入\n const handleDetailMouseEnter = () => {\n // 确保鼠标在详情面板时保持显示状态\n // 不需要做任何操作,保持当前状态\n };\n\n // 处理弹窗容器鼠标离开\n const handleDialogMouseLeave = () => {\n // 只有当鼠标完全离开弹窗时才清空状态\n setSelectedLog(null);\n setHoveredIndex(null);\n };\n\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n <DialogTrigger asChild>\n <Button variant=\"outline\" size=\"sm\" className=\"gap-2\">\n <FileText className=\"h-4 w-4\" />\n 调用日志\n </Button>\n </DialogTrigger>\n <DialogContent\n className=\"max-w-6xl max-h-[80vh]\"\n onMouseLeave={handleDialogMouseLeave}\n >\n <DialogHeader>\n <div className=\"flex items-center justify-between\">\n <DialogTitle className=\"flex items-center gap-2\">\n <FileText className=\"h-5 w-5\" />\n MCP 工具调用日志\n {total > 0 && (\n <span className=\"text-sm font-normal text-muted-foreground ml-2\">\n (共 {total} 条记录)\n </span>\n )}\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => fetchLogs(true)}\n disabled={refreshing}\n >\n <RotateCwIcon\n className={`h-4 w-4 ${refreshing ? \"animate-spin\" : \"\"}`}\n />\n 刷新\n </Button>\n </DialogTitle>\n </div>\n </DialogHeader>\n\n <div className=\"flex-1 flex gap-4\">\n {/* 左侧表格区域 */}\n <div className=\"flex-1\">\n {loading ? (\n <div className=\"flex flex-col items-center justify-center py-8\">\n <div className=\"relative\">\n <Loader2 className=\"h-8 w-8 animate-spin text-muted-foreground\" />\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <FileText className=\"h-4 w-4 text-muted-foreground/50\" />\n </div>\n </div>\n <div className=\"mt-4 text-center\">\n <p className=\"text-muted-foreground font-medium\">\n 正在加载日志数据\n </p>\n <p className=\"text-muted-foreground/70 text-sm mt-1\">\n 请稍候片刻...\n </p>\n </div>\n </div>\n ) : error ? (\n <div className=\"text-center py-8\">\n <div className=\"bg-destructive/10 border border-destructive/20 rounded-lg p-6 max-w-md mx-auto\">\n <XCircle className=\"h-12 w-12 text-destructive mx-auto mb-4\" />\n <h3 className=\"text-destructive font-semibold text-lg mb-2\">\n 加载失败\n </h3>\n <p className=\"text-muted-foreground text-sm mb-4 leading-relaxed\">\n {error}\n </p>\n <div className=\"flex flex-col gap-2\">\n <Button\n onClick={() => fetchLogs()}\n variant=\"outline\"\n size=\"sm\"\n className=\"gap-2\"\n >\n <RefreshCw className=\"h-4 w-4\" />\n 重试加载\n </Button>\n <Button\n onClick={() => fetchLogs(true)}\n variant=\"ghost\"\n size=\"sm\"\n className=\"text-xs\"\n >\n 强制刷新\n </Button>\n </div>\n </div>\n </div>\n ) : logs.length === 0 ? (\n <div className=\"text-center py-8\">\n <div className=\"bg-muted/30 border border-muted rounded-lg p-6 max-w-md mx-auto\">\n <FileText className=\"h-12 w-12 text-muted-foreground mx-auto mb-4\" />\n <h3 className=\"font-medium text-lg mb-2\">暂无工具调用记录</h3>\n <p className=\"text-muted-foreground text-sm leading-relaxed mb-4\">\n 当前还没有任何工具调用记录。当您开始使用工具时,相关的调用信息会在这里显示。\n </p>\n <Button\n onClick={() => fetchLogs(true)}\n variant=\"outline\"\n size=\"sm\"\n className=\"gap-2\"\n >\n <RefreshCw className=\"h-4 w-4\" />\n 检查更新\n </Button>\n </div>\n </div>\n ) : (\n <ScrollArea className=\"h-[60vh]\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>工具名称</TableHead>\n <TableHead>服务器</TableHead>\n <TableHead>状态</TableHead>\n <TableHead>耗时</TableHead>\n <TableHead>时间</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {logs.map((log, index) => (\n <TableRow\n key={generateStableKey(log, index)}\n className={`cursor-pointer transition-colors ${\n hoveredIndex === index\n ? \"bg-muted/50\"\n : \"hover:bg-muted/30\"\n }`}\n onMouseEnter={() => handleRowMouseEnter(log, index)}\n >\n <TableCell className=\"font-medium\">\n <div>\n <div>{log.toolName}</div>\n {log.originalToolName &&\n log.originalToolName !== log.toolName && (\n <div className=\"text-xs text-muted-foreground\">\n 原始: {log.originalToolName}\n </div>\n )}\n </div>\n </TableCell>\n <TableCell>\n {log.serverName || (\n <span className=\"text-muted-foreground\">-</span>\n )}\n </TableCell>\n <TableCell>\n <Badge\n variant={log.success ? undefined : \"destructive\"}\n className={`gap-1 w-[50px] text-center ${\n log.success\n ? \"bg-green-600 hover:bg-green-600\"\n : \"bg-red-600 hover:bg-red-600\"\n }`}\n >\n {log.success ? \"成功\" : \"失败\"}\n </Badge>\n </TableCell>\n <TableCell>{formatDuration(log.duration)}</TableCell>\n <TableCell className=\"text-muted-foreground text-sm\">\n {formatTimestamp(log.timestamp)}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </ScrollArea>\n )}\n </div>\n\n {/* 右侧详情面板 */}\n {selectedLog && (\n <div\n className=\"w-96 border-l pl-4\"\n onMouseEnter={handleDetailMouseEnter}\n >\n <CallLogDetail log={selectedLog} />\n </div>\n )}\n </div>\n </DialogContent>\n </Dialog>\n );\n}\n\n// 复制按钮组件\ninterface CopyButtonProps {\n size?: \"sm\" | \"default\" | \"lg\";\n copyContent: string;\n className?: string;\n}\n\nfunction CopyButton({\n size = \"sm\",\n copyContent,\n className = \"\",\n}: CopyButtonProps) {\n const [copied, setCopied] = useState(false);\n\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(copyContent);\n setCopied(true);\n\n // 3秒后自动恢复状态\n setTimeout(() => {\n setCopied(false);\n }, 3000);\n } catch (error) {\n console.error(\"复制失败:\", error);\n }\n };\n\n return (\n <Button\n variant=\"ghost\"\n size={size}\n className={`${className} ${\n copied ? \"text-green-600 hover:text-green-700\" : \"\"\n }`}\n onClick={handleCopy}\n >\n {copied ? <CheckIcon /> : <CopyIcon />}\n </Button>\n );\n}\n\n// 详情展示组件\ninterface CallLogDetailProps {\n log: ToolCallRecord;\n}\n\nfunction CallLogDetail({ log }: CallLogDetailProps) {\n const formatRawData = (log: ToolCallRecord) => {\n try {\n return JSON.stringify(log, null, 2);\n } catch (error) {\n return String(log);\n }\n };\n\n return (\n <Card className=\"h-[60vh]\">\n <div className=\"p-4 h-full flex flex-col\">\n {/* 详情内容 */}\n <Tabs defaultValue=\"arguments\" className=\"flex-1 flex flex-col min-h-0\">\n <TabsList className=\"grid w-full grid-cols-3 flex-shrink-0\">\n <TabsTrigger value=\"arguments\">入参</TabsTrigger>\n <TabsTrigger value=\"result\">出参</TabsTrigger>\n <TabsTrigger value=\"raw\">原始数据</TabsTrigger>\n </TabsList>\n\n <div className=\"flex-1 min-h-0\">\n <TabsContent\n value=\"arguments\"\n className=\"h-full data-[state=active]:flex data-[state=active]:flex-col\"\n >\n <ScrollArea className=\"h-full\">\n {log.arguments ? (\n <div className=\"relative\">\n <pre className=\"text-xs bg-muted p-3 rounded-md overflow-x-auto text-wrap break-words\">\n {formatJson(log.arguments)}\n </pre>\n <CopyButton\n copyContent={formatJson(log.arguments) || \"\"}\n className=\"absolute top-2 right-2 hover:bg-slate-200 w-[30px] h-[30px]\"\n />\n </div>\n ) : (\n <div className=\"text-center text-muted-foreground py-8\">\n <Code className=\"h-8 w-8 mx-auto mb-2 opacity-50\" />\n <p>无入参</p>\n </div>\n )}\n </ScrollArea>\n </TabsContent>\n\n <TabsContent\n value=\"result\"\n className=\"h-full data-[state=active]:flex data-[state=active]:flex-col\"\n >\n <ScrollArea className=\"h-full\">\n {log.success ? (\n log.result ? (\n <div className=\"relative\">\n <pre className=\"text-xs bg-muted p-3 rounded-md overflow-x-auto text-wrap break-words\">\n {formatJson(log.result)}\n </pre>\n <CopyButton\n copyContent={formatJson(log.result) || \"\"}\n className=\"absolute top-2 right-2 hover:bg-slate-200 w-[30px] h-[30px]\"\n />\n </div>\n ) : (\n <div className=\"text-center text-muted-foreground py-8\">\n <CheckCircle className=\"h-8 w-8 mx-auto mb-2 opacity-50\" />\n <p>无出参</p>\n </div>\n )\n ) : (\n <div className=\"relative\">\n <div className=\"bg-destructive/10 border border-destructive/20 p-3 rounded-md\">\n <div className=\"flex items-center gap-2 mb-2\">\n <XCircle className=\"h-4 w-4 text-destructive\" />\n <span className=\"font-medium text-destructive\">\n 调用失败\n </span>\n </div>\n {log.error && (\n <pre className=\"text-xs text-destructive/80 whitespace-pre-wrap\">\n {log.error}\n </pre>\n )}\n </div>\n {log.error && (\n <CopyButton\n copyContent={log.error || \"\"}\n className=\"absolute top-2 right-2\"\n />\n )}\n </div>\n )}\n </ScrollArea>\n </TabsContent>\n\n <TabsContent\n value=\"raw\"\n className=\"h-full data-[state=active]:flex data-[state=active]:flex-col\"\n >\n <ScrollArea className=\"h-full\">\n <div className=\"relative\">\n <pre className=\"text-xs bg-muted p-3 rounded-md overflow-x-auto text-wrap break-words\">\n {formatRawData(log)}\n </pre>\n <CopyButton\n copyContent={formatRawData(log)}\n className=\"absolute top-2 right-2 hover:bg-slate-200 w-[30px] h-[30px]\"\n />\n </div>\n </ScrollArea>\n </TabsContent>\n </div>\n </Tabs>\n\n <Separator className=\"my-4 flex-shrink-0\" />\n <div className=\"text-xs text-muted-foreground flex justify-between flex-shrink-0\">\n <span>耗时: {formatDuration(log.duration)}</span>\n <span>{formatTimestamp(log.timestamp)}</span>\n </div>\n </div>\n </Card>\n );\n}\n","import * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { type VariantProps, cva } from \"class-variance-authority\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst labelVariants = cva(\n \"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\"\n);\n\nconst Label = React.forwardRef<\n React.ElementRef<typeof LabelPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &\n VariantProps<typeof labelVariants>\n>(({ className, ...props }, ref) => (\n <LabelPrimitive.Root\n ref={ref}\n className={cn(labelVariants(), className)}\n {...props}\n />\n));\nLabel.displayName = LabelPrimitive.Root.displayName;\n\nexport { Label };\n","import type * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport * as React from \"react\";\nimport {\n Controller,\n type ControllerProps,\n type FieldPath,\n type FieldValues,\n FormProvider,\n useFormContext,\n} from \"react-hook-form\";\n\nimport { Label } from \"@/components/ui/label\";\nimport { cn } from \"@/lib/utils\";\n\nconst Form = FormProvider;\n\ntype FormFieldContextValue<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n> = {\n name: TName;\n};\n\nconst FormFieldContext = React.createContext<FormFieldContextValue>(\n {} as FormFieldContextValue\n);\n\nconst FormField = <\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n>({\n ...props\n}: ControllerProps<TFieldValues, TName>) => {\n return (\n <FormFieldContext.Provider value={{ name: props.name }}>\n <Controller {...props} />\n </FormFieldContext.Provider>\n );\n};\n\nconst useFormField = () => {\n const fieldContext = React.useContext(FormFieldContext);\n const itemContext = React.useContext(FormItemContext);\n const { getFieldState, formState } = useFormContext();\n\n const fieldState = getFieldState(fieldContext.name, formState);\n\n if (!fieldContext) {\n throw new Error(\"useFormField should be used within <FormField>\");\n }\n\n const { id } = itemContext;\n\n return {\n id,\n name: fieldContext.name,\n formItemId: `${id}-form-item`,\n formDescriptionId: `${id}-form-item-description`,\n formMessageId: `${id}-form-item-message`,\n ...fieldState,\n };\n};\n\ntype FormItemContextValue = {\n id: string;\n};\n\nconst FormItemContext = React.createContext<FormItemContextValue>(\n {} as FormItemContextValue\n);\n\nconst FormItem = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => {\n const id = React.useId();\n\n return (\n <FormItemContext.Provider value={{ id }}>\n <div ref={ref} className={cn(\"space-y-2\", className)} {...props} />\n </FormItemContext.Provider>\n );\n});\nFormItem.displayName = \"FormItem\";\n\nconst FormLabel = React.forwardRef<\n React.ElementRef<typeof LabelPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>\n>(({ className, ...props }, ref) => {\n const { error, formItemId } = useFormField();\n\n return (\n <Label\n ref={ref}\n className={cn(error && \"text-destructive\", className)}\n htmlFor={formItemId}\n {...props}\n />\n );\n});\nFormLabel.displayName = \"FormLabel\";\n\nconst FormControl = React.forwardRef<\n React.ElementRef<typeof Slot>,\n React.ComponentPropsWithoutRef<typeof Slot>\n>(({ ...props }, ref) => {\n const { error, formItemId, formDescriptionId, formMessageId } =\n useFormField();\n\n return (\n <Slot\n ref={ref}\n id={formItemId}\n aria-describedby={\n !error\n ? `${formDescriptionId}`\n : `${formDescriptionId} ${formMessageId}`\n }\n aria-invalid={!!error}\n {...props}\n />\n );\n});\nFormControl.displayName = \"FormControl\";\n\nconst FormDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => {\n const { formDescriptionId } = useFormField();\n\n return (\n <p\n ref={ref}\n id={formDescriptionId}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n );\n});\nFormDescription.displayName = \"FormDescription\";\n\nconst FormMessage = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, children, ...props }, ref) => {\n const { error, formMessageId } = useFormField();\n const body = error ? String(error?.message ?? \"\") : children;\n\n if (!body) {\n return null;\n }\n\n return (\n <p\n ref={ref}\n id={formMessageId}\n className={cn(\"text-sm font-medium text-destructive\", className)}\n {...props}\n >\n {body}\n </p>\n );\n});\nFormMessage.displayName = \"FormMessage\";\n\nexport {\n useFormField,\n Form,\n FormItem,\n FormLabel,\n FormControl,\n FormDescription,\n FormMessage,\n FormField,\n};\n","/**\n * WebSocket 连接状态管理 Store (重构版)\n *\n * 职责:\n * - 纯 WebSocket 连接状态管理\n * - 集成 WebSocketManager 单例\n * - 提供连接控制方法\n * - 保持向后兼容性\n *\n * 注意:\n * - 配置数据管理已迁移到 stores/config.ts\n * - 状态数据管理已迁移到 stores/status.ts\n */\n\nimport { ConnectionState, webSocketManager } from \"@services/websocket\";\nimport { create } from \"zustand\";\nimport { devtools } from \"zustand/middleware\";\nimport { useShallow } from \"zustand/react/shallow\";\n\n/**\n * 端口变更状态接口(保留用于端口切换功能)\n */\ninterface PortChangeStatus {\n status:\n | \"idle\"\n | \"checking\"\n | \"polling\"\n | \"connecting\"\n | \"completed\"\n | \"failed\";\n targetPort?: number;\n currentAttempt?: number;\n maxAttempts?: number;\n error?: string;\n timestamp: number;\n}\n\n/**\n * WebSocket 连接统计信息\n */\ninterface ConnectionStats {\n reconnectAttempts: number;\n maxReconnectAttempts: number;\n lastHeartbeat: number;\n eventListenerCount: number;\n}\n\n/**\n * WebSocket Store 状态(简化版)\n */\ninterface WebSocketState {\n // WebSocket 连接状态\n connectionState: ConnectionState;\n wsUrl: string;\n\n // 连接统计信息\n connectionStats: ConnectionStats;\n\n // 端口变更状态(保留用于端口切换功能)\n portChangeStatus?: PortChangeStatus;\n\n // 连接错误信息\n lastError: Error | null;\n\n // 连接时间戳\n connectedAt: number | null;\n disconnectedAt: number | null;\n}\n\n/**\n * WebSocket Store 操作方法(简化版)\n */\ninterface WebSocketActions {\n // 基础连接状态管理\n setConnectionState: (state: ConnectionState) => void;\n setWsUrl: (url: string) => void;\n setConnectionStats: (stats: ConnectionStats) => void;\n setLastError: (error: Error | null) => void;\n\n // 端口变更状态管理(保留用于端口切换功能)\n setPortChangeStatus: (portChangeStatus: PortChangeStatus | undefined) => void;\n\n // WebSocket 连接控制\n connect: () => Promise<void>;\n disconnect: () => void;\n reconnect: () => Promise<void>;\n send: (message: any) => boolean;\n\n // URL 管理\n updateUrl: (url: string) => void;\n\n // 工具方法\n reset: () => void;\n initialize: () => void;\n getConnectionInfo: () => {\n state: ConnectionState;\n url: string;\n stats: ConnectionStats;\n isConnected: boolean;\n };\n\n // 向后兼容的方法(废弃)\n /** @deprecated 使用 setConnectionState 替代 */\n setConnected: (connected: boolean) => void;\n}\n\nexport interface WebSocketStore extends WebSocketState, WebSocketActions {}\n\n/**\n * 初始状态(简化版)\n */\nconst initialState: WebSocketState = {\n // WebSocket 连接状态\n connectionState: ConnectionState.DISCONNECTED,\n wsUrl: \"\",\n\n // 连接统计信息\n connectionStats: {\n reconnectAttempts: 0,\n maxReconnectAttempts: 5,\n lastHeartbeat: 0,\n eventListenerCount: 0,\n },\n\n // 端口变更状态\n portChangeStatus: undefined,\n\n // 连接错误信息\n lastError: null,\n\n // 连接时间戳\n connectedAt: null,\n disconnectedAt: null,\n};\n\n/**\n * 创建 WebSocket Store(重构版)\n */\nexport const useWebSocketStore = create<WebSocketStore>()(\n devtools(\n (set, get) => ({\n ...initialState,\n\n // ==================== 基础连接状态管理 ====================\n\n setConnectionState: (connectionState: ConnectionState) => {\n console.log(\"[WebSocketStore] 更新连接状态:\", connectionState);\n\n const now = Date.now();\n const updates: Partial<WebSocketState> = { connectionState };\n\n // 更新连接时间戳\n if (connectionState === ConnectionState.CONNECTED) {\n updates.connectedAt = now;\n updates.lastError = null;\n } else if (connectionState === ConnectionState.DISCONNECTED) {\n updates.disconnectedAt = now;\n }\n\n set(updates, false, \"setConnectionState\");\n\n // 同步更新 WebSocketManager 的统计信息\n const stats = webSocketManager.getConnectionStats();\n get().setConnectionStats(stats);\n },\n\n setWsUrl: (wsUrl: string) => {\n console.log(\"[WebSocketStore] 更新 WebSocket URL:\", wsUrl);\n set({ wsUrl }, false, \"setWsUrl\");\n },\n\n setConnectionStats: (connectionStats: ConnectionStats) => {\n set({ connectionStats }, false, \"setConnectionStats\");\n },\n\n setLastError: (lastError: Error | null) => {\n console.log(\"[WebSocketStore] 更新连接错误:\", lastError?.message);\n set({ lastError }, false, \"setLastError\");\n },\n\n // ==================== 端口变更状态管理 ====================\n\n setPortChangeStatus: (portChangeStatus: PortChangeStatus | undefined) => {\n console.log(\n \"[WebSocketStore] 更新端口变更状态:\",\n portChangeStatus?.status\n );\n set({ portChangeStatus }, false, \"setPortChangeStatus\");\n },\n\n // ==================== WebSocket 连接控制 ====================\n\n connect: async (): Promise<void> => {\n try {\n console.log(\"[WebSocketStore] 开始连接 WebSocket\");\n webSocketManager.connect();\n } catch (error) {\n const err = error instanceof Error ? error : new Error(\"连接失败\");\n console.error(\"[WebSocketStore] 连接失败:\", err);\n get().setLastError(err);\n throw err;\n }\n },\n\n disconnect: () => {\n console.log(\"[WebSocketStore] 断开 WebSocket 连接\");\n webSocketManager.disconnect();\n },\n\n reconnect: async (): Promise<void> => {\n try {\n console.log(\"[WebSocketStore] 重新连接 WebSocket\");\n webSocketManager.disconnect();\n await new Promise((resolve) => setTimeout(resolve, 1000));\n webSocketManager.connect();\n } catch (error) {\n const err = error instanceof Error ? error : new Error(\"重连失败\");\n console.error(\"[WebSocketStore] 重连失败:\", err);\n get().setLastError(err);\n throw err;\n }\n },\n\n send: (message: any): boolean => {\n try {\n return webSocketManager.send(message);\n } catch (error) {\n const err =\n error instanceof Error ? error : new Error(\"发送消息失败\");\n console.error(\"[WebSocketStore] 发送消息失败:\", err);\n get().setLastError(err);\n return false;\n }\n },\n\n // ==================== URL 管理 ====================\n\n updateUrl: (url: string) => {\n console.log(\"[WebSocketStore] 更新 WebSocket URL:\", url);\n webSocketManager.setUrl(url);\n get().setWsUrl(url);\n },\n\n // ==================== 工具方法 ====================\n\n getConnectionInfo: () => {\n const state = get();\n return {\n state: state.connectionState,\n url: state.wsUrl,\n stats: state.connectionStats,\n isConnected: state.connectionState === ConnectionState.CONNECTED,\n };\n },\n\n reset: () => {\n console.log(\"[WebSocketStore] 重置状态\");\n set(initialState, false, \"reset\");\n },\n\n // ==================== 初始化方法 ====================\n\n initialize: () => {\n console.log(\"[WebSocketStore] 初始化 WebSocket Store\");\n\n // 设置 WebSocket 事件监听\n webSocketManager.subscribe(\"connection:connecting\", () => {\n get().setConnectionState(ConnectionState.CONNECTING);\n });\n\n webSocketManager.subscribe(\"connection:connected\", () => {\n get().setConnectionState(ConnectionState.CONNECTED);\n });\n\n webSocketManager.subscribe(\"connection:disconnected\", () => {\n get().setConnectionState(ConnectionState.DISCONNECTED);\n });\n\n webSocketManager.subscribe(\"connection:reconnecting\", () => {\n get().setConnectionState(ConnectionState.RECONNECTING);\n const stats = webSocketManager.getConnectionStats();\n get().setConnectionStats(stats);\n });\n\n webSocketManager.subscribe(\"connection:error\", ({ error }) => {\n get().setLastError(error);\n });\n\n webSocketManager.subscribe(\"system:heartbeat\", () => {\n const stats = webSocketManager.getConnectionStats();\n get().setConnectionStats(stats);\n });\n\n // 初始化连接状态\n const initialStats = webSocketManager.getConnectionStats();\n get().setConnectionStats(initialStats);\n get().setWsUrl(webSocketManager.getUrl());\n\n console.log(\"[WebSocketStore] WebSocket Store 初始化完成\");\n },\n\n // ==================== 向后兼容方法 ====================\n\n /** @deprecated 使用 setConnectionState 替代 */\n setConnected: (connected: boolean) => {\n console.warn(\n \"[WebSocketStore] setConnected 方法已废弃,请使用 setConnectionState\"\n );\n const connectionState: ConnectionState = connected\n ? ConnectionState.CONNECTED\n : ConnectionState.DISCONNECTED;\n get().setConnectionState(connectionState);\n },\n }),\n {\n name: \"websocket-store\",\n }\n )\n);\n\n// ==================== 选择器 Hooks ====================\n\n/**\n * 获取连接状态\n */\nexport const useWebSocketConnectionState = () =>\n useWebSocketStore((state) => state.connectionState);\n\n/**\n * 获取连接状态(布尔值)\n */\nexport const useWebSocketConnected = () =>\n useWebSocketStore(\n (state) => state.connectionState === ConnectionState.CONNECTED\n );\n\n/**\n * 获取 WebSocket URL\n */\nexport const useWebSocketUrl = () => useWebSocketStore((state) => state.wsUrl);\n\n/**\n * 获取连接统计信息\n */\nexport const useWebSocketConnectionStats = () =>\n useWebSocketStore((state) => state.connectionStats);\n\n/**\n * 获取端口变更状态\n */\nexport const useWebSocketPortChangeStatus = () =>\n useWebSocketStore((state) => state.portChangeStatus);\n\n/**\n * 获取最后的连接错误\n */\nexport const useWebSocketLastError = () =>\n useWebSocketStore((state) => state.lastError);\n\n/**\n * 获取连接时间戳\n */\nexport const useWebSocketConnectionTimes = () =>\n useWebSocketStore(\n useShallow((state) => ({\n connectedAt: state.connectedAt,\n disconnectedAt: state.disconnectedAt,\n }))\n );\n\n// ==================== 向后兼容的选择器(废弃) ====================\n\n// 导入兼容性选择器\nimport {\n useWebSocketConfig as useWebSocketConfigCompat,\n useWebSocketMcpEndpoint as useWebSocketMcpEndpointCompat,\n useWebSocketMcpServerConfig as useWebSocketMcpServerConfigCompat,\n useWebSocketMcpServers as useWebSocketMcpServersCompat,\n useWebSocketRestartStatus as useWebSocketRestartStatusCompat,\n useWebSocketStatus as useWebSocketStatusCompat,\n} from \"./websocket-compat\";\n\n/**\n * @deprecated 配置数据已迁移到 stores/config.ts,请使用 useConfig()\n */\nexport const useWebSocketConfig = useWebSocketConfigCompat;\n\n/**\n * @deprecated 状态数据已迁移到 stores/status.ts,请使用 useClientStatus()\n */\nexport const useWebSocketStatus = useWebSocketStatusCompat;\n\n/**\n * @deprecated 重启状态已迁移到 stores/status.ts,请使用 useRestartStatus()\n */\nexport const useWebSocketRestartStatus = useWebSocketRestartStatusCompat;\n\n/**\n * @deprecated MCP 服务器数据已迁移到 stores/config.ts,请使用 useMcpServers()\n */\nexport const useWebSocketMcpServers = useWebSocketMcpServersCompat;\n\n/**\n * @deprecated MCP 服务器配置已迁移到 stores/config.ts,请使用 useMcpServerConfig()\n */\nexport const useWebSocketMcpServerConfig = useWebSocketMcpServerConfigCompat;\n\n/**\n * @deprecated MCP 端点已迁移到 stores/config.ts,请使用 useMcpEndpoint()\n */\nexport const useWebSocketMcpEndpoint = useWebSocketMcpEndpointCompat;\n\n/**\n * @deprecated MCP 端点已迁移到 stores/config.ts,请使用 useMcpEndpoint()\n */\nexport const useMcpEndpoint = useWebSocketMcpEndpointCompat;\n\n// ==================== 复合选择器 ====================\n\n/**\n * 获取连接相关信息\n */\nexport const useWebSocketConnectionInfo = () =>\n useWebSocketStore(\n useShallow((state) => ({\n connected: state.connectionState === ConnectionState.CONNECTED,\n connectionState: state.connectionState,\n wsUrl: state.wsUrl,\n stats: state.connectionStats,\n lastError: state.lastError,\n connectedAt: state.connectedAt,\n disconnectedAt: state.disconnectedAt,\n }))\n );\n\n/**\n * 获取端口变更相关信息\n */\nexport const useWebSocketPortInfo = () =>\n useWebSocketStore(\n useShallow((state) => ({\n portChangeStatus: state.portChangeStatus,\n wsUrl: state.wsUrl,\n }))\n );\n\n// ==================== 操作方法 Hooks ====================\n\n/**\n * 获取 WebSocket 操作方法\n */\nexport const useWebSocketActions = () =>\n useWebSocketStore(\n useShallow((state) => ({\n // 连接状态管理\n setConnectionState: state.setConnectionState,\n setWsUrl: state.setWsUrl,\n setConnectionStats: state.setConnectionStats,\n setLastError: state.setLastError,\n\n // 端口变更状态管理\n setPortChangeStatus: state.setPortChangeStatus,\n\n // WebSocket 连接控制\n connect: state.connect,\n disconnect: state.disconnect,\n reconnect: state.reconnect,\n send: state.send,\n\n // URL 管理\n updateUrl: state.updateUrl,\n\n // 工具方法\n reset: state.reset,\n initialize: state.initialize,\n getConnectionInfo: state.getConnectionInfo,\n\n // 向后兼容(废弃)\n setConnected: state.setConnected,\n }))\n );\n\n/**\n * 获取连接控制方法\n */\nexport const useWebSocketControls = () =>\n useWebSocketStore(\n useShallow((state) => ({\n connect: state.connect,\n disconnect: state.disconnect,\n reconnect: state.reconnect,\n send: state.send,\n updateUrl: state.updateUrl,\n isConnected: state.connectionState === ConnectionState.CONNECTED,\n }))\n );\n\n// ==================== 向后兼容的复合选择器(废弃) ====================\n\n/**\n * @deprecated 数据已分离到不同的 stores,请使用对应的选择器\n */\nexport const useWebSocketData = () => {\n console.warn(\"useWebSocketData 已废弃,请使用对应的专门 stores\");\n return {\n config: null,\n status: null,\n };\n};\n","/**\n * 端口连通性检测工具函数\n */\n\n/**\n * 检测指定端口是否可用\n * @param port 端口号\n * @param timeout 超时时间(毫秒),默认3秒\n * @returns Promise<boolean> 端口是否可用\n */\nexport async function checkPortAvailability(\n port: number,\n timeout = 3000\n): Promise<boolean> {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n // 尝试连接到服务端的健康检查端点\n // 先尝试 WebServer 的 /api/status 端点,如果失败再尝试 MCPServer 的 /health 端点\n let response: Response;\n try {\n response = await fetch(`http://localhost:${port}/api/status`, {\n method: \"GET\",\n signal: controller.signal,\n });\n } catch {\n // 如果 /api/status 失败,尝试 /health 端点\n response = await fetch(`http://localhost:${port}/health`, {\n method: \"GET\",\n signal: controller.signal,\n });\n }\n\n clearTimeout(timeoutId);\n return response.ok;\n } catch (error) {\n // 连接失败或超时\n return false;\n }\n}\n\n/**\n * 轮询检测端口直到可用或超时\n * @param port 端口号\n * @param maxAttempts 最大尝试次数,默认30次\n * @param interval 检测间隔(毫秒),默认2秒\n * @param onProgress 进度回调函数\n * @returns Promise<boolean> 是否在超时前检测到端口可用\n */\nexport async function pollPortUntilAvailable(\n port: number,\n maxAttempts = 30,\n interval = 2000,\n onProgress?: (attempt: number, maxAttempts: number) => void\n): Promise<boolean> {\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n if (onProgress) {\n onProgress(attempt, maxAttempts);\n }\n\n const isAvailable = await checkPortAvailability(port, 1000);\n if (isAvailable) {\n return true;\n }\n\n // 如果不是最后一次尝试,等待指定间隔\n if (attempt < maxAttempts) {\n await new Promise((resolve) => setTimeout(resolve, interval));\n }\n }\n\n return false;\n}\n\n/**\n * 构建 WebSocket URL\n * @param port 端口号\n * @param hostname 主机名,默认使用当前页面的 hostname\n * @returns WebSocket URL\n */\nexport function buildWebSocketUrl(port: number, hostname?: string): string {\n const protocol = window.location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n const host = hostname || window.location.hostname || \"localhost\";\n\n // 如果是标准端口(80 for HTTP, 443 for HTTPS),不显示端口号\n if (\n (protocol === \"ws:\" && port === 80) ||\n (protocol === \"wss:\" && port === 443)\n ) {\n return `${protocol}//${host}`;\n }\n\n return `${protocol}//${host}:${port}`;\n}\n\n/**\n * 从 WebSocket URL 中提取端口号\n * @param url WebSocket URL\n * @returns 端口号,如果无法提取则返回 null\n */\nexport function extractPortFromUrl(url: string): number | null {\n try {\n const urlObj = new URL(url);\n const port = Number.parseInt(urlObj.port);\n return Number.isNaN(port) ? null : port;\n } catch {\n return null;\n }\n}\n","/**\n * WebSocket Hook - 重构版本(第二阶段)\n *\n * 重构内容:\n * - 移除直接的 WebSocket 实例创建,使用 WebSocketManager 单例\n * - 集成新的 config 和 status stores\n * - 使用事件总线进行消息处理\n * - 保持向后兼容性,现有组件无需修改\n *\n * 架构说明:\n * - WebSocketManager: 单例 WebSocket 连接管理\n * - ConfigStore: 配置数据统一管理\n * - StatusStore: 状态数据统一管理\n * - WebSocketStore: 纯连接状态管理\n */\n\nimport type { AppConfig, ClientStatus } from \"@/types/index\";\nimport { webSocketManager } from \"@services/websocket\";\nimport { useConfig, useConfigActions } from \"@stores/config\";\nimport {\n useClientStatus,\n useRestartStatus,\n useStatusActions,\n} from \"@stores/status\";\nimport { useWebSocketActions } from \"@stores/websocket\";\nimport {\n buildWebSocketUrl,\n checkPortAvailability,\n extractPortFromUrl,\n} from \"@utils/portUtils\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\n/**\n * 向后兼容的状态接口\n */\ninterface WebSocketState {\n connected: boolean;\n config: AppConfig | null;\n status: ClientStatus | null;\n restartStatus?: {\n status: \"restarting\" | \"completed\" | \"failed\";\n error?: string;\n timestamp: number;\n };\n}\n\n/**\n * useWebSocket Hook - 重构版本\n *\n * @deprecated 建议使用新的专用 hooks:\n * - useWebSocketConnection() 用于连接管理\n * - useConfigData() 用于配置数据\n * - useStatusData() 用于状态数据\n */\nexport function useWebSocket() {\n console.warn(\n \"[useWebSocket] 此 hook 已重构,建议使用新的专用 hooks:useWebSocketConnection()、useConfigData()、useStatusData()\"\n );\n\n // 使用新的 stores 获取数据\n const config = useConfig();\n const clientStatus = useClientStatus();\n const restartStatus = useRestartStatus();\n\n // 获取 store actions\n const webSocketActions = useWebSocketActions();\n const configActions = useConfigActions();\n const statusActions = useStatusActions();\n\n // 向后兼容的本地状态\n const [wsUrl, setWsUrl] = useState<string>(\"\");\n const isInitialized = useRef(false);\n\n // 初始化 WebSocket 连接和数据加载\n useEffect(() => {\n if (isInitialized.current) return;\n isInitialized.current = true;\n\n console.log(\"[useWebSocket] 初始化 WebSocket 连接和数据加载\");\n\n // 确保 WebSocket 连接\n if (!webSocketManager.isConnected()) {\n webSocketManager.connect();\n }\n\n // 获取当前 WebSocket URL\n const currentUrl = webSocketManager.getUrl();\n setWsUrl(currentUrl);\n\n // 初始化数据加载\n const initializeData = async () => {\n try {\n // 并行加载配置和状态数据\n await Promise.allSettled([\n configActions.getConfig(),\n statusActions.getStatus(),\n ]);\n console.log(\"[useWebSocket] 初始数据加载完成\");\n } catch (error) {\n console.error(\"[useWebSocket] 初始数据加载失败:\", error);\n }\n };\n\n initializeData();\n }, [configActions, statusActions]);\n\n // 动态获取WebSocket连接地址(向后兼容)\n const getWebSocketUrl = useCallback((configPort?: number) => {\n // 优先使用localStorage中保存的地址\n const savedUrl = localStorage.getItem(\"xiaozhi-ws-url\");\n if (savedUrl) {\n return savedUrl;\n }\n\n // 确定要使用的端口号\n let targetPort = 9999; // 默认端口\n\n // 如果传入了配置端口,使用配置端口\n if (configPort) {\n targetPort = configPort;\n } else if (window.location.port) {\n // 如果当前页面有端口号,使用当前页面的端口号\n const currentPort = Number.parseInt(window.location.port);\n if (!Number.isNaN(currentPort)) {\n targetPort = currentPort;\n }\n } else if (window.location.protocol === \"http:\" && !window.location.port) {\n // 标准 HTTP 端口 (80)\n targetPort = 80;\n } else if (window.location.protocol === \"https:\" && !window.location.port) {\n // 标准 HTTPS 端口 (443)\n targetPort = 443;\n }\n\n // 构建 WebSocket URL\n return buildWebSocketUrl(targetPort);\n }, []);\n\n // 向后兼容的状态计算\n const state: WebSocketState = {\n connected: webSocketManager.isConnected(),\n config: config,\n status: clientStatus,\n restartStatus: restartStatus || undefined,\n };\n\n // 重构后的配置更新方法\n const updateConfig = useCallback(\n async (config: AppConfig): Promise<void> => {\n console.log(\"[useWebSocket] updateConfig 调用,使用新的 configActions\");\n try {\n await configActions.updateConfig(config);\n } catch (error) {\n console.error(\"[useWebSocket] 配置更新失败:\", error);\n throw error;\n }\n },\n [configActions]\n );\n\n // 重构后的状态刷新方法\n const refreshStatus = useCallback(async () => {\n console.log(\"[useWebSocket] refreshStatus 调用,使用新的 statusActions\");\n try {\n await statusActions.refreshStatus();\n } catch (error) {\n console.error(\"[useWebSocket] 状态刷新失败:\", error);\n throw error;\n }\n }, [statusActions]);\n\n // 重构后的服务重启方法\n const restartService = useCallback(async (): Promise<void> => {\n console.log(\"[useWebSocket] restartService 调用,使用新的 statusActions\");\n try {\n await statusActions.restartService();\n } catch (error) {\n console.error(\"[useWebSocket] 服务重启失败:\", error);\n throw error;\n }\n }, [statusActions]);\n\n // 保存自定义WebSocket地址\n const setCustomWsUrl = useCallback(\n (url: string) => {\n console.log(\"[useWebSocket] setCustomWsUrl 调用,使用 WebSocketManager\");\n if (url) {\n localStorage.setItem(\"xiaozhi-ws-url\", url);\n webSocketManager.setUrl(url);\n } else {\n localStorage.removeItem(\"xiaozhi-ws-url\");\n // 恢复默认 URL\n const defaultUrl = getWebSocketUrl();\n webSocketManager.setUrl(defaultUrl);\n }\n // 更新本地状态\n setWsUrl(webSocketManager.getUrl());\n },\n [getWebSocketUrl]\n );\n\n // 端口切换核心函数\n const changePort = useCallback(\n async (newPort: number): Promise<void> => {\n const currentPort = extractPortFromUrl(wsUrl) || 9999;\n\n // 如果端口号相同,直接返回\n if (currentPort === newPort) {\n return;\n }\n\n // 更新端口切换状态\n webSocketActions.setPortChangeStatus({\n status: \"checking\",\n targetPort: newPort,\n timestamp: Date.now(),\n });\n\n try {\n // 更新端口切换状态\n webSocketActions.setPortChangeStatus({\n status: \"checking\",\n targetPort: newPort,\n timestamp: Date.now(),\n });\n\n // 检查端口可用性\n const isAvailable = await checkPortAvailability(newPort);\n if (!isAvailable) {\n throw new Error(`端口 ${newPort} 不可用`);\n }\n\n // 构建新的 WebSocket URL\n const newUrl = buildWebSocketUrl(newPort);\n\n // 更新 WebSocket URL\n webSocketManager.setUrl(newUrl);\n setWsUrl(newUrl);\n\n // 成功完成端口切换\n console.log(`[WebSocket] 端口切换到 ${newPort} 成功完成`);\n webSocketActions.setPortChangeStatus({\n status: \"completed\",\n targetPort: newPort,\n timestamp: Date.now(),\n });\n } catch (error) {\n // 端口切换失败\n const errorMessage =\n error instanceof Error ? error.message : \"端口切换失败\";\n console.error(`[WebSocket] 端口切换到 ${newPort} 失败:`, errorMessage);\n\n webSocketActions.setPortChangeStatus({\n status: \"failed\",\n targetPort: newPort,\n error: errorMessage,\n timestamp: Date.now(),\n });\n throw error;\n }\n },\n [wsUrl, webSocketActions]\n );\n\n return {\n ...state,\n updateConfig,\n refreshStatus,\n restartService,\n wsUrl,\n setCustomWsUrl,\n changePort,\n };\n}\n","import { Button } from \"@/components/ui/button\";\nimport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from \"@/components/ui/dialog\";\nimport {\n Form,\n FormControl,\n FormField,\n FormItem,\n FormMessage,\n} from \"@/components/ui/form\";\nimport { Input } from \"@/components/ui/input\";\nimport { useWebSocket } from \"@/hooks/useWebSocket\";\nimport { useConfig } from \"@/stores/config\";\nimport {\n useWebSocketConnected,\n useWebSocketPortChangeStatus,\n} from \"@/stores/websocket\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport { SettingsIcon } from \"lucide-react\";\nimport { useEffect, useState } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport { toast } from \"sonner\";\nimport z from \"zod\";\n\nconst formSchema = z.object({\n port: z\n .string()\n .min(1, { message: \"端口号不能为空\" })\n .refine((val) => !Number.isNaN(Number(val)), {\n message: \"请输入有效的数字\",\n })\n .refine((val) => Number(val) >= 1 && Number(val) <= 65535, {\n message: \"端口号必须在 1-65535 之间\",\n })\n .refine((val) => Number.isInteger(Number(val)), {\n message: \"端口号必须是整数\",\n }),\n});\n\nexport function WebUrlSettingButton() {\n const [open, setOpen] = useState(false);\n const [isLoading, setIsLoading] = useState(false);\n const config = useConfig();\n const connected = useWebSocketConnected();\n const portChangeStatus = useWebSocketPortChangeStatus();\n const { changePort } = useWebSocket();\n\n const form = useForm<z.infer<typeof formSchema>>({\n resolver: zodResolver(formSchema),\n defaultValues: {\n port: \"9999\",\n },\n });\n\n // 当配置加载后,更新表单默认值\n useEffect(() => {\n if (config?.webUI?.port) {\n form.reset({\n port: config.webUI.port.toString(),\n });\n }\n }, [config, form]);\n\n // 获取按钮文本\n const getButtonText = () => {\n if (isLoading) {\n return \"处理中...\";\n }\n\n if (portChangeStatus?.status === \"checking\") {\n return \"检测端口...\";\n }\n\n if (portChangeStatus?.status === \"polling\") {\n const { currentAttempt, maxAttempts } = portChangeStatus;\n return `等待服务重启 (${currentAttempt || 0}/${maxAttempts || 45})`;\n }\n\n if (portChangeStatus?.status === \"connecting\") {\n return \"连接中...\";\n }\n\n return connected ? \"保存并重启\" : \"保存并连接\";\n };\n\n async function onSubmit(values: z.infer<typeof formSchema>) {\n const newPort = Number(values.port);\n const currentPort = config?.webUI?.port;\n\n // 如果端口号没有变化,直接关闭对话框\n if (newPort === currentPort) {\n setOpen(false);\n return;\n }\n\n console.log(\n `[WebUrlSettingButton] 开始端口切换: ${currentPort} -> ${newPort}`\n );\n setIsLoading(true);\n\n try {\n // 显示开始处理的提示\n toast.info(\n connected\n ? `正在将端口从 ${currentPort} 切换到 ${newPort}...`\n : `正在连接到端口 ${newPort}...`\n );\n\n await changePort(newPort);\n\n // 成功提示\n toast.success(\n connected\n ? `端口已成功切换到 ${newPort},页面即将刷新...`\n : `已成功连接到端口 ${newPort},页面即将刷新...`\n );\n setOpen(false);\n } catch (error) {\n console.error(\"端口切换失败:\", error);\n const errorMessage =\n error instanceof Error ? error.message : \"端口切换失败\";\n toast.error(`端口切换失败: ${errorMessage}`);\n } finally {\n setIsLoading(false);\n }\n }\n\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n <DialogTrigger asChild>\n <Button variant=\"secondary\" size=\"icon\" className=\"size-8\">\n <SettingsIcon className=\"h-4 w-4\" />\n </Button>\n </DialogTrigger>\n <DialogContent className=\"sm:max-w-[250px]\">\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)}>\n <DialogHeader className=\"mb-4\">\n <DialogTitle>配置服务端端口</DialogTitle>\n <DialogDescription>\n {connected\n ? \"修改端口后将自动重启服务并重新连接。\"\n : \"请输入服务端端口号,系统将尝试连接。\"}\n </DialogDescription>\n </DialogHeader>\n <div className=\"flex items-center gap-2\">\n <div>ws://{window.location.hostname}:</div>\n <div className=\"w-[100px]\">\n <FormField\n control={form.control}\n name=\"port\"\n render={({ field }) => (\n <FormItem>\n <FormControl>\n <Input\n placeholder=\"服务端端口,默认9999\"\n className=\"font-mono text-sm\"\n disabled={isLoading}\n type=\"number\"\n {...field}\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n </div>\n </div>\n <DialogFooter className=\"mt-4\">\n <DialogClose asChild>\n <Button variant=\"outline\" disabled={isLoading}>\n 取消\n </Button>\n </DialogClose>\n <Button\n type=\"submit\"\n disabled={isLoading || portChangeStatus?.status === \"polling\"}\n >\n {getButtonText()}\n </Button>\n </DialogFooter>\n </form>\n </Form>\n </DialogContent>\n </Dialog>\n );\n}\n","import { McpEndpointSettingButton } from \"@/components/McpEndpointSettingButton\";\nimport { ToolCallLogsDialog } from \"@/components/ToolCallLogsDialog\";\nimport { WebUrlSettingButton } from \"@/components/WebUrlSettingButton\";\nimport {\n Card,\n CardDescription,\n CardFooter,\n CardHeader,\n CardTitle,\n} from \"@/components/ui/card\";\nimport { useMcpEndpoint, useMcpServers } from \"@/stores/config\";\nimport { useWebSocketConnected, useWebSocketUrl } from \"@/stores/websocket\";\n\nconst MiniCircularProgress = ({\n showValue = true,\n value = 0,\n maxValue = 100,\n size = 60,\n activeColor = \"#3b82f6\",\n inactiveColor = \"#e5e7eb\",\n symbol = \"%\",\n}) => {\n const radius = (size - 6) / 2;\n const circumference = radius * 2 * Math.PI;\n const strokeDasharray = circumference;\n // 防止除零错误,当maxValue为0时,将strokeDashoffset设为circumference(显示为空)\n const strokeDashoffset =\n maxValue === 0\n ? circumference\n : circumference - (value / maxValue) * circumference;\n\n return (\n <div className=\"relative inline-flex items-center justify-center\">\n <svg width={size} height={size} className=\"transform -rotate-90\">\n <circle\n cx={size / 2}\n cy={size / 2}\n r={radius}\n stroke={inactiveColor}\n strokeWidth={6}\n fill=\"none\"\n />\n <circle\n cx={size / 2}\n cy={size / 2}\n r={radius}\n stroke={activeColor}\n strokeWidth={6}\n fill=\"none\"\n strokeDasharray={strokeDasharray}\n strokeDashoffset={strokeDashoffset}\n strokeLinecap=\"round\"\n className=\"transition-all duration-300 ease-in-out\"\n />\n </svg>\n {showValue && (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <span className=\"text-xs font-medium\">\n {value}\n {symbol}\n </span>\n </div>\n )}\n </div>\n );\n};\n\nexport function DashboardStatusCard() {\n const mcpServers = useMcpServers();\n const connected = useWebSocketConnected();\n const mcpServerCount = Object.keys(mcpServers || {}).length;\n const wsUrl = useWebSocketUrl();\n const mcpEndpoint = useMcpEndpoint();\n return (\n <div className=\"*:data-[slot=card]:shadow-xs @xl/main:grid-cols-2 @5xl/main:grid-cols-4 grid grid-cols-1 gap-4 px-4 *:data-[slot=card]:bg-gradient-to-t *:data-[slot=card]:from-primary/5 *:data-[slot=card]:to-card dark:*:data-[slot=card]:bg-card lg:px-6\">\n <Card className=\"@container/card\">\n <CardHeader className=\"relative\">\n <CardDescription>小智接入点</CardDescription>\n <CardTitle className=\"@[250px]/card:text-3xl text-2xl font-semibold tabular-nums\">\n {Array.isArray(mcpEndpoint)\n ? mcpEndpoint.length\n : mcpEndpoint\n ? 1\n : 0}\n </CardTitle>\n <div className=\"absolute right-4 top-4 flex flex-col items-center\">\n <MiniCircularProgress\n showValue={false}\n value={\n Array.isArray(mcpEndpoint)\n ? mcpEndpoint.length\n : mcpEndpoint\n ? 1\n : 0\n }\n maxValue={Math.max(\n Array.isArray(mcpEndpoint) ? mcpEndpoint.length : 1,\n 1\n )}\n activeColor=\"#16a34a\"\n inactiveColor=\"#f87171\"\n size={30}\n symbol=\"\"\n />\n </div>\n </CardHeader>\n <CardFooter className=\"flex-col items-end gap-1 text-sm\">\n <McpEndpointSettingButton />\n </CardFooter>\n </Card>\n <Card className=\"@container/card\">\n <CardHeader className=\"relative\">\n <CardDescription>Xiaozhi Client</CardDescription>\n <CardTitle className=\"@[250px]/card:text-3xl text-2xl font-semibold tabular-nums\">\n {connected ? \"已连接\" : \"未连接\"}\n </CardTitle>\n <div className=\"absolute right-4 top-4\">\n <MiniCircularProgress\n showValue={false}\n value={1}\n maxValue={1}\n activeColor={connected ? \"#16a34a\" : \"#f87171\"}\n inactiveColor={connected ? \"#16a34a\" : \"#f87171\"}\n size={30}\n symbol=\"\"\n />\n </div>\n </CardHeader>\n <CardFooter className=\"flex items-center justify-between gap-1 text-sm\">\n <div className=\"text-muted-foreground\">{wsUrl}</div>\n <WebUrlSettingButton />\n </CardFooter>\n </Card>\n <Card className=\"@container/card\">\n <CardHeader className=\"relative\">\n <CardDescription>MCP服务</CardDescription>\n <CardTitle className=\"@[250px]/card:text-3xl text-2xl font-semibold tabular-nums\">\n {mcpServerCount}\n </CardTitle>\n <div className=\"absolute right-4 top-4\">\n <MiniCircularProgress\n showValue={false}\n value={mcpServerCount}\n maxValue={Math.max(mcpServerCount, 1)}\n activeColor=\"#16a34a\"\n inactiveColor=\"#f87171\"\n size={30}\n symbol=\"\"\n />\n </div>\n </CardHeader>\n <CardFooter className=\"flex items-center justify-between gap-1 text-sm\">\n <div className=\"text-muted-foreground\">\n 共 {mcpServerCount} 个服务\n </div>\n <ToolCallLogsDialog />\n </CardFooter>\n </Card>\n </div>\n );\n}\n","import * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\nimport { Check } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst Checkbox = React.forwardRef<\n React.ElementRef<typeof CheckboxPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>\n>(({ className, ...props }, ref) => (\n <CheckboxPrimitive.Root\n ref={ref}\n className={cn(\n \"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground\",\n className\n )}\n {...props}\n >\n <CheckboxPrimitive.Indicator\n className={cn(\"flex items-center justify-center text-current\")}\n >\n <Check className=\"h-4 w-4\" />\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n));\nCheckbox.displayName = CheckboxPrimitive.Root.displayName;\n\nexport { Checkbox };\n","import * as SelectPrimitive from \"@radix-ui/react-select\";\nimport { Check, ChevronDown, ChevronUp } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst Select = SelectPrimitive.Root;\n\nconst SelectGroup = SelectPrimitive.Group;\n\nconst SelectValue = SelectPrimitive.Value;\n\nconst SelectTrigger = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>\n>(({ className, children, ...props }, ref) => (\n <SelectPrimitive.Trigger\n ref={ref}\n className={cn(\n \"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1\",\n className\n )}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n <ChevronDown className=\"h-4 w-4 opacity-50\" />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n));\nSelectTrigger.displayName = SelectPrimitive.Trigger.displayName;\n\nconst SelectScrollUpButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollUpButton\n ref={ref}\n className={cn(\n \"flex cursor-default items-center justify-center py-1\",\n className\n )}\n {...props}\n >\n <ChevronUp className=\"h-4 w-4\" />\n </SelectPrimitive.ScrollUpButton>\n));\nSelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;\n\nconst SelectScrollDownButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollDownButton\n ref={ref}\n className={cn(\n \"flex cursor-default items-center justify-center py-1\",\n className\n )}\n {...props}\n >\n <ChevronDown className=\"h-4 w-4\" />\n </SelectPrimitive.ScrollDownButton>\n));\nSelectScrollDownButton.displayName =\n SelectPrimitive.ScrollDownButton.displayName;\n\nconst SelectContent = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>\n>(({ className, children, position = \"popper\", ...props }, ref) => (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n ref={ref}\n className={cn(\n \"relative z-50 max-h-[--radix-select-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-select-content-transform-origin]\",\n position === \"popper\" &&\n \"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1\",\n className\n )}\n position={position}\n {...props}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.Viewport\n className={cn(\n \"p-1\",\n position === \"popper\" &&\n \"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]\"\n )}\n >\n {children}\n </SelectPrimitive.Viewport>\n <SelectScrollDownButton />\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n));\nSelectContent.displayName = SelectPrimitive.Content.displayName;\n\nconst SelectLabel = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.Label\n ref={ref}\n className={cn(\"py-1.5 pl-8 pr-2 text-sm font-semibold\", className)}\n {...props}\n />\n));\nSelectLabel.displayName = SelectPrimitive.Label.displayName;\n\nconst SelectItem = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>\n>(({ className, children, ...props }, ref) => (\n <SelectPrimitive.Item\n ref={ref}\n className={cn(\n \"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <SelectPrimitive.ItemIndicator>\n <Check className=\"h-4 w-4\" />\n </SelectPrimitive.ItemIndicator>\n </span>\n\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n));\nSelectItem.displayName = SelectPrimitive.Item.displayName;\n\nconst SelectSeparator = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.Separator\n ref={ref}\n className={cn(\"-mx-1 my-1 h-px bg-muted\", className)}\n {...props}\n />\n));\nSelectSeparator.displayName = SelectPrimitive.Separator.displayName;\n\nexport {\n Select,\n SelectGroup,\n SelectValue,\n SelectTrigger,\n SelectContent,\n SelectLabel,\n SelectItem,\n SelectSeparator,\n SelectScrollUpButton,\n SelectScrollDownButton,\n};\n","import { Button } from \"@/components/ui/button\";\nimport { Checkbox } from \"@/components/ui/checkbox\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from \"@/components/ui/dialog\";\nimport {\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@/components/ui/form\";\nimport { Input } from \"@/components/ui/input\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@/components/ui/select\";\nimport type { CozeWorkflow, WorkflowParameter } from \"@/types/index\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport { Plus, Trash2 } from \"lucide-react\";\nimport { useEffect } from \"react\";\nimport { useFieldArray, useForm } from \"react-hook-form\";\nimport { z } from \"zod\";\n\n/**\n * 参数验证Schema\n */\nconst parameterSchema = z.object({\n fieldName: z\n .string()\n .min(1, \"字段名不能为空\")\n .regex(\n /^[a-zA-Z][a-zA-Z0-9_]*$/,\n \"字段名必须以字母开头,只能包含字母、数字和下划线\"\n ),\n description: z\n .string()\n .min(1, \"描述不能为空\")\n .max(200, \"描述不能超过200个字符\"),\n type: z.enum([\"string\", \"number\", \"boolean\"]),\n required: z.boolean(),\n});\n\n/**\n * 表单验证Schema\n */\nconst formSchema = z.object({\n parameters: z.array(parameterSchema).refine(\n (parameters) => {\n const fieldNames = parameters.map((p) => p.fieldName);\n return fieldNames.length === new Set(fieldNames).size;\n },\n {\n message: \"字段名不能重复\",\n }\n ),\n});\n\ntype FormData = z.infer<typeof formSchema>;\n\n/**\n * WorkflowParameterConfigDialog组件属性\n */\nexport interface WorkflowParameterConfigDialogProps {\n /** 对话框是否打开 */\n open: boolean;\n /** 对话框打开状态变化回调 */\n onOpenChange: (open: boolean) => void;\n /** 工作流信息 */\n workflow: CozeWorkflow;\n /** 确认回调 */\n onConfirm: (workflow: CozeWorkflow, parameters: WorkflowParameter[]) => void;\n /** 取消回调 */\n onCancel: () => void;\n /** 自定义标题 */\n title?: string;\n}\n\n/**\n * 从 inputSchema 提取现有参数配置\n */\nfunction extractParametersFromSchema(inputSchema: any): FormData[\"parameters\"] {\n if (!inputSchema || !inputSchema.properties) {\n return [];\n }\n\n const properties = inputSchema.properties;\n const required = inputSchema.required || [];\n\n return Object.entries(properties).map(\n ([fieldName, schema]: [string, any]) => {\n let type: \"string\" | \"number\" | \"boolean\" = \"string\";\n\n if (schema.type === \"integer\" || schema.type === \"number\") {\n type = \"number\";\n } else if (schema.type === \"boolean\") {\n type = \"boolean\";\n }\n\n return {\n fieldName,\n description: schema.description || \"\",\n type,\n required: required.includes(fieldName),\n };\n }\n );\n}\n\n/**\n * 工作流参数配置对话框组件\n *\n * 提供通用的工作流参数配置界面,支持:\n * - 动态添加/删除参数\n * - 参数类型选择(string/number/boolean)\n * - 字段名和描述验证\n * - 必填参数设置\n */\nexport function WorkflowParameterConfigDialog({\n open,\n onOpenChange,\n workflow,\n onConfirm,\n onCancel,\n title,\n}: WorkflowParameterConfigDialogProps) {\n const form = useForm<FormData>({\n resolver: zodResolver(formSchema),\n defaultValues: {\n parameters: [],\n },\n });\n\n useEffect(() => {\n if (open) {\n form.reset({\n parameters: extractParametersFromSchema(workflow.inputSchema),\n });\n }\n }, [open, workflow, form.reset]);\n\n const { fields, append, remove } = useFieldArray({\n control: form.control,\n name: \"parameters\",\n });\n\n /**\n * 添加新参数\n */\n const handleAddParameter = () => {\n append({\n fieldName: \"\",\n description: \"\",\n type: \"string\",\n required: false,\n });\n };\n\n /**\n * 删除参数\n */\n const handleRemoveParameter = (index: number) => {\n remove(index);\n };\n\n /**\n * 表单提交处理\n */\n const handleSubmit = (data: FormData) => {\n onConfirm(workflow, data.parameters);\n form.reset();\n };\n\n /**\n * 取消处理\n */\n const handleCancel = () => {\n form.reset();\n onCancel();\n };\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-w-4xl max-h-[80vh] overflow-y-auto\">\n <DialogHeader>\n <DialogTitle>\n {title || `配置工作流参数 - ${workflow.workflow_name}`}\n </DialogTitle>\n <DialogDescription>\n 为工作流配置输入参数,这些参数将用于生成工具的输入架构。\n 您可以跳过此步骤使用默认的空参数配置。\n </DialogDescription>\n </DialogHeader>\n\n <Form {...form}>\n <form\n onSubmit={form.handleSubmit(handleSubmit)}\n className=\"space-y-6\"\n >\n <div className=\"space-y-4 mb-10\">\n <div className=\"flex items-center justify-between\">\n <h3 className=\"text-lg font-medium\">参数列表</h3>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={handleAddParameter}\n className=\"flex items-center gap-2\"\n >\n <Plus className=\"h-4 w-4\" />\n 添加参数\n </Button>\n </div>\n\n {fields.length === 0 && (\n <div className=\"text-center py-8 text-muted-foreground\">\n 暂无参数,点击\"添加参数\"开始配置\n </div>\n )}\n\n {fields.map((field, index) => (\n <div key={field.id} className=\"flex gap-2\">\n <FormField\n control={form.control}\n name={`parameters.${index}.fieldName`}\n render={({ field }) => (\n <FormItem>\n <FormLabel>字段名</FormLabel>\n <FormControl>\n <Input placeholder=\"例如: userName\" {...field} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={form.control}\n name={`parameters.${index}.description`}\n render={({ field }) => (\n <FormItem className=\"flex-1\">\n <FormLabel>描述</FormLabel>\n <FormControl>\n <Input placeholder=\"例如: 用户名称\" {...field} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={form.control}\n name={`parameters.${index}.type`}\n render={({ field }) => (\n <FormItem className=\"w-[140px]\">\n <FormLabel>参数类型</FormLabel>\n <Select\n onValueChange={field.onChange}\n defaultValue={field.value}\n >\n <FormControl>\n <SelectTrigger>\n <SelectValue placeholder=\"选择参数类型\" />\n </SelectTrigger>\n </FormControl>\n <SelectContent>\n <SelectItem value=\"string\">string</SelectItem>\n <SelectItem value=\"number\">number</SelectItem>\n <SelectItem value=\"boolean\">boolean</SelectItem>\n </SelectContent>\n </Select>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={form.control}\n name={`parameters.${index}.required`}\n render={({ field }) => (\n <FormItem>\n <FormLabel>是否必填</FormLabel>\n <FormControl>\n <div className=\"flex items-center justify-center h-[40px]\">\n <Checkbox\n checked={field.value}\n onCheckedChange={field.onChange}\n />\n </div>\n </FormControl>\n </FormItem>\n )}\n />\n\n <div className=\"flex flex-col h-[72px] justify-end\">\n <Button\n type=\"button\"\n variant=\"link\"\n size=\"sm\"\n onClick={() => handleRemoveParameter(index)}\n className=\"text-destructive mb-[4px]\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n ))}\n </div>\n\n <DialogFooter>\n <Button type=\"button\" variant=\"outline\" onClick={handleCancel}>\n 取消\n </Button>\n <Button type=\"submit\">确认配置</Button>\n </DialogFooter>\n </form>\n </Form>\n </DialogContent>\n </Dialog>\n );\n}\n","/**\n * MCP 服务工具函数\n * 用于判断 MCP 服务的通信类型和其他相关操作\n */\n\n// 定义通信类型\nexport type MCPCommunicationType = \"stdio\" | \"sse\" | \"streamable-http\";\n\n// 定义 MCP 服务配置类型(与服务端保持一致)\nexport interface LocalMCPServerConfig {\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\nexport interface SSEMCPServerConfig {\n type: \"sse\";\n url: string;\n}\n\nexport interface StreamableHTTPMCPServerConfig {\n type?: \"streamable-http\"; // 可选,因为默认就是 streamable-http\n url: string;\n}\n\nexport type MCPServerConfig =\n | LocalMCPServerConfig\n | SSEMCPServerConfig\n | StreamableHTTPMCPServerConfig;\n\n/**\n * 判断 MCP 服务的通信类型\n *\n * @param serverConfig MCP 服务配置对象\n * @returns 通信类型:'stdio' | 'sse' | 'streamable-http'\n *\n * 判断逻辑:\n * 1. 如果配置对象有 command 字段 → stdio\n * 2. 如果配置对象有 type 字段且值为 \"sse\" → sse\n * 3. 如果配置对象有 url 字段但没有 type 字段,或者 type 字段不是 \"sse\" → streamable-http\n *\n * @example\n * ```typescript\n * // stdio 类型\n * const stdioConfig = {\n * command: \"node\",\n * args: [\"./mcpServers/calculator.js\"]\n * };\n * getMcpServerCommunicationType(stdioConfig); // \"stdio\"\n *\n * // sse 类型\n * const sseConfig = {\n * type: \"sse\" as const,\n * url: \"https://mcp.api-inference.modelscope.net/d3cfd34529ae4e/sse\"\n * };\n * getMcpServerCommunicationType(sseConfig); // \"sse\"\n *\n * // streamable-http 类型\n * const httpConfig = {\n * url: \"https://mcp.amap.com/mcp?key=1ec31da021b2702787841ea4ee822de3\"\n * };\n * getMcpServerCommunicationType(httpConfig); // \"streamable-http\"\n * ```\n */\nexport function getMcpServerCommunicationType(\n serverConfig: MCPServerConfig | Record<string, any>\n): MCPCommunicationType {\n // 参数验证\n if (!serverConfig || typeof serverConfig !== \"object\") {\n throw new Error(\"服务配置必须是一个有效的对象\");\n }\n\n // 1. 检查是否为 stdio 类型(有 command 字段)\n if (\"command\" in serverConfig && typeof serverConfig.command === \"string\") {\n return \"stdio\";\n }\n\n // 2. 检查是否为 sse 类型(有 type: \"sse\" 字段)\n if (\"type\" in serverConfig && serverConfig.type === \"sse\") {\n return \"sse\";\n }\n\n // 3. 检查是否为 streamable-http 类型(有 url 字段)\n if (\"url\" in serverConfig && typeof serverConfig.url === \"string\") {\n return \"streamable-http\";\n }\n\n // 如果都不匹配,抛出错误\n throw new Error(\n \"无法识别的 MCP 服务配置类型。配置必须包含 command 字段(stdio)、type: 'sse' 字段(sse)或 url 字段(streamable-http)\"\n );\n}\n\n/**\n * 检查 MCP 服务配置是否为 stdio 类型\n */\nexport function isStdioMcpServer(\n serverConfig: MCPServerConfig | Record<string, any>\n): serverConfig is LocalMCPServerConfig {\n return getMcpServerCommunicationType(serverConfig) === \"stdio\";\n}\n\n/**\n * 检查 MCP 服务配置是否为 sse 类型\n */\nexport function isSSEMcpServer(\n serverConfig: MCPServerConfig | Record<string, any>\n): serverConfig is SSEMCPServerConfig {\n return getMcpServerCommunicationType(serverConfig) === \"sse\";\n}\n\n/**\n * 检查 MCP 服务配置是否为 streamable-http 类型\n */\nexport function isStreamableHTTPMcpServer(\n serverConfig: MCPServerConfig | Record<string, any>\n): serverConfig is StreamableHTTPMCPServerConfig {\n return getMcpServerCommunicationType(serverConfig) === \"streamable-http\";\n}\n\n/**\n * 获取 MCP 服务配置的显示名称\n * 用于在 UI 中显示更友好的通信类型名称\n */\nexport function getMcpServerTypeDisplayName(\n serverConfig: MCPServerConfig | Record<string, any>\n): string {\n const type = getMcpServerCommunicationType(serverConfig);\n\n switch (type) {\n case \"stdio\":\n return \"本地进程 (stdio)\";\n case \"sse\":\n return \"服务器推送 (SSE)\";\n case \"streamable-http\":\n return \"流式 HTTP\";\n default:\n return \"未知类型\";\n }\n}\n","import * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst Textarea = React.forwardRef<\n HTMLTextAreaElement,\n React.ComponentProps<\"textarea\">\n>(({ className, ...props }, ref) => {\n return (\n <textarea\n className={cn(\n \"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm\",\n className\n )}\n ref={ref}\n {...props}\n />\n );\n});\nTextarea.displayName = \"Textarea\";\n\nexport { Textarea };\n","import { Button } from \"@/components/ui/button\";\nimport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from \"@/components/ui/dialog\";\nimport {\n Form,\n FormControl,\n FormField,\n FormItem,\n FormMessage,\n} from \"@/components/ui/form\";\nimport { mcpServerApi } from \"@/services/api\";\nimport { useConfig } from \"@/stores/config\";\nimport type { MCPServerConfig } from \"@/types/index\";\nimport { getMcpServerCommunicationType } from \"@/utils/mcpServerUtils\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport { Textarea } from \"@ui/textarea\";\nimport { PlusIcon } from \"lucide-react\";\nimport { useState } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport { toast } from \"sonner\";\nimport z from \"zod\";\n\nconst formSchema = z.object({\n config: z.string().min(2, {\n message: \"配置不能为空\",\n }),\n});\n\nexport function AddMcpServerButton() {\n const [open, setOpen] = useState(false);\n const [isLoading, setIsLoading] = useState(false);\n const config = useConfig();\n\n const form = useForm<z.infer<typeof formSchema>>({\n resolver: zodResolver(formSchema),\n defaultValues: {\n config: \"\",\n },\n });\n\n // 验证结果接口\n interface ValidationResult {\n success: boolean;\n data?: Record<string, MCPServerConfig>;\n error?: string;\n }\n\n // 验证单个 MCP 服务配置\n const validateSingleServerConfig = (\n serverName: string,\n serverConfig: any\n ): { valid: boolean; error?: string } => {\n if (!serverConfig || typeof serverConfig !== \"object\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的配置必须是一个对象`,\n };\n }\n\n // 先进行基本字段检查,避免 getMcpServerCommunicationType 抛出错误\n const hasCommand = \"command\" in serverConfig;\n const hasType = \"type\" in serverConfig;\n const hasUrl = \"url\" in serverConfig;\n\n // 判断配置类型并验证相应字段\n if (hasCommand) {\n // stdio 类型\n if (!serverConfig.command || typeof serverConfig.command !== \"string\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 缺少必需的 command 字段或字段类型不正确`,\n };\n }\n if (!Array.isArray(serverConfig.args)) {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 args 字段必须是数组`,\n };\n }\n } else if (hasType && serverConfig.type === \"sse\") {\n // sse 类型\n if (!serverConfig.url || typeof serverConfig.url !== \"string\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 缺少必需的 url 字段或字段类型不正确`,\n };\n }\n } else if (hasUrl) {\n // streamable-http 类型\n if (!serverConfig.url || typeof serverConfig.url !== \"string\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 缺少必需的 url 字段或字段类型不正确`,\n };\n }\n } else {\n // 无法识别的配置类型\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的配置无效: 必须包含 command 字段(stdio)、type: 'sse' 字段(sse)或 url 字段(streamable-http)`,\n };\n }\n\n // 最后用工具函数验证配置是否完整\n try {\n getMcpServerCommunicationType(serverConfig);\n return { valid: true };\n } catch (error) {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的配置无效: ${\n error instanceof Error ? error.message : \"未知错误\"\n }`,\n };\n }\n };\n\n // 验证 MCP 配置的函数\n const validateMCPConfig = (input: string): ValidationResult => {\n try {\n const trimmed = input.trim();\n if (!trimmed) {\n return { success: false, error: \"配置不能为空\" };\n }\n\n const parsed = JSON.parse(trimmed);\n\n let mcpServers: Record<string, any>;\n\n // 检查是否包含 mcpServers 层\n if (parsed.mcpServers && typeof parsed.mcpServers === \"object\") {\n mcpServers = parsed.mcpServers;\n } else if (typeof parsed === \"object\" && !Array.isArray(parsed)) {\n // 检查是否是单个服务配置\n try {\n getMcpServerCommunicationType(parsed);\n // 如果能识别类型,说明是单个服务配置,生成默认名称\n const defaultName = parsed.command\n ? parsed.command.split(\"/\").pop() || \"mcp-server\"\n : parsed.type === \"sse\"\n ? \"sse-server\"\n : \"http-server\";\n mcpServers = { [defaultName]: parsed };\n } catch {\n // 无法识别为单个服务配置,认为是多个服务的配置对象\n mcpServers = parsed;\n }\n } else {\n return { success: false, error: \"配置格式错误: 必须是对象格式\" };\n }\n\n // 验证每个服务配置\n for (const [serverName, serverConfig] of Object.entries(mcpServers)) {\n const validation = validateSingleServerConfig(serverName, serverConfig);\n if (!validation.valid) {\n return { success: false, error: validation.error };\n }\n }\n\n return { success: true, data: mcpServers };\n } catch (error) {\n return {\n success: false,\n error: `JSON 格式错误: ${\n error instanceof Error ? error.message : \"无法解析 JSON\"\n }`,\n };\n }\n };\n\n async function onSubmit(values: z.infer<typeof formSchema>) {\n if (!config) {\n toast.error(\"配置数据未加载,请稍后重试\");\n return;\n }\n\n setIsLoading(true);\n try {\n // 验证用户输入的配置\n const validation = validateMCPConfig(values.config);\n\n if (!validation.success) {\n toast.error(validation.error || \"配置验证失败\");\n return;\n }\n\n const parsedServers = validation.data!;\n\n // 检查重名 - 需要调用API获取当前服务器列表\n const existingServers = await mcpServerApi.listServers();\n const existingNames = Object.keys(parsedServers).filter((name) =>\n existingServers.servers.some((server) => server.name === name)\n );\n if (existingNames.length > 0) {\n toast.error(\n `服务名称冲突: 以下服务已存在: ${existingNames.join(\", \")}`\n );\n return;\n }\n\n // 调用API添加服务器\n for (const [serverName, serverConfig] of Object.entries(parsedServers)) {\n const result = await mcpServerApi.addServer(serverName, serverConfig);\n if (!result) {\n throw new Error(\"添加服务器失败\");\n }\n }\n\n // 成功反馈\n const addedCount = Object.keys(parsedServers).length;\n toast.success(\n addedCount === 1\n ? `已添加 MCP 服务 \"${Object.keys(parsedServers)[0]}\"`\n : `已添加 ${addedCount} 个 MCP 服务`\n );\n\n // 重置表单并关闭对话框\n form.reset();\n setOpen(false);\n } catch (error) {\n console.error(\"更新配置失败:\", error);\n toast.error(error instanceof Error ? error.message : \"更新配置失败\");\n } finally {\n setIsLoading(false);\n }\n }\n\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n <DialogTrigger asChild>\n <Button size=\"icon\" className=\"w-full\">\n <PlusIcon className=\"h-4 w-4\" />\n <span>添加MCP服务</span>\n </Button>\n </DialogTrigger>\n <DialogContent className=\"sm:max-w-[500px]\">\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)}>\n <DialogHeader className=\"mb-4\">\n <DialogTitle>添加MCP服务</DialogTitle>\n <DialogDescription>\n 添加后,需要重启服务才会生效。\n </DialogDescription>\n </DialogHeader>\n <div className=\"grid gap-4\">\n <FormField\n control={form.control}\n name=\"config\"\n render={({ field }) => (\n <FormItem>\n <FormControl>\n <Textarea\n className=\"resize-none h-[300px] font-mono text-sm\"\n disabled={isLoading}\n placeholder={`支持三种通信方式:\n\n1. 本地进程 (stdio):\n{\n \"mcpServers\": {\n \"local-server\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@example/mcp-server\"]\n }\n }\n}\n\n2. 服务器推送 (SSE):\n{\n \"mcpServers\": {\n \"sse-server\": {\n \"type\": \"sse\",\n \"url\": \"https://example.com/sse\"\n }\n }\n}\n\n3. 流式 HTTP:\n{\n \"mcpServers\": {\n \"http-server\": {\n \"url\": \"https://example.com/mcp\"\n }\n }\n}`}\n {...field}\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n </div>\n <DialogFooter className=\"mt-4\">\n <DialogClose asChild>\n <Button variant=\"outline\" disabled={isLoading}>\n 取消\n </Button>\n </DialogClose>\n <Button type=\"submit\" disabled={isLoading}>\n {isLoading ? \"保存中...\" : \"保存\"}\n </Button>\n </DialogFooter>\n </form>\n </Form>\n </DialogContent>\n </Dialog>\n );\n}\n","/**\n * 扣子 API 前端包装器\n * 负责与后端扣子 API 的通信\n */\n\nimport type {\n CozeWorkflowsParams,\n CozeWorkflowsResult,\n CozeWorkspace,\n} from \"@/types/index\";\n\n/**\n * API 响应格式\n */\ninterface ApiResponse<T = any> {\n success: boolean;\n data?: T;\n message?: string;\n}\n\ninterface ApiErrorResponse {\n error: {\n code: string;\n message: string;\n details?: any;\n };\n}\n\n/**\n * 缓存统计信息\n */\ninterface CacheStats {\n size: number;\n keys: string[];\n}\n\n/**\n * 扣子 API 客户端类\n */\nexport class CozeApiClient {\n private baseUrl: string;\n\n constructor(baseUrl?: string) {\n // 从当前页面 URL 推断 API 基础 URL\n if (baseUrl) {\n this.baseUrl = baseUrl;\n } else {\n const protocol = window.location.protocol;\n const hostname = window.location.hostname;\n const port = window.location.port;\n this.baseUrl = `${protocol}//${hostname}${port ? `:${port}` : \"\"}`;\n }\n }\n\n /**\n * 通用请求方法\n */\n private async request<T>(\n endpoint: string,\n options: RequestInit = {}\n ): Promise<T> {\n const url = `${this.baseUrl}${endpoint}`;\n\n const defaultOptions: RequestInit = {\n headers: {\n \"Content-Type\": \"application/json\",\n ...options.headers,\n },\n };\n\n const response = await fetch(url, { ...defaultOptions, ...options });\n\n if (!response.ok) {\n let errorMessage = `HTTP ${response.status}: ${response.statusText}`;\n\n try {\n const errorData: ApiErrorResponse = await response.json();\n errorMessage = errorData.error?.message || errorMessage;\n } catch {\n // 如果无法解析错误响应,使用默认错误消息\n }\n\n throw new Error(errorMessage);\n }\n\n return response.json();\n }\n\n /**\n * 获取工作空间列表\n */\n async fetchWorkspaces(): Promise<{ workspaces: CozeWorkspace[] }> {\n try {\n const response: ApiResponse<{ workspaces: CozeWorkspace[] }> =\n await this.request(\"/api/coze/workspaces\");\n\n if (!response.success || !response.data) {\n throw new Error(response.message || \"获取工作空间列表失败\");\n }\n\n return response.data;\n } catch (error) {\n console.error(\"获取工作空间列表失败:\", error);\n throw error;\n }\n }\n\n /**\n * 获取工作流列表\n */\n async fetchWorkflows(\n params: CozeWorkflowsParams\n ): Promise<CozeWorkflowsResult> {\n try {\n const searchParams = new URLSearchParams();\n searchParams.append(\"workspace_id\", params.workspace_id);\n\n if (params.page_num !== undefined) {\n searchParams.append(\"page_num\", params.page_num.toString());\n }\n\n if (params.page_size !== undefined) {\n searchParams.append(\"page_size\", params.page_size.toString());\n }\n\n const response: ApiResponse<CozeWorkflowsResult> = await this.request(\n `/api/coze/workflows?${searchParams.toString()}`\n );\n\n if (!response.success || !response.data) {\n throw new Error(response.message || \"获取工作流列表失败\");\n }\n\n return response.data;\n } catch (error) {\n console.error(\"获取工作流列表失败:\", error);\n throw error;\n }\n }\n\n /**\n * 清除缓存\n */\n async clearCache(): Promise<void> {\n try {\n const response: ApiResponse = await this.request(\n \"/api/coze/cache/clear\",\n {\n method: \"POST\",\n }\n );\n\n if (!response.success) {\n throw new Error(response.message || \"清除缓存失败\");\n }\n } catch (error) {\n console.error(\"清除缓存失败:\", error);\n throw error;\n }\n }\n\n /**\n * 获取缓存统计信息\n */\n async getCacheStats(): Promise<CacheStats> {\n try {\n const response: ApiResponse<CacheStats> = await this.request(\n \"/api/coze/cache/stats\"\n );\n\n if (!response.success || !response.data) {\n throw new Error(response.message || \"获取缓存统计失败\");\n }\n\n return response.data;\n } catch (error) {\n console.error(\"获取缓存统计失败:\", error);\n throw error;\n }\n }\n}\n\n// 创建默认的扣子 API 客户端实例\nexport const cozeApiClient = new CozeApiClient();\n\n// 导出类型\nexport type { ApiResponse, ApiErrorResponse, CacheStats };\n","/**\n * 扣子工作流相关的 React Hook\n * 提供工作空间和工作流数据的状态管理\n */\n\nimport type {\n CozeUIState,\n CozeWorkflow,\n CozeWorkflowsParams,\n CozeWorkspace,\n} from \"@/types/index\";\nimport { cozeApiClient } from \"@services/cozeApi\";\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\n\n/**\n * Hook 返回值类型\n */\nexport interface UseCozeWorkflowsReturn {\n // 数据状态\n workspaces: CozeWorkspace[];\n workflows: CozeWorkflow[];\n selectedWorkspace: CozeWorkspace | null;\n\n // UI 状态\n workspacesLoading: boolean;\n workflowsLoading: boolean;\n workspacesError: string | null;\n workflowsError: string | null;\n hasMoreWorkflows: boolean;\n\n // 操作方法\n selectWorkspace: (workspaceId: string | null) => void;\n loadWorkflows: (params?: Partial<CozeWorkflowsParams>) => Promise<void>;\n refreshWorkspaces: () => Promise<void>;\n refreshWorkflows: () => Promise<void>;\n clearCache: () => Promise<void>;\n setWorkflows: (\n workflows: CozeWorkflow[] | ((prev: CozeWorkflow[]) => CozeWorkflow[])\n ) => void;\n\n // 分页相关\n currentPage: number;\n pageSize: number;\n setPage: (page: number) => void;\n setPageSize: (size: number) => void;\n}\n\n/**\n * Hook 配置选项\n */\nexport interface UseCozeWorkflowsOptions {\n /** 是否自动加载工作空间列表 */\n autoLoadWorkspaces?: boolean;\n /** 是否在选择工作空间后自动加载工作流 */\n autoLoadWorkflows?: boolean;\n /** 默认页面大小 */\n defaultPageSize?: number;\n /** 初始选中的工作空间ID */\n initialWorkspaceId?: string;\n}\n\n/**\n * 扣子工作流 Hook\n */\nexport function useCozeWorkflows(\n options: UseCozeWorkflowsOptions = {}\n): UseCozeWorkflowsReturn {\n const {\n autoLoadWorkspaces = true,\n autoLoadWorkflows = true,\n defaultPageSize = 20,\n initialWorkspaceId,\n } = options;\n\n // 数据状态\n const [workspaces, setWorkspaces] = useState<CozeWorkspace[]>([]);\n const [workflows, setWorkflows] = useState<CozeWorkflow[]>([]);\n const [selectedWorkspaceId, setSelectedWorkspaceId] = useState<string | null>(\n initialWorkspaceId || null\n );\n\n // UI 状态\n const [uiState, setUiState] = useState<CozeUIState>({\n selectedWorkspaceId: initialWorkspaceId || null,\n workspacesLoading: false,\n workflowsLoading: false,\n workspacesError: null,\n workflowsError: null,\n });\n\n // 分页状态\n const [currentPage, setCurrentPage] = useState(1);\n const [pageSize, setPageSize] = useState(defaultPageSize);\n const [hasMoreWorkflows, setHasMoreWorkflows] = useState(false);\n\n // 计算选中的工作空间\n const selectedWorkspace = useMemo(() => {\n return workspaces && Array.isArray(workspaces)\n ? workspaces.find((ws) => ws.id === selectedWorkspaceId) || null\n : null;\n }, [workspaces, selectedWorkspaceId]);\n\n /**\n * 加载工作空间列表\n */\n const loadWorkspaces = useCallback(async () => {\n setUiState((prev) => ({\n ...prev,\n workspacesLoading: true,\n workspacesError: null,\n }));\n\n try {\n const data = await cozeApiClient.fetchWorkspaces();\n setWorkspaces(data.workspaces);\n setUiState((prev) => ({ ...prev, workspacesLoading: false }));\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : \"加载工作空间失败\";\n setUiState((prev) => ({\n ...prev,\n workspacesLoading: false,\n workspacesError: errorMessage,\n }));\n console.error(\"加载工作空间失败:\", error);\n }\n }, []);\n\n /**\n * 加载工作流列表\n */\n const loadWorkflows = useCallback(\n async (params: Partial<CozeWorkflowsParams> = {}) => {\n const workspaceId = params.workspace_id || selectedWorkspaceId;\n\n if (!workspaceId) {\n console.warn(\"无法加载工作流:未选择工作空间\");\n return;\n }\n\n setUiState((prev) => ({\n ...prev,\n workflowsLoading: true,\n workflowsError: null,\n }));\n\n try {\n const requestParams: CozeWorkflowsParams = {\n workspace_id: workspaceId,\n page_num: params.page_num || currentPage,\n page_size: params.page_size || pageSize,\n };\n\n const result = await cozeApiClient.fetchWorkflows(requestParams);\n setWorkflows(result.items);\n setHasMoreWorkflows(result.hasMore);\n setUiState((prev) => ({ ...prev, workflowsLoading: false }));\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : \"加载工作流失败\";\n setUiState((prev) => ({\n ...prev,\n workflowsLoading: false,\n workflowsError: errorMessage,\n }));\n console.error(\"加载工作流失败:\", error);\n }\n },\n [selectedWorkspaceId, currentPage, pageSize]\n );\n\n /**\n * 选择工作空间\n */\n const selectWorkspace = useCallback(\n (workspaceId: string | null) => {\n setSelectedWorkspaceId(workspaceId);\n setUiState((prev) => ({ ...prev, selectedWorkspaceId: workspaceId }));\n\n // 重置工作流相关状态\n setWorkflows([]);\n setCurrentPage(1);\n setHasMoreWorkflows(false);\n\n // 如果启用自动加载且选择了工作空间,则加载工作流\n if (autoLoadWorkflows && workspaceId) {\n loadWorkflows({ workspace_id: workspaceId, page_num: 1 });\n }\n },\n [autoLoadWorkflows, loadWorkflows]\n );\n\n /**\n * 刷新工作空间列表\n */\n const refreshWorkspaces = useCallback(async () => {\n await loadWorkspaces();\n }, [loadWorkspaces]);\n\n /**\n * 刷新工作流列表\n */\n const refreshWorkflows = useCallback(async () => {\n if (selectedWorkspaceId) {\n await loadWorkflows({\n workspace_id: selectedWorkspaceId,\n page_num: currentPage,\n });\n }\n }, [loadWorkflows, selectedWorkspaceId, currentPage]);\n\n /**\n * 清除缓存\n */\n const clearCache = useCallback(async () => {\n try {\n await cozeApiClient.clearCache();\n // 清除缓存后重新加载数据\n if (autoLoadWorkspaces) {\n await loadWorkspaces();\n }\n if (autoLoadWorkflows && selectedWorkspaceId) {\n await loadWorkflows({ workspace_id: selectedWorkspaceId, page_num: 1 });\n }\n } catch (error) {\n console.error(\"清除缓存失败:\", error);\n throw error;\n }\n }, [\n autoLoadWorkspaces,\n autoLoadWorkflows,\n selectedWorkspaceId,\n loadWorkspaces,\n loadWorkflows,\n ]);\n\n /**\n * 设置页码\n */\n const setPage = useCallback(\n (page: number) => {\n setCurrentPage(page);\n if (selectedWorkspaceId) {\n loadWorkflows({ workspace_id: selectedWorkspaceId, page_num: page });\n }\n },\n [selectedWorkspaceId, loadWorkflows]\n );\n\n /**\n * 设置页面大小\n */\n const setPageSizeCallback = useCallback(\n (size: number) => {\n setPageSize(size);\n setCurrentPage(1); // 重置到第一页\n if (selectedWorkspaceId) {\n loadWorkflows({\n workspace_id: selectedWorkspaceId,\n page_num: 1,\n page_size: size,\n });\n }\n },\n [selectedWorkspaceId, loadWorkflows]\n );\n\n // 初始化加载工作空间\n useEffect(() => {\n if (autoLoadWorkspaces) {\n loadWorkspaces();\n }\n }, [autoLoadWorkspaces, loadWorkspaces]);\n\n // 当选择工作空间变化时,如果启用自动加载则加载工作流\n useEffect(() => {\n if (autoLoadWorkflows && selectedWorkspaceId) {\n // 直接调用 API 而不是使用 loadWorkflows 回调,避免依赖循环\n const loadInitialWorkflows = async () => {\n setUiState((prev) => ({\n ...prev,\n workflowsLoading: true,\n workflowsError: null,\n }));\n\n try {\n const requestParams = {\n workspace_id: selectedWorkspaceId,\n page_num: 1,\n page_size: pageSize,\n };\n\n const result = await cozeApiClient.fetchWorkflows(requestParams);\n setWorkflows(result.items);\n setHasMoreWorkflows(result.hasMore);\n setUiState((prev) => ({ ...prev, workflowsLoading: false }));\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : \"加载工作流失败\";\n setUiState((prev) => ({\n ...prev,\n workflowsLoading: false,\n workflowsError: errorMessage,\n }));\n console.error(\"加载工作流失败:\", error);\n }\n };\n\n loadInitialWorkflows();\n }\n }, [autoLoadWorkflows, selectedWorkspaceId, pageSize]);\n\n return {\n // 数据状态\n workspaces,\n workflows,\n selectedWorkspace,\n\n // UI 状态\n workspacesLoading: uiState.workspacesLoading,\n workflowsLoading: uiState.workflowsLoading,\n workspacesError: uiState.workspacesError,\n workflowsError: uiState.workflowsError,\n hasMoreWorkflows,\n\n // 操作方法\n selectWorkspace,\n loadWorkflows,\n refreshWorkspaces,\n refreshWorkflows,\n clearCache,\n setWorkflows,\n\n // 分页相关\n currentPage,\n pageSize,\n setPage,\n setPageSize: setPageSizeCallback,\n };\n}\n","import { WorkflowParameterConfigDialog } from \"@/components/common/WorkflowParameterConfigDialog\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n} from \"@/components/ui/alert-dialog\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from \"@/components/ui/dialog\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@/components/ui/select\";\nimport { Skeleton } from \"@/components/ui/skeleton\";\nimport { useCozeWorkflows } from \"@/hooks/useCozeWorkflows\";\nimport { apiClient } from \"@/services/api\";\nimport type { CozeWorkflow, WorkflowParameter } from \"@/types/index\";\nimport {\n AlertCircle,\n ChevronLeft,\n ChevronRight,\n Loader2,\n Plus,\n RefreshCw,\n Workflow,\n} from \"lucide-react\";\nimport { useEffect, useState } from \"react\";\nimport { toast } from \"sonner\";\n\ninterface CozeWorkflowIntegrationProps {\n onToolAdded?: () => void;\n}\n\nexport function CozeWorkflowIntegration({\n onToolAdded,\n}: CozeWorkflowIntegrationProps) {\n const [open, setOpen] = useState(false);\n const [isAddingWorkflow, setIsAddingWorkflow] = useState(false);\n const [confirmDialog, setConfirmDialog] = useState<{\n open: boolean;\n workflow?: CozeWorkflow;\n toolName?: string;\n action: \"add\" | \"remove\";\n }>({ open: false, action: \"add\" });\n const [parameterConfigDialog, setParameterConfigDialog] = useState<{\n open: boolean;\n workflow?: CozeWorkflow;\n }>({ open: false });\n const [isOnline, setIsOnline] = useState(navigator.onLine);\n const [pendingOperations, setPendingOperations] = useState<Set<string>>(\n new Set()\n );\n const [hasAutoSelected, setHasAutoSelected] = useState(false);\n\n // 使用 useCozeWorkflows Hook 获取数据和状态\n const {\n workspaces,\n workflows,\n selectedWorkspace,\n workspacesLoading,\n workflowsLoading,\n workspacesError,\n workflowsError,\n hasMoreWorkflows,\n currentPage,\n selectWorkspace,\n refreshWorkflows,\n setPage,\n setWorkflows,\n } = useCozeWorkflows({\n autoLoadWorkspaces: true,\n autoLoadWorkflows: true,\n });\n\n // 监听网络状态\n useEffect(() => {\n const handleOnline = () => setIsOnline(true);\n const handleOffline = () => setIsOnline(false);\n\n window.addEventListener(\"online\", handleOnline);\n window.addEventListener(\"offline\", handleOffline);\n\n return () => {\n window.removeEventListener(\"online\", handleOnline);\n window.removeEventListener(\"offline\", handleOffline);\n };\n }, []);\n\n // 自动选择第一个工作空间\n useEffect(() => {\n // 当工作空间加载完成且不为空,且尚未进行过自动选择时\n if (\n !workspacesLoading &&\n workspaces.length > 0 &&\n !selectedWorkspace &&\n !hasAutoSelected\n ) {\n const firstWorkspace = workspaces[0];\n console.log(`自动选择第一个工作空间: ${firstWorkspace.name}`);\n selectWorkspace(firstWorkspace.id);\n setHasAutoSelected(true);\n }\n\n // 如果工作空间列表被清空或重新加载,重置自动选择状态\n if (workspacesLoading && hasAutoSelected) {\n setHasAutoSelected(false);\n }\n }, [\n workspaces,\n workspacesLoading,\n selectedWorkspace,\n hasAutoSelected,\n selectWorkspace,\n ]);\n\n const handleWorkspaceChange = (workspaceId: string) => {\n // 用户手动选择工作空间时,标记为已进行手动选择\n // 这样自动选择逻辑就不会再次触发\n setHasAutoSelected(true);\n selectWorkspace(workspaceId);\n };\n\n const handleAddWorkflow = (workflow: CozeWorkflow) => {\n // 检查网络状态\n if (!isOnline) {\n toast.error(\"网络连接已断开,请检查网络后重试\");\n return;\n }\n\n // 检查是否已有相同操作在进行\n const operationKey = `add_${workflow.workflow_id}`;\n if (pendingOperations.has(operationKey)) {\n toast.warning(\"该工作流正在添加中,请勿重复操作\");\n return;\n }\n\n // 显示参数配置对话框\n setParameterConfigDialog({\n open: true,\n workflow,\n });\n };\n\n // 处理参数配置确认\n const handleParameterConfigConfirm = async (\n workflow: CozeWorkflow,\n parameters: WorkflowParameter[]\n ) => {\n const operationKey = `add_${workflow.workflow_id}`;\n\n setIsAddingWorkflow(true);\n setPendingOperations((prev) => new Set(prev).add(operationKey));\n\n try {\n // 验证工作流数据完整性\n if (\n !workflow.workflow_id ||\n !workflow.workflow_name ||\n !workflow.app_id\n ) {\n throw new Error(\"工作流数据不完整,缺少必要字段\");\n }\n\n // 再次检查网络状态\n if (!isOnline) {\n throw new Error(\"网络连接已断开,请检查网络后重试\");\n }\n\n // 构建参数配置\n const parameterConfig =\n parameters.length > 0 ? { parameters } : undefined;\n\n const request = {\n type: \"coze\" as const,\n data: {\n workflow,\n customName: undefined,\n customDescription: undefined,\n parameterConfig,\n },\n };\n const addedTool = await apiClient.addCustomTool(request);\n\n toast.success(\n `已添加工作流 \"${workflow.workflow_name}\" 为 MCP 工具 \"${\n addedTool.name\n }\"${\n parameters.length > 0 ? `,配置了 ${parameters.length} 个参数` : \"\"\n }`\n );\n\n // 立即更新本地工作流状态,标记为已添加\n setWorkflows((prevWorkflows) =>\n prevWorkflows.map((w) =>\n w.workflow_id === workflow.workflow_id\n ? {\n ...w,\n isAddedAsTool: true,\n toolName: addedTool.name,\n }\n : w\n )\n );\n\n // 通知父组件工具已添加,触发工具列表刷新\n onToolAdded?.();\n\n // 刷新工作流列表以确保状态同步\n await refreshWorkflows();\n } catch (error) {\n console.error(\"添加工作流失败:\", error);\n\n // 根据错误类型显示不同的错误信息\n let errorMessage = \"添加工作流失败,请重试\";\n\n if (error instanceof Error) {\n if (\n error.message.includes(\"已存在\") ||\n error.message.includes(\"冲突\")\n ) {\n errorMessage = `工作流 \"${workflow.workflow_name}\" 已存在,请勿重复添加`;\n } else if (\n error.message.includes(\"配置\") ||\n error.message.includes(\"token\")\n ) {\n errorMessage = \"系统配置错误,请检查扣子API配置\";\n } else if (\n error.message.includes(\"验证失败\") ||\n error.message.includes(\"格式\")\n ) {\n errorMessage = \"工作流数据格式错误,请联系管理员\";\n } else if (\n error.message.includes(\"网络\") ||\n error.message.includes(\"超时\") ||\n error.message.includes(\"连接\")\n ) {\n errorMessage = \"网络连接失败,请检查网络后重试\";\n } else if (error.message.includes(\"权限\")) {\n errorMessage = \"权限不足,请检查API权限配置\";\n } else if (error.message.includes(\"频繁\")) {\n errorMessage = \"操作过于频繁,请稍后重试\";\n } else {\n errorMessage = error.message;\n }\n }\n\n toast.error(errorMessage);\n } finally {\n setIsAddingWorkflow(false);\n setPendingOperations((prev) => {\n const newSet = new Set(prev);\n newSet.delete(operationKey);\n return newSet;\n });\n setParameterConfigDialog({ open: false });\n }\n };\n\n // 处理参数配置取消\n const handleParameterConfigCancel = () => {\n setParameterConfigDialog({ open: false });\n };\n\n const handleConfirmAddWorkflow = async (workflow: CozeWorkflow) => {\n const operationKey = `add_${workflow.workflow_id}`;\n\n setIsAddingWorkflow(true);\n setPendingOperations((prev) => new Set(prev).add(operationKey));\n\n try {\n // 验证工作流数据完整性\n if (\n !workflow.workflow_id ||\n !workflow.workflow_name ||\n !workflow.app_id\n ) {\n throw new Error(\"工作流数据不完整,缺少必要字段\");\n }\n\n // 再次检查网络状态\n if (!isOnline) {\n throw new Error(\"网络连接已断开,请检查网络后重试\");\n }\n\n // 使用新的统一数据格式添加工具\n const request = {\n type: \"coze\" as const,\n data: {\n workflow,\n customName: undefined,\n customDescription: undefined,\n parameterConfig: undefined,\n },\n };\n const addedTool = await apiClient.addCustomTool(request);\n\n toast.success(\n `已添加工作流 \"${workflow.workflow_name}\" 为 MCP 工具 \"${addedTool.name}\"`\n );\n\n // 立即更新本地工作流状态,标记为已添加\n setWorkflows((prevWorkflows) =>\n prevWorkflows.map((w) =>\n w.workflow_id === workflow.workflow_id\n ? {\n ...w,\n isAddedAsTool: true,\n toolName: addedTool.name,\n }\n : w\n )\n );\n\n // 通知父组件工具已添加,触发工具列表刷新\n onToolAdded?.();\n\n // 刷新工作流列表以确保状态同步\n await refreshWorkflows();\n } catch (error) {\n console.error(\"添加工作流失败:\", error);\n\n // 根据错误类型显示不同的错误信息\n let errorMessage = \"添加工作流失败,请重试\";\n\n if (error instanceof Error) {\n if (\n error.message.includes(\"已存在\") ||\n error.message.includes(\"冲突\")\n ) {\n errorMessage = `工作流 \"${workflow.workflow_name}\" 已存在,请勿重复添加`;\n } else if (\n error.message.includes(\"配置\") ||\n error.message.includes(\"token\")\n ) {\n errorMessage = \"系统配置错误,请检查扣子API配置\";\n } else if (\n error.message.includes(\"验证失败\") ||\n error.message.includes(\"格式\")\n ) {\n errorMessage = \"工作流数据格式错误,请联系管理员\";\n } else if (\n error.message.includes(\"网络\") ||\n error.message.includes(\"超时\") ||\n error.message.includes(\"连接\")\n ) {\n errorMessage = \"网络连接失败,请检查网络后重试\";\n } else if (error.message.includes(\"权限\")) {\n errorMessage = \"权限不足,请检查API权限配置\";\n } else if (error.message.includes(\"频繁\")) {\n errorMessage = \"操作过于频繁,请稍后重试\";\n } else {\n errorMessage = error.message;\n }\n }\n\n toast.error(errorMessage);\n } finally {\n setIsAddingWorkflow(false);\n setPendingOperations((prev) => {\n const newSet = new Set(prev);\n newSet.delete(operationKey);\n return newSet;\n });\n setConfirmDialog({ open: false, action: \"add\" });\n }\n };\n\n const handlePrevPage = () => {\n if (currentPage > 1) {\n setPage(currentPage - 1);\n }\n };\n\n const handleNextPage = () => {\n if (hasMoreWorkflows) {\n setPage(currentPage + 1);\n }\n };\n\n const handleRefreshWorkflows = () => {\n if (selectedWorkspace) {\n refreshWorkflows();\n }\n };\n\n // 渲染工作空间选择器\n const renderWorkspaceSelector = () => (\n <div className=\"space-y-2\">\n {workspacesError ? (\n <div className=\"flex items-center gap-2 p-3 text-sm text-red-600 bg-red-50 rounded-md\">\n <AlertCircle className=\"h-4 w-4\" />\n <span>加载工作空间失败: {workspacesError}</span>\n </div>\n ) : (\n <Select\n value={selectedWorkspace?.id || \"\"}\n onValueChange={handleWorkspaceChange}\n disabled={workspacesLoading}\n >\n <SelectTrigger>\n <SelectValue\n placeholder={workspacesLoading ? \"加载中...\" : \"请选择工作空间\"}\n />\n </SelectTrigger>\n <SelectContent>\n {workspaces.map((workspace) => (\n <SelectItem key={workspace.id} value={workspace.id}>\n <div className=\"flex items-center gap-2\">\n <span>{workspace.name}</span>\n </div>\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )}\n </div>\n );\n\n // 渲染工作流列表\n const renderWorkflowList = () => {\n if (!selectedWorkspace) {\n return (\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <Workflow className=\"h-12 w-12 text-muted-foreground mb-4\" />\n <h3 className=\"text-lg font-medium mb-2\">请先选择工作空间</h3>\n <p className=\"text-sm text-muted-foreground\">\n 选择一个工作空间后,将显示该空间下的工作流列表\n </p>\n </div>\n );\n }\n\n if (workflowsError) {\n return (\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <AlertCircle className=\"h-12 w-12 text-red-500 mb-4\" />\n <h3 className=\"text-lg font-medium mb-2\">加载工作流失败</h3>\n <p className=\"text-sm text-muted-foreground mb-4\">{workflowsError}</p>\n <Button onClick={handleRefreshWorkflows} variant=\"outline\">\n <RefreshCw className=\"h-4 w-4 mr-2\" />\n 重试\n </Button>\n </div>\n );\n }\n\n if (workflowsLoading) {\n return (\n <div className=\"space-y-3\">\n {Array.from({ length: 3 }, (_, i) => i).map((index) => (\n <div\n key={`skeleton-${index}`}\n className=\"flex items-center gap-4 p-4 border rounded-lg\"\n >\n <Skeleton\n className=\"w-10 h-10 rounded-lg\"\n data-testid=\"skeleton\"\n />\n <div className=\"flex-1 space-y-2\">\n <Skeleton className=\"h-4 w-1/3\" data-testid=\"skeleton\" />\n <Skeleton className=\"h-3 w-2/3\" data-testid=\"skeleton\" />\n </div>\n <Skeleton className=\"w-16 h-8\" data-testid=\"skeleton\" />\n </div>\n ))}\n </div>\n );\n }\n\n if (workflows.length === 0) {\n return (\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <Workflow className=\"h-12 w-12 text-muted-foreground mb-4\" />\n <h3 className=\"text-lg font-medium mb-2\">暂无工作流</h3>\n <p className=\"text-sm text-muted-foreground\">\n 当前工作空间下没有可用的工作流\n </p>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-3 max-h-[500px] overflow-auto\">\n {workflows.map((workflow) => (\n <div\n key={workflow.workflow_id}\n className=\"flex items-center gap-4 p-4 border rounded-lg hover:bg-slate-50 transition-colors\"\n >\n {/* 工作流图标 */}\n <div className=\"flex-shrink-0 w-10 h-10 bg-green-100 rounded-lg flex items-center justify-center text-lg\">\n <Workflow className=\"h-5 w-5 text-green-600\" />\n </div>\n\n {/* 工作流信息 */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2 mb-1\">\n <h4 className=\"font-medium text-sm truncate\">\n {workflow.workflow_name}\n </h4>\n <Badge variant=\"secondary\" className=\"text-xs\">\n 工作流\n </Badge>\n </div>\n <p className=\"text-sm text-muted-foreground line-clamp-2\">\n {workflow.description || \"暂无描述\"}\n </p>\n </div>\n\n {/* 添加按钮 */}\n <div className=\"flex-shrink-0\">\n {workflow.isAddedAsTool ? (\n <Badge\n variant=\"secondary\"\n className=\"text-xs bg-green-100 text-green-800\"\n >\n 已添加\n </Badge>\n ) : (\n <Button\n size=\"sm\"\n onClick={() => handleAddWorkflow(workflow)}\n disabled={isAddingWorkflow}\n >\n {isAddingWorkflow ? (\n <Loader2\n className=\"h-4 w-4 animate-spin\"\n data-testid=\"loader\"\n />\n ) : (\n <Plus className=\"h-4 w-4\" />\n )}\n 添加\n </Button>\n )}\n </div>\n </div>\n ))}\n </div>\n );\n };\n\n // 渲染分页控件\n const renderPagination = () => {\n if (!selectedWorkspace || workflows.length === 0) {\n return null;\n }\n\n return (\n <div className=\"flex items-center justify-end\">\n <div className=\"flex items-center gap-2\">\n <Button\n variant=\"link\"\n size=\"sm\"\n onClick={handlePrevPage}\n disabled={currentPage === 1}\n className=\"text-muted-foreground\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n </Button>\n\n <div className=\"flex items-center gap-1\">\n <span className=\"text-sm\">{currentPage}</span>\n </div>\n\n <Button\n variant=\"link\"\n size=\"sm\"\n onClick={handleNextPage}\n disabled={!hasMoreWorkflows}\n className=\"text-muted-foreground\"\n >\n <ChevronRight className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n );\n };\n\n return (\n <>\n <Dialog open={open} onOpenChange={setOpen}>\n <DialogTrigger asChild>\n <Button variant=\"outline\" className=\"w-full\">\n <Workflow className=\"h-4 w-4 mr-2\" />\n 工作流集成\n </Button>\n </DialogTrigger>\n <DialogContent className=\"flex flex-col max-w-full w-[1000px]\">\n <DialogHeader className=\"flex-shrink-0\">\n <DialogTitle className=\"flex items-center gap-2\">\n <Workflow className=\"h-5 w-5\" />\n 工作流集成\n </DialogTitle>\n </DialogHeader>\n\n {/* 工作空间选择器 */}\n <div className=\"w-[120px]\">{renderWorkspaceSelector()}</div>\n\n {/* 工作流列表 */}\n <div className=\"flex-1 pr-2 w-full\">{renderWorkflowList()}</div>\n\n {/* 分页控件 */}\n {renderPagination()}\n </DialogContent>\n </Dialog>\n\n {/* 参数配置对话框 */}\n {parameterConfigDialog.workflow && (\n <WorkflowParameterConfigDialog\n open={parameterConfigDialog.open}\n onOpenChange={(open) =>\n setParameterConfigDialog((prev) => ({ ...prev, open }))\n }\n workflow={parameterConfigDialog.workflow}\n onConfirm={handleParameterConfigConfirm}\n onCancel={handleParameterConfigCancel}\n title=\"配置工作流参数\"\n />\n )}\n\n {/* 确认对话框 */}\n <AlertDialog\n open={confirmDialog.open}\n onOpenChange={(open) => setConfirmDialog((prev) => ({ ...prev, open }))}\n >\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>确认添加工作流</AlertDialogTitle>\n <AlertDialogDescription>\n 确定要将工作流 \"{confirmDialog.workflow?.workflow_name}\" 添加为\n MCP 工具吗?\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>取消</AlertDialogCancel>\n <AlertDialogAction\n onClick={() => {\n if (confirmDialog.workflow) {\n handleConfirmAddWorkflow(confirmDialog.workflow);\n }\n }}\n >\n 添加\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </>\n );\n}\n","import { Button } from \"@/components/ui/button\";\nimport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from \"@/components/ui/dialog\";\nimport {\n Form,\n FormControl,\n FormField,\n FormItem,\n FormMessage,\n} from \"@/components/ui/form\";\n\nimport { useWebSocket } from \"@/hooks/useWebSocket\";\nimport { useConfig } from \"@/stores/config\";\nimport type { MCPServerConfig } from \"@/types/index\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport { Textarea } from \"@ui/textarea\";\nimport { SettingsIcon } from \"lucide-react\";\nimport { useState } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport { toast } from \"sonner\";\nimport z from \"zod\";\n\nconst formSchema = z.object({\n config: z.string().min(2, {\n message: \"配置不能为空\",\n }),\n});\n\nexport function McpServerSettingButton({\n mcpServer,\n mcpServerName,\n}: {\n mcpServer: MCPServerConfig;\n mcpServerName: string;\n}) {\n const [open, setOpen] = useState(false);\n const [isLoading, setIsLoading] = useState(false);\n const config = useConfig();\n const { updateConfig } = useWebSocket();\n\n const form = useForm<z.infer<typeof formSchema>>({\n resolver: zodResolver(formSchema),\n defaultValues: {\n config: JSON.stringify(mcpServer, null, 2),\n },\n });\n\n async function onSubmit(values: z.infer<typeof formSchema>) {\n if (!config) {\n toast.error(\"配置数据未加载,请稍后重试\");\n return;\n }\n\n setIsLoading(true);\n try {\n // 解析用户输入的JSON配置\n let newMcpServerConfig: MCPServerConfig;\n try {\n newMcpServerConfig = JSON.parse(values.config);\n } catch (error) {\n toast.error(\"JSON格式错误,请检查配置格式\");\n return;\n }\n\n // 验证配置格式\n if (!newMcpServerConfig || typeof newMcpServerConfig !== \"object\") {\n toast.error(\"配置格式无效\");\n return;\n }\n\n // 更新配置\n const updatedConfig = {\n ...config,\n mcpServers: {\n ...config.mcpServers,\n [mcpServerName]: newMcpServerConfig,\n },\n };\n\n await updateConfig(updatedConfig);\n toast.success(\"MCP服务器配置已更新\");\n setOpen(false);\n } catch (error) {\n console.error(\"更新配置失败:\", error);\n toast.error(error instanceof Error ? error.message : \"更新配置失败\");\n } finally {\n setIsLoading(false);\n }\n }\n\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n <DialogTrigger asChild>\n <Button variant=\"secondary\" size=\"icon\" className=\"size-8\">\n <SettingsIcon className=\"h-4 w-4\" />\n </Button>\n </DialogTrigger>\n <DialogContent className=\"sm:max-w-[500px]\">\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)}>\n <DialogHeader className=\"mb-4\">\n <DialogTitle>配置 {mcpServerName} MCP</DialogTitle>\n <DialogDescription>\n 点击保存后,需要重启服务才会生效。\n </DialogDescription>\n </DialogHeader>\n <div className=\"grid gap-4\">\n <FormField\n control={form.control}\n name=\"config\"\n render={({ field }) => (\n <FormItem>\n <FormControl>\n <Textarea\n placeholder=\"MCP服务配置\"\n className=\"resize-none h-[300px] font-mono text-sm\"\n disabled={isLoading}\n {...field}\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n </div>\n <DialogFooter className=\"mt-4\">\n <DialogClose asChild>\n <Button variant=\"outline\" disabled={isLoading}>\n 取消\n </Button>\n </DialogClose>\n <Button type=\"submit\" disabled={isLoading}>\n {isLoading ? \"保存中...\" : \"保存\"}\n </Button>\n </DialogFooter>\n </form>\n </Form>\n </DialogContent>\n </Dialog>\n );\n}\n","import { Button } from \"@/components/ui/button\";\nimport { mcpServerApi } from \"@/services/api\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from \"@ui/alert-dialog\";\nimport { TrashIcon } from \"lucide-react\";\nimport { useState } from \"react\";\nimport { toast } from \"sonner\";\n\nexport function RemoveMcpServerButton({\n mcpServerName,\n onRemoveSuccess,\n disabled = false,\n}: {\n mcpServerName: string;\n onRemoveSuccess?: () => Promise<void>;\n disabled?: boolean;\n}) {\n const [isLoading, setIsLoading] = useState(false);\n\n const onRemove = async () => {\n try {\n setIsLoading(true);\n\n // 调用API删除服务器\n const result = await mcpServerApi.removeServer(mcpServerName);\n\n if (!result) {\n throw new Error(\"删除服务器失败\");\n }\n\n toast.success(`MCP 服务 \"${mcpServerName}\" 已删除`);\n\n // 调用成功回调\n if (onRemoveSuccess) {\n await onRemoveSuccess();\n }\n } catch (error) {\n console.error(\"删除 MCP 服务失败:\", error);\n toast.error(\n `删除 MCP 服务失败: ${error instanceof Error ? error.message : \"未知错误\"}`\n );\n } finally {\n setIsLoading(false);\n }\n };\n\n return (\n <AlertDialog>\n <AlertDialogTrigger asChild>\n <Button\n variant=\"destructive\"\n size=\"icon\"\n className=\"size-8\"\n disabled={disabled || isLoading}\n >\n <TrashIcon className=\"h-4 w-4\" />\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>\n 确定要删除这个({mcpServerName})MCP服务吗?\n </AlertDialogTitle>\n <AlertDialogDescription>\n 删除后,对应的工具列表也会移除。\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>取消</AlertDialogCancel>\n <AlertDialogAction\n onClick={onRemove}\n disabled={disabled || isLoading}\n className=\"bg-destructive text-destructive-foreground hover:bg-destructive/90\"\n >\n {isLoading ? \"删除中...\" : \"确定\"}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n );\n}\n","import { Button } from \"@/components/ui/button\";\nimport { useRestartPollingStatus, useStatusStore } from \"@/stores/status\";\nimport clsx from \"clsx\";\nimport { LoaderCircleIcon, PowerIcon } from \"lucide-react\";\n\n/**\n * 重启状态接口\n */\nexport interface RestartStatus {\n status: \"restarting\" | \"completed\" | \"failed\";\n error?: string;\n timestamp: number;\n}\n\n/**\n * RestartButton 组件属性接口\n */\nexport interface RestartButtonProps {\n /** 重启状态 */\n restartStatus?: RestartStatus;\n /** 是否禁用按钮 */\n disabled?: boolean;\n /** 按钮样式变体 */\n variant?:\n | \"default\"\n | \"destructive\"\n | \"outline\"\n | \"secondary\"\n | \"ghost\"\n | \"link\";\n /** 自定义样式类 */\n className?: string;\n /** 重启中的文本 */\n restartingText?: string;\n /** 默认文本 */\n defaultText?: string;\n}\n\n/**\n * 独立的重启按钮组件\n * 基于 ConfigEditor.tsx 中的重启服务功能实现\n */\nexport function RestartButton({\n disabled = false,\n variant = \"outline\",\n className = \"\",\n restartingText = \"重启中...\",\n defaultText = \"重启服务\",\n}: RestartButtonProps) {\n const {\n loading: { isRestarting },\n restartService,\n } = useStatusStore();\n const restartPollingStatus = useRestartPollingStatus();\n\n // 处理重启点击事件\n const handleRestart = async () => {\n try {\n await restartService();\n } catch (error) {\n console.error(\"[RestartButton] 重启失败:\", error);\n }\n };\n\n // 计算显示文本\n const getDisplayText = () => {\n if (!isRestarting) {\n return defaultText;\n }\n\n // 如果重启轮询正在进行,显示进度信息\n if (restartPollingStatus.enabled && restartPollingStatus.startTime) {\n return \"重连中...\";\n }\n\n return restartingText;\n };\n\n return (\n <Button\n type=\"button\"\n onClick={handleRestart}\n variant={variant}\n disabled={isRestarting || disabled}\n className={clsx(\"flex items-center gap-2 w-[120px]\", className)}\n >\n {!isRestarting ? (\n <PowerIcon className=\"size-4\" />\n ) : (\n <LoaderCircleIcon className=\"size-4 animate-spin\" />\n )}\n {getDisplayText()}\n </Button>\n );\n}\n","import { type VariantProps, cva } from \"class-variance-authority\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst alertVariants = cva(\n \"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground\",\n {\n variants: {\n variant: {\n default: \"bg-background text-foreground\",\n destructive:\n \"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\nconst Alert = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>\n>(({ className, variant, ...props }, ref) => (\n <div\n ref={ref}\n role=\"alert\"\n className={cn(alertVariants({ variant }), className)}\n {...props}\n />\n));\nAlert.displayName = \"Alert\";\n\nconst AlertTitle = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLHeadingElement>\n>(({ className, ...props }, ref) => (\n <h5\n ref={ref}\n className={cn(\"mb-1 font-medium leading-none tracking-tight\", className)}\n {...props}\n />\n));\nAlertTitle.displayName = \"AlertTitle\";\n\nconst AlertDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"text-sm [&_p]:leading-relaxed\", className)}\n {...props}\n />\n));\nAlertDescription.displayName = \"AlertDescription\";\n\nexport { Alert, AlertTitle, AlertDescription };\n","import { z } from \"zod\";\n\n/**\n * 根据 JSON Schema 动态生成 Zod schema\n */\nexport function createZodSchemaFromJsonSchema(jsonSchema: any): z.ZodTypeAny {\n if (!jsonSchema || typeof jsonSchema !== \"object\") {\n return z.any();\n }\n\n switch (jsonSchema.type) {\n case \"string\": {\n if (jsonSchema.enum) {\n return z.enum(jsonSchema.enum as [string, ...string[]]);\n }\n let stringSchema = z.string();\n if (jsonSchema.minLength) {\n stringSchema = stringSchema.min(jsonSchema.minLength);\n }\n if (jsonSchema.maxLength) {\n stringSchema = stringSchema.max(jsonSchema.maxLength);\n }\n if (jsonSchema.pattern) {\n stringSchema = stringSchema.regex(new RegExp(jsonSchema.pattern));\n }\n return stringSchema;\n }\n\n case \"number\":\n case \"integer\": {\n let numberSchema = z.number();\n if (jsonSchema.type === \"integer\") {\n numberSchema = numberSchema.int();\n }\n if (typeof jsonSchema.minimum === \"number\") {\n numberSchema = numberSchema.min(jsonSchema.minimum);\n }\n if (typeof jsonSchema.maximum === \"number\") {\n numberSchema = numberSchema.max(jsonSchema.maximum);\n }\n if (typeof jsonSchema.multipleOf === \"number\") {\n numberSchema = numberSchema.multipleOf(jsonSchema.multipleOf);\n }\n return numberSchema;\n }\n\n case \"boolean\":\n return z.boolean();\n\n case \"array\":\n if (jsonSchema.items) {\n const itemSchema = createZodSchemaFromJsonSchema(jsonSchema.items);\n let arraySchema = z.array(itemSchema);\n if (typeof jsonSchema.minItems === \"number\") {\n arraySchema = arraySchema.min(jsonSchema.minItems);\n }\n if (typeof jsonSchema.maxItems === \"number\") {\n arraySchema = arraySchema.max(jsonSchema.maxItems);\n }\n return arraySchema;\n }\n return z.array(z.any());\n\n case \"object\":\n if (\n jsonSchema.properties &&\n Object.keys(jsonSchema.properties).length > 0\n ) {\n const shape: Record<string, z.ZodTypeAny> = {};\n const requiredFields = jsonSchema.required || [];\n\n for (const [key, propSchema] of Object.entries(jsonSchema.properties)) {\n let fieldSchema = createZodSchemaFromJsonSchema(propSchema);\n\n // 如果字段不是必填的,设为可选\n if (!requiredFields.includes(key)) {\n fieldSchema = fieldSchema.optional();\n }\n\n shape[key] = fieldSchema;\n }\n\n return z.object(shape);\n }\n return z.record(z.string(), z.any());\n\n default:\n return z.any();\n }\n}\n\n/**\n * 获取字段的默认值\n */\nexport function getDefaultValueForSchema(schema: any): any {\n if (!schema) return undefined;\n\n switch (schema.type) {\n case \"string\":\n if (schema.enum) return schema.enum[0];\n return \"\";\n\n case \"number\":\n case \"integer\":\n return 0;\n\n case \"boolean\":\n return false;\n\n case \"array\":\n return [];\n\n case \"object\":\n if (schema.properties) {\n const defaults: Record<string, any> = {};\n for (const [key, propSchema] of Object.entries(schema.properties)) {\n defaults[key] = getDefaultValueForSchema(propSchema);\n }\n return defaults;\n }\n return {};\n\n default:\n return undefined;\n }\n}\n\n/**\n * 根据 JSON Schema 生成默认值对象\n */\nexport function createDefaultValues(jsonSchema: any): Record<string, any> {\n if (!jsonSchema || !jsonSchema.properties) return {};\n\n const defaults: Record<string, any> = {};\n const requiredFields = jsonSchema.required || [];\n\n for (const [key, propSchema] of Object.entries(jsonSchema.properties)) {\n if (requiredFields.includes(key)) {\n defaults[key] = getDefaultValueForSchema(propSchema);\n } else {\n // 对于可选字段,只设置明显的默认值\n const defaultValue = getDefaultValueForSchema(propSchema);\n if (defaultValue !== undefined && defaultValue !== \"\") {\n defaults[key] = defaultValue;\n }\n }\n }\n\n return defaults;\n}\n","\"use client\";\n\nimport { Alert, AlertDescription } from \"@/components/ui/alert\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n} from \"@/components/ui/dialog\";\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@/components/ui/form\";\nimport { Input } from \"@/components/ui/input\";\nimport { ScrollArea } from \"@/components/ui/scroll-area\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@/components/ui/select\";\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"@/components/ui/tabs\";\nimport { Textarea } from \"@/components/ui/textarea\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport {\n createDefaultValues,\n createZodSchemaFromJsonSchema,\n} from \"@/lib/schema-utils\";\nimport { apiClient } from \"@/services/api\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport {\n AlertCircle,\n BrushCleaningIcon,\n CheckIcon,\n Code,\n CopyIcon,\n InfoIcon,\n Loader2,\n PlayIcon,\n Plus,\n Trash2,\n Zap,\n} from \"lucide-react\";\nimport { memo, useCallback, useEffect, useMemo, useState } from \"react\";\nimport { Controller, useFieldArray, useForm } from \"react-hook-form\";\nimport { toast } from \"sonner\";\nimport { z } from \"zod\";\n\n// 数组字段渲染器组件\ninterface ArrayFieldProps {\n name: string;\n schema: any;\n form: any;\n renderFormField: (fieldName: string, fieldSchema: any) => JSX.Element | null;\n}\n\nconst ArrayField = memo(function ArrayField({\n name,\n schema,\n form,\n renderFormField,\n}: ArrayFieldProps) {\n const { fields, append, remove } = useFieldArray({\n control: form.control,\n name: name as any,\n });\n\n const addItem = () => {\n const itemSchema = schema.items;\n let newItem: any;\n\n switch (itemSchema.type) {\n case \"string\":\n newItem = itemSchema.enum ? itemSchema.enum[0] : \"\";\n break;\n case \"number\":\n case \"integer\":\n newItem = 0;\n break;\n case \"boolean\":\n newItem = false;\n break;\n case \"array\":\n newItem = [];\n break;\n case \"object\":\n newItem = {};\n break;\n default:\n newItem = \"\";\n }\n\n append(newItem);\n };\n\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm font-medium\">\n 数组项目 ({schema.items?.type || \"unknown\"})\n </span>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={addItem}\n className=\"h-8 px-2\"\n >\n <Plus className=\"h-3 w-3 mr-1\" />\n 添加\n </Button>\n </div>\n {fields.length === 0 ? (\n <div className=\"text-center py-4 border border-dashed rounded-md\">\n <span className=\"text-sm text-muted-foreground\">暂无数组项目</span>\n </div>\n ) : (\n <div className=\"space-y-3\">\n {fields.map((field, index) => (\n <div\n key={field.id}\n className=\"relative p-3 border rounded-md bg-muted/20\"\n >\n <div className=\"absolute top-2 right-2\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => remove(index)}\n className=\"h-6 w-6 p-0 text-red-500 hover:text-red-700\"\n >\n <Trash2 className=\"h-3 w-3\" />\n </Button>\n </div>\n <div className=\"pr-8\">\n <span className=\"text-xs font-medium text-muted-foreground mb-2 block\">\n 项目 {index + 1}\n </span>\n <FormField\n control={form.control}\n name={`${name}.${index}` as any}\n render={() => (\n <FormItem>\n {(() => {\n if (\n schema.items?.type === \"object\" ||\n schema.items?.type === \"array\"\n ) {\n return (\n <div className=\"ml-6 border-l-2 border-muted pl-4\">\n {renderFormField(\n `${name}.${index}`,\n schema.items\n )}\n </div>\n );\n }\n return renderFormField(\n `${name}.${index}`,\n schema.items\n );\n })()}\n </FormItem>\n )}\n />\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n );\n});\n\n// 对象字段渲染器组件\ninterface ObjectFieldProps {\n name: string;\n schema: any;\n form: any;\n renderFormField: (fieldName: string, fieldSchema: any) => JSX.Element | null;\n getTypeBadge: (type: string) => string;\n}\n\nconst ObjectField = memo(function ObjectField({\n name,\n schema,\n form,\n renderFormField,\n getTypeBadge,\n}: ObjectFieldProps) {\n if (!schema.properties || Object.keys(schema.properties).length === 0) {\n return (\n <div className=\"text-center py-4 border border-dashed rounded-md\">\n <span className=\"text-sm text-muted-foreground\">对象无定义字段</span>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-4\">\n <span className=\"text-sm font-medium\">对象字段</span>\n {Object.entries(schema.properties).map(\n ([fieldName, fieldSchema]: [string, any]) => (\n <div\n key={`${name}-${fieldName}`}\n className=\"ml-6 border-l-2 border-muted pl-4\"\n >\n <FormField\n control={form.control}\n name={`${name}.${fieldName}` as any}\n render={() => (\n <FormItem>\n <div className=\"flex items-center gap-2\">\n <FormLabel>\n {schema.required?.includes(fieldName) && (\n <span className=\"text-red-500 mr-1\">*</span>\n )}\n {fieldName}\n </FormLabel>\n <Badge\n variant=\"secondary\"\n className={`text-xs ${getTypeBadge(fieldSchema.type)}`}\n >\n {fieldSchema.type}\n </Badge>\n {fieldSchema.description && (\n <Tooltip>\n <TooltipTrigger>\n <InfoIcon className=\"h-4 w-4 text-muted-foreground\" />\n </TooltipTrigger>\n <TooltipContent>\n <p className=\"max-w-xs whitespace-pre-wrap\">\n {fieldSchema.description}\n </p>\n </TooltipContent>\n </Tooltip>\n )}\n </div>\n {renderFormField(`${name}.${fieldName}`, fieldSchema)}\n {fieldSchema.description && (\n <FormDescription>{fieldSchema.description}</FormDescription>\n )}\n <FormMessage />\n </FormItem>\n )}\n />\n </div>\n )\n )}\n </div>\n );\n});\n\n// 无参数提示组件\nconst NoParamsMessage = memo(function NoParamsMessage() {\n return (\n <div className=\"h-full flex items-center justify-center\">\n <div className=\"text-center space-y-4 max-w-sm mx-auto p-6\">\n <div className=\"mx-auto w-16 h-16 bg-green-100 rounded-full flex items-center justify-center\">\n <CheckIcon className=\"h-8 w-8 text-green-600\" />\n </div>\n <div className=\"space-y-2\">\n <h3 className=\"text-lg font-semibold text-foreground\">\n 无需输入参数\n </h3>\n <p className=\"text-sm text-muted-foreground\">\n 点击\"调用工具\"按钮执行,无需输入任何参数。\n </p>\n </div>\n </div>\n </div>\n );\n});\n\n// 表单渲染器组件\ninterface FormRendererProps {\n tool: ToolDebugDialogProps[\"tool\"];\n form: any;\n renderFormField: (fieldName: string, fieldSchema: any) => JSX.Element | null;\n}\n\nconst FormRenderer = memo(function FormRenderer({\n tool,\n form,\n renderFormField,\n}: FormRendererProps) {\n if (!tool?.inputSchema?.properties) {\n return (\n <div className=\"text-center py-8\">\n <Code className=\"h-8 w-8 mx-auto mb-2 opacity-50\" />\n <p className=\"text-muted-foreground\">该工具无参数定义</p>\n </div>\n );\n }\n\n return (\n <Form {...form}>\n <ScrollArea className=\"h-full\">\n <div className=\"space-y-4 p-2\">\n {Object.entries(tool.inputSchema.properties).map(\n ([fieldName, fieldSchema]: [string, any]) => (\n <FormField\n key={`${tool.name}-${fieldName}`} // 添加工具名称作为前缀,确保 key 的唯一性和稳定性\n control={form.control}\n name={fieldName as any}\n render={() => (\n <FormItem>\n <div className=\"flex items-center gap-2\">\n <FormLabel>\n {tool.inputSchema.required?.includes(fieldName) && (\n <span className=\"text-red-500 mr-1\">*</span>\n )}\n {fieldName}\n </FormLabel>\n <Badge\n variant=\"secondary\"\n className={`text-xs ${\n fieldSchema.type === \"string\"\n ? \"bg-blue-100 text-blue-800\"\n : fieldSchema.type === \"number\" ||\n fieldSchema.type === \"integer\"\n ? \"bg-green-100 text-green-800\"\n : fieldSchema.type === \"boolean\"\n ? \"bg-purple-100 text-purple-800\"\n : fieldSchema.type === \"array\"\n ? \"bg-orange-100 text-orange-800\"\n : fieldSchema.type === \"object\"\n ? \"bg-gray-100 text-gray-800\"\n : \"bg-gray-100 text-gray-800\"\n }`}\n >\n {fieldSchema.type}\n </Badge>\n {fieldSchema.description && (\n <Tooltip>\n <TooltipTrigger>\n <InfoIcon className=\"h-4 w-4 text-muted-foreground\" />\n </TooltipTrigger>\n <TooltipContent>\n <p className=\"max-w-xs whitespace-pre-wrap\">\n {fieldSchema.description}\n </p>\n </TooltipContent>\n </Tooltip>\n )}\n </div>\n {renderFormField(fieldName, fieldSchema)}\n <FormMessage />\n </FormItem>\n )}\n />\n )\n )}\n </div>\n </ScrollArea>\n </Form>\n );\n});\n\ninterface ToolDebugDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n tool: {\n name: string;\n serverName: string;\n toolName: string;\n description?: string;\n inputSchema?: any;\n } | null;\n}\n\nexport function ToolDebugDialog({\n open,\n onOpenChange,\n tool,\n}: ToolDebugDialogProps) {\n const [inputMode, setInputMode] = useState<\"form\" | \"json\">(\"form\");\n const [jsonInput, setJsonInput] = useState<string>(\"{\\n \\n}\");\n const [result, setResult] = useState<any>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [copied, setCopied] = useState(false);\n\n // 创建动态 schema\n const formSchema = useMemo(() => {\n if (!tool?.inputSchema) return z.object({});\n return createZodSchemaFromJsonSchema(tool.inputSchema);\n }, [tool?.inputSchema]);\n\n // 创建默认值\n const defaultValues = useMemo(() => {\n if (!tool?.inputSchema) return {};\n return createDefaultValues(tool.inputSchema);\n }, [tool?.inputSchema]);\n\n // 初始化表单\n const form = useForm({\n resolver: zodResolver(formSchema as any),\n defaultValues,\n mode: \"onChange\",\n });\n\n // 当工具变化时重置表单\n useEffect(() => {\n if (tool?.inputSchema) {\n // 重置表单到默认值\n form.reset(defaultValues);\n try {\n setJsonInput(JSON.stringify(defaultValues, null, 2));\n } catch {\n setJsonInput(\"{\\n \\n}\");\n }\n } else {\n form.reset({});\n setJsonInput(\"{\\n \\n}\");\n }\n }, [tool?.inputSchema, defaultValues, form]); // 添加 form 依赖以满足 linter 要求\n\n // 重置状态\n const resetState = useCallback(() => {\n setInputMode(\"form\");\n setJsonInput(\"{\\n \\n}\");\n setResult(null);\n setError(null);\n setCopied(false);\n // 只在有工具且有输入schema时才重置表单\n if (tool?.inputSchema) {\n form.reset(defaultValues);\n }\n }, [tool?.inputSchema, defaultValues, form]);\n\n // 处理Tab切换\n const handleModeChange = useCallback(\n (newMode: \"form\" | \"json\") => {\n if (newMode === \"json\" && inputMode === \"form\") {\n // 从表单模式切换到JSON模式时,同步数据\n const currentValues = form.getValues();\n try {\n setJsonInput(JSON.stringify(currentValues, null, 2));\n } catch {\n setJsonInput(\"{\\n \\n}\");\n }\n } else if (newMode === \"form\" && inputMode === \"json\") {\n // 从JSON模式切换到表单模式时,同步数据\n try {\n const parsedData = JSON.parse(jsonInput);\n // 使用 setValue 而不是 reset 来避免表单重新初始化导致的失焦\n for (const key of Object.keys(parsedData)) {\n form.setValue(key as any, parsedData[key]);\n }\n } catch {\n // JSON 解析失败,保持表单数据不变\n }\n }\n setInputMode(newMode);\n },\n [inputMode, jsonInput, form]\n );\n\n // 当弹窗关闭时重置状态\n const handleOpenChange = useCallback(\n (newOpen: boolean) => {\n if (!newOpen) {\n resetState();\n }\n onOpenChange(newOpen);\n },\n [onOpenChange, resetState]\n );\n\n // 验证JSON格式\n const validateJSON = useCallback((jsonString: string) => {\n try {\n JSON.parse(jsonString);\n return true;\n } catch {\n return false;\n }\n }, []);\n\n // 调用工具\n const handleCallTool = useCallback(async () => {\n if (!tool) return;\n\n let args: any;\n\n // 检查是否无参数工具\n const hasNoParams =\n !tool?.inputSchema?.properties ||\n Object.keys(tool.inputSchema.properties).length === 0;\n\n if (hasNoParams) {\n // 无参数工具使用空对象\n args = {};\n } else if (inputMode === \"form\") {\n const values = form.getValues();\n const isValid = await form.trigger();\n if (!isValid) {\n toast.error(\"请检查表单中的错误\");\n return;\n }\n args = values;\n } else {\n // 验证JSON格式\n if (!validateJSON(jsonInput)) {\n toast.error(\"输入参数不是有效的JSON格式\");\n return;\n }\n args = JSON.parse(jsonInput);\n }\n\n setLoading(true);\n setError(null);\n setResult(null);\n\n try {\n const response = await apiClient.callTool(\n tool.serverName,\n tool.toolName,\n args\n );\n\n setResult(response);\n toast.success(\"工具调用成功\");\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : \"调用工具失败\";\n setError(errorMessage);\n toast.error(errorMessage);\n } finally {\n setLoading(false);\n }\n }, [tool, inputMode, form, jsonInput, validateJSON]);\n\n // 复制结果\n const handleCopy = useCallback(async () => {\n const content = result ? JSON.stringify(result, null, 2) : error || \"\";\n try {\n await navigator.clipboard.writeText(content);\n setCopied(true);\n toast.success(\"已复制到剪贴板\");\n setTimeout(() => setCopied(false), 2000);\n } catch {\n toast.error(\"复制失败\");\n }\n }, [result, error]);\n\n // 清空输入\n const handleClear = useCallback(() => {\n setResult(null);\n setError(null);\n\n if (inputMode === \"form\" && tool?.inputSchema) {\n // 在表单模式下,重置为默认值\n form.reset(defaultValues);\n try {\n setJsonInput(JSON.stringify(defaultValues, null, 2));\n } catch {\n setJsonInput(\"{\\n \\n}\");\n }\n } else {\n // 在JSON模式或无schema时,清空JSON输入\n setJsonInput(\"{\\n \\n}\");\n if (tool?.inputSchema) {\n // 如果有schema,也重置表单\n form.reset(defaultValues);\n } else {\n form.reset({});\n }\n }\n }, [inputMode, tool?.inputSchema, defaultValues, form]);\n\n // 渲染表单字段的辅助函数 - 使用 useMemo 优化性能\n const renderFormField = useMemo(() => {\n const getTypeBadge = (type: string) => {\n const colors: Record<string, string> = {\n string: \"bg-blue-100 text-blue-800\",\n number: \"bg-green-100 text-green-800\",\n integer: \"bg-green-100 text-green-800\",\n boolean: \"bg-purple-100 text-purple-800\",\n array: \"bg-orange-100 text-orange-800\",\n object: \"bg-gray-100 text-gray-800\",\n };\n\n return colors[type] || \"bg-gray-100 text-gray-800\";\n };\n\n return (fieldName: string, fieldSchema: any): JSX.Element | null => {\n switch (fieldSchema.type) {\n case \"string\":\n if (fieldSchema.enum) {\n return (\n <Controller\n name={fieldName as any}\n control={form.control}\n render={({ field }) => (\n <Select value={field.value} onValueChange={field.onChange}>\n <FormControl>\n <SelectTrigger>\n <SelectValue placeholder={`选择${fieldName}`} />\n </SelectTrigger>\n </FormControl>\n <SelectContent>\n {fieldSchema.enum.map((option: string) => (\n <SelectItem key={option} value={option}>\n {option}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )}\n />\n );\n }\n return (\n <Controller\n name={fieldName as any}\n control={form.control}\n render={({ field }) => (\n <FormControl>\n <Input\n {...field}\n placeholder={`输入${fieldName}`}\n type={\n fieldSchema.format === \"password\" ? \"password\" : \"text\"\n }\n />\n </FormControl>\n )}\n />\n );\n\n case \"number\":\n case \"integer\":\n return (\n <Controller\n name={fieldName as any}\n control={form.control}\n render={({ field }) => (\n <FormControl>\n <Input\n {...field}\n type=\"number\"\n placeholder={`输入${fieldName}`}\n step={fieldSchema.type === \"integer\" ? \"1\" : \"0.1\"}\n onChange={(e) => {\n const value = e.target.value;\n field.onChange(value === \"\" ? \"\" : Number(value));\n }}\n />\n </FormControl>\n )}\n />\n );\n\n case \"boolean\":\n return (\n <Controller\n name={fieldName as any}\n control={form.control}\n render={({ field }) => (\n <Select\n value={field.value?.toString()}\n onValueChange={(value) => field.onChange(value === \"true\")}\n >\n <FormControl>\n <SelectTrigger>\n <SelectValue placeholder={`选择${fieldName}`} />\n </SelectTrigger>\n </FormControl>\n <SelectContent>\n <SelectItem value=\"true\">true</SelectItem>\n <SelectItem value=\"false\">false</SelectItem>\n </SelectContent>\n </Select>\n )}\n />\n );\n\n case \"array\":\n return (\n <ArrayField\n name={fieldName}\n schema={fieldSchema}\n form={form}\n renderFormField={renderFormField}\n />\n );\n\n case \"object\":\n return (\n <ObjectField\n name={fieldName}\n schema={fieldSchema}\n form={form}\n renderFormField={renderFormField}\n getTypeBadge={getTypeBadge}\n />\n );\n\n default:\n return (\n <Controller\n name={fieldName as any}\n control={form.control}\n render={({ field }) => (\n <FormControl>\n <Input {...field} placeholder={`输入${fieldName}`} />\n </FormControl>\n )}\n />\n );\n }\n };\n }, [form]);\n\n // 格式化结果显示\n const formatResult = useCallback((data: any) => {\n try {\n return JSON.stringify(data, null, 2);\n } catch {\n return String(data);\n }\n }, []);\n\n // 检测操作系统并获取快捷键文本\n const getShortcutText = useCallback(() => {\n if (typeof window === \"undefined\") return \"⌘+Enter\";\n const isMac = /Mac|iPhone|iPad|iPod/.test(navigator.platform);\n return isMac ? \"⌘+Enter\" : \"Ctrl+Enter\";\n }, []);\n\n // 处理键盘事件\n const handleKeyDown = useCallback(\n async (event: KeyboardEvent) => {\n // 检查是否是 Command+Enter (Mac) 或 Ctrl+Enter (Windows/Linux)\n const isMac = /Mac|iPhone|iPad|iPod/.test(navigator.platform);\n const isShortcutKey = isMac\n ? event.metaKey && event.key === \"Enter\"\n : event.ctrlKey && event.key === \"Enter\";\n\n if (isShortcutKey && open && !loading) {\n // 阻止默认行为\n event.preventDefault();\n\n // 检查是否无参数工具,或者是有参数工具且JSON模式时验证格式\n const hasNoParams =\n !tool?.inputSchema?.properties ||\n Object.keys(tool.inputSchema.properties).length === 0;\n if (!hasNoParams && inputMode === \"json\" && !validateJSON(jsonInput)) {\n toast.error(\"输入参数不是有效的JSON格式\");\n return;\n }\n\n // 调用工具\n await handleCallTool();\n }\n },\n [\n open,\n loading,\n inputMode,\n jsonInput,\n validateJSON,\n handleCallTool,\n tool?.inputSchema?.properties,\n ]\n );\n\n // 添加键盘事件监听器\n useEffect(() => {\n if (open) {\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => {\n window.removeEventListener(\"keydown\", handleKeyDown);\n };\n }\n }, [open, handleKeyDown]);\n\n return (\n <Dialog open={open} onOpenChange={handleOpenChange}>\n <TooltipProvider>\n <DialogContent className=\"max-w-4xl max-h-[90vh] flex flex-col\">\n <DialogHeader>\n <DialogTitle className=\"flex items-center gap-2\">\n <Zap className=\"h-5 w-5\" />\n 工具调试\n </DialogTitle>\n </DialogHeader>\n\n {tool && (\n <div className=\"flex flex-col gap-4 h-[80vh]\">\n {/* 工具信息 */}\n <Card>\n <CardHeader className=\"pb-0\">\n <CardTitle className=\"text-base flex items-center gap-2\">\n <Badge variant=\"secondary\">{tool.serverName}</Badge>\n {tool.toolName}\n </CardTitle>\n </CardHeader>\n <CardContent>\n {tool.description && (\n <p className=\"text-sm text-muted-foreground mt-2\">\n {tool.description}\n </p>\n )}\n </CardContent>\n </Card>\n\n {/* 输入参数 */}\n <div className=\"flex-1 flex min-h-0 w-full overflow-hidden\">\n <div className=\"w-1/2 flex flex-col gap-2 flex-shrink-0 overflow-hidden pr-0.5\">\n <div className=\"flex items-center justify-between h-[40px]\">\n <h3 className=\"text-sm font-medium\">输入参数</h3>\n {tool?.inputSchema?.properties &&\n Object.keys(tool.inputSchema.properties).length > 0 && (\n <Tabs\n value={inputMode}\n onValueChange={(value) =>\n handleModeChange(value as \"form\" | \"json\")\n }\n >\n <TabsList className=\"grid w-full grid-cols-2\">\n <TabsTrigger value=\"form\" className=\"text-xs\">\n 表单模式\n </TabsTrigger>\n <TabsTrigger value=\"json\" className=\"text-xs\">\n 高级模式\n </TabsTrigger>\n </TabsList>\n </Tabs>\n )}\n </div>\n <div className=\"flex-1 min-h-0\">\n {tool?.inputSchema?.properties &&\n Object.keys(tool.inputSchema.properties).length > 0 ? (\n <Tabs\n value={inputMode}\n onValueChange={(value) =>\n handleModeChange(value as \"form\" | \"json\")\n }\n className=\"h-full flex flex-col\"\n >\n <TabsContent\n value=\"form\"\n className=\"flex-1 data-[state=active]:flex data-[state=active]:flex-col mt-0\"\n >\n <FormRenderer\n tool={tool}\n form={form}\n renderFormField={renderFormField}\n />\n </TabsContent>\n <TabsContent\n value=\"json\"\n className=\"flex-1 data-[state=active]:flex data-[state=active]:flex-col mt-0\"\n >\n <div className=\"flex-1 flex flex-col\">\n <Textarea\n value={jsonInput}\n onChange={(e) => setJsonInput(e.target.value)}\n placeholder=\"请输入JSON格式的参数...\"\n className=\"flex-1 font-mono text-sm resize-none min-h-[200px]\"\n disabled={loading}\n />\n {!validateJSON(jsonInput) &&\n jsonInput.trim() !== \"{\\n \\n}\" && (\n <Alert className=\"mt-2\">\n <AlertCircle className=\"h-4 w-4\" />\n <AlertDescription>\n JSON格式错误,请检查输入\n </AlertDescription>\n </Alert>\n )}\n </div>\n </TabsContent>\n </Tabs>\n ) : (\n <NoParamsMessage />\n )}\n </div>\n </div>\n\n {/* 结果显示 */}\n <div className=\"w-1/2 flex flex-col gap-2 flex-shrink-0 overflow-hidden pl-0.5\">\n <div className=\"flex items-center justify-between h-[40px]\">\n <h3 className=\"text-sm font-medium\">调用结果</h3>\n {(result || error) && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleCopy}\n className=\"gap-0\"\n >\n {copied ? (\n <>\n <CheckIcon className=\"h-4 w-4 mr-1\" />\n 已复制\n </>\n ) : (\n <>\n <CopyIcon className=\"h-4 w-4 mr-1\" />\n 复制结果\n </>\n )}\n </Button>\n )}\n </div>\n <div className=\"flex-1 min-h-0\">\n {loading ? (\n <div className=\"h-full flex items-center justify-center border rounded-md\">\n <div className=\"flex flex-col items-center gap-2\">\n <Loader2 className=\"h-8 w-8 animate-spin\" />\n <span className=\"text-sm text-muted-foreground\">\n 正在调用工具...\n </span>\n </div>\n </div>\n ) : error ? (\n <div className=\"h-full\">\n <Alert variant=\"destructive\" className=\"h-full\">\n <AlertDescription className=\"font-mono text-sm whitespace-pre-wrap break-words\">\n {error}\n </AlertDescription>\n </Alert>\n </div>\n ) : result ? (\n <ScrollArea className=\"h-full border rounded-md\">\n <pre className=\"p-3 text-sm font-mono whitespace-pre-wrap break-words min-w-0\">\n {formatResult(result)}\n </pre>\n </ScrollArea>\n ) : (\n <div className=\"h-full flex items-center justify-center border rounded-md\">\n <div className=\"text-center text-muted-foreground\">\n <Code className=\"h-8 w-8 mx-auto mb-2 opacity-50\" />\n <p>等待调用工具...</p>\n </div>\n </div>\n )}\n </div>\n </div>\n </div>\n\n {/* 底部操作按钮 */}\n <div className=\"flex justify-end gap-2 pt-4 border-t\">\n <Button\n variant=\"outline\"\n onClick={handleClear}\n disabled={loading}\n >\n <BrushCleaningIcon className=\"h-4 w-4\" />\n 清空\n </Button>\n <Button\n onClick={handleCallTool}\n disabled={\n loading ||\n // 只有有参数工具且在JSON模式时才检查JSON格式\n (() => {\n const hasNoParams =\n !tool?.inputSchema?.properties ||\n Object.keys(tool.inputSchema.properties).length === 0;\n return (\n !hasNoParams &&\n inputMode === \"json\" &&\n !validateJSON(jsonInput)\n );\n })()\n }\n >\n {loading ? (\n <>\n <Loader2 className=\"h-4 w-4 mr-2 animate-spin\" />\n 调用中...\n </>\n ) : (\n <>\n <PlayIcon className=\"h-4 w-4\" />\n {(() => {\n const hasNoParams =\n !tool?.inputSchema?.properties ||\n Object.keys(tool.inputSchema.properties).length === 0;\n return hasNoParams ? \"直接调用\" : \"调用工具\";\n })()} ({getShortcutText()})\n </>\n )}\n </Button>\n </div>\n </div>\n )}\n </DialogContent>\n </TooltipProvider>\n </Dialog>\n );\n}\n","import { WorkflowParameterConfigDialog } from \"@/components/common/WorkflowParameterConfigDialog\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n} from \"@/components/ui/alert-dialog\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardFooter } from \"@/components/ui/card\";\nimport { apiClient } from \"@/services/api\";\nimport {\n useConfigActions,\n useMcpServerConfig,\n useMcpServers,\n} from \"@/stores/config\";\nimport type {\n CozeWorkflow,\n MCPServerConfig,\n WorkflowParameter,\n} from \"@/types/index\";\nimport { getMcpServerCommunicationType } from \"@/utils/mcpServerUtils\";\nimport {\n CoffeeIcon,\n MinusIcon,\n PlusIcon,\n Settings,\n Wrench,\n ZapIcon,\n} from \"lucide-react\";\nimport { useCallback, useEffect, useState } from \"react\";\nimport { toast } from \"sonner\";\nimport { AddMcpServerButton } from \"./AddMcpServerButton\";\nimport { CozeWorkflowIntegration } from \"./CozeWorkflowIntegration\";\nimport { McpServerSettingButton } from \"./McpServerSettingButton\";\nimport { RemoveMcpServerButton } from \"./RemoveMcpServerButton\";\nimport { RestartButton } from \"./RestartButton\";\nimport { ToolDebugDialog } from \"./ToolDebugDialog\";\n\ninterface McpServerListProps {\n updateConfig?: (config: any) => Promise<void>;\n}\n\nexport function McpServerList({\n updateConfig: _updateConfig,\n}: McpServerListProps) {\n const mcpServerConfig = useMcpServerConfig();\n const mcpServers = useMcpServers();\n const { refreshConfig } = useConfigActions();\n // const config = useConfig(); // 不再使用配置更新,改为使用 API\n\n // 添加工具列表状态管理\n const [enabledTools, setEnabledTools] = useState<\n Array<{\n name: string;\n serverName: string;\n toolName: string;\n enable: boolean;\n description?: string;\n usageCount?: number;\n lastUsedTime?: string;\n inputSchema?: any;\n }>\n >([]);\n const [disabledTools, setDisabledTools] = useState<\n Array<{\n name: string;\n serverName: string;\n toolName: string;\n enable: boolean;\n description?: string;\n usageCount?: number;\n lastUsedTime?: string;\n inputSchema?: any;\n }>\n >([]);\n const [isLoadingTools, setIsLoadingTools] = useState(false);\n const [toolsError, setToolsError] = useState<string | null>(null);\n\n // 格式化工具信息的辅助函数\n const formatTool = useCallback((tool: any, enable: boolean) => {\n const { serviceName, toolName } = (() => {\n // 安全检查:确保 handler 存在\n if (!tool || !tool.handler) {\n return {\n serviceName: \"unknown\",\n toolName: tool?.name || \"unknown\",\n };\n }\n\n if (tool.handler.type === \"mcp\") {\n return {\n serviceName: tool.handler.config?.serviceName || \"unknown\",\n toolName: tool.handler.config?.toolName || tool.name,\n };\n }\n if (tool.handler.type === \"proxy\" && tool.handler.platform === \"coze\") {\n return {\n serviceName: \"coze\",\n toolName: tool.name,\n };\n }\n return {\n serviceName: \"custom\",\n toolName: tool.name,\n };\n })();\n\n return {\n serverName: serviceName,\n toolName,\n enable,\n name: tool.name,\n description: tool.description,\n usageCount: tool.stats?.usageCount,\n lastUsedTime: tool.stats?.lastUsedTime,\n inputSchema: tool.inputSchema,\n };\n }, []);\n\n // 获取工具列表\n const fetchTools = useCallback(async () => {\n setIsLoadingTools(true);\n setToolsError(null);\n\n try {\n // 并行获取已启用和未启用的工具列表\n const [enabledToolsList, disabledToolsList] = await Promise.all([\n apiClient.getToolsList(\"enabled\"),\n apiClient.getToolsList(\"disabled\"),\n ]);\n\n // 格式化已启用的工具\n const formattedEnabledTools = enabledToolsList.map((tool) =>\n formatTool(tool, true)\n );\n\n // 格式化未启用的工具\n const formattedDisabledTools = disabledToolsList.map((tool) =>\n formatTool(tool, false)\n );\n\n setEnabledTools(formattedEnabledTools);\n setDisabledTools(formattedDisabledTools);\n } catch (error) {\n console.error(\"获取工具列表失败:\", error);\n const errorMessage =\n error instanceof Error ? error.message : \"获取工具列表失败\";\n setToolsError(errorMessage);\n toast.error(errorMessage);\n\n // 发生错误时回退到使用 mcpServerConfig\n if (mcpServerConfig) {\n const fallbackTools = Object.entries(mcpServerConfig).flatMap(\n ([serverName, value]) => {\n return Object.entries(value?.tools || {}).map(\n ([toolName, tool]) => ({\n serverName,\n toolName,\n ...(tool as any),\n })\n );\n }\n );\n\n const enabled = fallbackTools.filter((tool) => tool.enable !== false);\n const disabled = fallbackTools.filter((tool) => tool.enable === false);\n\n setEnabledTools(enabled);\n setDisabledTools(disabled);\n }\n } finally {\n setIsLoadingTools(false);\n }\n }, [mcpServerConfig, formatTool]);\n\n // 添加刷新状态管理\n const [isRefreshing, setIsRefreshing] = useState(false);\n\n // 数据刷新处理函数 - 用于删除MCP服务后的状态同步\n const handleRefreshData = useCallback(async () => {\n if (isRefreshing) return; // 防止重复刷新\n\n try {\n setIsRefreshing(true);\n // 并行刷新配置数据和工具列表\n await Promise.all([refreshConfig(), fetchTools()]);\n } catch (error) {\n console.error(\"刷新数据失败:\", error);\n toast.error(\"刷新数据失败\");\n } finally {\n setIsRefreshing(false);\n }\n }, [refreshConfig, fetchTools, isRefreshing]);\n\n // 更新工具列表状态(用于启用/禁用后刷新)\n const refreshToolLists = useCallback(async () => {\n try {\n const [enabledToolsList, disabledToolsList] = await Promise.all([\n apiClient.getToolsList(\"enabled\"),\n apiClient.getToolsList(\"disabled\"),\n ]);\n\n // 格式化已启用的工具\n const formattedEnabledTools = enabledToolsList.map((tool) =>\n formatTool(tool, true)\n );\n\n // 格式化未启用的工具\n const formattedDisabledTools = disabledToolsList.map((tool) =>\n formatTool(tool, false)\n );\n\n setEnabledTools(formattedEnabledTools);\n setDisabledTools(formattedDisabledTools);\n } catch (error) {\n console.error(\"刷新工具列表失败:\", error);\n toast.error(\"刷新工具列表失败\");\n }\n }, [formatTool]);\n\n // 组件加载时获取工具列表\n useEffect(() => {\n fetchTools();\n }, [fetchTools]);\n\n // 添加状态来管理 Coze 工具确认对话框\n const [cozeToolToRemove, setCozeToolToRemove] = useState<string | null>(null);\n\n // 添加状态来管理参数配置对话框\n const [parameterConfigDialog, setParameterConfigDialog] = useState<{\n open: boolean;\n tool?: any;\n }>({ open: false });\n\n // 添加状态来管理工具调试对话框\n const [debugDialog, setDebugDialog] = useState<{\n open: boolean;\n tool?: {\n name: string;\n serverName: string;\n toolName: string;\n description?: string;\n inputSchema?: any;\n };\n }>({ open: false });\n\n const handleToggleTool = async (name: string, currentEnable: boolean) => {\n try {\n if (currentEnable) {\n // 从使用中的工具移除(删除工具)\n // 首先找到对应的原始工具信息\n const originalTool = [...enabledTools, ...disabledTools].find(\n (tool) => tool.name === name\n );\n\n if (!originalTool) {\n toast.error(\"找不到对应的工具信息\");\n return;\n }\n\n // 检查是否为 Coze 工作流工具\n if (originalTool.serverName === \"coze\") {\n // Coze 工作流工具需要确认对话框\n setCozeToolToRemove(name);\n return; // 等待用户确认\n }\n\n // 执行移除操作(普通 MCP 工具)\n await apiClient.removeCustomTool(name);\n toast.success(`删除工具 ${name} 成功`);\n } else {\n // 添加到使用中的工具(启用工具)\n // 首先找到对应的原始工具信息来构建添加工具的请求\n const originalTool = [...enabledTools, ...disabledTools].find(\n (tool) => tool.name === name\n );\n\n if (!originalTool) {\n toast.error(\"找不到对应的工具信息\");\n return;\n }\n\n // 根据工具类型构建对应的请求格式\n if (originalTool.serverName === \"coze\") {\n // Coze 工作流工具 - 使用旧的向后兼容格式\n await apiClient.addCustomTool(\n {\n workflow_id: \"\", // Coze 工具不需要 workflow_id\n workflow_name: name,\n description: originalTool.description || \"\",\n icon_url: \"\",\n app_id: \"\",\n },\n name,\n originalTool.description || \"\"\n );\n } else {\n // MCP 工具 - 使用新的类型化格式\n await apiClient.addCustomTool({\n type: \"mcp\",\n data: {\n serviceName: originalTool.serverName,\n toolName: originalTool.toolName,\n customName: name,\n customDescription: originalTool.description || \"\",\n },\n });\n }\n\n toast.success(`添加工具 ${name} 成功`);\n }\n\n // 重新获取工具列表以更新状态\n await refreshToolLists();\n } catch (error) {\n console.error(\"切换工具状态失败:\", error);\n toast.error(error instanceof Error ? error.message : \"切换工具状态失败\");\n }\n };\n\n // 确认移除 Coze 工具的处理函数\n const handleConfirmRemoveCozeTool = async () => {\n if (!cozeToolToRemove) return;\n\n try {\n await apiClient.removeCustomTool(cozeToolToRemove);\n toast.success(`删除工具 ${cozeToolToRemove} 成功`);\n await refreshToolLists();\n } catch (error) {\n console.error(\"删除 Coze 工具失败:\", error);\n toast.error(\n error instanceof Error ? error.message : \"删除 Coze 工具失败\"\n );\n } finally {\n setCozeToolToRemove(null);\n }\n };\n\n // 取消移除 Coze 工具的处理函数\n const handleCancelRemoveCozeTool = () => {\n setCozeToolToRemove(null);\n };\n\n // 处理打开参数配置对话框\n const handleConfigureTool = (tool: any) => {\n // 检查是否为 coze 工具\n if (tool.serverName === \"coze\") {\n setParameterConfigDialog({\n open: true,\n tool,\n });\n }\n };\n\n // 处理打开工具调试对话框\n const handleDebugTool = (tool: any) => {\n setDebugDialog({\n open: true,\n tool: {\n name: tool.name,\n serverName: tool.serverName,\n toolName: tool.toolName,\n description: tool.description,\n inputSchema: tool.inputSchema,\n },\n });\n };\n\n // 从工具对象构建 CozeWorkflow 对象\n const buildCozeWorkflowFromTool = (tool: any): CozeWorkflow => {\n // 如果是 coze 工具,尝试从 handler 中提取信息\n if (tool.serverName === \"coze\" && tool.handler?.type === \"proxy\") {\n return {\n workflow_id: tool.handler.config?.workflow_id || \"\",\n workflow_name: tool.toolName,\n description: tool.description || \"\",\n icon_url: \"\",\n app_id: tool.handler.config?.app_id || \"\",\n creator: { id: \"\", name: \"\" },\n created_at: 0,\n updated_at: 0,\n isAddedAsTool: true,\n toolName: tool.name,\n inputSchema: tool.inputSchema,\n };\n }\n\n // 默认的工作流对象\n return {\n workflow_id: \"\",\n workflow_name: tool.toolName,\n description: tool.description || \"\",\n icon_url: \"\",\n app_id: \"\",\n creator: { id: \"\", name: \"\" },\n created_at: 0,\n updated_at: 0,\n isAddedAsTool: true,\n toolName: tool.name,\n inputSchema: tool.inputSchema,\n };\n };\n\n // 处理参数配置确认\n const handleParameterConfigConfirm = async (\n workflow: CozeWorkflow,\n parameters: WorkflowParameter[]\n ) => {\n if (!parameterConfigDialog.tool) return;\n\n try {\n // 构建参数配置\n const parameterConfig =\n parameters.length > 0 ? { parameters } : undefined;\n\n // 从工具对象构建正确的 CozeWorkflow 对象,确保包含必需的字段\n const cozeWorkflow = buildCozeWorkflowFromTool(\n parameterConfigDialog.tool\n );\n\n // 更新 workflow_id 和其他必需字段(如果传入的 workflow 有这些字段的话)\n if (workflow.workflow_id) {\n cozeWorkflow.workflow_id = workflow.workflow_id;\n }\n if (workflow.app_id) {\n cozeWorkflow.app_id = workflow.app_id;\n }\n\n // 构建更新请求\n const updateRequest = {\n type: \"coze\" as const,\n data: {\n workflow: cozeWorkflow,\n customName: undefined,\n customDescription: undefined,\n parameterConfig,\n },\n };\n\n // 调用API更新工具配置\n await apiClient.updateCustomTool(\n parameterConfigDialog.tool.name,\n updateRequest\n );\n\n toast.success(`工具 \"${cozeWorkflow.workflow_name}\" 参数配置更新成功`);\n\n // 刷新工具列表\n await refreshToolLists();\n } catch (error) {\n console.error(\"更新工具参数配置失败:\", error);\n\n let errorMessage = \"更新工具参数配置失败,请重试\";\n if (error instanceof Error) {\n errorMessage = error.message;\n }\n\n toast.error(errorMessage);\n } finally {\n setParameterConfigDialog({ open: false });\n }\n };\n\n // 处理参数配置取消\n const handleParameterConfigCancel = () => {\n setParameterConfigDialog({ open: false });\n };\n\n if (!mcpServers || Object.keys(mcpServers).length === 0) {\n return (\n <div className=\"@container/main flex flex-1 flex-col gap-2\">\n <div className=\"flex flex-col gap-4 py-4 md:gap-6 md:py-6\">\n <div className=\"flex items-center justify-between px-4 lg:px-6\">\n <div>\n <h2 className=\"text-lg font-semibold\">你的聚合 MCP 服务</h2>\n <p className=\"text-sm text-muted-foreground\">\n 在这里管理你的 MCP 服务器和工具。\n </p>\n </div>\n {/* <AddMcpServerButton /> */}\n </div>\n\n <div className=\"px-4 lg:px-6\">\n <Card className=\"border-dashed\">\n <CardContent className=\"flex flex-col items-center justify-center py-12\">\n <CoffeeIcon className=\"h-12 w-12 text-muted-foreground mb-4\" />\n <h3 className=\"text-lg font-semibold mb-2\">还没有 MCP 服务</h3>\n <p className=\"text-sm text-muted-foreground text-center mb-4\">\n 添加你的第一个 MCP 服务器来开始使用强大的工具集成功能。\n </p>\n <AddMcpServerButton />\n </CardContent>\n </Card>\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col gap-4 px-4 lg:px-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h2 className=\"text-2xl font-bold\">你的聚合 MCP 服务</h2>\n <p className=\"text-sm text-muted-foreground\">\n 你可以在这里管理你的 MCP\n 服务,包括启用/禁用工具,以及查看工具的详细信息。\n </p>\n </div>\n {isRefreshing && (\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <div className=\"animate-spin rounded-full h-4 w-4 border-b-2 border-primary\" />\n 刷新中...\n </div>\n )}\n </div>\n <div className=\"*:data-[slot=card]:shadow-xs @xl/main:grid-cols-8 @5xl/main:grid-cols-8 grid grid-cols-1 gap-4 *:data-[slot=card]:bg-gradient-to-t *:data-[slot=card]:from-primary/5 *:data-[slot=card]:to-card dark:*:data-[slot=card]:bg-card\">\n {/* <div>{JSON.stringify(enabledTools, null, 2)}</div> */}\n <Card className=\"transition-all duration-200 col-span-3\">\n <CardContent className=\"p-4\">\n <div className=\"flex-col\">\n <h4 className=\"text-sm font-medium mb-3 flex items-center gap-2\">\n <Wrench className=\"h-4 w-4\" />\n 使用中的工具 ({enabledTools.length})\n {isLoadingTools && (\n <span className=\"text-xs text-muted-foreground\">\n (加载中...)\n </span>\n )}\n </h4>\n <div className=\"flex-1 space-y-2\">\n {isLoadingTools ? (\n <div className=\"flex items-center justify-center py-8\">\n <div className=\"text-sm text-muted-foreground\">\n 加载工具列表中...\n </div>\n </div>\n ) : toolsError ? (\n <div className=\"flex flex-col items-center justify-center py-8 px-4\">\n <div className=\"text-sm text-red-500 mb-2\">\n {toolsError}\n </div>\n <Button variant=\"outline\" size=\"sm\" onClick={fetchTools}>\n 重试\n </Button>\n </div>\n ) : (\n enabledTools.map((tool) => (\n <div\n key={tool.toolName}\n className=\"flex items-start justify-between p-4 bg-slate-50 rounded-md font-mono\"\n >\n <div className=\"text-md flex flex-col gap-2\">\n <div className=\"flex items-center gap-2 justify-start\">\n <Badge variant=\"secondary\" className=\"rounded-md\">\n {tool.serverName}\n </Badge>\n <span>{tool.toolName}</span>\n </div>\n <p className=\"text-sm text-muted-foreground my-2\">\n {tool.description}\n </p>\n <div className=\"flex items-center gap-4\">\n <span className=\"text-sm text-muted-foreground\">\n <span className=\"text-muted-foreground\">\n 使用次数:\n </span>{\" \"}\n <span className=\"text-primary font-bold\">\n {tool.usageCount || 0}\n </span>\n </span>\n <span className=\"text-sm text-muted-foreground\">\n <span className=\"text-muted-foreground\">\n 最后使用:\n </span>{\" \"}\n <span className=\"text-primary font-bold\">\n {tool.lastUsedTime || \"-\"}\n </span>\n </span>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2 ml-4\">\n {tool.serverName === \"coze\" && (\n <Button\n variant=\"secondary\"\n size=\"icon\"\n className=\"size-8 hover:bg-blue-500 hover:text-white\"\n onClick={() => handleConfigureTool(tool)}\n title=\"配置参数\"\n >\n <Settings size={16} />\n </Button>\n )}\n <Button\n variant=\"secondary\"\n size=\"icon\"\n className=\"size-8 hover:bg-blue-500 hover:text-white\"\n onClick={() => handleDebugTool(tool)}\n title=\"调试工具\"\n >\n <ZapIcon size={18} />\n </Button>\n <Button\n variant=\"secondary\"\n size=\"icon\"\n className=\"size-8 hover:bg-red-500 hover:text-white\"\n onClick={() => handleToggleTool(tool.name, true)}\n >\n <MinusIcon size={18} />\n </Button>\n </div>\n </div>\n ))\n )}\n </div>\n </div>\n </CardContent>\n </Card>\n <Card className=\"transition-all duration-200 col-span-3\">\n <CardContent className=\"p-4\">\n <div className=\"flex-col\">\n <h4 className=\"text-sm font-medium mb-3 flex items-center gap-2\">\n <Wrench className=\"h-4 w-4\" />\n 未使用的工具 ({disabledTools.length})\n {isLoadingTools && (\n <span className=\"text-xs text-muted-foreground\">\n (加载中...)\n </span>\n )}\n </h4>\n <div className=\"flex-1 space-y-2\">\n {isLoadingTools ? (\n <div className=\"flex items-center justify-center py-8\">\n <div className=\"text-sm text-muted-foreground\">\n 加载工具列表中...\n </div>\n </div>\n ) : toolsError ? (\n <div className=\"flex flex-col items-center justify-center py-8 px-4\">\n <div className=\"text-sm text-red-500 mb-2\">\n {toolsError}\n </div>\n <Button variant=\"outline\" size=\"sm\" onClick={fetchTools}>\n 重试\n </Button>\n </div>\n ) : disabledTools.length === 0 ? (\n // 保持原有的空状态显示\n <div className=\"flex-1 flex flex-col items-center gap-4 py-20 px-4 bg-slate-50 rounded-md font-mono h-full\">\n <CoffeeIcon\n strokeWidth={1.5}\n size={48}\n className=\"text-muted-foreground\"\n />\n <span className=\"text-sm text-muted-foreground\">\n 全部工具都已经启用\n </span>\n </div>\n ) : (\n disabledTools.map((tool) => (\n <div\n key={tool.toolName}\n className=\"flex items-start justify-between p-4 bg-slate-50 rounded-md font-mono\"\n >\n <div className=\"text-md flex flex-col gap-2\">\n <div className=\"flex items-center gap-2 justify-start\">\n <Badge variant=\"secondary\" className=\"rounded-md\">\n {tool.serverName}\n </Badge>\n <span>{tool.toolName}</span>\n </div>\n <p className=\"text-sm text-muted-foreground\">\n {tool.description}\n </p>\n <div className=\"flex items-center gap-4\">\n <span className=\"text-sm text-muted-foreground\">\n <span className=\"text-muted-foreground\">\n 使用次数:\n </span>{\" \"}\n <span className=\"text-primary font-bold\">\n {tool.usageCount || 0}\n </span>\n </span>\n <span className=\"text-sm text-muted-foreground\">\n <span className=\"text-muted-foreground\">\n 最后使用:\n </span>{\" \"}\n <span className=\"text-primary font-bold\">\n {tool.lastUsedTime || \"-\"}\n </span>\n </span>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2 ml-4\">\n <Button\n variant=\"secondary\"\n size=\"icon\"\n className=\"size-8 hover:bg-green-500 hover:text-white\"\n onClick={() => handleToggleTool(tool.name, false)}\n >\n <PlusIcon className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n ))\n )}\n </div>\n </div>\n </CardContent>\n </Card>\n <div className=\"transition-all duration-200 gap-4 flex flex-col col-span-2\">\n <div className=\"flex flex-col gap-2\">\n <div className=\"flex items-center gap-2\">\n <AddMcpServerButton />\n <RestartButton />\n </div>\n <CozeWorkflowIntegration onToolAdded={refreshToolLists} />\n </div>\n {Object.entries(mcpServers || {}).map(\n ([mcpServerName, mcpServer]) => (\n <Card\n key={mcpServerName}\n className={\"transition-all duration-200\"}\n >\n <CardContent className=\"p-0\">\n <div className=\"p-4 pb-2\">\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-start gap-4 flex-1\">\n {/* <div className=\"mt-1\">{getStatusIcon(service.status)}</div> */}\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2 mb-2\">\n <h3 className=\"text-lg font-semibold\">\n {mcpServerName}\n </h3>\n </div>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2 ml-4\">\n <McpServerSettingButton\n mcpServerName={mcpServerName}\n mcpServer={mcpServer as MCPServerConfig}\n />\n <RemoveMcpServerButton\n mcpServerName={mcpServerName}\n onRemoveSuccess={handleRefreshData}\n disabled={isRefreshing}\n />\n </div>\n </div>\n </div>\n </CardContent>\n <CardFooter className=\"p-4 pt-2\">\n <Badge variant=\"outline\" className=\"text-xs\">\n {getMcpServerCommunicationType(mcpServer)}\n </Badge>\n </CardFooter>\n </Card>\n )\n )}\n </div>\n </div>\n\n {/* Coze 工具移除确认对话框 */}\n <AlertDialog\n open={cozeToolToRemove !== null}\n onOpenChange={(open) => !open && setCozeToolToRemove(null)}\n >\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>确认移除 Coze 工作流工具</AlertDialogTitle>\n <AlertDialogDescription>\n 移除后需要通过【工作流集成】重新添加并配置入参,确定要移除工具 \"\n {cozeToolToRemove}\" 吗?\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel onClick={handleCancelRemoveCozeTool}>\n 取消\n </AlertDialogCancel>\n <AlertDialogAction\n onClick={handleConfirmRemoveCozeTool}\n className=\"bg-destructive text-destructive-foreground hover:bg-destructive/90\"\n >\n 确认移除\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n\n {/* 参数配置对话框 */}\n {parameterConfigDialog.tool && (\n <WorkflowParameterConfigDialog\n open={parameterConfigDialog.open}\n onOpenChange={(open) =>\n setParameterConfigDialog((prev) => ({ ...prev, open }))\n }\n workflow={parameterConfigDialog.tool}\n onConfirm={handleParameterConfigConfirm}\n onCancel={handleParameterConfigCancel}\n title=\"配置工作流参数\"\n />\n )}\n\n {/* 工具调试对话框 */}\n <ToolDebugDialog\n open={debugDialog.open}\n onOpenChange={(open) => setDebugDialog((prev) => ({ ...prev, open }))}\n tool={debugDialog.tool || null}\n />\n </div>\n );\n}\n","export const QQIcon = ({ size = 24, color = \"currentColor\", ...props }) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 1024 1024\"\n fill=\"none\"\n stroke={color}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...props}\n >\n <path d=\"M980.79827 694.105946c-21.144216-122.796973-109.844757-203.250162-109.844757-203.250162 12.647784-111.477622-33.792-131.26573-33.792-131.26573C827.392 14.668108 530.985514 20.67373 524.730811 20.839784 518.476108 20.67373 222.01427 14.668108 212.300108 359.590054c0 0-46.467459 19.788108-33.819676 131.26573 0 0-88.700541 80.453189-109.817081 203.250162 0 0-11.291676 207.484541 101.403676 25.40627 0 0 25.350919 69.161514 71.790703 131.26573 0 0-83.082378 28.256865-75.997405 101.625081 0 0-2.87827 81.836973 177.401081 76.218811 0 0 126.699243-9.852541 164.753297-63.515676l16.605405 0 0.276757 0 16.633081 0c38.026378 53.635459 164.725622 63.515676 164.725622 63.515676 180.224 5.618162 177.401081-76.218811 177.401081-76.218811 7.029622-73.368216-75.997405-101.625081-75.997405-101.625081 46.439784-62.104216 71.790703-131.26573 71.790703-131.26573C992.034595 901.590486 980.79827 694.105946 980.79827 694.105946z\" />\n </svg>\n);\n","export const GithubIcon = ({ size = 24, color = \"currentColor\", ...props }) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 1024 1024\"\n fill=\"none\"\n stroke={color}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...props}\n >\n <path\n d=\"M0 524.992q0 166.016 95.488 298.496t247.488 185.504q6.016 0.992 10.016 0.992t6.496-1.504 4-3.008 2.016-4.992 0.512-4.992v-100.512q-36.992 4-66.016-0.512t-45.504-14.016-28.992-23.488-16.992-25.504-8.992-24-5.504-14.496q-8.992-15.008-27.008-27.488t-27.008-20-2.016-14.496q50.016-26.016 112.992 66.016 34.016 51.008 119.008 30.016 10.016-40.992 40-70.016Q293.984 736 237.984 670.976t-56-158.016q0-87.008 55.008-151.008-22.016-64.992 6.016-136.992 28.992-2.016 64.992 11.488t50.496 23.008 25.504 17.504q56.992-16 128.512-16t129.504 16q12.992-8.992 28.992-19.008t48.992-21.504 60.992-9.504q27.008 71.008 7.008 135.008 56 64 56 151.008 0 92.992-56.992 158.496t-172 85.504q43.008 43.008 43.008 104v128.992q0 0.992 0.992 3.008 0 6.016 0.512 8.992t4.512 6.016 12 3.008q152.992-52 250.496-185.504t97.504-300.512q0-104-40.512-199.008t-108.992-163.488-163.488-108.992T512.032 12.96 313.024 53.472 149.536 162.464t-108.992 163.488-40.512 199.008z\"\n p-id=\"4674\"\n />\n </svg>\n);\n","/**\n * useNPMInstall Hook - NPM 安装日志实时推送\n *\n * 功能:\n * - 管理 NPM 安装状态\n * - 订阅 WebSocket 安装事件\n * - 提供安装日志实时更新\n * - 支持安装操作触发\n */\n\nimport { webSocketManager } from \"@services/websocket\";\nimport { useCallback, useEffect, useState } from \"react\";\n\n/**\n * 安装日志接口\n */\nexport interface InstallLog {\n type: \"stdout\" | \"stderr\";\n message: string;\n timestamp: number;\n}\n\n/**\n * 安装状态接口\n */\nexport interface InstallStatus {\n status: \"idle\" | \"installing\" | \"completed\" | \"failed\";\n version?: string;\n installId?: string;\n logs: InstallLog[];\n error?: string;\n duration?: number;\n}\n\n/**\n * useNPMInstall Hook\n *\n * @returns 安装状态和操作方法\n */\nexport function useNPMInstall() {\n const [installStatus, setInstallStatus] = useState<InstallStatus>({\n status: \"idle\",\n logs: [],\n });\n\n useEffect(() => {\n // 订阅安装开始事件\n const unsubscribeStarted = webSocketManager.subscribe(\n \"data:npmInstallStarted\",\n (data) => {\n console.log(\"[useNPMInstall] 安装开始:\", data);\n setInstallStatus({\n status: \"installing\",\n version: data.version,\n installId: data.installId,\n logs: [],\n });\n }\n );\n\n // 订阅安装日志事件\n const unsubscribeLog = webSocketManager.subscribe(\n \"data:npmInstallLog\",\n (data) => {\n console.log(\"[useNPMInstall] 收到日志:\", data);\n setInstallStatus((prev) => {\n // 只处理当前安装任务的日志\n if (prev.installId === data.installId) {\n return {\n ...prev,\n logs: [\n ...prev.logs,\n {\n type: data.type,\n message: data.message,\n timestamp: data.timestamp,\n },\n ],\n };\n }\n return prev;\n });\n }\n );\n\n // 订阅安装完成事件\n const unsubscribeCompleted = webSocketManager.subscribe(\n \"data:npmInstallCompleted\",\n (data) => {\n console.log(\"[useNPMInstall] 安装完成:\", data);\n setInstallStatus((prev) => {\n // 只处理当前安装任务的完成事件\n if (prev.installId === data.installId) {\n return {\n ...prev,\n status: \"completed\",\n duration: data.duration,\n };\n }\n return prev;\n });\n }\n );\n\n // 订阅安装失败事件\n const unsubscribeFailed = webSocketManager.subscribe(\n \"data:npmInstallFailed\",\n (data) => {\n console.log(\"[useNPMInstall] 安装失败:\", data);\n setInstallStatus((prev) => {\n // 只处理当前安装任务的失败事件\n if (prev.installId === data.installId) {\n return {\n ...prev,\n status: \"failed\",\n error: data.error,\n duration: data.duration,\n };\n }\n return prev;\n });\n }\n );\n\n // 清理函数:取消所有事件订阅\n return () => {\n unsubscribeStarted();\n unsubscribeLog();\n unsubscribeCompleted();\n unsubscribeFailed();\n };\n }, []);\n\n /**\n * 开始安装指定版本\n *\n * @param version 要安装的版本号\n * @returns Promise<安装结果>\n */\n const startInstall = useCallback(async (version: string) => {\n try {\n console.log(\"[useNPMInstall] 开始安装版本:\", version);\n\n const response = await fetch(\"/api/update\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ version }),\n });\n\n const result = await response.json();\n\n if (!result.success) {\n throw new Error(result.error?.message || \"安装请求失败\");\n }\n\n console.log(\"[useNPMInstall] 安装请求已接受:\", result);\n return result;\n } catch (error) {\n console.error(\"[useNPMInstall] 安装请求失败:\", error);\n\n // 更新状态为失败\n setInstallStatus((prev) => ({\n ...prev,\n status: \"failed\",\n error: error instanceof Error ? error.message : \"未知错误\",\n }));\n\n throw error;\n }\n }, []);\n\n /**\n * 清除安装状态\n */\n const clearStatus = useCallback(() => {\n console.log(\"[useNPMInstall] 清除安装状态\");\n setInstallStatus({\n status: \"idle\",\n logs: [],\n });\n }, []);\n\n /**\n * 获取状态描述文本\n */\n const getStatusText = useCallback(() => {\n switch (installStatus.status) {\n case \"installing\":\n return `正在安装 xiaozhi-client@${installStatus.version}...`;\n case \"completed\":\n return \"安装完成!\";\n case \"failed\":\n return `安装失败: ${installStatus.error}`;\n default:\n return \"\";\n }\n }, [installStatus]);\n\n /**\n * 获取状态颜色类名\n */\n const getStatusColor = useCallback(() => {\n switch (installStatus.status) {\n case \"installing\":\n return \"text-blue-600\";\n case \"completed\":\n return \"text-green-600\";\n case \"failed\":\n return \"text-red-600\";\n default:\n return \"text-gray-600\";\n }\n }, [installStatus]);\n\n /**\n * 检查是否正在安装\n */\n const isInstalling = useCallback(() => {\n return installStatus.status === \"installing\";\n }, [installStatus.status]);\n\n /**\n * 检查是否可以关闭对话框\n */\n const canCloseDialog = useCallback(() => {\n return installStatus.status !== \"installing\";\n }, [installStatus.status]);\n\n return {\n installStatus,\n startInstall,\n clearStatus,\n getStatusText,\n getStatusColor,\n isInstalling,\n canCloseDialog,\n };\n}\n","import { cn } from \"@/lib/utils\";\nimport * as React from \"react\";\n\ninterface ProgressProps extends React.HTMLAttributes<HTMLDivElement> {\n value?: number;\n status?: \"installing\" | \"completed\" | \"failed\" | \"idle\";\n}\n\nconst Progress = React.forwardRef<HTMLDivElement, ProgressProps>(\n ({ className, value, status = \"idle\", ...props }, ref) => {\n const getProgressColor = () => {\n switch (status) {\n case \"installing\":\n return \"bg-blue-500\";\n case \"completed\":\n return \"bg-green-500\";\n case \"failed\":\n return \"bg-red-500\";\n default:\n return \"bg-gray-300\";\n }\n };\n\n return (\n <div\n ref={ref}\n className={cn(\n \"relative h-4 w-full overflow-hidden rounded-full bg-gray-200 dark:bg-gray-800\",\n className\n )}\n {...props}\n >\n <div\n className={cn(\n \"h-full transition-all duration-300 ease-in-out\",\n getProgressColor()\n )}\n style={{ width: `${value || 0}%` }}\n />\n </div>\n );\n }\n);\nProgress.displayName = \"Progress\";\n\nexport { Progress };\n","/**\n * InstallLogDialog 组件 - NPM 安装日志实时显示对话框\n *\n * 功能:\n * - 实时显示 NPM 安装日志\n * - 显示安装状态和进度\n * - 支持自动滚动到最新日志\n * - 安装完成后提供操作选项\n */\n\nimport { useNPMInstall } from \"@hooks/useNPMInstall\";\nimport { Alert, AlertDescription } from \"@ui/alert\";\nimport { Badge } from \"@ui/badge\";\nimport { Button } from \"@ui/button\";\nimport {\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from \"@ui/dialog\";\nimport { Progress } from \"@ui/progress\";\nimport { ScrollArea } from \"@ui/scroll-area\";\nimport {\n CheckCircleIcon,\n ChevronDownIcon,\n ChevronUpIcon,\n TerminalIcon,\n XCircleIcon,\n} from \"lucide-react\";\nimport type React from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { toast } from \"sonner\";\n\ninterface InstallLogDialogProps {\n isOpen: boolean;\n onClose: () => void;\n version: string;\n}\n\nexport function InstallLogDialog({\n isOpen,\n onClose,\n version,\n}: InstallLogDialogProps) {\n const {\n installStatus,\n startInstall,\n clearStatus,\n isInstalling,\n canCloseDialog,\n } = useNPMInstall();\n\n const logContainerRef = useRef<HTMLDivElement>(null);\n const [showDetails, setShowDetails] = useState(false);\n\n // 对话框打开时开始安装\n useEffect(() => {\n if (isOpen && version) {\n console.log(\"[InstallLogDialog] 对话框打开,开始安装版本:\", version);\n clearStatus();\n startInstall(version).catch((error) => {\n console.error(\"[InstallLogDialog] 启动安装失败:\", error);\n });\n }\n }, [isOpen, version, startInstall, clearStatus]);\n\n // 自动滚动到最新日志\n useEffect(() => {\n const timer = setTimeout(() => {\n if (logContainerRef.current) {\n logContainerRef.current.scrollTop =\n logContainerRef.current.scrollHeight;\n }\n }, 100);\n return () => clearTimeout(timer);\n });\n\n // 计算进度条进度\n const getProgressValue = () => {\n switch (installStatus.status) {\n case \"idle\":\n return 0;\n case \"installing\":\n // 基于日志数量估算进度,最多到90%\n return Math.min(90, installStatus.logs.length * 2);\n case \"completed\":\n return 100;\n case \"failed\":\n return 100;\n default:\n return 0;\n }\n };\n\n // 获取简洁的状态描述\n const getSimpleStatusText = () => {\n switch (installStatus.status) {\n case \"installing\":\n return \"正在安装...\";\n case \"completed\":\n return \"安装完成\";\n case \"failed\":\n return \"安装失败\";\n default:\n return \"准备安装\";\n }\n };\n\n // 获取状态图标\n const getStatusIcon = () => {\n switch (installStatus.status) {\n case \"installing\":\n return <TerminalIcon className=\"h-4 w-4 animate-pulse\" />;\n case \"completed\":\n return <CheckCircleIcon className=\"h-4 w-4 text-green-600\" />;\n case \"failed\":\n return <XCircleIcon className=\"h-4 w-4 text-red-600\" />;\n default:\n return null;\n }\n };\n\n // 获取状态徽章样式\n const getStatusBadgeVariant = () => {\n switch (installStatus.status) {\n case \"installing\":\n return \"default\";\n case \"completed\":\n return \"secondary\";\n case \"failed\":\n return \"destructive\";\n default:\n return \"outline\";\n }\n };\n\n // 格式化日志消息\n const formatLogMessage = (message: string) => {\n // 简单清理日志消息,移除常见的 ANSI 控制序列\n let cleanedMessage = message;\n\n // 移除常见的 ANSI 转义序列\n const ansiPatterns = [\n /\\[0m/g, // 重置\n /\\[31m/g, // 红色\n /\\[32m/g, // 绿色\n /\\[33m/g, // 黄色\n /\\[34m/g, // 蓝色\n /\\[35m/g, // 紫色\n /\\[36m/g, // 青色\n /\\[37m/g, // 白色\n /\\[90m/g, // 亮黑(灰色)\n /\\[91m/g, // 亮红\n /\\[92m/g, // 亮绿\n /\\[93m/g, // 亮黄\n /\\[94m/g, // 亮蓝\n /\\[95m/g, // 亮紫\n /\\[96m/g, // 亮青\n /\\[97m/g, // 亮白\n ];\n\n for (const pattern of ansiPatterns) {\n cleanedMessage = cleanedMessage.replace(pattern, \"\");\n }\n\n // 分割成行并去除空行\n return cleanedMessage\n .split(\"\\n\")\n .filter((line) => line.trim())\n .map((line, index) => (\n <div key={`${line.slice(0, 20)}-${index}`} className=\"leading-relaxed\">\n {line}\n </div>\n ));\n };\n\n // 处理关闭操作\n const handleClose = () => {\n if (canCloseDialog()) {\n clearStatus();\n onClose();\n } else {\n toast.error(\"安装过程中无法关闭对话框,请等待安装完成\");\n }\n };\n\n // 处理键盘事件\n const handleKeyDown = (event: React.KeyboardEvent) => {\n if (event.key === \"Escape\" && canCloseDialog()) {\n handleClose();\n }\n };\n\n // 切换详情显示\n const toggleDetails = () => {\n setShowDetails(!showDetails);\n };\n\n return (\n <Dialog open={isOpen} onOpenChange={handleClose}>\n <DialogContent\n className=\"max-w-2xl max-h-[80vh] flex flex-col\"\n onKeyDown={handleKeyDown}\n >\n <DialogHeader className=\"flex flex-row items-center justify-between space-y-0 pb-4\">\n <div className=\"flex items-center gap-3\">\n <DialogTitle className=\"text-lg font-semibold\">\n 正在安装\n </DialogTitle>\n {installStatus.status !== \"idle\" && (\n <Badge\n variant={getStatusBadgeVariant()}\n className=\"flex items-center gap-1\"\n >\n {getStatusIcon()}\n {getSimpleStatusText()}\n </Badge>\n )}\n </div>\n </DialogHeader>\n\n {/* 简洁的进度显示 */}\n <div className=\"space-y-4\">\n {/* 进度条 */}\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"font-medium\">安装进度</span>\n {installStatus.version && (\n <Badge variant=\"outline\" className=\"text-xs\">\n v{installStatus.version}\n </Badge>\n )}\n </div>\n <Progress\n value={getProgressValue()}\n status={installStatus.status}\n className=\"w-full h-2\"\n />\n <div className=\"flex items-center justify-between text-xs text-muted-foreground\">\n <span>{getSimpleStatusText()}</span>\n {installStatus.duration && (\n <span>耗时: {(installStatus.duration / 1000).toFixed(1)}s</span>\n )}\n </div>\n </div>\n\n {/* 状态描述 */}\n {installStatus.status === \"failed\" && (\n <Alert variant=\"destructive\">\n <AlertDescription>\n 安装失败,请查看详细日志了解具体原因。\n </AlertDescription>\n </Alert>\n )}\n\n {/* 详细日志区域(可折叠) */}\n <div>\n <button\n type=\"button\"\n onClick={toggleDetails}\n className=\"flex w-full items-center justify-between h-auto p-0 gap-0 hover:bg-none bg-none text-sm mb-2\"\n >\n <h4 className=\"font-medium\">安装日志</h4>\n <div className=\"flex items-center gap-1\">\n {showDetails ? (\n <>\n 收起 <ChevronUpIcon className=\"h-4 w-4\" />\n </>\n ) : (\n <>\n 展开 <ChevronDownIcon className=\"h-4 w-4\" />\n </>\n )}\n </div>\n </button>\n {showDetails && (\n <ScrollArea\n ref={logContainerRef}\n className=\"h-[300px] w-full rounded-md border bg-background\"\n >\n <div className=\"p-4 font-mono text-xs\">\n {installStatus.logs.length === 0 ? (\n <div className=\"text-muted-foreground flex items-center gap-2\">\n <TerminalIcon className=\"h-4 w-4 animate-pulse\" />\n 等待日志输出...\n </div>\n ) : (\n <div className=\"space-y-1\">\n {installStatus.logs.map((log) => (\n <div\n key={`${log.timestamp}-${log.message.slice(0, 50)}`}\n className={`${\n log.type === \"stderr\"\n ? \"text-orange-600\"\n : \"text-foreground\"\n } break-words`}\n >\n {formatLogMessage(log.message)}\n </div>\n ))}\n </div>\n )}\n </div>\n </ScrollArea>\n )}\n </div>\n </div>\n\n {/* 底部操作栏 */}\n <DialogFooter className=\"flex items-center justify-between pt-4 border-t\">\n <div className=\"flex gap-2\">\n {installStatus.status === \"completed\" && (\n <Button\n variant=\"outline\"\n onClick={() => window.location.reload()}\n className=\"flex items-center gap-2\"\n >\n <CheckCircleIcon className=\"h-4 w-4\" />\n 重启应用\n </Button>\n )}\n\n <Button\n onClick={handleClose}\n disabled={!canCloseDialog()}\n variant={\n installStatus.status === \"failed\" ? \"destructive\" : \"default\"\n }\n >\n {isInstalling()\n ? \"安装中...\"\n : installStatus.status === \"completed\"\n ? \"完成\"\n : installStatus.status === \"failed\"\n ? \"关闭\"\n : \"关闭\"}\n </Button>\n </div>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n","/**\n * VersionUpgradeDialog 组件 - 版本升级选择对话框\n *\n * 功能:\n * - 提供版本选择下拉菜单\n * - 触发版本安装\n * - 集成安装日志显示\n */\n\nimport { Button } from \"@/components/ui/button\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from \"@/components/ui/dialog\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@/components/ui/select\";\nimport { useNPMInstall } from \"@/hooks/useNPMInstall\";\nimport { apiClient } from \"@/services/api\";\nimport { Alert, AlertDescription, AlertTitle } from \"@ui/alert\";\nimport { DownloadIcon, ShieldAlertIcon } from \"lucide-react\";\nimport { useCallback, useEffect, useState } from \"react\";\nimport semver from \"semver\";\nimport { InstallLogDialog } from \"./InstallLogDialog\";\n\ninterface VersionUpgradeDialogProps {\n children?: React.ReactNode;\n defaultSelectedVersion?: string;\n}\n\n// 版本类型选项\nconst VERSION_TYPES = [\n { value: \"stable\", label: \"正式版\" },\n { value: \"rc\", label: \"预览版\" },\n { value: \"beta\", label: \"测试版\" },\n { value: \"all\", label: \"全部版本\" },\n] as const;\n\ntype VersionType = (typeof VERSION_TYPES)[number][\"value\"];\n\nexport function VersionUpgradeDialog({\n children,\n defaultSelectedVersion,\n}: VersionUpgradeDialogProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [selectedVersion, setSelectedVersion] = useState<string>(\"\");\n const [selectedVersionType, setSelectedVersionType] =\n useState<VersionType>(\"stable\");\n const [showInstallDialog, setShowInstallDialog] = useState(false);\n const [availableVersions, setAvailableVersions] = useState<\n { value: string; label: string }[]\n >([]);\n const [isLoadingVersions, setIsLoadingVersions] = useState(false);\n\n const { startInstall } = useNPMInstall();\n\n // 获取可用版本列表\n const fetchAvailableVersions = useCallback(\n async (type: VersionType) => {\n try {\n setIsLoadingVersions(true);\n const response = await apiClient.getAvailableVersions(type);\n const versions = response.versions.map((version) => ({\n value: version,\n label: `v${version}`,\n }));\n setAvailableVersions(versions);\n console.log(\n `[VersionUpgradeDialog] 获取到 ${response.total} 个${type}版本`\n );\n if (\n defaultSelectedVersion &&\n response.versions.includes(defaultSelectedVersion || \"\")\n ) {\n setSelectedVersion(defaultSelectedVersion || \"\");\n }\n } catch (error) {\n console.error(\"[VersionUpgradeDialog] 获取版本列表失败:\", error);\n // 如果获取失败,使用默认版本列表\n const defaultVersions = [] as { value: string; label: string }[];\n setAvailableVersions(defaultVersions);\n } finally {\n setIsLoadingVersions(false);\n }\n },\n [defaultSelectedVersion]\n );\n\n // 当对话框打开时获取版本列表\n useEffect(() => {\n if (isOpen) {\n fetchAvailableVersions(selectedVersionType);\n }\n }, [isOpen, selectedVersionType, fetchAvailableVersions]);\n\n // 处理版本类型选择\n const handleVersionTypeSelect = (value: VersionType) => {\n setSelectedVersionType(value);\n setSelectedVersion(\"\"); // 清空之前选择的版本\n };\n\n // 处理版本选择\n const handleVersionSelect = (value: string) => {\n setSelectedVersion(value);\n };\n\n // 处理确认安装\n const handleConfirmInstall = async () => {\n if (!selectedVersion) {\n return;\n }\n\n try {\n console.log(\"[VersionUpgradeDialog] 开始安装版本:\", selectedVersion);\n\n // 关闭版本选择对话框\n setIsOpen(false);\n\n // 显示安装日志对话框\n setShowInstallDialog(true);\n\n // 开始安装\n await startInstall(selectedVersion);\n } catch (error) {\n console.error(\"[VersionUpgradeDialog] 安装失败:\", error);\n // 如果安装失败,关闭安装日志对话框\n setShowInstallDialog(false);\n }\n };\n\n // 处理安装对话框关闭\n const handleInstallDialogClose = () => {\n setShowInstallDialog(false);\n setSelectedVersion(\"\");\n };\n\n // 处理对话框关闭\n const handleDialogClose = (open: boolean) => {\n if (!open) {\n setSelectedVersion(\"\");\n setSelectedVersionType(\"stable\"); // 重置为默认选择\n }\n setIsOpen(open);\n };\n\n return (\n <>\n <Dialog open={isOpen} onOpenChange={handleDialogClose}>\n <DialogTrigger asChild>\n {children || (\n <Button className=\"flex items-center gap-2\">\n <DownloadIcon className=\"h-4 w-4\" />\n 升级版本\n </Button>\n )}\n </DialogTrigger>\n <DialogContent className=\"sm:max-w-md\">\n <DialogHeader>\n <DialogTitle>选择安装版本</DialogTitle>\n <DialogDescription>\n 请选择要安装的 xiaozhi-client 版本\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-4 py-4\">\n {/* 版本选择 */}\n <div className=\"space-y-2\">\n <label htmlFor=\"version-select\" className=\"text-sm font-medium\">\n 版本选择\n </label>\n <div className=\"flex items-center gap-2\">\n <Select\n value={selectedVersionType}\n onValueChange={handleVersionTypeSelect}\n >\n <SelectTrigger id=\"version-type-select\" className=\"w-[150px]\">\n <SelectValue placeholder=\"请选择版本类型\" />\n </SelectTrigger>\n <SelectContent>\n {VERSION_TYPES.map((type) => (\n <SelectItem key={type.value} value={type.value}>\n {type.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Select\n value={selectedVersion}\n onValueChange={handleVersionSelect}\n disabled={isLoadingVersions}\n >\n <SelectTrigger id=\"version-select\">\n <SelectValue\n placeholder={\n isLoadingVersions ? \"正在获取版本列表...\" : \"请选择版本\"\n }\n />\n </SelectTrigger>\n <SelectContent>\n {isLoadingVersions ? (\n <SelectItem value=\"loading\" disabled>\n 正在获取版本列表...\n </SelectItem>\n ) : availableVersions.length === 0 ? (\n <SelectItem value=\"empty\" disabled>\n 暂无可用版本\n </SelectItem>\n ) : (\n availableVersions.map((version) => (\n <SelectItem key={version.value} value={version.value}>\n {version.label}\n </SelectItem>\n ))\n )}\n </SelectContent>\n </Select>\n </div>\n {!isLoadingVersions && availableVersions.length === 0 && (\n <p className=\"text-xs text-muted-foreground\">\n 当前版本类型暂无可用版本\n </p>\n )}\n {selectedVersion && semver.lt(selectedVersion, \"1.8.0\") && (\n <Alert variant=\"destructive\">\n <ShieldAlertIcon size={18} />\n <AlertTitle>重要提醒</AlertTitle>\n <AlertDescription>\n 指定版本低于1.8.0,安装后无法再使用Web界面重装,需手动通过命令操作,请谨慎操作!\n </AlertDescription>\n </Alert>\n )}\n </div>\n </div>\n\n <div className=\"flex justify-end gap-2\">\n <Button variant=\"outline\" onClick={() => setIsOpen(false)}>\n 取消\n </Button>\n <Button\n onClick={handleConfirmInstall}\n disabled={!selectedVersion || isLoadingVersions}\n >\n 确定安装\n </Button>\n </div>\n </DialogContent>\n </Dialog>\n\n {/* 安装日志对话框 */}\n <InstallLogDialog\n isOpen={showInstallDialog}\n onClose={handleInstallDialogClose}\n version={selectedVersion}\n />\n </>\n );\n}\n","import { Badge } from \"@/components/ui/badge\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport type { VersionInfo } from \"@/services/api\";\nimport { apiClient } from \"@/services/api\";\nimport { Button } from \"@ui/button\";\nimport { CopyIcon, InfoIcon, RocketIcon } from \"lucide-react\";\nimport { useEffect, useState } from \"react\";\nimport { VersionUpgradeDialog } from \"./VersionUpgradeDialog\";\n\ninterface VersionDisplayProps {\n className?: string;\n}\n\ninterface LatestVersionInfo {\n currentVersion: string;\n latestVersion: string | null;\n hasUpdate: boolean;\n error?: string;\n}\n\nexport function VersionDisplay({ className }: VersionDisplayProps) {\n const [versionInfo, setVersionInfo] = useState<VersionInfo | null>(null);\n const [latestVersionInfo, setLatestVersionInfo] =\n useState<LatestVersionInfo | null>(null);\n const [loading, setLoading] = useState(true);\n const [checkingUpdate, setCheckingUpdate] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [copied, setCopied] = useState(false);\n\n useEffect(() => {\n const fetchVersion = async () => {\n try {\n setLoading(true);\n setError(null);\n const info = await apiClient.getVersion();\n setVersionInfo(info);\n } catch (err) {\n setError(err instanceof Error ? err.message : \"获取版本信息失败\");\n console.error(\"获取版本信息失败:\", err);\n } finally {\n setLoading(false);\n }\n };\n\n fetchVersion();\n }, []);\n\n useEffect(() => {\n const checkForUpdates = async () => {\n try {\n setCheckingUpdate(true);\n const updateInfo = await apiClient.getLatestVersion();\n setLatestVersionInfo(updateInfo);\n } catch (err) {\n console.error(\"检查更新失败:\", err);\n // 设置默认值,不显示错误给用户\n setLatestVersionInfo({\n currentVersion: versionInfo?.version || \"unknown\",\n latestVersion: null,\n hasUpdate: false,\n error: err instanceof Error ? err.message : \"检查更新失败\",\n });\n } finally {\n setCheckingUpdate(false);\n }\n };\n\n // 只有在获取到版本信息后才检查更新\n if (versionInfo) {\n checkForUpdates();\n }\n }, [versionInfo]);\n\n const handleCopyVersion = async () => {\n if (versionInfo?.version) {\n try {\n await navigator.clipboard.writeText(versionInfo.version);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch (err) {\n console.error(\"复制版本号失败:\", err);\n }\n }\n };\n\n if (loading) {\n return (\n <Badge variant=\"outline\" className={className}>\n <span className=\"text-xs\">加载中...</span>\n </Badge>\n );\n }\n\n if (error || !versionInfo) {\n return (\n <Badge variant=\"outline\" className={className}>\n <span className=\"text-xs text-muted-foreground\">版本未知</span>\n </Badge>\n );\n }\n\n const tooltipContent = (\n <div className=\"space-y-1\">\n <div className=\"flex items-center gap-2\">\n <InfoIcon className=\"h-3 w-3\" />\n <span className=\"font-semibold\">版本详情</span>\n </div>\n <div className=\"text-xs space-y-0.5\">\n <div>\n <strong>名称:</strong> {versionInfo.name}\n </div>\n <div>\n <strong>版本:</strong> {versionInfo.version}\n </div>\n {latestVersionInfo && (\n <>\n <div>\n <strong>最新版本:</strong>{\" \"}\n {latestVersionInfo.latestVersion || \"未知\"}\n </div>\n <div>\n <strong>状态:</strong>\n {checkingUpdate\n ? \"检查中...\"\n : latestVersionInfo.hasUpdate\n ? \"有新版本\"\n : \"已是最新\"}\n </div>\n </>\n )}\n <div>\n <strong>描述:</strong> {versionInfo.description}\n </div>\n <div>\n <strong>作者:</strong> {versionInfo.author}\n </div>\n </div>\n <div className=\"pt-1 border-t\">\n <button\n type=\"button\"\n onClick={handleCopyVersion}\n className=\"text-xs text-primary hover:underline flex items-center gap-1\"\n >\n <CopyIcon className=\"h-3 w-3\" />\n {copied ? \"已复制!\" : \"复制版本号\"}\n </button>\n </div>\n </div>\n );\n\n // 决定显示的按钮文案和图标\n const getUpgradeButton = () => {\n if (checkingUpdate) return null;\n\n if (latestVersionInfo?.hasUpdate && latestVersionInfo.latestVersion) {\n return (\n <VersionUpgradeDialog\n defaultSelectedVersion={latestVersionInfo.latestVersion}\n >\n <Button variant=\"link\" className=\"p-0 gap-1\">\n <RocketIcon />\n 升级版本\n </Button>\n </VersionUpgradeDialog>\n );\n }\n\n return (\n <VersionUpgradeDialog defaultSelectedVersion={versionInfo.version}>\n <Button variant=\"link\" className=\"p-0 gap-1\">\n 切换版本\n </Button>\n </VersionUpgradeDialog>\n );\n };\n\n return (\n <TooltipProvider>\n <div className=\"flex items-center gap-2\">\n {getUpgradeButton()}\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"text-sm cursor-help\">v{versionInfo.version}</span>\n </TooltipTrigger>\n <TooltipContent>{tooltipContent}</TooltipContent>\n </Tooltip>\n </div>\n </TooltipProvider>\n );\n}\n","import { GithubIcon, QQIcon } from \"@/components/icons\";\nimport { Separator } from \"@/components/ui/separator\";\nimport { SidebarTrigger } from \"@/components/ui/sidebar\";\nimport { VersionDisplay } from \"./VersionDisplay\";\n\nexport function SiteHeader({ title }: { title: string }) {\n return (\n <header className=\"group-has-data-[collapsible=icon]/sidebar-wrapper:h-12 flex h-12 shrink-0 items-center gap-2 border-b transition-[width,height] ease-linear pr-4\">\n <div className=\"flex w-full items-center gap-2 px-4 box-border\">\n <SidebarTrigger className=\"-ml-1\" />\n <Separator\n orientation=\"vertical\"\n className=\"mx-2 data-[orientation=vertical]:h-4\"\n />\n <h1 className=\"text-base font-medium\">{title}</h1>\n </div>\n <div className=\"flex w-full justify-end items-center gap-4 box-border\">\n <VersionDisplay />\n <a\n href=\"https://qun.qq.com/universal-share/share?ac=1&authKey=c08PvS2zvAF1NN%2F%2BuaOi0ze1AElTIsvFBLwbWUMFc2ixjaZYxqZTUQHzipwd8Kka&busi_data=eyJncm91cENvZGUiOiIxMDU0ODg4NDczIiwidG9rZW4iOiJuSmJUN2cyUEVkNEQ5WXovM3RQbFVNcDluMGVibUNZTUQvL1RuQnFJRjBkZmRZQnRBRTdwU0szL3V2Y0dLc1ZmIiwidWluIjoiMzkxMTcyMDYwMCJ9&data=9cH6_zEC-sN3xYlwzKEWiYF71RLY9CId5taN-gy6XZo7axSlSWDpd1Ojui5hYMQKIgEJYSPw59XYgF5vH2wLog&svctype=4&tempid=h5_group_info\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n <QQIcon size={24} className=\"text-slate-800\" fill=\"currentColor\" />\n </a>\n <a\n href=\"https://github.com/shenjingnan/xiaozhi-client\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n <GithubIcon\n size={24}\n className=\"text-slate-800\"\n fill=\"currentColor\"\n />\n </a>\n </div>\n </header>\n );\n}\n","/**\n * 统一的网络服务管理器\n * 整合 HTTP API 客户端和 WebSocket 管理器\n */\n\nimport type { AppConfig, ClientStatus } from \"@/types/index\";\nimport { type ApiClient, apiClient } from \"./api\";\nimport {\n type ConnectionState,\n type WebSocketManager,\n webSocketManager,\n} from \"./websocket\";\n\n/**\n * 网络服务管理器类\n */\nexport class NetworkService {\n private apiClient: ApiClient;\n private webSocketManager: WebSocketManager;\n private initialized = false;\n\n constructor() {\n this.apiClient = apiClient;\n this.webSocketManager = webSocketManager;\n }\n\n /**\n * 初始化网络服务\n */\n async initialize(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n console.log(\"[NetworkService] 初始化网络服务\");\n\n // 启动 WebSocket 连接\n this.webSocketManager.connect();\n\n this.initialized = true;\n console.log(\"[NetworkService] 网络服务初始化完成\");\n }\n\n /**\n * 销毁网络服务\n */\n destroy(): void {\n console.log(\"[NetworkService] 销毁网络服务\");\n this.webSocketManager.disconnect();\n this.initialized = false;\n }\n\n // ==================== HTTP API 方法 ====================\n\n /**\n * 获取配置 (HTTP)\n */\n async getConfig(): Promise<AppConfig> {\n return this.apiClient.getConfig();\n }\n\n /**\n * 更新配置 (HTTP)\n */\n async updateConfig(config: AppConfig): Promise<void> {\n return this.apiClient.updateConfig(config);\n }\n\n /**\n * 获取状态 (HTTP)\n */\n async getStatus(): Promise<any> {\n return this.apiClient.getStatus();\n }\n\n /**\n * 获取客户端状态 (HTTP)\n */\n async getClientStatus(): Promise<ClientStatus> {\n return this.apiClient.getClientStatus();\n }\n\n /**\n * 重启服务 (HTTP)\n */\n async restartService(): Promise<void> {\n return this.apiClient.restartService();\n }\n\n /**\n * 停止服务 (HTTP)\n */\n async stopService(): Promise<void> {\n return this.apiClient.stopService();\n }\n\n /**\n * 启动服务 (HTTP)\n */\n async startService(): Promise<void> {\n return this.apiClient.startService();\n }\n\n /**\n * 获取服务状态 (HTTP)\n */\n async getServiceStatus(): Promise<any> {\n return this.apiClient.getServiceStatus();\n }\n\n /**\n * 获取服务健康状态 (HTTP)\n */\n async getServiceHealth(): Promise<any> {\n return this.apiClient.getServiceHealth();\n }\n\n /**\n * 获取 MCP 端点 (HTTP)\n */\n async getMcpEndpoint(): Promise<string> {\n return this.apiClient.getMcpEndpoint();\n }\n\n /**\n * 获取 MCP 端点列表 (HTTP)\n */\n async getMcpEndpoints(): Promise<string[]> {\n return this.apiClient.getMcpEndpoints();\n }\n\n /**\n * 获取 MCP 服务配置 (HTTP)\n */\n async getMcpServers(): Promise<Record<string, any>> {\n return this.apiClient.getMcpServers();\n }\n\n /**\n * 获取连接配置 (HTTP)\n */\n async getConnectionConfig(): Promise<any> {\n return this.apiClient.getConnectionConfig();\n }\n\n /**\n * 重新加载配置 (HTTP)\n */\n async reloadConfig(): Promise<AppConfig> {\n return this.apiClient.reloadConfig();\n }\n\n /**\n * 获取配置文件路径 (HTTP)\n */\n async getConfigPath(): Promise<string> {\n return this.apiClient.getConfigPath();\n }\n\n /**\n * 检查配置是否存在 (HTTP)\n */\n async checkConfigExists(): Promise<boolean> {\n return this.apiClient.checkConfigExists();\n }\n\n /**\n * 获取重启状态 (HTTP)\n */\n async getRestartStatus(): Promise<any> {\n return this.apiClient.getRestartStatus();\n }\n\n /**\n * 检查客户端是否连接 (HTTP)\n */\n async checkClientConnected(): Promise<boolean> {\n return this.apiClient.checkClientConnected();\n }\n\n /**\n * 获取最后心跳时间 (HTTP)\n */\n async getLastHeartbeat(): Promise<number | null> {\n return this.apiClient.getLastHeartbeat();\n }\n\n /**\n * 获取活跃的 MCP 服务器列表 (HTTP)\n */\n async getActiveMCPServers(): Promise<string[]> {\n return this.apiClient.getActiveMCPServers();\n }\n\n /**\n * 更新客户端状态 (HTTP)\n */\n async updateClientStatus(status: Partial<ClientStatus>): Promise<void> {\n return this.apiClient.updateClientStatus(status);\n }\n\n /**\n * 设置活跃的 MCP 服务器列表 (HTTP)\n */\n async setActiveMCPServers(servers: string[]): Promise<void> {\n return this.apiClient.setActiveMCPServers(servers);\n }\n\n /**\n * 重置状态 (HTTP)\n */\n async resetStatus(): Promise<void> {\n return this.apiClient.resetStatus();\n }\n\n // ==================== WebSocket 方法 ====================\n\n /**\n * 获取 WebSocket 连接状态\n */\n getWebSocketState(): ConnectionState {\n return this.webSocketManager.getState();\n }\n\n /**\n * 检查 WebSocket 是否已连接\n */\n isWebSocketConnected(): boolean {\n return this.webSocketManager.isConnected();\n }\n\n /**\n * 设置 WebSocket URL\n */\n setWebSocketUrl(url: string): void {\n this.webSocketManager.setUrl(url);\n }\n\n /**\n * 监听 WebSocket 事件\n */\n onWebSocketEvent<\n K extends keyof import(\"./websocket\").WebSocketEventListeners,\n >(\n event: K,\n listener: import(\"./websocket\").WebSocketEventListeners[K]\n ): void {\n this.webSocketManager.on(event, listener);\n }\n\n /**\n * 移除 WebSocket 事件监听器\n */\n offWebSocketEvent<\n K extends keyof import(\"./websocket\").WebSocketEventListeners,\n >(event: K): void {\n this.webSocketManager.off(event);\n }\n\n /**\n * 重新连接 WebSocket\n */\n reconnectWebSocket(): void {\n this.webSocketManager.disconnect();\n setTimeout(() => {\n this.webSocketManager.connect();\n }, 1000);\n }\n\n // ==================== 便捷方法 ====================\n\n /**\n * 获取完整的应用状态 (HTTP + WebSocket)\n */\n async getFullAppState(): Promise<{\n config: AppConfig;\n status: any;\n webSocketConnected: boolean;\n }> {\n const [config, status] = await Promise.all([\n this.getConfig(),\n this.getStatus(),\n ]);\n\n return {\n config,\n status,\n webSocketConnected: this.isWebSocketConnected(),\n };\n }\n\n /**\n * 更新配置并等待 WebSocket 通知 (混合模式)\n */\n async updateConfigWithNotification(\n config: AppConfig,\n timeout = 5000\n ): Promise<void> {\n // 设置 WebSocket 监听器等待配置更新通知\n return new Promise((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n this.webSocketManager.off(\"configUpdate\");\n reject(new Error(\"等待配置更新通知超时\"));\n }, timeout);\n\n this.webSocketManager.on(\"configUpdate\", () => {\n clearTimeout(timeoutId);\n this.webSocketManager.off(\"configUpdate\");\n resolve();\n });\n\n // 通过 HTTP API 更新配置\n this.updateConfig(config).catch((error) => {\n clearTimeout(timeoutId);\n this.webSocketManager.off(\"configUpdate\");\n reject(error);\n });\n });\n }\n\n /**\n * 重启服务并等待状态通知 (混合模式)\n */\n async restartServiceWithNotification(timeout = 30000): Promise<void> {\n return new Promise((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n this.webSocketManager.off(\"restartStatus\");\n reject(new Error(\"等待重启状态通知超时\"));\n }, timeout);\n\n this.webSocketManager.on(\"restartStatus\", (status) => {\n if (status.status === \"completed\") {\n clearTimeout(timeoutId);\n this.webSocketManager.off(\"restartStatus\");\n resolve();\n } else if (status.status === \"failed\") {\n clearTimeout(timeoutId);\n this.webSocketManager.off(\"restartStatus\");\n reject(new Error(status.error || \"服务重启失败\"));\n }\n });\n\n // 通过 HTTP API 重启服务\n this.restartService().catch((error) => {\n clearTimeout(timeoutId);\n this.webSocketManager.off(\"restartStatus\");\n reject(error);\n });\n });\n }\n}\n\n// 创建默认的网络服务实例\nexport const networkService = new NetworkService();\n\n// 导出其他服务\nexport { apiClient, webSocketManager };\nexport { ConnectionState } from \"./websocket\";\nexport { cozeApiClient, CozeApiClient } from \"./cozeApi\";\n\n// 导出类型\nexport type { ApiClient, WebSocketManager };\n","/**\n * 新的网络服务 Hook\n * 使用统一的网络服务管理器,实现 HTTP 和 WebSocket 的协调使用\n */\n\nimport type { AppConfig, ClientStatus } from \"@/types/index\";\nimport { ConnectionState, networkService } from \"@services/index\";\nimport { useConfigStore } from \"@stores/config\";\nimport { useStatusStore } from \"@stores/status\";\nimport { useWebSocketActions } from \"@stores/websocket\";\nimport { useCallback, useEffect, useRef } from \"react\";\n\n/**\n * 网络服务 Hook\n */\nexport function useNetworkService() {\n const webSocketActions = useWebSocketActions();\n const initializationRef = useRef(false);\n\n // 初始化网络服务\n useEffect(() => {\n if (initializationRef.current) {\n return;\n }\n\n console.log(\"[NetworkService] 初始化网络服务\");\n initializationRef.current = true;\n\n // 初始化网络服务\n networkService.initialize().catch((error) => {\n console.error(\"[NetworkService] 初始化失败:\", error);\n });\n\n // 设置 WebSocket 事件监听器\n networkService.onWebSocketEvent(\"connected\", () => {\n console.log(\"[NetworkService] WebSocket 已连接\");\n webSocketActions.setConnectionState(ConnectionState.CONNECTED);\n\n // 连接成功后立即获取初始数据\n loadInitialData();\n });\n\n networkService.onWebSocketEvent(\"disconnected\", () => {\n console.log(\"[NetworkService] WebSocket 已断开\");\n webSocketActions.setConnectionState(ConnectionState.DISCONNECTED);\n });\n\n networkService.onWebSocketEvent(\"configUpdate\", (config: AppConfig) => {\n console.log(\"[NetworkService] 收到配置更新通知\");\n useConfigStore.getState().setConfig(config, \"websocket\");\n });\n\n networkService.onWebSocketEvent(\"statusUpdate\", (status: ClientStatus) => {\n console.log(\"[NetworkService] 收到状态更新通知\");\n useStatusStore.getState().setClientStatus(status, \"websocket\");\n });\n\n networkService.onWebSocketEvent(\"restartStatus\", (restartStatus) => {\n console.log(\"[NetworkService] 收到重启状态通知:\", restartStatus);\n useStatusStore.getState().setRestartStatus(restartStatus, \"websocket\");\n });\n\n networkService.onWebSocketEvent(\"error\", (error: Error) => {\n console.error(\"[NetworkService] WebSocket 错误:\", error);\n });\n\n // 清理函数\n return () => {\n console.log(\"[NetworkService] 清理网络服务\");\n networkService.destroy();\n initializationRef.current = false;\n };\n }, [webSocketActions]);\n\n /**\n * 加载初始数据\n */\n const loadInitialData = useCallback(async () => {\n try {\n console.log(\"[NetworkService] 加载初始数据\");\n\n // 并行获取配置和状态\n const [config, status] = await Promise.all([\n networkService.getConfig(),\n networkService.getClientStatus(),\n ]);\n\n console.log(\"[NetworkService] 初始数据加载成功\");\n useConfigStore.getState().setConfig(config, \"http\");\n useStatusStore.getState().setClientStatus(status, \"http\");\n } catch (error) {\n console.error(\"[NetworkService] 加载初始数据失败:\", error);\n }\n }, []);\n\n /**\n * 获取配置\n */\n const getConfig = useCallback(async (): Promise<AppConfig> => {\n try {\n const config = await networkService.getConfig();\n useConfigStore.getState().setConfig(config, \"http\");\n return config;\n } catch (error) {\n console.error(\"[NetworkService] 获取配置失败:\", error);\n throw error;\n }\n }, []);\n\n /**\n * 更新配置\n */\n const updateConfig = useCallback(async (config: AppConfig): Promise<void> => {\n try {\n console.log(\"[NetworkService] 更新配置\");\n await networkService.updateConfig(config);\n\n // 立即更新本地状态,WebSocket 通知会进一步确认\n useConfigStore.getState().setConfig(config, \"http\");\n console.log(\"[NetworkService] 配置更新成功\");\n } catch (error) {\n console.error(\"[NetworkService] 配置更新失败:\", error);\n throw error;\n }\n }, []);\n\n /**\n * 获取状态\n */\n const getStatus = useCallback(async () => {\n try {\n const status = await networkService.getStatus();\n useStatusStore.getState().setClientStatus(status.client, \"http\");\n return status;\n } catch (error) {\n console.error(\"[NetworkService] 获取状态失败:\", error);\n throw error;\n }\n }, []);\n\n /**\n * 刷新状态\n */\n const refreshStatus = useCallback(async (): Promise<void> => {\n try {\n await getStatus();\n } catch (error) {\n console.error(\"[NetworkService] 刷新状态失败:\", error);\n }\n }, [getStatus]);\n\n /**\n * 重启服务\n */\n const restartService = useCallback(async (): Promise<void> => {\n try {\n console.log(\"[NetworkService] 重启服务\");\n await networkService.restartService();\n console.log(\"[NetworkService] 重启请求已发送\");\n } catch (error) {\n console.error(\"[NetworkService] 重启服务失败:\", error);\n throw error;\n }\n }, []);\n\n /**\n * 重启服务并等待完成通知\n */\n const restartServiceWithNotification = useCallback(\n async (timeout = 30000): Promise<void> => {\n try {\n console.log(\"[NetworkService] 重启服务并等待通知\");\n await networkService.restartServiceWithNotification(timeout);\n console.log(\"[NetworkService] 服务重启完成\");\n } catch (error) {\n console.error(\"[NetworkService] 重启服务失败:\", error);\n throw error;\n }\n },\n []\n );\n\n /**\n * 更新配置并等待通知\n */\n const updateConfigWithNotification = useCallback(\n async (config: AppConfig, timeout = 5000): Promise<void> => {\n try {\n console.log(\"[NetworkService] 更新配置并等待通知\");\n await networkService.updateConfigWithNotification(config, timeout);\n console.log(\"[NetworkService] 配置更新完成\");\n } catch (error) {\n console.error(\"[NetworkService] 配置更新失败:\", error);\n throw error;\n }\n },\n []\n );\n\n /**\n * 设置自定义 WebSocket URL\n */\n const setCustomWsUrl = useCallback(\n (url: string): void => {\n console.log(\"[NetworkService] 设置自定义 WebSocket URL:\", url);\n networkService.setWebSocketUrl(url);\n webSocketActions.setWsUrl(url);\n },\n [webSocketActions]\n );\n\n /**\n * 端口切换功能 (保留向后兼容)\n */\n const changePort = useCallback(\n async (newPort: number): Promise<void> => {\n try {\n console.log(`[NetworkService] 切换到端口 ${newPort}`);\n\n // 更新端口变更状态\n webSocketActions.setPortChangeStatus({\n status: \"checking\",\n targetPort: newPort,\n timestamp: Date.now(),\n });\n\n // 构建新的 WebSocket URL\n const protocol = window.location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n const hostname = window.location.hostname;\n const newUrl = `${protocol}//${hostname}:${newPort}`;\n\n // 重启服务\n await restartService();\n\n // 等待一段时间让服务重启\n await new Promise((resolve) => setTimeout(resolve, 5000));\n\n // 更新 WebSocket URL\n setCustomWsUrl(newUrl);\n\n // 重新加载页面\n window.location.reload();\n } catch (error) {\n console.error(\"[NetworkService] 端口切换失败:\", error);\n webSocketActions.setPortChangeStatus({\n status: \"failed\",\n targetPort: newPort,\n error: error instanceof Error ? error.message : \"端口切换失败\",\n timestamp: Date.now(),\n });\n throw error;\n }\n },\n [webSocketActions, restartService, setCustomWsUrl]\n );\n\n /**\n * 获取当前 WebSocket URL\n */\n const getWebSocketUrl = useCallback((): string => {\n // 从 localStorage 获取自定义 URL\n const savedUrl = localStorage.getItem(\"xiaozhi-ws-url\");\n if (savedUrl) {\n return savedUrl;\n }\n\n // 根据当前页面 URL 构建 WebSocket URL\n const protocol = window.location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n const hostname = window.location.hostname;\n const port = window.location.port;\n return `${protocol}//${hostname}${port ? `:${port}` : \"\"}`;\n }, []);\n\n return {\n // 数据操作方法 (HTTP)\n getConfig,\n updateConfig,\n getStatus,\n refreshStatus,\n restartService,\n\n // 混合模式方法 (HTTP + WebSocket)\n updateConfigWithNotification,\n restartServiceWithNotification,\n\n // WebSocket 管理\n setCustomWsUrl,\n getWebSocketUrl,\n\n // 端口切换 (向后兼容)\n changePort,\n\n // 工具方法\n loadInitialData,\n\n // 网络服务状态\n isWebSocketConnected: () => networkService.isWebSocketConnected(),\n getWebSocketState: () => networkService.getWebSocketState(),\n };\n}\n","/**\n * Stores 统一初始化和管理\n *\n * 这个文件负责:\n * - 初始化所有 stores\n * - 设置 stores 之间的协调\n * - 提供统一的初始化入口\n */\n\nimport { useConfigStore } from \"./config\";\nimport { useStatusStore } from \"./status\";\nimport { useWebSocketStore } from \"./websocket\";\n\n/**\n * 初始化所有 stores\n *\n * 这个函数应该在应用启动时调用一次\n */\nexport async function initializeStores(): Promise<void> {\n console.log(\"[Stores] 开始初始化所有 stores\");\n\n try {\n // 1. 首先初始化 WebSocket store(建立连接管理)\n console.log(\"[Stores] 初始化 WebSocket store\");\n useWebSocketStore.getState().initialize();\n\n // 2. 初始化配置 store(设置配置数据管理和 WebSocket 监听)\n console.log(\"[Stores] 初始化配置 store\");\n await useConfigStore.getState().initialize();\n\n // 3. 初始化状态 store(设置状态数据管理和 WebSocket 监听)\n console.log(\"[Stores] 初始化状态 store\");\n await useStatusStore.getState().initialize();\n\n console.log(\"[Stores] 所有 stores 初始化完成\");\n } catch (error) {\n console.error(\"[Stores] Stores 初始化失败:\", error);\n throw error;\n }\n}\n\n/**\n * 重置所有 stores\n *\n * 用于测试或需要完全重置应用状态时\n */\nexport function resetAllStores(): void {\n console.log(\"[Stores] 重置所有 stores\");\n\n useWebSocketStore.getState().reset();\n useConfigStore.getState().reset();\n useStatusStore.getState().reset();\n\n console.log(\"[Stores] 所有 stores 已重置\");\n}\n\n/**\n * 获取所有 stores 的状态摘要\n *\n * 用于调试和监控\n */\nexport function getStoresStatus() {\n const websocketState = useWebSocketStore.getState();\n const configState = useConfigStore.getState();\n const statusState = useStatusStore.getState();\n\n return {\n websocket: {\n connectionState: websocketState.connectionState,\n url: websocketState.wsUrl,\n connected: websocketState.connectionState === \"connected\",\n lastError: websocketState.lastError?.message,\n },\n config: {\n hasConfig: !!configState.config,\n isLoading: configState.loading.isLoading,\n isUpdating: configState.loading.isUpdating,\n lastUpdated: configState.loading.lastUpdated,\n lastError: configState.loading.lastError?.message,\n source: configState.lastSource,\n },\n status: {\n hasStatus: !!statusState.clientStatus,\n isLoading: statusState.loading.isLoading,\n isRestarting: statusState.loading.isRestarting,\n pollingEnabled: statusState.polling.enabled,\n lastUpdated: statusState.loading.lastUpdated,\n lastError: statusState.loading.lastError?.message,\n source: statusState.lastSource,\n },\n };\n}\n\n// 导出所有 stores 以便统一访问\nexport { useWebSocketStore } from \"./websocket\";\nexport { useConfigStore } from \"./config\";\nexport { useStatusStore } from \"./status\";\n\n// 导出所有选择器 hooks(避免命名冲突)\nexport {\n // WebSocket store exports\n useWebSocketConnectionState,\n useWebSocketConnected,\n useWebSocketUrl,\n useWebSocketConnectionStats,\n useWebSocketPortChangeStatus,\n useWebSocketLastError,\n useWebSocketConnectionTimes,\n useWebSocketConnectionInfo,\n useWebSocketPortInfo,\n useWebSocketActions,\n useWebSocketControls,\n useWebSocketData,\n // 废弃的导出(向后兼容)\n useWebSocketConfig,\n useWebSocketStatus,\n useWebSocketRestartStatus,\n useWebSocketMcpServers,\n useWebSocketMcpServerConfig,\n} from \"./websocket\";\n\nexport {\n // Config store exports\n useConfig,\n useConfigLoading,\n useConfigIsLoading,\n useConfigIsUpdating,\n useConfigError,\n useMcpEndpoint,\n useMcpServers,\n useMcpServerConfig,\n useConnectionConfig,\n useModelScopeConfig,\n useWebUIConfig,\n useConfigSource,\n useConfigWithLoading,\n useMcpConfig,\n useSystemConfig,\n useConfigActions,\n useConfigUpdaters,\n} from \"./config\";\n\nexport {\n // Status store exports\n useClientStatus,\n useRestartStatus,\n useServiceStatus,\n useServiceHealth,\n useFullStatus,\n useStatusLoading,\n useStatusIsLoading,\n useStatusIsRestarting,\n useStatusError,\n usePollingConfig,\n usePollingEnabled,\n useStatusSource,\n useConnectionStatus,\n useStatusMcpEndpoint,\n useActiveMcpServers,\n useLastHeartbeat,\n useStatusWithLoading,\n useServiceInfo,\n useConnectionInfo,\n useStatusActions,\n usePollingActions,\n} from \"./status\";\n","import type { AppConfig } from \"@/types/index\";\nimport { useNetworkService } from \"@hooks/useNetworkService\";\nimport { initializeStores } from \"@stores/index\";\nimport {\n type ReactNode,\n createContext,\n useContext,\n useEffect,\n useState,\n} from \"react\";\n\ninterface NetworkServiceContextType {\n // HTTP API 方法\n getConfig: () => Promise<AppConfig>;\n updateConfig: (config: AppConfig) => Promise<void>;\n getStatus: () => Promise<any>;\n refreshStatus: () => Promise<void>;\n restartService: () => Promise<void>;\n\n // 混合模式方法 (HTTP + WebSocket)\n updateConfigWithNotification: (\n config: AppConfig,\n timeout?: number\n ) => Promise<void>;\n restartServiceWithNotification: (timeout?: number) => Promise<void>;\n\n // WebSocket 管理\n setCustomWsUrl: (url: string) => void;\n getWebSocketUrl: () => string;\n\n // 端口切换 (向后兼容)\n changePort: (newPort: number) => Promise<void>;\n\n // 工具方法\n loadInitialData: () => Promise<void>;\n isWebSocketConnected: () => boolean;\n getWebSocketState: () => any;\n}\n\nconst NetworkServiceContext = createContext<NetworkServiceContextType | null>(\n null\n);\n\ninterface NetworkServiceProviderProps {\n children: ReactNode;\n}\n\nexport function NetworkServiceProvider({\n children,\n}: NetworkServiceProviderProps) {\n const networkService = useNetworkService();\n const [storesInitialized, setStoresInitialized] = useState(false);\n\n // 初始化 stores\n useEffect(() => {\n let mounted = true;\n\n const initStores = async () => {\n try {\n console.log(\"[WebSocketProvider] 开始初始化 stores\");\n await initializeStores();\n\n if (mounted) {\n setStoresInitialized(true);\n console.log(\"[WebSocketProvider] Stores 初始化完成\");\n }\n } catch (error) {\n console.error(\"[WebSocketProvider] Stores 初始化失败:\", error);\n // 即使初始化失败,也允许应用继续运行\n if (mounted) {\n setStoresInitialized(true);\n }\n }\n };\n\n initStores();\n\n return () => {\n mounted = false;\n };\n }, []);\n\n // 在 stores 初始化完成前显示加载状态(可选)\n if (!storesInitialized) {\n return (\n <div className=\"flex items-center justify-center min-h-screen\">\n <div className=\"text-center\">\n <div className=\"animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto mb-2\" />\n <p className=\"text-sm text-gray-600\">正在初始化应用...</p>\n </div>\n </div>\n );\n }\n\n return (\n <NetworkServiceContext.Provider value={networkService}>\n {children}\n </NetworkServiceContext.Provider>\n );\n}\n\nexport function useNetworkServiceActions() {\n const context = useContext(NetworkServiceContext);\n if (!context) {\n throw new Error(\n \"useNetworkServiceActions must be used within a NetworkServiceProvider\"\n );\n }\n return context;\n}\n\n// 向后兼容的别名\nexport const WebSocketProvider = NetworkServiceProvider;\nexport const useWebSocketActions = useNetworkServiceActions;\n","import { AppSidebar } from \"@/components/AppSidebar\";\nimport { DashboardStatusCard } from \"@/components/DashboardStatusCard\";\nimport { McpServerList } from \"@/components/McpServerList\";\nimport { SiteHeader } from \"@/components/SiteHeder\";\nimport { SidebarInset, SidebarProvider } from \"@/components/ui/sidebar\";\nimport { useWebSocketActions } from \"@/providers/WebSocketProvider\";\n\nexport default function DashboardPage() {\n // 从 WebSocketProvider 获取操作方法\n const { updateConfig } = useWebSocketActions();\n\n return (\n <SidebarProvider>\n <AppSidebar variant=\"inset\" />\n <SidebarInset>\n <SiteHeader title=\"看板\" />\n <div className=\"flex flex-1 flex-col\">\n <div className=\"@container/main flex flex-1 flex-col gap-2\">\n <div className=\"flex flex-col gap-4 py-4 md:gap-6 md:py-6\">\n <DashboardStatusCard />\n <McpServerList updateConfig={updateConfig} />\n </div>\n </div>\n </div>\n </SidebarInset>\n </SidebarProvider>\n );\n}\n","/**\n * VersionManager 组件 - 版本管理和更新界面\n *\n * 功能:\n * - 显示当前版本信息\n * - 检查可用更新\n * - 提供版本更新功能\n * - 显示实时安装日志\n */\n\nimport { apiClient } from \"@services/api\";\nimport { Badge } from \"@ui/badge\";\nimport { Button } from \"@ui/button\";\nimport {\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n} from \"@ui/card\";\nimport {\n AlertCircle,\n Calendar,\n CheckCircle,\n Download,\n ExternalLink,\n Package,\n RefreshCw,\n} from \"lucide-react\";\nimport { useCallback, useEffect, useState } from \"react\";\nimport { InstallLogDialog } from \"./InstallLogDialog\";\nimport { VersionDisplay } from \"./VersionDisplay\";\n\ninterface VersionInfo {\n name: string;\n version: string;\n description: string;\n author: string;\n}\n\ninterface UpdateInfo {\n currentVersion: string;\n latestVersion: string;\n updateAvailable: boolean;\n releaseNotes?: string;\n publishDate?: string;\n}\n\nexport function VersionManager() {\n const [currentVersion, setCurrentVersion] = useState<VersionInfo | null>(\n null\n );\n const [updateInfo, setUpdateInfo] = useState<UpdateInfo | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [showInstallDialog, setShowInstallDialog] = useState(false);\n const [targetVersion, setTargetVersion] = useState<string>(\"\");\n\n // 加载当前版本信息\n const loadCurrentVersion = useCallback(async () => {\n try {\n setError(null);\n const versionInfo = await apiClient.getVersion();\n setCurrentVersion(versionInfo);\n console.log(\"[VersionManager] 当前版本信息:\", versionInfo);\n } catch (err) {\n const errorMessage =\n err instanceof Error ? err.message : \"获取版本信息失败\";\n setError(errorMessage);\n console.error(\"[VersionManager] 获取版本信息失败:\", err);\n }\n }, []);\n\n // 检查更新\n const checkForUpdates = async () => {\n if (!currentVersion) return;\n\n try {\n setIsLoading(true);\n setError(null);\n\n // 这里可以调用检查更新的 API\n // 暂时模拟一个检查更新的过程\n console.log(\"[VersionManager] 检查更新...\");\n\n // 模拟 API 调用延迟\n await new Promise((resolve) => setTimeout(resolve, 1000));\n\n // 模拟更新检查结果\n // 在实际实现中,这里应该调用真实的 API\n const mockUpdateInfo: UpdateInfo = {\n currentVersion: currentVersion.version,\n latestVersion: \"1.8.0\", // 模拟最新版本\n updateAvailable: true,\n releaseNotes: \"• 修复了若干 bug\\n• 新增实时日志功能\\n• 性能优化\",\n publishDate: new Date().toISOString(),\n };\n\n setUpdateInfo(mockUpdateInfo);\n console.log(\"[VersionManager] 更新检查结果:\", mockUpdateInfo);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : \"检查更新失败\";\n setError(errorMessage);\n console.error(\"[VersionManager] 检查更新失败:\", err);\n } finally {\n setIsLoading(false);\n }\n };\n\n // 开始更新\n const startUpdate = (version: string) => {\n console.log(\"[VersionManager] 开始更新到版本:\", version);\n setTargetVersion(version);\n setShowInstallDialog(true);\n };\n\n // 处理安装对话框关闭\n const handleInstallDialogClose = () => {\n setShowInstallDialog(false);\n setTargetVersion(\"\");\n // 重新加载版本信息\n setTimeout(() => {\n loadCurrentVersion();\n }, 1000);\n };\n\n // 组件初始化时加载版本信息\n useEffect(() => {\n loadCurrentVersion();\n }, [loadCurrentVersion]);\n\n return (\n <Card className=\"w-full max-w-2xl\">\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <div>\n <CardTitle className=\"flex items-center gap-2\">\n <Package className=\"h-5 w-5\" />\n 版本管理\n </CardTitle>\n <CardDescription>管理应用版本和更新</CardDescription>\n </div>\n <VersionDisplay />\n </div>\n </CardHeader>\n\n <CardContent className=\"space-y-6\">\n {error && (\n <div className=\"flex items-center gap-2 p-3 bg-destructive/10 border border-destructive/20 rounded-md\">\n <AlertCircle className=\"h-4 w-4 text-destructive\" />\n <span className=\"text-sm text-destructive\">{error}</span>\n </div>\n )}\n\n {/* 当前版本信息 */}\n <div className=\"space-y-3\">\n <h3 className=\"text-lg font-medium\">当前版本</h3>\n {currentVersion ? (\n <div className=\"p-4 bg-muted/50 rounded-md space-y-2\">\n <div className=\"flex items-center justify-between\">\n <span className=\"font-medium\">\n 版本 {currentVersion.version}\n </span>\n <Badge variant=\"secondary\">{currentVersion.name}</Badge>\n </div>\n <p className=\"text-sm text-muted-foreground\">\n {currentVersion.description}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n 作者: {currentVersion.author}\n </p>\n </div>\n ) : (\n <div className=\"p-4 bg-muted/50 rounded-md\">\n <span className=\"text-muted-foreground\">加载中...</span>\n </div>\n )}\n </div>\n\n {/* 更新检查 */}\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between\">\n <h3 className=\"text-lg font-medium\">更新检查</h3>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={checkForUpdates}\n disabled={isLoading || !currentVersion}\n className=\"flex items-center gap-2\"\n >\n <RefreshCw\n className={`h-4 w-4 ${isLoading ? \"animate-spin\" : \"\"}`}\n />\n {isLoading ? \"检查中...\" : \"检查更新\"}\n </Button>\n </div>\n\n {updateInfo && (\n <div className=\"p-4 border rounded-md space-y-3\">\n {updateInfo.updateAvailable ? (\n <>\n <div className=\"flex items-center gap-2\">\n <AlertCircle className=\"h-4 w-4 text-blue-600\" />\n <span className=\"font-medium text-blue-600\">\n 发现新版本 {updateInfo.latestVersion}\n </span>\n </div>\n\n {updateInfo.publishDate && (\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Calendar className=\"h-3 w-3\" />\n 发布日期:{\" \"}\n {new Date(updateInfo.publishDate).toLocaleDateString()}\n </div>\n )}\n\n {updateInfo.releaseNotes && (\n <div className=\"mt-3\">\n <h4 className=\"text-sm font-medium mb-2\">更新内容:</h4>\n <div className=\"text-sm text-muted-foreground whitespace-pre-line bg-muted/30 p-2 rounded\">\n {updateInfo.releaseNotes}\n </div>\n </div>\n )}\n\n <div className=\"flex gap-2 pt-2\">\n <Button\n onClick={() => startUpdate(updateInfo.latestVersion)}\n className=\"flex items-center gap-2\"\n >\n <Download className=\"h-4 w-4\" />\n 更新到 {updateInfo.latestVersion}\n </Button>\n <Button variant=\"outline\" size=\"sm\" asChild>\n <a\n href=\"https://github.com/shenjingnan/xiaozhi-client/releases\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"flex items-center gap-1\"\n >\n <ExternalLink className=\"h-3 w-3\" />\n 查看详情\n </a>\n </Button>\n </div>\n </>\n ) : (\n <div className=\"flex items-center gap-2\">\n <CheckCircle className=\"h-4 w-4 text-green-600\" />\n <span className=\"text-green-600\">\n 当前版本 {updateInfo.currentVersion} 是最新版本\n </span>\n </div>\n )}\n </div>\n )}\n </div>\n </CardContent>\n\n {/* 安装日志对话框 */}\n <InstallLogDialog\n isOpen={showInstallDialog}\n onClose={handleInstallDialogClose}\n version={targetVersion}\n />\n </Card>\n );\n}\n","import { AppSidebar } from \"@/components/AppSidebar\";\nimport { RestartButton } from \"@/components/RestartButton\";\nimport { SiteHeader } from \"@/components/SiteHeder\";\nimport { VersionManager } from \"@/components/VersionManager\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@/components/ui/form\";\nimport { Input } from \"@/components/ui/input\";\nimport { SidebarInset, SidebarProvider } from \"@/components/ui/sidebar\";\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"@/components/ui/tabs\";\nimport { useWebSocketActions } from \"@/providers/WebSocketProvider\";\nimport { useConfig } from \"@/stores/config\";\nimport type { AppConfig } from \"@/types/index\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport { useEffect, useState } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport { toast } from \"sonner\";\nimport z from \"zod\";\n\nconst formSchema = z.object({\n modelscope: z.object({\n apiKey: z.string().optional(),\n }),\n platforms: z.object({\n coze: z.object({\n token: z.string().optional(),\n }),\n }),\n connection: z.object({\n heartbeatInterval: z.number().min(1000, {\n message: \"心跳间隔不能小于1000毫秒\",\n }),\n heartbeatTimeout: z.number().min(1000, {\n message: \"心跳超时不能小于1000毫秒\",\n }),\n reconnectInterval: z.number().min(1000, {\n message: \"重连间隔不能小于1000毫秒\",\n }),\n }),\n});\n\nexport default function SettingsPage() {\n const config = useConfig();\n const { updateConfig } = useWebSocketActions();\n const [isLoading, setIsLoading] = useState(false);\n const form = useForm<z.infer<typeof formSchema>>({\n resolver: zodResolver(formSchema),\n defaultValues: {\n platforms: {\n coze: {\n token: config?.platforms?.coze?.token || \"\",\n },\n },\n modelscope: {\n apiKey: config?.modelscope?.apiKey || \"\",\n },\n connection: {\n heartbeatInterval: config?.connection?.heartbeatInterval || 30000,\n heartbeatTimeout: config?.connection?.heartbeatTimeout || 10000,\n reconnectInterval: config?.connection?.reconnectInterval || 5000,\n },\n },\n });\n\n useEffect(() => {\n form.reset({\n modelscope: {\n apiKey: config?.modelscope?.apiKey || \"\",\n },\n connection: {\n heartbeatInterval: config?.connection?.heartbeatInterval || 30000,\n heartbeatTimeout: config?.connection?.heartbeatTimeout || 10000,\n reconnectInterval: config?.connection?.reconnectInterval || 5000,\n },\n });\n }, [config, form.reset]);\n\n async function onSubmit(values: z.infer<typeof formSchema>) {\n if (!config) {\n toast.error(\"配置数据未加载,请稍后重试\");\n return;\n }\n\n setIsLoading(true);\n try {\n const newConfig: AppConfig = {\n ...config,\n modelscope: {\n apiKey: values.modelscope.apiKey,\n },\n connection: {\n heartbeatInterval: values.connection.heartbeatInterval,\n heartbeatTimeout: values.connection.heartbeatTimeout,\n reconnectInterval: values.connection.reconnectInterval,\n },\n platforms: {\n ...(config?.platforms ?? {}),\n coze: {\n ...(config?.platforms?.coze ?? {}),\n token: values.platforms.coze.token,\n },\n },\n };\n\n await updateConfig(newConfig);\n toast.success(\"配置已更新\");\n } catch (error) {\n console.error(\"更新配置失败:\", error);\n toast.error(error instanceof Error ? error.message : \"更新配置失败\");\n } finally {\n setIsLoading(false);\n }\n }\n\n return (\n <SidebarProvider>\n <AppSidebar variant=\"inset\" />\n <SidebarInset>\n <SiteHeader title=\"设置\" />\n <div className=\"flex flex-1 flex-col p-4\">\n <div className=\"@container/main flex flex-1 flex-col gap-2 items-center\">\n <div className=\"flex flex-col gap-4 py-4 md:gap-6 md:py-6 w-full max-w-4xl\">\n <Tabs defaultValue=\"general\" className=\"w-full\">\n <TabsList className=\"grid w-full grid-cols-2\">\n <TabsTrigger value=\"general\">常规设置</TabsTrigger>\n <TabsTrigger value=\"version\">版本管理</TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"general\" className=\"mt-6\">\n <div className=\"w-[600px] mx-auto\">\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)}>\n <div className=\"grid gap-4\">\n <FormField\n control={form.control}\n name=\"modelscope.apiKey\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>魔搭社区 API Key</FormLabel>\n <div className=\"flex gap-2\">\n <FormControl>\n <Input\n placeholder=\"魔搭社区 API Key\"\n className=\"font-mono text-sm\"\n type=\"password\"\n disabled={isLoading}\n autoComplete=\"off\"\n data-1p-ignore\n {...field}\n />\n </FormControl>\n <Button\n variant=\"outline\"\n onClick={() => {\n window.open(\n \"https://www.modelscope.cn/my/myaccesstoken\",\n \"_blank\"\n );\n }}\n >\n 打开魔搭社区\n </Button>\n </div>\n <FormMessage />\n </FormItem>\n )}\n />\n <FormField\n control={form.control}\n name=\"platforms.coze.token\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>扣子身份凭证</FormLabel>\n <div className=\"flex gap-2\">\n <FormControl>\n <Input\n placeholder=\"扣子身份凭证\"\n className=\"font-mono text-sm\"\n type=\"password\"\n autoComplete=\"off\"\n data-1p-ignore\n disabled={isLoading}\n {...field}\n />\n </FormControl>\n <Button\n variant=\"outline\"\n onClick={() => {\n window.open(\n \"https://www.coze.cn/open/oauth/sats\",\n \"_blank\"\n );\n }}\n >\n 打开扣子平台\n </Button>\n </div>\n <FormMessage />\n </FormItem>\n )}\n />\n <FormField\n control={form.control}\n name=\"connection.heartbeatInterval\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>心跳间隔(毫秒)</FormLabel>\n <div className=\"flex gap-2 items-center\">\n <FormControl>\n <Input\n placeholder=\"心跳间隔(毫秒)\"\n className=\"font-mono text-sm\"\n type=\"number\"\n disabled={isLoading}\n {...field}\n value={field.value || \"\"}\n onChange={(e) => {\n const value = e.target.value;\n field.onChange(\n value === \"\" ? \"\" : Number(value)\n );\n }}\n />\n </FormControl>\n <span className=\"text-sm text-muted-foreground w-[50px]\">\n 毫秒\n </span>\n </div>\n <FormMessage />\n </FormItem>\n )}\n />\n <FormField\n control={form.control}\n name=\"connection.heartbeatTimeout\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>心跳超时(毫秒)</FormLabel>\n <div className=\"flex gap-2 items-center\">\n <FormControl>\n <Input\n placeholder=\"心跳超时(毫秒)\"\n className=\"font-mono text-sm\"\n type=\"number\"\n disabled={isLoading}\n {...field}\n value={field.value || \"\"}\n onChange={(e) => {\n const value = e.target.value;\n field.onChange(\n value === \"\" ? \"\" : Number(value)\n );\n }}\n />\n </FormControl>\n <span className=\"text-sm text-muted-foreground w-[50px]\">\n 毫秒\n </span>\n </div>\n <FormMessage />\n </FormItem>\n )}\n />\n <FormField\n control={form.control}\n name=\"connection.reconnectInterval\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>重连间隔(毫秒)</FormLabel>\n <div className=\"flex gap-2 items-center\">\n <FormControl>\n <Input\n placeholder=\"重连间隔(毫秒)\"\n className=\"font-mono text-sm\"\n type=\"number\"\n disabled={isLoading}\n {...field}\n value={field.value || \"\"}\n onChange={(e) => {\n const value = e.target.value;\n field.onChange(\n value === \"\" ? \"\" : Number(value)\n );\n }}\n />\n </FormControl>\n <span className=\"text-sm text-muted-foreground w-[50px]\">\n 毫秒\n </span>\n </div>\n <FormMessage />\n </FormItem>\n )}\n />\n <div className=\"flex gap-2 justify-end\">\n <Button\n type=\"submit\"\n disabled={isLoading}\n className=\"flex-1\"\n >\n {isLoading ? \"保存中...\" : \"保存\"}\n </Button>\n <RestartButton />\n </div>\n </div>\n </form>\n </Form>\n </div>\n </TabsContent>\n\n <TabsContent value=\"version\" className=\"mt-6\">\n <div className=\"w-[600px] mx-auto\">\n <VersionManager />\n </div>\n </TabsContent>\n </Tabs>\n </div>\n </div>\n </div>\n </SidebarInset>\n </SidebarProvider>\n );\n}\n","import { Toaster } from \"@/components/ui/sonner\";\nimport { RestartNotificationProvider } from \"@/hooks/useRestartNotifications\";\nimport DashboardPage from \"@/pages/DashboardPage\";\nimport SettingsPage from \"@/pages/SettingsPage\";\nimport { WebSocketProvider } from \"@/providers/WebSocketProvider\";\nimport { Navigate, Route, Routes } from \"react-router-dom\";\n\nfunction App() {\n return (\n <WebSocketProvider>\n {/* 重启通知管理器 - 全局监听重启状态变化 */}\n <RestartNotificationProvider />\n\n <Routes>\n <Route path=\"/\" element={<Navigate to=\"/dashboard\" />} />\n <Route path=\"/dashboard\" element={<DashboardPage />} />\n <Route path=\"/settings\" element={<SettingsPage />} />\n </Routes>\n\n {/* Toast 通知容器 */}\n <Toaster\n richColors\n toastOptions={{\n classNames: {\n description: \"group-[.toast]:text-muted-foreground\",\n actionButton:\n \"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground\",\n cancelButton: \"group-[.toast]:bg-white group-[.toast]:text-black\",\n error:\n \"group toast group-[.toaster]:bg-red group-[.toaster]:text-red-600 dark:group-[.toaster]:text-foreground group-[.toaster]:shadow-lg\",\n success:\n \"group toast group-[.toaster]:bg-green group-[.toaster]:text-green-600 dark:group-[.toaster]:text-foreground group-[.toaster]:shadow-lg\",\n warning:\n \"group toast group-[.toaster]:bg-yellow group-[.toaster]:text-yellow-600 dark:group-[.toaster]:text-foreground group-[.toaster]:shadow-lg\",\n info: \"group toast group-[.toaster]:bg-blue group-[.toaster]:text-blue-600 dark:group-[.toaster]:text-foreground group-[.toaster]:shadow-lg\",\n },\n }}\n />\n </WebSocketProvider>\n );\n}\n\nexport default App;\n","import React from \"react\";\nimport ReactDOM from \"react-dom/client\";\nimport { BrowserRouter } from \"react-router-dom\";\nimport App from \"./App\";\nimport \"./index.css\";\n\nReactDOM.createRoot(document.getElementById(\"root\")!).render(\n <React.StrictMode>\n <BrowserRouter>\n <App />\n </BrowserRouter>\n </React.StrictMode>\n);\n"],"names":["ApiClient","baseUrl","__publicField","protocol","hostname","port","endpoint","options","url","defaultOptions","response","errorMessage","_a","config","status","servers","param1","customName","customDescription","parameterConfig","workflow","toolName","updateRequest","queryParams","type","version","name","requestData","serverName","error","serviceName","args","apiClient","mcpServerApi","ConnectionState","EventBus","event","listener","eventListeners","data","total","listeners","_WebSocketManager","_b","savedUrl","message","messageStr","heartbeatMessage","WebSocketManager","webSocketManager","initialState","pollingTimer","restartPollingTimer","useStatusStore","create","devtools","set","get","source","state","health","loading","fullStatus","setLoading","setFullStatus","setError","polling","err","newRetries","setRestartStatus","startRestartPolling","interval","refreshStatus","restartPolling","startTime","currentState","currentRestartPolling","elapsed","attempts","useClientStatus","useRestartStatus","useRestartPollingStatus","useStatusActions","useShallow","useRestartNotifications","restartStatus","restartPollingStatus","lastNotifiedStatus","useRef","lastNotifiedTimestamp","useEffect","timestamp","toast","successMessage","failureMessage","description","RestartNotificationProvider","cn","inputs","twMerge","clsx","buttonVariants","cva","Button","React.forwardRef","className","variant","size","asChild","props","ref","Comp","Slot","jsx","Input","Separator","orientation","decorative","SeparatorPrimitive.Root","Sheet","SheetPrimitive.Root","SheetPortal","SheetPrimitive.Portal","SheetOverlay","SheetPrimitive.Overlay","sheetVariants","SheetContent","side","children","jsxs","SheetPrimitive.Content","SheetPrimitive.Close","X","SheetHeader","SheetTitle","SheetPrimitive.Title","SheetDescription","SheetPrimitive.Description","Skeleton","TooltipProvider","TooltipPrimitive.Provider","Tooltip","TooltipPrimitive.Root","TooltipTrigger","TooltipPrimitive.Trigger","TooltipContent","sideOffset","TooltipPrimitive.Content","MOBILE_BREAKPOINT","useIsMobile","isMobile","setIsMobile","React.useState","React.useEffect","mql","onChange","SIDEBAR_COOKIE_NAME","SIDEBAR_COOKIE_MAX_AGE","SIDEBAR_WIDTH","SIDEBAR_WIDTH_MOBILE","SIDEBAR_WIDTH_ICON","SIDEBAR_KEYBOARD_SHORTCUT","SidebarContext","React.createContext","useSidebar","context","React.useContext","SidebarProvider","defaultOpen","openProp","setOpenProp","style","openMobile","setOpenMobile","_open","_setOpen","open","setOpen","React.useCallback","value","openState","toggleSidebar","handleKeyDown","contextValue","React.useMemo","Sidebar","collapsible","SidebarTrigger","onClick","PanelLeft","SidebarRail","SidebarInset","SidebarInput","SidebarHeader","SidebarFooter","SidebarSeparator","SidebarContent","SidebarGroup","SidebarGroupLabel","SidebarGroupAction","SidebarGroupContent","SidebarMenu","SidebarMenuItem","sidebarMenuButtonVariants","SidebarMenuButton","isActive","tooltip","button","SidebarMenuAction","showOnHover","SidebarMenuBadge","SidebarMenuSkeleton","showIcon","width","SidebarMenuSub","SidebarMenuSubItem","SidebarMenuSubButton","AppSidebarNav","items","location","useLocation","item","Link","LayoutDashboardIcon","SettingsIcon","AppSidebar","badgeVariants","Badge","AlertDialog","AlertDialogPrimitive.Root","AlertDialogTrigger","AlertDialogPrimitive.Trigger","AlertDialogPortal","AlertDialogPrimitive.Portal","AlertDialogOverlay","AlertDialogPrimitive.Overlay","AlertDialogContent","AlertDialogPrimitive.Content","AlertDialogHeader","AlertDialogFooter","AlertDialogTitle","AlertDialogPrimitive.Title","AlertDialogDescription","AlertDialogPrimitive.Description","AlertDialogAction","AlertDialogPrimitive.Action","AlertDialogCancel","AlertDialogPrimitive.Cancel","Dialog","DialogPrimitive.Root","DialogTrigger","DialogPrimitive.Trigger","DialogPortal","DialogPrimitive.Portal","DialogClose","DialogPrimitive.Close","DialogOverlay","DialogPrimitive.Overlay","DialogContent","DialogPrimitive.Content","DialogHeader","DialogFooter","DialogTitle","DialogPrimitive.Title","DialogDescription","DialogPrimitive.Description","useConfigStore","newConfig","setConfig","updateConfig","connection","modelscope","webUI","refreshConfig","useConfig","useMcpEndpoint","useMcpServers","useMcpServerConfig","useConfigActions","sliceEndpoint","validateEndpoint","McpEndpointSettingButton","useState","deleteConfirmOpen","setDeleteConfirmOpen","endpointToDelete","setEndpointToDelete","isDeleting","setIsDeleting","addDialogOpen","setAddDialogOpen","newEndpoint","setNewEndpoint","isAdding","setIsAdding","validationError","setValidationError","endpointStates","setEndpointStates","mcpEndpoint","fetchEndpointStatus","useCallback","updateEndpointState","updates","prev","initializeEndpointStates","endpoints","states","handleConnect","handleDisconnect","handleCopy","textArea","successful","handleDeleteEndpoint","newStates","handleAddEndpoint","endpointStatus","openAddDialog","handleInputChange","openDeleteConfirm","mcpEndpoints","useMemo","list","unsubscribers","unsubscribe","endpointState","isConnected","isOperating","Loader2Icon","WifiIcon","WifiOffIcon","CopyIcon","TrashIcon","BadgeInfoIcon","PlusIcon","e","Card","CardHeader","CardTitle","CardDescription","CardContent","CardFooter","ScrollArea","ScrollBar","Table","TableHeader","TableBody","TableFooter","TableRow","TableHead","TableCell","TableCaption","Tabs","TabsPrimitive.Root","TabsList","TabsPrimitive.List","TabsTrigger","TabsPrimitive.Trigger","TabsContent","TabsPrimitive.Content","formatTimestamp","formatDuration","duration","generateStableKey","log","index","formatJson","ToolCallLogsDialog","logs","setLogs","refreshing","setRefreshing","selectedLog","setSelectedLog","hoveredIndex","setHoveredIndex","limit","setTotal","fetchLogs","isRefresh","resolve","handleRowMouseEnter","handleDetailMouseEnter","handleDialogMouseLeave","FileText","RotateCwIcon","Loader2","XCircle","RefreshCw","CallLogDetail","CopyButton","copyContent","copied","setCopied","CheckIcon","formatRawData","Code","CheckCircle","labelVariants","Label","LabelPrimitive.Root","Form","FormProvider","FormFieldContext","FormField","Controller","useFormField","fieldContext","itemContext","FormItemContext","getFieldState","formState","useFormContext","fieldState","id","FormItem","React.useId","FormLabel","formItemId","FormControl","formDescriptionId","formMessageId","FormDescription","FormMessage","body","useWebSocketStore","connectionState","now","stats","wsUrl","connectionStats","lastError","portChangeStatus","initialStats","connected","useWebSocketConnected","useWebSocketUrl","useWebSocketPortChangeStatus","useWebSocketActions","checkPortAvailability","timeout","controller","timeoutId","buildWebSocketUrl","host","extractPortFromUrl","urlObj","useWebSocket","clientStatus","webSocketActions","configActions","statusActions","setWsUrl","isInitialized","currentUrl","getWebSocketUrl","configPort","targetPort","currentPort","restartService","setCustomWsUrl","defaultUrl","changePort","newPort","newUrl","formSchema","z","val","WebUrlSettingButton","isLoading","setIsLoading","form","useForm","zodResolver","getButtonText","currentAttempt","maxAttempts","onSubmit","values","field","MiniCircularProgress","showValue","maxValue","activeColor","inactiveColor","symbol","radius","circumference","strokeDasharray","strokeDashoffset","DashboardStatusCard","mcpServers","mcpServerCount","Checkbox","CheckboxPrimitive.Root","CheckboxPrimitive.Indicator","Check","Select","SelectPrimitive.Root","SelectValue","SelectPrimitive.Value","SelectTrigger","SelectPrimitive.Trigger","SelectPrimitive.Icon","ChevronDown","SelectScrollUpButton","SelectPrimitive.ScrollUpButton","ChevronUp","SelectScrollDownButton","SelectPrimitive.ScrollDownButton","SelectContent","position","SelectPrimitive.Portal","SelectPrimitive.Content","SelectPrimitive.Viewport","SelectLabel","SelectPrimitive.Label","SelectItem","SelectPrimitive.Item","SelectPrimitive.ItemIndicator","SelectPrimitive.ItemText","SelectSeparator","SelectPrimitive.Separator","parameterSchema","z.object","z.string","z.enum","z.boolean","z.array","parameters","fieldNames","p","extractParametersFromSchema","inputSchema","properties","required","fieldName","schema","WorkflowParameterConfigDialog","onOpenChange","onConfirm","onCancel","title","fields","append","remove","useFieldArray","handleAddParameter","handleRemoveParameter","handleSubmit","handleCancel","Plus","Trash2","getMcpServerCommunicationType","serverConfig","Textarea","AddMcpServerButton","validateSingleServerConfig","hasCommand","hasType","hasUrl","validateMCPConfig","input","trimmed","parsed","validation","parsedServers","existingServers","existingNames","server","addedCount","CozeApiClient","params","searchParams","cozeApiClient","useCozeWorkflows","autoLoadWorkspaces","autoLoadWorkflows","defaultPageSize","initialWorkspaceId","workspaces","setWorkspaces","workflows","setWorkflows","selectedWorkspaceId","setSelectedWorkspaceId","uiState","setUiState","currentPage","setCurrentPage","pageSize","setPageSize","hasMoreWorkflows","setHasMoreWorkflows","selectedWorkspace","ws","loadWorkspaces","loadWorkflows","workspaceId","requestParams","result","selectWorkspace","refreshWorkspaces","refreshWorkflows","clearCache","setPage","page","setPageSizeCallback","CozeWorkflowIntegration","onToolAdded","isAddingWorkflow","setIsAddingWorkflow","confirmDialog","setConfirmDialog","parameterConfigDialog","setParameterConfigDialog","isOnline","setIsOnline","pendingOperations","setPendingOperations","hasAutoSelected","setHasAutoSelected","workspacesLoading","workflowsLoading","workspacesError","workflowsError","handleOnline","handleOffline","firstWorkspace","handleWorkspaceChange","handleAddWorkflow","operationKey","handleParameterConfigConfirm","request","addedTool","prevWorkflows","w","newSet","handleParameterConfigCancel","handleConfirmAddWorkflow","handlePrevPage","handleNextPage","handleRefreshWorkflows","renderWorkspaceSelector","AlertCircle","workspace","renderWorkflowList","_","i","Workflow","renderPagination","ChevronLeft","ChevronRight","Fragment","McpServerSettingButton","mcpServer","mcpServerName","newMcpServerConfig","updatedConfig","RemoveMcpServerButton","onRemoveSuccess","disabled","onRemove","RestartButton","restartingText","defaultText","isRestarting","handleRestart","getDisplayText","LoaderCircleIcon","PowerIcon","alertVariants","Alert","AlertTitle","AlertDescription","createZodSchemaFromJsonSchema","jsonSchema","z.any","stringSchema","numberSchema","z.number","itemSchema","arraySchema","shape","requiredFields","key","propSchema","fieldSchema","z.record","getDefaultValueForSchema","defaults","createDefaultValues","defaultValue","ArrayField","memo","renderFormField","addItem","newItem","ObjectField","getTypeBadge","InfoIcon","NoParamsMessage","FormRenderer","tool","ToolDebugDialog","inputMode","setInputMode","jsonInput","setJsonInput","setResult","defaultValues","resetState","handleModeChange","newMode","currentValues","parsedData","handleOpenChange","newOpen","validateJSON","jsonString","handleCallTool","content","handleClear","option","formatResult","getShortcutText","Zap","BrushCleaningIcon","PlayIcon","McpServerList","_updateConfig","mcpServerConfig","enabledTools","setEnabledTools","disabledTools","setDisabledTools","isLoadingTools","setIsLoadingTools","toolsError","setToolsError","formatTool","enable","fetchTools","enabledToolsList","disabledToolsList","formattedEnabledTools","formattedDisabledTools","fallbackTools","enabled","isRefreshing","setIsRefreshing","handleRefreshData","refreshToolLists","cozeToolToRemove","setCozeToolToRemove","debugDialog","setDebugDialog","handleToggleTool","currentEnable","originalTool","handleConfirmRemoveCozeTool","handleCancelRemoveCozeTool","handleConfigureTool","handleDebugTool","buildCozeWorkflowFromTool","_c","cozeWorkflow","CoffeeIcon","Wrench","Settings","ZapIcon","MinusIcon","QQIcon","color","GithubIcon","useNPMInstall","installStatus","setInstallStatus","unsubscribeStarted","unsubscribeLog","unsubscribeCompleted","unsubscribeFailed","startInstall","clearStatus","getStatusText","getStatusColor","isInstalling","canCloseDialog","Progress","getProgressColor","InstallLogDialog","isOpen","onClose","logContainerRef","showDetails","setShowDetails","timer","getProgressValue","getSimpleStatusText","getStatusIcon","TerminalIcon","CheckCircleIcon","XCircleIcon","getStatusBadgeVariant","formatLogMessage","cleanedMessage","ansiPatterns","pattern","line","handleClose","toggleDetails","ChevronUpIcon","ChevronDownIcon","VERSION_TYPES","VersionUpgradeDialog","defaultSelectedVersion","setIsOpen","selectedVersion","setSelectedVersion","selectedVersionType","setSelectedVersionType","showInstallDialog","setShowInstallDialog","availableVersions","setAvailableVersions","isLoadingVersions","setIsLoadingVersions","fetchAvailableVersions","versions","handleVersionTypeSelect","handleVersionSelect","handleConfirmInstall","handleInstallDialogClose","handleDialogClose","DownloadIcon","semver","ShieldAlertIcon","VersionDisplay","versionInfo","setVersionInfo","latestVersionInfo","setLatestVersionInfo","checkingUpdate","setCheckingUpdate","info","updateInfo","handleCopyVersion","tooltipContent","getUpgradeButton","RocketIcon","SiteHeader","NetworkService","reject","networkService","useNetworkService","initializationRef","loadInitialData","getConfig","getStatus","restartServiceWithNotification","updateConfigWithNotification","initializeStores","NetworkServiceContext","createContext","NetworkServiceProvider","storesInitialized","setStoresInitialized","mounted","useNetworkServiceActions","useContext","WebSocketProvider","DashboardPage","VersionManager","currentVersion","setCurrentVersion","setUpdateInfo","targetVersion","setTargetVersion","loadCurrentVersion","checkForUpdates","mockUpdateInfo","startUpdate","Package","Calendar","Download","ExternalLink","SettingsPage","_d","_e","_f","App","Routes","Route","Navigate","Toaster","ReactDOM","React","BrowserRouter"],"mappings":"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"}