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/root.go |   89 ++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 81 insertions(+), 8 deletions(-)

diff --git a/cmd/root.go b/cmd/root.go
index 0726524..83fa380 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -3,8 +3,10 @@
 import (
 	"fmt"
 	"os"
+	"strings"
 
 	"github.com/spf13/cobra"
+	"github.com/aisim/kb-cli/internal/llm"
 )
 
 var (
@@ -12,27 +14,98 @@
 	dbPath    string
 )
 
+// buildLong 为父命令动态生成 Long,格式:# cmd - Short\n子命令详细用法
+func buildLong(cmd *cobra.Command) string {
+	var sb strings.Builder
+	sb.WriteString(fmt.Sprintf("# %s - %s\n", cmd.Name(), cmd.Short))
+	for _, sub := range cmd.Commands() {
+		if sub.Hidden {
+			continue
+		}
+		if sub.Long != "" {
+			sb.WriteString(sub.Long)
+			// 确保 Long 末尾有换行
+			if !strings.HasSuffix(sub.Long, "\n") {
+				sb.WriteString("\n")
+			}
+		} else {
+			sb.WriteString(fmt.Sprintf("%s # %s\n", sub.CommandPath(), sub.Short))
+		}
+	}
+	return sb.String()
+}
+
 var rootCmd = &cobra.Command{
-	Use:   "kb",
-	Short: "知识库 CLI 工具",
-	Long:  "kb-cli: 知识库搜索与管理工具,支持知识图谱搜索",
+	Use:   "kb-cli",
+	Short: "知识库搜索与管理工具",
+	Long: `kb-cli - 知识库搜索与管理工具
+
+Global: [--vault <路径>] [--db <路径>]`,
 }
 
 func Execute() {
+	// 为每个父命令动态生成 Long(包含子命令详细用法)
+	for _, cmd := range rootCmd.Commands() {
+		if cmd.HasAvailableSubCommands() && !cmd.Hidden {
+			cmd.Long = buildLong(cmd)
+		}
+	}
+
+	// root Long = 头部 + 所有一级子命令的 Long
+	var sb strings.Builder
+	sb.WriteString(rootCmd.Long)
+	for _, cmd := range rootCmd.Commands() {
+		if cmd.Hidden {
+			continue
+		}
+		sb.WriteString("\n")
+		sb.WriteString(cmd.Long)
+	}
+	rootCmd.Long = sb.String()
+
 	if err := rootCmd.Execute(); err != nil {
-		fmt.Fprintln(os.Stderr, err)
-		os.Exit(1)
+		// 如果是参数不足的错误,显示对应命令的 help
+		errMsg := err.Error()
+		if strings.Contains(errMsg, "arg(s)") || strings.Contains(errMsg, "received") || strings.Contains(errMsg, "required flag") {
+			// 找到当前命令并显示其 help
+			cmd, _, findErr := rootCmd.Find(os.Args[1:])
+			if findErr == nil {
+				cmd.Help()
+			}
+			fmt.Println() // 空行
+		} else {
+			cobra.CheckErr(err)
+		}
 	}
 }
 
 func init() {
 	homeDir, _ := os.UserHomeDir()
-	defaultVault := os.Getenv("KB_VAULT")
+
+	// 从配置文件读取默认值(优先级:配置文件 > 环境变量 > 内置默认值)
+	cfg := llm.LoadConfig()
+	defaultVault := cfg.KnowledgeBase.VaultPath
+	defaultDB := cfg.KnowledgeBase.DBPath
+
+	// 如果配置文件没有设置,使用环境变量或默认值
 	if defaultVault == "" {
-		defaultVault = homeDir + "/aisim/note/001/笔记001"
+		defaultVault = os.Getenv("KB_VAULT")
+		if defaultVault == "" {
+			defaultVault = homeDir + "/aisim/note/001/笔记001"
+		}
 	}
-	defaultDB := homeDir + "/.cache/kb-cli/kb.db"
+	if defaultDB == "" {
+		defaultDB = homeDir + "/.cache/kb-cli/kb.db"
+	}
 
 	rootCmd.PersistentFlags().StringVar(&vaultPath, "vault", defaultVault, "知识库根目录")
 	rootCmd.PersistentFlags().StringVar(&dbPath, "db", defaultDB, "索引数据库路径")
+
+	// 自定义 help 模板:只输出 Long
+	helpTemplate := `{{.Long}}`
+	rootCmd.SetUsageTemplate(helpTemplate)
+	rootCmd.SetHelpTemplate(helpTemplate)
+
+	rootCmd.SilenceUsage = true
+	rootCmd.SilenceErrors = true
 }

--
Gitblit v1.9.1