diff --git a/.release-please-manifest.json b/.release-please-manifest.json index f1c1e588..bcd05228 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.5.0" + ".": "0.6.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index f567b599..f9341b14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 ` 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 ` 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=` 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=` ([#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 .` 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 , 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-` (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 `-` 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//` to `/tmp/agent-tty-//`. 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 diff --git a/README.md b/README.md index f54981b0..b3a6c5bd 100644 --- a/README.md +++ b/README.md @@ -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. +`agent-tty` is `0.6.0` and focused on reliable, isolated, reviewable terminal and TUI automation through a stable CLI. - 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`. diff --git a/package.json b/package.json index b8903200..ceae6049 100644 --- a/package.json +++ b/package.json @@ -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": [