ADR-033: JLine Interactive Prompt Enhancements

Status

Proposed

Date

2025-12-07

Deciders

Context and Problem Statement

The idempiere-cli needs a modern, interactive terminal UI similar to tools like Cursor Agent, Claude Code, and other AI-powered CLIs. These tools provide rich input experiences including boxed input fields, slash command autocomplete, placeholder text, status lines, and thinking indicators.

The current JLinePrompt.java provides basic interactive prompts (select, checkbox, string input) but lacks the polished UI elements seen in modern AI-focused CLI tools.

Decision Drivers

Considered Options

  1. Enhance existing JLinePrompt with new methods
  2. Use Lanterna - full TUI library with windows/panels
  3. Use JLine3 LineReader with custom widgets
  4. Custom ANSI rendering from scratch

Decision Outcome

Chosen option: "Enhance existing JLinePrompt with new methods", because it builds on the existing JLine3 foundation, keeps dependencies minimal, and provides the specific features needed without over-engineering.

Confirmation

Pros and Cons of the Options

Option 1: Enhance existing JLinePrompt

Extend JLinePrompt.java with new methods for modern UI features.

Option 2: Use Lanterna

Full TUI library with windows, panels, text boxes.

Option 3: Use JLine3 LineReader with Widgets

Use JLine's built-in LineReader with custom AutopairWidgets.

Option 4: Custom ANSI rendering

Build everything from raw ANSI escape sequences.

More Information

Feature Specifications

1. Boxed Input Field (promptWithBox)

┌─────────────────────────────────────────────────────────────────────┐
│ → Plan, search, build anything                                      │
└─────────────────────────────────────────────────────────────────────┘

Features:

2. Slash Command Autocomplete (promptWithAutocomplete)

When user types /:

→ /m█
   /model <model>      Set or list models
 → /mcp                Start MCP server
   /migrate            Run migrations

Features:

3. Status Line (setStatusLine)

Persistent line at terminal bottom:

LangChain4j GPT-4                                         / for commands

Features:

4. Thinking Indicator (showThinking)

● Thinking.    240 tokens                              ctrl+c to stop

Features:

Implementation Architecture

JLinePrompt.java
├── Existing Methods (unchanged)
│   ├── promptString()
│   ├── promptBoolean()
│   ├── promptSelect()
│   └── promptCheckboxes()
│
├── New Box Drawing Methods
│   ├── promptWithBox(placeholder, width)
│   ├── drawBox(content, width)
│   └── updateBoxContent(content)
│
├── Autocomplete Methods
│   ├── promptWithAutocomplete(placeholder, completions)
│   ├── showCompletionDropdown(matches, selected)
│   └── filterCompletions(input, completions)
│
├── Status Line Methods
│   ├── setStatusLine(left, right)
│   ├── clearStatusLine()
│   └── saveAndRestorePosition()
│
└── Thinking Indicator Methods
    ├── showThinking(message)
    ├── updateThinking(message, tokens)
    └── hideThinking()

Data Structures

/**
 * Completion option for autocomplete prompts.
 */
public record CompletionOption(
    String value,           // The actual value to insert
    String display,         // Display text (may include formatting)
    String description      // Optional description shown beside
) {}

/**
 * Status line configuration.
 */
public record StatusLine(
    String leftContent,     // Left-aligned text
    String rightContent,    // Right-aligned text
    String separator        // Optional middle separator
) {}

ANSI Escape Sequences Used

// Cursor positioning
"\033[s"          // Save cursor position
"\033[u"          // Restore cursor position
"\033[%d;%dH"     // Move to row;col
"\033[%dA"        // Move up N lines
"\033[%dB"        // Move down N lines
"\033[2K"         // Clear entire line
"\033[J"          // Clear from cursor to end of screen

// Terminal queries
"\033[6n"         // Query cursor position (response: ESC[row;colR)
"\033[18t"        // Query terminal size (response: ESC[8;rows;colst)

Integration with Existing Components

ASCII Logo / Banner (Implemented)

Added to CliTheme.java:

▗▄▄▄▖▗▄▄▄ ▗▄▄▄▖▗▖  ▗▖▗▄▄▖▗▄▄▄▖▗▄▄▄▖▗▄▄▖ ▗▄▄▄▖     ▗▄▄▖▗▖   ▗▄▄▄▖
  █  ▐▌  █▐▌   ▐▛▚▞▜▌▐▌ ▐▌ █  ▐▌   ▐▌ ▐▌▐▌       ▐▌   ▐▌     █
  █  ▐▌  █▐▛▀▀▘▐▌  ▐▌▐▛▀▘  █  ▐▛▀▀▘▐▛▀▚▖▐▛▀▀▘    ▐▌   ▐▌     █
▗▄█▄▖▐▙▄▄▀▐▙▄▄▖▐▌  ▐▌▐▌  ▗▄█▄▖▐▙▄▄▖▐▌ ▐▌▐▙▄▄▖    ▝▚▄▄▖▐▙▄▄▖▗▄█▄▖

Three logo variants:

Methods in CliTheme:

Method Description
printLogo() Full logo in primary color
printLogo(version) Full logo with version
printLogoCompact() Compact logo
printLogoCompact(version) Compact logo with version
printBanner(version, message) Logo + message + separator
printBoxedBanner(version) Logo inside box frame

Methods in JLinePrompt:

Method Description
showBanner() Display full logo
showBanner(version) Display logo with version
showBannerCompact() Display compact logo
showBoxedBanner(version) Display boxed banner
showWelcome(version, desc) Welcome message with logo
showLogoMini() Single-line logo

Example Usage

@Inject
JLinePrompt prompt;

// Boxed input with placeholder
String input = prompt.promptWithBox(
    "Plan, search, build anything",
    80  // width, or -1 for terminal width
);

// Autocomplete for slash commands
List<CompletionOption> commands = List.of(
    new CompletionOption("/help", "/help", "Show available commands"),
    new CompletionOption("/model", "/model <name>", "Set AI model"),
    new CompletionOption("/clear", "/clear", "Clear conversation")
);
String command = prompt.promptWithAutocomplete("Type / for commands", commands);

// Status line
prompt.setStatusLine("GPT-4", "/ for commands");
// ... do work ...
prompt.clearStatusLine();

// Thinking indicator
prompt.showThinking("Generating response");
for (int tokens = 0; tokens < 500; tokens += 10) {
    prompt.updateThinking("Generating response", tokens);
    Thread.sleep(50);
}
prompt.hideThinking();

Terminal Size Handling

private int getTerminalWidth() {
    if (terminal != null) {
        return terminal.getWidth();
    }
    // Fallback to standard 80 columns
    return 80;
}

private int getTerminalHeight() {
    if (terminal != null) {
        return terminal.getHeight();
    }
    return 24;
}

References

Path: /docs/developers/architecture/idempiere-hub/033-jline-interactive-prompt