Repository navigation
fix(projects): list symlinked folders as folders in the remote Add Project browser - #29658
Conversation
…oject browser A symlink to a directory was listed as a file on SSH and managed hosts, so projects behind a linked path could not be reached. Follow links when classifying entries; broken links and loops stay files. Co-authored-by: Gideon <jjin6573@naver.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Priority: ➖ Normal Severity of issue fixed: Medium Merge Risk: ⚪ Minimal · up to
|
ELI5
When you add a project on a remote machine, Orca shows you that machine's folders. A shortcut (symlink) that points at a folder was shown as a plain file, so you could not open it or pick anything inside it. Now it shows up and opens like any other folder.
What Changed
Before: in Add Project for an SSH host or a managed Orca server host,
linked -> /data/projectsappeared among the files, with no folder icon, and clicking it did nothing. Anything that lived behind a symlinked path was unreachable from the picker.After: a symlink to a folder is listed with the folders and you can open it and select projects inside it. A broken symlink, a symlink loop and a symlink to a file still appear as files, and none of them break the listing.
Mechanism, for both ways Orca lists a remote folder:
files.browseServerDir,runtime-server-environment-commands.ts):Dirent.isDirectory()is false for a symlink. For entries that are symlinks we nowstat()the target and count it as a folder only if the target is a folder. Anystaterror (missing target,ELOOPfrom a loop) leaves it as a file.ssh-remote-directory-browse.ts): the listing ranls -1Ap, and-pmarks only real directories with/. The command now capturesls -1Aand adds the/with[ -d ], which follows symlinks and is false for broken links and loops. The output format the parser reads is unchanged. Thelsoutput is captured into a variable first, so a directory that can be entered but not read still fails the command instead of looking empty (covered by a test).The Windows PowerShell listing already used
PSIsContainer, which follows links, so it is unchanged. The local and WSL "browse" buttons open the operating system's own folder picker, which already follows symlinks, so they do not have this bug. WSL hosts that are browsed in-app go through the managed-server path above.Why
ls -Lwould also follow links, but GNUls -Lreports an error and exits non-zero on a broken symlink, so one dangling link would fail the whole listing. A per-entry[ -d ]test is POSIX, works with busybox and macOSsh, and costs onestatper entry. On the managed side we onlystatentries that are symlinks, so a big folder costs nothing extra. Paths are not resolved to their real location, so the breadcrumb still shows the path the user navigated.This takes over the approach from #8987 by @choihjin (credited as co-author). That PR targets files that no longer exist on main, so it is ported onto the current modules here.
Linked Issue
Fixes #29490
Fixes #8983
Visual Proof
N/A: no new UI. The existing entry list just classifies the entry correctly. The live check on a real Linux host is described under Testing.
Testing
src/main/ssh/ssh-remote-directory-browse.test.ts(new) runs the real generated command in/bin/shagainst a temporary directory. It contains a symlink to a folder, a symlink to a file, a broken link, a two-link loop, a hidden file, a name with a space, an empty linked folder and an unreadable folder. It fails on main becauselinked-diris listed as a file.src/main/runtime/runtime-server-environment-commands.test.ts(new) uses the same fixture for the managed-server listing, and fails on main the same way.src/main/ipc/ssh-browse.test.tsassertions were updated for the new command.Live: verified on openclaw (Linux) under host isolation: a private user-level sshd and throwaway HOME in /tmp, an isolated hidden desktop built from this change, and a managed server auto-deployed from that build. The home folder held
linked -> real/,repo-link -> repo/, a broken link and a two-link loop. In the real "Browse host filesystem" dialog (the managed-server listing),linkedandrepo-linkwere listed with the folders, clickinglinkedopened it and showedproject-a, and the broken link and loop entries were listed as files without an error. The raw-SSH listing (ssh.browseDirover the live SSH connection to the same host) returnedlinkedandrepo-linkas folders and the broken link and loops as files, and~/linkedlistedproject-a. On main, the soak run had reproduced the bug in the same dialog. Windows SSH hosts are not verified live, because their PowerShell path is unchanged.I manually tested these changes locally
Automated tests added/updated, or explained why not below
AI Disclosure
Review
Codex review (
gpt-6.1-sol, high): no findings.Agent skill upstream boundary
Notes
SSH and managed hosts are the main target. Windows SSH hosts (PowerShell) are unchanged. No wire change: the entry shape is the same, and only the
isDirectoryvalue is now correct.Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)