| | |
| | | import ( |
| | | "fmt" |
| | | "os" |
| | | "os/exec" |
| | | "path/filepath" |
| | | "strings" |
| | | "time" |
| | | |
| | | "github.com/aisim/kb-cli/internal/index" |
| | | "github.com/spf13/cobra" |
| | |
| | | var indexBuildCmd = &cobra.Command{ |
| | | Use: "build", |
| | | Short: "构建或重建知识库索引", |
| | | RunE: runIndexBuild, |
| | | Long: `# index build - 构建或重建知识库索引 |
| | | kb-cli index build [--vault=<路径>] |
| | | |
| | | 操作说明: |
| | | 1. 扫描知识库目录下的所有 Markdown 文件 |
| | | 2. 解析 frontmatter、标签、实体、wikilinks |
| | | 3. 构建知识图谱并写入 SQLite 数据库 |
| | | 4. 创建 FTS5 全文索引 |
| | | |
| | | 参数: |
| | | --vault <路径> 知识库根目录(默认:~/aisim/note/001/笔记001) |
| | | --db <路径> 索引数据库路径(默认:~/.cache/kb-cli/kb.db)`, |
| | | RunE: runIndexBuild, |
| | | } |
| | | |
| | | var indexStatusCmd = &cobra.Command{ |
| | | Use: "status", |
| | | Short: "查看索引状态信息", |
| | | RunE: runIndexStatus, |
| | | Long: `# index status - 查看索引状态信息 |
| | | kb-cli index status |
| | | |
| | | 输出信息: |
| | | - 知识库路径 |
| | | - 索引文件路径 |
| | | - 节点数量 |
| | | - 边数量 |
| | | - 索引 commit |
| | | - 当前 commit |
| | | - 构建时间 |
| | | - 是否需要更新 |
| | | |
| | | 参数: |
| | | --vault <路径> 知识库根目录(默认:~/aisim/note/001/笔记001) |
| | | --db <路径> 索引数据库路径(默认:~/.cache/kb-cli/kb.db)`, |
| | | RunE: runIndexStatus, |
| | | } |
| | | |
| | | var indexGcCmd = &cobra.Command{ |
| | | Use: "gc", |
| | | Short: "清理孤立节点和边", |
| | | RunE: runIndexGc, |
| | | Long: `# index gc - 清理孤立节点和边 |
| | | kb-cli index gc |
| | | |
| | | 操作说明: |
| | | 1. 扫描索引中的所有节点 |
| | | 2. 检查对应的 Markdown 文件是否存在 |
| | | 3. 删除不存在的文件对应的节点和边 |
| | | 4. 输出清理的节点数量 |
| | | |
| | | 参数: |
| | | --vault <路径> 知识库根目录(默认:~/aisim/note/001/笔记001) |
| | | --db <路径> 索引数据库路径(默认:~/.cache/kb-cli/kb.db)`, |
| | | RunE: runIndexGc, |
| | | } |
| | | |
| | | var gitCmd = &cobra.Command{ |
| | | Use: "git", |
| | | Short: "Git 同步操作", |
| | | } |
| | | |
| | | var gitSyncCmd = &cobra.Command{ |
| | | Use: "sync", |
| | | Short: "同步知识库到 Git 仓库", |
| | | Long: `# git sync - 同步知识库到 Git 仓库 |
| | | kb-cli git sync |
| | | |
| | | 操作说明: |
| | | 1. 检查知识库目录是否是 Git 仓库 |
| | | 2. 执行 git add -A 添加所有变更 |
| | | 3. 如果有变更,执行 git commit(自动生成提交信息) |
| | | 4. 执行 git push 推送到远程仓库 |
| | | |
| | | 参数: |
| | | --vault <路径> 知识库根目录(默认:~/aisim/note/001/笔记001)`, |
| | | RunE: runGitSync, |
| | | } |
| | | |
| | | func init() { |
| | |
| | | indexCmd.AddCommand(indexBuildCmd) |
| | | indexCmd.AddCommand(indexStatusCmd) |
| | | indexCmd.AddCommand(indexGcCmd) |
| | | |
| | | rootCmd.AddCommand(gitCmd) |
| | | gitCmd.AddCommand(gitSyncCmd) |
| | | } |
| | | |
| | | func runIndexBuild(cmd *cobra.Command, args []string) error { |
| | |
| | | fmt.Fprintf(os.Stderr, "已清理 %d 个孤立节点\n", deletedCount) |
| | | return nil |
| | | } |
| | | |
| | | func runGitSync(cmd *cobra.Command, args []string) error { |
| | | // 展开 ~ 为实际路径 |
| | | expandedVaultPath := vaultPath |
| | | if strings.HasPrefix(vaultPath, "~/") { |
| | | home, err := os.UserHomeDir() |
| | | if err != nil { |
| | | return fmt.Errorf("获取用户目录失败: %w", err) |
| | | } |
| | | expandedVaultPath = filepath.Join(home, vaultPath[2:]) |
| | | } |
| | | |
| | | fmt.Fprintln(os.Stderr, "正在同步知识库到 Git 仓库...") |
| | | |
| | | // 检查是否是 git 仓库 |
| | | gitDir := filepath.Join(expandedVaultPath, ".git") |
| | | if _, err := os.Stat(gitDir); os.IsNotExist(err) { |
| | | return fmt.Errorf("知识库目录不是 Git 仓库: %s", expandedVaultPath) |
| | | } |
| | | |
| | | // 执行 git add -A |
| | | addCmd := exec.Command("git", "-C", expandedVaultPath, "add", "-A") |
| | | if output, err := addCmd.CombinedOutput(); err != nil { |
| | | return fmt.Errorf("git add 失败: %w\n%s", err, output) |
| | | } |
| | | |
| | | // 检查是否有变更 |
| | | statusCmd := exec.Command("git", "-C", expandedVaultPath, "status", "--porcelain") |
| | | statusOutput, err := statusCmd.Output() |
| | | if err != nil { |
| | | return fmt.Errorf("git status 失败: %w", err) |
| | | } |
| | | |
| | | if len(statusOutput) == 0 { |
| | | fmt.Fprintln(os.Stderr, "没有变更需要提交") |
| | | return nil |
| | | } |
| | | |
| | | // 生成 commit 信息 |
| | | commitMsg := fmt.Sprintf("kb-cli: 自动同步 %s", time.Now().Format("2006-01-02 15:04:05")) |
| | | commitCmd := exec.Command("git", "-C", expandedVaultPath, "commit", "-m", commitMsg) |
| | | if output, err := commitCmd.CombinedOutput(); err != nil { |
| | | return fmt.Errorf("git commit 失败: %w\n%s", err, output) |
| | | } |
| | | |
| | | // 执行 git push |
| | | pushCmd := exec.Command("git", "-C", expandedVaultPath, "push") |
| | | if output, err := pushCmd.CombinedOutput(); err != nil { |
| | | return fmt.Errorf("git push 失败: %w\n%s", err, output) |
| | | } |
| | | |
| | | fmt.Fprintln(os.Stderr, "Git 同步完成") |
| | | return nil |
| | | } |