Codex (Ratatui) emits an 8x RI burst on startup right after setting DECSTBM. RI at the top of the scroll region scrolls the region down, and DECSTBM only constrains rows -- so the scroll spans every column and drags the right-rail session-tree entries down with the main pane. The chrome cache then hid the clobber because the computed sidebar frame was unchanged. The viewport renderer now flags any chunk containing RI / IND / NEL / SU / SD / IL / DL and OnPTYOut drops the sidebar cache when the flag is set, so the next drawSidebar repaints over the drift. Adds unit tests for the new flag and a harness regression scenario (sidebar_survives_ri_scroll) that fails without the fix.
111 lines
6.0 KiB
Markdown
111 lines
6.0 KiB
Markdown
# Changelog
|
||
|
||
All notable changes to patterm are tracked in this file. Format follows
|
||
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project
|
||
loosely follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||
|
||
## [Unreleased]
|
||
|
||
### Added
|
||
- Ctrl+A / Ctrl+D step focus between top-level tabs; Ctrl+W / Ctrl+S
|
||
step through processes (root + sub-agents) inside the current tab.
|
||
Recognised in legacy, kitty CSI u, and xterm modifyOtherKeys
|
||
encodings. The chord shadows the corresponding raw byte for the
|
||
focused pane — pressing Ctrl+D no longer sends EOF to the
|
||
underlying shell, for instance.
|
||
- MCP protocol layer (`internal/mcp/protocol.go`) implementing
|
||
`initialize`, `tools/list`, `tools/call`, `ping`, and MCP
|
||
notifications. Tool catalog with input schemas is advertised via
|
||
`tools/list`. Real MCP clients (claude, etc.) can now complete the
|
||
handshake against patterm's per-PID socket. Legacy direct-tool
|
||
dispatch is preserved so the harness keeps working unchanged.
|
||
- `mcp_injection.kind = "cli_override"` for agents that accept inline
|
||
`key=value` config overrides on the command line. The default codex
|
||
preset uses it to emit `-c mcp_servers.patterm.command=…` and
|
||
`-c mcp_servers.patterm.args=[…]` — zero files written, no
|
||
`CODEX_HOME` override.
|
||
- `mcp_injection.kind = "config_env"` for agents that read their
|
||
config from an env var. The default opencode preset uses it to pass
|
||
a merged `opencode.json` inline through `OPENCODE_CONFIG_CONTENT`,
|
||
so auth/agents/tui.json/skills resolve from the user's real `$HOME`
|
||
with no XDG override.
|
||
- Palette macros: typing `sw `, `k `, or `sp ` filters the list to
|
||
switch / kill / spawn entries respectively. Footer shows the
|
||
available macros.
|
||
|
||
### Changed
|
||
- Palette ordering: open agents/processes (`Switch to …`) now appear
|
||
above the option to spawn new ones, with kill entries pushed down
|
||
toward the end of the list.
|
||
- Tab bar trimmed from three rows (label / subtitle / underline) to
|
||
two (label / underline). Tabs flex to fill the available host width
|
||
evenly with leftover columns distributed to the leftmost tabs; the
|
||
`+ new` hint sits in a reserved slot on the right. Layout's
|
||
`mainTop` consequently drops from 4 to 3, giving each pane one
|
||
extra row of viewport.
|
||
|
||
### Fixed
|
||
- Child processes spawned by an orchestrator are now killed when the
|
||
orchestrator dies, recursively through the tree. Applies whether the
|
||
parent was closed via MCP, Ctrl-C'd by the user, or exited on its
|
||
own — `reapChild` cascades a SIGTERM (escalating to SIGKILL after 2s)
|
||
to every direct child, and each descendant's own reap fires the same
|
||
cascade so the kill flows through arbitrary depth.
|
||
- Killed agents no longer linger in the command palette. Agent
|
||
entries that aren't running are filtered out of the switch list;
|
||
session-persistent commands (which can be restarted) stay visible.
|
||
- `tools/list` now emits a concrete `properties` object (`{}`) for
|
||
parameterless tools instead of `null`. Claude rejected the
|
||
`null`-properties form with "tools fetch failed" even though the
|
||
initialize handshake had succeeded.
|
||
- Sidebar no longer flickers on every PTY chunk. The tab bar,
|
||
sidebar, and status line now cache their last rendered byte string
|
||
and skip the write when the new frame matches; full repaint paths
|
||
(resize / focus change / palette close / screen clear) invalidate
|
||
the cache so the next draw fires unconditionally.
|
||
- Spawning a child agent now clears the viewport area before it
|
||
paints, so the previous focused child's PTY output no longer bleeds
|
||
through underneath the new pane.
|
||
- Orchestrator-injected input (initial agent prompts, MCP
|
||
`send_input` with `submit: true`, `send_message`, `timer_wait`
|
||
callbacks) now ends with CR (`\r`) instead of LF (`\n`). Claude
|
||
treated `\n` as "newline in textarea"; with CR the prompt actually
|
||
submits, matching what the host terminal sends when a user presses
|
||
Enter directly.
|
||
- Enter is now written to a child PTY as its own `write()` call,
|
||
separated from the preceding text by a short delay. Both
|
||
`InjectAsUser` (user typing forwarded through patterm) and
|
||
`InjectAsOrchestrator` (MCP / send_message / initial-prompt paths)
|
||
share the split. Without it, claude — and other paste-detecting
|
||
TUIs — coalesced `"hello\r"` into one read and inserted the CR as
|
||
literal text instead of treating it as the Enter keystroke.
|
||
- Sidebar (and tab bar) no longer get wiped when the focused child
|
||
issues `CSI 0 J` / `CSI 1 J` (clear-to-cursor). The viewport renderer
|
||
already clamped `CSI 2 J` and `CSI K` to viewport columns, but the
|
||
partial-screen variants were forwarded verbatim, so any tool-call
|
||
expansion in claude (Ctrl+O) would erase every cell to the right of
|
||
the cursor — including the right rail. Both forms are now translated
|
||
into per-row ECH sequences that stop at the viewport's right edge.
|
||
- Sidebar left border no longer vanishes when the viewport repaints.
|
||
The border column was the same column as the viewport's rightmost
|
||
cell, so any child write to that column (or `clearViewport`'s ECH)
|
||
would erase it. The viewport is now one column narrower so the
|
||
border has a dedicated column.
|
||
- Sidebar session-tree entries no longer get pushed downward when an
|
||
agent emits a scroll burst on startup. Codex (Ratatui) issues 8× RI
|
||
(`\x1bM`) right after setting its scroll region, which scrolls the
|
||
region down across every column — dragging the right-rail entries
|
||
with it. The chrome cache then hid the clobber because the computed
|
||
frame still matched. The viewport renderer now flags any chunk that
|
||
contains a scroll-triggering escape (RI / IND / NEL / SU / SD / IL /
|
||
DL) and `OnPTYOut` drops the sidebar cache when the flag is set, so
|
||
the next `drawSidebar` repaints over the drift.
|
||
|
||
## Conventions
|
||
|
||
- This file is the single record of user-visible changes; the TODO is
|
||
scratch space, not history.
|
||
- One bullet per change, written in the past tense from the user's
|
||
point of view. Reference the package or preset name when it helps a
|
||
reader find the code.
|