Skip to content

Releases: subinium/ezpn

v0.13.1

28 Apr 17:03
e3f678e

Choose a tag to compare

What's Changed

  • chore: release v0.13.1 — clippy gate + 6 RFCs + cwd inheritance (#109) by @subinium

Full Changelog: v0.13.0...v0.13.1

v0.13.0

28 Apr 15:23
0d0bd80

Choose a tag to compare

What's Changed

  • ci(bench): skip regression detect on push to main by @subinium in #101
  • feat: v0.13.0 — multiplexer wiring + memory & persistence foundations by @subinium in #108

Full Changelog: v0.12.0...v0.13.0

v0.12.0

28 Apr 09:33

Choose a tag to compare

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

26 Apr 07:58
17c93a8

Choose a tag to compare

What's Changed

  • fix: v0.11.1 — security & correctness hotfixes (B1-B3, C1-C7) (#55) by @subinium

Full Changelog: v0.11.0...v0.11.1

v0.11.0 — Automation, UX & parity foundations

26 Apr 06:51

Choose a tag to compare

What's Changed

🚀 Features

  • feat: v0.11 batch foundations — vocab/nucleo/layout/regex (#54) by @subinium

Full Changelog: v0.10.0...v0.11.0

v0.10.0 — Daemon stability & perf hygiene

26 Apr 06:23

Choose a tag to compare

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

  • fix(daemon): pane lifecycle GC — drop joins reader, close prunes maps (#48) by @subinium

📚 Docs

  • docs: v0.10.0 roadmap — PRD + 13 SPECs (#32) by @subinium

Full Changelog: v0.9.0...v0.10.0

v0.9.0 — Codebase & Release Hygiene

26 Apr 01:11
2cabaa5

Choose a tag to compare

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 into cli/, app/{state,bootstrap,lifecycle,attach,render_ctl,input_dispatch,event_loop}.rs, direct.rs.
  • src/server.rs: 2700+ → 16 lines. Split into daemon/{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. 3 TODO(perf) flags for follow-up Arc<…> 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.rs opt-in via --features soak.
  • scripts/coverage.sh enforcing 65% floor via cargo-llvm-cov.

Convention enforcement

  • commitlint validates PR titles + every commit. Type enum: feat fix perf refactor chore docs test ci style release.
  • branch-naming enforces <type>/<slug>.
  • actions/labeler@v5 auto-applies area:* labels by path.
  • release-drafter aggregates merged PRs into a draft release note grouped by type.

Repo hygiene

  • gitleaks on every push and PR (full-history + custom Cargo-token / PEM rules).
  • Weekly cargo audit + per-PR cargo deny check --all-features (advisories, license allowlist, banned wildcards, unknown sources).
  • CHANGELOG enforcement: PRs touching src/** or Cargo.toml must update CHANGELOG.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

25 Apr 23:25
b5faad2

Choose a tag to compare

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 via EZPN_READY_FD.
  • Daemon writes one byte right after UnixListener::bind succeeds 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_VERSION bump).
  • 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.0

Full changelog: CHANGELOG.md

v0.6.0 — Stability & Safety Net

25 Apr 23:13
57ac8f9

Choose a tag to compare

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, send S_EXIT to attached clients, clean up sockets, and exit cleanly.
  • SIGCHLD → reap exited children non-blocking via child.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_PINGS_PONG round-trip.
  • C_HELLO v=1 succeeds with negotiated caps 0x07.
  • C_HELLO v=999 is rejected with a clear mismatch reason.
  • SIGTERM triggers 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.toml to 1.95.0 so cargo fmt --check is deterministic across hosts.
  • Resolved 10 pre-existing clippy collapsible_match warnings 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.0

Full changelog: CHANGELOG.md

v0.5.0

28 Mar 09:21
9579656

Choose a tag to compare

What's Changed

  • feat: v0.5.0 — multi-client, full-session snapshots, settings overhaul by @subinium in #7

Full Changelog: v0.4.2...v0.5.0