<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[dhlptx00]]></title><description><![CDATA[dhlptx00]]></description><link>https://dhlptx00.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Wed, 21 Oct 2026 09:52:37 GMT</lastBuildDate><atom:link href="https://dhlptx00.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[I built an SSH terminal for VS Code and Cursor where Ctrl+click downloads the file]]></title><description><![CDATA[Version 0.4.0: a cleaner home screen, guided /new with Test connection, colors that follow your theme, and a Ctrl+click menu to download, open, rename or…]]></description><link>https://dhlptx00.hashnode.dev/ssh-terminal-vs-code-cursor-ctrl-click-download</link><guid isPermaLink="true">https://dhlptx00.hashnode.dev/ssh-terminal-vs-code-cursor-ctrl-click-download</guid><category><![CDATA[VS Code]]></category><category><![CDATA[ssh]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Linux]]></category><category><![CDATA[open source]]></category><dc:creator><![CDATA[DHLPTX00]]></dc:creator><pubDate>Sun, 04 Oct 2026 02:18:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ac1b6874d1f4eb76c7dd2fa/26541e89-1543-4435-80fa-c8078aeb859e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I'm a solo developer, and this is a short write-up of a small, free, MIT-licensed extension I made: <strong>Easy SSH</strong>, an SSH terminal that lives inside VS Code and Cursor. Updated for Easy SSH 0.4.0 (Oct 5, 2026).</p>
<p><img src="https://raw.githubusercontent.com/dhlptx00/EasySSH/b1b0aae04988aaad4dbf79368be3ff1a647603f1/media/readme/infographic-0.4.0.png" alt="Easy SSH overview: a home screen with your recent connection, a guided /new setup with Test connection, colors that follow your VS Code theme, sign-in options, jump hosts, a real login shell, a Ctrl+click or Cmd+click menu to download, open, rename or delete a file or folder, editing a remote file in a VS Code tab, and drop to upload" /></p>
<h3>The itch</h3>
<p>Most of my SSH sessions are not "develop on the server" sessions. They're "log in, look at something, grab a file, maybe fix a config" sessions. For that I wanted:</p>
<ul>
<li>a list of my servers, including ones behind a bastion</li>
<li>a normal login shell, not a special file browser</li>
<li>a way to get a file (or a whole folder) off the box without switching to <code>scp</code> and retyping the path</li>
<li>a quick way to fix a line in a remote config without leaving the editor</li>
<li>nothing installed on the server, and no remote editor downloaded when I connect</li>
</ul>
<h3>What it does</h3>
<p>Click the Easy SSH icon in the activity bar and you get a home screen in a terminal tab. 0.4.0 redesigned it:</p>
<ul>
<li>A <strong>Last:</strong> line names the connection you used most recently. The list starts on it, so opening Easy SSH and pressing Enter reconnects.</li>
<li>The table shows each connection's user@host:port, how it signs in (key, password, agent, or "key via bastion" for a jump host) and when you last used it.</li>
<li>When the terminal is tall enough, the selected connection's details (host, port, sign-in, jump host, start folder) show under the list.</li>
<li>One line of key hints at the bottom, and a different tip in the prompt each time.</li>
</ul>
<p>Type <code>/</code> for commands (<code>/new</code>, <code>/edit</code>, <code>/delete</code>, <code>/import</code>, <code>/folder</code>, <code>/quit</code>), or <code>/name</code> to connect to a saved connection by name.</p>
<p><img src="https://raw.githubusercontent.com/dhlptx00/EasySSH/b1b0aae04988aaad4dbf79368be3ff1a647603f1/media/readme/01-connection-list.png" alt="The Easy SSH home screen: the Last line, a table with host, sign-in method and last use, and the selected connection's details" /></p>
<h3>Adding a server</h3>
<p><code>/new</code> used to be a long form. It's now a short wizard: Step 2 of 6, one field per step with a help line under it, and a red message as soon as a value can't work (an empty host, a port that isn't a number from 1 to 65535, a key file that doesn't exist). Esc goes back one step.</p>
<p>The last page shows every value and the matching <code>ssh</code> command, so you can see exactly what will happen. From there, <strong>Test connection</strong> connects, signs in and opens SFTP <em>without saving</em>. If the password is wrong or the key isn't accepted, you find out now rather than on the first real connect. Then <strong>Save</strong>, or Enter on any value to change just that field.</p>
<p><img src="https://raw.githubusercontent.com/dhlptx00/EasySSH/b1b0aae04988aaad4dbf79368be3ff1a647603f1/media/readme/20-new-connection-test.png" alt="The last page of /new: every value, the matching ssh command, and a successful Test connection" /></p>
<p><code>/edit</code> opens the same page for a saved connection: pick a field, change it, save. <code>/delete</code> asks in red with the name and host, and "No, keep it" is selected by default.</p>
<h3>Colors that follow your theme</h3>
<p>Easy SSH now has two palettes, Easy SSH Dark and Easy SSH Light, and it picks one from your VS Code theme. A dark theme gets Dark, a light theme gets Light, and high-contrast themes get the one that matches their brightness. Change the VS Code theme and an open Easy SSH terminal recolors right away. There's no setting to set.</p>
<p>Both palettes draw on VS Code's own terminal background. The purple and pink from the icon are only used for the brand mark, accents and a soft tint on the selected row, and text contrast is at least 4.5:1 on VS Code's default backgrounds.</p>
<p><img src="https://raw.githubusercontent.com/dhlptx00/EasySSH/b1b0aae04988aaad4dbf79368be3ff1a647603f1/media/readme/21-theme-light.png" alt="Easy SSH Light with VS Code's Light Modern theme" /></p>
<p>Connected shells get the palette's cursor and ANSI colors as well, in Easy SSH terminals only. The terminal's own colors come back when the session ends, and <code>easySsh.themeSession</code> turns this off.</p>
<h3>The shell and the Ctrl+click menu</h3>
<p>Connecting opens your login shell in your home directory. Aliases, <code>vim</code>, <code>less</code>, <code>top</code> and <code>sudo</code> work as they do over <code>ssh</code>. File and folder names in the output are links: Ctrl+click one (Windows/Linux) or Cmd+click it (macOS) and a small menu opens. Its title shows the name and the folder it's in, for example <code>access.log â€” /home/deploy/logs</code>.</p>
<ul>
<li><strong>Files:</strong> Download, Open, Rename, Delete.</li>
<li><strong>Folders:</strong> Download (the whole folder, subfolders included), Upload, Rename, Delete.</li>
</ul>
<p><img src="https://raw.githubusercontent.com/dhlptx00/EasySSH/b1b0aae04988aaad4dbf79368be3ff1a647603f1/media/readme/08-folder-action-menu.png" alt="The action menu for the folder logs: Download, Upload, Rename, Delete" /></p>
<p><img src="https://raw.githubusercontent.com/dhlptx00/EasySSH/b1b0aae04988aaad4dbf79368be3ff1a647603f1/media/readme/09-file-action-menu.png" alt="The action menu for the text file access.log: Download, Open, Rename, Delete" /></p>
<p>What each one does:</p>
<ul>
<li><strong>Download</strong> is first, so Ctrl+click and then Enter downloads. It opens a save dialog (a folder picker for a folder) that starts in your Downloads folder; <code>/folder</code> changes that default. A folder keeps its structure and permission bits. Big transfers show a progress notification with a Cancel button.</li>
<li><strong>Upload:</strong> drag files or folders onto the terminal and they land in the current remote directory, as before. To put files into a different folder, Ctrl+click that folder and choose <strong>Uploadâ€¦</strong>. If something with the same name already exists, it asks first: Replace, Keep Both, or Skip.</li>
<li><strong>Rename</strong> and <strong>Delete</strong> ask before they change anything. Deleting a folder tells you how many files are in it first, for example <code>Delete folder "logs" and its 128 files?</code>.</li>
<li><strong>Open</strong> puts a text file in an editor tab. More on that below.</li>
</ul>
<p>Names you create with commands (<code>touch notes.md</code>, <code>mv a b</code>, <code>tar xf release.tgz</code>) are clickable as soon as the prompt comes back, without a <code>cd</code>. To change directory, you type <code>cd</code> as in any shell; Tab completes remote paths.</p>
<p>Hovering a name underlines it and lists what you can do with it, for example "Folder logs: download, upload into, rename, delete". Normal mouse selection still works for copying text.</p>
<h3>Open a remote file in an editor tab</h3>
<p>Added in 0.3.0. Ctrl+click a text file, choose <strong>Open</strong>, and the file opens in a normal VS Code editor tab with syntax highlighting, search and everything else the editor has. <strong>Ctrl+S</strong> (Cmd+S on macOS) saves it straight back to the server.</p>
<p><img src="https://raw.githubusercontent.com/dhlptx00/EasySSH/b1b0aae04988aaad4dbf79368be3ff1a647603f1/media/readme/16-open-in-editor.png" alt="config.yaml opened from the terminal in an editor tab; after Ctrl+S the shell below shows the saved change" /></p>
<p>A few details I cared about:</p>
<ul>
<li><strong>Open is only offered for text files.</strong> Easy SSH decides by the name first (<code>.yaml</code>, <code>.log</code>, <code>.conf</code>, <code>.sh</code>, <code>Dockerfile</code>, <code>authorized_keys</code>â€¦ are text; <code>.tar.gz</code>, <code>.png</code>, <code>.so</code>â€¦ are not). For any other name it reads the first 8 KB: no NUL bytes and valid UTF-8 means text. An archive or a binary gets Download, Rename and Delete only.</li>
<li><strong>Big files ask first.</strong> A text file over 5 MB shows its size and asks: Open Anyway, Download, or Cancel. Files over 256 MB aren't opened in the editor.</li>
<li><strong>Changed on the server?</strong> If someone else (or a command in your shell) changed the file after you opened it, saving shows both versions' size and time and asks before overwriting.</li>
<li><strong>Disconnected?</strong> The save fails with a message that says so, and your edits stay in the editor. Reconnect and save again.</li>
<li><strong>Permissions stay as they were.</strong> A save writes a temporary file next to the original with the same permissions, then puts it in place. A symlink stays a symlink, and a file owned by another user is rewritten in place so its owner doesn't change.</li>
</ul>
<p>It's one file at a time, opened from the shell. It's not a remote workspace with a file explorer.</p>
<h3>Sign-in and jump hosts</h3>
<p>You can sign in with a password (saved, or asked every time), a private key, or an SSH agent (on Windows, the OpenSSH agent or Pageant). Two-factor prompts are shown in the terminal. You can hop through one or more jump hosts, and <code>/import</code> reads <code>~/.ssh/config</code> while keeping the <code>ProxyJump</code> chain and <code>Host *</code> defaults. New servers show their host key fingerprint, and Easy SSH connects only after you accept it.</p>
<p><img src="https://raw.githubusercontent.com/dhlptx00/EasySSH/b1b0aae04988aaad4dbf79368be3ff1a647603f1/media/readme/12-jump-host-session.png" alt="A shell on staging-db, reached through a jump host" /></p>
<h3>How it knows where you are</h3>
<p>This was the fun part. When the shell starts, Easy SSH sends one line that adds a bash <code>PROMPT_COMMAND</code> hook (a zsh <code>precmd</code> function, or a fish prompt event handler). The hook prints <code>$PWD</code> as an OSC 7 escape sequence before every prompt. The extension reads that, so it always knows the remote directory, and it doesn't install anything on the server to do it. The line is sent after the login message, its echo is hidden, and it's kept out of your shell history.</p>
<p>File and directory names are exposed as VS Code terminal links, which is why it's Ctrl+click on Windows/Linux and Cmd+click on macOS, and why normal mouse selection still works. After each command, Easy SSH lists the current folder again over SFTP (once, shortly after the prompt returns), which is how new names become links without a <code>cd</code>. VS Code can keep an old link under a pointer that hasn't moved while the text below it changes (for example after <code>clear &amp;&amp; ls</code>), so Easy SSH checks the row when you click: it acts on the name that's there now, or asks you to click again if it can't tell.</p>
<p>The editor tab has an address like <code>easyssh://&lt;connection&gt;/&lt;path&gt;</code>. It reads and saves through the terminal's own SFTP connection, as the user you signed in as.</p>
<p>When Easy SSH <em>can't</em> know the directory, for example after <code>sudo su</code>, it follows the <code>cd</code> commands it can see and otherwise doesn't guess. An upload then asks whether to use the last known directory, your home directory, or a path you type. Transfers always run over SFTP as the user you logged in as, so Easy SSH shows you the <code>sudo mv</code> command to finish the job.</p>
<h3>What changed in 0.4.0</h3>
<ul>
<li><strong>New home screen:</strong> the Last line (Enter reconnects), a table with sign-in method and last use, the selected connection's details, and Getting started when the list is empty.</li>
<li><strong><code>/new</code> is a step-by-step wizard</strong> with inline checks and a summary page with the <code>ssh</code> command.</li>
<li><strong>Test connection</strong> before you save a new or edited connection.</li>
<li><strong><code>/edit</code></strong> opens the summary and changes one field at a time. <strong><code>/delete</code></strong> asks in red.</li>
<li><strong>Easy SSH Dark and Light</strong> palettes that follow the VS Code theme and switch live.</li>
<li>A smaller extension: dead code removed, 213 KB VSIX.</li>
</ul>
<p>0.3.0 (the day before) made Ctrl+click open an action menu (Download, Open, Rename, Delete) and added editing remote files in an editor tab. The full list is in the <a href="https://github.com/dhlptx00/EasySSH/blob/main/CHANGELOG.md">changelog</a>.</p>
<h3>Limitations (being honest)</h3>
<ul>
<li>It targets Linux and Unix servers; Windows servers aren't supported. Folder tracking works with bash, zsh and fish.</li>
<li>Downloads, uploads and Open need SFTP on the server. Without it you still get the terminal, but no file transfers.</li>
<li>A single upload or folder download is capped at 5000 files, and symbolic links inside folders are skipped.</li>
<li><code>ProxyCommand</code> isn't supported; use <code>ProxyJump</code>.</li>
<li>Transfers and saves run as the user you signed in as, even after <code>sudo su</code>.</li>
<li>Editing is one file at a time, opened from the shell. It's not a remote workspace: no remote file explorer, language servers or debugging. Remote-SSH is the better tool for that.</li>
<li>It's version 0.4.0 and still young.</li>
</ul>
<h3>Try it</h3>
<ul>
<li>VS Code Marketplace: <a href="https://marketplace.visualstudio.com/items?itemName=easy-ssh.easy-ssh">https://marketplace.visualstudio.com/items?itemName=easy-ssh.easy-ssh</a></li>
<li>Open VSX (Cursor, VSCodium): <a href="https://open-vsx.org/extension/easy-ssh/easy-ssh">https://open-vsx.org/extension/easy-ssh/easy-ssh</a></li>
<li>Source and issues: <a href="https://github.com/dhlptx00/EasySSH">https://github.com/dhlptx00/EasySSH</a></li>
</ul>
<p>Bug reports and "this broke on my server" stories are the most useful thing you could send me.</p>
<p><em>If it saves you time, there's a <a href="https://buymeacoffee.com/dhlptx00">Buy Me a Coffee</a> link. No pressure.</em></p>
<p><em>Disclosure: I used AI assistance for parts of the code and this write-up; I reviewed and tested everything myself.</em></p>
<hr />
<p><em>Originally published on <a href="https://dev.to/dhlptx00/i-built-an-ssh-terminal-for-vs-code-and-cursor-where-ctrlclick-downloads-the-file-296f">DEV</a>.</em></p>
]]></content:encoded></item></channel></rss>