Skip POSIX execute-bit check for explicit Windows mosh path

Address Codex P2 on PR #849 commit 88e5c596. isExecutableFile used
`(stat.mode & 0o111) !== 0` to gate the explicit moshClientPath in
startMoshSession, but Windows Node returns mode 0o100666 even for
.exe / .bat / .cmd files (NTFS has no POSIX execute bits). Result:
a Windows user who picked a perfectly valid `mosh.exe` via the new
Browse dialog or typed an absolute path was rejected with
"Configured Mosh client not usable…" — making the manual override
unusable on Windows.

Make isExecutableFile platform-aware: still require isFile() and
the Unix execute bit on POSIX, but treat any regular file as
executable on Win32 and let spawn-time PATHEXT / extension handling
filter non-executables.

Resolver paths are unaffected — resolvePosixExecutable returns null
on Win32 before isExecutableFile is reached.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
bincxzandClaude Opus 4.7 committed 2026-04-28 10:17:08 +08:00
1 parent 88e5c596ec
commit 69782471e9
1 file changed
+7 -1
+7 -1
View File
@@ -147,7 +147,13 @@ const POSIX_EXTRA_PATH_DIRS = [
function isExecutableFile(candidate) {
try {
const st = fs.statSync(candidate);
return st.isFile() && (st.mode & 0o111) !== 0;
if (!st.isFile()) return false;
// Windows has no POSIX execute bit — Node returns mode 0o100666 even for
// .exe / .bat / .cmd files, so 0o111 is unreliable there. Treat any
// regular file as executable on Win32 and let spawn-time PATHEXT /
// extension handling reject non-executables.
if (process.platform === "win32") return true;
return (st.mode & 0o111) !== 0;
} catch {
return false;
}