| Name | Modified | Size | Downloads / Week |
|---|---|---|---|
| Parent folder | |||
| macSCP-1.4.0.dmg | 2026-09-07 | 38.7 MB | |
| README.md | 2026-09-07 | 38.4 kB | |
| v1.4.0 source code.tar.gz | 2026-09-07 | 4.9 MB | |
| v1.4.0 source code.zip | 2026-09-07 | 5.8 MB | |
| Totals: 4 Items | 49.5 MB | 0 | |
1.4.0 (2026-09-07)
Features
- app: quitting tears every live tab down through the one owner, bounded (c14c277)
- app: the stores are re-read when the app becomes active (bfa0cd0)
- app: what's new after an update (487a071)
- browser: a bucket row opens, nothing else (2818eb6)
- browser: a checksum column that shows only what was asked for (3cd7221)
- browser: a Type column, and a bucket looks like one (506eae7)
- browser: the local pane shows the folder first and fills the details as they arrive (db71304)
- browser: the permissions editor follows the capability, and says so where there is none (78a0916)
- checksums: a host without the algorithm's tool says so (d55211c)
- checksums: a per-tab ledger of what the user asked for (57e5927)
- cli: --group and --tag complete their values from the store (8b965b5)
- cli: a host-key capability axis, and help on an unknown subcommand is a usage error (cab8c7b)
- cli: complete session names from the store, and nothing else (ae0078c)
- cli: list the saved sessions with filters and --json (66b3a52)
- cli: macscp-cli diagnose runs the connection diagnostics from the terminal (8565c54)
- cli: sessions add, edit and rm write the store, never a secret (df03779)
- cli: the diagnosis renders to rows, JSON lines and an exit code (6e16b67)
- cli: tunnels list, add, edit and rm over the app's profile store (f47475e)
- cli: tunnels start holds a forwarding open in the foreground (d171b74)
- core: a file's type label, and buckets know they are buckets (4e6fd24)
- core: forwarding specs, tunnel carriers and the session-name rule as one truth (31654ef)
- core: parse the changelog into releases (88229bf)
- diagnostics: a diagnosis can run one probe instead of all of them (0176da6)
- diagnostics: a diagnostic log with a level, written off the caller's path (51f9c49)
- diagnostics: an IPv4 network trace on unprivileged sockets (d4e2e8e)
- diagnostics: choose what to run, and read the trace as a table (7a81a45)
- diagnostics: ICMP echo without privileges (1f52564)
- diagnostics: listings, connects, SFTP requests and transfers write to the diagnostic log (6d428df)
- diagnostics: one panel behind the tab, the session menu and the error dialog (9d23232)
- diagnostics: resolve, TCP ping and the dial as one report, behind the descriptor seam (8997c95)
- diagnostics: rows appear as steps finish, and a diagnosis belongs to the tab that opened it (bf3b3bd)
- diagnostics: the running line names the step in flight (391083a)
- diagnostics: the S3 key's access level and the WebDAV server's claims, as contributions (5828610)
- diagnostics: the trace carries its hops as a table (5ea7f2b)
- import: a bookmark source reads Cyberduck's files (d146ce5)
- import: Cyberduck's keychain items, read on request (43c4b4d)
- import: import from Cyberduck — preview, selection, update (b612ebe)
- import: the preview planner tells new from known and changed (2c35447)
- keys: RSA and ECDSA managed keys can be file logins (8f9dd89)
- local: metadata arrives per entry as a stream, and a stuck entry is left behind (3f9e3cf)
- local: the listing returns names and kinds from the directory read alone (9d8354c)
- s3: a connection may start at the bucket list (3bbafcd)
- s3: a preset per Hetzner Object Storage location (c60d115)
- s3: default the region on a new form and say why bucket and region are needed (62d2678)
- s3: the form's "Start at the bucket list" toggle and its messages (f325ce3)
- sessions: a catalog value that lists and filters stored sessions (00ce088)
- sessions: a session remembers where it was imported from (167cbfb)
- sessions: the overview model derives facts, history and snippets from what is stored (7b2d5ee)
- settings: a "What's new" pane (b18ea20)
- settings: keep-alive is an on/off switch and an interval, not one value (726ffb9)
- settings: the diagnostic log has a level, a folder, and a way to find it (b1ce349)
- sidebar: "Move to…" moves a folder without dragging, and both submenus share one target rule (f798788)
- sidebar: a click shows the session's overview — facts, history, snippets, three actions (df58a6a)
- sidebar: a compact mode, as a setting (dc9ce11)
- snippets: a placeholder is inserted at the cursor, replacing the selection (96d02cb)
- snippets: name a placeholder that is declared as an environment variable (96ea4d1)
- snippets: Run from the session overview connects, opens the terminal and sends (fefdab3)
- ssh: name a key's type before trying to load it (15e5042)
- ssh: RSA and ECDSA private key files authenticate directly (fa67138), closes #135
- ssh: say what a key is and what works instead (8f66d41)
- ssh: verify rsa-sha2-512 host keys (38b8781), closes PKCS#1
- tabs: a registry that lets a tab change windows without changing hands (8445961)
- tabs: drag a tab into another window (fb61213)
- tabs: duplicate a tab, connected when its source is (7fecc64)
- transfers: a row shows its full source and destination paths on demand (4d0b04f)
- transfers: a setting shows every row's full paths without hovering (f198548)
- transfers: cancel one transfer, or all of them (66bea86)
- tunnels: a dynamic forward speaks SOCKS5 (d0cbf65)
- tunnels: a local forward pumps bytes through a direct-tcpip channel (bf9f16c)
- tunnels: a remote forward brings the server's port to this Mac (8ce2535)
- tunnels: a runner drives a profile through its states, reconnecting with backoff (ab5f62d)
- tunnels: autostart at app start or login, and the state in the sidebar and the Dock (b1d2c71)
- tunnels: profiles per session, started from the context menu, stopped at quit (ea797a6)
- tunnels: profiles, their store, and the state machine (7c19a30)
- windows: a tab moves into its own window (aee95e9)
- windows: keep a window on top (3fd16e6)
- windows: restore windows, disconnected, when asked (3b3f8e0)
Bug Fixes
- app: a caller that waits for a reconcile still gets a pass of its own (7c1a196)
- app: a forwarding deleted on disk is stopped, not orphaned, by the activation reload (1f6e89d)
- app: an unreadable tunnels.json is not a deletion, and one reconcile runs at a time (ccf4dfd)
- app: the diagnostic log is flushed synchronously when the app terminates (7a3716e)
- app: the quit's watchdog can end the chain between tabs, and a relaunch waits for the old process (5e87722)
- app: the reconcile passes are chained, not gated (d6b6ad9)
- app: what's new tests pin a release by version, and the guards read the extracted load (ae8daed)
- app: what's new treats a non-numeric version as nothing to show (232661e)
- browser: a checksum recorded after a reconnect stays out of the new session's ledger (589e431)
- browser: every transfer entry point asks the same scope; a bucket row downloads nothing (2d911fc)
- browser: the info sheet feeds the checksum column; the ledger lives with the tab (da30363)
- browser: the name column's kind marker keeps a gap before the name (017adf7)
- browser: the Type column shows by default, the bucket glyph has a behavioural test, and the labels are compared through the catalogue (89646c4)
- cli: derive sessions --kind help text from ConnectionKind.allCases (77a885b)
- cli: diagnose rows reach a pipe as they land, the secret chain answers once, and the docs say complete (36ec918)
- cli: give sessions its own --json-only option group instead of GlobalOptions (19f4128)
- cli: locate the gated roundtrip's CLI binary bundle-relative, not by repo path (6ee9e04)
- cli: the host-key axis pin is not a derivation, and the running-step catalogs are checked for their placeholder (3875777)
- cli: the parsed root command is run where it is parsed, so nothing non-sendable crosses an isolation boundary (0b771fe)
- cli: the root command is parsed and run inside one nonisolated free function (efe44f1)
- cli: the sessions verbs refuse an empty value, an empty name and a port outside 1-65535 (f4af523)
- cli: the tunnels start loop is Core's, and its guard reads only the dial (60831bb)
- cli: tunnels start refuses an unknown option as one, and the record's last counts match the tree (8b5ee7a)
- connection: the connection form scrolls when the window is short, its buttons stay put (bc94bac)
- core: the changelog parser reduces every link and orders releases newest first (5eb201f), closes #N
- diagnostics: a backend error reaches a row as a fixed sentence, never as its description (bd6ec81)
- diagnostics: a cancelled report says it was cancelled (d6cec28)
- diagnostics: a diagnosis ends with its sheet or its tab, and the guard reads every form of an automatic start (01ee521)
- diagnostics: a logged reason only ever comes from the audited mapper, and so does the browser's error text (1f1f3f3)
- diagnostics: a trace ends honestly on refusal, hop limit and socket error, and its comments say so (4456836)
- diagnostics: an echo reply counts only when it carries this probe's payload (42a730e)
- diagnostics: no credential in a report, named errors, and a deadline that bounds the clock (ea9ea54)
- diagnostics: the connect line drops user-info from the endpoint, the writer cannot trap on a closed handle, and the sink tests read only their own lines (7f7b626), closes #require
- diagnostics: the echo nonce is pinned per socket, and the routeless case is anchored on a counted send (ae0be51)
- diagnostics: the guard reads interpolations, a foreign error's description is measured, and the row counts the sites (800c9b6)
- diagnostics: the lifecycle tests can fail, the entry guard reads every overload, and a running report can be copied (287d4d2)
- diagnostics: the log's timestamp always carries an offset, flush cannot hang, and a batch splits at midnight (41831e4)
- diagnostics: the panel's footer keeps its buttons whole (7481db8)
- diagnostics: the plan's records count what happened, the guards read every door, and a report without an endpoint says so (0c483d7)
- diagnostics: the report strips any authority, names no loader reason, and its comments say what was measured (6485440)
- diagnostics: the S3 probe signs the file system's own request shapes (4fc6045)
- diagnostics: the trace has its own budget and says when the budget, not the path, ended it (1a4573a)
- diagnostics: the trace's outcome words are looked up, not passed through (36edabd)
- diagnostics: the write lock covers taking the batch, so a synchronous flush cannot overtake the writer (40445d0)
- i18n: align keep-alive footer framing and fix Polish plural (4387b6f)
- import: a provenance match needs the same connection kind (f054b73)
- import: an update replaces its record by id, carries its groups, and takes the nickname (e8a61bd)
- import: reject a field bag the backend's own schema cannot dial (0587a2c)
- import: the gate reads a blank value as absent, and says what it judges (fd6304f)
- import: the gate trims before it decides a value is there (c4ac55e)
- import: the keychain answer has three states, the folder is read off the main actor, and the alert lines are pinned (70188e0)
- import: the replace handle never leaves memory, an update keeps the auth kind, and an unchanged row can take provenance (61eeb24)
- keys: the generator's caption asks isConnectable, not the type literal (e9320c4)
- liveness: the probe loop keys on the switch, not on a zero interval (192ed54)
- local: a late-returning child clears its stuck mark after the tally has seen it finish (92a8efa)
- local: a stuck entry is named at the deadline, remembered for the session, and the merge is O(1) per arrival (092d068)
- local: a stuck path is remembered only after a longer deadline, marked atomically, and forgiven when it answers (8f56f4a)
- s3: a bucket is not a file, an error names its bucket, a rename stays in one (8f727f2)
- s3: a key that is both an object and a folder is refused by delete and fully removed by deleteTree (1799071)
- s3: an endpoint with a port connects, and the form says what it understood (43e06e8)
- s3: an IP endpoint is addressed path-style, and the form names the origin the request uses (7fcd1a0)
- s3: bucket-level refusals are an enum with a sentence everywhere; list mode stores no bucket (539dc59)
- s3: correct the Hetzner-id doc claim, two guard scan spans, and Darwin import (9af168d)
- s3: deleteTree deletes a plain file, delete refuses a directory and reports a missing key (e7169c1)
- s3: seed the login-set sheet's initial values from editBaseline (96e2f7d)
- s3: stop fillForm from dialing a connect with a guessed region (d2b908f)
- s3: stop the region default from leaking into a saved session (a9693b5)
- s3: the presigned URL signs the factory's path, and the doors guard says when a key must land (64a5dc5)
- sessions: a connection row is as old as its start, not as its close (c3e45c1)
- sessions: a dangling groupID surfaces at top level, not dropped (43912d4)
- sessions: a duplicated session id yields one row, not the first session twice (3482154)
- sessions: a pending snippet is dropped before the terminal shuts down, and three comments count again (a61df6b)
- sessions: don't let a duplicated session id trap the whole CLI (a929fa8)
- sessions: make the sidebar-order test sensitive, pin the blockless-block target, unify formatting (f916597)
- settings: a stored 0 keep-alive interval reads as the default, not the floor (e75a049)
- settings: drop the reader-less keep-alive default, pin the toggle/interval split at the store (8f04e83)
- settings: the "What's new" pane parses the changelog once (e6dbc83)
- sftp: a file close cannot hang — the raw file never reaches the file system (55e6830)
- sidebar: "Move to…" says "Top level", hides an empty submenu, and the guard reads each row (9ca4465)
- sidebar: compact mode changes density only; the default row is what it was (0ce0ca6)
- sidebar: compact mode keeps the kind badge; density is the padding alone (fbd3177)
- sidebar: compact mode tightens the folder rows too (3f7b7a0)
- sidebar: the error caption can be closed and clears itself after six seconds (ece5aaf)
- sidebar: the hidden-imports caption can be closed and clears itself (c4558e9)
- sidebar: the overview drops the previous session's facts, and the guard scans for secrets (9d4e4a4)
- snippets: inserting a placeholder is undoable like typing (94e7ff8), closes #require
- snippets: one shell attempt for a Run, offered only where a shell exists (066afd2)
- ssh: a comment's line citation into Citadel, off by one (8573fa2)
- ssh: a connect failure's text is the error's localizedDescription, never its description (b7e1854)
- ssh: an RSA host key below 1024 bits is not a key (14f3ed3)
- ssh: close the write-then-chmod window in the ASKPASS helper (0d72b84)
- ssh: make the ASKPASS helper's cleanup exception-safe and its passphrase shell-safe (43f8ed8)
- ssh: name the verified Go-server RSA caveat in the message (1a0e3ab)
- ssh: RSA logins type the key blob ssh-rsa; Go-based servers accept them (6740c2a)
- tabs: a drop lands nowhere only when it is outside every window of ours (e0f4108)
- tabs: a move is proven not to tear anything down, and detaching the last tab clears the active id (36fb81d)
- tabs: a tab drag carries its own type, and dropping it outside every window opens a new one (6f7dc62)
- tabs: a window on another Space does not count as ours for a drop, and the docs say what shipped (4e482fb)
- tabs: every new tab is registered with its window, and the strip's comments say what the sidebar drops (c52c83b)
- tabs: the drag source offers move and copy in-app, lets control-click through, and accepts the first mouse (c8c9670)
- terminal: a failed window-change is not remembered as sent, and a failing sizing test goes red instead of hanging (1cc7f07)
- terminal: a window-change is remembered only for the shell it was sent to (273c678)
- terminal: the shell learns the panel's size when it opens, and again when it reopens (2d0fa18)
- tests: a cancelled waiter leaves the agent lock's queue, and a continuation exemption sits beside its use (99d305b)
- tests: a waiter cancelled before it registers never leaves a token behind (2f5f4e6)
- tests: import Citadel with @preconcurrency in the frozen-peer suite — the two toolchains agree on nothing else (56ddcff)
- tests: keep the bounded-SFTP test helper on the main actor so CI's toolchain compiles it (38b7434)
- tests: rewrite terminal inset expectation without ?? on optional (a336bb3)
- tests: the agent lock's fast path commits under the same lock the cancel path reads (d2c5f94)
- tests: the polish plan's guards pin what they name, and its records say what the code does (f780d3c)
- test: the cancellation wait is cancellable, and the foreign origin is read at accept (d4423be)
- test: the loader's offer helper awaits NIO instead of blocking the cooperative pool (cdf46be)
- test: the retry helper's callers counted, the Citadel claim corrected, the port list complete (45ebb39)
- transfers: "Copy paths" copies raw paths, the row's hint and menu cover the whole row, and the guard reads code (3f77a60)
- tunnels: a deleted session stops its forwardings, and one sheet at a time (4600f4e)
- tunnels: a rejected handshake stays silent after handover, and the reply codes say what reaches them (04ee188)
- tunnels: a remote forward's start is bounded and cancellable, port 0 is a recorded fork debt, and the pump's wrapper is gone (a037a2b)
- tunnels: a resumed peer is read again, a forward's reason survives, and a failed open closes both sides (4f67365)
- tunnels: a session's profiles leave the store before their runners stop (679bcde)
- tunnels: a start cannot land inside a suspended stop, and a run that ends clears its own task (94ade42)
- tunnels: one command chain, a mapped TunnelFailure, and a guard that reads through the wrapper (94baa44)
- tunnels: the alarm has a row behind it, the footer says what the launch cannot tell (1a4b94b)
- tunnels: the kind's doc says what the fixture shows, and two rows are pinned (f48fa73)
- tunnels: the prompt's candidate is stored, and the quit's tunnel stop really is bounded (1100ff3)
- tunnels: the pump starts its reads from the channel lifecycle, never from a task (e853066)
- tunnels: the server side of a negotiated forward is read only after the reply, and every rig case awaits its teardown (385f262)
- tunnels: the window's bridge wiring is pinned, and a forced tunnel stop is written down (7046da2)
- webdav: delete refuses a directory, and the delete rows say what was measured (8c87c49)
- webdav: deleteTree on a plain file deletes the file (4587c85)
- windows: a restored, never-connected tab keeps its session across a second quit, and the plan's docs say what shipped (46da790)
- windows: a source window closes when its tab is claimed, not on a turn count (71fdf91)
- windows: menus follow the key window through focused values, a move opens before it closes, and seeded windows are not restored (c9ae9e7)
- windows: the registry owns pending moves, and an unclaimed tab is torn down when its source closes or the app quits (33d508f)
- windows: the windows on screen at quit are the ones restored, and a restored tab shows its session's overview (88a54ff)
Performance Improvements
- s3: a delete looks its key up in two constant requests instead of paging the parent (0876efd)