diff --git a/internal/fsext/expand.go b/internal/fsext/expand.go new file mode 100644 index 0000000000000000000000000000000000000000..d4265ca6381f43056032ffdf35ab61f137d1752f --- /dev/null +++ b/internal/fsext/expand.go @@ -0,0 +1,29 @@ +package fsext + +import ( + "os" + "strings" + + "mvdan.cc/sh/v3/expand" + "mvdan.cc/sh/v3/syntax" +) + +// Expand is a wrapper around [expand.Literal]. It will escape the input +// string, expand any shell symbols (such as '~') and resolve any environment +// variables. +func Expand(s string) (string, error) { + if s == "" { + return "", nil + } + p := syntax.NewParser() + word, err := p.Document(strings.NewReader(s)) + if err != nil { + return "", err + } + cfg := &expand.Config{ + Env: expand.FuncEnviron(os.Getenv), + ReadDir2: os.ReadDir, + GlobStar: true, + } + return expand.Literal(cfg, word) +} diff --git a/internal/llm/tools/ls.go b/internal/llm/tools/ls.go index 559758c05c97e6540b8c63053a58ba2ee682d9a4..9dfce8ef83570414f6f61078bead34804f83a2cc 100644 --- a/internal/llm/tools/ls.go +++ b/internal/llm/tools/ls.go @@ -121,12 +121,10 @@ func (l *lsTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error) { searchPath = l.workingDir } - if searchPath == "~" { - homeDir, err := os.UserHomeDir() - if err != nil { - return ToolResponse{}, fmt.Errorf("error resolving home directory: %w", err) - } - searchPath = homeDir + var err error + searchPath, err = fsext.Expand(searchPath) + if err != nil { + return ToolResponse{}, fmt.Errorf("error expanding path: %w", err) } if !filepath.IsAbs(searchPath) {