The first ping after `herdr update --handoff` was sent exactly once. A
server still binding its socket turned into "更新/热切换未完成" even
though the update had succeeded. Retry connection errors for up to 20
seconds before giving up; a healthy server still answers immediately.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The update popup kept the last 64 KiB of raw bytes and decoded the
whole buffer on every refresh. Cutting the buffer, or reading a chunk
that ended inside a multi-byte sequence, made the UTF-8 decode fail and
sent everything through the GB18030 fallback, garbling the display.
Clip the retained tail at a UTF-8 boundary and decode still-growing
streams with an incremental decoder that holds back an incomplete
trailing sequence instead of treating it as corruption.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- Display names starting with '-' were parsed by tmux rename-window as
flags. The alias was persisted before tmux rejected it, so every later
start/refresh/open failed in refresh_labels until aliases.json was
edited by hand. Guard rename-window with '--', apply the name before
persisting it, and roll back the in-memory table on failure.
- Start the Hub tmux server with -f /dev/null by default. Reading the
user's ~/.tmux.conf let theme status-formats replace the Sessions bar
and root-table bindings leak into Herdr; HERDR_HUB_TMUX_CONFIG still
opts into a custom file.
- An unreadable aliases.json blocked start/refresh/open/choose. Degrade
to default names with a warning (stderr, or the popup message) and
leave the file untouched for `doctor` to report.
- `doctor` crashed with a traceback when a *_BIN override pointed at a
missing executable; report it as a failure instead.
- Refuse to run inside another tmux server before discovery and server
creation, so no unattached Hub is left behind.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Opening a window whose target was removed from the registry (its tab
stays open by design) and failing landed in the action menu with a
"重试连接" row that indexed self.entries directly and raised KeyError,
killing the popup with a traceback.
Only offer the retry action for registered targets, degrade a stale
retry row to a message, and keep the popup alive when a handler raises
anything unexpected instead of dying with a traceback.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The Ctrl+A h command menu gains two host-scoped actions: a plain
`herdr update` that streams updater output into the popup, and an
experimental update-and-hot-restart flow that verifies a live server
handoff and reconnects the originating Hub tab once the popup closes.
Remote updates use the remote host's own proxy settings. A standalone
helper reads literal proxy assignments from shell profiles and running
Clash/Mihomo listeners without executing startup files; Windows reads
process, user and machine proxy variables through PowerShell.