[3.5.9] - 2026-04-20
CLI Agent Experience Polish
Follow-up patch to v3.5.8 focused entirely on the CLI surface. All items are small, independent, and addressed in one coherent pass so an agent using aeroftp-cli against a generic FTP hoster has the same UX quality the MCP server got in v3.5.8.
Added
plan[]insync --dry-run --json: every candidate operation is now listed with{op, path, local_size, remote_size, conflict_path}. Real (non-dry-run) runs omit the field viaskip_serializing_if, so legacy parsers that never asked for dry-run see the exact same shape. Agents no longer have to fall back to parsing the text-verbose output to build an execution plan.
Fixed
- Missing-parent uploads now explain the failure:
putruns a pre-flightstaton the remote parent directory. If the parent is missing the CLI errors out with "Parent directory '/X/Y' does not exist on the remote. Create it first with: aeroftp-cli mkdir -p '/X/Y'" — one crisp message instead of three retries of a generic553 Can't open that file: No such file or directoryreturned by the hoster.is_retryable_exitnow excludes exit code2(not-found) so the retry loop stops burning attempts on stable failures. - Sync remote scanner auto-reconnects on transport failure:
sync_core::scan_remote_treenow classifieslist()errors against the sameis_transport_levelpattern used by the MCP pool (variant matches onNotConnected/ConnectionFailed/Timeout/NetworkError/IoErrorplus message patterns like "Data connection is already open", "broken pipe", "connection reset"). When it fires, the provider is disconnected and reconnected, thenlist()is retried once. Previously the scanner logged a warning and treated the failure as an empty directory — which let sync silently duplicate files that actually existed on the remote. lsfollow-up hint no longer ships a literal*.extplaceholder:suggest_ls_followupnow renders"*"so agents copy-pasting the hint get real results. The*.extstring survives only in bootstrap playbook JSON where it is documented as a placeholder the user must substitute.
Build
- cli-smoke Windows runner installs Strawberry Perl: the
openssl-sysvendored build pulled in transitively byssh2 = "=0.9.5"requiresParams::Checkto configure OpenSSL, and the stockwindows-latestPerl no longer ships it. Added achoco install strawberryperlstep gated byrunner.os == 'Windows'. Linux and macOS jobs are unaffected.
Downloads:
- Windows:
.msiinstaller,.exe, or.zipportable (no installation required) - macOS:
.dmgdisk image - Linux:
.deb,.rpm,.snap, or.AppImage