🌐 Net Remote Panel (SSH / SFTP / SCP)
An official Nuclr Commander plugin that adds a Net file panel root for browsing and managing remote servers over SSH. Built on Apache MINA SSHD, it shares a single SSH session per server for both SFTP (filesystem operations) and SCP (transfers).
✨ What it does
| Feature | Details |
|---|---|
| 📡 Browsing | List remote directories via SFTP, with progressive streaming as entries arrive |
| 🔑 Authentication | Password, or a private key with optional passphrase — OpenSSH, PEM/PKCS#8 and PuTTY PPK (v2/v3) are all auto-detected; every password/passphrase field has a "Show" toggle to verify what was typed |
| 🛡️ Host verification | known_hosts-backed, trust-on-first-use with an explicit fingerprint confirmation; a changed host key is flagged as a possible attack and requires an extra confirmation; Left/Right arrow keys move between the Yes/No buttons, same as Tab |
| 📋 Copy / Move | Both directions (local↔remote, remote↔remote, remote↔other virtual filesystems), with conflict prompts (Overwrite/Skip, with "…All" stickiness) and cancellable progress |
| ✏️ Rename | F6 on a single item within the same folder prompts for a new name and renames it over SFTP |
| 📁 Make Folder / Create File | F7 / Shift+F4 create a new remote directory or empty file |
| 📂 Go to Folder | F9 opens a dialog pre-filled with the current path; accepts an absolute (/var/log) or relative (.., subdir) remote path and navigates there |
| 🗑️ Delete | F8 recursively deletes files/folders over SFTP (always permanent — there is no remote trash) |
| 🔍 Find | Alt+F7 filename search: remote find -iname/-name streamed over an exec channel, falling back to a recursive SFTP walk (used automatically for regex searches, or when find is unavailable) |
| 📜 Tail -F | Live-follow any remote file (tail -F) in its own window, with automatic reconnect on a dropped session |
| 🖥️ Remote shell | Ctrl+O opens the commander's embedded console on an SSH shell channel of the same session — no second connection, no second authentication — starting in the folder the panel is showing. The shell reports its working directory through the terminal title, so cd-ing in the console moves the panel with it |
| 📝 Text / hex editing | F4 downloads to a local temp copy, opens the commander's usual editor picker (text or hex — whichever supports a plain file), watches the copy, detects remote changes made while you edited, and uploads via a hidden temp sibling + atomic SFTP rename |
| 👁️ View / Quick View | F3 and Ctrl+Q both work directly against the mounted SFTP path — no download needed, since the SFTP filesystem is a real java.nio.file.FileSystem |
| 🔌 Shared sessions | One SSH connection per server, shared by both panels and reused for reconnects; connections open lazily on first use |
| 💾 Server profiles | Saved to ~/.nuclr/net/servers.json — passwords/passphrases are never written to disk, only cached in memory for the session, and dropped immediately if the server rejects them so the next attempt prompts again |
| 🗃️ Listing cache | Directory listings are cached per server+path to avoid re-fetching on routine navigation; Ctrl+R ("Refresh") drops the cache for the current folder, and every mutation this plugin makes (create/delete/rename/copy/move/edit) invalidates the affected folder automatically |
| ↕️ Sortable columns | Ctrl+F3..F7/F12 sort by Name, Extension, Size or Modified, or open the sort dialog — the same convention as the local file panel |
⌨️ Keyboard shortcuts
Server-list view (Net root):
| Shortcut | Action |
|---|---|
Enter | Connect (lazily) and open the server's remote root |
F4 | Edit the selected server profile |
F7 | New server profile |
F8 | Remove the selected server profile(s) |
Remote-folder view:
| Shortcut | Action |
|---|---|
F3 | View (streams the file directly over SFTP) |
F4 | Edit (downloads to a temp copy; see above) |
F5 | Copy |
F6 | Move / Rename |
F7 | Make Folder |
F8 | Delete |
F9 | Go to Folder (type or paste an absolute or relative remote path) |
Shift+F4 | Create empty file |
Alt+F7 | Find |
Ctrl+O | Open the embedded console on a remote shell in the current folder |
Ctrl+R | Refresh (clears the cached listing for the current folder) |
Ctrl+F3 / Ctrl+F4 / Ctrl+F5 / Ctrl+F6 | Sort by Name / Extension / Modified / Size |
Ctrl+F7 | Unsort |
Ctrl+F12 | Sort dialog |
| (context menu) | Tail -F on a focused file |
🖥️ Server profile fields
| Field | Description |
|---|---|
| Name | Optional display label; falls back to user@host |
| Host / Port | Hostname or IP; port defaults to 22 |
| Username | SSH login user |
| Authentication | Password, or a private key file (+ optional passphrase) |
| Initial directory | Remote path to open on connect; blank uses the login home directory |
📁 Server configuration file
Profiles are stored at ~/.nuclr/net/servers.json. Passwords and key passphrases are not part of this file at all — there is no blank placeholder field, the schema simply has nowhere to put a secret:
[
{
"id": "a1b2c3d4-...",
"name": "Production Box",
"host": "example.com",
"port": 22,
"username": "alice",
"authMethod": "KEY",
"privateKeyPath": "/home/alice/.ssh/id_ed25519",
"initialPath": "/var/www"
}
]
Host keys are recorded in the standard OpenSSH known_hosts format at ~/.nuclr/net/known_hosts.
📥 Installation
Copy the signed plugin archive and detached signature into the Nuclr Commander plugins/ directory:
filepanel-net-<version>.zip
filepanel-net-<version>.zip.sig
Nuclr Commander verifies the RSA-SHA256 signature against nuclr-cert.pem on load. The plugin becomes available immediately without a restart.
⚙️ How it works
NetConnection(inssh/) wraps one Apache MINA SSHDClientSessionper server: it authenticates (password or key, viaKeyLoader), mounts the SFTP filesystem, and lazily creates SCP clients and exec channels on the same session.ensureOpen()transparently rebuilds a dropped session, so every panel operation reconnects on demand rather than failing outright.ConnectionRegistryis a process-wide, connection-per-server-id map, so both panels (and any number of plugin instances created while navigating) share one SSH session to a given server, plus the in-memory password/passphrase cache for that session.NetResourcewraps entries from the mounted SFTP filesystem as ordinaryNuclrResources backed by a realjava.nio.file.Path. Because the path is genuinely on ajava.nio.file.FileSystem, the host's existing copy engines, quick-view plugins, and viewers work against it with no special-casing — only F4 Edit needs plugin-specific handling (seeNetEditService), since editors need a fast local scratch file with conflict detection rather than reading/writing over the network on every keystroke.NetTransferEnginecopies files into a remote directory: local sources upload via SCP (fast, matches the task's "SCP for transfers" requirement); sources on another virtual filesystem (a different server, an archive mount, …) fall back to a generic stream copy, since SCP is a single-host protocol.NetFindServicestreamsfind -print0output from an exec channel for glob searches, or walks the tree over SFTP (used for regex searches, and as the fallback when the remotefindis missing or fails outright).NetEditServicedownloads the remote file via SCP, hands amainpanel.editevent pointing at the local temp copy to the host (which shows the usual text/hex editor chooser), and polls the temp copy on a background thread. On a save it re-stats the remote file; if it changed since download/last-upload, the user is asked before overwriting. Otherwise it uploads to a hidden temp sibling (.name.nuclr-<token>.tmp) via SCP and renames it over the target with SFTP's overwriting rename (falling back to delete-then-rename if the server rejects that).NetTerminalSessionimplements the SDK'sNuclrTerminalSessionover aChannelShellon the already-openNetConnection, soCtrl+Ocosts neither a new TCP connection nor a second authentication. Closing it closes only the channel, leaving the shared session up for SFTP/SCP. The shell is made to publish its working directory in the terminal title (CWD_TITLE_PREFIX); the panel follows that title so the console and the listing stay on the same folder.NetDirectoryCachecaches each folder's listing (per server id + remote path) so repeat navigation doesn't re-run SFTPreadDir. It's invalidated automatically whenever this plugin performs a write against the cached folder (mkdir, create file, delete, rename, copy/move destination, or a completed F4 upload) and by the user's explicit Ctrl+R; changes made outside the plugin's knowledge (another SSH client, a cron job) are only picked up on that explicit refresh.- SCP path safety — Apache MINA's
ScpClientbuilds itsscp -t/scp -fexec command by concatenating the remote path into the command string with no shell quoting, and the same string is also used verbatim as the literal filename recorded in the SCP protocol stream, so it can't simply be quoted after the fact either. A path with spaces, parentheses or other shell-significant characters breaks the remote invocation outright (surfacing asEOFException: readAck - EOF before ACK).ShellEscape.isSafeForUnquotedScpchecks the target path before every SCP upload/download (copy-into-Net, F4 edit download/upload) and falls back to a plain SFTP read/write for anything that isn't plain ASCII-ish — slower, but always correct.
🗂️ Source layout
src/main/java/dev/nuclr/plugin/core/panel/net/
├── NetFilePanelPlugin.java plugin entry point: navigation, actions, function-key bar
├── NetResource.java a remote file/folder entry (real SFTP-backed Path)
├── NetVirtualResource.java the "Net" root and server-list entries (path-less)
├── find/ Alt+F7 Find: remote find + SFTP-walk fallback, dialog, results window
├── service/ copy/move/delete/mkdir/edit engines and shared dialog helpers
├── NetDirectoryCache.java per-server+path listing cache
├── ssh/ SSH session, SFTP/SCP access, remote shell channel, server profiles, key loading, host-key gate
├── tail/ tail -F viewer window
└── ui/ connection/go-to-folder dialogs, credential/host-key prompts, shared text-field editing (undo/redo, cut/copy/paste/select-all with icons)
📚 Dependencies
| Library | Version | Purpose |
|---|---|---|
dev.nuclr:platform-sdk | 3.0.3 | Nuclr platform interfaces |
sshd-sftp | 2.12.1 | Apache MINA SSHD — SFTP client/filesystem |
sshd-scp | 2.12.1 | Apache MINA SSHD — SCP transfers |
sshd-putty | 2.12.1 | Apache MINA SSHD — PuTTY PPK key parsing |
bcprov / bcutil / bcpkix / bcpg-jdk18on | 1.77 | BouncyCastle — sshd-putty declares these as optional, but PuTTYgen's current default output (PPK v3, Argon2 KDF for encrypted keys) needs them; version pinned to exactly what sshd's own POM specifies |
eddsa | 0.3.0 | Also optional in sshd-putty — needed for ssh-ed25519 PPK keys |
jackson-databind | 2.21.0 | Server profile JSON persistence |
flatlaf / flatlaf-extras | 3.7.1 | FlatSVGIcon for the text-field context menus (provided by the commander host at runtime, not bundled) |
⚠️ Known limitations
- Hex/quick-view writes bypass the atomic-upload flow. F4 Edit routes through the temp-copy-and-atomic-rename workflow described above, so both the text and hex editors get conflict detection there. Quick View (Ctrl+Q) and any other code path that writes directly to the SFTP-backed
Path(rather than going through F4) writes straight to the remote file with a plain SFTP write — no atomicity, no conflict check. - Same-server copies are not server-side. Copying between two folders of the same connection currently downloads-then-uploads over SFTP rather than issuing a server-side copy command; correct, but not as fast as it could be.
tail -Freconnect resumes from "now", not from the exact byte offset. If the SSH session drops mid-tail, a couple of lines written during the gap could be missed (the newtailinvocation starts with-n 0).- Remote
findregex dialects vary too much to target directly (GNU vs BusyBox vs macOS), so regex searches always use the slower SFTP-walk fallback, even when the server'sfindwould have supported an equivalent flag. - No FTP/FTPS support — only SFTP/SCP over SSH, per the task scope.
- Deleting a remote file is always permanent — there is no server-side trash to move it to.
- The directory-listing cache has no cross-server-mutation awareness. A move's destination folder is invalidated by the plugin instance that receives it, but if the source side of a cross-panel move is also a Net panel, its own cached listing isn't proactively invalidated (mirrors a pre-existing gap in the equivalent local-filesystem/move flow) — an explicit Ctrl+R on that side clears it.
- Context-menu icons (
NuclrContextMenuItem.iconKey) are set but not yet rendered by the commander. Nothing in the host currently resolvesiconKeyinto an actual icon for any plugin's context menu, so the New/Edit/Remove Server, Delete and Tail -F entries carry a sensible key (e.g."delete","terminal") for forward compatibility, but show no icon today. The one context menu this plugin fully renders itself — the text-field Cut/Copy/Paste/Undo/Redo/Select All menu in the connection dialog — does show icons, bundled with the plugin.
📜 License
Apache License 2.0 — see LICENSE.