Skip to content

Commit 658a11e

Browse files
skulidropekclaude
andcommitted
feat(app): direct SSH (local network) section in VS Code panel
Shows IP:port SSH config without cloudflared — one port per container. Host IP taken from window.location.hostname, port from project.sshPort. - SSH config: Host IP-ssh / HostName IP / Port N / User dev - Command: ssh -p PORT dev@IP - VS Code URI using config alias (no cloudflared needed) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 02a5bd2 commit 658a11e

1 file changed

Lines changed: 29 additions & 1 deletion

File tree

packages/app/src/web/app-ready-terminal-pane.tsx

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,11 +154,12 @@ const handleTerminalKill = (props: TerminalPaneProps, runtime: TerminalPaneRunti
154154
type VsCodeAccessInfo = {
155155
readonly sshUser: string
156156
readonly targetDir: string
157+
readonly sshPort: number
157158
}
158159

159160
const 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

164165
type CfTunnelState =
@@ -170,6 +171,9 @@ type CfTunnelState =
170171
const 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+
173177
const copyText = (text: string): void => { void navigator.clipboard.writeText(text).catch(() => {}) }
174178

175179
const 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

Comments
 (0)