1package server
2
3import (
4 "os"
5 "os/exec"
6 "path/filepath"
7 "strings"
8 "testing"
9)
10
11// TestSystemPromptIncludesCwdGuidanceFiles verifies that AGENTS.md from the working directory
12// is included in the generated system prompt.
13func TestSystemPromptIncludesCwdGuidanceFiles(t *testing.T) {
14 // Create a temp directory to serve as our "context directory"
15 tmpDir, err := os.MkdirTemp("", "shelley_test")
16 if err != nil {
17 t.Fatalf("failed to create temp dir: %v", err)
18 }
19 defer os.RemoveAll(tmpDir)
20
21 // Create an AGENTS.md file in the temp directory
22 agentsContent := "TEST_UNIQUE_CONTENT_12345: Always use Go for everything."
23 agentsFile := filepath.Join(tmpDir, "AGENTS.md")
24 if err := os.WriteFile(agentsFile, []byte(agentsContent), 0o644); err != nil {
25 t.Fatalf("failed to write AGENTS.md: %v", err)
26 }
27
28 // Generate system prompt for this directory
29 prompt, err := GenerateSystemPrompt(tmpDir)
30 if err != nil {
31 t.Fatalf("GenerateSystemPrompt failed: %v", err)
32 }
33
34 // Verify the unique content from AGENTS.md is included in the prompt
35 if !strings.Contains(prompt, "TEST_UNIQUE_CONTENT_12345") {
36 t.Errorf("system prompt should contain content from AGENTS.md in the working directory")
37 t.Logf("AGENTS.md content: %s", agentsContent)
38 t.Logf("Generated prompt (first 2000 chars): %s", prompt[:min(len(prompt), 2000)])
39 }
40
41 // Verify the file path is mentioned in guidance section
42 if !strings.Contains(prompt, agentsFile) {
43 t.Errorf("system prompt should reference the AGENTS.md file path")
44 }
45}
46
47// TestSystemPromptEmptyCwdFallsBackToCurrentDir verifies that an empty workingDir
48// causes GenerateSystemPrompt to use the current directory.
49func TestSystemPromptEmptyCwdFallsBackToCurrentDir(t *testing.T) {
50 // Get current directory for comparison
51 currentDir, err := os.Getwd()
52 if err != nil {
53 t.Fatalf("failed to get current directory: %v", err)
54 }
55
56 // Generate system prompt with empty workingDir
57 prompt, err := GenerateSystemPrompt("")
58 if err != nil {
59 t.Fatalf("GenerateSystemPrompt failed: %v", err)
60 }
61
62 // Verify the current directory is mentioned in the prompt
63 if !strings.Contains(prompt, currentDir) {
64 t.Errorf("system prompt should contain current directory when cwd is empty")
65 }
66}
67
68// TestSystemPromptDetectsGitInWorkingDir verifies that the system prompt
69// correctly detects a git repo in the specified working directory, not the
70// process's cwd. Regression test for https://github.com/boldsoftware/shelley/issues/71
71func TestSystemPromptDetectsGitInWorkingDir(t *testing.T) {
72 // Create a temp dir with a git repo
73 tmpDir, err := os.MkdirTemp("", "shelley_git_test")
74 if err != nil {
75 t.Fatalf("failed to create temp dir: %v", err)
76 }
77 defer os.RemoveAll(tmpDir)
78
79 // Initialize a git repo in the temp dir
80 cmd := exec.Command("git", "init")
81 cmd.Dir = tmpDir
82 if out, err := cmd.CombinedOutput(); err != nil {
83 t.Fatalf("git init failed: %v\n%s", err, out)
84 }
85 cmd = exec.Command("git", "commit", "--allow-empty", "-m", "initial")
86 cmd.Dir = tmpDir
87 if out, err := cmd.CombinedOutput(); err != nil {
88 t.Fatalf("git commit failed: %v\n%s", err, out)
89 }
90
91 // Generate system prompt for the git repo directory
92 prompt, err := GenerateSystemPrompt(tmpDir)
93 if err != nil {
94 t.Fatalf("GenerateSystemPrompt failed: %v", err)
95 }
96
97 // The prompt should say "Git repository root:" not "Not in a git repository"
98 if strings.Contains(prompt, "Not in a git repository") {
99 t.Errorf("system prompt incorrectly says 'Not in a git repository' for a directory that is a git repo")
100 }
101 if !strings.Contains(prompt, "Git repository root:") {
102 t.Errorf("system prompt should contain 'Git repository root:' for a git repo directory")
103 }
104 if !strings.Contains(prompt, tmpDir) {
105 t.Errorf("system prompt should reference the git root directory %s", tmpDir)
106 }
107}
108
109func min(a, b int) int {
110 if a < b {
111 return a
112 }
113 return b
114}
115
116// TestSystemPromptIncludesSkillsFromAnyWorkingDir verifies that user-level
117// skills (e.g. from ~/.config/agents/skills) appear in the system prompt
118// regardless of the conversation's working directory.
119// Regression test for https://github.com/boldsoftware/shelley/issues/83
120func TestSystemPromptIncludesSkillsFromAnyWorkingDir(t *testing.T) {
121 // Create a fake home with a skill
122 tmpHome := t.TempDir()
123 skillDir := filepath.Join(tmpHome, ".config", "agents", "skills", "test-skill")
124 if err := os.MkdirAll(skillDir, 0o755); err != nil {
125 t.Fatal(err)
126 }
127 if err := os.WriteFile(filepath.Join(skillDir, "SKILL.md"), []byte("---\nname: test-skill\ndescription: A test skill for issue 83.\n---\nInstructions.\n"), 0o644); err != nil {
128 t.Fatal(err)
129 }
130
131 oldHome := os.Getenv("HOME")
132 os.Setenv("HOME", tmpHome)
133 t.Cleanup(func() { os.Setenv("HOME", oldHome) })
134
135 // Generate system prompt from a directory completely unrelated to home
136 unrelatedDir := t.TempDir()
137 prompt, err := GenerateSystemPrompt(unrelatedDir)
138 if err != nil {
139 t.Fatalf("GenerateSystemPrompt failed: %v", err)
140 }
141
142 if !strings.Contains(prompt, "test-skill") {
143 t.Error("system prompt should contain skill 'test-skill' even when working dir is unrelated to home")
144 }
145 if !strings.Contains(prompt, "A test skill for issue 83.") {
146 t.Error("system prompt should contain the skill description")
147 }
148}