Commit Graph

758 Commits

Author SHA1 Message Date
roboomp 3822a83b46 fix(tui): cleared stale streaming prefix caches
Cleared frozen-prefix render state after full-lex renders cannot establish a current appendable prefix, preventing truncated transient text from reusing spacer lines produced with a former tail.

Added regression coverage for truncating back to a previously frozen prefix.

Fixes #3975
2026-07-01 05:31:53 +02:00
roboomp 7054265483 fix(tui): cached streaming markdown prefix renders
Reused rendered frozen-prefix lines during transient Markdown renders so streaming assistant updates avoid re-rendering stable code blocks and other completed blocks.

Added focused regression coverage for prefix reuse and cache advancement across newly frozen blocks.

Fixes #3975
2026-07-01 02:46:36 +00:00
can1357 f7df67ad72 Merge remote-tracking branch 'origin/farm/df125a92/fix-skill-slash-replace-prompt' 2026-06-30 20:17:24 +02:00
roboomp 095392d144 fix(tui,coding-agent): preserved draft when accepting mid-prompt /skill: autocomplete
The mid-prompt slash skill autocomplete added in #3654 replaced the
entire editor draft with /skill:<name> on accept so the dispatcher
(which only matched leading /skill:) would still fire. That wiped
every keystroke the user had typed before reaching for the skill.

Insert the /skill:<name> token at the cursor in the TUI editor —
replacing only the partial /sk slash token, leaving prose before and
after intact — and extend the skill-command parser so a /skill:<name>
token surrounded by whitespace is recognized as an invocation too,
with the surrounding prose threaded through to the skill as args.

The parser change is shared across all three dispatch sites
(interactive TUI, ACP, RPC) via a new parseSkillInvocation helper
in extensibility/skills, so the three Map<string,string> /
session.skills lookups stay aligned on the same parse.

Fixes #3913
2026-06-30 16:12:53 +00:00
can1357 5cc84db4c4 feat(tui): enabled programmatic form submission via editor APIs
- Added a public `submit()` method to the `Editor` class to trigger form submission.
- Updated the `EditorComponent` interface to expose an optional `submit()` method.
2026-06-30 16:16:39 +02:00
roboomp c2d6c8cf18 fix(tui): deliver buffered double-Esc as two events and re-arm loader after task completion
StdinBuffer held a bare `\x1b\x1b` chunk and timer-flushed it as one
sequence. `parseKey("\x1b\x1b")` returns undefined, so CustomEditor
fell through to the base editor and never fired the configured `onEscape` —
the double-escape gesture and the second-press single-Esc handler both went
dead whenever the terminal batched the two presses into one stdin read.

Split an exact bare `\x1b\x1b` into two ESC events only after the
flush window proves no follower arrived. If a follower does arrive, emit the
first ESC and restart parsing at the second ESC so legacy Alt chords
(`\x1bd`, `\x1b\x7f`) remain one downstream keypress. Meta-CSI/SS3
chords (`\x1b\x1b[A`, `\x1b\x1bO…`) still emit as one combined
sequence.

EventController.tool_execution_update re-armed the working loader when a
transient overlay (auto-compaction / auto-retry / handoff) had torn it down
mid-tool; tool_execution_end did not. A subagent (`task`) call only fires
_end, so a task result landing after such an overlay left the UI looking
idle even though the session was still streaming. Mirror the reconciler
call in #handleToolExecutionEnd.

Fixes #3857
2026-06-30 04:30:42 +00:00
roboomp 64734021a7 fix(tui): deliver buffered double-Esc as two events and re-arm loader after task completion
StdinBuffer held a bare `\x1b\x1b` chunk (or emitted it as one when followed by
a non-CSI byte). `parseKey("\x1b\x1b")` returns undefined, so CustomEditor
fell through to the base editor and never fired the configured `onEscape` —
the double-escape gesture and the second-press single-Esc handler both went
dead whenever the terminal batched the two presses into one stdin read.

Split a bare `\x1b\x1b` into two ESC events at the buffer layer, mirroring
the existing split for ESC + SGR mouse report. Meta-CSI/SS3 chords
(`\x1b\x1b[A`, `\x1b\x1bO…`) still emit as one combined sequence.

EventController.tool_execution_update re-armed the working loader when a
transient overlay (auto-compaction / auto-retry / handoff) had torn it down
mid-tool; tool_execution_end did not. A subagent (`task`) call only fires
_end, so a task result landing after such an overlay left the UI looking
idle even though the session was still streaming. Mirror the reconciler
call in #handleToolExecutionEnd.

Fixes #3857
2026-06-30 03:41:24 +00:00
can1357 9320f53664 test(tui): enabled slash command fallback and refined notification logic
- Allow mid-prompt slash tokens (e.g., `/tmp`) to fall back to file-path completion when no matching skill is found.
- Update notification eligibility logic to allow D-Bus delivery for in-band terminals while excluding Bell-only protocols.
- Add test case verifying slash-command fallback behavior for file paths.
2026-06-28 09:52:44 +02:00
can1357 ccf2b1adf6 feat(tui): implemented protocol-based detection for desktop notifications
- Removed the hardcoded terminal whitelist for native notifications in favor of protocol-based detection.
- Updated Warp terminal configuration to prefer `NotifyProtocol.Osc9` over `NotifyProtocol.Bell`.
- Simplified notification delivery logic by delegating D-Bus toast filtering to terminal protocol capabilities.
2026-06-28 09:52:44 +02:00
can1357 2bd840a20f Merge remote-tracking branch 'origin/farm/4678e70c/fix-iterm-shift-enter' 2026-06-28 08:41:17 +02:00
can1357 670d60fa60 feat(tui): added file-path completion support to autocomplete provider
- Added `getForceFileSuggestions` and `shouldTriggerFileCompletion` to `AutocompleteProvider` interface.
- Updated `Editor` to invoke file completion logic dynamically when providers support it.
- Corrected log viewer scroll offset calculation to account for viewport height.
- Added comprehensive unit test for log row selection and expansion.
2026-06-28 08:25:32 +02:00
roboomp f761171f68 refactor(tui): split keyboard enhancement into enter/exit pair
Renamed the buffer-switch helper to keyboardEnhancementEnterSequence and added a sibling keyboardEnhancementExitSequence so callers can balance push/pop generically instead of hard-coding the kitty pop.

ProcessTerminal returns the matching kitty pop on exit when kitty is active, and null when only the xterm modifyOtherKeys fallback is active: modifyOtherKeys is a global terminal flag with no per-screen stack, so emitting >4;0m on overlay exit would clear it on the normal screen and break composer typing between overlays. terminal.stop() and the emergency-restore path still disable it globally on graceful teardown.

TUI alt-screen entry/exit and resize alt-screen helpers now route through the new pair with fallbacks to kittyEnableSequence for custom Terminal implementations predating the new properties.

Fixes #3705
2026-06-28 06:25:26 +00:00
can1357 f1afe8faa4 Merge remote-tracking branch 'origin/farm/4678e70c/fix-iterm-shift-enter' 2026-06-28 08:19:19 +02:00
roboomp 78c4a29cbe fix(tui): preserved legacy terminal keyboard fallback
Kept Terminal.keyboardEnhancementSequence optional and fell back to kittyEnableSequence when custom Terminal implementations do not expose the new property.

Covered the legacy custom Terminal path in the fullscreen overlay regression tests.

Fixes #3705
2026-06-28 06:18:50 +00:00
roboomp 2edd55e494 fix(tui): reassert modifyotherkeys in overlays
Re-pushed the active modified-key reporting sequence when fullscreen and resize alternate screens are entered, so terminals using the xterm modifyOtherKeys fallback keep Shift+Enter distinct from plain Enter after terminal buffer switches.

Added a ProcessTerminal regression covering the iTerm-style fallback path alongside the existing Kitty keyboard negotiation tests.

Fixes #3705
2026-06-28 06:10:18 +00:00
can1357 3ccef0a8bf fix(tui): preserve path tab completion after prose 2026-06-28 07:44:28 +02:00
can1357 414d3479bb merge #3657: open mid-prompt skill autocomplete 2026-06-28 07:44:28 +02:00
roboomp 91dfd2ac50 fix(tui): unref'd desktop notifier subprocess so it cannot delay process exit
Bun keeps spawned subprocesses referenced by the event loop until they exit, regardless of stdio: "ignore". A slow notify-send or a hung gdbus call (e.g. stalled session-bus activation) could therefore keep omp alive past renderer shutdown after a completion or ask notification. Call .unref() on the spawned child so the event loop can exit immediately.

Test updated to assert .unref() is invoked on the spawned subprocess.

Re #3685
2026-06-27 23:32:56 +00:00
roboomp 16fef78c97 feat(tui): delivered desktop toasts via d-bus when terminal escapes do not
Introduces desktop-notify.ts which dispatches completion/ask notifications to org.freedesktop.Notifications through notify-send (libnotify) and falls back to gdbus when libnotify is absent. TerminalInfo.sendNotification fans out to D-Bus whenever the chosen notifyProtocol is BEL and DBUS_SESSION_BUS_ADDRESS is set on Linux, so VTE-family hosts (Ptyxis, GNOME Terminal, Tilix) plus Alacritty and bare xterm finally surface toasts they cannot deliver in-band.

Delivery is fire-and-forget, skipped for terminals with their own notification UI (VS Code, Warp), and gated by PI_NO_DESKTOP_NOTIFY=1. The BEL emission is preserved for tmux monitor-bell, X11 urgency hints, and audible-bell handlers.

Fixes #3685
2026-06-27 23:26:06 +00:00
roboomp 61cf24bd68 revert(tui): dropped vte osc 9 notification mapping
Verified against VTE 0.84 (Fedora 40+'s shipping version) and VTE master that OSC 9 is the ConEmu progress extension (only 9;4;... matches), OSC 99 is unimplemented, and OSC 777 only matches notify;Command completed to set a shell-postexec termprop that Ptyxis does not wire to its desktop-notification flow (Ptyxis fires notifications from shell-preexec+shell-precmd cycle, BEL only flashes a visual bell).

No terminal escape currently surfaces an arbitrary toast on VTE-family terminals, so the OSC 9 mapping never delivered a notification and only hid the BEL fallback. Restored the trueColor mapping until a real VTE notification path exists.

Re #3685
2026-06-27 22:34:14 +00:00
roboomp 1019adabad fix(tui): selected osc9 notifications for vte terminals
Recognized VTE_VERSION before the COLORTERM fallback so modern VTE terminals use the vte profile and OSC 9 desktop notifications instead of BEL.

Added regression coverage for VTE detection and notification formatting.

Fixes #3685
2026-06-27 22:19:52 +00:00
roboomp 1c05d059a7 fix(tui): opened mid-prompt skill autocomplete
Detected slash skill lookup after existing prompt text and filtered the popup to skill commands only.

Replaced the whole draft when a mid-prompt skill completion is accepted so the submitted prompt invokes /skill:<name>.

Fixes #3654
2026-06-27 13:14:59 +00:00
can1357 577d2a8eb8 style: biome format/organize-imports across integrated PRs 2026-06-27 02:06:38 +02:00
can1357 f366e7bea8 Merge PR #3402: Shared TUI mouse-routing helpers and overlay selector migration (@wolfiesch)
# Conflicts:
#	packages/coding-agent/src/modes/components/settings-selector.ts
2026-06-27 01:40:11 +02:00
can1357 cf8ac5b2f1 Merge PR #3496: fix(tui): guard streaming Esc cancellation (@roboomp) 2026-06-27 01:39:35 +02:00
can1357 b76fb2be1f Merge PR #3472: feat(tui): recognize Warp as a first-class terminal (@metaphorics)
# Conflicts:
#	packages/tui/src/terminal-capabilities.ts
#	packages/tui/test/terminal-capabilities.test.ts
2026-06-27 01:39:35 +02:00
can1357 a427449d69 feat(tui): extended markdown rendering with html component support
- Added support for `<code>`, `<hr>`, and `<blockquote>` tags to the markdown renderer.
- Improved HTML entity decoding and tag handling logic for consistent terminal output.
- Refactored internal block parsing methods to facilitate specialized styling for new HTML elements.
- Verified new rendering behaviors and entity handling through updated test suites.
2026-06-26 22:45:01 +02:00
Can Bölük 4e56e8bd37 Merge pull request #3465 from cexll/local-build-pr-3428
fix(tui): keep interrupts ahead of repaint
2026-06-25 22:41:21 +02:00
roboomp a538cddd33 fix(tui): guarded streaming escape cancel
Added a two-step Esc guard for active streaming responses and deferred ordinary render scheduling behind queued input so Esc delivery stays responsive under streaming load.

Fixes #3493
2026-06-25 18:52:09 +00:00
can1357 201b91199f fix(tui): corrected ellipsis type check in truncateToWidth
- Adjusted the conditional check to correctly identify string-based ellipsis inputs.
- Resolved logic for applying default ellipsis behavior when invalid or empty types are provided.

Fixes #3492
2026-06-25 20:51:20 +02:00
roboomp 1ab1838587 fix(tui): treated warp wsl host as windows for kitty
Bun reports process.platform as 'linux' inside WSL even when the rendering Warp is the Windows build, which lacks Kitty support and prints APC sequences as visible garbage. Detected WSL via WSL_DISTRO_NAME/WSL_INTEROP and disabled the Kitty image protocol in that case.

Refs #3471
2026-06-25 15:22:32 +00:00
roboomp 4ab1f25503 fix(tui): recognized warp terminal capabilities
Detected Warp via TERM_PROGRAM=WarpTerminal and mapped its platform-specific image and hyperlink capabilities.

Fixes #3471
2026-06-25 15:15:04 +00:00
metaphorics 405222014c feat(tui): recognize Warp as a first-class terminal
Add warp to the TerminalId union and KNOWN_TERMINALS, detected via TERM_PROGRAM=WarpTerminal. Inline images negotiate the Kitty graphics protocol on macOS/Linux and are dropped on Windows (resolveWarpImageProtocol), since Warp ships Kitty on Mac/Linux only. True color is enabled; OSC 8 hyperlinks stay off because Warp renders the escape as literal text rather than a clickable link (override with PI_FORCE_HYPERLINKS=1); synchronized output is left to the runtime DECRQM probe.

Closes #3471
2026-06-26 00:09:10 +09:00
ben d3060f9491 fix(tui): keep interrupts ahead of repaint 2026-06-25 20:01:06 +08:00
roboomp 040846336d fix(tui): shrunk bordered Editor right chrome by cursor overflow cells, not a 1-cell boolean
When the end-of-line cursor glyph lands past a wide trailing grapheme
(CJK comma ',', emoji, etc.), the inverse-video cursor extends past
'lineContentWidth' by the full overflow. Prior cursorInPadding logic
dropped exactly one space of right padding but always re-emitted '─'
before '╯', so 'paddingX=1' overflow=1 stayed 1 cell too wide and
'paddingX=2' overflow=2 stayed 2 cells too wide. In the user's
terminal the '╯' wrapped to a new row, looking like the editor box
collapsed onto two lines.

Replaced the boolean with the actual overflow cell count and recomputed
the right chrome budget (padding + optional '─' + corner) from
'paddingX + 1 - overflow', floored at 1 so the corner/vertical bar
survives. The else branch (non-last lines) follows the same budget for
symmetry.

Fixes #3431
2026-06-25 03:34:24 +00:00
Wolfgang Schoenberger e5e29219fe feat(tui): add shared SGR mouse-routing helpers and SelectList.routeMouse
Add routeSgrMouseInput() and routeSelectListMouse() to centralize the
repeated SGR parse + SelectList hit-test/hover/wheel/click patterns, and
make SelectList implement MouseRoutable via routeMouse(). The structural
SelectListMouseTarget interface keeps mouse.ts free of component imports.

Extend the emergency-restore tests to assert mouse-off sequences
(1006l/1003l/1000l) are emitted while keeping the alt-screen 1049 gating.
2026-06-24 20:09:48 -07:00
can1357 45ade3ef9d Merge remote-tracking branch 'origin/farm/d5c3021f/tmux-notification-bell-passthrough' 2026-06-24 21:00:19 +02:00
roboomp 28e1caec69 fix(tui): deliver notifications under tmux via DCS passthrough + BEL fallback
When the inner-terminal env markers (KITTY_WINDOW_ID, GHOSTTY_RESOURCES_DIR,
WEZTERM_PANE, ITERM_SESSION_ID) leak into a tmux session, TERMINAL_ID
resolves to the inner terminal and notifyProtocol becomes OSC 9 / OSC 99.
sendNotification() wrote that raw OSC straight to stdout, but tmux does not
forward bare OSC 9/99 to the outer terminal and the bare sequence does not
flag tmux's own monitor-bell / monitor-activity — so a backgrounded omp pane
under the common tmux + kitty/ghostty/wezterm/iTerm2 stack had no signal at
all for completion or 'ask' blockage.

Under TMUX, OSC-protocol notifications are now wrapped in tmux's
\x1bPtmux;…\x1b\\ DCS passthrough envelope (so users with
allow-passthrough on still get the real desktop toast) and followed by a
\x07 BEL (so monitor-bell flags the window otherwise — the standard
'needs attention' workflow). The OSC 99 capability probe is wrapped the
same way so rich notifications keep working across tmux. Bell-protocol
paths are unchanged.

Fixes #3395
2026-06-24 18:07:14 +00:00
can1357 7b619400fd Merge PR #1800: fix(tui): runtime Hangul Compatibility Jamo width override + Ghostty detection (@ZergRocks) 2026-06-24 18:43:01 +02:00
can1357 ee57c07371 Merge PR #3377: fix(settings): prevent numeric config values from crashing settings UI (@roboomp) 2026-06-24 18:26:18 +02:00
can1357 a34f4fc129 Merge PR #3345: fix(tui): @-path autocomplete on Windows for paths outside cwd (@oldschoola) 2026-06-24 18:23:50 +02:00
roboomp e261848293 fix(settings): coerced rendered settings values
Coerced malformed YAML-derived settings values to strings before they reach settings row truncation. Added regression coverage for numeric enum display values.

Fixes #3338
2026-06-24 13:53:06 +00:00
changhee.an 82ef6c0a04 feat(tui): runtime Hangul Compatibility Jamo width override + Ghostty detection
Replace the compile-time cfg!(target_os = "macos") jamo-width heuristic
with a runtime override (process-global AtomicU8 in pi-natives, mirrored in
the TS width engine) plus terminal-identity detection: Ghostty renders
Hangul Compatibility Jamo (U+3131..U+318E) at 2 cells, so it is forced wide;
every other terminal keeps the platform default (macOS narrow, otherwise
UAX#11), making the override a no-op outside Ghostty.

Fixes doubled/ghosted jamo during Korean IME composition on Ghostty, where
the hardware cursor landed inside the typed text and the IME candidate window
drifted from the glyph. The width is resolved synchronously before the first
paint, so no stdin/CPR probe or async cache invalidation is needed.

A runtime DSR/CPR probe that auto-detects the width on unknown terminals is
tracked in a follow-up.
2026-06-24 10:27:17 +09:00
oldschoola c96e6b7083 fix: preserve bare ~ as home-directory prefix in autocomplete root check
Address codex P2 review: after #expandHomePath rewrites ~ to the actual
home path (e.g. /home/me), the expandedPrefix === '~' and '~/' checks
became unreachable. When a user types @~, the code fell into the
partial-leaf branch and offered wrong suggestions.

Capture preExpand before home expansion and use it for root-prefix
checks so bare ~ and ~/ are correctly detected as root prefixes.
2026-06-23 15:39:02 -07:00
oldschoola 5febc29d4b fix: use normalized prefix for trailing-separator and root checks in autocomplete
Address codex P2 review: when a Windows @ path ends with a backslash
(e.g. @C:\tmp\outside\), the code checked rawPrefix.endsWith('/')
which is false for backslash endings, causing it to fall into the
partial-leaf branch instead of showing directory contents.

Use expandedPrefix (normalized to forward slashes) for all root-prefix,
trailing-separator, and startsWith('~') checks in getFileSuggestions.
2026-06-23 15:25:47 -07:00
oldschoola d1242a70c8 fix: preserve full absolute prefix in Windows drive-path autocomplete
Address codex review feedback on PR #3345:
- When a Windows user types @C:\tmp\outside\a, the displayPrefix
  includes '/' but doesn't start with '/', so it fell to the else
  branch which uses path.join(path.dirname(...), name). On Windows,
  path.dirname('C:/a') returns 'C:' (no trailing slash), and
  path.join('C:', 'alpha') produces 'C:alpha' — a drive-relative path
  that drops the directory context.
- Replace displayPrefix.startsWith('/') check with path.isAbsolute()
  to cover both /unix/paths and C:/drive/paths.
- Use string concat with '/' instead of path.join to avoid
  platform-native separator issues and drive-relative results.
- Add regression test: completing a partial leaf under an absolute path
  preserves the full parent path in the suggestion value.
2026-06-23 13:59:18 -07:00
oldschoola aae914afdc fix: normalize backslashes in Windows path prefix before splitting (review feedback) 2026-06-23 13:41:42 -07:00
oldschoola a5ae78cc4f fix(tui): @-path autocomplete on Windows for paths outside cwd
CombinedAutocompleteProvider.#getFileSuggestions had two cross-platform
bugs that caused @-path autocomplete to fail on Windows:

1. Absolute path detection only checked startsWith('/') — Windows
   drive-letter paths (C:\Users\...) were not recognized as absolute,
   so they were incorrectly joined with the base directory via
   path.join, producing invalid search paths and empty suggestions.

2. path.join and path.dirname introduce backslashes on Windows, so
   suggestion values contained backslashes that didn't match the
   user's forward-slash input and broke round-trip insertion.

Fix: replace startsWith('/') with path.isAbsolute() (handles drive
letters on Windows, / on Unix). Normalize relativePath to forward
slashes before constructing the suggestion value (forward slashes are
valid path separators on all platforms, including Windows).

Updated 2 test assertions to normalize expected paths to forward
slashes for cross-platform compatibility. Both previously-failing
tests now pass on Windows.
2026-06-23 12:12:15 -07:00
oldschoola 92ef137d7e fix(tui): stop OSC 11 background-color poll from wiping text selection (#3297)
ProcessTerminal.start() armed a 30-second OSC 11 + DA1 background-color
poll on every non-WSL terminal so OS theme switches could be picked up
mid-session on terminals without DEC Mode 2031 push notifications. Each
poll's OSC 11/DA1 write wipes the user's active text selection on several
of those terminals (macOS Terminal.app, Warp, VS Code's built-in, older
Alacritty/WezTerm) — already documented in the comment at terminal.ts
and in the [15.9.0]/[15.10.x] CHANGELOG entries that tightened the
interval from 2s to 30s. Any drag-select that straddles the 30s boundary
gets wiped, matching the 'sometimes can't copy' pattern reported in #3297.

Removed the poll outright: #startOsc11Poll/#stopOsc11Poll methods, the
#osc11PollTimer field, the isWSL-gated startup call, and all stop calls
in the Mode 2031 handler, #resolvePrivateMode, and stop().

Theme detection now relies on (1) the existing startup OSC 11 probe and
(2) DEC Mode 2031 push notifications. Terminals without Mode 2031 pick
up OS theme changes on next launch.

Replaced three poll-asserting tests with two regression tests that
advance fake timers 10 minutes and assert zero additional OSC 11 queries
fire, on both non-WSL and WSL paths.

Fixes #3297
2026-06-23 12:03:04 -07:00
can1357 be3687a5f1 feat(tui): improved settings list wheel interaction handling
- Implement `handleWheelAt` to restrict wheel scrolling to the settings pane.
- Update selection movement to support clamping when scrolling at boundaries.
- Add tests to verify boundary behavior and spatial constraints.
2026-06-22 06:10:17 +02:00