feat: Phase2 JLine终端交互增强 - 行编辑、历史、Tab补全、信号处理

JLine 3 集成:
- ReplSession重写: JLine Terminal + LineReader 替代Scanner
- 支持行编辑(光标移动、删除、Home/End等)
- 持久化历史记录(~/.claude-code-java/history)
- 上下箭头浏览输入历史
- Ctrl+C取消当前输入、Ctrl+D退出
- JLine失败时自动降级到Scanner模式

Tab补全:
- ClaudeCodeCompleter: 斜杠命令补全(/后按Tab)
- 支持命令别名补全(如 /q → exit)
- 分组显示(Commands / Aliases)

新增命令:
- /model: 显示当前AI模型信息
- /compact: 压缩对话上下文
- /cost: Token用量显示(占位)

改进:
- HelpCommand清理为统一格式
- Banner增加终端信息显示和快捷键提示
- 彩色提示符使用AttributedStringBuilder

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
liuzh
2026-04-01 20:18:59 +08:00
co-authored by Copilot
parent 70c9ebed2b
commit b29d61581a
7 changed files with 358 additions and 53 deletions
@@ -1,6 +1,7 @@
package com.claudecode.command.impl;
import com.claudecode.command.CommandContext;
import com.claudecode.command.CommandRegistry;
import com.claudecode.command.SlashCommand;
import com.claudecode.console.AnsiStyle;
@@ -31,24 +32,21 @@ public class HelpCommand implements SlashCommand {
StringBuilder sb = new StringBuilder();
sb.append(AnsiStyle.bold("\n Available Commands:\n\n"));
for (SlashCommand cmd : context.toolRegistry() != null
? List.<SlashCommand>of() // 这里后续会获取注册的命令
: List.<SlashCommand>of()) {
sb.append(String.format(" %s%-12s%s %s%n",
AnsiStyle.CYAN, "/" + cmd.name(), AnsiStyle.RESET, cmd.description()));
}
// 硬编码展示(后续重构为动态)
sb.append(String.format(" %s%-12s%s %s%n", AnsiStyle.CYAN, "/help", AnsiStyle.RESET, "Show available commands"));
sb.append(String.format(" %s%-12s%s %s%n", AnsiStyle.CYAN, "/clear", AnsiStyle.RESET, "Clear conversation history"));
sb.append(String.format(" %s%-12s%s %s%n", AnsiStyle.CYAN, "/compact", AnsiStyle.RESET, "Compact conversation context"));
sb.append(String.format(" %s%-12s%s %s%n", AnsiStyle.CYAN, "/cost", AnsiStyle.RESET, "Show token usage and cost"));
sb.append(String.format(" %s%-12s%s %s%n", AnsiStyle.CYAN, "/model", AnsiStyle.RESET, "Show or switch AI model"));
sb.append(String.format(" %s%-12s%s %s%n", AnsiStyle.CYAN, "/exit", AnsiStyle.RESET, "Exit the application"));
// 从注入的 CommandRegistry 获取不到(因为 context 里没有),所以硬编码与注册保持一致
sb.append(formatCmd("help", "Show available commands"));
sb.append(formatCmd("clear", "Clear conversation history"));
sb.append(formatCmd("compact", "Compact conversation context"));
sb.append(formatCmd("cost", "Show token usage and cost"));
sb.append(formatCmd("model", "Show or switch AI model"));
sb.append(formatCmd("exit", "Exit the application (also: /quit, /q)"));
sb.append("\n");
sb.append(AnsiStyle.dim(" Tips: Press Tab for command completion, Ctrl+D to exit\n"));
sb.append(AnsiStyle.dim(" Shortcuts: Tab to autocomplete, ↑↓ to browse history, Ctrl+D to exit\n"));
return sb.toString();
}
private String formatCmd(String name, String desc) {
return String.format(" %s%-12s%s %s%n", AnsiStyle.CYAN, "/" + name, AnsiStyle.RESET, desc);
}
}