rust-pty 0.5.0

Cross-platform async PTY (pseudo-terminal) library for Rust
Documentation
# Changelog

All notable changes to `rust-pty` will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

Changes before 0.5.0 predate this file; see the git history.

## [Unreleased]

## [0.5.0] - 2026-07-08

Hardens the Unix spawn and PTY I/O paths and adds reliable final-output capture
on macOS and Windows. Released together with the rest of the workspace.

### Changed

- **Unix spawn runs the child via `tokio::process`.** The only work between
  `fork()` and `exec` is async-signal-safe (`setsid` + `TIOCSCTTY`), so spawning
  is sound under a multi-threaded Tokio runtime. `try_wait` now reaps through the
  tokio child rather than a raw `waitpid`, so exit status and reaping stay
  consistent.

### Fixed

- **Default Unix spawn no longer fails with `EPERM`.** The child no longer calls
  `setsid` after `process_group(0)` had already created a new session — the
  redundant `setsid` returned `EPERM` and broke the default spawn path.
- **The PTY master is opened close-on-exec.** Atomic on Linux (`openpt` with
  `CLOEXEC`); on macOS/BSD, whose `posix_openpt` has no atomic `O_CLOEXEC`, a
  follow-up `fcntl` sets it (a small open→`fcntl` window remains). Prevents the
  master leaking into an unrelated concurrently-spawned child.
- **Retry PTY allocation on transient exhaustion.** macOS caps system-wide PTYs
  at `kern.tty.ptmx_max`, so allocation can transiently fail under heavy
  concurrent spawning; allocation now retries with a short bounded backoff and
  surfaces the underlying OS error on genuine failure.
- **Retry `poll_read`/`poll_write` on `EINTR`** rather than surfacing a spurious
  error when a signal interrupts the syscall before any bytes move.
- **macOS: open the slave before setting the initial window size**, so the
  `TIOCSWINSZ` applied at allocation takes effect.
- **Harden child stdio setup** with checked `dup` and close-on-exec on the slave
  handle used only for the `pre_exec` `TIOCSCTTY`.
- **Windows: recover a fast-exiting child's final output.** The ConPTY read path
  stopped as soon as the `open` flag was cleared on child exit, discarding bytes
  already written to the output pipe. Reads now drain the pipe until `ReadFile`
  reports `ERROR_BROKEN_PIPE`.
- **macOS: capture a fast-exiting child's final PTY output.** macOS discards the
  master's still-buffered bytes when the last slave fd closes around child exit.
  A dedicated drain thread, started before the child spawns, reads the master
  into a userspace buffer the instant bytes arrive, so the output survives
  teardown.