[3.8.0] - 2026-05-15
AeroVault Wrapper-Stack, Behind-the-Scenes Telemetry, AeroRsync Streaming and Dual-Panel Unification
A large release across three fronts: the AeroVault v3 wrapper stack gets real small-file packing and a behind-the-scenes technical receipt, the native AeroRsync engine ships streaming and enabled by default, and the AeroFile dual panel grows endpoint-aware unification. It also lands the v3.8.0 wishlist batch and the CLI profile-management fixes from issues #194, #195, #196 and #180.
The AeroVault wrapper-stack design (the compression -> chunking -> crypt -> error-correction pipeline, the wrapper-vs-step taxonomy, the corrected AES-256-GCM-SIV avalanche framing, algorithm versioning as a forward-compat clause, and the small-file-packing model) is a sustained community design contribution by Ehud Kirsh in the COMMUNITY ROADMAP thread (#162). The wrapper-stack hardening and telemetry land in commits 406e273c (engine), abad0cba (receipt UI plus 47-language i18n) and ed01fbe3 (CLI vault subcommand documentation). Credit is inline in every receipt and in the architecture primer.
AeroRsync Native Streaming, Session Reuse, Default ON, and Local-to-Local Sync
This release closes the P3-T01 cap and the Track Z.1 + Z.2 AeroRsync/AeroFile convergence work (internal roadmap APPENDIX-Z). It is the first release where the native rsync delta-sync engine ships enabled by default on fresh installs and no longer caps file size at 256 MiB.
Streaming end-to-end. The upload and download paths now stream delta plans through iterator-style state machines (send_delta_phase_streaming on the upload side, apply_delta_streaming + StreamingAtomicWriter on the download side). The 256 MiB in-memory cap that previously gated multi-gigabyte files is gone. A 4 GB cold upload and a 4 GB file re-synced after a 5% mutation both completed end-to-end against a real WD My Cloud NAS over residential SSH (862s / 846s wall clock respectively), confirming feature parity with the wire protocol and headroom for arbitrary file sizes. The writer ensures kill-9 safety by writing to a .aerotmp temp file and renaming atomically on completion.
Batch session reuse. Multi-file batches now share a single SSH session via AerorsyncBatch. A 100-file batch (1.1 MiB each) against the Docker fixture archives delta_session_count = Some(1) and a 99.45% savings on the second pass. The session-pool spec keeps short-lived sessions to side-step long-running NAS embedded-SSH lock-ups, and the new delta_session_count / delta_bytes_on_wire fields are surfaced in SyncReport, plumbed into the AeroSync UI as syncPanel.deltaBatchSummary and syncPanel.deltaBytesOnWire, and translated across all 47 locales.
Host-key pinning symmetric across transports. Classic SFTP (libssh2) and native probe (russh 0.57) now use the same AERORSYNC_HOST_KEY_ALGS ordering (Ed25519 → ECDSA → RSA SHA-2). Previously the two transports could land on different host keys when a server exposed multiple, which produced a fingerprint mismatch during pin verification. Both transports now publish identical preferences via session.method_pref (libssh2) and russh::Preferred.key (russh).
Default ON. load_native_rsync_enabled() now returns true when no config file exists. Existing installs with a TOML config keep their stored choice (no breaking change). Users on a fresh boot get the native delta engine automatically; the legacy classic SFTP path remains opt-in via Settings > Sync > Use native rsync = off or by editing the config.
Wire preamble robustness. A 2 to 3% hard-rejection rate on high-cardinality batches (≥ 50 files over a single SSH session) was traced to read_u8_len_prefixed_ascii returning InvalidAlgoListLen (terminal) when the SSH read chunk happened to end exactly on a length byte of the algo list. The parser now returns TruncatedBuffer { needed, available } (recoverable), letting the preamble exchange loop continue reading. Two regression unit tests pin the behaviour, and the Z.1.1 KPI batch test now asserts errors = 0 (pre-fix: 2/100).
Local-to-local AeroSync (Z.2 track). A new LocalDeltaTransport implements the same DeltaTransport trait against pure local paths, bypassing SSH entirely. Files at or above 1 MiB go through the in-process delta engine; smaller files fall back to plain copy. Exposed two ways: the CLI auto-detects aeroftp sync <SRC> <DST> when both arguments are local paths (smoke: 99.91% savings on a 1-byte mutation of a 2 MiB file), and a dedicated AeroSync panel reachable from View → Local Sync... and from the command palette. The panel offers source and destination pickers, exclude patterns, a delta-transport toggle, dry-run preview, live progress events (local-sync-progress), and a final report with byte-savings percentage.
AeroVault v3 Wrapper-Stack Hardening and Behind-the-Scenes Telemetry
Real small-file packing. The packing: small-file-batching wrapper declared in the v3 manifest is now actually exercised by the write path. Previously the manifest advertised the wrapper but the writer processed one file at a time, so a tree of small files was never packed and the CDC chunker saw one tiny entry per file. The packing stage now concatenates sub-threshold files (engine-derived 256 KiB boundary) into a pure-concatenation pack with the manifest as the index (offset plus length per file, no in-pack frame headers, the "tar-ish framing without metadata bloat" agreed in #162). The CDC chunker runs over the pack, so chunks stay multi-MiB and dedup stays chunk-aligned regardless of how small the inputs are. The change is additive and serde-compatible (pack_offset: Option<u64> with #[serde(default)]): existing v3 vaults open and extract byte-identically with no format bump, the format stays v3 Beta. Verified end-to-end through the new CLI vault subcommand: a 254-file round trip (250 small, 2 duplicates, 2 large above threshold) collapsed to 4 physical chunks with 251 dedup hits and byte-identical extraction 254/254.
Behind-the-scenes technical receipt. A shared vault_telemetry module records the per-operation wrapper trail (packing, chunking, chunk-id, compression, crypt, cipher hash), plaintext vs compressed bytes, compression ratio, dedup count, chunk count and timing, and surfaces it as a VaultReport. A new in-modal receipt panel shows the wrapper stack and the numbers after a vault create/add, exportable as text, and an Activity Log entry records each vault operation with the same redaction pipeline as the rest of the Debug Panel buffer. The receipt carries an inline academic attribution to Ehud Kirsh for the wrapper-stack design. The module is wired across v1, v2 and v3 so the receipt is consistent regardless of vault tier.
CLI vault subcommand (v1, v2, v3). aeroftp-cli vault exposes the create/add/info/extract lifecycle for every AeroVault format. The on-disk version is auto-detected from the file header for info/add/extract (v3 magic, v2 self-describing, else the legacy v1 WinZip-AES container); --vault-version selects it explicitly and create defaults to v3 (--cascade enables the v2 paranoid mode). add --receipt prints the technical receipt. The library crate gained the necessary pub surface for the binary to call each engine directly. Round-trip verified byte-identical on v1, v2 and v3 with wrong-password rejection.
AeroFile Dual-Panel Unification (issue #162 Slice B + Slice C bridge)
The dual-panel surface from T-DUAL-PANEL-UNIFICATION advances past Slice A: a unified panel controller with an endpoint selector and a transfer planner that routes local/local, local/remote and remote/local through the right engine, plus a FreeFileSync-style compare panel (6-bucket classifier), sync presets, conflict policy with versioned backup, inline cross-profile transfer from the planner, and the terminal cwd following the focused panel. The local-to-local Copy/Move chips are exposed for setup-only selectors and translated across all 47 locales.
Provider Modes and AeroCrypt
OpenDrive gains a Native API plus WebDAV mode group, the generalized ProviderModeTabs (lifted from FileLuSubTabs) adds a Filen group and fixes legacy-profile edit and connect, and the FileLu Rsync R2 dedicated provider lands behind the engine-awareness and classic-availability gate. AeroCrypt gains path-overlay decode plus mkdir and rename with encrypted names (#179).
v3.8.0 Wishlist and CLI Profile Management (issues #180, #194, #195, #196)
The CLI profile-management batch from the wishlist and the three profile bug reports lands here. aeroftp-cli profiles -i gets a substantial interactive-shell refactor (multi-target selectors, 0/-1/q quit, tombstone reprint, f/r/c/e actions with colour cues), a scriptable profile-add / profile-duplicate, vault-first profile reconcile so CLI deletes propagate to the GUI, favourites moved into the vault (config_favorite_servers) so the Fav column renders, the Type column renamed to Badges to match the GUI, the real OAuth error surfaced before browser re-auth, the Activity Log Errors filter including status=error rows, and a quick-win polish pass (eye-icon hit area, search-by-badges). This release also closes the four open items from the post-09:36 wishlist replies: an exclusive --show allowlist with */all wildcard, the font-size popup at the min/max bound, the server Duplicate action renamed to Copy, and the docs.aeroftp.app PWA meta deprecation.
Storage Quota, Vault CLI Parity and Compression Telemetry (Ehud batch 2)
A second interactive batch with Ehud Kirsh: storage accounting for the many backends that expose no quota API, full CLI vault parity, a methodology fix for the MEGA speed test, and the compression telemetry surfaced as opt-in columns. A user-set manual total cap is now a true override (it wins even over an API total, because SFTP statfs reports the whole server disk, not the user's allotment) and an explicit, user-triggered recursive scan supplies used for no-quota FTP/FTPS/SFTP/S3/WebDAV; both are cached on the profile and reconciled against the live connection identity so a scanned figure can never land on the wrong card across open sessions.
Added
- AeroRsync streaming upload and download (W1, W2): the 256 MiB size cap is removed on both ends. Iterator-style delta plans (
send_delta_phase_streaming,apply_delta_streaming) stream signatures and literals through the SSH session without buffering the full file in memory.StreamingAtomicWriterwrites the reconstructed target to a temp file and renames atomically on success, kill-9-safe. Validated against 4 GB cold and 4 GB modified files over real residential SSH. - Batch session reuse (W3):
AerorsyncBatchshares one SSH session across a multi-file batch.delta_session_countanddelta_bytes_on_wireare recorded inSyncReportand surfaced in the AeroSync UI undersyncPanel.deltaBatchSummary/syncPanel.deltaBytesOnWire, translated in all 47 locales. - Native rsync ON by default: fresh installs (no
~/.config/aeroftp/sync.toml) now enable the native rsync engine. Existing installs keep their stored choice. LocalDeltaTransportfor local-to-local sync (Z.2.1): in-process delta engine that bypasses SSH for two local paths. Includes Unix mode and mtime preservation,write_atomic_chunkedfor kill-9 safety, aLOCAL_DELTA_MAX_IN_MEMORY_BYTES = 256 MiBguardrail with explicitTransferFailedfor caller-side fallback, and aTooSmallfast path for files below 1 MiB.- CLI
synclocal-to-local (Z.2.2):aeroftp sync <SRC> <DST>auto-detects when both arguments are local paths and routes throughLocalDeltaTransport.--localforces detection,--no-local-deltafalls back to plain copy.--dry-run,--exclude, and--jsonare supported. JSON shape:{status, uploaded, skipped, errors, elapsed_ms, total_payload_bytes, bytes_on_wire, savings_ratio}. - AeroSync Local-to-Local panel (Z.2.3): new dedicated modal reachable from View → Local Sync... and from the command palette (Ctrl+Shift+P → "AeroSync: Local to Local"). Two folder pickers via
@tauri-apps/plugin-dialog, exclude patterns (comma or newline separated globs), delta-transport toggle (on by default), dry-run mode, live progress bar driven by thelocal-sync-progressTauri event, and a final report with byte counters and savings percentage. The Tauri commandlocal_sync_runis feature-gatedaerorsync(and the feature is on by default). - AeroVault behind-the-scenes technical receipt: a shared
vault_telemetrymodule records the per-operation wrapper trail, plaintext/compressed bytes, compression ratio, dedup count, chunk count and timing into aVaultReport. An in-modal receipt panel renders the wrapper stack and the numbers after every vault create/add, exportable as text, with an Activity Log entry per operation (redacted through the existing Debug Panel pipeline). Inline academic attribution to Ehud Kirsh for the wrapper-stack design. Wired across v1/v2/v3 so the receipt is tier-consistent. Commitabad0cba, i18n in all 47 locales. - AeroVault v3 real small-file packing: the
packingwrapper now concatenates sub-256-KiB files into a pure-concatenation pack indexed by the manifest, so the CDC chunker sees a wide stream and dedup stays chunk-aligned. Additivepack_offset: Option<u64>with#[serde(default)], no format bump, existing v3 vaults extract byte-identically. Commit406e273c. - CLI
aeroftp-cli vaultsubcommand (v3): scriptable v3 vault lifecycle (create/open/add/extract/list/info) calling the same engine as the GUI;add --receiptprints the technical receipt to stdout; round-trip verified on 254 files (251 dedup hits, 4 physical chunks, byte-identical extraction). Documented indocs/CLI-GUIDE.md, commited01fbe3. - CLI
vaultv1 and v2 parity (Ehud):aeroftp-cli vault {create,add,info,extract}now handles the legacy v1 WinZip-AES container and the v2 AES-256-GCM-SIV format alongside v3, calling the exact backend the GUI invokes. Format auto-detected from the file header;--vault-versionto force it;createdefaults to v3 with--cascadefor the v2 paranoid mode; v1 extract accepts a directory destination like v2/v3. Live round-trip verified byte-identical on all three with wrong-password rejection. - Manual total-storage override (Ehud): optional
options.manualTotalBytesper profile, accepts a human size in the connection form; it is a TRUE override that wins even over an API-reported total. SingleresolveEffectiveQuotarule shared by the GUI (StatusBar, My Servers card and table) and the CLI (df,profiles), with a source marker (api/manual/scan). - Explicit used-storage scan (Ehud): a user-triggered recursive scan computes
usedfor no-quota backends (S3 list-recursive, WebDAVDepth:infinitywith a files>0 guard and BFS fallback, generic BFS elsewhere). Never automatic on connect. CLIdf --scan/--full; in the GUI the StatusBar quota chip is click-to-rescan, with a cancellable progress, a scanned file count shown next to the byte figure, and the whole lifecycle (method + result) tracked in the Activity Log for every backend. The figure is cached on the profile and incrementally adjusted on upload instead of forcing a rescan. - Compression
Saved/Saved%columns (Ehud #162): the per-operation vault telemetry is aggregated into a per-profilelastCompressionwritten whenaeroftp-cli --profile <name> vault addruns against it. Two optional, default-hidden columns expose it inaeroftp-cli profiles(--show/--hide/*aware, text and JSON) and in the My Servers table column picker. - AeroFile dual-panel endpoint unification (issue #162 Slice B + Slice C bridge): unified panel controller with an endpoint selector and a transfer planner routing local/local, local/remote and remote/local through the correct engine; FreeFileSync-style compare panel with a 6-bucket classifier; sync presets; conflict policy with versioned backup; inline cross-profile transfer from the planner; terminal cwd follows the focused panel. Local-to-local Copy/Move chips exposed for setup-only selectors, translated in all 47 locales.
- OpenDrive Native API + WebDAV mode group: OpenDrive joins the generalized
ProviderModeTabs(lifted fromFileLuSubTabs) with a Native API plus WebDAV selector; a Filen group is added and legacy-profile edit/connect is fixed. FileLu Rsync R2 lands as a dedicated provider behind the engine-awareness and classic-availability gate. - AeroCrypt encrypted-name path operations (#179): path-overlay decode plus mkdir and rename with encrypted names.
aeroftp-cli profile-add/profile-duplicate: scriptable CLI counterparts to the GUI New Server and Duplicate flows, JSON output via--json, protocol validated against the GUI registry. Plus theprofiles -iinteractive-shell refactor: multi-target selectors (mix indices and names, shell-quoted),0/-1/qquit, tombstone reprint with red strikethrough,f/r/c/eactions with colour cues, zebra-striped rows.
Fixed
- Host-key fingerprint drift between transports (Z.1.4):
ssh_transport.rs(libssh2 classic SFTP) andrussh_session_transport.rs(russh native probe) now publish the sameAERORSYNC_HOST_KEY_ALGSordering. Servers exposing multiple host keys (typical OpenSSH default) no longer land on different fingerprints between the two transports, which previously could produce a pin mismatch on first use. - Wire preamble truncation misclassified as hard rejection (Z.1.6):
read_u8_len_prefixed_asciiinreal_wire.rswas returningInvalidAlgoListLen(terminal) when the SSH read chunk ended on a length byte of the algo list. It now returnsTruncatedBufferso the preamble loop keeps reading. Zero hard rejections on 100-file batches (pre-fix: 2 to 3% intermittent). - CLI profile delete did not propagate to the GUI (#194):
delete_profile_in_vault()now also removes theserver_<id>credential and the id fromconfig_favorite_servers, matching the GUIconfirmDeleteflow.App.tsxprewarm usessecureGet('server_profiles')and overwrites the localStorage backup when the two diverge, and theMyServersPanelreconcile dropped the stale-localStorage fallback. The vault is now the single source of truth, so a CLI delete is visible in the GUI after refresh. - CLI
Favcolumn always showed-(#195): favourites lived in localStorage, unreachable from the CLI. They are now persisted to the vault keyconfig_favorite_serversbyMyServersPanel.toggleFavorite(with a one-shot localStorage->vault migration on first mount), and the CLI renders★for ids in the set, sorts on it, and exposes afavoriteboolean in--json. - CLI
ls/treeopened a browser tab instead of reporting the real OAuth error (#196): the TTY branch oftry_create_oauth_providerswallowed the provider error before opening the browser. It now prints the underlying cause (for exampleinvalid_grant: Refresh token has expired) before re-authorizing, so an expired refresh token, a429, a5xxor a network reset are distinguishable and the user can cancel a re-auth that is not warranted. - Activity Log
Errorsfilter was operation-only (#180): a redCONNECTorINFOrow did not surface under theErrorsfilter.ActivityLogPanel.filteredEntriesnow also matches any entry withstatus === 'error', so failed connects appear when you narrow toErrors. - CLI
--showdid not work and was not intuitive (#180):--showis now an exclusive allowlist (only the pinned#/Nameplus the listed columns stay visible, like the GUI Table view), and both--hideand--showaccept*/all. Newparse_col_specinaeroftp_cli.rs,--helpupdated. - Font-size popup did not show at the min/max bound (#180):
useFontSizeShortcutsearly-returned on the no-op clamp, so the indicator never rendered at the boundary. It now flashes with themin/maxbadge every time, skipping only the redundant state write. - Server
Duplicateaction renamed toCopy(#180): the table row, server card, context menu and Settings list now label the duplicate actionCopyto match its Copy icon and the CLIcaction. Reuses the existingcommon.copystring, no new translation. - WebDAV Nextcloud unlimited-quota sentinel: a Nextcloud
quota-available-bytesof-3(unlimited) was treated as a real number; it is now mapped to "unlimited" so the storage bar is not garbage on unlimited plans. - Speed test inflated throughput on MEGA (Ehud):
run_single_speed_testgenerated the random payload once before the iteration loop, so iterations 2+ re-uploaded identical content that MEGA dedups server-side, reporting hundreds of MB/s. The payload is now regenerated per iteration so every upload is unique; live-verified realistic single/low-double-digit MB/s with integrity confirmed. - No-quota WebDAV reconnect wiped the cached scan: WebDAV is in the quota-capable set (for Nextcloud), so a server that answers
0/0(DriveHQ, CloudMe, jianguoyun) made the API branch persistused:0over a prior scan, zeroing the card on every reconnect. An empty API response is now treated as no-quota: seed from the cached scan or manual cap and never persist a meaningless zero. - MEGA (MEGAcmd mode) download did not overwrite an existing local target (#128): MEGAcmd's
mega-getwrites to a(1)-suffixed sibling and leaves the original file untouched when the destination already exists. AeroFTP's MEGAcmd-modedownloadpassed the path straight through, so any caller that pre-creates the destination (atomic temp, re-download, the speed-test verify buffer) read stale or empty bytes from the original path while the real data sat next to it, surfacing as a spurious integrity failure and as wrong content for previews / hashing / agent reads.downloadnow removes a pre-existing regular-file (or symlink) target beforemega-get, matching the overwrite-on-download semantics every other provider already has;download_to_bytesuses a per-call UUID temp path so it can never collide. The native MEGA API mode was not affected. Found while profiling MEGAcmd vs native throughput for the issue #128 performance question.
Changed
native_rsync_enableddefault:load_native_rsync_enabled()returnstruewhen no config file is present. Stored choices are preserved.- CLI
Typecolumn renamed toBadges(#180): theaeroftp-cli profilescolumn header now matches the GUI label. Thetypesortable alias keeps working as a back-compat shim for--sort. - Classic rsync toggle disabled when the binary is absent:
Settings > Syncgreys out the Classic rsync option when norsyncbinary is onPATH, instead of letting the user pick a mode that cannot run. - Wishlist quick-win polish (#180): the password eye-icon hit area now spans the full input height (was a ~16 px target), and the My Servers search box matches every badge (protocol class, E2E bit depth, provider display name, OCS aliases) not just WebDAV/S3.
- Dependency bumps: quick-xml 0.39.3 -> 0.40.0, clap 4.6.0 -> 4.6.1, tokio 1.52.2 -> 1.52.3, plus dev-dependency bumps (postcss, @tauri-apps/cli, react-virtuoso, vitest) and CI action bumps (actions/download-artifact, sigstore/cosign-installer). GHSA-7gmj-67g7-phm9 (CVE-2026-42184) documented as non-reachable.
Security
- Three-layer pre-release audit, every finding triaged: this release was gated by (1) a self-hosted
/security-reviewover the full branch diff, which found no newly-introduced HIGH or MEDIUM security vulnerabilities, (2) the npm security regression suite (5/5 checks pass) and the self-hosted vulnerability report (0 open findings, 26 suppressed with written justification), and (3) an independent five-area multi-agent expert audit (frontend quota/UI, Rust scan/provider backend, CLI vault and compression, i18n and docs integrity, security and cryptography). Every HIGH and every material MEDIUM finding was fixed before tagging; the remaining LOW/INFO items are recorded with an explicit accept rationale. Notable hardening shipped from the audit: a recursive-scan baseline can no longer be clobbered by an API quota read on whole-disk-statfs backends, the used-storage scan skips symlink cycles and caps server-controlled input on every path (BFS, S3 list-recursive, WebDAV Depth:infinity), the AeroVault v3 master and MAC keys are zeroized on drop, and the compression Saved/Saved% telemetry no longer persists a fabricated value for formats with no compression stage. We run this full audit pass every release.
Contributors
- Ehud Kirsh (@EhudKirsh): sustained design contribution to the AeroVault wrapper stack and the small-file-packing model in the COMMUNITY ROADMAP thread (#162), plus the v3.8.0 wishlist and CLI profile-management reports (#180, #194, #195, #196).
Downloads:
- Windows:
.msiinstaller,.exe, or.zipportable (no installation required) - macOS:
.dmgdisk image - Linux:
.deb,.rpm,.snap, or.AppImage