1package prompt
2
3import (
4 "os"
5 "path/filepath"
6 "strings"
7 "sync"
8
9 "github.com/charmbracelet/crush/internal/config"
10)
11
12type PromptID string
13
14const (
15 PromptCoder PromptID = "coder"
16 PromptTitle PromptID = "title"
17 PromptTask PromptID = "task"
18 PromptSummarizer PromptID = "summarizer"
19 PromptDefault PromptID = "default"
20)
21
22func GetPrompt(promptID PromptID, provider string, contextPaths ...string) string {
23 basePrompt := ""
24 switch promptID {
25 case PromptCoder:
26 basePrompt = CoderPrompt(provider)
27 case PromptTitle:
28 basePrompt = TitlePrompt()
29 case PromptTask:
30 basePrompt = TaskPrompt()
31 case PromptSummarizer:
32 basePrompt = SummarizerPrompt()
33 default:
34 basePrompt = "You are a helpful assistant"
35 }
36 return basePrompt
37}
38
39func getContextFromPaths(contextPaths []string) string {
40 return processContextPaths(config.Get().WorkingDir(), contextPaths)
41}
42
43func processContextPaths(workDir string, paths []string) string {
44 var (
45 wg sync.WaitGroup
46 resultCh = make(chan string)
47 )
48
49 // Track processed files to avoid duplicates
50 processedFiles := make(map[string]bool)
51 var processedMutex sync.Mutex
52
53 for _, path := range paths {
54 wg.Add(1)
55 go func(p string) {
56 defer wg.Done()
57
58 if strings.HasSuffix(p, "/") {
59 filepath.WalkDir(filepath.Join(workDir, p), func(path string, d os.DirEntry, err error) error {
60 if err != nil {
61 return err
62 }
63 if !d.IsDir() {
64 // Check if we've already processed this file (case-insensitive)
65 lowerPath := strings.ToLower(path)
66
67 processedMutex.Lock()
68 alreadyProcessed := processedFiles[lowerPath]
69 if !alreadyProcessed {
70 processedFiles[lowerPath] = true
71 }
72 processedMutex.Unlock()
73
74 if !alreadyProcessed {
75 if result := processFile(path); result != "" {
76 resultCh <- result
77 }
78 }
79 }
80 return nil
81 })
82 } else {
83 fullPath := filepath.Join(workDir, p)
84
85 // Check if we've already processed this file (case-insensitive)
86 lowerPath := strings.ToLower(fullPath)
87
88 processedMutex.Lock()
89 alreadyProcessed := processedFiles[lowerPath]
90 if !alreadyProcessed {
91 processedFiles[lowerPath] = true
92 }
93 processedMutex.Unlock()
94
95 if !alreadyProcessed {
96 result := processFile(fullPath)
97 if result != "" {
98 resultCh <- result
99 }
100 }
101 }
102 }(path)
103 }
104
105 go func() {
106 wg.Wait()
107 close(resultCh)
108 }()
109
110 results := make([]string, 0)
111 for result := range resultCh {
112 results = append(results, result)
113 }
114
115 return strings.Join(results, "\n")
116}
117
118func processFile(filePath string) string {
119 content, err := os.ReadFile(filePath)
120 if err != nil {
121 return ""
122 }
123 return "# From:" + filePath + "\n" + string(content)
124}