Skip to content

fix(filesystem): resolve symlink/junction targets to directory type in readDirectoryEntries#28532

Open
danielxxomg wants to merge 1 commit into
anomalyco:devfrom
danielxxomg:fix/symlink-directory-listing-clean
Open

fix(filesystem): resolve symlink/junction targets to directory type in readDirectoryEntries#28532
danielxxomg wants to merge 1 commit into
anomalyco:devfrom
danielxxomg:fix/symlink-directory-listing-clean

Conversation

@danielxxomg
Copy link
Copy Markdown

Issue for this PR

Closes #28526

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Symlinked directories (Linux ln -s) and Windows junction points (e.g., OneDrive Desktop) are invisible in the directory picker, @file picker, and file listing because readDirectoryEntries classifies them as "symlink" and downstream filters skip non-directory types.

This fixes the root cause in packages/core/src/filesystem.ts:readDirectoryEntries: when isSymbolicLink() is true, stat() the target and return "directory" if the target is a directory. This fixes ALL consumers at once — no downstream filter changes needed.

Also resolves long-standing open issues:

How did you verify your code works?

bun test test/file/ — 87 pass, 1 skip, 0 fail. No regressions.

Screenshots / recordings

N/A, no UI changes.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

…n readDirectoryEntries

When isSymbolicLink() is true (Linux symlinks, Windows junction points like
OneDrive Desktop), stat() the target to determine if it points to a directory.
Previously these entries were classified as 'symlink' and silently filtered
out by downstream code (file/index.ts), making symlinked directories invisible
in the project picker, @file picker, and file listing on ALL platforms.

This fixes the root cause instead of patching individual filter sites.
Closes anomalyco#28526, also resolves anomalyco#10365 and anomalyco#16342.
Copilot AI review requested due to automatic review settings May 20, 2026 21:05
Copy link
Copy Markdown
Contributor

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

Note

Copilot was unable to run its full agentic suite in this review.

Updates directory listing logic to better classify filesystem entries, especially symbolic links that point to directories.

Changes:

  • Replaces synchronous map with async mapping + Promise.all to allow stat calls during classification.
  • Resolves symlink targets with NFS.stat to classify symlinks-to-directories as "directory".

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

Comment on lines +71 to 90
return await Promise.all(
entries.map(async (e): Promise<DirEntry> => {
let type: DirEntry["type"]
if (e.isDirectory()) {
type = "directory"
} else if (e.isSymbolicLink()) {
try {
const target = await NFS.stat(join(dirPath, e.name))
type = target.isDirectory() ? "directory" : "symlink"
} catch {
type = "symlink"
}
} else if (e.isFile()) {
type = "file"
} else {
type = "other"
}
return { name: e.name, type }
}),
)
Comment on lines +71 to 90
return await Promise.all(
entries.map(async (e): Promise<DirEntry> => {
let type: DirEntry["type"]
if (e.isDirectory()) {
type = "directory"
} else if (e.isSymbolicLink()) {
try {
const target = await NFS.stat(join(dirPath, e.name))
type = target.isDirectory() ? "directory" : "symlink"
} catch {
type = "symlink"
}
} else if (e.isFile()) {
type = "file"
} else {
type = "other"
}
return { name: e.name, type }
}),
)
@github-actions
Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

Potential duplicate found:

Why they're related: Both PRs address the same core issue of treating symlinked/junction directories as the "directory" type in readDirectoryEntries. PR #28531 appears to be the earlier attempt at the same fix. You should review whether #28531 is already merged, closed, or if this is a newer/refined version of the same fix.

@danielxxomg
Copy link
Copy Markdown
Author

Not a duplicate. #28531 uses e.isDirectory() inside the ternary, which doesn't resolve Windows junction points (reparse points). isDirectory() returns false for those.

This PR uses NFS.stat() to explicitly follow the link target, which correctly identifies junction-to-directory on Windows, symlink-to-directory on Linux, and aliases on macOS. The extra stat() only fires on isSymbolicLink() entries, so non-symlink entries have zero overhead.

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.

fix: symlink/junction directories invisible in directory picker and @file

2 participants