package cmd import ( "fmt" "os" "time" "github.com/aisim/kb-cli/internal/graph" "github.com/aisim/kb-cli/internal/index" "github.com/aisim/kb-cli/internal/vault" ) // rebuildIndex 重建索引:扫描 vault → 构建图 → 写入 SQLite func rebuildIndex(store *index.Store, commit string) error { // 清空旧数据 if err := store.ClearData(); err != nil { return fmt.Errorf("清空数据失败: %w", err) } // 扫描 vault files, err := vault.ScanVault(vaultPath) if err != nil { return fmt.Errorf("扫描知识库失败: %w", err) } fmt.Fprintf(os.Stderr, "扫描到 %d 个文件\n", len(files)) // 构建图 g := graph.BuildGraph(files) // 写入节点,并记录 BuildGraph ID -> SQLite ID 的映射 idMap := make(map[int64]int64) // BuildGraph ID -> SQLite ID for _, n := range g.Nodes { sqliteID, err := store.InsertNode(n) if err != nil { return fmt.Errorf("插入节点失败 [%s]: %w", n.Path, err) } idMap[n.ID] = sqliteID } // 写入边,将 BuildGraph ID 转换为 SQLite ID actualEdgeCount := 0 for _, e := range g.Edges { fromID, ok := idMap[e.FromNode] if !ok { // 可能是虚拟节点(tag/entity),跳过 continue } toID, ok := idMap[e.ToNode] if !ok { // 目标节点不存在,跳过 continue } edge := &graph.Edge{ FromNode: fromID, ToNode: toID, Relation: e.Relation, Label: e.Label, } if err := store.InsertEdge(edge); err != nil { return fmt.Errorf("插入边失败: %w", err) } actualEdgeCount++ } // 创建并填充 FTS5 索引 if err := store.CreateFTS(); err != nil { return fmt.Errorf("创建 FTS 索引失败: %w", err) } if err := store.PopulateFTS(); err != nil { return fmt.Errorf("填充 FTS 索引失败: %w", err) } // 记录元信息 if commit != "" { if err := store.SetMeta("git_commit", commit); err != nil { return fmt.Errorf("记录 git commit 失败: %w", err) } } if err := store.SetMeta("built_at", time.Now().Format(time.RFC3339)); err != nil { return fmt.Errorf("记录构建时间失败: %w", err) } fmt.Fprintf(os.Stderr, "已索引 %d 个节点, %d 条边\n", len(g.Nodes), actualEdgeCount) return nil }