Releases: subinium/ezpn
v0.13.1
v0.13.0
v0.12.0
What's Changed
- chore(release): v0.12.0 — multiplexer foundations + terminal protocol modernisation by @subinium in #100
Full Changelog: v0.11.1...v0.12.0
v0.11.1
What's Changed
Full Changelog: v0.11.0...v0.11.1
v0.11.0 — Automation, UX & parity foundations
v0.10.0 — Daemon stability & perf hygiene
What's Changed
🚀 Features
- feat(daemon): hooks system — shell-out worker pool + 5 wired events (#53) by @subinium
- feat(daemon): event subscription stream — c_subscribe + s_event bus (#52) by @subinium
- feat(daemon): send-keys api — keyspec parser + ipc + ezpn-ctl (#51) by @subinium
- feat(daemon): per-pane scrollback caps + clear-history ipc (#47) by @subinium
⚡ Performance
- perf(daemon): bounded wake_rx + vt100-cached paste + vecdeque tabs (#50) by @subinium
- perf(daemon): async snapshot worker — debounced off-main writes (#49) by @subinium
- perf(daemon): I/O resilience — slow-client backpressure + IPC thread pool (#46) by @subinium
🧹 Refactor
📚 Docs
Full Changelog: v0.9.0...v0.10.0
v0.9.0 — Codebase & Release Hygiene
Final milestone of the 0.6 → 0.9 series. v0.6 made the daemon impossible to crash; v0.7 made it feel native; v0.8 made workflows stick; v0.9 makes the codebase reviewable and the release pipeline opinionated.
Highlights
Module decomposition
src/main.rs: 2951 → 144 lines. Split intocli/,app/{state,bootstrap,lifecycle,attach,render_ctl,input_dispatch,event_loop}.rs,direct.rs.src/server.rs: 2700+ → 16 lines. Split intodaemon/{state,router,snapshot,render,dispatch,keys,event_loop}.rs.- ZERO behavior change. 105 unit + 3 integration + 8 property + 4 daemon-lifecycle tests pass. Bench within ±2% of baseline.
- 18
.clone()call sites annotated with[perf:cold]/[perf:init]/[perf:hot]classifications. 3TODO(perf)flags for follow-upArc<…>conversion.
Test pyramid
- 8 property tests (proptest 1.x, 128 cases each) for layout invariants and snapshot round-trips.
- 5 new integration recordings (3 active; 2
#[ignore]d pending harness work). benches/soak_10min.rsopt-in via--features soak.scripts/coverage.shenforcing 65% floor viacargo-llvm-cov.
Convention enforcement
commitlintvalidates PR titles + every commit. Type enum:feat fix perf refactor chore docs test ci style release.branch-namingenforces<type>/<slug>.actions/labeler@v5auto-appliesarea:*labels by path.release-drafteraggregates merged PRs into a draft release note grouped by type.
Repo hygiene
gitleakson every push and PR (full-history + custom Cargo-token / PEM rules).- Weekly
cargo audit+ per-PRcargo deny check --all-features(advisories, license allowlist, banned wildcards, unknown sources). - CHANGELOG enforcement: PRs touching
src/**orCargo.tomlmust updateCHANGELOG.md. - README badges for gitleaks + audit added.
Compatibility
- Wire protocol: unchanged (still v1).
- Snapshot schema: unchanged (still v3).
- New deps: `proptest 1` (dev-only). No new runtime deps.
Install
```bash
cargo install ezpn --version 0.9.0
```
Or grab the prebuilt binary for your platform from the assets below (auto-built by the Release workflow).
Full changelog: CHANGELOG.md
v0.7.0 — Native Feel & Perf
ezpn 0.7.0 — Native Feel & Perf
Second milestone of the 0.6 → 0.9 series. v0.6.0 made the daemon impossible to crash from a single bad pane; this release makes it feel native — sub-50ms attach, zero-allocation render path, RFC-3665 keyboard encoding, geometry guards that prevent unusable splits.
Highlights
Sub-50ms attach via parent-pipe ready signal
Cold attach used to wake every 50 ms to probe whether the daemon's socket existed. Now:
- Parent creates a
pipe(2)and hands the daemon the write fd viaEZPN_READY_FD. - Daemon writes one byte right after
UnixListener::bindsucceeds and closes the fd. - Parent
poll(2)s for that byte. Wake within microseconds of bind, not 50 ms quanta. - Legacy 50 ms fallback retained for sandboxed environments where pipe creation fails.
Zero-allocation render clear path
clear_rect and clear_title previously allocated " ".repeat(rect.w) per row per call — the dominant heap traffic during resize / scroll bursts. Now they borrow from a shared BLANK_ROW_BUF: OnceLock<String> sized at 1024 cols (any sane terminal). Cow::Owned fallback covers the pathological case for terminals wider than 1024 cells.
Alt+Char now uses CSI u (RFC 3665)
Alt+Arrow and Alt+function-key already emitted \x1b[<code>;<mods>u; only Alt+Char still used the legacy \x1b<char> form. The mismatch confused shells that bind on the modern form (zsh, bash with bind, vim, helix) — Alt+a worked but Alt+Right matched a different binding, or vice versa. Now everything is consistent. Set EZPN_ALT_LEGACY=1 in your parent shell if you need the pre-0.7 ESC-prefix behavior for a legacy binding.
Geometry guards: no more 1-cell panes
Layout::split_area could produce a 1-cell child at extreme ratios. Now it clamps both children to MIN_PANE_W = 3 / MIN_PANE_H = 2 whenever the area can afford it. New can_split(area, dir) -> bool helper for callers to pre-check before invoking a split; status-bar rejection message lands in a follow-up.
Display-width-correct copy mode search
/search highlight was using byte length as visual width. "🔍" highlighted 4 cells instead of 2; "café" highlighted 5 instead of 4. Now uses UnicodeWidthStr::width over the matched substring — emoji, combining marks, and CJK all render correctly.
Compatibility
- Wire protocol: unchanged (still v1, no
PROTOCOL_VERSIONbump). - Snapshot schema: unchanged (still v2). Scrollback persistence with v3 schema lands in v0.8.0.
- Dependencies: no new production deps.
Install
cargo install ezpn --version 0.7.0Full changelog: CHANGELOG.md
v0.6.0 — Stability & Safety Net
ezpn 0.6.0 — Stability & Safety Net
The first milestone of the v0.6 → v0.9 series focuses on making the daemon impossible to crash from a single bad pane, bounding memory growth from runaway clipboard or shell output, and giving the wire protocol a real version handshake so future upgrades can refuse incompatible clients up-front instead of silently corrupting sessions.
Highlights
Daemon survives any single-pane panic
PTY readers (pane.rs), client readers (server.rs), IPC accept loops, and per-client handlers (ipc.rs) are now wrapped with std::panic::catch_unwind. A bad ANSI sequence or a malformed IPC message kills only the affected pane / client — the daemon and other panes keep running. Panes that died abnormally are marked with exit_code = u32::MAX so callers can distinguish "shell exited cleanly" from "we lost the reader thread".
OSC 52 clipboard queue is bounded
Pane::osc52_pending was an unbounded Vec<Vec<u8>> — a malicious or buggy child could exhaust memory by streaming clipboard sequences. Now capped at 16 entries / 256 KiB total / 128 KiB single-sequence; oldest entries are dropped FIFO when either cap is reached.
Wire-protocol versioning + handshake
New optional first message C_HELLO { version, capabilities, client }. The daemon replies S_HELLO_OK on a matching major (with intersection of supported capabilities) or S_HELLO_ERR with a clear "please upgrade" message on mismatch. Capability bits cover kitty keyboard, focus events, true color, and a reserved bit for v0.8 scrollback persistence. Fully backwards compatible — older clients that don't send C_HELLO keep working.
POSIX signal handling
SIGTERM/SIGHUP→ snapshot the workspace, kill children, sendS_EXITto attached clients, clean up sockets, and exit cleanly.SIGCHLD→ reap exited children non-blocking viachild.try_wait(); no more zombie panes accumulating in long-lived sessions.
First end-to-end integration tests
tests/daemon_lifecycle.rs spawns the real ezpn --server binary, talks to it over a Unix socket, and asserts:
C_PING→S_PONGround-trip.C_HELLO v=1succeeds with negotiated caps0x07.C_HELLO v=999is rejected with a clear mismatch reason.SIGTERMtriggers graceful shutdown within 3s and the socket file is cleaned up.
Other changes
- Repo conventions (CONTRIBUTING.md, MAINTENANCE.md, PR/issue templates, label taxonomy, hardened .gitignore).
- Pinned
rust-toolchain.tomlto1.95.0socargo fmt --checkis deterministic across hosts. - Resolved 10 pre-existing clippy
collapsible_matchwarnings that broke CI on Rust 1.95.
Compatibility
- Wire protocol: additive only. v0.5 clients (no
C_HELLO) still attach to v0.6 daemons unchanged. - Snapshot schema: unchanged (still v2). Scrollback persistence with v3 schema lands in v0.8.0.
- Dependencies: adds
signal-hook = "0.3"(production),tempfile = "3"(dev).
Install
cargo install ezpn --version 0.6.0Full changelog: CHANGELOG.md
v0.5.0
What's Changed
Full Changelog: v0.4.2...v0.5.0