termuna

Moving files

A file moves with the session it belongs to. On a saved SSH host that is an SFTP browser. On the web and the phone it is a files pane beside the live terminal. On any pane that reaches a shell at all, it is a drop that rides the shell's own bytes.

On the desktop: the SFTP browser

On any SSH session opened from the vault, the files button opens an SFTP browser for that host: browse, upload, download, rename, make a folder, delete, without leaving the session. It is a second channel on the connection the session already holds, so it needs no extra credential and nothing installed on the far side beyond an sshd that serves SFTP.

In the web dashboard: the files pane

Open a live session at termuna.com/app and the session bar offers terminal | files. The files pane lists the directory the session's shells are running in, directories first, and the breadcrumb is the path the daemon itself reports. The arrow on a row streams a download through the relay and decrypts it in your browser. Upload by dragging a file onto the pane, behind a dashed scrim that names the destination directory, or with the upload button. Transfers ride in a footer with progress and a cancel on each.

Above 900px the terminal and the pane sit side by side; below it the control shows one at a time. Every failure is one of four named states: the machine is offline, permission was denied, the host's sshd has no SFTP, or the directory is empty. Never a spinner that does not stop.

On the phone

In the native app (Android and iOS, still in the works: see the roadmap), an open session carries one flip under its header, terminal | files. The files side lists the same directory, tapping a directory descends, the breadcrumb walks back up, and tapping a file opens a sheet with its size, when it changed and its permission bits over four verbs: download to the phone's files, share to another app, rename, and delete, which asks once. Upload and new folder sit in the action row.

Transfers ride in a band above that row with a cancel on each. They are owned outside the screen, so a download keeps moving when you flip back to the terminal, where a count chip says how many are still going. A desktop that is asleep says files are not reachable and offers one retry. The web dashboard in the phone's browser has the pane described above, one of the two at a time.

Drop a file on the pane

The three lanes above need an SSH target the daemon can name. The shells people actually drop files on often have none: a second ssh typed at the prompt, a docker exec, a kubectl exec, a jump chain the vault never knew about, a tmux inside an ssh inside an ssh. There is still a working byte stream to that machine right there in the pane, and that is what this lane uses.

Drag a file onto a pane in the desktop app and it lands in that shell's own working directory. While the drag hovers, the scrim prints the file and the shell's own user@host:cwd from the prompt's title, so four hops deep you can see the file lands inside the container and not on the jump host. Several files queue in the order they were dropped.

The transfer is the trzsz protocol: the daemon types trz, the helper on the far side answers with one trigger line, and the file moves as ordinary terminal input and output. No port, no second credential, and on a mirrored session nothing new for the relay, because transfer bytes are pane bytes, sealed like keystrokes. That is why it works past jump hosts, containers and tmux, where SFTP cannot follow.

It needs trz and tsz on the far side. When no helper answers within two seconds, the daemon writes a card into the pane's own output: this shell has no trzsz helper, so the drop cannot start, with the one-line install (pip3 install trzsz) as selectable text and the reminder that the vault SFTP drawer still works for saved hosts. Hosts set up for Tabby or iTerm2 already have the helper.

A file comes back the same way. Type tsz path on the far side and it lands in your downloads folder, or select a path in the scrollback and choose Download from the pane's menu: the app types that same tsz for you. Progress is one row in the pane's output, so it scrolls with the buffer, sits in the replay log and is seen by a phone watching the session. ctrl+c cancels.

What it will not do

  • Overwrite. A file that arrives over the pane never replaces one already there: crash-0828.log is followed by crash-0828 (2).log, and the settled row says which name it got. No dialog interrupts the transfer to ask.
  • Keep half a file. Cancel deletes what was partially written, on both lanes: a cancelled SFTP upload is removed from the host, and a cancelled drop or tsz removes its partial local file. The helper prints Stopped and exits.
  • Send a directory over the pane. A dropped directory is refused as one status-bar line (logs is a directory: only files can be sent over a shell) and the files beside it in the same drop still go. Nothing is zipped in silence.
  • Reach in from a share link. A shared /s/<id> viewer has no files pane. A share link grants eyes on a session, not hands on the machine behind it; files need the dashboard and your own account.
  • Drop from the web or the phone. The drop on the pane is the desktop's, because it is the machine running the shell that types trz. The web and the phone reach files through the pane above.

What the relay learns

Nothing. The files pane on the web and the phone rides the same sealed query channel the session already uses: every name, path, size and byte is encrypted on your device before it crosses the relay, which routes ciphertext and cannot list a directory it forwards. A drop on the pane is pane bytes, sealed exactly like the keystrokes around it. Files are on every plan, free included, under the same live-session limit as everything else.

Next: On a server