1- import { useState , useEffect } from "react" ;
2- import { usePersistedState } from ". /usePersistedState" ;
3- import { useThinkingLevel } from ". /useThinkingLevel" ;
1+ import { useState , useEffect , useRef } from "react" ;
2+ import { usePersistedState } from "@/browser/hooks /usePersistedState" ;
3+ import { useThinkingLevel } from "@/browser/hooks /useThinkingLevel" ;
44import { useMode } from "@/browser/contexts/ModeContext" ;
5- import { useModelLRU } from ". /useModelLRU" ;
5+ import { useModelLRU } from "@/browser/hooks /useModelLRU" ;
66import {
77 type RuntimeMode ,
88 type ParsedRuntime ,
@@ -109,6 +109,37 @@ export function useDraftWorkspaceSettings(
109109 { listener : true }
110110 ) ;
111111
112+ // If the default runtime string contains a host/image (e.g. older persisted values like "ssh devbox"),
113+ // prefer it as the initial remembered value.
114+ useEffect ( ( ) => {
115+ if (
116+ parsedDefault ?. mode === RUNTIME_MODE . SSH &&
117+ ! lastSshHost . trim ( ) &&
118+ parsedDefault . host . trim ( )
119+ ) {
120+ setLastSshHost ( parsedDefault . host ) ;
121+ }
122+ if (
123+ parsedDefault ?. mode === RUNTIME_MODE . DOCKER &&
124+ ! lastDockerImage . trim ( ) &&
125+ parsedDefault . image . trim ( )
126+ ) {
127+ setLastDockerImage ( parsedDefault . image ) ;
128+ }
129+ } , [
130+ projectPath ,
131+ parsedDefault ,
132+ lastSshHost ,
133+ lastDockerImage ,
134+ setLastSshHost ,
135+ setLastDockerImage ,
136+ ] ) ;
137+
138+ const defaultSshHost =
139+ parsedDefault ?. mode === RUNTIME_MODE . SSH ? parsedDefault . host : lastSshHost ;
140+ const defaultDockerImage =
141+ parsedDefault ?. mode === RUNTIME_MODE . DOCKER ? parsedDefault . image : lastDockerImage ;
142+
112143 // Build ParsedRuntime from mode + stored host/image
113144 // Defined as a function so it can be used in both useState init and useEffect
114145 const buildRuntimeForMode = (
@@ -132,13 +163,49 @@ export function useDraftWorkspaceSettings(
132163 // Currently selected runtime for this session (initialized from default)
133164 // Uses discriminated union: SSH has host, Docker has image
134165 const [ selectedRuntime , setSelectedRuntimeState ] = useState < ParsedRuntime > ( ( ) =>
135- buildRuntimeForMode ( defaultRuntimeMode , lastSshHost , lastDockerImage )
166+ buildRuntimeForMode ( defaultRuntimeMode , defaultSshHost , defaultDockerImage )
136167 ) ;
137168
138- // Sync selected runtime when default changes (e.g., from checkbox or project switch)
169+ const prevProjectPathRef = useRef < string | null > ( null ) ;
170+ const prevDefaultRuntimeModeRef = useRef < RuntimeMode | null > ( null ) ;
171+
172+ // When switching projects or changing the persisted default mode, reset the selection.
173+ // Importantly: do NOT reset selection when lastSshHost/lastDockerImage changes while typing.
139174 useEffect ( ( ) => {
140- setSelectedRuntimeState ( buildRuntimeForMode ( defaultRuntimeMode , lastSshHost , lastDockerImage ) ) ;
141- } , [ defaultRuntimeMode , lastSshHost , lastDockerImage ] ) ;
175+ const projectChanged = prevProjectPathRef . current !== projectPath ;
176+ const defaultModeChanged = prevDefaultRuntimeModeRef . current !== defaultRuntimeMode ;
177+
178+ if ( projectChanged || defaultModeChanged ) {
179+ setSelectedRuntimeState (
180+ buildRuntimeForMode ( defaultRuntimeMode , defaultSshHost , defaultDockerImage )
181+ ) ;
182+ }
183+
184+ prevProjectPathRef . current = projectPath ;
185+ prevDefaultRuntimeModeRef . current = defaultRuntimeMode ;
186+ } , [ projectPath , defaultRuntimeMode , defaultSshHost , defaultDockerImage ] ) ;
187+
188+ // When the user switches into SSH/Docker mode, seed the field with the remembered host/image.
189+ // This avoids clearing the last host/image when the UI switches modes with an empty field.
190+ const prevSelectedRuntimeModeRef = useRef < RuntimeMode | null > ( null ) ;
191+ useEffect ( ( ) => {
192+ const prevMode = prevSelectedRuntimeModeRef . current ;
193+ if ( prevMode !== selectedRuntime . mode ) {
194+ if ( selectedRuntime . mode === RUNTIME_MODE . SSH ) {
195+ if ( ! selectedRuntime . host . trim ( ) && lastSshHost . trim ( ) ) {
196+ setSelectedRuntimeState ( { mode : RUNTIME_MODE . SSH , host : lastSshHost } ) ;
197+ }
198+ }
199+
200+ if ( selectedRuntime . mode === RUNTIME_MODE . DOCKER ) {
201+ if ( ! selectedRuntime . image . trim ( ) && lastDockerImage . trim ( ) ) {
202+ setSelectedRuntimeState ( { mode : RUNTIME_MODE . DOCKER , image : lastDockerImage } ) ;
203+ }
204+ }
205+ }
206+
207+ prevSelectedRuntimeModeRef . current = selectedRuntime . mode ;
208+ } , [ selectedRuntime , lastSshHost , lastDockerImage ] ) ;
142209
143210 // Initialize trunk branch from backend recommendation or first branch
144211 useEffect ( ( ) => {
@@ -151,11 +218,17 @@ export function useDraftWorkspaceSettings(
151218 // Setter for selected runtime (also persists host/image for future mode switches)
152219 const setSelectedRuntime = ( runtime : ParsedRuntime ) => {
153220 setSelectedRuntimeState ( runtime ) ;
154- // Persist host/image so they're remembered when switching modes
155- if ( runtime . mode === "ssh" ) {
156- setLastSshHost ( runtime . host ) ;
157- } else if ( runtime . mode === "docker" ) {
158- setLastDockerImage ( runtime . image ) ;
221+
222+ // Persist host/image so they're remembered when switching modes.
223+ // Avoid wiping the remembered value when the UI switches modes with an empty field.
224+ if ( runtime . mode === RUNTIME_MODE . SSH ) {
225+ if ( runtime . host . trim ( ) ) {
226+ setLastSshHost ( runtime . host ) ;
227+ }
228+ } else if ( runtime . mode === RUNTIME_MODE . DOCKER ) {
229+ if ( runtime . image . trim ( ) ) {
230+ setLastDockerImage ( runtime . image ) ;
231+ }
159232 }
160233 } ;
161234
0 commit comments