From f11619c8cb34ea3641491a74d83dde964d626603 Mon Sep 17 00:00:00 2001 From: Ammar Date: Tue, 2 Dec 2025 12:39:14 -0600 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20fix:=20preserve=20SSH=20host=20w?= =?UTF-8?q?hen=20switching=20runtime=20modes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The regression was introduced in 7087ef49 when adding Local/Worktree/SSH distinction. The onChange handler for runtime selection was changed from: mode === LOCAL ? '' : props.sshHost to: mode === SSH ? props.sshHost : '' This cleared the SSH host when switching away from SSH mode, losing the user's configured host when switching back. The fix stores the SSH host in a separate localStorage key (lastSshHost) that persists independently of the runtime mode. This ensures the SSH host is remembered when: 1. Switching from SSH → Local → SSH 2. Switching from SSH → Worktree → SSH _Generated with `mux`_ --- .../components/ChatInput/CreationControls.tsx | 4 ++-- .../hooks/useDraftWorkspaceSettings.ts | 23 +++++++++++++++---- src/common/constants/storage.ts | 10 ++++++++ 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/browser/components/ChatInput/CreationControls.tsx b/src/browser/components/ChatInput/CreationControls.tsx index bd0d0efd6..3ad806fe4 100644 --- a/src/browser/components/ChatInput/CreationControls.tsx +++ b/src/browser/components/ChatInput/CreationControls.tsx @@ -41,8 +41,8 @@ export function CreationControls(props: CreationControlsProps) { ]} onChange={(newMode) => { const mode = newMode as RuntimeMode; - // Clear SSH host when switching away from SSH - props.onRuntimeChange(mode, mode === RUNTIME_MODE.SSH ? props.sshHost : ""); + // Preserve SSH host across mode switches so it's remembered when returning to SSH + props.onRuntimeChange(mode, props.sshHost); }} disabled={props.disabled} aria-label="Runtime mode" diff --git a/src/browser/hooks/useDraftWorkspaceSettings.ts b/src/browser/hooks/useDraftWorkspaceSettings.ts index d809a3ae0..fffb6304f 100644 --- a/src/browser/hooks/useDraftWorkspaceSettings.ts +++ b/src/browser/hooks/useDraftWorkspaceSettings.ts @@ -12,6 +12,7 @@ import { getModelKey, getRuntimeKey, getTrunkBranchKey, + getLastSshHostKey, getProjectScopeId, } from "@/common/constants/storage"; import type { UIMode } from "@/common/types/mode"; @@ -78,8 +79,16 @@ export function useDraftWorkspaceSettings( { listener: true } ); - // Parse runtime string into mode and host - const { mode: runtimeMode, host: sshHost } = parseRuntimeModeAndHost(runtimeString); + // Project-scoped SSH host preference (persisted separately from runtime mode) + // This allows the SSH host to be remembered when switching between runtime modes + const [lastSshHost, setLastSshHost] = usePersistedState( + getLastSshHostKey(projectPath), + "", + { listener: true } + ); + + // Parse runtime string into mode (host from runtime string is ignored in favor of lastSshHost) + const { mode: runtimeMode } = parseRuntimeModeAndHost(runtimeString); // Initialize trunk branch from backend recommendation or first branch useEffect(() => { @@ -89,15 +98,19 @@ export function useDraftWorkspaceSettings( } }, [branches, recommendedTrunk, trunkBranch, setTrunkBranch]); - // Setter for runtime options (updates persisted runtime string) + // Setter for runtime options (updates persisted runtime mode and SSH host separately) const setRuntimeOptions = (newMode: RuntimeMode, newHost: string) => { const newRuntimeString = buildRuntimeString(newMode, newHost); setRuntimeString(newRuntimeString); + // Always persist the SSH host separately so it's remembered across mode switches + if (newHost) { + setLastSshHost(newHost); + } }; // Helper to get runtime string for IPC calls const getRuntimeString = (): string | undefined => { - return buildRuntimeString(runtimeMode, sshHost); + return buildRuntimeString(runtimeMode, lastSshHost); }; return { @@ -106,7 +119,7 @@ export function useDraftWorkspaceSettings( thinkingLevel, mode, runtimeMode, - sshHost, + sshHost: lastSshHost, trunkBranch, }, setRuntimeOptions, diff --git a/src/common/constants/storage.ts b/src/common/constants/storage.ts index 26d0e2243..09b472416 100644 --- a/src/common/constants/storage.ts +++ b/src/common/constants/storage.ts @@ -126,6 +126,16 @@ export function getTrunkBranchKey(projectPath: string): string { return `trunkBranch:${projectPath}`; } +/** + * Get the localStorage key for last SSH host preference for a project + * Stores the last entered SSH host separately from runtime mode + * so it persists when switching between runtime modes + * Format: "lastSshHost:{projectPath}" + */ +export function getLastSshHostKey(projectPath: string): string { + return `lastSshHost:${projectPath}`; +} + /** * Get the localStorage key for the preferred compaction model (global) * Format: "preferredCompactionModel"