Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.5.0"
".": "0.6.0"
}
43 changes: 43 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,49 @@

## [Unreleased]

## [0.6.0] - 2026-11-05

### Added

- `agent-tty mouse` command, batch step, and `mouse-input` RPC capability: zero-based row/column clicks, drags, motion, wheel, and modifier state, encoded through `@coder/libghostty-vt-node` (now pinned at `0.1.0-beta.7`). Suppressed events still get a sequence number with `reported: false`; cells outside the grid fail `INVALID_INPUT`; renderers without the native encoder fail `CAPABILITY_UNAVAILABLE` (exit 12) ([#179](https://github.com/coder/agent-tty/pull/179) by @pmarreck, with mode-freshness and log-order fixes).
- `wait --scope cursor-line` (also on batch `wait` steps and the `waitForRender` RPC): match `--text`/`--regex` only against the row the cursor is on, so a post-command wait cannot be satisfied by the terminal's own echo. `--regex 'READY> $' --scope cursor-line` becomes a precise prompt wait ([#169](https://github.com/coder/agent-tty/pull/169)).
- `record diff <a> <b>` command: offline, replayed line-diff of two sessions' canonical visible screens, with `--at-seq-a`/`--at-seq-b` for intra-session diffs. `--json` returns `{ identical, a, b, diff }` with `equal|delete|add` ops; human mode prints a unified-style diff ([#170](https://github.com/coder/agent-tty/pull/170), [#300](https://github.com/coder/agent-tty/pull/300)).
- `screenshot --out <path>` writes the PNG to a chosen path (parallel to `record export --out`), with a shared `--out` resolver. Missing parent folders are created like `mkdir -p`, parents must be writable and searchable, and `--out` inside the Home's `sessions/` is refused. The in-session capture and its manifest entry are still published, and are rolled back if the `--out` copy fails ([#241](https://github.com/coder/agent-tty/pull/241), [#279](https://github.com/coder/agent-tty/pull/279), [#290](https://github.com/coder/agent-tty/pull/290), [#300](https://github.com/coder/agent-tty/pull/300)).
- `screenshot --json` reports `missingGlyphs` (per-cell codepoints that Chromium drew as `.notdef` boxes) and `missingGlyphsTruncated`; `record export --format webm --json` reports `missingGlyphs` (codepoint only) for glyphs drawn as boxes in any painted frame. The judge resolves which font face drew each probe by PostScript name, and the built-in font stack now bundles `Noto Sans Symbols 2` and `Noto Sans Math` WOFF2 subsets (OFL-1.1) to cover 4,761 additional symbol codepoints, kept behind `monospace` so host color-emoji fonts still win ([#240](https://github.com/coder/agent-tty/pull/240), [#278](https://github.com/coder/agent-tty/pull/278)).
- Spawned processes now see `AGENT_TTY_ACTIVE=true` and `AGENT_TTY_SESSION_ID=<id>` for session detection and self-identification. Session-less PTYs (the `doctor` probe) strip any inherited values ([#166](https://github.com/coder/agent-tty/pull/166) by @prmartinow, [#178](https://github.com/coder/agent-tty/pull/178)).
- Sessions now default `COLORTERM=truecolor`, and the host answers `XTGETTCAP` queries for `Tc`/`RGB`/`setrgbf`/`setrgbb` and declines `DECRQSS SGR` on the live PTY, so Neovim (including under `env -i`) turns `termguicolors` on and screenshots keep 24-bit highlights. Opt out with `--env COLORTERM=<value>` ([#231](https://github.com/coder/agent-tty/pull/231), [#271](https://github.com/coder/agent-tty/pull/271)).
- `snapshot`, `screenshot`, and render `wait` now return a valid blank result with `capturedAtSeq: -1` on a session that has printed nothing (previously failed with `RPC_ERROR`). `record export --format asciicast`/`webm` also accept an empty log at seq -1 (WebM produces a blank video) ([#235](https://github.com/coder/agent-tty/pull/235), [#270](https://github.com/coder/agent-tty/pull/270)).
- `snapshot --include-cells` now streams host responses up to 64 MiB, covering realistic 500×200 styled grids; a larger success is refused with `PROTOCOL_ERROR`. The live snapshot RPC timeout is raised to 60 s when cells are requested ([PR #320](https://github.com/coder/agent-tty/pull/320)).
- Advisory Node-version warning on startup: commands print `[agent-tty] warn: Node X is not supported. agent-tty requires <engines.node>.` when the running Node is outside the package `engines.node` range, and `doctor` now enforces the same range instead of a hard-coded `24+` ([#245](https://github.com/coder/agent-tty/pull/245)).

### Changed

- Standalone `wait` default `--timeout` is now **30 s** (was 600 s) and is shown in `--help`; `--timeout 0` keeps the "no limit" behavior. Batch `wait` steps default to the same 30 s ([#236](https://github.com/coder/agent-tty/pull/236), [#250](https://github.com/coder/agent-tty/pull/250)).
- Timed-out `wait` now returns `ok: false` with `error.code: "WAIT_TIMEOUT"` (exit 11) while still carrying the `result.timedOut: true` fields for existing readers; fail-fast `batch` under `--json` prints a parallel error envelope with the failed step's code and `details.stepIndex`. Without `--json`, the message now names the timeout: `Wait timed out after 30000 ms (the default; pass --timeout <ms>, or --timeout 0 to wait without a limit).` ([#232](https://github.com/coder/agent-tty/pull/232), [#273](https://github.com/coder/agent-tty/pull/273), [#301](https://github.com/coder/agent-tty/pull/301)).
- `wait` rejects `--idle-ms`/`--screen-stable-ms` windows that cannot finish inside the effective timeout with `INVALID_DURATION` (exit 2) before contacting the host; batch wait steps get the same check with `INVALID_INPUT` + `details.stepIndex` ([#277](https://github.com/coder/agent-tty/pull/277)).
- Every `--json` command now prints exactly one envelope. Unexpected errors become `INTERNAL_ERROR` on stdout (stack goes to debug logs); empty/path-like session IDs become `INVALID_SESSION_ID`; Commander usage errors become `INVALID_INPUT` under the command name `agent-tty`; `config.json` read and parse failures are typed (`STORAGE_READ_ERROR` / `INVALID_INPUT`); `help` exits 0. The CLI now exits as soon as stdio flushes after `INTERNAL_ERROR` instead of hanging on a leaked handle ([#237](https://github.com/coder/agent-tty/pull/237), [#287](https://github.com/coder/agent-tty/pull/287)).
- Session RPC sockets live under a per-uid root `/tmp/agent-tty-<uid>` (mode `0o700`, owner-checked). `inspect --json`'s `host.rpcSocketPath` moves accordingly; a one-release fallback keeps older hosts reachable. The empty per-Home socket directory is now removed after the last session and after a reconciled host crash ([#239](https://github.com/coder/agent-tty/pull/239), [#288](https://github.com/coder/agent-tty/pull/288)).
- WebM exports now play back at their recorded wall-clock pace instead of batching bursts of output into one frame at the next non-output event. Live `destroy` sent via Ctrl-C/SIGTERM to a copy that re-ran in a new session is now forwarded; the copy exits `128+signal` (`130`/`143`) ([#285](https://github.com/coder/agent-tty/pull/285), [#281](https://github.com/coder/agent-tty/pull/281)).
- Live command error envelopes now carry the host error's `details` over RPC (for example `details.path` / `details.errno` on `snapshot`/`screenshot` when the artifacts path is a file or a symlink loop). Max RPC request-id length is capped (128 chars) and shortened error messages no longer split surrogate pairs ([#313](https://github.com/coder/agent-tty/pull/313), [#315](https://github.com/coder/agent-tty/pull/315), [#319](https://github.com/coder/agent-tty/pull/319), [#322](https://github.com/coder/agent-tty/pull/322)).

### Fixed

- **Lifecycle**: a large set of create/reconcile/gc/destroy races that could lose a session, serve a session after a failed `create`, kill a destroyed session's leftover without recording it, or leak an unreachable host. Highlights: `create` races closed by writing the manifest with the host pid up front and serializing `session.json` writes ([#181](https://github.com/coder/agent-tty/pull/181)); idle/EPERM/in-session-destroy gaps closed with proper hang-up, group-waits, and a re-run-in-new-session for in-session `destroy` ([#216](https://github.com/coder/agent-tty/pull/216)); `destroy` typed into a shell job off Linux now matched by controlling terminal ([#246](https://github.com/coder/agent-tty/pull/246)); a failed `create` now stops its host and reports `details.sessionId` ([#247](https://github.com/coder/agent-tty/pull/247), [#294](https://github.com/coder/agent-tty/pull/294)); the host record is written at create time and only trusted after a start-up record ([#260](https://github.com/coder/agent-tty/pull/260), [#303](https://github.com/coder/agent-tty/pull/303)); `gc` now keeps a session whose program group still runs (frozen double-judge via SIGSTOP/SIGCONT, zombie chains handled) and only removes a session when it can prove the group gone or out-of-view ([#302](https://github.com/coder/agent-tty/pull/302), [#326](https://github.com/coder/agent-tty/pull/326), [#312](https://github.com/coder/agent-tty/pull/312)); `destroy --force` ends a session whose program group it cannot read ([#327](https://github.com/coder/agent-tty/pull/327)) or cannot see in `/proc` ([#334](https://github.com/coder/agent-tty/pull/334)); Windows late-host and marker-write races closed ([#324](https://github.com/coder/agent-tty/pull/324)); plus [#178](https://github.com/coder/agent-tty/pull/178), [#194](https://github.com/coder/agent-tty/pull/194), [#201](https://github.com/coder/agent-tty/pull/201), [#221](https://github.com/coder/agent-tty/pull/221), [#233](https://github.com/coder/agent-tty/pull/233), [#256](https://github.com/coder/agent-tty/pull/256), [#259](https://github.com/coder/agent-tty/pull/259), [#274](https://github.com/coder/agent-tty/pull/274), [#275](https://github.com/coder/agent-tty/pull/275), [#276](https://github.com/coder/agent-tty/pull/276), [#283](https://github.com/coder/agent-tty/pull/283), [#284](https://github.com/coder/agent-tty/pull/284), [#291](https://github.com/coder/agent-tty/pull/291), [#305](https://github.com/coder/agent-tty/pull/305), [#330](https://github.com/coder/agent-tty/pull/330), [#331](https://github.com/coder/agent-tty/pull/331), [#333](https://github.com/coder/agent-tty/pull/333).
- **Storage / artifacts**: the artifact manifest is now cross-process locked, so concurrent captures from the host and CLI processes keep every entry ([#282](https://github.com/coder/agent-tty/pull/282), [#299](https://github.com/coder/agent-tty/pull/299)). Repeat `screenshot`/`snapshot` at the same seq publish via `link` (or `copyFile` with `COPYFILE_EXCL`) and never overwrite an earlier capture's file, falling back to `<name>-<n>` when bytes differ ([#191](https://github.com/coder/agent-tty/pull/191)). `record export` keeps a valid manifest entry when the written file's size still matches, preserving the entry under mtime changes from SMB/Windows servers ([#316](https://github.com/coder/agent-tty/pull/316)). `writeManifest` no longer resurrects a `gc`-removed session folder ([#200](https://github.com/coder/agent-tty/pull/200)), artifact writes and `gc`'s `rm` keep a removed folder removed ([#212](https://github.com/coder/agent-tty/pull/212)), a Home resolves the same way behind a symlink before and after it exists ([#210](https://github.com/coder/agent-tty/pull/210)), and the APFS `EINVAL` from writes into a folder being removed now maps to `SESSION_NOT_FOUND` ([#318](https://github.com/coder/agent-tty/pull/318), [#321](https://github.com/coder/agent-tty/pull/321)). One invalid Home Registry entry no longer causes all other Homes to be lost on the next `create` ([#186](https://github.com/coder/agent-tty/pull/186)).
- **Rendering / mouse**: `--show-cursor` and `--hide-cursor` now produce different PNGs; the canvas is forced to redraw when the cursor toggles ([#289](https://github.com/coder/agent-tty/pull/289)). Same-cell mouse motion stays deduplicated after child-program output and across renderer swaps; mouse input now has its own renderer manager so a `ghostty-web` snapshot no longer loses the libghostty-vt encoder state ([#234](https://github.com/coder/agent-tty/pull/234), [#293](https://github.com/coder/agent-tty/pull/293)).
- **Wait**: a render wait whose polls all fail now stops with the renderer's error (for example `RPC_ERROR`) instead of reporting `WAIT_TIMEOUT`, so `WAIT_TIMEOUT` only means the timeout actually elapsed; batch wait-step timeout messages now name the timeout ([#301](https://github.com/coder/agent-tty/pull/301)).
- **CLI**: `--out` rejects a `0200` (write but no search) parent folder before writing, re-checks the parent just before the rename, and uses a temp-file+rename for WebM so a symlinked `--out` path is replaced (never written through) ([#279](https://github.com/coder/agent-tty/pull/279)). A failed `screenshot --out` copy now rolls back the in-session capture and its manifest entry ([#300](https://github.com/coder/agent-tty/pull/300)). `inspect`/`snapshot`/`screenshot` artifact-path check now reports a non-folder with `STORAGE_WRITE_ERROR` instead of a renderer invariant ([#287](https://github.com/coder/agent-tty/pull/287)); internal errors carry useful `cause` and `details.errno` ([#301](https://github.com/coder/agent-tty/pull/301)); the host stays running when an RPC error response cannot be built ([#315](https://github.com/coder/agent-tty/pull/315)); waited-run input is logged in PTY order ([#234](https://github.com/coder/agent-tty/pull/234)).

### Breaking Changes

- `wait` without `--timeout` now stops at **30 s** (was 600 s); `--idle-ms`/`--screen-stable-ms` windows that cannot fit in the effective timeout are rejected up front with `INVALID_DURATION` ([#236](https://github.com/coder/agent-tty/pull/236), [#277](https://github.com/coder/agent-tty/pull/277)). Batch `wait` steps default to the same 30 s ([#250](https://github.com/coder/agent-tty/pull/250)).
- A timed-out `wait`, and a fail-fast `batch` with a failed step, now emit `ok: false` with `error.code` set (exit code unchanged). Automation that branches on `.ok` will need to read `.result.timedOut`/`.result.steps` under `error` as well ([#232](https://github.com/coder/agent-tty/pull/232)).
- Session RPC sockets move from `/tmp/agent-tty/<hash>/<id>` to `/tmp/agent-tty-<uid>/<hash>/<id>`. A fallback still reaches older 0.5.0 hosts for one minor release; a CLI running under a different uid (for example `sudo agent-tty`) can no longer reach a host started by your own uid ([#288](https://github.com/coder/agent-tty/pull/288)).
- `capturedAtSeq` can now be `-1` for captures on a silent session; render-wait `--after-seq` accepts `-1`. Readers that require `capturedAtSeq >= 0` need to accept `-1` ([#235](https://github.com/coder/agent-tty/pull/235), [#270](https://github.com/coder/agent-tty/pull/270)).
- `@coder/libghostty-vt-node` is pinned to `0.1.0-beta.7` (needs AVX2 on `linux-x64`; no longer requires AVX-512). Native snapshots inherit Ghostty 1.4.0 upstream behavior ([#179](https://github.com/coder/agent-tty/pull/179), [#293](https://github.com/coder/agent-tty/pull/293)).

**Full Changelog**: https://github.com/coder/agent-tty/compare/v0.5.0...main

## [0.5.0] - 2026-06-23

### Added
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ See [`docs/AGENT-SKILLS.md`](./docs/AGENT-SKILLS.md).

## Status & platform support

`agent-tty` is `0.5.0` and focused on reliable, isolated, reviewable terminal and TUI automation through a stable CLI. <!-- x-release-please-version -->
`agent-tty` is `0.6.0` and focused on reliable, isolated, reviewable terminal and TUI automation through a stable CLI. <!-- x-release-please-version -->

- Linux and macOS are tier-1; Windows is tier-2 and not CI-tested.
- Semantic snapshots and render-backed waits prefer the optional `libghostty-vt` backend when it is available, then fall back to `ghostty-web`.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "agent-tty",
"version": "0.5.0",
"version": "0.6.0",
"description": "Terminal automation CLI for AI agents and humans",
"license": "Apache-2.0",
"keywords": [
Expand Down
Loading