e3202f345a
On the interactive commit path the active cursor position was never forwarded to the frame writer, so the cursor was never shown at the useCursor() position, never followed input, and a cursor-only move on a byte-identical frame emitted nothing. Aligns with Ink v7.0.4 by wiring three coupled defects together: - render.ts setCursorPosition now forwards to writer.setCursorPosition, marking log-update's cursorDirty (Ink ink.tsx:494-497). - the synchronized-update commit gate is split into Ink's two levels: the write is gated on willRender() || isCursorDirty(), but BSU/ESU wrap only when willRender() (Ink ink.tsx:1094 outer, :372-382 inner) -- an idle cursor-dirty re-render emits zero bytes, not an empty BSU/ESU pair. - FrameWriter.write() bypasses its frame===lastFrame dedup when the cursor is dirty, so a cursor-only move still reaches log-update's buildCursorOnlySequence. The mount-time hide-cursor write moves before originalMount so the first commit's show is the last visibility change (Ink hides before its first render); a synchronous mount throw now runs best-effort teardown (cursor/alt-screen restore) before rethrowing the ORIGINAL error, matching Ink's constructor-wired signalExit. Adds 8 interactive-TTY tests; the prior use-cursor tests used the debug render() helper where log-update never runs, so they passed for the wrong reason. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>