2 Commits

Author SHA1 Message Date
bsncubed 0ecdffbbbd docs: correct Go version and remove unshipped SFTP browser claims
- README: build-from-source requires Go 1.25+ (matches go.mod), was 1.23+.
- docs/v2-report.md: the in-app SFTP file browser was never built (no `t`
  action, no xfer/sshx/browser packages, pkg/sftp not a dependency). Cut the
  false "shipped" claims and moved it into the Deferred section.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-26 16:27:59 +10:00
bsncubed 271a794895 Add prebuilt release binaries for v0.1.0
Force-add the cross-platform binaries (macOS arm64/amd64, Linux
amd64/arm64, Windows amd64) and their SHA256SUMS into dist/, rebuilt
from current source with `make dist` (go1.26.5, -trimpath). All tests
pass. These override the /dist/ .gitignore entry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-26 16:18:23 +10:00
8 changed files with 34 additions and 81 deletions
+1 -1
View File
@@ -106,7 +106,7 @@ that ships in `%WINDIR%\System32\OpenSSH`.
### Build from source instead
Requires Go 1.23+.
Requires Go 1.25+.
```sh
make install # builds and installs into $GOBIN (or $GOPATH/bin, ~/go/bin)
+5
View File
@@ -0,0 +1,5 @@
c5fc3eb4c3903aa2b7a30aba13e3646b960b020da6b49ca99ae9e63e2de431ce dial-darwin-amd64
708b4037e7aa857b7311f9d707ebfb197d4fb3018a55ba0c885df96c8268e567 dial-darwin-arm64
05e27c52bd21d525f78b5b43bc14ee1a7c3b2b5629165eec104028731f45211b dial-linux-amd64
94a89c8de21f1a4673f82ab4f230346839b9bd8408e9599eac566c2cba689a3f dial-linux-arm64
cd5786b303799cc001215afd793c26883c77eb04e10a161dd467909595aa9b09 dial-windows-amd64.exe
Vendored Executable
BIN
View File
Binary file not shown.
Vendored Executable
BIN
View File
Binary file not shown.
Vendored Executable
BIN
View File
Binary file not shown.
Vendored Executable
BIN
View File
Binary file not shown.
Vendored Executable
BIN
View File
Binary file not shown.
+28 -80
View File
@@ -11,10 +11,10 @@ added and where it stands.)
interactive host picker: it reads `~/.ssh/config`, shows a clean, static,
high-contrast, low-light-friendly list, and on selection `exec`s the real system
`ssh` client into the host (so tty/ProxyJump/agent forwarding just work). It's a
single Go binary. v2 added sorting/grouping, an SSH key generator, and an in-app
SFTP file browser. Optional features include a YubiKey launch gate. App data
(recents, favourites, settings) lives under `~/.ssh/.dial/` so it syncs via the
user's existing Syncthing.
single Go binary. v2 added richer sorting/grouping and a native SSH key
generator. Optional features include a YubiKey launch gate. App data (recents,
favourites, settings) lives under `~/.ssh/.dial/` so it syncs via the user's
existing Syncthing.
## What v2 shipped
@@ -40,21 +40,6 @@ user's existing Syncthing.
duplicate an existing alias. It's a rebuild of an old `create_ssh_keypair.sh`,
fixing that script's macOS-only `sed`, key-deletion, and unquoted-append bugs.
5. **In-app SFTP file browser.** Pressing `t` on a host opens a dual-pane
browser (local left, remote right) that transfers files without leaving dial:
- Side-by-side panes, `tab` to switch, arrow/`jk` to move, `enter` to descend,
`backspace` up, `space` to batch-select.
- Directional transfers: `→`/`p` push local→remote, `←`/`g` pull remote→local,
into the other pane's current directory.
- Recursive directory transfers, aggregate progress bar, and overwrite prompts
(`[o]verwrite`/`[s]kip`/`[r]ename`, uppercase = apply to all remaining).
- **Same-session resume**: an interrupted transfer retried in the same session
resumes partial files instead of restarting.
- Connects over SFTP in-process (`pkg/sftp` + `golang.org/x/crypto/ssh`),
reusing the host's real `~/.ssh/config` (resolved via `ssh -G`), including
ProxyJump, authenticating via ssh-agent or unencrypted key files.
- When the YubiKey gate is enabled it re-challenges before opening the browser.
## Architecture (packages)
Existing v1 packages: `sshconf` (read-only config parser), `store`
@@ -63,87 +48,50 @@ Existing v1 packages: `sshconf` (read-only config parser), `store`
- `internal/keygen` — native key generation (crypto + `x/crypto/ssh`), key-file
writing with correct perms, and safe `~/.ssh/config` appends.
- `internal/xfer` — the transfer engine. A small `fs` abstraction lets push and
pull share one recursive copy routine; handles progress, conflict policy, and
resume. **Fully unit-tested against an in-memory SFTP server** (no sshd needed).
- `internal/sshx` — the connection layer. Resolves effective config via
`ssh -G <alias>`, builds the `ssh.ClientConfig` (agent + key auth, known_hosts
verification), and dials directly or through a ProxyJump chain.
- `internal/browser` — the dual-pane Bubble Tea file browser, using `xfer` for
transfers and coordinating the overwrite prompt across goroutines.
The picker's `t` key returns an `ActionSFTP` result; `main` then (re-)runs the
gate, connects via `sshx`, opens an `sftp.Client`, and runs the browser. The
default flow is now a loop: pick → connect (exec, ends) or sftp (returns to the
picker). Host *selection* stayed decoupled from the *action*, which is what let
SFTP reuse the picker cleanly.
Host *selection* stayed decoupled from the *action*, which keeps room to add new
per-host actions (e.g. the deferred SFTP browser) without disturbing the picker.
## Current state
- **Complete and green.** All packages build; `go vet` clean; unit tests pass
for `sshconf`, `store`, `yubikey`, `picker`, `keygen`, `xfer`, `sshx`.
for `sshconf`, `store`, `yubikey`, `picker`, `keygen`.
- **Cross-compiles** to all five targets (macOS arm64/amd64, Linux amd64/arm64,
Windows amd64). Binary grew from ~3.5 MB to ~6.1 MB — the cost of the
in-process SFTP stack (`x/crypto/ssh` + `pkg/sftp`), a deliberate trade chosen
over shelling out to the system `sftp`.
- **Live-verified via tmux** (against an in-memory SFTP server): dual-pane
render, navigation, batch selection, single-file push, recursive directory
push (contents verified on the far side), and the overwrite-conflict prompt
(goroutine↔UI coordination). keygen verified end-to-end (valid ed25519,
correct perms, config append with backup).
Windows amd64).
- **Live-verified via tmux**: keygen verified end-to-end (valid ed25519, correct
perms, config append with backup); picker navigation, sort cycling, tag
grouping, and favourites toggling all exercised.
## Known limitations / not yet exercised
- **The SFTP connection layer is now live-verified against a real sshd.**
Against a test host (key-based auth, no agent, unencrypted key loaded directly
from `IdentityFile`): `sshx.Connect` + SFTP listing, an SFTP write/read/remove
round-trip, and a full-TUI pull *and* push both passed with byte-for-byte
sha256 matches. An env-gated live test (`DIAL_LIVE_HOST=<host> go test
./internal/sshx -run TestLiveConnect`) is kept for re-running this. Still
unverified against a real host: **ProxyJump chaining** and **agent-backed /
encrypted-key auth** (the test host used a plain key file, no agent). (Same
hardware-untested posture remains for the YubiKey gate.)
- **ssh-agent on Windows** uses named pipes, not the `SSH_AUTH_SOCK` unix socket
the code dials; it compiles, but agent auth on Windows likely needs follow-up.
- **Encrypted key files** are skipped by the SFTP auth (it relies on the agent
for those) — dial never prompts for a key passphrase when connecting.
- **No mid-transfer cancel** — resume covers interruptions, but there's no
in-flight cancel key; a stuck transfer would need Ctrl-C out of the browser.
- **known_hosts is verify-only** — an unknown host errors out ("ssh to it once
first") rather than offering trust-on-first-use; no known_hosts management.
- **YubiKey gate is hardware-untested** — the challenge-response and recovery-code
logic have unit coverage, but the gate has not been exercised against a
physical YubiKey + `ykman` on real hardware.
- Still unsigned binaries (Gatekeeper/SmartScreen warnings); no CI/releases.
## Deferred (explicitly out of this pass)
Idle-timeout gate option; crash-persistent resume (surviving a dial restart);
distribution/signing/package managers; multi-select/batch actions *across hosts*
(distinct from the in-browser batch file selection, which shipped); per-host
notes; fuzzy search.
- **In-app SFTP file browser.** Planned for v2 (see `dial-v2-plan.md` §3) — a
dual-pane push/pull browser opened with `t`, built on an in-process SFTP stack
(`pkg/sftp` + `golang.org/x/crypto/ssh`). **Not built.** No `t` action, no
transfer/connection packages, and `pkg/sftp` is not a dependency. This is the
largest deferred item and would be the natural centrepiece of a v3.
- Idle-timeout gate option; distribution/signing/package managers; multi-select
actions across hosts; per-host notes; fuzzy search.
## Open questions & directions to brainstorm
1. **Real-host validation plan for SFTP** — what's the cheapest way to smoke-test
the connection layer (a throwaway VM? a container running sshd? a known host)?
2. **Windows agent support** — is Windows a real target for the SFTP browser, or
is it macOS/Linux-first? Determines whether named-pipe agent support is worth
building.
3. **Cancel & crash-persistent resume** — how often do transfers of very large
files over flaky links actually happen? That's the trigger for investing in
disk-persisted transfer state.
4. **known_hosts UX** — is verify-only acceptable, or should the browser offer to
record a new host key (with a clear prompt)?
5. **Grouping refinements** — should multi-tagged hosts optionally appear under
1. **SFTP browser — build it next?** It was the headline v2 plan but slipped.
Worth scoping as the v3 centrepiece, and if so, what's the cheapest way to
smoke-test the connection layer against a real sshd (a throwaway VM? a
container running sshd? a known host)?
2. **Grouping refinements** — should multi-tagged hosts optionally appear under
*every* tag? Should there be a per-tag filter shortcut or colour legend?
6. **Distribution** — Homebrew tap / Scoop / `install.sh` / signed releases via
3. **Distribution** — Homebrew tap / Scoop / `install.sh` / signed releases via
CI: worth doing now that the feature set is broad?
7. **SFTP polish** — a file preview? delete/rename/mkdir on either side? a "sync
this directory" one-shot? These edge toward a full file manager — where's the
line for a tool that's fundamentally a host picker?
## How to build / try
- Build: `make build` (native) or `make dist` (all platforms). Requires Go 1.23+.
- Build: `make build` (native) or `make dist` (all platforms). Requires Go 1.25+.
- Keys: `dial keygen` (no external deps).
- SFTP browser: `dial`, pick a host, press `t` (needs the host in known_hosts and
agent/key auth working — i.e. a host you can already `ssh` to).
- YubiKey gate: `dial yubikey enable` (requires Yubico's `ykman`).