cwd_test.go

  1package server
  2
  3import (
  4	"context"
  5	"encoding/json"
  6	"net/http"
  7	"net/http/httptest"
  8	"os"
  9	"os/exec"
 10	"path/filepath"
 11	"strings"
 12	"testing"
 13
 14	"shelley.exe.dev/db/generated"
 15	"shelley.exe.dev/llm"
 16)
 17
 18// TestWorkingDirectoryConfiguration tests that the working directory (cwd) setting
 19// is properly passed through from HTTP requests to tool execution.
 20func TestWorkingDirectoryConfiguration(t *testing.T) {
 21	h := NewTestHarness(t)
 22	defer h.Close()
 23
 24	t.Run("cwd_tmp", func(t *testing.T) {
 25		h.NewConversation("bash: pwd", "/tmp")
 26		result := strings.TrimSpace(h.WaitToolResult())
 27		// Resolve symlinks for comparison (on macOS, /tmp -> /private/tmp)
 28		expected, _ := filepath.EvalSymlinks("/tmp")
 29		if result != expected {
 30			t.Errorf("expected %q, got: %s", expected, result)
 31		}
 32	})
 33
 34	t.Run("cwd_root", func(t *testing.T) {
 35		h.NewConversation("bash: pwd", "/")
 36		result := strings.TrimSpace(h.WaitToolResult())
 37		if result != "/" {
 38			t.Errorf("expected '/', got: %s", result)
 39		}
 40	})
 41}
 42
 43// TestListDirectory tests the list-directory API endpoint used by the directory picker.
 44func TestListDirectory(t *testing.T) {
 45	h := NewTestHarness(t)
 46	defer h.Close()
 47
 48	t.Run("list_tmp", func(t *testing.T) {
 49		req := httptest.NewRequest("GET", "/api/list-directory?path=/tmp", nil)
 50		w := httptest.NewRecorder()
 51		h.server.handleListDirectory(w, req)
 52
 53		if w.Code != http.StatusOK {
 54			t.Fatalf("expected status 200, got %d: %s", w.Code, w.Body.String())
 55		}
 56
 57		var resp ListDirectoryResponse
 58		if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
 59			t.Fatalf("failed to parse response: %v", err)
 60		}
 61
 62		if resp.Path != "/tmp" {
 63			t.Errorf("expected path '/tmp', got: %s", resp.Path)
 64		}
 65
 66		if resp.Parent != "/" {
 67			t.Errorf("expected parent '/', got: %s", resp.Parent)
 68		}
 69	})
 70
 71	t.Run("list_root", func(t *testing.T) {
 72		req := httptest.NewRequest("GET", "/api/list-directory?path=/", nil)
 73		w := httptest.NewRecorder()
 74		h.server.handleListDirectory(w, req)
 75
 76		if w.Code != http.StatusOK {
 77			t.Fatalf("expected status 200, got %d: %s", w.Code, w.Body.String())
 78		}
 79
 80		var resp ListDirectoryResponse
 81		if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
 82			t.Fatalf("failed to parse response: %v", err)
 83		}
 84
 85		if resp.Path != "/" {
 86			t.Errorf("expected path '/', got: %s", resp.Path)
 87		}
 88
 89		// Root should have no parent
 90		if resp.Parent != "" {
 91			t.Errorf("expected no parent, got: %s", resp.Parent)
 92		}
 93
 94		// Root should have at least some directories (tmp, etc, home, etc.)
 95		if len(resp.Entries) == 0 {
 96			t.Error("expected at least some entries in root")
 97		}
 98	})
 99
100	t.Run("list_default_path", func(t *testing.T) {
101		req := httptest.NewRequest("GET", "/api/list-directory", nil)
102		w := httptest.NewRecorder()
103		h.server.handleListDirectory(w, req)
104
105		if w.Code != http.StatusOK {
106			t.Fatalf("expected status 200, got %d: %s", w.Code, w.Body.String())
107		}
108
109		var resp ListDirectoryResponse
110		if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
111			t.Fatalf("failed to parse response: %v", err)
112		}
113
114		// Should default to home directory
115		homeDir, _ := os.UserHomeDir()
116		if homeDir != "" && resp.Path != homeDir {
117			t.Errorf("expected path '%s', got: %s", homeDir, resp.Path)
118		}
119	})
120
121	t.Run("list_nonexistent", func(t *testing.T) {
122		req := httptest.NewRequest("GET", "/api/list-directory?path=/nonexistent/path/123456", nil)
123		w := httptest.NewRecorder()
124		h.server.handleListDirectory(w, req)
125
126		if w.Code != http.StatusOK {
127			t.Fatalf("expected status 200, got %d: %s", w.Code, w.Body.String())
128		}
129
130		var resp map[string]interface{}
131		if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
132			t.Fatalf("failed to parse response: %v", err)
133		}
134
135		if resp["error"] == nil {
136			t.Error("expected error field in response")
137		}
138	})
139
140	t.Run("list_file_not_directory", func(t *testing.T) {
141		// Create a temp file
142		f, err := os.CreateTemp("", "test")
143		if err != nil {
144			t.Fatalf("failed to create temp file: %v", err)
145		}
146		defer os.Remove(f.Name())
147		f.Close()
148
149		req := httptest.NewRequest("GET", "/api/list-directory?path="+f.Name(), nil)
150		w := httptest.NewRecorder()
151		h.server.handleListDirectory(w, req)
152
153		if w.Code != http.StatusOK {
154			t.Fatalf("expected status 200, got %d: %s", w.Code, w.Body.String())
155		}
156
157		var resp map[string]interface{}
158		if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
159			t.Fatalf("failed to parse response: %v", err)
160		}
161
162		errMsg, ok := resp["error"].(string)
163		if !ok || errMsg != "path is not a directory" {
164			t.Errorf("expected error 'path is not a directory', got: %v", resp["error"])
165		}
166	})
167
168	t.Run("only_directories_returned", func(t *testing.T) {
169		// Create a temp directory with both files and directories
170		tmpDir, err := os.MkdirTemp("", "listdir_test")
171		if err != nil {
172			t.Fatalf("failed to create temp dir: %v", err)
173		}
174		defer os.RemoveAll(tmpDir)
175
176		// Create a subdirectory
177		subDir := tmpDir + "/subdir"
178		if err := os.Mkdir(subDir, 0o755); err != nil {
179			t.Fatalf("failed to create subdir: %v", err)
180		}
181
182		// Create a file
183		file := tmpDir + "/file.txt"
184		if err := os.WriteFile(file, []byte("test"), 0o644); err != nil {
185			t.Fatalf("failed to create file: %v", err)
186		}
187
188		req := httptest.NewRequest("GET", "/api/list-directory?path="+tmpDir, nil)
189		w := httptest.NewRecorder()
190		h.server.handleListDirectory(w, req)
191
192		if w.Code != http.StatusOK {
193			t.Fatalf("expected status 200, got %d: %s", w.Code, w.Body.String())
194		}
195
196		var resp ListDirectoryResponse
197		if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
198			t.Fatalf("failed to parse response: %v", err)
199		}
200
201		// Should only include the directory, not the file
202		if len(resp.Entries) != 1 {
203			t.Errorf("expected 1 entry, got: %d", len(resp.Entries))
204		}
205
206		if len(resp.Entries) > 0 && resp.Entries[0].Name != "subdir" {
207			t.Errorf("expected entry 'subdir', got: %s", resp.Entries[0].Name)
208		}
209	})
210
211	t.Run("hidden_directories_sorted_last", func(t *testing.T) {
212		// Create a temp directory with hidden and non-hidden directories
213		tmpDir, err := os.MkdirTemp("", "listdir_hidden_test")
214		if err != nil {
215			t.Fatalf("failed to create temp dir: %v", err)
216		}
217		defer os.RemoveAll(tmpDir)
218
219		for _, name := range []string{".alpha", "beta", ".gamma", "delta", "alpha"} {
220			if err := os.Mkdir(filepath.Join(tmpDir, name), 0o755); err != nil {
221				t.Fatalf("failed to create dir %s: %v", name, err)
222			}
223		}
224
225		req := httptest.NewRequest("GET", "/api/list-directory?path="+tmpDir, nil)
226		w := httptest.NewRecorder()
227		h.server.handleListDirectory(w, req)
228
229		if w.Code != http.StatusOK {
230			t.Fatalf("expected status 200, got %d: %s", w.Code, w.Body.String())
231		}
232
233		var resp ListDirectoryResponse
234		if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
235			t.Fatalf("failed to parse response: %v", err)
236		}
237
238		if len(resp.Entries) != 5 {
239			t.Fatalf("expected 5 entries, got: %d", len(resp.Entries))
240		}
241
242		// Non-hidden sorted first, then hidden sorted
243		want := []string{"alpha", "beta", "delta", ".alpha", ".gamma"}
244		for i, e := range resp.Entries {
245			if e.Name != want[i] {
246				t.Errorf("entry[%d]: expected %q, got %q", i, want[i], e.Name)
247			}
248		}
249	})
250
251	t.Run("git_repo_head_subject", func(t *testing.T) {
252		// Create a temp directory containing a git repo
253		tmpDir, err := os.MkdirTemp("", "listdir_git_test")
254		if err != nil {
255			t.Fatalf("failed to create temp dir: %v", err)
256		}
257		defer os.RemoveAll(tmpDir)
258
259		// Create a subdirectory that will be a git repo
260		repoDir := tmpDir + "/myrepo"
261		if err := os.Mkdir(repoDir, 0o755); err != nil {
262			t.Fatalf("failed to create repo dir: %v", err)
263		}
264
265		// Initialize git repo and create a commit
266		cmd := exec.Command("git", "init")
267		cmd.Dir = repoDir
268		if err := cmd.Run(); err != nil {
269			t.Fatalf("failed to init git: %v", err)
270		}
271
272		cmd = exec.Command("git", "config", "user.email", "test@example.com")
273		cmd.Dir = repoDir
274		if err := cmd.Run(); err != nil {
275			t.Fatalf("failed to config git email: %v", err)
276		}
277
278		cmd = exec.Command("git", "config", "user.name", "Test User")
279		cmd.Dir = repoDir
280		if err := cmd.Run(); err != nil {
281			t.Fatalf("failed to config git name: %v", err)
282		}
283
284		// Create a file and commit it
285		if err := os.WriteFile(repoDir+"/README.md", []byte("# Hello"), 0o644); err != nil {
286			t.Fatalf("failed to write file: %v", err)
287		}
288
289		cmd = exec.Command("git", "add", "README.md")
290		cmd.Dir = repoDir
291		if err := cmd.Run(); err != nil {
292			t.Fatalf("failed to git add: %v", err)
293		}
294
295		cmd = exec.Command("git", "commit", "-m", "Test commit subject line\n\nPrompt: test")
296		cmd.Dir = repoDir
297		if err := cmd.Run(); err != nil {
298			t.Fatalf("failed to git commit: %v", err)
299		}
300
301		// Create another directory that is not a git repo
302		nonRepoDir := tmpDir + "/notarepo"
303		if err := os.Mkdir(nonRepoDir, 0o755); err != nil {
304			t.Fatalf("failed to create non-repo dir: %v", err)
305		}
306
307		req := httptest.NewRequest("GET", "/api/list-directory?path="+tmpDir, nil)
308		w := httptest.NewRecorder()
309		h.server.handleListDirectory(w, req)
310
311		if w.Code != http.StatusOK {
312			t.Fatalf("expected status 200, got %d: %s", w.Code, w.Body.String())
313		}
314
315		var resp ListDirectoryResponse
316		if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
317			t.Fatalf("failed to parse response: %v", err)
318		}
319
320		if len(resp.Entries) != 2 {
321			t.Fatalf("expected 2 entries, got: %d", len(resp.Entries))
322		}
323
324		// Find the git repo entry and verify it has the commit subject
325		var gitEntry, nonGitEntry *DirectoryEntry
326		for i := range resp.Entries {
327			if resp.Entries[i].Name == "myrepo" {
328				gitEntry = &resp.Entries[i]
329			} else if resp.Entries[i].Name == "notarepo" {
330				nonGitEntry = &resp.Entries[i]
331			}
332		}
333
334		if gitEntry == nil {
335			t.Fatal("expected to find myrepo entry")
336		}
337		if nonGitEntry == nil {
338			t.Fatal("expected to find notarepo entry")
339		}
340
341		// Git repo should have the HEAD commit subject
342		if gitEntry.GitHeadSubject != "Test commit subject line" {
343			t.Errorf("expected git_head_subject 'Test commit subject line', got: %q", gitEntry.GitHeadSubject)
344		}
345
346		// Non-git dir should not have a subject
347		if nonGitEntry.GitHeadSubject != "" {
348			t.Errorf("expected empty git_head_subject for non-git dir, got: %q", nonGitEntry.GitHeadSubject)
349		}
350	})
351
352	t.Run("git_worktree_root", func(t *testing.T) {
353		// Create a main git repo and a worktree, then verify that
354		// listing the worktree returns git_worktree_root pointing to the main repo.
355		tmpDir, err := os.MkdirTemp("", "listdir_wtroot_test")
356		if err != nil {
357			t.Fatalf("failed to create temp dir: %v", err)
358		}
359		defer os.RemoveAll(tmpDir)
360
361		mainRepo := filepath.Join(tmpDir, "main-repo")
362		if err := os.Mkdir(mainRepo, 0o755); err != nil {
363			t.Fatalf("failed to create main repo dir: %v", err)
364		}
365
366		for _, args := range [][]string{
367			{"git", "init"},
368			{"git", "config", "user.email", "test@example.com"},
369			{"git", "config", "user.name", "Test User"},
370		} {
371			cmd := exec.Command(args[0], args[1:]...)
372			cmd.Dir = mainRepo
373			if err := cmd.Run(); err != nil {
374				t.Fatalf("%v failed: %v", args, err)
375			}
376		}
377
378		if err := os.WriteFile(filepath.Join(mainRepo, "README.md"), []byte("# Hi"), 0o644); err != nil {
379			t.Fatal(err)
380		}
381		cmd := exec.Command("git", "add", ".")
382		cmd.Dir = mainRepo
383		if err := cmd.Run(); err != nil {
384			t.Fatal(err)
385		}
386		cmd = exec.Command("git", "commit", "-m", "init\n\nPrompt: test")
387		cmd.Dir = mainRepo
388		if err := cmd.Run(); err != nil {
389			t.Fatal(err)
390		}
391
392		// Create a worktree
393		cmd = exec.Command("git", "branch", "wt-branch")
394		cmd.Dir = mainRepo
395		if err := cmd.Run(); err != nil {
396			t.Fatal(err)
397		}
398		worktreePath := filepath.Join(tmpDir, "my-worktree")
399		cmd = exec.Command("git", "worktree", "add", worktreePath, "wt-branch")
400		cmd.Dir = mainRepo
401		if err := cmd.Run(); err != nil {
402			t.Fatal(err)
403		}
404
405		// List the worktree directory itself - should have git_worktree_root
406		req := httptest.NewRequest("GET", "/api/list-directory?path="+worktreePath, nil)
407		w := httptest.NewRecorder()
408		h.server.handleListDirectory(w, req)
409
410		var resp ListDirectoryResponse
411		if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
412			t.Fatalf("failed to parse response: %v", err)
413		}
414		if resp.GitWorktreeRoot != mainRepo {
415			t.Errorf("expected git_worktree_root=%q, got %q", mainRepo, resp.GitWorktreeRoot)
416		}
417
418		// List the main repo directory - should NOT have git_worktree_root
419		req = httptest.NewRequest("GET", "/api/list-directory?path="+mainRepo, nil)
420		w = httptest.NewRecorder()
421		h.server.handleListDirectory(w, req)
422
423		var resp2 ListDirectoryResponse
424		if err := json.Unmarshal(w.Body.Bytes(), &resp2); err != nil {
425			t.Fatalf("failed to parse response: %v", err)
426		}
427		if resp2.GitWorktreeRoot != "" {
428			t.Errorf("main repo should not have git_worktree_root, got %q", resp2.GitWorktreeRoot)
429		}
430	})
431
432	t.Run("git_worktree_head_subject", func(t *testing.T) {
433		// Create a temp directory containing a git repo and a worktree
434		tmpDir, err := os.MkdirTemp("", "listdir_worktree_test")
435		if err != nil {
436			t.Fatalf("failed to create temp dir: %v", err)
437		}
438		defer os.RemoveAll(tmpDir)
439
440		// Create a main git repo
441		mainRepo := tmpDir + "/main-repo"
442		if err := os.Mkdir(mainRepo, 0o755); err != nil {
443			t.Fatalf("failed to create main repo dir: %v", err)
444		}
445
446		// Initialize git repo and create a commit
447		cmd := exec.Command("git", "init")
448		cmd.Dir = mainRepo
449		if err := cmd.Run(); err != nil {
450			t.Fatalf("failed to init git: %v", err)
451		}
452
453		cmd = exec.Command("git", "config", "user.email", "test@example.com")
454		cmd.Dir = mainRepo
455		if err := cmd.Run(); err != nil {
456			t.Fatalf("failed to config git email: %v", err)
457		}
458
459		cmd = exec.Command("git", "config", "user.name", "Test User")
460		cmd.Dir = mainRepo
461		if err := cmd.Run(); err != nil {
462			t.Fatalf("failed to config git name: %v", err)
463		}
464
465		// Create a file and commit it
466		if err := os.WriteFile(mainRepo+"/README.md", []byte("# Hello"), 0o644); err != nil {
467			t.Fatalf("failed to write file: %v", err)
468		}
469
470		cmd = exec.Command("git", "add", "README.md")
471		cmd.Dir = mainRepo
472		if err := cmd.Run(); err != nil {
473			t.Fatalf("failed to git add: %v", err)
474		}
475
476		cmd = exec.Command("git", "commit", "-m", "Main repo commit\n\nPrompt: test")
477		cmd.Dir = mainRepo
478		if err := cmd.Run(); err != nil {
479			t.Fatalf("failed to git commit: %v", err)
480		}
481
482		// Create a branch and worktree
483		cmd = exec.Command("git", "branch", "feature-branch")
484		cmd.Dir = mainRepo
485		if err := cmd.Run(); err != nil {
486			t.Fatalf("failed to create branch: %v", err)
487		}
488
489		worktreePath := tmpDir + "/worktree-dir"
490		cmd = exec.Command("git", "worktree", "add", worktreePath, "feature-branch")
491		cmd.Dir = mainRepo
492		if err := cmd.Run(); err != nil {
493			t.Fatalf("failed to create worktree: %v", err)
494		}
495
496		// Verify the worktree has a .git file (not directory)
497		gitPath := worktreePath + "/.git"
498		fi, err := os.Stat(gitPath)
499		if err != nil {
500			t.Fatalf("failed to stat worktree .git: %v", err)
501		}
502		if fi.IsDir() {
503			t.Fatalf("expected .git to be a file for worktree, got directory")
504		}
505
506		req := httptest.NewRequest("GET", "/api/list-directory?path="+tmpDir, nil)
507		w := httptest.NewRecorder()
508		h.server.handleListDirectory(w, req)
509
510		if w.Code != http.StatusOK {
511			t.Fatalf("expected status 200, got %d: %s", w.Code, w.Body.String())
512		}
513
514		var resp ListDirectoryResponse
515		if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
516			t.Fatalf("failed to parse response: %v", err)
517		}
518
519		// Find the worktree entry and verify it has the commit subject
520		var worktreeEntry *DirectoryEntry
521		for i := range resp.Entries {
522			if resp.Entries[i].Name == "worktree-dir" {
523				worktreeEntry = &resp.Entries[i]
524			}
525		}
526
527		if worktreeEntry == nil {
528			t.Fatal("expected to find worktree-dir entry")
529		}
530
531		// Worktree should have the HEAD commit subject
532		if worktreeEntry.GitHeadSubject != "Main repo commit" {
533			t.Errorf("expected git_head_subject 'Main repo commit', got: %q", worktreeEntry.GitHeadSubject)
534		}
535	})
536}
537
538// TestConversationCwdReturnedInList tests that CWD is returned in the conversations list.
539func TestConversationCwdReturnedInList(t *testing.T) {
540	h := NewTestHarness(t)
541	defer h.Close()
542
543	// Create a conversation with a specific CWD
544	h.NewConversation("bash: pwd", "/tmp")
545	h.WaitToolResult() // Wait for the conversation to complete
546
547	// Get the conversations list
548	req := httptest.NewRequest("GET", "/api/conversations", nil)
549	w := httptest.NewRecorder()
550	h.server.handleConversations(w, req)
551
552	if w.Code != http.StatusOK {
553		t.Fatalf("expected status 200, got %d: %s", w.Code, w.Body.String())
554	}
555
556	var convs []map[string]interface{}
557	if err := json.Unmarshal(w.Body.Bytes(), &convs); err != nil {
558		t.Fatalf("failed to parse response: %v", err)
559	}
560
561	if len(convs) == 0 {
562		t.Fatal("expected at least one conversation")
563	}
564
565	// Find our conversation
566	found := false
567	for _, conv := range convs {
568		if conv["conversation_id"] == h.ConversationID() {
569			found = true
570			cwd, ok := conv["cwd"].(string)
571			if !ok {
572				t.Errorf("expected cwd to be a string, got: %T", conv["cwd"])
573			}
574			if cwd != "/tmp" {
575				t.Errorf("expected cwd '/tmp', got: %s", cwd)
576			}
577			break
578		}
579	}
580
581	if !found {
582		t.Error("conversation not found in list")
583	}
584}
585
586// TestSystemPromptUsesCwdFromConversation verifies that when a conversation
587// is created with a specific cwd, the system prompt is generated using that
588// directory (not the server's working directory). This tests the fix for
589// https://github.com/boldsoftware/shelley/issues/30
590func TestSystemPromptUsesCwdFromConversation(t *testing.T) {
591	// Create a temp directory with an AGENTS.md file
592	tmpDir, err := os.MkdirTemp("", "shelley_cwd_test")
593	if err != nil {
594		t.Fatalf("failed to create temp dir: %v", err)
595	}
596	defer os.RemoveAll(tmpDir)
597
598	// Create an AGENTS.md file with unique content we can search for
599	agentsContent := "UNIQUE_MARKER_FOR_CWD_TEST_XYZ123: This is test guidance."
600	agentsFile := filepath.Join(tmpDir, "AGENTS.md")
601	if err := os.WriteFile(agentsFile, []byte(agentsContent), 0o644); err != nil {
602		t.Fatalf("failed to write AGENTS.md: %v", err)
603	}
604
605	h := NewTestHarness(t)
606	defer h.Close()
607
608	// Create a conversation with the temp directory as cwd
609	h.NewConversation("bash: echo hello", tmpDir)
610	h.WaitToolResult()
611
612	// Get the system prompt from the database
613	var messages []generated.Message
614	err = h.db.Queries(context.Background(), func(q *generated.Queries) error {
615		var qerr error
616		messages, qerr = q.ListMessages(context.Background(), h.ConversationID())
617		return qerr
618	})
619	if err != nil {
620		t.Fatalf("failed to get messages: %v", err)
621	}
622
623	// Find the system message
624	var systemPrompt string
625	for _, msg := range messages {
626		if msg.Type == "system" && msg.LlmData != nil {
627			var llmMsg llm.Message
628			if err := json.Unmarshal([]byte(*msg.LlmData), &llmMsg); err == nil {
629				for _, content := range llmMsg.Content {
630					if content.Type == llm.ContentTypeText {
631						systemPrompt = content.Text
632						break
633					}
634				}
635			}
636			break
637		}
638	}
639
640	if systemPrompt == "" {
641		t.Fatal("no system prompt found in messages")
642	}
643
644	// Verify the system prompt contains our unique marker from AGENTS.md
645	if !strings.Contains(systemPrompt, "UNIQUE_MARKER_FOR_CWD_TEST_XYZ123") {
646		t.Errorf("system prompt should contain content from AGENTS.md in the cwd directory")
647		// Log first 1000 chars to help debug
648		if len(systemPrompt) > 1000 {
649			t.Logf("system prompt (first 1000 chars): %s...", systemPrompt[:1000])
650		} else {
651			t.Logf("system prompt: %s", systemPrompt)
652		}
653	}
654
655	// Verify the working directory in the prompt is our temp directory
656	if !strings.Contains(systemPrompt, tmpDir) {
657		t.Errorf("system prompt should reference the cwd directory: %s", tmpDir)
658	}
659}