Upload phone files over SFTP and insert remote paths#149
Merged
Conversation
fix: skip Termux setup in Debian release build
fix: make release workflow pass under act
release 1.4.9
Merge pull request #113 from gwitko/fix/ios fix: select hk
feat: android file system access in full version
feat: snippets, keyrow
feat: add website (#104)
fix: apk name
fix: apk name again
feat: add 1.14.4
Add an Upload key to the terminal keyboard bar: pick one or more phone files (photos, videos, documents) with the native picker, stream them to the active SSH host over SFTP, and insert the shell-quoted remote paths into the terminal without executing anything. Uploads land in an app-managed directory — ~/.conduit/uploads/<date>/ by default, configurable per machine (absolute or ~/-relative) in the host form. Directories are created as needed, picked filenames are sanitized to a single path segment with control characters stripped, collisions get a compact time suffix before the extension, and transfers stream chunk-by-chunk through the existing SftpSession.write path with live progress and cancellation (cancel closes the batch session). Every uploaded file is recorded in a per-host manifest (conduit.upload_manifest.v1, defensive parsing). The new per-machine 'Delete my uploads after' setting (never/7/30/90 days) removes only manifest-listed files past the cutoff during later uploads — never arbitrary directories or files Conduit didn't write. Path insertion quotes each path for POSIX shells (spaces, quotes, parentheses, dollar signs, newlines) and joins multiple files with spaces. Insertion never submits, so the user can compose text around the paths. The key ships in the default layout and rides the unseen built-ins migration; local-shell sessions explain that uploads need an SSH machine. New SavedHost fields ride backup export/import via the existing host serialization.
Review follow-ups: files that reached the server are now recorded in the per-host manifest even when a later file fails or the batch is cancelled mid-write, so automatic cleanup can always manage them. Cleanup of expired earlier uploads now runs only after a fully successful batch — failed or cancelled batches never delete anything. Cancelling during connect no longer creates remote directories, and a manifest write failure no longer misreports a successful upload as failed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
User problem
Attaching a screenshot, PDF, or video to an agent prompt from a phone means leaving the terminal, opening SFTP, navigating folders, uploading, then typing a remote path by hand — with any typo or unquoted space silently breaking the command.
New workflow
An Upload key in the terminal key row opens the native file picker (any file type, multiple selection). A confirmation sheet shows each filename, size, and the remote destination — nothing uploads until you confirm. Uploads stream with per-file progress and a working Cancel; on success you can Insert path (each path independently shell-quoted, multiple files joined by single spaces, never submitted — so you can write around them), copy the paths, or close. Local-shell sessions explain that uploads need an SSH machine.
Files land in
~/.conduit/uploads/<yyyy-mm-dd>/by default; each machine's form gains an Upload directory override (absolute or~/-relative) and a Delete my uploads after preference (Never / 7 / 30 / 90 days).Screenshots
Rendered from the real widgets at Pixel-class resolution (1080×2400) via a widget-test screenshot harness.
Technical design
TerminalUploadController(ChangeNotifier) owns one batch: opens a dedicated SFTP session via the existingSftpRepository/SshClientFactoryauth stack, resolves home server-side, creates the directory chain (tolerating existing components), lists the target once for collision detection, then streams each file through the existing chunkedSftpSession.write— nothing is ever loaded wholly into memory. Cancel closes the batch session so an in-flight transfer aborts promptly; the session is always closed infinally.-HHmmsssuffix before the extension, then a counter.posixShellQuotepasses only[A-Za-z0-9._/-](non-leading-dash) through unquoted; everything else is single-quoted with'→'\'', keeping spaces, quotes, parentheses,$, globs, and newlines literal in sh/bash/zsh/fish.conduit.upload_manifest.v1, defensive parsing) — including files that landed before a mid-batch failure or cancel, so nothing app-owned escapes the ledger. Cleanup runs only after a fully successful batch, deletes only exact manifest-listed file paths past the cutoff, and never touches directories or anything Conduit didn't write.SftpUploadFileand the picker pattern are reused from the SFTP browser rather than duplicated.Failure and security behavior
Permission-denied, disk-full, interrupted connections, SFTP-unavailable, duplicate names, zero-byte, and large files all have explicit paths (and tests). A failed or cancelled batch never deletes anything and reports which files did land; credentials and file contents never appear in logs or error strings. New
SavedHostfields default safely for old records and ride backup export/import via the existing host serialization.Test evidence (all executed)
dart format— no diff;flutter analyze— 0 issues;flutter test— 287/287 green.~/-relative/blank), hostile-name sanitization (../../etc/passwd, backslash paths, control chars), collision suffixing, quoting (spaces,$( ), globs, embedded quotes, newlines, leading dash, empty), manifest round-trip/corrupt/partial payloads, controller behaviors (mkdir chain order, progress, custom dir, connect failure, write failure, partial-batch manifest recording, cancel-between-files, cancelled-batch-never-deletes, zero-byte, cleanup-cutoff-only, cleanup-disabled),SavedHostround-trip + corrupt-value defaults, and full widget flows (picker → confirm → progress → insert-quoted-path-without-Enter; error state).sandbox-relayprerelease for sideload testing). iOS: not built — no macOS host available.Dependency / merge order
Based on
master, independent of the other PRs proposed from this fork. It does not stack on the SFTP viewer/file-tabs branches; if those merge first,TerminalPage's new constructor params conflict trivially with the file-tabs PR's identical-shaped change. Addswakelock_plus_platform_interfaceas a dev dependency for widget tests.Manual phone checklist
~/.conduit/uploads/<date>/and that the inserted path is quoted correctly and not executed.