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