From 44c79decf3ee8f7a2e968bf1e3ec13225b79da9d Mon Sep 17 00:00:00 2001 From: Vantz Stockwell Date: Wed, 25 Mar 2026 00:41:50 -0400 Subject: [PATCH] fix: SFTP preserves position on tab switch + CWD following on macOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SFTP tab switch fix: - Removed :key on FileTree that destroyed component on every switch - useSftp now accepts a reactive Ref sessionId - Watches sessionId changes and reinitializes without destroying state - Per-session path memory via sessionPaths map — switching back to a tab restores exactly where you were browsing CWD following fix (macOS + all platforms): - Injects OSC 7 prompt hook into the shell after SSH connect - zsh: precmd() emits \e]7;file://host/path\e\\ - bash: PROMPT_COMMAND emits the same sequence - Sent via the PTY channel so it configures the interactive shell - The passive OSC 7 parser in the output loop picks it up - SFTP sidebar auto-navigates to the current working directory Co-Authored-By: Claude Opus 4.6 (1M context) --- src-tauri/src/ssh/session.rs | 17 +++++++ src/components/sftp/FileTree.vue | 4 +- src/composables/useSftp.ts | 82 ++++++++++++++++++++++++-------- src/layouts/MainLayout.vue | 1 - 4 files changed, 82 insertions(+), 22 deletions(-) diff --git a/src-tauri/src/ssh/session.rs b/src-tauri/src/ssh/session.rs index 4852d29..c36be93 100644 --- a/src-tauri/src/ssh/session.rs +++ b/src-tauri/src/ssh/session.rs @@ -157,6 +157,23 @@ impl SshService { // Start remote monitoring if enabled (runs on a separate exec channel) crate::ssh::monitor::start_monitor(handle.clone(), app_handle.clone(), session_id.clone()); + // Inject OSC 7 CWD reporting hook into the user's shell. + // This enables SFTP CWD following on all platforms (Linux, macOS, FreeBSD). + // Sent via the PTY channel so it configures the interactive shell. + { + let osc7_hook = concat!( + // Detect shell and inject the appropriate hook silently + r#"if [ -n "$ZSH_VERSION" ]; then "#, + r#"precmd() { printf '\033]7;file://%s%s\033\\' "$HOST" "$PWD"; }; "#, + r#"elif [ -n "$BASH_VERSION" ]; then "#, + r#"PROMPT_COMMAND='printf "\033]7;file://%s%s\033\\\\" "$HOSTNAME" "$PWD"'; "#, + r#"fi"#, + "\n" + ); + let h = handle.lock().await; + let _ = h.data(channel_id, CryptoVec::from_slice(osc7_hook.as_bytes())).await; + } + // Output reader loop — owns the Channel exclusively. // Writes go through Handle::data() so no shared mutex is needed. let sid = session_id.clone(); diff --git a/src/components/sftp/FileTree.vue b/src/components/sftp/FileTree.vue index 0bb9523..3b711ba 100644 --- a/src/components/sftp/FileTree.vue +++ b/src/components/sftp/FileTree.vue @@ -208,7 +208,7 @@