Skip to content

fix(tools): list_files returns paths relative to queried directory — closes #24#102

Open
jpleva91 wants to merge 1 commit intomainfrom
fix/list-files-relative-path-24
Open

fix(tools): list_files returns paths relative to queried directory — closes #24#102
jpleva91 wants to merge 1 commit intomainfrom
fix/list-files-relative-path-24

Conversation

@jpleva91
Copy link
Copy Markdown
Contributor

@jpleva91 jpleva91 commented Apr 2, 2026

Summary

  • Bug: listFiles() called filepath.Rel(".", path), computing paths relative to the process cwd instead of the queried directory. Agents listing internal/agent received internal/agent/loop.go instead of loop.go, causing double-prefix errors on follow-up read_file calls.
  • Fix: Use filepath.Rel(dir, path) anchored to the requested directory. Also skip the root "." entry so empty directories correctly return "(empty directory)".
  • Tests: 5 new tests in TestListFiles_* covering relative paths, no-double-prefix regression, extension filter, empty directory, and hidden dir exclusion.

Test plan

  • go build ./... passes
  • go vet ./... passes
  • go test ./... — all packages pass (including 5 new listFiles tests)
  • Verify REPL list_files output shows leaf-relative paths in agent sessions

🤖 Generated with Claude Code

…24

filepath.Rel(".", path) computed paths relative to the process cwd,
not the directory the agent requested. Agents listing "internal/agent"
got back "internal/agent/loop.go" instead of "loop.go", causing
double-prefix errors on follow-up read_file calls.

Fix: use filepath.Rel(dir, path) and skip the root "." entry so
empty directories return "(empty directory)" correctly.

Adds 5 tests covering: relative paths, no-double-prefix regression,
extension filter, empty directory, and hidden dir exclusion.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 2, 2026 02:32
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes list_files path rendering so returned entries are relative to the directory being listed (not the process CWD), preventing “double-prefix” follow-up paths when agents call read_file on list results.

Changes:

  • Compute listed paths via filepath.Rel(dir, path) (anchored to the queried directory) instead of filepath.Rel(".", path).
  • Skip the root "." entry so truly empty directories return "(empty directory)".
  • Add 5 new listFiles tests covering relative path behavior, regression for double-prefixing, extension filtering, empty directories, and hidden/node_modules exclusion.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
internal/tools/tools.go Fixes listFiles() relative-path computation and skips the root entry.
internal/tools/tools_test.go Adds test coverage for the corrected listFiles() output behavior and regressions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

return nil
}
rel, _ := filepath.Rel(".", path)
rel, _ := filepath.Rel(dir, path)
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filepath.Rel(dir, path) errors are currently ignored. If Rel fails (e.g., different volume on Windows, malformed input), rel becomes an empty string and the code may append "" or "/" to the output, producing incorrect paths. Handle the error explicitly (e.g., return it to fail the tool call, or skip the entry) before using rel.

Suggested change
rel, _ := filepath.Rel(dir, path)
rel, errRel := filepath.Rel(dir, path)
if errRel != nil {
return errRel
}

Copilot uses AI. Check for mistakes.
Comment on lines +432 to +436
// Paths must be relative to dir, not cwd
for _, line := range strings.Split(r.Output, "\n") {
if strings.HasPrefix(line, dir) {
t.Fatalf("got absolute path %q — expected relative to listed dir", line)
}
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TestListFiles_PathsRelativeToDirectory only checks that output lines aren’t absolute and don’t start with the temp dir path. With the original bug, entries like "../../tmp/.../a.go" are still relative and would pass these assertions. To actually verify paths are relative to the queried directory, assert that returned paths don’t start with ".." (after filepath.Clean) / don’t contain parent traversals, or add a direct expectation like "sub/b.go" vs any prefixed path.

Suggested change
// Paths must be relative to dir, not cwd
for _, line := range strings.Split(r.Output, "\n") {
if strings.HasPrefix(line, dir) {
t.Fatalf("got absolute path %q — expected relative to listed dir", line)
}
// Paths must be relative to dir, not cwd, and must not contain parent traversals.
for _, raw := range strings.Split(r.Output, "\n") {
line := strings.TrimSpace(raw)
if line == "" {
continue
}
if strings.HasPrefix(line, dir) {
t.Fatalf("got absolute path %q — expected relative to listed dir", line)
}
clean := filepath.Clean(line)
if clean == ".." || strings.HasPrefix(clean, ".."+string(filepath.Separator)) {
t.Fatalf("got path with parent traversal %q (clean: %q) — expected path relative to listed dir", line, clean)
}

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

@jpleva91 jpleva91 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewer: shellforge:reviewer (automated, 2026-04-02)

Code review: LGTM — would approve if self-review were permitted.

Fix correctness: filepath.Rel(dir, path) is the right anchor — "." resolves to process cwd, not the queried directory, so any absolute-path listing produced double-prefixed paths in the prior code. The rel == "." guard is also necessary: WalkDir visits the root directory itself first, and without this guard that visit emits a spurious . entry.

Tests: 5 targeted tests cover the core regression, no-double-prefix scenario, extension filter, empty dir, and hidden dir exclusion. Good coverage.

CI: All 5 checks passing (build, CodeQL, Analyze ×3).

One pre-existing note (not introduced here): filepath.Rel error is silently discarded. Safe on Linux (only errors cross-volume), but worth a comment if this function grows. Not a blocker.

Blast radius is minimal (2 files, 1 prod line changed). Ready to merge — needs a second reviewer from the team.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants