/** * Commands Hook * * 管理斜杠命令的加载、搜索和缓存 */ import { useState, useEffect, useCallback, useRef } from 'react'; import { listCommands, searchCommands } from '../api/client.js'; import type { CommandListResponse } from '../api/types.js'; type CommandItem = CommandListResponse['commands'][number]; interface UseCommandsOptions { /** 是否在挂载时自动加载命令列表 */ autoLoad?: boolean; } interface UseCommandsState { /** 所有命令列表 */ commands: CommandItem[]; /** 过滤后的命令列表 */ filteredCommands: CommandItem[]; /** 是否正在加载 */ isLoading: boolean; /** 错误信息 */ error: string | null; } export function useCommands(options: UseCommandsOptions = {}) { const { autoLoad = true } = options; const [state, setState] = useState({ commands: [], filteredCommands: [], isLoading: false, error: null, }); const loadedRef = useRef(false); // 加载命令列表 const loadCommands = useCallback(async () => { if (state.isLoading) return; setState((prev) => ({ ...prev, isLoading: true, error: null })); try { const result = await listCommands(); if (result.success) { setState({ commands: result.data.commands, filteredCommands: result.data.commands, isLoading: false, error: null, }); } else { setState((prev) => ({ ...prev, isLoading: false, error: 'Failed to load commands', })); } } catch (error) { setState((prev) => ({ ...prev, isLoading: false, error: error instanceof Error ? error.message : 'Unknown error', })); } }, [state.isLoading]); // 搜索/过滤命令 const filterCommands = useCallback( async (query: string) => { // 空查询显示所有命令 if (!query.trim()) { setState((prev) => ({ ...prev, filteredCommands: prev.commands, })); return; } // 本地过滤(快速响应) const queryLower = query.toLowerCase(); const localFiltered = state.commands.filter( (cmd) => cmd.name.toLowerCase().includes(queryLower) || cmd.description?.toLowerCase().includes(queryLower) ); // 如果本地过滤有结果,直接使用 if (localFiltered.length > 0) { setState((prev) => ({ ...prev, filteredCommands: localFiltered, })); return; } // 否则尝试服务端搜索(可能有模糊匹配) try { const result = await searchCommands(query, 10); if (result.success && result.data.length > 0) { setState((prev) => ({ ...prev, filteredCommands: result.data.map((r) => ({ name: r.name, description: r.description, source: r.source, })), })); } else { setState((prev) => ({ ...prev, filteredCommands: [], })); } } catch { // 搜索失败,保持本地过滤结果 setState((prev) => ({ ...prev, filteredCommands: localFiltered, })); } }, [state.commands] ); // 自动加载 useEffect(() => { if (autoLoad && !loadedRef.current) { loadedRef.current = true; loadCommands(); } }, [autoLoad, loadCommands]); return { ...state, loadCommands, filterCommands, }; }