From 1196f409d86bc61e7596eb274840244a62ce84ba Mon Sep 17 00:00:00 2001
From: ai_xiaopei <xiaopei@aisim.cn>
Date: Wed, 29 Jul 2026 14:58:19 +0800
Subject: [PATCH] feat: config priority over env vars, export LoadConfig, add review feature

---
 cmd/draft.go |  130 ++++++++++++++++++++++++++++++++++++-------
 1 files changed, 108 insertions(+), 22 deletions(-)

diff --git a/cmd/draft.go b/cmd/draft.go
index 32d280c..4341371 100644
--- a/cmd/draft.go
+++ b/cmd/draft.go
@@ -1,6 +1,7 @@
 package cmd
 
 import (
+	"encoding/json"
 	"fmt"
 	"os"
 
@@ -12,21 +13,35 @@
 var draftCmd = &cobra.Command{
 	Use:   "draft",
 	Short: "草稿管理",
-	Long:  `kb-cli draft create # 创建草稿(AI 生成 tags + 合并指示)`,
+	Long: `# draft - 草稿管理
+kb-cli draft create --type <类型> --title <标题> --content-file <文件> [--source <来源>] [--force] # 创建草稿(AI 提取 tags + 生成合并指示)
+kb-cli draft list [--json] # 列出待审阅区的所有活跃草稿
+kb-cli draft convert [目录名] # 转换老格式单文件草稿到新格式(NNN-标题/draft.md + merge.md)`,
 }
 
 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"`,
+	Long: `# draft create - 创建草稿
+kb-cli draft create --type <类型> --title <标题> --content-file <文件> [--source <来源>] [--force] # 创建草稿,自动提取 tags 并生成合并指示`,
 	RunE: runDraftCreate,
+}
+
+var draftListCmd = &cobra.Command{
+	Use:   "list",
+	Short: "列出所有活跃草稿",
+	Long: `# draft list - 列出所有活跃草稿
+kb-cli draft list [--json] # 列出待审阅区的所有草稿(目录结构 + 老格式单文件)`,
+	RunE: runDraftList,
+}
+
+var draftConvertCmd = &cobra.Command{
+	Use:   "convert [目录名]",
+	Short: "转换老格式草稿到新格式",
+	Long: `# draft convert - 转换老格式草稿到新格式
+kb-cli draft convert # 扫描所有待审阅子目录,转换老格式单文件
+kb-cli draft convert TAPD提取 # 只转换指定子目录`,
+	RunE: runDraftConvert,
 }
 
 var tagsCmd = &cobra.Command{
@@ -38,24 +53,21 @@
 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            # 仅预览,不实际更新`,
+	Long:  `# tags rebuild - 批量重建 tags
+kb-cli tags rebuild [--vault <路径>] [--limit <数量>] [--dry-run] # 使用 LLM 重新提取现有文档的 tags`,
 	RunE: runTagsRebuild,
 }
 
 var (
-	draftType       string
-	draftTitle      string
+	draftType        string
+	draftTitle       string
 	draftContentFile string
-	draftSource     string
-	draftForce      bool
-	tagsLimit       int
-	tagsDryRun      bool
+	draftSource      string
+	draftForce       bool
+	draftJSON        bool
+	tagsLimit        int
+	tagsDryRun       bool
+	convertTarget    string
 )
 
 func init() {
@@ -69,7 +81,14 @@
 	draftCreateCmd.MarkFlagRequired("title")
 	draftCreateCmd.MarkFlagRequired("content-file")
 
+	// draft list 命令
+	draftListCmd.Flags().BoolVar(&draftJSON, "json", false, "JSON 格式输出")
+
+	// draft convert 命令(无额外参数,target 从 args 读取)
+
 	draftCmd.AddCommand(draftCreateCmd)
+	draftCmd.AddCommand(draftListCmd)
+	draftCmd.AddCommand(draftConvertCmd)
 
 	// tags rebuild 命令
 	tagsRebuildCmd.Flags().IntVar(&tagsLimit, "limit", 0, "限制处理文档数量(0=全部)")
@@ -128,3 +147,70 @@
 
 	return nil
 }
+
+// runDraftList 列出所有活跃草稿
+func runDraftList(cmd *cobra.Command, args []string) error {
+	// 创建草稿录入器
+	intake := draft.NewIntake(vaultPath, nil)
+
+	// 列出草稿
+	drafts, err := intake.ListDrafts()
+	if err != nil {
+		return fmt.Errorf("列出草稿失败: %w", err)
+	}
+
+	if draftJSON {
+		// JSON 输出
+		output := struct {
+			Drafts []draft.DraftInfo `json:"drafts"`
+			Total  int               `json:"total"`
+		}{
+			Drafts: drafts,
+			Total:  len(drafts),
+		}
+		encoder := json.NewEncoder(os.Stdout)
+		encoder.SetIndent("", "  ")
+		return encoder.Encode(output)
+	}
+
+	// 表格输出
+	if len(drafts) == 0 {
+		fmt.Println("没有活跃草稿")
+		return nil
+	}
+
+	fmt.Printf("找到 %d 个活跃草稿:\n\n", len(drafts))
+	for _, d := range drafts {
+		mergeStatus := "❌"
+		if d.HasMergeHint {
+			mergeStatus = "✅"
+		}
+		fmt.Printf("• %s\n", d.Title)
+		fmt.Printf("  路径: %s\n", d.Filepath)
+		fmt.Printf("  类型: %s | 状态: %s | 合并指示: %s\n", d.Type, d.Status, mergeStatus)
+		fmt.Printf("  创建: %s\n\n", d.Created)
+	}
+
+	return nil
+}
+
+// runDraftConvert 转换老格式草稿到新格式
+func runDraftConvert(cmd *cobra.Command, args []string) error {
+	// 可选参数:指定子目录
+	target := ""
+	if len(args) > 0 {
+		target = args[0]
+	}
+
+	// 创建草稿录入器
+	intake := draft.NewIntake(vaultPath, nil)
+
+	// 转换草稿
+	converted, err := intake.ConvertOldDrafts(target)
+	if err != nil {
+		return fmt.Errorf("转换草稿失败: %w", err)
+	}
+
+	fmt.Printf("\n✅ 成功转换 %d 个草稿\n", converted)
+	return nil
+}

--
Gitblit v1.9.1