@@ -154,11 +154,12 @@ const handleTerminalKill = (props: TerminalPaneProps, runtime: TerminalPaneRunti
154154type VsCodeAccessInfo = {
155155 readonly sshUser : string
156156 readonly targetDir : string
157+ readonly sshPort : number
157158}
158159
159160const buildVsCodeAccessInfo = ( project : TerminalPaneProps [ "project" ] ) : VsCodeAccessInfo | null => {
160161 if ( project === null ) return null
161- return { sshUser : project . sshUser , targetDir : project . targetDir }
162+ return { sshUser : project . sshUser , targetDir : project . targetDir , sshPort : project . sshPort }
162163}
163164
164165type CfTunnelState =
@@ -170,6 +171,9 @@ type CfTunnelState =
170171const hostSshConfig = ( hostname : string , sshUser : string ) : string =>
171172 `Host ${ hostname } \n User ${ sshUser } \n ProxyCommand cloudflared access ssh --hostname %h\n StrictHostKeyChecking no\n UserKnownHostsFile /dev/null`
172173
174+ const directSshConfig = ( host : string , sshPort : number , sshUser : string ) : string =>
175+ `Host ${ host } -ssh\n HostName ${ host } \n Port ${ sshPort } \n User ${ sshUser } \n StrictHostKeyChecking no\n UserKnownHostsFile /dev/null`
176+
173177const copyText = ( text : string ) : void => { void navigator . clipboard . writeText ( text ) . catch ( ( ) => { } ) }
174178
175179const vsCodePanelCodeStyle : CSSProperties = {
@@ -220,6 +224,10 @@ const VsCodeAccessPanel = (
220224 const cfVscodeUri = cfState . tag === "ready"
221225 ? `vscode://ms-vscode-remote.remote-ssh/open?hostName=${ encodeURIComponent ( `${ info . sshUser } @${ cfState . hostname } ` ) } &folder=${ encodeURIComponent ( info . targetDir ) } `
222226 : null
227+ const directHost = window . location . hostname
228+ const directConfig = directSshConfig ( directHost , info . sshPort , info . sshUser )
229+ const directCommand = `ssh -p ${ info . sshPort } ${ info . sshUser } @${ directHost } `
230+ const directVscodeUri = `vscode://ms-vscode-remote.remote-ssh/open?hostName=${ encodeURIComponent ( `${ directHost } -ssh` ) } &folder=${ encodeURIComponent ( info . targetDir ) } `
223231 return (
224232 < div style = { {
225233 background : "#0d1520" ,
@@ -278,6 +286,26 @@ const VsCodeAccessPanel = (
278286 ) }
279287 </ >
280288 ) }
289+
290+ < div style = { { borderTop : "1px solid #2a4060" , margin : "14px 0 10px" } } />
291+ < div style = { { color : "#8be9fd" , fontWeight : "bold" , marginBottom : "8px" } } > Direct SSH (local network)</ div >
292+
293+ < div style = { { color : "#8be9fd" , fontSize : "0.9em" , fontWeight : "bold" } } > Add to ~/.ssh/config</ div >
294+ < div style = { { color : "#8fa6c4" , fontSize : "0.78em" } } > no cloudflared needed — works on same LAN</ div >
295+ < code style = { vsCodePanelCodeStyle } > { directConfig } </ code >
296+ < button onClick = { ( ) => { copyText ( directConfig ) } } style = { vsCodePanelCopyBtnStyle } type = "button" > copy</ button >
297+
298+ < div style = { { color : "#8be9fd" , fontSize : "0.9em" , fontWeight : "bold" , marginTop : "10px" } } > Connect via SSH</ div >
299+ < code style = { vsCodePanelCodeStyle } > { directCommand } </ code >
300+ < button onClick = { ( ) => { copyText ( directCommand ) } } style = { vsCodePanelCopyBtnStyle } type = "button" > copy</ button >
301+
302+ < div style = { { color : "#8be9fd" , fontSize : "0.9em" , fontWeight : "bold" , marginTop : "10px" } } > Open in VS Code</ div >
303+ < div style = { { color : "#8fa6c4" , fontSize : "0.78em" } } > requires config entry above in ~/.ssh/config</ div >
304+ < div style = { { marginTop : "4px" } } >
305+ < a href = { directVscodeUri } style = { { color : "#56f39a" , cursor : "pointer" , fontFamily : "inherit" , fontSize : "inherit" , fontWeight : "bold" , textDecoration : "none" } } >
306+ open in VS Code (direct)
307+ </ a >
308+ </ div >
281309 </ div >
282310 )
283311}
0 commit comments