repo_description: A cross-platform desktop All-in-One assistant tool for Claude Code, Codex, OpenCode, openclaw & Gemini CLI.
repo_topics: ai-tools claude-code codex desktop-app mcp minimax omo open-source openclaw openclaw-ui opencode provider-management rust skills skills-management tauri typescript wsl-support
code: import { useCallback, useMemo } from "react";
  import FlexSearch from "flexsearch";
  import type { SessionMeta } from "@/types";
  
  interface UseSessionSearchOptions {
    sessions: SessionMeta[];
    providerFilter: string;
  }
  
  interface UseSessionSearchResult {
    search: (query: string) => SessionMeta[];
  }
  
  /**
   * 使用 FlexSearch 实现会话全文搜索
   * 索引会话元数据（标题、摘要、项目目录等）
   */
  export function useSessionSearch({
    sessions,
    providerFilter,
  }: UseSessionSearchOptions): UseSessionSearchResult {
    const filteredByProvider = useMemo(() => {
      if (providerFilter === "all") return sessions;
      return sessions.filter((s) => s.providerId === providerFilter);
    }, [sessions, providerFilter]);
  
    const index = useMemo(() => {
      const nextIndex = new FlexSearch.Index({
        tokenize: "full",
        resolution: 9,
      });
  
      filteredByProvider.forEach((session, idx) => {
        const metaContent = [
          session.sessionId,
          session.title,
          session.summary,
          session.projectDir,
          session.sourcePath,
        ]
          .filter(Boolean)
          .join(" ");
  
        nextIndex.add(idx, metaContent);
      });
  
      return nextIndex;
    }, [filteredByProvider]);
  
    const search = useCallback(
      (query: string): SessionMeta[] => {
        const needle = query.trim();
  
        if (!needle) {
          return [...filteredByProvider].sort((a, b) => {
            const aTs = a.lastActiveAt ?? a.createdAt ?? 0;
            const bTs = b.lastActiveAt ?? b.createdAt ?? 0;
            return bTs - aTs;
          });
        }
  
        const results = index.search(needle, {
          limit: filteredByProvider.length,
        }) as number[];
  
        return results.map((idx) => filteredByProvider[idx]);
      },
      [index, filteredByProvider],
    );
  
    return { search };
  }
  