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
- Add
ink-text-input as a dependency
- Replace the presentational
InputPanel with an ink-text-input component
- Move input handling (typing, Enter, backspace, history nav) from App's
useInput hook into the component's event handlers
- Wire the component's value changes back to App via a callback prop
- 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:
- Run
/opsx:propose to generate a full proposal with specs and tasks
- Iterate on the design before any code is written
- 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.
Summary
Replace the current custom
InputPanelcomponent withink-text-inputto gain built-in keyboard handling, cursor navigation, focus management, and multi-line support without manual implementation.Motivation
The current
InputPanelis purely presentational — all input handling (typing, Enter-to-send, backspace, history navigation) lives in App's singleuseInputhook. This approach works but requires manual implementation of every keyboard feature.Three specific gaps:
ink-text-inputhandles this nativelyProposed Solution
ink-text-inputas a dependencyInputPanelwith anink-text-inputcomponentuseInputhook into the component's event handlersAlternatives Considered
ink-text-input— proven package, encapsulates input logic, reduces App complexityOpenSpec Note
This project uses OpenSpec for feature development. If this request is approved, I will:
/opsx:proposeto generate a full proposal with specs and tasksAdditional Context
Current Architecture
InputPanel(src/tui/inputPanel.js) — purely presentational, renders text + blinking cursorApp(src/tui/app.js) — owns all input handling via a singleuseInputhookinputText,historyIndex,inputFocused) managed in App componentTradeoffs
ink-text-inputuseInputinputFocusedstate)Audit Findings (for Issue #591)
src/tui/app.js:739— The entire input handling lives in a singleuseInputcallback (~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. Withink-text-input, the component would own its text state, and App would only need a callback prop (onSubmit/onChange) and a separateinputFocusedstate for focus/blur events.src/tui/app.js:778-791— History navigation (up/down arrow) reads fromchatHistoryarray. This logic would need to be preserved — either kept in App'sonSubmithandler or wired into the input component's key handlers.src/tui/app.js:764-767— Tab key togglesinputFocused. Withink-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 currentInputPanel(Blink cursor component) would be replaced entirely. The cursor blinking behavior would be handled byink-text-inputnatively.src/tui/app.js:741-752— Onboarding input uses the sameuseInputpattern. 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 withinputText,cursorChar, andcursorColorprops. These would change tovalue,onSubmit, and focus-related props.