Repository navigation
Replies: 43 comments
|
🟢 #389 fixed on main ( Root cause: the Filen Desktop local S3 (1800) and WebDAV (1900) servers let you choose HTTP or HTTPS inside the Filen app, independently of the scheme saved in the AeroFTP profile. When the two did not match, the connect failed at the transport layer, which is why S3 failed every time and WebDAV connected only sometimes (it depended on how each profile was created versus how the Filen app happened to be set). Fix: AeroFTP now probes the live bridge at connect and uses whichever protocol it actually speaks, so it connects regardless of the Filen app setting. It also pins the loopback IP so the Verified live on both bridges across every combination:
Gate green: |
v4.1.3 batch: Quick Connect polish, Transfer Queue progress bar, eject step-out, CLI --no-cryptPost-v4.1.2 follow-up, all fixed on
Two live checks stay owner-driven and are pending: the Transfer Queue bar climbing honestly 0 to 100 during a real folder drag-drop (normal and crypt profiles), and a real-code 2FA login on MEGA / Filen / Internxt exercising the 6-box input. Both need GUI input the CI cannot drive; the logic is proven by the unit tests and a clean app boot. Verified green: |
#390 crypt phantom folder: fixed on
|
| Area | Description | Status | Commit |
|---|---|---|---|
| Crypt write | The upload is now refused with a clear message instead of creating a phantom folder, when the on-wire parent is a plaintext folder that already exists. A genuinely-new encrypted subtree still creates and uploads normally | 🟢 fixed | c80822600 |
| Crypt arm | Turning the overlay on re-anchors you out of a hidden plaintext folder to a valid encrypted location (the scope, or the remote root for a whole-remote overlay), but keeps you in place inside a genuine encrypted subfolder, so toggling on/off to compare encrypted vs decrypted no longer bounces you to the root | 🟢 fixed | c80822600 |
Live-verified two ways: the phantom refusal end to end via the CLI on a Filen remote (no phantom folder appears in the raw view, the folder stays empty), and the smart re-anchor in the GUI on a MEGA rclone remote (staying inside a valid encrypted subfolder across a toggle, re-anchoring out of a plaintext folder). The same root also covers the crypt cd into a decrypted folder. Option 2 and the wider crypt ls/tree scoping land with #369.
Verified green: tsc --noEmit clean, vitest 388 tests passing, i18n:validate 46/46 locales, cargo fmt --check clean, cargo clippy --all-features --tests -D warnings and --bin aeroftp-cli -D warnings clean, cargo test --lib 2497 passing (2 new #390 regression tests).
AeroCrypt keyfile: optional second factor for native vaultsNew in 4.1.3 (#272, raised by @EhudKirsh). Native AeroCrypt now supports an optional keyfile as a real second factor. The keyfile is "something you have" mixed into the key derivation (blake3-derived digest combined with the password before Argon2id), so a vault needs the password AND the keyfile to open. It is stronger than copying rclone's password2 and it does not change the on-disk object format: a hostile remote that strips the keyfile requirement just makes the reader derive a different key, which fails the config MAC closed. A vault can also be keyfile-only, with an empty password.
Live verified on the SFTP lab (2026-07-07):
Verified green: cargo fmt, cargo clippy --all-targets -D warnings, cargo test --lib (2510 passed), cargo test --bin aeroftp-cli (426 passed), npm typecheck, npm i18n:validate (47 locales). |
Encrypted archives flagged at a glance in the file browser (unlock modal + list/grid/large-icons indicators)Pre-release 4.1.3 work, done on Two parts landed. First, a dedicated draggable unlock modal that shows the real, detected cipher of a password-protected archive (zip/7z/rar) instead of a generic prompt. Second, the local file browser now tells you an archive is encrypted before you open it, consistently across all three view modes.
The detection is lazy and opt-in: it reads only the archive header (a few bytes), only for zip/7z, only when a lock-bearing surface is visible, capped and cached module-wide by path/size/mtime, so switching between list, grid and large-icons re-reads nothing and the plain layout costs nothing. Verified green: cargo fmt, clippy (all-features, tests, and the aeroftp-cli bin), cargo test (11 integration + the lib suite, including 5 new |
Encryption surfacing extended to our native formats, plus a Compression column and an AeroVault version chipPost-4.1.2 follow-up, done on Building on the list / grid / large-icons encrypted-archive indicators, the local file browser now also recognizes our own container formats and gains two more read-only columns.
Verified live on the local panel across the three view modes against real fixtures: Deflate / BZip2 / LZMA2 / PPMd archives, a Deflate-under-AES-256 zip, an encrypted-header 7z (correctly hidden), and v2 and v4 vaults. Verified green: cargo fmt, cargo clippy --tests (0 warnings), 9 backend unit tests (archive_meta: encryption + compression), frontend typecheck, i18n 47 locales. |
Proactive RAR support, plus a "Store" label and a clamp glyph in the Compression columnPost-4.1.2 follow-up, done on RAR joins zip and 7z in the proactive, password-free surfacing, and the Compression column stops leaving uncompressed archives blank.
Verified live on the local panel against real fixtures: RAR4/RAR5 data-encrypted (AES-128 / AES-256 + method) and header-encrypted (method hidden), a compressed RAR, and the zip/7z Store cases. Verified green: cargo fmt, cargo clippy --tests (0 warnings), 10 backend unit tests (archive_meta), frontend typecheck. |
User-selectable date format across the appPost-v4.1.2 follow-up, done on Dates in the file browser Modified column (and everywhere the shared
Verified green: |
Remote-panel archive surfacing (our own formats) + folder-scroll resetPost-v4.1.2 follow-up, done on Until now the padlock, Encryption column and AeroVault generation chip were local-panel only. They now appear on the remote panel too for
Verified live over SFTP: a remote Verified green: |
Remote panel: third-party ZIP and 7z now show the encryption padlock tooPost-4.1.2 follow-up, on Phase A brought our own container formats ( A ZIP keeps its index (central directory) at the file tail and a 7z its next-header near the tail, so a head-only read cannot classify them. The new backend command fetches only the byte ranges the archive index occupies (the end-of-central-directory window plus the central directory, resolving ZIP64 from the tail; or the 7z start header plus its next-header) via the provider ranged read, and feeds them to the same parsers the local detector uses.
A content-only-encrypted 7z whose header is LZMA-compressed (the default when file-name encryption is off) hides the AES id inside the compressed header, so neither the local nor the remote detector flags it: a shared, pre-existing false-negative that degrades to no badge, never a wrong one. Verified green: |
Remote surfacing now lights up on four more clouds (Azure, Uploadcare, Cloudinary, ImageKit)Post-4.1.2 follow-up, on The remote panel padlock, Encryption column and AeroVault chip all sit on one primitive: the provider's ranged read. Any provider that can serve a byte range gets both surfacings for free. Four providers already advertised range support but never implemented the ranged read, so they quietly showed no badge. Each now has one, so an encrypted archive stored on them shows its badge with no whole-file download.
All four read the 206 partial body, and if a CDN ignores the range and returns the whole object (200) they slice the requested window locally, so a range-blind edge degrades to a bounded read, never a wrong badge. E2EE providers and the crypt overlay stay degraded to no badge by design, since a raw byte range there is not a plaintext prefix. Verified green: |
2FA 6-box code input: focus no longer skips a box per keystrokePost-4.1.2 follow-up, on QA on the shared 6-box one-time-code input (used on the Internxt, Filen and MEGA Quick Connect 2FA pages) turned up a focus bug: typing a single digit advanced the caret by two boxes, not one (box 1 to box 3, box 3 to box 5). The joined code still came out right (empty slots collapse when the boxes are joined), so authentication was not broken, but the caret visibly skipped boxes while the digits packed to the left, away from the cursor.
After the fix: typing advances one box at a time, full-code paste spreads across all six and lands on the last box, non-digits are rejected, and backspace on an empty box clears and steps back. The kDrive Drive ID field is a separate numeric input (up to 10 digits) and was confirmed unaffected. Verified green: |
Pre-push commit audit: PASSPost-4.1.2 follow-up, on Two integer-overflow hazards were confirmed in the remote archive-detect parser and fixed, plus one consistency fix; the rest came back clean.
Both overflow fixes are pure hardening: no behavior change on well-formed archives, and the detect path still degrades to no badge (never a wrong badge) on hostile input. Verified green: |
Command and tool inventory: one drift-proof source of truthPost-4.1.2 work, landed on
Verified green: cargo fmt, cargo clippy --bin aeroftp-cli --tests (0 warnings), cargo test --bin aeroftp-cli (427 passed, 0 failed, including a new inventory-consistency test and the dispatcher-allowlist sync test), i18n 47 locales (0 NEEDS TRANSLATION). |
View Trash works again under the crypt overlayPost-4.1.2 follow-up, fixed on With Crypt on, the red View Trash button failed for most cloud providers. Trash, restore and empty are provider-specific methods (not on the storage trait), so their handlers downcast the live provider box to the concrete provider type; with a crypt overlay active that box is the overlay decorator, whose downcast target is itself, so the operation failed while the same providers worked with Crypt off.
Verified green: cargo fmt, clippy (lib, tests, aeroftp-cli bin), the test suite including two new regression tests (peel reaches the inner transport through a live overlay; trash-name decode-or-passthrough leaves the restore token untouched). Runtime confirmed on a live pCloud rclone-crypt profile. |
The SFTP listing stops asking the server what it already told usInternal performance work, done on
Measured on a plain OpenSSH 9.6p1 remote at 41 to 62 ms RTT, over a tree of 20 directories and 600 files. SourceForge was never used as a benchmark target: it rate-limits bursts of SFTP sessions.
Roughly 2.9x, and the emitted JSON is byte-identical across the change. 620 entries at ~49 ms of avoided Correctness was pinned with a five-entry symlink matrix on a real remote (plain file, real directory, symlink to file, symlink to directory, broken symlink). Five probes captured before and after, all byte-identical: Also confirmed, so nobody re-litigates it: Verified green: |
A remote symlink to
|
| Area | Description | Status | Ref |
|---|---|---|---|
| Providers | The invariant now lives on the type that carries the data: RemoteEntry::is_walkable_dir(), which every descent is gated on. The entry keeps is_dir = true, so only the traversal is refused. |
🟢 fixed | 8b39ed17 |
| CLI | rmdirs offered the link itself as an empty-directory candidate to remove, and descended through it. It is now skipped entirely, out of both the stack and the candidate list: SSH_FXP_RMDIR does not follow links, and removing a link because its target looks empty is not this tool's call. |
🟢 fixed | 8b39ed17 |
| CLI | get -r and crypt-get would have written the target's whole subtree twice into the local tree, or never terminated. sync, the sync remote scan and sync-doctor duplicated the target's files in the plan. dedupe and cleanup double counted. lsjson -R, tree, crypt-ls emitted phantom entries. |
🟢 fixed | 8b39ed17 |
| CLI | tree's text renderer decided whether to descend by sniffing a trailing / off the rendered name, which a symlink-to-directory also carries. It now carries walkable explicitly on its queue item: a type is not something to recover from a formatting character. |
🟢 fixed | 8b39ed17 |
| MCP | tree, cleanup, dedupe, sync_doctor and reconcile had the same hole through the agent surface. The local_tree agent tool typed entries with metadata(), which follows links, and now uses file_type(), which does not. |
🟢 fixed | 8b39ed17 |
One design point worth recording, because the obvious fix is the wrong one. Swapping the guard naively would have dropped a symlink-to-directory into each walker's else branch, where it would be treated as a file: get -r would try to download it and dedupe would hash it. The classification stays, the traversal stops.
Live before and after on the same scratch remote:
| Probe | Before | After |
|---|---|---|
lsjson -R on the cycle tree |
123 entries, max depth 81 | 3 entries, max depth 1 |
tree -d 6 on the cycle tree |
6 directories and 3 files | 2 directories and 1 files (the truth) |
lsjson -R on the symlink matrix |
7 entries, includes link-to-dir/inner.txt |
6 entries, that child gone, link-to-dir still present with IsDir: true |
tree on the symlink matrix |
link-to-dir/ with inner.txt under it |
rendered with no children |
ls -l, rm --dry-run -r, size |
(already correct) | unchanged |
The last row is the control: those three walkers already honoured the guardrail, and this change must not perturb them. None of them moved.
Two things the live test corrected, which static analysis alone had wrong. tree has a second walker that no is_dir grep can find, because its descent test is a string suffix. And find looked fixed but had never been broken: SftpProvider::find classifies straight from the raw READDIR mode without resolving the link, so a symlink reports is_dir = false. It is safe by accident, not by design.
Providers other than SFTP always report is_symlink = false, so is_walkable_dir() collapses to is_dir there and nothing changes for S3, WebDAV or FTP.
Verified green: cargo fmt --all -- --check, cargo clippy --all-targets -- -D warnings, cargo test --lib 2545 passed (one new test pinning the invariant on the type), cargo test --bin aeroftp-cli 436 passed.
FTPS connections from the GUI hung forever, then crashed the appPost-4.1.2 follow-up, fixed on Every FTPS connect attempted from the desktop GUI never returned. The card kept spinning, the "still connecting" modal appeared after 8 seconds, its Cancel button did nothing, and after a few minutes the app died. No server was at fault: the same profiles connect in about a second from
That single panic produced all three symptoms:
The provider is now installed once in Measured in the dev GUI, on a connect that previously hung indefinitely:
Confirmed end to end from the saved-server card: connect, authenticate and list 44 items in about 3 seconds, with no panic in the log. One related weakness stays open and is deliberately out of scope here: a Tauri command that dies by panic leaves the frontend waiting forever, with no timeout and no error surfaced. This fix removes this panic, not that fragility. Verified green: |
Flatpak ownership and AUR package repairPost-4.1.2 follow-up, fixed on @jing2uo packaged AeroFTP for Flatpak and asked about the sandbox default rather than just shipping it. I took the recipe on from our side to co-maintain it, and while auditing it I found and fixed a chain of related issues across the vault, the updater, the Flatpak, and our AUR package. None of these ever affected
The GUI first-run import prompt and its strings, translated across all 47 locales, are on The root cause the audit kept hitting: the Verified green: |
The SFTP listing pipelines its per-entry follow-ups (lever 2)Internal performance work, done on Lever 1 (
Measured on a plain OpenSSH 9.6p1 remote at ~44 ms RTT, a directory of 250 symlinks where every entry pays
About 2.8x, output identical. The theoretical round-trip-count win is larger, and the reason it is not reached is worth recording: A plain 620-entry tree with no symlinks issues no follow-up at all and is unchanged: serial 18.0 / 19.3 / 16.5 s, pipelined 18.1 / 21.5 / 15.3 s, within measurement noise. This is the expected shape, and it is why the change was re-priced before shipping: lever 1 already removed the common-case cost, so lever 2 helps only symlink-heavy trees and capability-poor servers. Correctness unchanged, confirmed live: the symlink matrix ( Verified green: |
|
| Area | Description | Status | Ref |
|---|---|---|---|
| CLI | --ndjson writes one compact JSON object per line to stdout as each entry is discovered, skipping the buffer and the global sort. Documented as unsorted (a stream and a global sort are mutually exclusive) and as newline-delimited JSON rather than an array, so a line-based consumer can split on newline. conflicts_with --stat. |
🟢 done | 767e83aa |
| CLI | A progress spinner on stderr names the directory being listed, gated on stderr being a TTY and --quiet unset, drawn with \r\x1b[2K and erased before any real output. Stderr-only, so stdout stays pure JSON through a pipe, a redirect, or a non-TTY. |
🟢 done | 767e83aa |
The buffered, sorted array stays the byte-for-byte default, so nothing that parses today's output has to change.
Live on a scratch remote, a tree of 3 directories and 1 symlink (8 emitted entries):
| Check | Result |
|---|---|
Default lsjson -R |
valid JSON array, 8 entries, sorted |
--ndjson |
8 lines, every line valid JSON, same path set as the default |
| stderr piped (not a TTY) | no spinner, 0 escape bytes |
| stderr a TTY, stdout to file | spinner names all 4 directories; the file is clean JSON, 0 escape bytes |
--quiet on a TTY |
no spinner |
--ndjson --stat |
refused by clap |
Verified green: cargo fmt --all -- --check, cargo clippy --all-targets -- -D warnings, cargo test --lib 2560 passed, cargo test --bin aeroftp-cli 437 passed (one new test pinning that an NDJSON record is a single line and round-trips).
The native
|
| Area | Description | Status | Ref |
|---|---|---|---|
| CLI | profile-import --dry-run decrypts the file and prints which profiles it would add and which it would skip as duplicates, then exits 0 without touching the vault or the keyring. The import already ran in two phases for the v4.1.0 audit (phase 1 decrypts and returns the list without writing; phase 2 restores only new profiles); the flag stops right after the merge decision, before phase 2 and the save. A duplicate (same profile id) is skipped, never overwritten, so there is no "would overwrite" case. Plan to stdout, notices to stderr, mirroring the delete verbs. |
🟢 done | b39a8b53 |
| CLI | The native format joins the families: export aeroftp and import aeroftp (the latter with --dry-run) are arms of the export/import subcommands, each delegating to the existing handler. export --help listed 15 foreign formats and not ours; now both --help list AeroFTP's own. |
🟢 done | b39a8b53 |
Live on the dev vault (22 profiles):
| Step | Result |
|---|---|
export aeroftp -o rt.aeroftp |
22 profiles, 108380 bytes |
profile-import --dry-run |
each profile "would skip (already present)", "Would add 0, skip 22" |
profile-import --dry-run --json |
dry_run:true, would_import:0, would_skip:22, total:22 |
import aeroftp --dry-run (family alias) |
same, alias delegates correctly |
| vault after the dry-run | SHA-256 and profile count unchanged |
wrong password on --dry-run |
Invalid password, exit 6, vault untouched |
Verified green: cargo fmt --all -- --check, cargo clippy --all-targets -- -D warnings, cargo test --lib 2560 passed, cargo test --bin aeroftp-cli 438 passed (one new test pinning that the merge decision exposes which entries are skipped).
The MCP listing tools now speak one entry shapePre-v4.1.3 internal follow-up, done on A remote directory entry had five different JSON shapes across the app. This step closes the MCP half additively, with no breaking change to any public surface.
Live proof, driven through the real MCP daemon (
Verified green: fmt, clippy |
A panicking command can no longer strand the UI in an infinite spinnerPost-4.1.2 follow-up, fixed on A Tauri async command that dies by panic never sends an IPC response: Tauri wraps the command future with no
A note on scope: v4.1.3 wraps the connect family plus the connect frontend backstop. Remote and local listing already have a working Cancel (and listing is now panic-safe too), and transfers already carry a real transfer timeout, so those flows have an escape. Extending the backend net to the transfer verbs and then, via an attribute macro, to every command is tracked as a follow-up so no frontend timeout beyond connect is ever required. Verified green: |
CLI credential seeding + FTP path handling made honest + My Servers scroll fixPost-4.1.2 follow-up, fixed on
Verified green: |
The crypt overlay now behaves the same from the CLI and MCP as it does in the GUI (CWP-20C)Post-v4.1.2 follow-up, fixed on The Model-B crypt scope (plaintext outside a bound subtree, decrypted inside) had shipped GUI-only: the React layer routed each op to the overlay or the raw provider, but the backend
The user-facing Remote Path configuration (a GUI field + a CLI flag to set the encrypted subtree explicitly) is the remaining follow-up (Requested #12); the scope already flows from the profile binding / initial path today. Verified green: |
Three quick wins from the Requested list shippedFixed on
The false-complete guard is retry-safe by construction: it only blocks a direct Verified green: |
Final pre-release audit closes six integrity and fail-open residualsPost-v4.1.2 follow-up, fixed on A direct code review of the release delta found six cases where a happy-path test could stay green while an error, compatibility edge or local race was still handled incorrectly. All six are fixed in one pre-tag commit.
Verified green: frontend 43 files / 403 tests, production build, Rust fmt, Clippy strict, S3 parser 5/5, and security regression 5/5. |
Closing: v4.1.3 is shippingThe full v4.1.3 change set is complete on What shipped in 4.1.3 (71 tracked entries above):
Known issues reported against v4.1.3 and everything landing on |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
AeroFTP 4.1.3, Rolling Tracker
Umbrella issue for the next AeroFTP point release (v4.1.3): known issues reported against v4.1.2 and the patches/updates landing on
mainafter the v4.1.2 tag.Before opening a new issue, please check the lists below. If your problem is already tracked here, just add a thumbs-up reaction or a comment with your environment (OS, version, provider) instead of filing a duplicate. We update this issue as bugs are found and fixed.
Found something that is not listed? Open a new issue and we will link it here.
What shipped in 4.1.2
See the v4.1.2 tracker (#384) and the release notes for the full 4.1.2 change set: complete archive format coverage (standalone gz/xz/bz2 round-trip, 7z Advanced options, ZIP non-Deflate read methods, safe tar links, multi-volume detection, 7-Zip canonical level presets), the full-surface security audit (16 findings fixed) plus a pre-tag commit audit (PASS, 6 minor findings fixed), AeroShare LAN (mDNS) discovery with relays fully disabled in lan mode, the Quick Connect consistency pass (MEGA two-column, kDrive refinements, 2FA polish), the crypt overlay reconnect / strict-WebDAV / Koofr mode-switch / Convert secret-migration fixes, and the delta transport-drop classic fallback.
Patches & updates queued for 4.1.3
Landed on
mainafter the v4.1.2 tag; shipping in v4.1.3.2c90c69d3aab9038d833be6931de98ffa03416301478bb90159a2b6228a345dc80822600b1f8ce210,bb957ee55,a709c95b4,4458318f5,3d6f94f6f4c5f21035,ea011d8f3,dfbe55b7c,e036691bd.aerovaultand the exported.aeroftp-keystoreand.aeroftpbackups read as AES 256-bit encrypted (emerald padlock, Encryption column, grid and large-icons overlay), while the plaintext.aeroziplane reads as open, alongside third-party zip and 7z. A new optional Compression column shows the real method of compressed archives (Deflate, BZip2, LZMA, LZMA2, PPMd, Zstd, resolving the method inside a WinZip AES wrapper and reading 7z coders; a stored archive or a 7z with an encrypted header shows nothing), plus Zstd for the AeroVault v3 lanes. The Type column also carries an AeroVault generation chip: v2 (AEROVAULT2), v3 (AEROVAULT3), or v4 (v3 with the rev.4 Reed-Solomon error correction), detected password-free. Compression label translated across all 47 locales; 9 backend unit tests27491a82d.rargiving no false badge. The column now reads Store for an uncompressed zip/7z/rar (previously blank), always preferring a real method over Store in a mixed archive, and a small clamp glyph marks the actually-compressed methods; a 7z or RAR with an encrypted header stays blank (method unreadable). List, grid and large-icons views all include RAR now0867f03a62243dcd4a,560e39292.aerovault,.aerozipor exported.aeroftp/.aeroftp-keystoreon a remote now shows the same at-a-glance padlock, Encryption column (AES 256-bit) and AeroVault generation chip (v2/v3/v4) as a local file, across list, grid and large-icons views. A new backend command reads only the file header via the provider ranged read (never downloading the whole file) and reuses the existing detectors, scoped to the range-capable transports (SFTP, FTP/FTPS, S3, WebDAV, Backblaze B2, Koofr) and degrading to no badge elsewhere (E2EE, crypt overlay). Third-party zip/7z/rar on a remote (index at the file tail) is a later phase. Also resets the file list to the top when navigating into a different folder (local and remote), fixing a stale-scroll landing on a blank view61043e399-mheencrypted 7z on a remote shows the padlock and cipher without downloading the file, reading only the zip end-of-central-directory tail (and the central directory, resolving ZIP64) or the 7z start and next headers via provider ranged reads. Encryption only (the compression method needs the whole archive); rar stays local-only; degrades to no badge where a transport cannot serve byte ranges6fef67ba8d834278ec1c454c27919f1b1e4c,a5d235358aeroftp-cli inventorysubcommand: the authoritative, drift-proof inventory of every CLI subcommand and MCP tool, read straight from the in-code registries (clap command table, MCP tool catalog, agent tools) and emitted as JSON, a Markdown table, or a--checkCI drift gate. Fixes the long-standing count drift across the docs (the real numbers: 90 CLI subcommands, 73 MCP tools, 39 agent tools), de-stales the agent-info command-group count, ships a committed snapshot atdocs/COMMAND-INVENTORY.json, and rewires the aeroftp.app CLI Explorer generator to consume it. README counts aligned; the docs.aeroftp.app and aeroftp-mcp README counts are updated via PR8e3beb7b,4a542606c2868fb49d42068945880d0a744f0ac8ff368234fmt::Pointerimpl of crossbeam-epoch'sAtomic/Shared):Cargo.lock-only, 0.9.18 to 0.9.20, restoring a cleancargo auditgate2542b1e8switchSession(six raw listings, so switching tab between two saved servers),switchGitHubBranchand the AeroCloud tab completely mute. All of them now raise the spinner and name the directory being read, with a Please wait line under it. The Cancel button, meanwhile, cancelled nothing: it bumped a frontend counter and hid the spinner while the listing kept running, so the folders the user had just cancelled appeared moments later. It could not be honoured from the frontend, because the listing holds the provider mutex and a disconnect issued to force the point would simply queue behind it. The abort now happens inside the backend:provider_list_filesandprovider_change_dirrun under a cancellation token, and the newcancel_remote_listingcommand deliberately touches no provider state so it cannot block on the mutex the stuck listing holds. The meaning is contextual: cancelling the listing a connect is blocked on also tears the half-open session down and returns you to My Servers (logged honestly as "Cancelled by user: listing stopped, disconnected from server"), while cancelling a drill-in inside a usable session just aborts the listing and leaves you where you were. Three new keys translated across all 46 locales; 3 new backend unit tests0f372998,4df30affversions trash/versions purge/versions empty-trash) and MCP (remote_versions/remote_trash), with the crypt overlay peeled to the concrete S3 provider so names decrypt while every operation round-trips on the raw key. Also stops writing the zero-bytefolder/directory marker inmkdir(rclone-style no-op) so a newly created folder no longer renders as a phantom empty file on gateways that drop the trailing slash. Live delete-marker lifecycle verified end to end on Storj and AWS; 17 i18n keys translated across all 47 localesb3a06635,180f263d,2cf10a31,3d0fbb5a,d744affc7f53fc027c5413f9gzip -1on text because this build's flate2 resolves to the zlib-rs backend, which maps level 1 to its speed-firstdeflate_quickpreset. Backend level 2 already beatsgzip -1on both size and speed, so user level 1 is now pinned to backend level 2 at every DEFLATE entry point (ZIP creation including both store-if-larger trials, tar.gz, standalone gz, and the estimate sampler so the GUI preview matches real output). Re-run cross-check with the patched build: text gz/zip level 1 drop from +40.33% to -3.64% (smaller and still faster thangzip -1), mixed from +20.57% to -1.52%, every other level and format byte-unchanged, 42/42 round-trips pass. Levels 1 and 2 now emit identical streams by design, guarded by two new unit tests; xz/bz2 stay byte-identical to native and 7z level 1 stays byte-identical toxz -1by designefe42085archive_compressadvertised compression level default 6 while the shared compress cores and the CLI--levelhelp use 5 (7-Zip Normal, aligned in v4.1.2); the schema now states the real default528bd327d744affcwith "No space left on device" or a wedge-until-timeout while rebuilding the lib for the second cargo test invocation. Not a product regression: the aeroftp lib in test profile plus the docker fixture outgrew the ubuntu runner's free disk (last green0965e6d4a), so bisecting the reds pointed at innocent commits. The same disk reclaim step cli-smoke and build already use (drop preinstalled dotnet, ghc, android, CodeQL, boost, prune docker images) now runs in both lanes before the Rust cache restore; the Windows lane is untouched. Trap recorded in the release skill's recurring CI-red list (entry 11)6a48feecBuildandCLI Smokeworkflows red oncargo clippy --all-targets -D warnings(default features, the exact CI line) because 1.97 tightenedquestion_mark,dead_codeand theformat!redundant-reference lint. Fixed in two commits: the lib lints (amatchreducible to?in the TOML value parser, a useless&borrow in the transfer executor), then the cli-binary lints (a manualOption::filterin the profile selector, plusdead_codeon the Linuxfuse_mounthelpers reachable only fromfn main, which--all-targetsdrops via the test harness, allowed at the module boundary). Not a product change, the shipping binaries are byte-equivalent; the local--all-featuresclippy trio did not catch it because feature-gated paths hide default-features dead_codea51a7a62,977ef9c0c394a7da4327bc14b24c813c164983fdrecursivenow actually means something.aeroftp-cli rm --dry-runandpurge --dry-runprint the exact list of files and directories that would go plus the bytes reclaimed, and delete nothing (rmdirswas already dry-run by default anddedupealready had the flag, but the verbs that delete files had no preview: cleaning 846 files off SourceForge meant hand-writing one in Python). Because the recursive delete removes as it walks and never reports what it removed, the plan comes from a separate pre-pass; the root guard still fires under--dry-run, while the confirmation prompt and the non-TTY fail-closed exit do not, so a preview stays usable from a script. Text mode caps the list at 1000 entries and warns when the scan hit a depth or entry cap, so a truncated plan is never mistaken for a complete one;--format jsonalways carries the full plan. The MCPaeroftp_deleteandaeroftp_delete_manytools (and their aliases) take the samedry_run, returning the identical results/summary envelope withdeleted: false,would_delete: trueand the byte total, so an agent can diff a preview against the real run. Wiring this up surfaced a latent hazard:recursivewas declared in the schema of every delete tool and read by none of them, and the MCP backend calledrmdir_recursiveon any directory, so anaeroftp_deletewith norecursiveflag silently erased the whole subtree while the GUI and CLI backends only unlinked a single entry. Recursion is now opt-in through a newRemoteBackend::delete_recursivewhose default refuses rather than pretending, and a non-recursive delete that fails on a non-empty directory now answers "pass recursive=true" instead of the raw SFTPFailure: Failure, while an empty directory failing for another reason keeps its own errorfb6d5f29is_delete_marker || is_latest, so the live current version of every key under the prefix was reported as trash, andempty_object_versionshard-deletes each entry it is handed by version id:aeroftp-cli versions empty-trash <prefix>and the GUI trash manager's Empty trash therefore destroyed live files irreversibly, with no delete marker left to undo it. Caught by a live test against a versioned AWS bucket before any release carried it: a prefix holding a single never-deleted file reported one trash entry, andempty-trash --dry-runannounced it would purge 13 B, which was that file's current version. A key is now trash only when its current version is a delete marker (the marker plus the older bodies recoverable underneath it),--allwidens the sweep to the older versions of live keys, and the live current version is dropped in both modes. The filter moved into a pureretain_trash_entriesso it is unit-testable, with a regression test asserting no live current version can reach the sweep. The rest of the trash and version surface (list,get,restore,purgeof a delete marker as undelete) was live-verified correct and unchangedaba0c595crmandpurgenow honour the global filters, in dry-run and for real. The filter flags (--include,--exclude-global, their-fromvariants,--min-size/--max-size,--min-age/--max-age,--files-from) have existed since the filter system landed, but no destructive verb read them:rmtook one path, and a recursive delete went straight to the provider'srmdir_recursive, which takes one path and erases everything under it with no notion of scope. That is why freeing 43 GiB off SourceForge cost 846 separate deletes when it should have been onerm -r --include "*.snap" --dry-runfollowed by the same command without the flag. Both verbs now build the very plan--dry-runprints and execute exactly that, so the preview and the real run cannot drift apart, and it composes with the dry-run shipped infb6d5f29. A filtered recursive delete removes the matching files and only the directories it empties in doing so: a directory holding a spared file survives, one that was already empty survives (narrowing a delete to*.snapis not an invitation to prune empty directories), and a directory whose listing hit the depth or entry cap is never removed, because "everything in it is going" cannot be trusted from a partial listing. With no filter active the single-shotrmdir_recursivefast path is untouched. Two contracts the--helpnow states out loud: the include and exclude globs match the file NAME and not the path, so--include "*.snap"selects while--include "v3.*/**"matches nothing; and--files-fromis matched on the path relative to the deleted directory, with a path escaping that root refused. The global exclude flag is--exclude-global, not--exclude, because three subcommands already define a per-command--excludeand a global flag has to be unique58067191SftpProvider::listissued oneSSH_FXP_LSTATper directory entry, on every server, awaited serially, purely to test theS_IFLNKbit. The bit was already in hand: theSSH_FXP_READDIRreply carries each entry's own attributes withlstatsemantics, and the line above already consumed them to deriveis_dirfrom the very same mode field. That round trip bought nothing and it dominated every recursive walk in the product: the GUI panel, the sync scan,ls -R,tree,size,rmdirs, and the filtered delete plan. The cost of a walk isRTT x request count, not bandwidth, which is why the SourceForge cleanup watchedlsjson -Rmove 338 KB of metadata in nine minutes. The mode now comes from the attributes already held, andread_linkplusmetadatafire only for entries that really are symlinks. OneLSTATprobe survives, for exactly one case: a server that sends no file-type bits at all. That case is not hypothetical bookkeeping, it is load-bearing, because the attr-less recovery immediately above answers withSTAT, which follows the link and can therefore never reportS_IFLNK; an unknown mode is never silently read as "not a symlink", or callers would receive a symlink-to-directory as a real directory. Measured on a plain OpenSSH remote at 49 ms RTT over 620 entries: 42.31 s and 48.64 s before, 15.78 s and 14.36 s after, with byte-identical output3eebe9edGAP-A02is the standing rule that a symlink is unlinked, never followed, and five walkers honoured it:rmdir_recursive, the used-bytes scan, therm/purgeplan, the MCP delete preview and MCPstorage_quota. Fifteen others did not. They gated the descent onis_diralone, andlistresolves a symlink-to-directory tois_dir = truebecause callers need that to render the entry, so every one of them walked straight into the link. On a tree holdingsub/loop -> ..,lsjson -Remitted 123 entries for 3 real ones and stopped only at the depth cap of 100, whiletree -d 6reported 6 directories and 3 files where 2 and 1 exist; thevisitedsets never catch the cycle, because each pass yields a longer, distinct path string. The consequences were not cosmetic:rmdirsoffered the link itself as an empty-directory candidate to remove,get -randcrypt-getwould have written the target's whole subtree twice into the local tree, andsync,dedupeandcleanupdouble counted. The invariant now lives on the type that carries the data, asRemoteEntry::is_walkable_dir(), and gates every descent. The entry keepsis_dir = true: only the traversal is refused, because swapping the guard naively would drop a symlink-to-directory into each walker'selsebranch, whereget -rwould try to download it anddedupewould hash it.rmdirsskips it entirely, out of both the descent stack and the candidate list, sinceSSH_FXP_RMDIRdoes not follow links and removing a link because its target looks empty is not this tool's call. Two walks needed more:tree's text renderer decided to descend by sniffing a trailing/off the rendered name, which a symlink-to-directory also carries, and now carrieswalkableexplicitly on its queue item; thelocal_treeagent tool typed entries withmetadata(), which follows links, and now usesfile_type(), which does not. Providers other than SFTP always reportis_symlink = false, so nothing changes for S3, WebDAV or FTP8b39ed17aws-lc-rsandringsit in the dependency tree (the latter arrives throughnoq-proto), so rustls cannot auto-select a crypto backend andClientConfig::builder_with_protocol_versions()panics on the first TLS handshake.aeroftp_clipins the backend in its ownmain; the GUI binary never did, somake_tls_connectorpanicked before it ever spoke to the server, on every host and every FTPS profile. SFTP was untouched, since it goes through russh rather than this builder. One panic explained all three reported symptoms at once: theprovider_connectIPC call never answered, so the spinner and the "still connecting" modal ran forever with no timeout and no error; unwinding droppedConnectTokenGuard, which de-registers the connect token, so a latercancel_connectionfound nothing to cancel and the modal's Cancel button looked dead (not onecancel_connectionline ever reached the log); and repeated panics inside the GTK/WebKit process ended in an abort minutes later. The fix installs the provider once inrun()and, defensively, names the backend explicitly insidemake_tls_connector, so a panic there can never again strand the IPC call whatever the process-wide state is. A regression test covers it and fails on the old code with "Could not automatically determine the process-level CryptoProvider"c15ee3f38vault.db, still byte-intact on disk, could no longer be decrypted (it reads to the user as total credential loss). The keyring slot is now namespaced per install scope (native frozen and unchanged, Flatpak and Snap get their own), and a sandbox reads but never writes the native slot. Reproduced and fixed after our own Flatpak live test locked the maintainer's native vault.3dfc918ff.debdownload on Arch.detect_install_format()fell through todebon pacman systems, so the updater offered a download and a pkexec helper that installs outside the package manager. It now detects pacman (/etc/arch-releaseor/etc/pacman.conf) and degrades to notify-only, exactly as on Snap and Flatpak. 8 unit tests, mutation-checked.ab91b472c.debwould see an empty app and read it as lost servers and vault. AeroFTP now offers a consent-gated, copy-only import of the native~/.config/aeroftpon first run (files are only copied, nothing is overwritten, the vault still needs its password), reachable from both the GUI first-run prompt andaeroftp-cli flatpak-import, sharing one backend and one one-time decision marker. The GUI prompt and its strings are translated across all 47 locales.02d8566a3,eb977edce,9fa509389aeroftp-binwas repaired (now4.1.2-2, live). A launcher wrapper destroyedargv[0], soaeroftp-cliandaftpopened the GUI for every flag-first call; the desktop file carried 1 of 5 file associations and showed a duplicate menu entry; and the icon was pinned to a moving branch under a fixed checksum. All fixed by dropping the hand-written overrides and lettingpackage()replay what the.debpostinst does. None of these ever affected.deb,.rpmor AppImage.99e1ec3,ed26015(aeroftp-bin AUR)-betaname, but that rename ran in a later step, so at sign time the file was still*.dmgand nothing was signed (v4.1.2 shipped two dmg assets and zero.dmg.sigstore.json). The dmg is now signed under its real name and the in-app updater, which already pins the same workflow identity for every platform, can verify it. Windows and Linux were unaffected.544d63fd1-betasuffix (nowAeroFTP_<ver>_<arch>.dmg) and the README badge and Platform Status row read stable alongside Linux and Windows. The dmg is still not Apple code-signed, so Gatekeeper needs the documentedxattrworkaround.01fc9d9c5mainfixed. The CLI parity commit added theflatpak-importsubcommand to clap but not to the dispatcher allowlist, sodispatcher_allowlist_matches_clap_subcommands(asserts the allowlist equals clap's subcommands, in order) failed and the Rust tests job went red. Beyond the test, the allowlist is what routesaeroftp flatpak-importto the CLI rather than the GUI, so the entry was functionally required too.42cf4f5f7Network;FileTransfer;, notUtility;. Tauri's bundle category is a fixed macOS-style enum whose closest value is Utility, so every generated Linux desktop file landed under Utility. Rewritten in the two places that already post-process the desktop file (deb-postinst for .deb/.rpm, the AppImage patch script), plus a Keywords line; snap and the Flatpak were already correct, so all Linux formats converge.fb8880ebdaur/folder (pkgver 3.7.4, not the source of truth, referenced by nothing in the build path).27bf85279read_link+metadata), and they were awaited serially.listnow collects the work from theREADDIRreply and pipelines those follow-ups withbuffer_unordered(48)over the one SFTP channel:russh-sftptags each request with an id and every method takes&self, so they overlap on one connection with no pool and no trait change. Measured on a 250-symlink directory: 37.0 and 32.8 s serial, 12.2 and 11.8 s pipelined, about 2.8x, output identical. A plain tree issues no follow-up and is unchanged.38a3e063lsjsonno longer stares back in silence. A recursivelsjson -Rbuffered the whole listing into one sorted JSON array and printed nothing until the walk finished, so on a slow link the user could not tell "working" from "stuck". Two additions, no contract break:--ndjsonstreams one compact JSON object per line as each entry is discovered (documented as unsorted, because streaming and a global sort are mutually exclusive), and a progress spinner on stderr names the directory being listed when stderr is a TTY and--quietis unset. The default output is unchanged byte for byte (still the buffered, sorted array), and stdout is never touched by the spinner: it is stderr-only, so a pipe or a redirect stays pure JSON. This is the CLI twin of the GUI connect spinner shipped earlier this release.767e83aaprofile-importgained--dry-run: it decrypts the.aeroftpfile, prints which profiles it would add and which it would skip as duplicates, and exits without touching the vault or the keyring (a duplicate is skipped, never overwritten, so there is no silent credential clobber). And the native format joins theexport/importfamilies:export aeroftpandimport aeroftp(with--dry-run) are aliases forprofile-export/profile-import, so a user typingexport --helpnow finds our own format next to the 15 foreign ones instead of concluding we cannot export ourselves.b39a8b53aeroftp_treeused to hand-build each entry with an inline JSON that duplicated theentry_jsonshared bylist_files,search_filesandfile_info, so the same file came back with a slightly different JSON depending on which tool an agent called.treenow routes every entry through that oneentry_jsonchokepoint and adds only itsdepthfield on top, byte identical to before, so a recursive listing is exactly a flat listing plusdepth.list_filesis documented as one level and points ataeroftp_treefor recursion instead of growing a second recursive walker, and the CLIlsjsonoutput is frozen with a doc comment naming rclone as the reason for its PascalCase field names andSize: -1directory sentinel, so no future cleanup can quietly break the scripts that parse it.31a3da2ecatch_unwindand its resolver has noDropthat answers the call), so the frontendinvokepromise stayed pending forever: the spinner never stopped and the "still connecting" Cancel was dead, because the panic had already de-registered the connect token during unwind. The connect family (provider_connect,connect_ftp,provider_list_files) now runs underpanic_safe::catch, which turns a panic into a normalErrthe UI renders, and the connect additionally races a 120s frontend hard-timeout backstop whose "Keep waiting" button re-arms it. This is the same discovery that produced the FTPS crypto-provider fix earlier this release; the underlying fragility is now closed and guarded at the root by a sharedinstall_crypto_provider()plus a unit test. Covered by 5 new unit tests and a live GUI proofe25af6008,71806ae14c394a7da), and the deeper Cryptomator pass, a vault metadata-read size cap against a hostile vault (queued row 35,4327bc14, CLAUDE-AV-B1-11). B1 AeroFile is now 17/17.c394a7da,4327bc14--level 1gz/zip output is +40% larger thangzip -1on text (zlib-rsdeflate_quick, 2.4x faster, byte-comparable from level 2 up); evaluate a zlib-compatible level mapping or keep the speed-first point documented. Resolved ahead of B2: level 1 pinned to backend level 2, shipped as queued row 30 (efe42085)efe42085-mx1is invariant to dictionary size (the only exposed lever: 256 KiB to 8 MiB all land within 252 bytes), so it is inherent to lzma-rust2's fast-mode parse, not a level-mapping bug; AeroFTP 7z L1 is byte-identical toxz -1, a standard "Fastest" baseline. Closing it would require emitting preset 2 (+35% time at the Fastest level, and it would break the xz-parity and level-distinctness contracts). Decision: documented, no pin, the inverse of the DEFLATE L1 fix (DEFLATE L1 was pathological at +40%, 7z L1 is not). Cross-extraction 12/12 both ways, and a small-file interop matrix passes 18/18 across every createable format (zip, 7z, tar, tar.gz, tar.xz, tar.bz2, gz, xz, bz2), both directions.profile-addcan now seed the credential in one step, so a CLI-created profile is immediately connectable. It previously wrote only the config entry, so the new profile landedauth_state: no_credentialsand could not connect, and the global--password-stdinwas even accepted and silently ignored. Now--password-stdin(plain secret) plus new--credential-json/--credential-json-file(token/API-key blobs) write into the sameserver_<id>vault key the GUI Edit modal uses. Sources are read and JSON-validated before the profile is persisted, so a malformed blob fails fast with no orphan profile; omit them and the profile is created credential-free exactly as before. From a real FTPS maintenance job.66b88e74/mysiteanswers 550): listing a missing directory could hang forever behind theListing ...spinner, because an MLSD against a non-existent path opened a PASV data connection the server never serviced (a control-only MLST probe now fails fast in about a second), and a post-login 550 was shown asCheck credentialseven though the login had already succeeded (now reported as a path-not-found with guidance to edit the Remote Path or clear it, translated across all locales).0f55837c,3600715f592514a3CryptOverlayProvider::liststill decrypted-or-dropped every name, sols,tree,lsjsonand the MCP listing tools reported a remote whose root is not the vault as empty or as only its encrypted items.listis now scope-aware through awire_path_is_encryptedclassifier (decrypt strictly-below-anchor, pass the anchor and everything at/above/outside it through as raw plaintext), and path mapping gained a Read pass-through (encode_plain_targetreturns the raw path for a non-mutating op on an out-of-scope target instead of erroring) applied to every read path (list,cd,download,download_to_bytes,stat,size,exists,disk_usage,list_versions,download_version), which also stop decrypting content and sizes for plaintext siblings; every mutating op (upload,mkdir,delete,rmdir,rename,chmod,server_copy,restore_version, ...) keeps the fail-closed refusal so a write can never land plaintext where ciphertext is expected. A whole-remote overlay (scope=="") is byte-identical to before. 6 new unit tests (both AeroCrypt and rclone-crypt kinds), and live-verified on real scoped remotes (Filen and lab SFTP):ls/stat/lsjson/catand thesync/dedupe/cleanupwalkers show plaintext-outside and decrypted-inside, and the MCPlist/treetools the same. Closes known-issue 3; the user-facing Remote Path configuration UI is the remaining follow-upf4a31894dextractwindow mounts only the ExtractWindow dialog and never applied the theme class, so it always rendered light even though its components already carry the dark variants. It now reads the saved theme (aeroftp-theme, falling back to the OSprefers-color-schemewhen set to auto) and toggles thedark/truedarkclasses before render, mirroring the main app.3f1ac3d31completeevent could flip an item already in theerrorstate tocompleted, because the event-to-item correlation falls back to filename when several items share a name. The status transition is now a pure guard that refuses to move anerroritem tocompleted, so a mis-correlated completion cannot resurrect a failed item as successful; a genuine retry still completes because it re-enterstransferringfirst. Covered by unit tests on the same-name error/active scenario.3d4f82267docs.aeroftp.app), published separately from the app release.61264f2(docs.aeroftp.app)--checkershelp is now honest: it promised parallel metadata probes, but the--no-traversestat sweep runs sequentially today (StorageProvider::stattakes&mut self, so one provider handle serialises the probes and the cap only shows in the sweep summary note). The help now says so and points at the provider pool refactor (Sprint K2) as where it becomes a real concurrency gate. Doc-only.9ca342cc10dc7be6fclassifyUpdateVerificationstates are unit-tested and the new strings are translated across all 46 locales. The hard Sigstore gate (block an unverifiable update) is a deliberate deferral to v4.1.4.47ba808c2package.json,tauri.conf.json,Cargo.toml,snapcraft.yaml,splash.html, plusCargo.lock), a new<release>entry in the AppStream metainfo, and the curated CHANGELOG [4.1.3] section (Added, Changed, Fixed, Security) that CI extracts verbatim as the GitHub Release body.5e56fb513Requested / under consideration
Community requests and internal follow-ups being evaluated for this or a later release.
Effort: 🟩 quick win · 🟧 medium · 🟥 large / epic. Ordered by effort (quick wins first).
.mp3to.opusis destructive and should not be done silently)WM_DEVICECHANGElistener emittingvolumes-changedon device arrival/removal would make it instant; lighter mitigations are a refetch on window focus or a shorter poll interval. Surfaced during the #351 eject verification on real Windows hardware-iselectors (prioritised by the reporter ahead ofEdit(E)and the 2-letter semantics; exact behaviour to be pinned)users -i: a verb sousers -ican add/remove groups to/from a user. The groups-side counterpart (groups -ia/xfor member profiles) shipped in 4.1.0; this remaining users<->groups direction needs the data model pinned first, since groups live inside each user's partitionAeroFTP.ArchiveProgID + WindowsCapabilities/RegisteredApplications/OpenWithProgidsthat make zip/7z/tar/rar actually display the icon and list AeroFTP under "Open with" and Settings > Default apps. Available-opener only, never a forced default (decision c). Needs both hooks.nsh and the WiX fragment, plus a clean-machine Explorer eyeball of the MSI icons (the v4.1.0 dev-runner check had HKCU competitors masking the render; the HKLM registry was verified correct)xdg-mime default(works immediately), Windows registers capabilities and opens the OS chooser (Windows 8+ blocks silent forced association, so honest copy "Windows will ask you to confirm"), macOS best-effortLSSetDefaultRoleHandlerForContentType. Cross-platform follow-up to the OS extract / icon workf4a31894d, queued row 64); the scope already flows from the binding / initial path. Remaining: the user-facing Remote Path input (GUI form field + CLI flag) to set the subtree explicitly--s3-versions/cleanup-hidden). AeroFTP already ships the generic per-file version primitives for every S3 backend (list versions, download a version, restore by server-side copy-forward, itself a first-class op rclone core lacks). The bounded remaining work, all standard S3, is a bucket-wide trash browse (ourlist_versionsis per-key and drops delete markers, so a deleted file cannot be discovered without knowing its key) plus a permanent purge (DELETE with versionId for one version, and an empty-trash sweep equivalent to rclone's cleanup-hidden). Feasibility verdict only, no code this pass; owner-gated whether to build now or deferStorageProvidertrait, recommending a hybrid model. Implementation is a later, separate effort.jpgto.jxltranscode in AeroFile: JXL re-encodes an existing JPEG losslessly and reversibly (the original JPEG bytes reconstruct exactly), for a real size win with no quality loss. Candidate framing: AeroFile as a GUI for libjxl.icnsmulti-size (the v4.1.0 ones are single-resolution drafts). Needs a Mac to build and live-testparticipants/addcontactUUID format (currently a best-effort workaround), investigate the Filen free-plan 10-note limit ghost-note cleanup, and add a rich text editor for the rich note typeaeroftp dedupe, and as an agent tool). Part of a broader principle: deterministic, repeatable file chores should run as ready-made native features or plugins, not through an LLM. The plugin lane (manifest plus script, no AI) is the natural home for these but is currently gated: the signed-registry client is unfinished and CLI plugin support is pending (Fase 6.4, Low). Related to the lossless jpg-to-jxl transcode already tracked above (item 12)malloc(): unaligned fastbin chunk detectedwhile deserializing a D-Bus message, the classic GLib heap-corruption signature (that worker is the victim tripping over an already-poisoned fastbin, not the corruptor). Two marshalling fixes already shipped and are safe: tray badge (31db84f8b) andapp_ready+ splash-timeout (cae95ee91), present since v4.0.5. But the SIGABRT STILL recurs (v4.0.9 on 2026-06-25, and the v4.1.2-era build on 2026-07-05, identical signature): the marshalling is INCOMPLETE, a still-uncovered off-main-thread GTK path remains. Sync Tauri commands are provably main-thread (safe), so the suspects are the event/plugin callbacks whose thread context is unconfirmed: trayon_menu_event/on_tray_icon_event, the single-instance plugin callback, andon_window_eventCloseRequested. Pre-existing across versions, intermittent, triggered by D-Bus storms on suspend/resume or monitor standby; it can corrupt the whole app until restart. Definitive path (owner-approved): adopt self-hosted crash reporting with native minidumps to capture the real corruptor, plus an ASan/valgrind repro, then finish the marshalling on the remaining callbacksKnown issues found after release
Reported against v4.1.2. Fixed items ship in v4.1.3; reporters close after confirming in the release.
f4a31894d):CryptOverlayProvider::listis now scope-aware (plaintext outside the bound subtree, decrypted inside), and the CLI (ls/tree/lsjson) and MCP listing tools inherit it. Ships in the next release; the user-facing Remote Path configuration UI is a separate follow-upStatus legend: 🔴 confirmed · 🟡 investigating · 🔵 planned / idea · 🟢 done / fixed (pending release) · ✅ released
Affected platforms
Maintained by the AeroFTP team. Current release v4.1.2 (#384), next v4.1.3. Patches accumulated here; each release line still gets its own tracker.
All reactions