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
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
- Added a public `submit()` method to the `Editor` class to trigger form submission.
- Updated the `EditorComponent` interface to expose an optional `submit()` method.
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
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
- 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.
- 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.
- 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.
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
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
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
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
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
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
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
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
- 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.
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
- 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
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
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
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
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.
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
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.
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.
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.
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.
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.
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
- 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.