1.1.0
Released on 2026-06-08
Added
- new website
- install: add Windows PowerShell installer and copy buttons on site
Add install.ps1 mirroring install.sh for Windows: arch detection,
release zip download, binary extraction, user PATH update.- copy install.ps1 to site public/ at build time (copy-install.mjs)
- serve /install.ps1 with text/plain Content-Type (vercel.json)
- add PowerShell one-liner to install page and README
- bump install.ps1 default version in bump_version.sh
- add CopyButton component next to every install command line
- config: move config dir to ~/.config/termscp on macOS and %USERPROFILE%.termscp on Windows
Resolve the config directory through a single per-platform config_dir()
function instead of relying on dirs::config_dir everywhere:- macOS: ~/.config/termscp (was ~/Library/Application Support/termscp)
- Windows: %USERPROFILE%.termscp (was roaming %APPDATA%\termscp)
- Linux/other: /termscp (unchanged)
Existing users are migrated automatically on first run: when the new
directory is absent and the legacy location exists, the whole config
directory is moved to the new path. The cache directory stays at the
platform-native location.
CI
- automated release workflow
Single workflow_dispatch (version, dry_run) that bumps versions, regenerates
CHANGELOG via git-cliff, rebuilds site CSS, builds all targets, creates the
GitHub release, updates the Homebrew tap and publishes Chocolatey.- dist/release/bump_version.sh: version replacer across all tracked locations (+tests)
- .github/workflows/release.yml: prepare -> build matrix -> homebrew/release -> choco
- retire build-artifacts.yml (merged into release.yml)
- Linux builds via cargo-zigbuild (old glibc) for broad compatibility
- pin all actions to verified SHAs and clear zizmor findings
Pin every action to a commit SHA whose tag comment matches (verified via gh api),
add least-privilege permissions, set persist-credentials: false, and replace the
archived actions-rs/cargo with a plain cargo test. zizmor clean at default persona. - fix release notes generation in release workflow
prepare job failed: git-cliff --latest crashed with 'trim_start_matches on
null' because the checkout was shallow (no tags/history) so no release existed.- checkout prepare with fetch-depth: 0 + fetch-tags so git-cliff sees full
history and tags (also fixes an otherwise-truncated CHANGELOG) - generate release notes with --unreleased --tag v$VERSION instead of --latest:
--latest selected the previous real tag (stale notes); --unreleased --tag
renders the version being released
- checkout prepare with fetch-depth: 0 + fetch-tags so git-cliff sees full
Changed
- site: type-safe i18n keys derived from en
- site: drop in-site manual, link to external docs.termscp.rs
- site: english-only, remove i18n machinery
Fixed
- install: quote vars, fix set -e cargo check and rustup tmpfile cleanup
- silence SC3043 by declaring dash dialect (local is supported)
- quote unquoted vars (SC2086/SC1090)
- fix set -e aborting arch install before cargo check
- fix install_cargo removing unset $archive instead of $rustup
- make brew upgrade fallback a real if-then-else (SC2015)
- drop leftover starship BASE_URL and debug echo $1
- progress: rework transfer progress panel (#424)
Migrate the transfer progress UI to tuirealm 4, where the stdlib
ProgressBarwidget was dropped, by rebuilding the dual-bar panel on
top ofGauge.- Restore the unified two-bar look: the full bar (top) and partial bar
(bottom) draw joined borders so they read as a single panel; a single
file shows one fully-bordered bar. - Redraw on every file boundary in the send/recv queue loops so the
full bar's (N/total) counter advances even for small files that finish
within one in-loop redraw interval. - Track progress with a single
TransferProgress(exact file count from
the pre-scan, lazy partial/full computation) and consolidate the theme
progress-bar fields.
- Restore the unified two-bar look: the full bar (top) and partial bar
- progress: equalize dual progress bar heights
The bottom (partial) bar carried a block title (the current filename),
which forces a 1-row top inset in ratatui'sBlock::innereven though
its top border is dropped to join the seam with the full bar. That left
the partial bar with one inner row while the full bar kept two, so the
two gauges rendered at unequal heights.- Move the filename from the partial bar's title into its gauge label.
- Skip setting an empty title so no phantom top-positioned title triggers
the inset. - Put the panel title on the top (full) bar for multi-file transfers.
- Bump the two-bar popup height to fit the joined panel.
Also bump Cargo.lock and adapt the embedded terminal to the new vt100
screen_mut()API. - copy: prevent emptying file when copy destination is empty (#421)
An empty copy destination resolved to the source file's own path, so
std::fs::copy truncated the original file to 0 bytes.- localhost::copy now refuses to copy a file onto itself, returning an
error instead of truncating it (root cause). - action_copy treats an empty/whitespace destination as a cancel.
- localhost::copy now refuses to copy a file onto itself, returning an
- transfer: enqueue full destination path instead of directory
Queued transfers stored only the destination directory as the target
path. Downstream upload logic treats the queued destination as the full
file path and passes it straight to create_file, so transfers failed
with a Failure error when the remote target resolved to a directory.Append each entry's file name to the destination directory at enqueue
time in both enqueue_file and enqueue_all, matching the single-file
transfer path which already builds the full target path.