package cmd import ( "fmt" "os" "github.com/aisim/kb-cli/internal/draft" "github.com/aisim/kb-cli/internal/index" "github.com/spf13/cobra" ) var draftCmd = &cobra.Command{ Use: "draft", Short: "草稿管理", Long: `kb-cli draft create # 创建草稿(AI 生成 tags + 合并指示)`, } var draftCreateCmd = &cobra.Command{ Use: "create", Short: "创建草稿", Long: `kb-cli draft create --type <类型> --title <标题> --content-file <内容文件> [--source <来源>] [--force] 创建草稿,自动提取 tags 并生成合并指示。 类型: 售后/产品/运营/行业/TAPD 示例: kb-cli draft create --type 售后 --title "充不进气问题" --content-file /tmp/draft.md kb-cli draft create --type TAPD --title "档案下载失败" --content-file /tmp/bug.md --source "TAPD#12345"`, RunE: runDraftCreate, } var tagsCmd = &cobra.Command{ Use: "tags", Short: "标签管理", Long: `kb-cli tags rebuild # 批量重建现有文档的 tags`, } var tagsRebuildCmd = &cobra.Command{ Use: "rebuild", Short: "批量重建 tags", Long: `kb-cli tags rebuild [--vault <路径>] [--limit <数量>] [--dry-run] 批量重建现有文档的 tags,使用 LLM 重新提取。 示例: kb-cli tags rebuild --limit 10 # 重建前 10 个文档的 tags kb-cli tags rebuild --dry-run # 仅预览,不实际更新`, RunE: runTagsRebuild, } var ( draftType string draftTitle string draftContentFile string draftSource string draftForce bool tagsLimit int tagsDryRun bool ) func init() { // draft create 命令 draftCreateCmd.Flags().StringVar(&draftType, "type", "", "草稿类型(售后/产品/运营/行业/TAPD)") draftCreateCmd.Flags().StringVar(&draftTitle, "title", "", "草稿标题") draftCreateCmd.Flags().StringVar(&draftContentFile, "content-file", "", "草稿内容文件路径") draftCreateCmd.Flags().StringVar(&draftSource, "source", "", "来源标识") draftCreateCmd.Flags().BoolVar(&draftForce, "force", false, "强制创建(跳过重复检查)") draftCreateCmd.MarkFlagRequired("type") draftCreateCmd.MarkFlagRequired("title") draftCreateCmd.MarkFlagRequired("content-file") draftCmd.AddCommand(draftCreateCmd) // tags rebuild 命令 tagsRebuildCmd.Flags().IntVar(&tagsLimit, "limit", 0, "限制处理文档数量(0=全部)") tagsRebuildCmd.Flags().BoolVar(&tagsDryRun, "dry-run", false, "仅预览,不实际更新") tagsCmd.AddCommand(tagsRebuildCmd) rootCmd.AddCommand(draftCmd) rootCmd.AddCommand(tagsCmd) } func runDraftCreate(cmd *cobra.Command, args []string) error { // 读取内容文件 content, err := os.ReadFile(draftContentFile) if err != nil { return fmt.Errorf("读取内容文件失败: %w", err) } if len(content) == 0 { return fmt.Errorf("内容文件为空") } // 打开索引 store, err := index.Open(dbPath) if err != nil { return fmt.Errorf("打开索引失败: %w", err) } defer store.Close() // 创建草稿录入器 intake := draft.NewIntake(vaultPath, store) // 创建草稿 if err := intake.CreateDraft(draftType, draftTitle, string(content), draftSource, draftForce); err != nil { return fmt.Errorf("创建草稿失败: %w", err) } return nil } func runTagsRebuild(cmd *cobra.Command, args []string) error { // 打开索引 store, err := index.Open(dbPath) if err != nil { return fmt.Errorf("打开索引失败: %w", err) } defer store.Close() // 创建草稿录入器 intake := draft.NewIntake(vaultPath, store) // 重建 tags if err := intake.RebuildTags(tagsLimit, tagsDryRun); err != nil { return fmt.Errorf("重建 tags 失败: %w", err) } return nil }