Skip to content

Commit d3cc283

Browse files
authored
🤖 fix: preserve SSH host when switching runtime modes (#855)
The regression was introduced in 7087ef4 when adding Local/Worktree/SSH distinction. The onChange handler for runtime selection was changed from: ```js mode === LOCAL ? '' : props.sshHost ``` to: ```js mode === SSH ? props.sshHost : '' ``` This cleared the SSH host when switching away from SSH mode, losing the user's configured host when switching back. ## Fix The SSH host is now stored in a separate localStorage key (`lastSshHost:{projectPath}`) that persists independently of the runtime mode. This ensures the SSH host is remembered when switching runtime modes: - SSH → Local → SSH - SSH → Worktree → SSH ## Testing - Existing tests pass - All static checks pass _Generated with `mux`_
1 parent 7b5421c commit d3cc283

File tree

3 files changed

+30
-7
lines changed

3 files changed

+30
-7
lines changed

src/browser/components/ChatInput/CreationControls.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ export function CreationControls(props: CreationControlsProps) {
4141
]}
4242
onChange={(newMode) => {
4343
const mode = newMode as RuntimeMode;
44-
// Clear SSH host when switching away from SSH
45-
props.onRuntimeChange(mode, mode === RUNTIME_MODE.SSH ? props.sshHost : "");
44+
// Preserve SSH host across mode switches so it's remembered when returning to SSH
45+
props.onRuntimeChange(mode, props.sshHost);
4646
}}
4747
disabled={props.disabled}
4848
aria-label="Runtime mode"

src/browser/hooks/useDraftWorkspaceSettings.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
getModelKey,
1313
getRuntimeKey,
1414
getTrunkBranchKey,
15+
getLastSshHostKey,
1516
getProjectScopeId,
1617
} from "@/common/constants/storage";
1718
import type { UIMode } from "@/common/types/mode";
@@ -78,8 +79,16 @@ export function useDraftWorkspaceSettings(
7879
{ listener: true }
7980
);
8081

81-
// Parse runtime string into mode and host
82-
const { mode: runtimeMode, host: sshHost } = parseRuntimeModeAndHost(runtimeString);
82+
// Project-scoped SSH host preference (persisted separately from runtime mode)
83+
// This allows the SSH host to be remembered when switching between runtime modes
84+
const [lastSshHost, setLastSshHost] = usePersistedState<string>(
85+
getLastSshHostKey(projectPath),
86+
"",
87+
{ listener: true }
88+
);
89+
90+
// Parse runtime string into mode (host from runtime string is ignored in favor of lastSshHost)
91+
const { mode: runtimeMode } = parseRuntimeModeAndHost(runtimeString);
8392

8493
// Initialize trunk branch from backend recommendation or first branch
8594
useEffect(() => {
@@ -89,15 +98,19 @@ export function useDraftWorkspaceSettings(
8998
}
9099
}, [branches, recommendedTrunk, trunkBranch, setTrunkBranch]);
91100

92-
// Setter for runtime options (updates persisted runtime string)
101+
// Setter for runtime options (updates persisted runtime mode and SSH host separately)
93102
const setRuntimeOptions = (newMode: RuntimeMode, newHost: string) => {
94103
const newRuntimeString = buildRuntimeString(newMode, newHost);
95104
setRuntimeString(newRuntimeString);
105+
// Always persist the SSH host separately so it's remembered across mode switches
106+
if (newHost) {
107+
setLastSshHost(newHost);
108+
}
96109
};
97110

98111
// Helper to get runtime string for IPC calls
99112
const getRuntimeString = (): string | undefined => {
100-
return buildRuntimeString(runtimeMode, sshHost);
113+
return buildRuntimeString(runtimeMode, lastSshHost);
101114
};
102115

103116
return {
@@ -106,7 +119,7 @@ export function useDraftWorkspaceSettings(
106119
thinkingLevel,
107120
mode,
108121
runtimeMode,
109-
sshHost,
122+
sshHost: lastSshHost,
110123
trunkBranch,
111124
},
112125
setRuntimeOptions,

src/common/constants/storage.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,16 @@ export function getTrunkBranchKey(projectPath: string): string {
126126
return `trunkBranch:${projectPath}`;
127127
}
128128

129+
/**
130+
* Get the localStorage key for last SSH host preference for a project
131+
* Stores the last entered SSH host separately from runtime mode
132+
* so it persists when switching between runtime modes
133+
* Format: "lastSshHost:{projectPath}"
134+
*/
135+
export function getLastSshHostKey(projectPath: string): string {
136+
return `lastSshHost:${projectPath}`;
137+
}
138+
129139
/**
130140
* Get the localStorage key for the preferred compaction model (global)
131141
* Format: "preferredCompactionModel"

0 commit comments

Comments
 (0)