Commit Graph

334 Commits

  • feat: add type-safe KeyId for matchesKey function
    - Add KeyId union type covering all valid key combinations
    - Add Key helper object for autocomplete (Key.ctrl('c'), Key.escape, etc.)
    - Update matchesKey signature to use KeyId instead of string
    - Catches typos like 'esacpe' at compile time
  • feat: use keybindings in all selectors and lists
    Update all selector/list components to use EditorKeybindingsManager:
    - model-selector, session-selector, oauth-selector, user-message-selector
    - hook-selector, hook-input, hook-editor, tree-selector
    - select-list, settings-list, cancellable-loader
    
    This allows users to configure selectUp, selectDown, selectConfirm,
    selectCancel actions in keybindings.json
  • feat: configurable keybindings for all editor and app actions
    All keybindings configurable via ~/.pi/agent/keybindings.json
    
    Editor actions:
    - cursorUp, cursorDown, cursorLeft, cursorRight
    - cursorWordLeft, cursorWordRight, cursorLineStart, cursorLineEnd
    - deleteCharBackward, deleteCharForward, deleteWordBackward
    - deleteToLineStart, deleteToLineEnd
    - newLine, submit, tab
    - selectUp, selectDown, selectConfirm, selectCancel
    
    App actions:
    - interrupt, clear, exit, suspend
    - cycleThinkingLevel, cycleModelForward, cycleModelBackward
    - selectModel, expandTools, toggleThinking, externalEditor
    
    Also adds support for numpad Enter key (Kitty protocol codepoint 57414
    and SS3 M sequence)
    
    Example emacs-style keybindings.json:
    {
      "cursorUp": ["up", "ctrl+p"],
      "cursorDown": ["down", "ctrl+n"],
      "cursorLeft": ["left", "ctrl+b"],
      "cursorRight": ["right", "ctrl+f"],
      "deleteCharForward": ["delete", "ctrl+d"],
      "cycleModelForward": "ctrl+o"
    }
  • Merge pull request #411 from nathyong/feature/shift-backspace
    tui: fix shift+space/backspace/delete on kitty-protocol terminals
  • Add terminal title support to TUI framework (#407)
    Add setTitle() method to Terminal interface for setting window title.
    Uses standard OSC escape sequence \x1b]0;...\x07 for broad terminal
    compatibility (macOS Terminal, iTerm2, Kitty, WezTerm, Ghostty, etc.).
    
    Changes:
    - Add setTitle(title: string) to Terminal interface
    - Implement in ProcessTerminal using OSC sequence
    - Implement no-op in VirtualTerminal for testing
    - Use in interactive mode to set title as "pi - <dirname>"
  • tui: fix shift+space/backspace/delete on kitty-protocol terminals
    Kitty and other smart terminals send a specific CSI u control code for
    these shifted special keys, which are interpreted as a no-op by the
    editor component. These should send the underlying key instead, matching
    the behaviour of other TUI programs (e.g. readline, vim insert mode).
    
    On less smart terminals, these key combinations are the same as the
    non-shifted versions, and so already work with the existing code.
  • tui: only check for emojis in visibleWidth when necessary
    The initial render of a session, and any re-draws caused by terminal
    resizing are noticeably slow, especially on conversations with 20+
    turns and many tool calls.
    
    From profiling with `bun --cpu-prof` (available since bun 1.3.2), the
    majority of the rendering (90%) is spent on detection of emojis in the
    string-width library, running the expensive `/\p{RGI_Emoji}$/v`
    regular expression on every individual grapheme cluster in the entire
    scrollback. I believe it essentially expands to a fixed search against
    every possible emoji sequence, hence the amount of CPU time spent in it.
    
    This change replaces the `stringWidth` from string-width with a
    `graphemeWidth` function that performs a similar check, but avoids
    running the `/\p{RGI_Emoji}$/v` regex for emoji detection unless it
    contains codepoints that could be emojis.
    
    The `visibleWidth` function also has two more optimisations:
    - Short-circuits string length detection for strings that are entirely
      printable ASCII characters
    - Adds a cache for non-ASCII segments to avoid recomputing string length
      when resizing
  • Fix crash on Unicode format characters in visibleWidth
    Strip all Unicode format characters (category Cf) before passing to
    string-width. These are invisible control characters that crash
    string-width but have no visible width anyway.
    
    Closes #390
  • Fix characters (#372)
    * Fix cat command
    
    * Fix text rendering crash from undefined code points in bash output
    
    * Revert unintentional model parameter changes from fix cat command commit
  • Add setEditorText/getEditorText to hook UI context, improve custom() API
    - Add setEditorText() and getEditorText() to HookUIContext for prompt generator pattern
    - custom() now accepts async factories for fire-and-forget work
    - Add CancellableLoader component to tui package
    - Add BorderedLoader component for hooks with cancel UI
    - Export HookAPI, HookContext, HookFactory from main package
    - Update all examples to import from packages instead of relative paths
    - Update hooks.md and custom-tools.md documentation
    
    fixes #350
  • feat(tui): implement word wrapping in Editor component
    Previously, the Editor component used character-level (grapheme-level)
    wrapping, which broke words mid-character at line boundaries. This
    created an ugly visual experience when typing or pasting long text.
    
    Now the Editor uses word-aware wrapping:
    - Wraps at word boundaries when possible
    - Falls back to character-level wrapping for tokens wider than the
      available width (e.g., long URLs)
    - Strips leading whitespace at line starts
    - Preserves multiple spaces within lines
    
    Added wordWrapLine() helper function that tokenizes text into words
    and whitespace runs, then builds chunks that fit within the specified
    width while respecting word boundaries.
    
    Also updated buildVisualLineMap() to use the same word wrapping logic
    for consistent cursor navigation.
    
    Added tests for:
    - Word boundary wrapping
    - Leading whitespace stripping
    - Long token (URL) character-level fallback
    - Multiple space preservation
    - Edge cases (empty string, exact fit)
  • Export wrapTextWithAnsi utility and add handleInput docs
    - Export wrapTextWithAnsi from tui package
    - Add 'Handling Input' section to README with key detection example
    - Document wrapTextWithAnsi in utilities section
  • Tree selector improvements: active line highlight and tool filter
    - Add inverse background highlight for selected/active line
    - Add 'no-tools' filter mode to hide tool results
    - Add isShiftCtrlO to cycle filters backwards
    - Filter order: default → no-tools → user-only → labeled-only → all
  • fix(tui): render HTML tags as plain text in Markdown component
    Handles both block-level and inline HTML tags that were previously
    silently dropped.
    
    fixes #359
  • Merge pull request #315 from mitsuhiko/model-switcher
    Reverse model switching and binding for dialog
  • Add /settings command with unified settings menu (#312)
    * Add /settings command with unified settings menu
    
    - Add SettingsList component to tui package with support for:
      - Inline value cycling (Enter/Space toggles)
      - Submenus for complex selections
      - Selection preservation when returning from submenu
    
    - Add /settings slash command consolidating:
      - Auto-compact (toggle)
      - Show images (toggle)
      - Queue mode (cycle)
      - Hide thinking (toggle)
      - Collapse changelog (toggle)
      - Thinking level (submenu)
      - Theme (submenu with preview)
    
    - Update AGENTS.md to clarify no inline imports rule
    
    Fixes #310
    
    * Add /settings to README slash commands table
    
    * Remove old settings slash commands, consolidate into /settings
    
    - Remove /thinking, /queue, /theme, /autocompact, /show-images commands
    - Remove unused selector methods and imports
    - Update README references to use /settings
  • Fix Ctrl+W to use standard readline word deletion behavior (#306)
    - Skip trailing whitespace before deleting word (readline behavior)
    - Make word navigation grapheme-aware using Intl.Segmenter
    - Add Ctrl+Left/Right and Alt+Left/Right word navigation to Input
    - Accept full Unicode input while rejecting control characters (C0/C1/DEL)
    - Extract shared utilities to utils.ts (getSegmenter, isWhitespaceChar, isPunctuationChar)
    - Fix unsafe cast in Editor.forceFileAutocomplete with runtime type check
    - Add comprehensive tests for word deletion and navigation
  • Add safety-space before pasting (#307)
    * Add safety space when dropping in paths
    
    * Add safety space when dropping in paths
  • feat(coding-agent): add Ctrl+Z to suspend process (#267)
    * feat(tui): add isCtrlZ key detection and resetRenderState method
    
    * feat(coding-agent): add Ctrl+Z handler to suspend process
    
    * docs(coding-agent): add Ctrl+Z to keyboard shortcuts documentation
    
    * feat(tui): add force parameter to requestRender
  • Fix tab completion for absolute paths
    - Fix //tmp issue: distinguish slash commands from file paths by checking if anything precedes the /
    - Fix symlinks to directories (like /tmp) not getting trailing slash
  • feat(ai): add Google Cloud Code Assist provider
    - Add new API type 'google-cloud-code-assist' for Gemini CLI / Antigravity auth
    - Extract shared Google utilities to google-shared.ts
    - Implement streaming provider for Cloud Code Assist endpoint
    - Add 7 models: gemini-3-pro-high/low, gemini-3-flash, claude-sonnet/opus, gpt-oss
    
    Models use OAuth authentication and have sh cost (uses Google account quota).
    OAuth flow will be implemented in coding-agent in a follow-up.
  • fix(tui): fix input buffering in iTerm2 causing delayed keypresses
    The cell size query response parser was incorrectly holding back Kitty
    keyboard protocol sequences, thinking they might be incomplete cell size
    responses. This caused Ctrl+C/Ctrl+D to require multiple presses in iTerm2.
    
    Fixed by only waiting for more data if the buffer doesn't end with a
    terminal escape sequence terminator character.
  • fix(tui): use isBackspace and isEnter helpers in Editor
    Fixes Backspace and Enter not working with Caps Lock enabled.
    The Kitty protocol sends lock key bits in modifiers which broke
    the raw byte detection.
  • fix(tui): add isHome, isEnd, isDelete helpers for Kitty protocol
    Extended the Kitty protocol parser to handle functional keys with
    ~ terminator (Delete, Insert, PageUp, PageDown) and Home/End keys.
    Updated editor.ts and input.ts to use the new helpers.
  • fix(tui): use isEnter and isBackspace helpers in Input component
    Fixes Kitty protocol handling for Enter and Backspace in the Input
    component, matching the Editor component fix.
  • fix(tui): handle emoji deletion and cursor movement correctly
    Backspace, Delete, and arrow keys now use Intl.Segmenter to operate
    on grapheme clusters instead of individual UTF-16 code units. This
    fixes deletion of emojis and other multi-codepoint characters.
    
    fixes #240
  • fix(tui): handle Kitty protocol lock key modifiers
    Fixes keyboard input in Ghostty on Linux when Num Lock is enabled.
    The Kitty protocol includes Caps Lock (64) and Num Lock (128) bits
    in modifier values. Now masks out lock bits when matching shortcuts.
    
    Added helper functions: isArrowUp/Down/Left/Right, isEnter, isTab,
    isBackspace, isShiftEnter, isAltEnter, isAltLeft/Right, isCtrlLeft/Right
    
    fixes #243
  • Fix Escape key handling for Kitty keyboard protocol
    Add isEscape() helper that handles both raw (\x1b) and Kitty protocol
    (\x1b[27u) Escape sequences. Update all components that check for
    Escape key to use the new helper.
  • Remove isKittyCtrl and isKittyKey from public exports
    These generic helpers aren't used externally and would require
    exporting MODIFIERS constants to be ergonomic. The specific
    isCtrl* helpers cover all practical use cases.
  • Add Ctrl+D to exit when editor is empty
    - Add isCtrlD helper to keys.ts
    - CustomEditor intercepts Ctrl+D and only triggers callback when editor is empty
    - Single Ctrl+D with empty input exits immediately
    - Update CHANGELOG to frame as feature (Kitty protocol support) not fix
  • Add helper functions for key detection and update usage
    - Add isCtrlA/C/E/K/O/P/T/U/W helper functions that check both raw and Kitty formats
    - Add isAltBackspace helper function
    - Refactor editor.ts, input.ts, select-list.ts to use helper functions
    - Refactor custom-editor.ts, session-selector.ts, user-message-selector.ts
    - Add CHANGELOG entry for the Shift+Enter fix
  • Add Kitty keyboard protocol support for Shift+Enter and other modifier keys
    Enable the Kitty keyboard protocol on terminal start to receive enhanced
    key sequences that include modifier information. This fixes Shift+Enter
    not working in Ghostty, Kitty, WezTerm, and other modern terminals.
    
    Changes:
    - Enable Kitty protocol on start (\x1b[>1u), disable on stop (\x1b[<u)
    - Add centralized key definitions in packages/tui/src/keys.ts
    - Support both legacy and Kitty sequences for all modifier+key combos:
      - Shift+Enter, Alt+Enter for newlines
      - Shift+Tab for thinking level cycling
      - Ctrl+C, Ctrl+A, Ctrl+E, Ctrl+K, Ctrl+U, Ctrl+W, Ctrl+O, Ctrl+P, Ctrl+T
      - Alt+Backspace for word deletion
    - Export Keys constants and helper functions from @mariozechner/pi-tui
  • Custom tools with session lifecycle, examples for hooks and tools
    - Custom tools: TypeScript modules that extend pi with new tools
      - Custom TUI rendering via renderCall/renderResult
      - User interaction via pi.ui (select, confirm, input, notify)
      - Session lifecycle via onSession callback for state reconstruction
      - Examples: todo.ts, question.ts, hello.ts
    
    - Hook examples: permission-gate, git-checkpoint, protected-paths
    
    - Session lifecycle centralized in AgentSession
      - Works across all modes (interactive, print, RPC)
      - Unified session event for hooks (replaces session_start/session_switch)
    
    - Box component added to pi-tui
    
    - Examples bundled in npm and binary releases
    
    Fixes #190