【Bug已解决】Windows Codex Desktop should support SSH remote projects to Windows OpenSSH hosts 解决方案原始报错线索Windows Codex Desktop should support SSH remote projects to Windows OpenSSH hosts桌面应用应支持通过 SSH 连到 Windows OpenSSH 主机直接打开远端项目。一、现象长什么样桌面应用想「连上远程机器、直接编辑那边项目」时遇到填了userhost却连不上提示Permission denied (publickey)或Connection timed out连上了但打开的远端路径在应用里显示成乱码或不识别C:\projectsvs/home/user/projects混用编辑保存后远端文件换行符从 LF 变成 CRLF导致 Linux 脚本#!/bin/sh执行报bad interpreter长时间无操作后再操作命令卡住数分钟才报Broken pipe远端是 Windows OpenSSH路径是C:\...风格应用按 POSIX 解析直接报错。 这些都不是「SSH 坏了」而是应用层没把「远程文件系统的语义」和「本地编辑器预期」对齐。二、背景SSH 远程开发的两种模式2.1 远程命令执行最简单应用通过 SSH 在远端执行命令ls、cat、写文件把结果回传本地展示。适合「命令式」操作但每次交互都有网络往返。2.2 挂载 / 代理文件系统如 SFTP / FUSE应用用 SFTP 协议把远端目录「映射」成可浏览的虚拟文件系统编辑器像读本地文件一样读写。体验好但要正确处理路径、权限、换行。2.3 为什么 Windows OpenSSH 是特殊案例Windows 上的 OpenSSH 服务端基于C:\ProgramData\ssh暴露的是Windows 路径C:\Users\...但它的 shell 又接受类 POSIX 的命令。应用若假设「远端一定是 Linux」用/home/...拼路径就会失败。必须探测远端 OS 并用对应路径风格。三、为什么连上却打不开项目根因3.1 认证方式不匹配本地只有密钥远端没部署公钥或远端要求password而应用只试了publickey。顺序错就会Permission denied。3.2 路径风格假设错误应用硬编码 POSIX 路径/home/user/proj连到 Windows OpenSSH 时远端实际是C:\Users\user\proj。不做 OS 探测就拼错。3.3 换行符被偷偷转换Windows 编辑器默认把文本存成 CRLF而远端 Linux 脚本需要 LF。保存时未设textauto或显式 LF脚本就废了。3.4 无连接保活SSH 默认不发包中间 NAT / 防火墙空闲一段时间就悄悄断连下次操作才发现有Broken pipe。四、最小可运行复现用 subprocess 跑真实 SSH下面用 Python 标准库subprocess调用系统ssh演示「探测远端 OS 并正确列目录」——这是所有远程项目功能的第一步import subprocess import sys def ssh_run(host: str, user: str, cmd: str, timeout: int 15) - str: 通过系统 ssh 在远端执行命令返回 stdout。 remote f{user}{host} proc subprocess.run( [ssh, -o, BatchModeyes, # 禁止交互式密码逼出密钥问题 -o, ConnectTimeout10, remote, cmd], capture_outputTrue, textTrue, timeouttimeout, ) if proc.returncode ! 0: raise RuntimeError(fssh 失败({proc.returncode}): {proc.stderr.strip()}) return proc.stdout def detect_remote_os(host: str, user: str) - str: out ssh_run(host, user, uname -s 2/dev/null || cmd /c ver 2/dev/null) out out.strip() if Linux in out: return linux if MINGW in out or Microsoft in out or Windows in out: return windows return unknown if __name__ __main__: host, user 192.168.1.50, dev try: ros detect_remote_os(host, user) print(远端系统:, ros) # 根据系统选对列目录命令 ls_cmd ls -la /home/dev/proj if ros linux else rcmd /c dir C:\proj print(ssh_run(host, user, ls_cmd)) except RuntimeError as e: print(连接问题:, e)运行前需在本机ssh-keygen并把公钥放进远端authorized_keysWindows OpenSSH 在C:\Users\user\.ssh\authorized_keys。BatchModeyes会强制只用密钥能立刻暴露「公钥没部署」这类认证问题。五、解决方案一正确的认证与连接参数def build_ssh_options(): 一组稳健的 SSH 客户端选项适合被应用内置调用。 return [ -o, StrictHostKeyCheckingaccept-new, # 首次自动接受之后校验 -o, BatchModeyes, # 非交互避免卡在密码提示 -o, ConnectTimeout10, -o, ServerAliveInterval30, # 每 30s 发保活包 -o, ServerAliveCountMax3, # 连续 3 次无回应才断 -o, NumberOfPasswordPrompts0, # 不弹密码框 ] def ssh_with_options(host, user, cmd): opts build_ssh_options() proc subprocess.run( [ssh, *opts, f{user}{host}, cmd], capture_outputTrue, textTrue, timeout20, ) return proc要点ServerAliveIntervalServerAliveCountMax解决了「空闲断连」Broken pipeBatchMode避免应用卡在密码输入StrictHostKeyCheckingaccept-new兼顾安全与首次可用。六、解决方案二远端路径风格探测与映射应用必须根据远端 OS 选正确路径风格并做「本地逻辑路径 → 远端真实路径」的映射from dataclasses import dataclass dataclass class RemoteFS: os_kind: str # linux / windows def to_remote_path(self, logical: str) - str: 把应用内部的『逻辑项目路径』翻译成远端真实路径。 if self.os_kind windows: # Windows OpenSSH逻辑 /projects/foo - C:\projects\foo rel logical.lstrip(/).replace(/, \\) return fC:\\{rel} # Linux逻辑 /projects/foo - /projects/foo return logical def list_cmd(self, logical: str) - str: rp self.to_remote_path(logical) if self.os_kind windows: return fcmd /c dir {rp} return fls -la {rp} if __name__ __main__: wfs RemoteFS(os_kindwindows) print(wfs.to_remote_path(/projects/foo)) # C:\projects\foo print(wfs.list_cmd(/projects/foo)) # cmd /c dir C:\projects\foo这样无论远端是 Linux 还是 Windows OpenSSH应用都用统一的逻辑路径差异在RemoteFS内消化。七、解决方案三换行符与权限不踩坑7.1 换行符明确用 LF 保存脚本把远端文件拉到本地编辑再推回时强制以 LF 存盘尤其 Shell 脚本def write_remote_file_local(content: str, path: str): # 统一转成 LF避免 Windows CRLF 破坏 Linux 脚本 normalized content.replace(\r\n, \n) with open(path, w, encodingutf-8, newline\n) as f: f.write(normalized) def push_to_remote(host, user, local_path, remote_path): # 用 scp/ssh 推送newline\n 保证传输内容已是 LF subprocess.run([scp, local_path, f{user}{host}:{remote_path}], checkTrue)7.2 权限远端脚本需可执行位推完脚本别忘了chmod xLinux 远端否则执行报Permission denieddef ensure_executable(host, user, remote_path): if remote_path.startswith(C:): return # Windows 无 exec 位概念 ssh_run(host, user, fchmod x {remote_path})八、跨平台对照维度Linux 远端Windows OpenSSH 远端路径风格/home/user/projC:\Users\user\proj列目录命令ls -lacmd /c dir或powershell Get-ChildItem换行符LF应用侧强制 LF 保存可执行位chmod x不适用公钥位置~/.ssh/authorized_keysC:\Users\user\.ssh\authorized_keys默认 shellbash/zshcmd / PowerShell应用层用「OS 探测 映射表」把差异封住UI 只暴露统一的「项目路径」输入框。呼应第 102 篇的「SSH 远程文件列目录」话题——保活、路径、权限三件套是远程开发的铁三角。九、排查清单连上远程却打不开项目按下面排查先在本机终端手动ssh userhost确认密钥/密码能通排除网络与认证看应用是否只试了 publickey远端若要求密码需切换认证方式探测远端 OSLinux 还是 Windows OpenSSH路径风格是否匹配路径是否拼错/homevsC:\混用是头号坑换行符保存脚本是否变成 CRLF导致远端执行bad interpreter保活是否设了ServerAliveInterval否则空闲断连权限Linux 远端脚本是否丢了x主机密钥StrictHostKeyChecking策略是否过严导致首次连接被拒。十、小结「桌面应用通过 SSH 连远程项目打不开」本质是应用层没对齐远端文件系统的语义认证方式、路径风格、换行符、连接保活四件事任何一件错位都会失败。通用方案稳健认证BatchModeyes逼出密钥问题StrictHostKeyCheckingaccept-new兼顾安全与可用OS 探测 路径映射Linux 用 POSIX、Windows OpenSSH 用C:\应用内部只持逻辑路径换行与权限脚本强制 LF 保存Linux 远端推完补chmod x连接保活ServerAliveIntervalServerAliveCountMax消灭空闲Broken pipe。 把「远端差异」封进一个RemoteFS抽象里UI 只管统一的「项目路径」就能在 Linux / Windows / macOS 三端一致地打开远程项目。SSH 远程开发的可靠性从来不在「能不能连上」而在「连上之后路径、换行、保活对不对」。
【Bug已解决】Windows Codex Desktop should support SSH remote projects to Windows OpenSSH hosts 解决方案
【Bug已解决】Windows Codex Desktop should support SSH remote projects to Windows OpenSSH hosts 解决方案原始报错线索Windows Codex Desktop should support SSH remote projects to Windows OpenSSH hosts桌面应用应支持通过 SSH 连到 Windows OpenSSH 主机直接打开远端项目。一、现象长什么样桌面应用想「连上远程机器、直接编辑那边项目」时遇到填了userhost却连不上提示Permission denied (publickey)或Connection timed out连上了但打开的远端路径在应用里显示成乱码或不识别C:\projectsvs/home/user/projects混用编辑保存后远端文件换行符从 LF 变成 CRLF导致 Linux 脚本#!/bin/sh执行报bad interpreter长时间无操作后再操作命令卡住数分钟才报Broken pipe远端是 Windows OpenSSH路径是C:\...风格应用按 POSIX 解析直接报错。 这些都不是「SSH 坏了」而是应用层没把「远程文件系统的语义」和「本地编辑器预期」对齐。二、背景SSH 远程开发的两种模式2.1 远程命令执行最简单应用通过 SSH 在远端执行命令ls、cat、写文件把结果回传本地展示。适合「命令式」操作但每次交互都有网络往返。2.2 挂载 / 代理文件系统如 SFTP / FUSE应用用 SFTP 协议把远端目录「映射」成可浏览的虚拟文件系统编辑器像读本地文件一样读写。体验好但要正确处理路径、权限、换行。2.3 为什么 Windows OpenSSH 是特殊案例Windows 上的 OpenSSH 服务端基于C:\ProgramData\ssh暴露的是Windows 路径C:\Users\...但它的 shell 又接受类 POSIX 的命令。应用若假设「远端一定是 Linux」用/home/...拼路径就会失败。必须探测远端 OS 并用对应路径风格。三、为什么连上却打不开项目根因3.1 认证方式不匹配本地只有密钥远端没部署公钥或远端要求password而应用只试了publickey。顺序错就会Permission denied。3.2 路径风格假设错误应用硬编码 POSIX 路径/home/user/proj连到 Windows OpenSSH 时远端实际是C:\Users\user\proj。不做 OS 探测就拼错。3.3 换行符被偷偷转换Windows 编辑器默认把文本存成 CRLF而远端 Linux 脚本需要 LF。保存时未设textauto或显式 LF脚本就废了。3.4 无连接保活SSH 默认不发包中间 NAT / 防火墙空闲一段时间就悄悄断连下次操作才发现有Broken pipe。四、最小可运行复现用 subprocess 跑真实 SSH下面用 Python 标准库subprocess调用系统ssh演示「探测远端 OS 并正确列目录」——这是所有远程项目功能的第一步import subprocess import sys def ssh_run(host: str, user: str, cmd: str, timeout: int 15) - str: 通过系统 ssh 在远端执行命令返回 stdout。 remote f{user}{host} proc subprocess.run( [ssh, -o, BatchModeyes, # 禁止交互式密码逼出密钥问题 -o, ConnectTimeout10, remote, cmd], capture_outputTrue, textTrue, timeouttimeout, ) if proc.returncode ! 0: raise RuntimeError(fssh 失败({proc.returncode}): {proc.stderr.strip()}) return proc.stdout def detect_remote_os(host: str, user: str) - str: out ssh_run(host, user, uname -s 2/dev/null || cmd /c ver 2/dev/null) out out.strip() if Linux in out: return linux if MINGW in out or Microsoft in out or Windows in out: return windows return unknown if __name__ __main__: host, user 192.168.1.50, dev try: ros detect_remote_os(host, user) print(远端系统:, ros) # 根据系统选对列目录命令 ls_cmd ls -la /home/dev/proj if ros linux else rcmd /c dir C:\proj print(ssh_run(host, user, ls_cmd)) except RuntimeError as e: print(连接问题:, e)运行前需在本机ssh-keygen并把公钥放进远端authorized_keysWindows OpenSSH 在C:\Users\user\.ssh\authorized_keys。BatchModeyes会强制只用密钥能立刻暴露「公钥没部署」这类认证问题。五、解决方案一正确的认证与连接参数def build_ssh_options(): 一组稳健的 SSH 客户端选项适合被应用内置调用。 return [ -o, StrictHostKeyCheckingaccept-new, # 首次自动接受之后校验 -o, BatchModeyes, # 非交互避免卡在密码提示 -o, ConnectTimeout10, -o, ServerAliveInterval30, # 每 30s 发保活包 -o, ServerAliveCountMax3, # 连续 3 次无回应才断 -o, NumberOfPasswordPrompts0, # 不弹密码框 ] def ssh_with_options(host, user, cmd): opts build_ssh_options() proc subprocess.run( [ssh, *opts, f{user}{host}, cmd], capture_outputTrue, textTrue, timeout20, ) return proc要点ServerAliveIntervalServerAliveCountMax解决了「空闲断连」Broken pipeBatchMode避免应用卡在密码输入StrictHostKeyCheckingaccept-new兼顾安全与首次可用。六、解决方案二远端路径风格探测与映射应用必须根据远端 OS 选正确路径风格并做「本地逻辑路径 → 远端真实路径」的映射from dataclasses import dataclass dataclass class RemoteFS: os_kind: str # linux / windows def to_remote_path(self, logical: str) - str: 把应用内部的『逻辑项目路径』翻译成远端真实路径。 if self.os_kind windows: # Windows OpenSSH逻辑 /projects/foo - C:\projects\foo rel logical.lstrip(/).replace(/, \\) return fC:\\{rel} # Linux逻辑 /projects/foo - /projects/foo return logical def list_cmd(self, logical: str) - str: rp self.to_remote_path(logical) if self.os_kind windows: return fcmd /c dir {rp} return fls -la {rp} if __name__ __main__: wfs RemoteFS(os_kindwindows) print(wfs.to_remote_path(/projects/foo)) # C:\projects\foo print(wfs.list_cmd(/projects/foo)) # cmd /c dir C:\projects\foo这样无论远端是 Linux 还是 Windows OpenSSH应用都用统一的逻辑路径差异在RemoteFS内消化。七、解决方案三换行符与权限不踩坑7.1 换行符明确用 LF 保存脚本把远端文件拉到本地编辑再推回时强制以 LF 存盘尤其 Shell 脚本def write_remote_file_local(content: str, path: str): # 统一转成 LF避免 Windows CRLF 破坏 Linux 脚本 normalized content.replace(\r\n, \n) with open(path, w, encodingutf-8, newline\n) as f: f.write(normalized) def push_to_remote(host, user, local_path, remote_path): # 用 scp/ssh 推送newline\n 保证传输内容已是 LF subprocess.run([scp, local_path, f{user}{host}:{remote_path}], checkTrue)7.2 权限远端脚本需可执行位推完脚本别忘了chmod xLinux 远端否则执行报Permission denieddef ensure_executable(host, user, remote_path): if remote_path.startswith(C:): return # Windows 无 exec 位概念 ssh_run(host, user, fchmod x {remote_path})八、跨平台对照维度Linux 远端Windows OpenSSH 远端路径风格/home/user/projC:\Users\user\proj列目录命令ls -lacmd /c dir或powershell Get-ChildItem换行符LF应用侧强制 LF 保存可执行位chmod x不适用公钥位置~/.ssh/authorized_keysC:\Users\user\.ssh\authorized_keys默认 shellbash/zshcmd / PowerShell应用层用「OS 探测 映射表」把差异封住UI 只暴露统一的「项目路径」输入框。呼应第 102 篇的「SSH 远程文件列目录」话题——保活、路径、权限三件套是远程开发的铁三角。九、排查清单连上远程却打不开项目按下面排查先在本机终端手动ssh userhost确认密钥/密码能通排除网络与认证看应用是否只试了 publickey远端若要求密码需切换认证方式探测远端 OSLinux 还是 Windows OpenSSH路径风格是否匹配路径是否拼错/homevsC:\混用是头号坑换行符保存脚本是否变成 CRLF导致远端执行bad interpreter保活是否设了ServerAliveInterval否则空闲断连权限Linux 远端脚本是否丢了x主机密钥StrictHostKeyChecking策略是否过严导致首次连接被拒。十、小结「桌面应用通过 SSH 连远程项目打不开」本质是应用层没对齐远端文件系统的语义认证方式、路径风格、换行符、连接保活四件事任何一件错位都会失败。通用方案稳健认证BatchModeyes逼出密钥问题StrictHostKeyCheckingaccept-new兼顾安全与可用OS 探测 路径映射Linux 用 POSIX、Windows OpenSSH 用C:\应用内部只持逻辑路径换行与权限脚本强制 LF 保存Linux 远端推完补chmod x连接保活ServerAliveIntervalServerAliveCountMax消灭空闲Broken pipe。 把「远端差异」封进一个RemoteFS抽象里UI 只管统一的「项目路径」就能在 Linux / Windows / macOS 三端一致地打开远程项目。SSH 远程开发的可靠性从来不在「能不能连上」而在「连上之后路径、换行、保活对不对」。