Skip to content

feat: replace input panel with ink-text-input component #591

Description

@avoidwork

Summary

Replace the current custom InputPanel component with ink-text-input to gain built-in keyboard handling, cursor navigation, focus management, and multi-line support without manual implementation.

Motivation

The current InputPanel is purely presentational — all input handling (typing, Enter-to-send, backspace, history navigation) lives in App's single useInput hook. This approach works but requires manual implementation of every keyboard feature.

Three specific gaps:

  • Better UX — cursor movement, word deletion (Ctrl+W), line clearing (Ctrl+U), text selection are not implemented
  • Less code in App — input logic is scattered across the App component and should be encapsulated
  • Multi-line input — the current approach would need more work; ink-text-input handles this natively

Proposed Solution

  1. Add ink-text-input as a dependency
  2. Replace the presentational InputPanel with an ink-text-input component
  3. Move input handling (typing, Enter, backspace, history nav) from App's useInput hook into the component's event handlers
  4. Wire the component's value changes back to App via a callback prop
  5. Preserve existing features: history navigation, command parsing, streaming state awareness

Alternatives Considered

  • Keep the current approach — minimal dependencies but manual implementation of every keyboard feature
  • Build a custom input component — more control but reinvents the wheel
  • Use ink-text-input — proven package, encapsulates input logic, reduces App complexity

OpenSpec Note

This project uses OpenSpec for feature development. If this request is approved, I will:

  1. Run /opsx:propose to generate a full proposal with specs and tasks
  2. Iterate on the design before any code is written
  3. Follow the task-driven implementation workflow

Additional Context

Current Architecture

  • InputPanel (src/tui/inputPanel.js) — purely presentational, renders text + blinking cursor
  • App (src/tui/app.js) — owns all input handling via a single useInput hook
  • Input state (inputText, historyIndex, inputFocused) managed in App component

Tradeoffs

Current (custom) ink-text-input
Dependency None +1 package
Input logic All in App's useInput Encapsulated in component
Focus management Manual (inputFocused state) Built-in
Keyboard features Whatever implemented Cursor nav, selection, Ctrl+W, Ctrl+U, etc.
Multi-line Custom handling Built-in
Control Full Constrained by component API

Audit Findings (for Issue #591)

  • src/tui/app.js:739 — The entire input handling lives in a single useInput callback (~75 lines). This is the primary target for extraction. It handles: keystroke accumulation, Enter-to-submit, backspace, up/down history navigation, Tab for focus toggle, Escape for interrupt/quit, and onboarding input routing.
  • src/tui/app.js:38-39 — Input state (inputText, historyIndex, inputFocused) is managed in App. With ink-text-input, the component would own its text state, and App would only need a callback prop (onSubmit/onChange) and a separate inputFocused state for focus/blur events.
  • src/tui/app.js:778-791 — History navigation (up/down arrow) reads from chatHistory array. This logic would need to be preserved — either kept in App's onSubmit handler or wired into the input component's key handlers.
  • src/tui/app.js:764-767 — Tab key toggles inputFocused. With ink-text-input, focus management may be handled by the component's built-in focus API, but the Tab key is consumed by Ink's raw mode at the process level, so App may still need to intercept Tab and call the component's focus methods.
  • src/tui/inputPanel.js — The current InputPanel (Blink cursor component) would be replaced entirely. The cursor blinking behavior would be handled by ink-text-input natively.
  • src/tui/app.js:741-752 — Onboarding input uses the same useInput pattern. This is a separate concern — onboarding may need its own input handling or a separate input component. The refactoring should keep onboarding isolated.
  • src/tui/app.js:869-874 — InputPanel is rendered with inputText, cursorChar, and cursorColor props. These would change to value, onSubmit, and focus-related props.

Metadata

Metadata

Assignees

No one assigned

    Labels

    approvedAn identifier for Madz to take action.feature

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions