1package prompt
2
3import (
4 "context"
5 _ "embed"
6 "fmt"
7 "log/slog"
8 "os"
9 "path/filepath"
10 "runtime"
11 "time"
12
13 "github.com/charmbracelet/crush/internal/config"
14 "github.com/charmbracelet/crush/internal/llm/tools"
15)
16
17func CoderPrompt(p string, contextFiles ...string) string {
18 var basePrompt string
19
20 basePrompt = string(baseCoderPrompt)
21 envInfo := getEnvironmentInfo()
22
23 basePrompt = fmt.Sprintf("%s\n\n%s\n%s", basePrompt, envInfo, lspInformation())
24
25 contextContent := getContextFromPaths(config.Get().WorkingDir(), contextFiles)
26 slog.Debug("Context content", "Context", contextContent)
27 if contextContent != "" {
28 return fmt.Sprintf("%s\n\n# Project-Specific Context\n Make sure to follow the instructions in the context below\n%s", basePrompt, contextContent)
29 }
30 return basePrompt
31}
32
33//go:embed coder.md
34var baseCoderPrompt []byte
35
36func getEnvironmentInfo() string {
37 cwd := config.Get().WorkingDir()
38 isGit := isGitRepo(cwd)
39 platform := runtime.GOOS
40 date := time.Now().Format("1/2/2006")
41 ls := tools.NewLsTool(cwd)
42 r, _ := ls.Run(context.Background(), tools.ToolCall{
43 Input: `{"path":"."}`,
44 })
45 return fmt.Sprintf(`Here is useful information about the environment you are running in:
46<env>
47Working directory: %s
48Is directory a git repo: %s
49Platform: %s
50Today's date: %s
51</env>
52<project>
53%s
54</project>
55 `, cwd, boolToYesNo(isGit), platform, date, r.Content)
56}
57
58func isGitRepo(dir string) bool {
59 _, err := os.Stat(filepath.Join(dir, ".git"))
60 return err == nil
61}
62
63func lspInformation() string {
64 cfg := config.Get()
65 hasLSP := false
66 for _, v := range cfg.LSP {
67 if !v.Disabled {
68 hasLSP = true
69 break
70 }
71 }
72 if !hasLSP {
73 return ""
74 }
75 return `# LSP Information
76Tools that support it will also include useful diagnostics such as linting and typechecking.
77- These diagnostics will be automatically enabled when you run the tool, and will be displayed in the output at the bottom within the <file_diagnostics></file_diagnostics> and <project_diagnostics></project_diagnostics> tags.
78- Take necessary actions to fix the issues.
79- You should ignore diagnostics of files that you did not change or are not related or caused by your changes unless the user explicitly asks you to fix them.
80`
81}
82
83func boolToYesNo(b bool) string {
84 if b {
85 return "Yes"
86 }
87 return "No"
88}