package cmd import ( "fmt" "os" "path/filepath" "sort" "strings" "cliprepo/internal/config" "cliprepo/internal/resolver" "cliprepo/internal/tree" "cliprepo/internal/utils" "github.com/atotto/clipboard" "github.com/spf13/cobra" ) var delineate string var useClipboard bool var runCmd = &cobra.Command{ Use: "run", Short: "Generate LLM context from repo", RunE: func(cmd *cobra.Command, args []string) error { cfg, err := config.Load() if err != nil { return err } // 1. tree treeStr, err := tree.Generate(".") if err != nil { return err } var builder strings.Builder builder.WriteString(treeStr) builder.WriteString("\n\n") // 2. resolver (GLOBAL FILE REGISTRY) r := resolver.New(".") raw, ok := cfg.Preset[delineate] if !ok { return fmt.Errorf("preset not found: %s", delineate) } patterns := []string(raw) var files []string for _, pattern := range patterns { // ========================= // FULL REPO SCAN // ========================= if pattern == "*" { all, err := r.WalkAll() if err != nil { return err } files = append(files, all...) continue } // ========================= // recursive glob support // ========================= if strings.Contains(pattern, "**") { matches, err := utils.ExpandGlob([]string{pattern}) if err != nil { return err } for _, m := range matches { r.AddFile(m, &files) } continue } // ========================= // normal glob // ========================= matches, err := utils.ExpandGlob([]string{pattern}) if err != nil { return err } for _, m := range matches { r.AddFile(m, &files) } } // 3. dedup + stable order files = r.Unique(files) sort.Strings(files) // 4. template template := cfg.Prompts.Preset if template == "" { template = "The following code is from file {{path}}:\n---\n{{content}}" } // 5. render for _, file := range files { content, err := os.ReadFile(file) if err != nil { continue } // 先初始化 filePath 变量,避免作用域及同名包冲突 filePath := file if cfg.Config.PathMode == "absolute" { abs, _ := filepath.Abs(file) filePath = abs } block := strings.ReplaceAll(template, "{{path}}", filePath) block = strings.ReplaceAll(block, "{{content}}", string(content)) builder.WriteString(block) builder.WriteString("\n\n") } result := builder.String() // 6. output if useClipboard { return clipboard.WriteAll(result) } fmt.Println(result) return nil }, } func init() { rootCmd.AddCommand(runCmd) runCmd.Flags().StringVar(&delineate, "delineate", "", "preset key") runCmd.Flags().BoolVar(&useClipboard, "clipboard", false, "copy output to clipboard") }