fix: SFTP paths on Windows — double-slash for remote, remove broken MSYS env
- Remote paths in upload/download require // prefix on Windows/Git Bash - Removed useless MSYS_NO_PATHCONV from Python (must be shell-level) - Removed broken bash wrapper - Updated skill docs with // path rule and examples Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -48,13 +48,15 @@ python ~/.server-connections/ssh.py ALIAS --no-sudo "command"
|
||||
|
||||
### Загрузить файл на сервер
|
||||
```bash
|
||||
python ~/.server-connections/ssh.py ALIAS --upload /local/path /remote/path
|
||||
python ~/.server-connections/ssh.py ALIAS --upload "D:/path/local/file" //remote/path/file
|
||||
```
|
||||
**ВАЖНО (Windows/Git Bash):** remote path ОБЯЗАТЕЛЬНО с двойным слешем `//home/...`, `//tmp/...`. Одинарный `/` будет сконвертирован Git Bash в Windows-путь и сломает SFTP.
|
||||
|
||||
### Скачать файл с сервера
|
||||
```bash
|
||||
python ~/.server-connections/ssh.py ALIAS --download /remote/path /local/path
|
||||
python ~/.server-connections/ssh.py ALIAS --download //remote/path/file "D:/path/local/file"
|
||||
```
|
||||
Remote path тоже с `//`.
|
||||
|
||||
### Установить SSH-ключ на сервер
|
||||
```bash
|
||||
|
||||
13
tools/ssh.py
13
tools/ssh.py
@@ -1,6 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
# Disable MSYS path conversion to prevent Windows path conversion issues
|
||||
os.environ['MSYS_NO_PATHCONV'] = '1'
|
||||
"""
|
||||
SSH utility for Claude Code — connects to servers by alias.
|
||||
Credentials stored locally in servers.json (encrypted), NEVER exposed to AI API.
|
||||
@@ -168,7 +166,7 @@ def _shell_quote(s: str) -> str:
|
||||
def _normalize_remote_path(remote_path: str) -> str:
|
||||
"""Normalize remote path by detecting and fixing MSYS path conversions."""
|
||||
# If the path looks like a Windows path that was converted by MSYS, fix it back
|
||||
if ':' in remote_path and ('Program Files/Git' in remote_path or len(remote_path) > 1 and remote_path[1] == ':'):
|
||||
if ':' in remote_path and ('Program Files/Git' in remote_path or (len(remote_path) > 3 and remote_path[1] == ':' and remote_path[2] == '/')):
|
||||
# Convert C:/Program Files/Git/tmp/file.txt back to /tmp/file.txt
|
||||
# Find the position where Git path starts
|
||||
if 'Program Files/Git' in remote_path:
|
||||
@@ -183,11 +181,14 @@ def _normalize_remote_path(remote_path: str) -> str:
|
||||
# Try to determine if it's supposed to be a Unix path
|
||||
potential_unix_path = remote_path[3:] # Remove drive prefix like "C:"
|
||||
# If the resulting path starts with a common Unix directory, assume it should be Unix path
|
||||
if (potential_unix_path.startswith('/tmp/') or potential_unix_path.startswith('/home/') or potential_unix_path.startswith('/etc/') or potential_unix_path.startswith('/var/') or potential_unix_path.startswith('/usr/')):
|
||||
return potential_unix_path
|
||||
common_unix_prefixes = ['/tmp/', '/home/', '/etc/', '/var/', '/usr/', '/opt/', '/root/', '/bin/', '/sbin/', '/lib/', '/lib64/']
|
||||
for prefix in common_unix_prefixes:
|
||||
if potential_unix_path.startswith(prefix):
|
||||
return potential_unix_path
|
||||
return remote_path
|
||||
|
||||
|
||||
|
||||
def upload_file(server: dict, local_path: str, remote_path: str):
|
||||
# Normalize the remote path to handle MSYS conversion issues
|
||||
normalized_remote_path = _normalize_remote_path(remote_path)
|
||||
@@ -200,6 +201,7 @@ def upload_file(server: dict, local_path: str, remote_path: str):
|
||||
print(f"OK: {local_path} -> {server['alias']}:{normalized_remote_path}")
|
||||
finally:
|
||||
client.close()
|
||||
|
||||
def download_file(server: dict, remote_path: str, local_path: str):
|
||||
# Normalize the remote path to handle MSYS conversion issues
|
||||
normalized_remote_path = _normalize_remote_path(remote_path)
|
||||
@@ -211,6 +213,7 @@ def download_file(server: dict, remote_path: str, local_path: str):
|
||||
print(f"OK: {server['alias']}:{normalized_remote_path} -> {local_path}")
|
||||
finally:
|
||||
client.close()
|
||||
|
||||
def install_key(server: dict):
|
||||
pub_key_path = SSH_KEY_PATH + ".pub"
|
||||
if not os.path.exists(pub_key_path):
|
||||
|
||||
Reference in New Issue
Block a user