v0.1.17
Pre-releaseNo new features. Eighteen rounds of one question asked over and over: does this screen tell the truth, and does this button do what it says?
Some of what it found could lose your data.
Fixed — things that could lose something
Two saves at once could destroy the whole vault. Every save wrote the store to one temporary file and renamed it into place, with nothing keeping two of them apart. The timeline records an entry — without waiting for it — on every command, connection and file transfer, so a setting change landing in the same moment was an ordinary second in this app. When they overlapped, what ended up as the vault was half a JSON document, which the next launch could only read as corrupt: set aside, start empty. Every server, key and tunnel, gone. Saves now run one at a time.
Restoring a backup asked nothing and replaced everything. Pick a file, type the passphrase, done — every server, key, tunnel, saved command, group and the entire timeline gone, with no confirmation anywhere. Private keys that exist only on your device are the one thing in this app that cannot be recovered; deleting a single one asks, and deleting all of them did not. It now decrypts first and then asks, showing what is on the device, what is in the file, and that keys do not come back.
When the vault could not be read, the app said nothing. It set the file aside and opened empty, which from your side is indistinguishable from CubePilot having thrown your servers away. The first screen now says what happened, where the old file is, and that a backup will bring it back. If the store cannot be opened at all, it says that too — everything works and nothing is being saved is not something you should have to discover.
A downgrade would have eaten whatever a newer version added. The vault records its format version and never read it back. Installing an older build over a newer one would have dropped everything the newer one knew about, on its first save. Unknown fields are now carried through untouched.
Fixed — things that ran on the wrong machine
Docker and Kubernetes actions could hit a different server than the one on screen. Both pages follow the active session, and both re-resolved that session at the moment the action ran rather than using the one the list came from. Containers have random ids, so those mostly missed. Volumes and networks are addressed by name, and db_data exists on staging and on production. Actions are pinned to the list's session now — and both pages finally say which machine they are showing, which nothing on either screen did before.
The command library never said where a command would run. It fires at whichever session is active — systemctl restart nginx, docker compose down — and said only "Ran X" afterwards. It now names the machine before you tap anything, and again in the confirmation.
A log follow survived switching servers. tail -F kept running against the old server and printed into a page that by then belonged to a different one. The log export named the wrong server in its header for the same reason.
Fixed — SFTP
After a reconnect, the file browser was talking to a socket that no longer existed — every listing, upload and delete, until the app was restarted.
Rename, delete, mkdir and chmod returned quietly when the session was gone. No error, no refresh: renaming a file on a closed session looked exactly like renaming it successfully.
Two panes showing the same session were the same pane — walking into a directory on the left dragged the right one with it.
Downloads and uploads held the whole file in memory, so a database dump was simply unfetchable on a phone; downloads also asked where to save after transferring, throwing away a completed transfer if you cancelled. Both stream now, and an upload that would replace a file asks first.
Fixed — security
The app lock counted nothing. A four-digit PIN is ten thousand guesses and there was no cost to any of them. Five wrong now starts a wait that doubles, and the lock screen counts it down. A vault that says the lock is on with no PIN stored no longer locks you out of your own data for ever.
The CSV timeline export was executable. Spreadsheets read a field starting with = as a formula, and those fields hold whatever a server printed. Defanged.
A changed host key showed only the new fingerprint — the one thing you cannot check it against was the old one, which was not on screen. Fingerprints are also printed the way ssh prints them now, without the base64 padding that made them differ in the last character from what you were comparing against.
Closing a session takes its tunnels with it, and now says so before it happens, naming the forwards that will stop.
Better
Selecting text works where the text is. A bar appears over the terminal the moment something is selected — copy, or dismiss. Right-click copies a selection or pastes when there is none. The select-text sheet opens at the newest output instead of the top.
Shell prompts are coloured. They were the one line the highlighter could never touch, because a prompt arrives without a newline. It is also the only landmark there is when scrolling back through a long session.
Imported keys know what they are. Import used to store the PEM and nothing else: no fingerprint to tell two keys apart, and no public key to paste into a server's authorized_keys — which is most of why anyone imports a key. Both are derived from the key itself now.
A jump-host loop is caught when you save the server, not weeks later on a screen nowhere near the mistake.
Deleting a note or a bookmarked entry asks. Everything else in the timeline still goes with one tap.
Connect outside the VPN is a new per-server switch on Android, for a server the VPN cannot reach. The Android side of it is not in this build — and a session set to use it says so in its own terminal when it opens, rather than pretending.
Upgrading
Installs straight over v0.1.16. Same signing key, so your servers, keys and timeline are untouched.