Commit Graph

1335 Commits

Author SHA1 Message Date
can1357 246d7dd0ab chore: bump version to 15.10.3 2026-06-08 06:52:49 +02:00
can1357 573fb8a9a6 chore: reformat 2026-06-08 06:20:52 +02:00
can1357 a37e6c26ca Merge remote-tracking branch 'origin/farm/b7f4bc6d/fix-tmux-resize-viewport-flash' 2026-06-08 06:20:09 +02:00
roboomp 9ec17f51a9 fix(tui): routed forced renders through the multiplexer resize debounce
The earlier guard only suppressed throttled `requestRender(false)`; forced repaints (e.g. `#finishSixelProbe`, image-budget eviction, `resetDisplay`) bypassed it through `requestRender(true)` or the direct `#doRender` path and could still paint into a still-reflowing pane inside the 50 ms settle window — recreating the flash race.

Extracted `#armMultiplexerResizeTimer(clearScrollback)` as the single arm-or-extend point used by the SIGWINCH callback, the deferral branch in `requestRender(true)`, and `resetDisplay()`. Each call cancels any queued throttled render, ORs the callers `clearScrollback` intent into `#deferredForcedClearScrollback`, and re-arms the timer. When the timer fires it consumes the flag and re-enters `requestRender(true, { clearScrollback })`; clearing `#multiplexerResizeTimer` before re-entry lets the deferred call pass straight to `#prepareForcedRender`. `stop()` clears the flag.

Added regression tests for forced `requestRender(true)` and `resetDisplay()` landing inside the debounce window.
2026-06-08 04:04:34 +00:00
roboomp a31f088ffc fix(tui): superseded queued renders during multiplexer resize debounce
A streamed-token tick that landed `requestRender(false)` in the same 30fps frame as the SIGWINCH left `#renderTimer` armed, so the throttled render could fire inside the 50 ms settle window and paint at the new geometry while tmux was still reflowing — the same race the debounce is meant to avoid. The immediate-force path used to clear that timer through `#prepareForcedRender`; the debounce path now does the same when arming, and `#scheduleRender` short-circuits while the multiplexer timer is active so any follow-on `requestRender(false)` is held off until the eventual forced render. Added a regression test covering a queued render + SIGWINCH in the same frame.
2026-06-08 03:57:22 +00:00
can1357 bd079eef6a feat(coding-agent/modes): enabled mouse-hover highlighting for plan review options
- Handled SGR mouse motion reports in `PlanReviewOverlay` to set hovered options from hit-test rows and clear highlights outside option rows.
- Updated option rendering to paint a background band on hovered, non-disabled options while preserving keyboard selection behavior.
- Enabled any-motion mouse tracking for overlays and expanded regression coverage to verify hover tracking setup and teardown.
2026-06-08 05:53:33 +02:00
roboomp 227aaef984 fix(tui): coalesced multiplexer resize events into one settled render
Tmux/screen/zellij send SIGWINCH while the pane is still mid-reflow and fire several events during drag-resize or pane-close animations. Forcing an immediate render on each event raced those mid-reflow paints — the multiplexer overwrote the TUI output and the user saw the viewport flash blank before the next throttled frame.

The SIGWINCH callback now debounces inside multiplexer sessions through a 50 ms render-scheduler timer; subsequent events cancel and re-arm it, so a single forced render fires at the final geometry once the pane is quiet. `#resizeEventPending` is still set on every event so the eventual render classifies as a resize, and stop() cancels the pending timer.

Fixes #2088
2026-06-08 03:50:50 +00:00
can1357 da0502008e docs(coding-agent): rewrote plan-mode prompt as execution spec
- Reframed the plan artifact as a self-contained execution spec a fresh agent runs after context is cleared.
- Folded high-consensus requirements (sequencing, contracts, cutover, verification) into existing sections as inline rules.
- Banned decision-free sections and conversation back-references; kept the decision-complete self-check and completeness-wins tiebreak.
2026-06-08 04:44:19 +02:00
can1357 46578e57ba fix(tui): fixed handling of split DEC 2048 in-band resize reports
- Added a reassembly buffer for DEC 2048 in-band resize reports split across stdin reads.
- Dropped invalid or stale partial resize sequences to prevent leaked trailing bytes from entering terminal input.
- Added tests that verify split resize reports are handled and split kitty key sequences are forwarded correctly.
2026-06-08 04:42:26 +02:00
can1357 f38af64430 chore: bump version to 15.10.2 2026-06-08 02:57:31 +02:00
can1357 733d1dabb1 fix(tui): triggered viewport repaint when focus changes
- Tracked focus transitions in TUI and flagged renders after focus changes to allow unknown viewport mutations.
- Used the new focus-change flag when deciding explicit viewport mutation so subsequent frames repaint even when the terminal lacks a viewport-oracle position.
- Added a regression test covering menu teardown focus changes on unknown-viewport terminals with eager scrollback risk.
2026-06-08 02:45:16 +02:00
can1357 00e6e14cb4 feat: added reconstructed raw SSE capture for stream provider SDKs
- Added reconstructed SSE event emission for OpenAI, Azure, and Anthropic streams.
- Added raw SSE text to debug report bundles, including raw-sse.txt output.
- Included dropped-record metadata in raw SSE text when events were trimmed.
- Updated raw SSE and sse-debug tests for observer-based capture and safety checks.
2026-06-08 02:35:14 +02:00
can1357 a3efb62998 feat(coding-agent/modes): added canonical key matching behavior and exported alias utilities
- Built canonical and alias key maps for action/custom handlers and rebuilt them on changes.
- Preserved the first handler when custom key alias collisions occurred during rebuilds.
- Exported canonicalKeyId and addKeyAliases from keybindings for external use.
2026-06-08 02:29:30 +02:00
can1357 6d77bafe84 fix(tui): suppressed redundant cursor writes during no-op terminal rerenders
- Added hardware cursor state caching to reuse last known position and visibility.
- Updated cursor flow to preserve target row/column/visibility across rerenders.
- Reworked cursor output emission to skip unchanged cursor moves and hide/show writes.
2026-06-08 02:22:18 +02:00
can1357 078dac7ea8 fix(tui): skipped loader render requests when text unchanged
- Returned a changed flag from setText to gate render requests.
- Avoided redundant renders when composed loader text matches prior frame.
2026-06-08 02:15:24 +02:00
can1357 a89bb76444 fix(tui): preserved visible ANSI content when truncating terminal rows
- Replaced the TUI row truncation path with per-character and ANSI-sequence iteration that tracks visible cells before clipping output.
- Added ANSI helpers to parse sequence boundaries and preserve OSC66 visible payloads while enforcing max source length during truncation.
- Added natives regression coverage for Ghostty super+alt backspace key matching and parsing.
2026-06-08 01:22:26 +02:00
can1357 d6830b4b8b fix(packages/tui): resolved width-based truncation with issue-2045 test
- Switched long-row truncation to visible-cell width, preserving suffixes after zero-width prefixes.
- Added issue-2045 regression test in issue-2045-repro.test.ts for combining-prefix truncation.
2026-06-08 01:09:47 +02:00
Can Bölük 6ef7548fcb Merge branch 'main' into farm/9483b02b/fix-alt-backspace-kitty-ghostty 2026-06-08 00:45:21 +02:00
can1357 4f085de299 Merge remote-tracking branch 'origin/farm/cc1fae18/chunk-large-writes-conpty' 2026-06-08 00:30:45 +02:00
can1357 988b51ffad Merge remote-tracking branch 'origin/farm/da3d94d7/fix-deferred-shrink-viewport-clears' 2026-06-08 00:30:11 +02:00
can1357 d3290c3ee5 Merge remote-tracking branch 'origin/farm/e60e06f3/bound-tui-line-fitting' 2026-06-08 00:29:59 +02:00
roboomp 5bfad210a6 fix(tui): recognized Ghostty's super+alt+backspace as word delete
Ghostty on macOS reports Option+Backspace as kitty modifier 11
(wire) = 10 (mask) = super(8) | alt(2). The native key matcher only
recognised shift/ctrl/alt, so:

- format_kitty_key in crates/pi-natives/src/keys.rs rejected any
  sequence whose effective modifier had bits beyond shift/ctrl/alt
  set; parseKey returned undefined for \x1b[127;11u.
- parse_key_id recognised only those three modifiers, so even an
  explicit 'super+alt+backspace' degraded to 'alt+backspace' and
  could not match an actual super+alt encoded press.
- The editor's matchesKey(data, 'alt+backspace') branch was never
  reached and Option+Backspace either no-op'd or fell through to
  single-character delete.

Added a MOD_SUPER constant, taught parse_key_id, format_with_mods,
and format_kitty_key about the super bit, added super+alt+backspace
(and super+alt+delete / super+alt+d) to tui.editor.deleteWord*
defaults, and broadened the editor's direct matchesKey calls to
accept the super+alt variants. Existing alt+backspace / alt+d /
alt+delete paths are untouched, so the legacy ESC+DEL workaround
keeps working too.

Added Rust unit tests for the super modifier (positive and
negative for hyper/meta sequences we still drop) and TS
regressions in keys.test.ts and editor.test.ts that exercise
\x1b[127;11u end-to-end.

Fixes #2064
2026-06-07 16:17:29 +00:00
roboomp 4053fadf71 fix(tui): preserved osc66 spans in bounded fitting
Detected OSC 66 text-sizing sequences in the bounded line fitter and included them whole so payloads (e.g. Markdown headings) are not skipped as zero-width.

Added a regression assertion that OSC 66 visible cells survive the bound when the row begins with the sized span.
2026-06-07 11:26:09 +00:00
roboomp d78e29e17a fix(tui): preserved text after long ansi prefixes
Scanned oversized render rows by ANSI sequence so bounded line fitting skips leading zero-width control spans without dropping subsequent visible cells.

Extended issue #2045 regression coverage to assert visible text survives long SGR and OSC hyperlink prefixes.
2026-06-07 11:20:41 +00:00
roboomp 2b29fef9ef docs(tui): moved #2046 changelog entry under Unreleased 2026-06-07 11:18:56 +00:00
roboomp ee7e1e3ae3 fix(tui): preserved tmux viewport on offscreen shrink
Skipped repainting tmux panes when an offscreen shrink leaves the visible tail unchanged, and added regression coverage for the no-content-bytes contract.

Fixes #2046
2026-06-07 11:14:29 +00:00
roboomp c3c4c2749d fix(tui): bounded oversized render rows
Bounded the raw row span passed into TUI line fitting so ANSI-heavy subagent output cannot grow terminal write buffers independently of viewport width.

Added issue #2045 regression coverage for pathological zero-width ANSI rows.

Fixes #2045
2026-06-07 11:14:02 +00:00
roboomp d5183a14f9 fix(tui): honored kitty reply when DA1 sentinel arrives first
The kitty keyboard progressive-enhancement probe sends `CSI ? u CSI c`
and used the DA1 reply as a fallback sentinel: if no kitty reply arrived
the modifyOtherKeys fallback was engaged. The kitty handler then refused
to enable kitty whenever modifyOtherKeysActive was already true, which
silently dropped the reply on terminals that answer DA1 before CSI ? u
(Superset / xterm-on-Electron). The protocol never enabled, so
Shift+Enter was delivered as a bare \r and the input box submitted.

Make the kitty reply authoritative regardless of ordering: drop the
`!modifyOtherKeysActive` guard, and if the premature DA1 already engaged
the modifyOtherKeys fallback, send `CSI > 4 ; 0 m` to disable it before
pushing the kitty stack frame. Kitty is strictly preferred (per the
existing #3259-fallback comment), so this is a clean cutover.

Add a regression test that drives a real ProcessTerminal through the
existing render harness across three orderings: kitty-then-DA1 (control),
DA1-then-kitty (#2042 regression), and DA1-only (modifyOtherKeys
fallback stays).

Fixes #2042
2026-06-07 10:41:31 +00:00
roboomp 271b9ed620 fix(tui): extended ConPTY chunking gate to WSL
WSL processes report process.platform === 'linux', but their stdout still
funnels through wslhost into the same Windows ConPTY pipe, so the >32 KB
viewport-tracking regression reproduces there as well. The gate now fires
whenever process.platform === 'win32' OR isWindowsSubsystemForLinux()
detects WSL_DISTRO_NAME/WSL_INTEROP. Genuine POSIX terminals keep the
single-write fast path.

Added a WSL-specific test alongside the existing win32 / clean-linux
cases to lock the broader gate.

Fixes #2034
2026-06-07 08:54:07 +00:00
roboomp 1c2e22068a fix(tui): chunked oversized writes on Windows ConPTY so viewport tracks the cursor
Windows ConPTY ties viewport tracking to per-WriteFile boundaries: when a
single process.stdout.write exceeds ~32-64 KB, the pseudo-console stops
following the cursor and the host UI's scroll position stays parked at
wherever the write began. Full paints (resume, history rebuild, large
permission dialogs) showed only the first screenful until Alt+Tab forced
the host to re-query the cursor; the bytes always landed in scrollback.

ProcessTerminal#safeWrite now routes win32 writes through a new
chunkForConPTY helper that splits oversized buffers into <=8 KiB pieces
at \n boundaries, keeping every WriteFile well below the threshold and
escape sequences intact (TUI paints separate rows with \r\n, so a line
break almost always exists in range). Non-win32 platforms keep the
single-write fast path.

Fixes #2034
2026-06-07 08:49:15 +00:00
can1357 84573a0d1a chore: bump version to 15.10.1 2026-06-07 09:18:25 +02:00
can1357 493c67aa6a test(tui): adjusted TUI test timings for consistent render-throttle flushes
- Increased `Bun.sleep` delays in TUI tests from short frame intervals to 40ms.
- Adjusted mocked `performance.now` tick advances from 20ms to 40ms so render throttling sees full frame gaps.
- Modified the streaming scrollback settle helper to yield a `nextTick` before sleeping, then flush.
2026-06-07 09:18:06 +02:00
can1357 a40f01c1e9 fix(tui): fixed no-append live-region repaints during viewport shifts
- Constrained the no-append repaint optimization to execute only when the logical viewport position was unchanged.
- Documented the live-region pinned repaint cursor re-anchoring fix in the TUI changelog entry.
2026-06-07 08:50:14 +02:00
can1357 8543dcaee4 fix(tui): fixed uppercase Shift preservation for printable keybindings
- Updated key canonicalization in keybinding parsing to parse modifiers case-insensitively and infer `shift` from printable uppercase keys.
- Added regression tests for `shift+a` matching uppercase `A` and for cursor anchoring during no-append live repaint scenarios.
- Recorded the uppercase Shift keybinding fix in the package changelog entry.
2026-06-07 08:49:12 +02:00
can1357 9b98dafe4e test(packages/tui): updated tui test timing for 30fps render cadence
- Updated settle helpers in repro tests to wait 40ms before terminal flush.
- Raised process-terminal-render-harness SETTLE_MS to 67ms for 30fps timing.
- Updated render-throttle mocks to advance mock time by 40ms per frame.
- Added Loader component cadence test for 30fps animated repaint timing.
- Added render-regressions check that non-force renders are scheduled at ~33ms.
2026-06-07 08:42:51 +02:00
can1357 9d80a7d5c6 perf(packages/tui): optimized tui core by skipping redundant work paths
- Added animated message-color gating so loader timers run at 30fps only when needed.
- Added no-op checks in loader and text updates to skip work for unchanged values.
- Optimized key matching by canonicalizing key IDs and precomputing alias sets.
- Added prepared-line caching and bounded terminal/width scans to reduce repaint overhead.
2026-06-07 08:42:51 +02:00
can1357 76af35dcd6 fix(tui): preserved TUI initial scrollback unless clear was requested
- Updated the initial render intent to carry a `clearScrollback` flag.
- Adjusted first-frame rendering logic to preserve existing scrollback by default and clear only when requested.
- Added `resolver` stubs to coding-agent and web-search test registries for interface compatibility.
2026-06-07 07:54:50 +02:00
can1357 becc44ccef fix(tui): fixed startup scrollback clearing and ED3 streaming replay duplication
- Added a clear-initial-terminal-history flag to interactive mode initialization and passed it from cold-launch startup.
- Extended TUI.start to accept clearScrollback and clear native scrollback on initial full paint for non-multiplexer sessions.
- Preserved ED3 streaming scrollback accounting during capped streaming frames and added tests to prevent committed prefix duplication across terminal history rewrites.
2026-06-07 07:42:51 +02:00
can1357 c8217a1325 test(tui): added Markdown.render cache mutation regression tests
- Added tests confirming `Markdown.render` returns caller-owned lines so per-instance mutations do not change the next render output.
- Added coverage that mutating one instance's render output cannot leak injected lines into another instance via shared cache reuse.
- Added a repeated mutate-then-render test to ensure no line accumulation across multiple render cycles.
2026-06-07 07:37:20 +02:00
can1357 e78352abc7 fix(tui): fixed live viewport anchoring during repaint updates
- Replaced the repaint viewport clamp with strict bottom anchoring at lines.length - height.
- Removed the anti-duplication clamping path that could persist off-tail #viewportTopRow values between frames.
- Kept native scrollback cleanup to the existing dirty checkpoint mechanism for stale committed prefixes.
2026-06-07 07:36:08 +02:00
can1357 4080202911 fix(agent): prevented event-loop stalls during oneshot LLM completions
- Added `EventLoopKeepalive` in `instrumentedCompleteSimple` to keep the event loop alive during oneshot completion calls.
- This prevented long-lived completion promises from freezing host spinners in Bun by keeping timer servicing active.
2026-06-07 07:34:11 +02:00
can1357 4a3984eb0a fix(coding-agent/tools): fixed Markdown cache contamination from mutable render arrays
- Marked Markdown cached lines as readonly snapshots and returned copied arrays from `render()`.
- Stored fresh snapshot arrays in both L1 and L2 caches so callers appending rows cannot mutate shared cached Markdown output.
- Added an AskTool test that renders calls and results twice to verify repeated renders remain stable and do not duplicate option labels.
2026-06-07 07:33:43 +02:00
can1357 1a9d898b8a feat(coding-agent): added immediate steering flush on empty streaming submit
- Updated InputController streaming submit handling to interrupt and resume when queued steering exists, refreshing the pending-message UI and render.
- Added AgentSession.interruptAndFlushQueuedMessages to abort active work and continue processing queued messages immediately.
- Added tests for queued steering interruption in both agent-session concurrency and input-controller keybinding flows.
2026-06-07 07:18:02 +02:00
can1357 6adf98fd10 feat(coding-agent): added OSC5522 enhanced paste support for local image and text inserts
- Added OSC5522 parsing and a payload controller that prefers image MIME and reassembles chunks.
- Added bracketed image-path detection and `onPasteImagePath` callback wiring in the editor.
- Added local image-path paste insertion with fallback to text paste on image-size errors.
- Added `Editor.pasteText()` and OSC5522 disable sequencing on terminal cleanup.
2026-06-07 06:43:52 +02:00
can1357 021b621865 perf(tui): removed per-frame line-fit cache from tui render path
- Removed the per-frame `#fitLineCache` in `TUI` rendering to avoid rope-string hashing during repaints.
- Deleted `packages/tui/bench/width.ts`, retiring an obsolete visibleWidth benchmark script.
2026-06-07 06:26:49 +02:00
can1357 705c937c56 fix(tui): fixed visibleWidth parity and OSC66 width metadata behavior
- Fixed `visibleWidth` parity with native width using `Bun.stringWidth` ANSI stripping.
- Fixed tab and OSC66 width parsing with `s=`/`w=` metadata handling.
- Added ASCII and long-string fast paths in `visibleWidth` for faster width checks.
- Consolidated visible-width regression coverage by replacing removed IME/Arabic/Jamo tests with `visible-width.test.ts`.
2026-06-07 06:24:07 +02:00
can1357 d9f09a07b7 fix(tui): prevented committed-prefix duplication on viewport repaint
- Clamped repaint anchor to min(firstChanged, scrollbackHighWater) so byte-identical committed rows are not re-painted into the active grid.
- Added submitPinsViewportToTail capability to reconcile native scrollback at submit on unprobeable local terminals.
- Renamed allowUnknownViewportMutation to allowUnknownViewportTransientRepaint to clarify it never authorizes a settled transcript commit.
2026-06-07 06:01:25 +02:00
can1357 1ebe2c7484 feat(packages/tui-and-shared-tooling-primitives): added TUI terminal support
- Made `Component.invalidate` optional in `packages/tui/src/tui.ts` and callsites.
- Added `iconOverride` support to status-line rendering in `status-line.ts`.
- Added `borderColor` and `framedBlock()` primitives in `output-block.ts` for framed output styling.
- Adjusted `renderOutputBlock()` to draw a continuous border when no header text is present.
- Added terminal checkpoint-reconciliation tests in `submit-checkpoint-reconcile.test.ts` for pinned-tail behavior.
2026-06-07 05:13:58 +02:00
can1357 66583b414b fix(tui): allowed checkpoint replay when submit-scroll pins viewport to tail
- Added terminal detection for submit-key actions that pin the viewport to tail, and added a test override for that capability.
- Converted TERMINAL into a clone-based RuntimeTerminal so mutable capability fields can be updated directly by runtime setters.
- Updated checkpoint replay gating to allow ED3 rebuild when viewport position is unprobeable but submit-pin behavior is reported true.
2026-06-07 05:08:44 +02:00
can1357 9a8bf1c81c feat(coding-agent): added mouse interactions and preserved deleted headings in plan reviews
- Added SGR mouse input handling for wheel and click actions, mapped to option, ToC, and body targets.
- Added deleted-heading state to undo snapshots so removed titles persist and restore correctly.
- Updated the plan-mode active prompt to require decision-complete, implementation-ready plans.
- Enabled mouse tracking for fullscreen overlays and asserted mouse-on/off sequences in tests.
2026-06-07 04:53:59 +02:00