i18n: 全部用户可见字符串统一为英文(46个文件)
- 所有Command/Tool/Core/MCP/Plugin中的中文提示改为英文 - Javadoc注释和行内注释保留中文不变 - AI提示词(compact/commit/review等)改为英文 - 编译验证通过 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -20,7 +20,7 @@ public class CommandRegistry {
|
||||
for (String alias : command.aliases()) {
|
||||
commands.put(alias.toLowerCase(), command);
|
||||
}
|
||||
log.debug("注册命令: /{}", command.name());
|
||||
log.debug("Registered command: /{}", command.name());
|
||||
}
|
||||
|
||||
/** 批量注册 */
|
||||
|
||||
@@ -44,7 +44,7 @@ public class BranchCommand implements SlashCommand {
|
||||
@Override
|
||||
public String execute(String args, CommandContext context) {
|
||||
if (context.agentLoop() == null) {
|
||||
return AnsiStyle.red(" ✗ AgentLoop 不可用。");
|
||||
return AnsiStyle.red(" ✗ AgentLoop unavailable.");
|
||||
}
|
||||
|
||||
String trimmedArgs = args != null ? args.trim() : "";
|
||||
@@ -63,7 +63,7 @@ public class BranchCommand implements SlashCommand {
|
||||
case "load" -> loadBranch(branchName, context);
|
||||
case "list" -> listBranches(context);
|
||||
case "delete" -> deleteBranch(branchName);
|
||||
default -> AnsiStyle.red(" ✗ 未知子命令: " + subCommand) + "\n" + showUsage();
|
||||
default -> AnsiStyle.red(" ✗ Unknown subcommand: " + subCommand) + "\n" + showUsage();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -76,8 +76,8 @@ public class BranchCommand implements SlashCommand {
|
||||
*/
|
||||
private String saveBranch(String branchName, CommandContext context) {
|
||||
if (branchName.isEmpty()) {
|
||||
return AnsiStyle.red(" ✗ 请指定分支名称。") + "\n"
|
||||
+ AnsiStyle.dim(" 用法: /branch save <name>");
|
||||
return AnsiStyle.red(" ✗ Please specify branch name.") + "\n"
|
||||
+ AnsiStyle.dim(" Usage: /branch save <name>");
|
||||
}
|
||||
|
||||
List<Message> currentHistory = context.agentLoop().getMessageHistory();
|
||||
@@ -87,8 +87,8 @@ public class BranchCommand implements SlashCommand {
|
||||
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
branches.put(branchName, new BranchSnapshot(snapshot, timestamp));
|
||||
|
||||
return AnsiStyle.green(" ✓ 分支已保存: ") + AnsiStyle.bold(branchName) + "\n"
|
||||
+ AnsiStyle.dim(" 消息数: " + snapshot.size() + " 时间: " + timestamp);
|
||||
return AnsiStyle.green(" ✓ Branch saved: ") + AnsiStyle.bold(branchName) + "\n"
|
||||
+ AnsiStyle.dim(" Messages: " + snapshot.size() + " Time: " + timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,21 +100,21 @@ public class BranchCommand implements SlashCommand {
|
||||
*/
|
||||
private String loadBranch(String branchName, CommandContext context) {
|
||||
if (branchName.isEmpty()) {
|
||||
return AnsiStyle.red(" ✗ 请指定分支名称。") + "\n"
|
||||
+ AnsiStyle.dim(" 用法: /branch load <name>");
|
||||
return AnsiStyle.red(" ✗ Please specify branch name.") + "\n"
|
||||
+ AnsiStyle.dim(" Usage: /branch load <name>");
|
||||
}
|
||||
|
||||
BranchSnapshot snapshot = branches.get(branchName);
|
||||
if (snapshot == null) {
|
||||
return AnsiStyle.red(" ✗ 分支不存在: " + branchName) + "\n"
|
||||
+ AnsiStyle.dim(" 使用 /branch list 查看所有可用分支。");
|
||||
return AnsiStyle.red(" ✗ Branch not found: " + branchName) + "\n"
|
||||
+ AnsiStyle.dim(" Use /branch list to see all available branches.");
|
||||
}
|
||||
|
||||
// 恢复对话历史
|
||||
context.agentLoop().replaceHistory(new ArrayList<>(snapshot.messages()));
|
||||
|
||||
return AnsiStyle.green(" ✓ 已恢复到分支: ") + AnsiStyle.bold(branchName) + "\n"
|
||||
+ AnsiStyle.dim(" 已加载 " + snapshot.messages().size() + " 条消息 (保存于 " + snapshot.timestamp() + ")");
|
||||
return AnsiStyle.green(" ✓ Restored to branch: ") + AnsiStyle.bold(branchName) + "\n"
|
||||
+ AnsiStyle.dim(" Loaded " + snapshot.messages().size() + " messages (saved at " + snapshot.timestamp() + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,8 +125,8 @@ public class BranchCommand implements SlashCommand {
|
||||
*/
|
||||
private String listBranches(CommandContext context) {
|
||||
if (branches.isEmpty()) {
|
||||
return AnsiStyle.dim(" 没有保存的分支。") + "\n"
|
||||
+ AnsiStyle.dim(" 使用 /branch save <name> 保存当前对话。");
|
||||
return AnsiStyle.dim(" No saved branches.") + "\n"
|
||||
+ AnsiStyle.dim(" Use /branch save <name> to save current conversation.");
|
||||
}
|
||||
|
||||
int currentSize = context.agentLoop().getMessageHistory().size();
|
||||
@@ -149,7 +149,7 @@ public class BranchCommand implements SlashCommand {
|
||||
.append("\n");
|
||||
}
|
||||
|
||||
sb.append("\n").append(AnsiStyle.dim(" 共 " + branches.size() + " 个分支。")).append("\n");
|
||||
sb.append("\n").append(AnsiStyle.dim(" Total " + branches.size() + " branches.")).append("\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -161,16 +161,16 @@ public class BranchCommand implements SlashCommand {
|
||||
*/
|
||||
private String deleteBranch(String branchName) {
|
||||
if (branchName.isEmpty()) {
|
||||
return AnsiStyle.red(" ✗ 请指定分支名称。") + "\n"
|
||||
+ AnsiStyle.dim(" 用法: /branch delete <name>");
|
||||
return AnsiStyle.red(" ✗ Please specify branch name.") + "\n"
|
||||
+ AnsiStyle.dim(" Usage: /branch delete <name>");
|
||||
}
|
||||
|
||||
BranchSnapshot removed = branches.remove(branchName);
|
||||
if (removed == null) {
|
||||
return AnsiStyle.red(" ✗ 分支不存在: " + branchName);
|
||||
return AnsiStyle.red(" ✗ Branch not found: " + branchName);
|
||||
}
|
||||
|
||||
return AnsiStyle.green(" ✓ 分支已删除: ") + AnsiStyle.bold(branchName);
|
||||
return AnsiStyle.green(" ✓ Branch deleted: ") + AnsiStyle.bold(branchName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -180,11 +180,11 @@ public class BranchCommand implements SlashCommand {
|
||||
*/
|
||||
private String showUsage() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(AnsiStyle.bold("\n 🌿 Branch — 对话分支管理\n\n"));
|
||||
sb.append(" ").append(AnsiStyle.cyan("/branch save <name>")).append(" 保存当前对话为分支\n");
|
||||
sb.append(" ").append(AnsiStyle.cyan("/branch load <name>")).append(" 恢复到指定分支\n");
|
||||
sb.append(" ").append(AnsiStyle.cyan("/branch list")).append(" 列出所有分支\n");
|
||||
sb.append(" ").append(AnsiStyle.cyan("/branch delete <name>")).append(" 删除指定分支\n");
|
||||
sb.append(AnsiStyle.bold("\n 🌿 Branch — Conversation branch management\n\n"));
|
||||
sb.append(" ").append(AnsiStyle.cyan("/branch save <name>")).append(" Save current conversation as branch\n");
|
||||
sb.append(" ").append(AnsiStyle.cyan("/branch load <name>")).append(" Restore to specified branch\n");
|
||||
sb.append(" ").append(AnsiStyle.cyan("/branch list")).append(" List all branches\n");
|
||||
sb.append(" ").append(AnsiStyle.cyan("/branch delete <name>")).append(" Delete specified branch\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ public class CommitCommand implements SlashCommand {
|
||||
public String execute(String args, CommandContext context) {
|
||||
Path projectDir = Path.of(System.getProperty("user.dir"));
|
||||
if (!Files.isDirectory(projectDir.resolve(".git"))) {
|
||||
return AnsiStyle.yellow(" ⚠ 当前目录不是 Git 仓库");
|
||||
return AnsiStyle.yellow(" ⚠ Current directory is not a Git repository");
|
||||
}
|
||||
|
||||
args = args == null ? "" : args.strip();
|
||||
@@ -49,7 +49,7 @@ public class CommitCommand implements SlashCommand {
|
||||
if (addAll) {
|
||||
String addResult = runGit(projectDir, "add", "-A");
|
||||
if (addResult == null) {
|
||||
return AnsiStyle.red(" ✗ git add 失败");
|
||||
return AnsiStyle.red(" ✗ git add failed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,29 +58,29 @@ public class CommitCommand implements SlashCommand {
|
||||
if (staged == null || staged.isBlank()) {
|
||||
String status = runGit(projectDir, "status", "--short");
|
||||
if (status != null && !status.isBlank()) {
|
||||
return AnsiStyle.yellow(" ⚠ 没有已暂存的变更\n")
|
||||
+ AnsiStyle.dim(" 使用 /commit --all 自动添加所有文件\n")
|
||||
+ AnsiStyle.dim(" 或先手动执行 git add");
|
||||
return AnsiStyle.yellow(" ⚠ No staged changes\n")
|
||||
+ AnsiStyle.dim(" Use /commit --all to add all files\n")
|
||||
+ AnsiStyle.dim(" Or run git add manually first");
|
||||
}
|
||||
return AnsiStyle.green(" ✓ 工作区干净,无需提交");
|
||||
return AnsiStyle.green(" ✓ Working directory clean, nothing to commit");
|
||||
}
|
||||
|
||||
// 如果没有指定 message,使用 AI 生成
|
||||
if (message.isEmpty()) {
|
||||
message = generateCommitMessage(projectDir, context);
|
||||
if (message == null || message.isBlank()) {
|
||||
return AnsiStyle.red(" ✗ 无法生成 commit message");
|
||||
return AnsiStyle.red(" ✗ Failed to generate commit message");
|
||||
}
|
||||
}
|
||||
|
||||
// 执行 git commit
|
||||
String commitResult = runGit(projectDir, "commit", "-m", message);
|
||||
if (commitResult == null) {
|
||||
return AnsiStyle.red(" ✗ git commit 失败");
|
||||
return AnsiStyle.red(" ✗ git commit failed");
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("\n").append(AnsiStyle.green(" ✓ Commit 成功\n"));
|
||||
sb.append("\n").append(AnsiStyle.green(" ✓ Commit successful\n"));
|
||||
sb.append(" ").append("─".repeat(50)).append("\n");
|
||||
sb.append(" ").append(AnsiStyle.bold("Message: ")).append(message).append("\n");
|
||||
|
||||
@@ -90,7 +90,7 @@ public class CommitCommand implements SlashCommand {
|
||||
return sb.toString();
|
||||
|
||||
} catch (Exception e) {
|
||||
return AnsiStyle.red(" ✗ 提交失败: " + e.getMessage());
|
||||
return AnsiStyle.red(" ✗ Commit failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,12 +108,12 @@ public class CommitCommand implements SlashCommand {
|
||||
|
||||
// 使用 ChatModel 生成 commit message
|
||||
String prompt = """
|
||||
分析以下 git diff,生成一个简洁的 commit message。
|
||||
要求:
|
||||
1. 使用 conventional commits 格式(feat/fix/docs/refactor/chore等前缀)
|
||||
2. 第一行不超过 72 个字符
|
||||
3. 如果有多个变更,可以在第一行后空一行添加详细说明
|
||||
4. 只返回 commit message 文本,不要添加其他说明
|
||||
Analyze the following git diff and generate a concise commit message.
|
||||
Requirements:
|
||||
1. Use conventional commits format (feat/fix/docs/refactor/chore prefix)
|
||||
2. First line should not exceed 72 characters
|
||||
3. For multiple changes, add details after a blank line
|
||||
4. Return only the commit message text, no additional explanation
|
||||
|
||||
Git diff:
|
||||
```
|
||||
|
||||
@@ -22,14 +22,14 @@ import java.util.List;
|
||||
public class CompactCommand implements SlashCommand {
|
||||
|
||||
private static final String COMPACT_PROMPT = """
|
||||
请将以下对话历史压缩为一段简洁的摘要。要求:
|
||||
1. 保留所有关键决策、代码变更和技术细节
|
||||
2. 保留文件路径、函数名等具体信息
|
||||
3. 保留用户的偏好和要求
|
||||
4. 省略重复的讨论和无关的细节
|
||||
5. 用中文输出,控制在500字以内
|
||||
Please compress the following conversation history into a concise summary. Requirements:
|
||||
1. Preserve all key decisions, code changes, and technical details
|
||||
2. Keep file paths, function names, and specific information
|
||||
3. Preserve user preferences and requirements
|
||||
4. Omit repeated discussions and irrelevant details
|
||||
5. Output within 500 words
|
||||
|
||||
对话历史:
|
||||
Conversation history:
|
||||
""";
|
||||
|
||||
@Override
|
||||
@@ -45,14 +45,14 @@ public class CompactCommand implements SlashCommand {
|
||||
@Override
|
||||
public String execute(String args, CommandContext context) {
|
||||
if (context.agentLoop() == null) {
|
||||
return AnsiStyle.yellow(" ⚠ 没有活跃的对话可压缩。");
|
||||
return AnsiStyle.yellow(" ⚠ No active conversation to compact.");
|
||||
}
|
||||
|
||||
List<Message> history = context.agentLoop().getMessageHistory();
|
||||
int before = history.size();
|
||||
|
||||
if (before <= 3) {
|
||||
return AnsiStyle.dim(" 上下文已经很小(" + before + " 条消息),无需压缩。");
|
||||
return AnsiStyle.dim(" Context is already small (" + before + " messages), no compaction needed.");
|
||||
}
|
||||
|
||||
TokenTracker tracker = context.agentLoop().getTokenTracker();
|
||||
@@ -66,7 +66,7 @@ public class CompactCommand implements SlashCommand {
|
||||
compacted.add(history.getFirst()); // 原始系统提示词
|
||||
|
||||
if (summary != null && !summary.isBlank()) {
|
||||
compacted.add(new SystemMessage("[对话历史摘要] " + summary));
|
||||
compacted.add(new SystemMessage("[Conversation Summary] " + summary));
|
||||
}
|
||||
|
||||
// 保留最后一轮用户消息和助手回复(如果有)
|
||||
@@ -78,15 +78,15 @@ public class CompactCommand implements SlashCommand {
|
||||
int after = compacted.size();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(AnsiStyle.green(" ✅ 上下文已压缩")).append("\n");
|
||||
sb.append(" 消息数: ").append(before).append(" → ").append(after).append("\n");
|
||||
sb.append(AnsiStyle.green(" ✅ Context compacted")).append("\n");
|
||||
sb.append(" Messages: ").append(before).append(" → ").append(after).append("\n");
|
||||
if (tokensBefore > 0) {
|
||||
sb.append(" 压缩前累计 Token: ").append(TokenTracker.formatTokens(tokensBefore)).append("\n");
|
||||
sb.append(" Tokens before compaction: ").append(TokenTracker.formatTokens(tokensBefore)).append("\n");
|
||||
}
|
||||
if (summary != null) {
|
||||
sb.append(AnsiStyle.dim(" 📝 AI 摘要已生成并注入上下文"));
|
||||
sb.append(AnsiStyle.dim(" 📝 AI summary generated and injected into context"));
|
||||
} else {
|
||||
sb.append(AnsiStyle.dim(" ⚠ AI 摘要生成失败,仅保留最近对话"));
|
||||
sb.append(AnsiStyle.dim(" ⚠ AI summary generation failed, keeping recent conversation only"));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
@@ -101,17 +101,17 @@ public class CompactCommand implements SlashCommand {
|
||||
StringBuilder dialogText = new StringBuilder();
|
||||
for (Message msg : history) {
|
||||
switch (msg) {
|
||||
case UserMessage um -> dialogText.append("[用户] ").append(um.getText()).append("\n");
|
||||
case UserMessage um -> dialogText.append("[User] ").append(um.getText()).append("\n");
|
||||
case AssistantMessage am -> {
|
||||
if (am.getText() != null && !am.getText().isBlank()) {
|
||||
// 截断过长的助手回复
|
||||
String text = am.getText();
|
||||
if (text.length() > 500) text = text.substring(0, 500) + "...";
|
||||
dialogText.append("[助手] ").append(text).append("\n");
|
||||
dialogText.append("[Assistant] ").append(text).append("\n");
|
||||
}
|
||||
if (am.hasToolCalls()) {
|
||||
for (var tc : am.getToolCalls()) {
|
||||
dialogText.append("[工具调用] ").append(tc.name()).append("\n");
|
||||
dialogText.append("[Tool Call] ").append(tc.name()).append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public class CopyCommand implements SlashCommand {
|
||||
}
|
||||
|
||||
if (lastResponse == null) {
|
||||
return AnsiStyle.yellow(" ⚠ 暂无 AI 回复可复制");
|
||||
return AnsiStyle.yellow(" ⚠ No AI response to copy");
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -56,14 +56,14 @@ public class CopyCommand implements SlashCommand {
|
||||
|
||||
int charCount = lastResponse.length();
|
||||
int lineCount = (int) lastResponse.lines().count();
|
||||
return AnsiStyle.green(" ✓ 已复制到剪贴板")
|
||||
+ AnsiStyle.dim(" (" + charCount + " 字符, " + lineCount + " 行)");
|
||||
return AnsiStyle.green(" ✓ Copied to clipboard")
|
||||
+ AnsiStyle.dim(" (" + charCount + " chars, " + lineCount + " lines)");
|
||||
} catch (java.awt.HeadlessException e) {
|
||||
// 无头环境(如 SSH)无法使用 AWT 剪贴板
|
||||
return AnsiStyle.yellow(" ⚠ 当前环境不支持剪贴板(Headless 模式)\n")
|
||||
+ AnsiStyle.dim(" 提示:在有图形界面的终端中运行可使用此功能");
|
||||
return AnsiStyle.yellow(" ⚠ Clipboard not supported (headless mode)\n")
|
||||
+ AnsiStyle.dim(" Tip: Run in a graphical terminal to use this feature");
|
||||
} catch (Exception e) {
|
||||
return AnsiStyle.red(" ✗ 复制失败: " + e.getMessage());
|
||||
return AnsiStyle.red(" ✗ Copy failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public class DiffCommand implements SlashCommand {
|
||||
public String execute(String args, CommandContext context) {
|
||||
Path projectDir = Path.of(System.getProperty("user.dir"));
|
||||
if (!Files.isDirectory(projectDir.resolve(".git"))) {
|
||||
return AnsiStyle.yellow(" ⚠ 当前目录不是 Git 仓库");
|
||||
return AnsiStyle.yellow(" ⚠ Current directory is not a Git repository");
|
||||
}
|
||||
|
||||
args = args == null ? "" : args.strip();
|
||||
@@ -72,7 +72,7 @@ public class DiffCommand implements SlashCommand {
|
||||
long lineCount = unstaged.lines().count();
|
||||
if (lineCount > 100) {
|
||||
unstaged.lines().limit(100).forEach(l -> sb.append(" ").append(l).append("\n"));
|
||||
sb.append(AnsiStyle.dim(" ... (共 " + lineCount + " 行,截断显示前100行)\n"));
|
||||
sb.append(AnsiStyle.dim(" ... (" + lineCount + " lines total, showing first 100)\n"));
|
||||
} else {
|
||||
unstaged.lines().forEach(l -> sb.append(" ").append(l).append("\n"));
|
||||
}
|
||||
@@ -84,7 +84,7 @@ public class DiffCommand implements SlashCommand {
|
||||
}
|
||||
|
||||
if (staged.isBlank() && unstaged.isBlank() && untracked.isBlank()) {
|
||||
sb.append("\n").append(AnsiStyle.green(" ✓ 工作区干净,无变更\n"));
|
||||
sb.append("\n").append(AnsiStyle.green(" ✓ Working directory clean, no changes\n"));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
@@ -96,12 +96,12 @@ public class DiffCommand implements SlashCommand {
|
||||
sb.append(" ").append("─".repeat(50)).append("\n\n");
|
||||
|
||||
if (diffOutput.isBlank()) {
|
||||
sb.append(AnsiStyle.green(" ✓ 无变更\n"));
|
||||
sb.append(AnsiStyle.green(" ✓ No changes\n"));
|
||||
} else {
|
||||
long lineCount = diffOutput.lines().count();
|
||||
if (lineCount > 100) {
|
||||
diffOutput.lines().limit(100).forEach(l -> sb.append(" ").append(l).append("\n"));
|
||||
sb.append(AnsiStyle.dim(" ... (共 " + lineCount + " 行)\n"));
|
||||
sb.append(AnsiStyle.dim(" ... (" + lineCount + " lines)\n"));
|
||||
} else {
|
||||
diffOutput.lines().forEach(l -> sb.append(" ").append(l).append("\n"));
|
||||
}
|
||||
@@ -110,7 +110,7 @@ public class DiffCommand implements SlashCommand {
|
||||
return sb.toString();
|
||||
|
||||
} catch (Exception e) {
|
||||
return AnsiStyle.red(" ✗ Git diff 执行失败: " + e.getMessage());
|
||||
return AnsiStyle.red(" ✗ Git diff failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ public class ExportCommand implements SlashCommand {
|
||||
|
||||
// 至少需要系统提示 + 用户消息 + 助手回复
|
||||
if (history.size() < 3) {
|
||||
return AnsiStyle.yellow(" ⚠ 暂无足够的对话内容可导出");
|
||||
return AnsiStyle.yellow(" ⚠ Not enough conversation content to export");
|
||||
}
|
||||
|
||||
// 确定输出路径
|
||||
@@ -67,10 +67,10 @@ public class ExportCommand implements SlashCommand {
|
||||
|
||||
int msgCount = history.size();
|
||||
int lineCount = (int) markdown.lines().count();
|
||||
return AnsiStyle.green(" ✓ 对话已导出: " + outputPath)
|
||||
return AnsiStyle.green(" ✓ Conversation exported: " + outputPath)
|
||||
+ AnsiStyle.dim(" (" + msgCount + " messages, " + lineCount + " lines)");
|
||||
} catch (IOException e) {
|
||||
return AnsiStyle.red(" ✗ 导出失败: " + e.getMessage());
|
||||
return AnsiStyle.red(" ✗ Export failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,12 +28,12 @@ public class HistoryCommand implements SlashCommand {
|
||||
var conversations = persistence.listConversations();
|
||||
|
||||
if (conversations.isEmpty()) {
|
||||
return AnsiStyle.dim(" 📂 暂无保存的对话历史");
|
||||
return AnsiStyle.dim(" 📂 No saved conversation history");
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(AnsiStyle.bold(" 📂 对话历史") + AnsiStyle.dim(" (")
|
||||
+ conversations.size() + AnsiStyle.dim(" 条记录)\n"));
|
||||
sb.append(AnsiStyle.bold(" 📂 Conversation History") + AnsiStyle.dim(" (")
|
||||
+ conversations.size() + AnsiStyle.dim(" records)\n"));
|
||||
sb.append(AnsiStyle.dim(" " + "─".repeat(50)) + "\n");
|
||||
|
||||
int shown = Math.min(conversations.size(), 10);
|
||||
@@ -46,10 +46,10 @@ public class HistoryCommand implements SlashCommand {
|
||||
}
|
||||
|
||||
if (conversations.size() > 10) {
|
||||
sb.append(AnsiStyle.dim(" ... 还有 " + (conversations.size() - 10) + " 条更早的记录\n"));
|
||||
sb.append(AnsiStyle.dim(" ... and " + (conversations.size() - 10) + " older records\n"));
|
||||
}
|
||||
|
||||
sb.append(AnsiStyle.dim("\n 对话存储位置: " + persistence.getConversationsDir()));
|
||||
sb.append(AnsiStyle.dim("\n Storage location: " + persistence.getConversationsDir()));
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public class HooksCommand implements SlashCommand {
|
||||
@Override
|
||||
public String execute(String args, CommandContext context) {
|
||||
if (context.agentLoop() == null || context.agentLoop().getHookManager() == null) {
|
||||
return AnsiStyle.yellow(" ⚠ Hook 管理器不可用。");
|
||||
return AnsiStyle.yellow(" ⚠ Hook manager unavailable.");
|
||||
}
|
||||
|
||||
HookManager hookManager = context.agentLoop().getHookManager();
|
||||
@@ -86,10 +86,10 @@ public class HooksCommand implements SlashCommand {
|
||||
*/
|
||||
private String formatTypeName(HookType type) {
|
||||
return switch (type) {
|
||||
case PRE_TOOL_USE -> "PRE_TOOL_USE (工具执行前)";
|
||||
case POST_TOOL_USE -> "POST_TOOL_USE (工具执行后)";
|
||||
case PRE_PROMPT -> "PRE_PROMPT (发送提示前)";
|
||||
case POST_RESPONSE -> "POST_RESPONSE (收到响应后)";
|
||||
case PRE_TOOL_USE -> "PRE_TOOL_USE (before tool execution)";
|
||||
case POST_TOOL_USE -> "POST_TOOL_USE (after tool execution)";
|
||||
case PRE_PROMPT -> "PRE_PROMPT (before sending prompt)";
|
||||
case POST_RESPONSE -> "POST_RESPONSE (after receiving response)";
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public class McpCommand implements SlashCommand {
|
||||
// 暂时通过静态持有者或类似机制获取。
|
||||
McpManager manager = McpManagerHolder.getInstance();
|
||||
if (manager == null) {
|
||||
return AnsiStyle.red(" ❌ MCP 管理器未初始化");
|
||||
return AnsiStyle.red(" ❌ MCP manager not initialized");
|
||||
}
|
||||
|
||||
String trimmed = args.strip();
|
||||
@@ -63,7 +63,7 @@ public class McpCommand implements SlashCommand {
|
||||
case "resources" -> handleResources(manager, subArgs);
|
||||
case "reload" -> handleReload(manager, context);
|
||||
case "help" -> showHelp();
|
||||
default -> AnsiStyle.red(" 未知子命令: " + subCommand) + "\n" + showHelp();
|
||||
default -> AnsiStyle.red(" Unknown subcommand: " + subCommand) + "\n" + showHelp();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -73,14 +73,14 @@ public class McpCommand implements SlashCommand {
|
||||
private String showStatus(McpManager manager) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("\n");
|
||||
sb.append(AnsiStyle.bold(" 🔌 MCP 服务器状态\n"));
|
||||
sb.append(AnsiStyle.bold(" 🔌 MCP Server Status\n"));
|
||||
sb.append(" ").append("─".repeat(50)).append("\n\n");
|
||||
|
||||
Map<String, McpClient> clients = manager.getClients();
|
||||
if (clients.isEmpty()) {
|
||||
sb.append(" 无已连接的 MCP 服务器\n\n");
|
||||
sb.append(AnsiStyle.dim(" 提示: 使用 /mcp connect <name> <command> [args] 连接服务器\n"));
|
||||
sb.append(AnsiStyle.dim(" 或在 .mcp.json 配置文件中定义服务器\n"));
|
||||
sb.append(" No connected MCP servers\n\n");
|
||||
sb.append(AnsiStyle.dim(" Tip: Use /mcp connect <name> <command> [args] to connect\n"));
|
||||
sb.append(AnsiStyle.dim(" Or define servers in .mcp.json config file\n"));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -92,13 +92,13 @@ public class McpCommand implements SlashCommand {
|
||||
String statusText;
|
||||
if (client.isConnected() && client.isInitialized()) {
|
||||
statusIcon = "✅";
|
||||
statusText = AnsiStyle.green("已连接");
|
||||
statusText = AnsiStyle.green("Connected");
|
||||
} else if (client.isConnected()) {
|
||||
statusIcon = "🔄";
|
||||
statusText = AnsiStyle.yellow("连接中");
|
||||
statusText = AnsiStyle.yellow("Connecting");
|
||||
} else {
|
||||
statusIcon = "❌";
|
||||
statusText = AnsiStyle.red("已断开");
|
||||
statusText = AnsiStyle.red("Disconnected");
|
||||
}
|
||||
|
||||
sb.append(String.format(" %s %-18s %s%n", statusIcon, AnsiStyle.bold(name), statusText));
|
||||
@@ -107,7 +107,7 @@ public class McpCommand implements SlashCommand {
|
||||
int toolCount = client.getTools().size();
|
||||
int resCount = client.getResources().size();
|
||||
sb.append(String.format(" %s%n",
|
||||
AnsiStyle.dim(toolCount + " 工具, " + resCount + " 资源")));
|
||||
AnsiStyle.dim(toolCount + " tools, " + resCount + " resources")));
|
||||
|
||||
// 显示服务器信息
|
||||
if (client.getServerInfo() != null) {
|
||||
@@ -117,8 +117,8 @@ public class McpCommand implements SlashCommand {
|
||||
}
|
||||
|
||||
sb.append("\n");
|
||||
sb.append(AnsiStyle.dim(" 共 " + clients.size() + " 个服务器, "
|
||||
+ manager.getAllTools().size() + " 个工具\n"));
|
||||
sb.append(AnsiStyle.dim(" Total " + clients.size() + " servers, "
|
||||
+ manager.getAllTools().size() + " tools\n"));
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
@@ -128,12 +128,12 @@ public class McpCommand implements SlashCommand {
|
||||
*/
|
||||
private String handleConnect(McpManager manager, String args, CommandContext context) {
|
||||
if (args.isEmpty()) {
|
||||
return AnsiStyle.red(" 用法: /mcp connect <name> <command> [args...]");
|
||||
return AnsiStyle.red(" Usage: /mcp connect <name> <command> [args...]");
|
||||
}
|
||||
|
||||
String[] parts = args.split("\\s+");
|
||||
if (parts.length < 2) {
|
||||
return AnsiStyle.red(" 用法: /mcp connect <name> <command> [args...]");
|
||||
return AnsiStyle.red(" Usage: /mcp connect <name> <command> [args...]");
|
||||
}
|
||||
|
||||
String name = parts[0];
|
||||
@@ -149,13 +149,13 @@ public class McpCommand implements SlashCommand {
|
||||
registerBridgedTools(client, name, context);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(AnsiStyle.green(" ✅ 已连接 MCP 服务器: " + name)).append("\n");
|
||||
sb.append(AnsiStyle.dim(" " + client.getTools().size() + " 个工具, "
|
||||
+ client.getResources().size() + " 个资源")).append("\n");
|
||||
sb.append(AnsiStyle.green(" ✅ Connected to MCP server: " + name)).append("\n");
|
||||
sb.append(AnsiStyle.dim(" " + client.getTools().size() + " tools, "
|
||||
+ client.getResources().size() + " resources")).append("\n");
|
||||
|
||||
// 列出发现的工具
|
||||
if (!client.getTools().isEmpty()) {
|
||||
sb.append("\n 工具:\n");
|
||||
sb.append("\n Tools:\n");
|
||||
for (McpClient.McpTool tool : client.getTools()) {
|
||||
sb.append(" • ").append(tool.name());
|
||||
if (!tool.description().isEmpty()) {
|
||||
@@ -167,7 +167,7 @@ public class McpCommand implements SlashCommand {
|
||||
|
||||
return sb.toString();
|
||||
} catch (McpException e) {
|
||||
return AnsiStyle.red(" ❌ 连接失败: " + e.getMessage());
|
||||
return AnsiStyle.red(" ❌ Connection failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,15 +176,15 @@ public class McpCommand implements SlashCommand {
|
||||
*/
|
||||
private String handleDisconnect(McpManager manager, String args) {
|
||||
if (args.isEmpty()) {
|
||||
return AnsiStyle.red(" 用法: /mcp disconnect <name>");
|
||||
return AnsiStyle.red(" Usage: /mcp disconnect <name>");
|
||||
}
|
||||
|
||||
String name = args.split("\\s+")[0];
|
||||
try {
|
||||
manager.disconnect(name);
|
||||
return AnsiStyle.green(" ✅ 已断开 MCP 服务器: " + name);
|
||||
return AnsiStyle.green(" ✅ Disconnected MCP server: " + name);
|
||||
} catch (McpException e) {
|
||||
return AnsiStyle.red(" ❌ 断开失败: " + e.getMessage());
|
||||
return AnsiStyle.red(" ❌ Disconnect failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ public class McpCommand implements SlashCommand {
|
||||
private String handleTools(McpManager manager, String args) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("\n");
|
||||
sb.append(AnsiStyle.bold(" 🛠️ MCP 工具列表\n"));
|
||||
sb.append(AnsiStyle.bold(" 🛠️ MCP Tools\n"));
|
||||
sb.append(" ").append("─".repeat(50)).append("\n\n");
|
||||
|
||||
String serverFilter = args.isEmpty() ? null : args.split("\\s+")[0];
|
||||
@@ -203,13 +203,13 @@ public class McpCommand implements SlashCommand {
|
||||
if (serverFilter != null) {
|
||||
tools = manager.getServerTools(serverFilter);
|
||||
if (tools.isEmpty()) {
|
||||
return sb + " 服务器 '" + serverFilter + "' 无工具或不存在\n";
|
||||
return sb + " Server '" + serverFilter + "' has no tools or does not exist\n";
|
||||
}
|
||||
sb.append(AnsiStyle.dim(" 服务器: " + serverFilter)).append("\n\n");
|
||||
sb.append(AnsiStyle.dim(" Server: " + serverFilter)).append("\n\n");
|
||||
} else {
|
||||
tools = manager.getAllTools();
|
||||
if (tools.isEmpty()) {
|
||||
return sb + " 无可用的 MCP 工具\n";
|
||||
return sb + " No available MCP tools\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +225,7 @@ public class McpCommand implements SlashCommand {
|
||||
sb.append("\n");
|
||||
}
|
||||
|
||||
sb.append(AnsiStyle.dim(" 共 " + tools.size() + " 个工具")).append("\n");
|
||||
sb.append(AnsiStyle.dim(" Total " + tools.size() + " tools")).append("\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ public class McpCommand implements SlashCommand {
|
||||
private String handleResources(McpManager manager, String args) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("\n");
|
||||
sb.append(AnsiStyle.bold(" 📦 MCP 资源列表\n"));
|
||||
sb.append(AnsiStyle.bold(" 📦 MCP Resources\n"));
|
||||
sb.append(" ").append("─".repeat(50)).append("\n\n");
|
||||
|
||||
String serverFilter = args.isEmpty() ? null : args.split("\\s+")[0];
|
||||
@@ -244,13 +244,13 @@ public class McpCommand implements SlashCommand {
|
||||
if (serverFilter != null) {
|
||||
resourceList = manager.getServerResources(serverFilter);
|
||||
if (resourceList.isEmpty()) {
|
||||
return sb + " 服务器 '" + serverFilter + "' 无资源或不存在\n";
|
||||
return sb + " Server '" + serverFilter + "' has no resources or does not exist\n";
|
||||
}
|
||||
sb.append(AnsiStyle.dim(" 服务器: " + serverFilter)).append("\n\n");
|
||||
sb.append(AnsiStyle.dim(" Server: " + serverFilter)).append("\n\n");
|
||||
} else {
|
||||
resourceList = manager.getAllResources();
|
||||
if (resourceList.isEmpty()) {
|
||||
return sb + " 无可用的 MCP 资源\n";
|
||||
return sb + " No available MCP resources\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,7 +263,7 @@ public class McpCommand implements SlashCommand {
|
||||
sb.append(" MIME: ").append(AnsiStyle.dim(resource.mimeType())).append("\n\n");
|
||||
}
|
||||
|
||||
sb.append(AnsiStyle.dim(" 共 " + resourceList.size() + " 个资源")).append("\n");
|
||||
sb.append(AnsiStyle.dim(" Total " + resourceList.size() + " resources")).append("\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -279,11 +279,11 @@ public class McpCommand implements SlashCommand {
|
||||
registerBridgedTools(entry.getValue(), entry.getKey(), context);
|
||||
}
|
||||
|
||||
return AnsiStyle.green(" ✅ MCP 配置已重新加载: "
|
||||
+ manager.getClients().size() + " 个服务器, "
|
||||
+ manager.getAllTools().size() + " 个工具");
|
||||
return AnsiStyle.green(" ✅ MCP config reloaded: "
|
||||
+ manager.getClients().size() + " servers, "
|
||||
+ manager.getAllTools().size() + " tools");
|
||||
} catch (Exception e) {
|
||||
return AnsiStyle.red(" ❌ 重载失败: " + e.getMessage());
|
||||
return AnsiStyle.red(" ❌ Reload failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,20 +308,20 @@ public class McpCommand implements SlashCommand {
|
||||
private String showHelp() {
|
||||
return """
|
||||
|
||||
\033[1m🔌 MCP 命令帮助\033[0m
|
||||
\033[1m🔌 MCP Command Help\033[0m
|
||||
──────────────────────────────────────
|
||||
|
||||
/mcp 列出所有 MCP 服务器状态
|
||||
/mcp connect <name> <cmd> [args] 连接到 MCP 服务器
|
||||
/mcp disconnect <name> 断开 MCP 服务器
|
||||
/mcp tools [server] 列出 MCP 工具
|
||||
/mcp resources [server] 列出 MCP 资源
|
||||
/mcp reload 从配置文件重新加载
|
||||
/mcp help 显示此帮助信息
|
||||
/mcp List all MCP server status
|
||||
/mcp connect <name> <cmd> [args] Connect to MCP server
|
||||
/mcp disconnect <name> Disconnect MCP server
|
||||
/mcp tools [server] List MCP tools
|
||||
/mcp resources [server] List MCP resources
|
||||
/mcp reload Reload from config file
|
||||
/mcp help Show this help
|
||||
|
||||
配置文件:
|
||||
项目级: .mcp.json
|
||||
全局: ~/.claude-code-java/mcp.json
|
||||
Config files:
|
||||
Project: .mcp.json
|
||||
Global: ~/.claude-code-java/mcp.json
|
||||
""";
|
||||
}
|
||||
|
||||
|
||||
@@ -56,13 +56,13 @@ public class MemoryCommand implements SlashCommand {
|
||||
/** 显示项目级 CLAUDE.md */
|
||||
private String showProjectMemory() {
|
||||
Path projectClaudeMd = Path.of(System.getProperty("user.dir"), "CLAUDE.md");
|
||||
return showMemoryFile(projectClaudeMd, "项目级");
|
||||
return showMemoryFile(projectClaudeMd, "Project");
|
||||
}
|
||||
|
||||
/** 显示用户级 CLAUDE.md */
|
||||
private String showUserMemory() {
|
||||
Path userClaudeMd = Path.of(System.getProperty("user.home"), ".claude", "CLAUDE.md");
|
||||
return showMemoryFile(userClaudeMd, "用户级");
|
||||
return showMemoryFile(userClaudeMd, "User");
|
||||
}
|
||||
|
||||
private String showMemoryFile(Path path, String level) {
|
||||
@@ -76,17 +76,17 @@ public class MemoryCommand implements SlashCommand {
|
||||
try {
|
||||
String content = Files.readString(path, StandardCharsets.UTF_8);
|
||||
if (content.isBlank()) {
|
||||
sb.append(AnsiStyle.dim(" (文件为空)\n"));
|
||||
sb.append(AnsiStyle.dim(" (File is empty)\n"));
|
||||
} else {
|
||||
content.lines().forEach(line -> sb.append(" ").append(line).append("\n"));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
sb.append(AnsiStyle.red(" ✗ 读取失败: " + e.getMessage() + "\n"));
|
||||
sb.append(AnsiStyle.red(" ✗ Read failed: " + e.getMessage() + "\n"));
|
||||
}
|
||||
} else {
|
||||
sb.append(AnsiStyle.dim(" (文件不存在)\n\n"));
|
||||
sb.append(AnsiStyle.dim(" 使用 /memory add <内容> 创建并添加内容\n"));
|
||||
sb.append(AnsiStyle.dim(" 或使用 /init 命令初始化\n"));
|
||||
sb.append(AnsiStyle.dim(" (File does not exist)\n\n"));
|
||||
sb.append(AnsiStyle.dim(" Use /memory add <content> to create and add content\n"));
|
||||
sb.append(AnsiStyle.dim(" Or use /init command to initialize\n"));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
@@ -95,7 +95,7 @@ public class MemoryCommand implements SlashCommand {
|
||||
/** 追加内容到项目级 CLAUDE.md */
|
||||
private String handleAdd(String content) {
|
||||
if (content.isEmpty()) {
|
||||
return AnsiStyle.yellow(" ⚠ 请提供要添加的内容:/memory add <内容>");
|
||||
return AnsiStyle.yellow(" ⚠ Please provide content: /memory add <content>");
|
||||
}
|
||||
|
||||
Path projectClaudeMd = Path.of(System.getProperty("user.dir"), "CLAUDE.md");
|
||||
@@ -105,7 +105,7 @@ public class MemoryCommand implements SlashCommand {
|
||||
Files.writeString(projectClaudeMd,
|
||||
"# CLAUDE.md\n\n" + content + "\n",
|
||||
StandardCharsets.UTF_8);
|
||||
return AnsiStyle.green(" ✓ 已创建 CLAUDE.md 并添加内容");
|
||||
return AnsiStyle.green(" ✓ Created CLAUDE.md and added content");
|
||||
}
|
||||
|
||||
// 追加内容
|
||||
@@ -113,9 +113,9 @@ public class MemoryCommand implements SlashCommand {
|
||||
String newContent = existing.endsWith("\n") ? existing + "\n" + content + "\n" : existing + "\n\n" + content + "\n";
|
||||
Files.writeString(projectClaudeMd, newContent, StandardCharsets.UTF_8);
|
||||
|
||||
return AnsiStyle.green(" ✓ 已追加内容到 CLAUDE.md");
|
||||
return AnsiStyle.green(" ✓ Content appended to CLAUDE.md");
|
||||
} catch (IOException e) {
|
||||
return AnsiStyle.red(" ✗ 写入失败: " + e.getMessage());
|
||||
return AnsiStyle.red(" ✗ Write failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,20 +138,20 @@ public class MemoryCommand implements SlashCommand {
|
||||
pb.inheritIO();
|
||||
Process p = pb.start();
|
||||
p.waitFor();
|
||||
return AnsiStyle.green(" ✓ 编辑器已关闭");
|
||||
return AnsiStyle.green(" ✓ Editor closed");
|
||||
}
|
||||
|
||||
// Windows: 尝试 notepad
|
||||
if (System.getProperty("os.name").toLowerCase().contains("win")) {
|
||||
ProcessBuilder pb = new ProcessBuilder("notepad", projectClaudeMd.toString());
|
||||
pb.start(); // 不等待
|
||||
return AnsiStyle.green(" ✓ 已用记事本打开 CLAUDE.md");
|
||||
return AnsiStyle.green(" ✓ Opened CLAUDE.md with Notepad");
|
||||
}
|
||||
|
||||
return AnsiStyle.yellow(" ⚠ 未找到编辑器。请设置 EDITOR 环境变量,或手动编辑:\n " + projectClaudeMd);
|
||||
return AnsiStyle.yellow(" ⚠ No editor found. Set EDITOR environment variable, or manually edit:\n " + projectClaudeMd);
|
||||
|
||||
} catch (Exception e) {
|
||||
return AnsiStyle.red(" ✗ 打开编辑器失败: " + e.getMessage());
|
||||
return AnsiStyle.red(" ✗ Failed to open editor: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public class PluginCommand implements SlashCommand {
|
||||
public String execute(String args, CommandContext context) {
|
||||
PluginManager manager = getPluginManager(context);
|
||||
if (manager == null) {
|
||||
return AnsiStyle.red(" ✗ 插件系统未初始化");
|
||||
return AnsiStyle.red(" ✗ Plugin system not initialized");
|
||||
}
|
||||
|
||||
String trimmed = (args == null) ? "" : args.trim();
|
||||
@@ -67,7 +67,7 @@ public class PluginCommand implements SlashCommand {
|
||||
case "unload" -> unloadPlugin(manager, subArgs);
|
||||
case "reload" -> reloadPlugins(manager);
|
||||
case "info" -> pluginInfo(manager, subArgs);
|
||||
default -> AnsiStyle.yellow(" 未知子命令: " + subCommand) + "\n"
|
||||
default -> AnsiStyle.yellow(" Unknown subcommand: " + subCommand) + "\n"
|
||||
+ usageHelp();
|
||||
};
|
||||
}
|
||||
@@ -96,12 +96,12 @@ public class PluginCommand implements SlashCommand {
|
||||
sb.append(String.format(" ID: %s | %s%n",
|
||||
AnsiStyle.cyan(p.id()),
|
||||
p.description()));
|
||||
sb.append(String.format(" 工具: %d | 命令: %d%n",
|
||||
sb.append(String.format(" Tools: %d | Commands: %d%n",
|
||||
p.getTools().size(),
|
||||
p.getCommands().size()));
|
||||
sb.append("\n");
|
||||
}
|
||||
sb.append(AnsiStyle.dim(String.format(" 共 %d 个插件", plugins.size()))).append("\n");
|
||||
sb.append(AnsiStyle.dim(String.format(" Total %d plugins", plugins.size()))).append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
@@ -111,15 +111,15 @@ public class PluginCommand implements SlashCommand {
|
||||
*/
|
||||
private String loadPlugin(PluginManager manager, String pathStr) {
|
||||
if (pathStr.isEmpty()) {
|
||||
return AnsiStyle.yellow(" 用法: /plugin load <jar-path>");
|
||||
return AnsiStyle.yellow(" Usage: /plugin load <jar-path>");
|
||||
}
|
||||
Path jarPath = Path.of(pathStr);
|
||||
boolean success = manager.loadPlugin(jarPath);
|
||||
if (success) {
|
||||
return AnsiStyle.green(" ✓ 插件加载成功: " + jarPath.getFileName());
|
||||
return AnsiStyle.green(" ✓ Plugin loaded: " + jarPath.getFileName());
|
||||
} else {
|
||||
return AnsiStyle.red(" ✗ 插件加载失败: " + jarPath.getFileName())
|
||||
+ "\n" + AnsiStyle.dim(" 请检查 JAR 是否包含有效的 Plugin-Class 属性");
|
||||
return AnsiStyle.red(" ✗ Plugin load failed: " + jarPath.getFileName())
|
||||
+ "\n" + AnsiStyle.dim(" Please check if JAR contains a valid Plugin-Class attribute");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,13 +128,13 @@ public class PluginCommand implements SlashCommand {
|
||||
*/
|
||||
private String unloadPlugin(PluginManager manager, String pluginId) {
|
||||
if (pluginId.isEmpty()) {
|
||||
return AnsiStyle.yellow(" 用法: /plugin unload <plugin-id>");
|
||||
return AnsiStyle.yellow(" Usage: /plugin unload <plugin-id>");
|
||||
}
|
||||
boolean success = manager.unload(pluginId);
|
||||
if (success) {
|
||||
return AnsiStyle.green(" ✓ 插件已卸载: " + pluginId);
|
||||
return AnsiStyle.green(" ✓ Plugin unloaded: " + pluginId);
|
||||
} else {
|
||||
return AnsiStyle.red(" ✗ 未找到插件: " + pluginId);
|
||||
return AnsiStyle.red(" ✗ Plugin not found: " + pluginId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ public class PluginCommand implements SlashCommand {
|
||||
manager.loadAll();
|
||||
int afterCount = manager.getPlugins().size();
|
||||
return AnsiStyle.green(
|
||||
String.format(" ✓ 插件已重载(之前: %d,现在: %d)", beforeCount, afterCount));
|
||||
String.format(" ✓ Plugins reloaded (before: %d, now: %d)", beforeCount, afterCount));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,12 +155,12 @@ public class PluginCommand implements SlashCommand {
|
||||
*/
|
||||
private String pluginInfo(PluginManager manager, String pluginId) {
|
||||
if (pluginId.isEmpty()) {
|
||||
return AnsiStyle.yellow(" 用法: /plugin info <plugin-id>");
|
||||
return AnsiStyle.yellow(" Usage: /plugin info <plugin-id>");
|
||||
}
|
||||
|
||||
PluginInfo info = manager.findPlugin(pluginId);
|
||||
if (info == null) {
|
||||
return AnsiStyle.red(" ✗ 未找到插件: " + pluginId);
|
||||
return AnsiStyle.red(" ✗ Plugin not found: " + pluginId);
|
||||
}
|
||||
|
||||
Plugin p = info.plugin();
|
||||
@@ -245,11 +245,11 @@ public class PluginCommand implements SlashCommand {
|
||||
*/
|
||||
private String usageHelp() {
|
||||
return AnsiStyle.dim("""
|
||||
用法:
|
||||
/plugin 列出所有插件
|
||||
/plugin load <path> 加载 JAR 插件
|
||||
/plugin unload <id> 卸载插件
|
||||
/plugin reload 重载所有插件
|
||||
/plugin info <id> 查看插件详情""");
|
||||
Usage:
|
||||
/plugin List all plugins
|
||||
/plugin load <path> Load JAR plugin
|
||||
/plugin unload <id> Unload plugin
|
||||
/plugin reload Reload all plugins
|
||||
/plugin info <id> View plugin details""");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,8 +41,8 @@ public class ResumeCommand implements SlashCommand {
|
||||
args = args == null ? "" : args.strip();
|
||||
|
||||
if (conversations.isEmpty()) {
|
||||
return AnsiStyle.yellow(" ⚠ 没有已保存的对话\n")
|
||||
+ AnsiStyle.dim(" 对话在退出时自动保存到 ~/.claude-code-java/conversations/");
|
||||
return AnsiStyle.yellow(" ⚠ No saved conversations\n")
|
||||
+ AnsiStyle.dim(" Conversations are auto-saved on exit to ~/.claude-code-java/conversations/");
|
||||
}
|
||||
|
||||
// /resume list —— 列出所有对话
|
||||
@@ -56,10 +56,10 @@ public class ResumeCommand implements SlashCommand {
|
||||
try {
|
||||
index = Integer.parseInt(args) - 1;
|
||||
if (index < 0 || index >= conversations.size()) {
|
||||
return AnsiStyle.red(" ✗ 无效序号(范围 1-" + conversations.size() + ")");
|
||||
return AnsiStyle.red(" ✗ Invalid index (range 1-" + conversations.size() + ")");
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
return AnsiStyle.yellow(" ⚠ 用法: /resume [序号] 或 /resume list");
|
||||
return AnsiStyle.yellow(" ⚠ Usage: /resume [index] or /resume list");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ public class ResumeCommand implements SlashCommand {
|
||||
List<Message> messages = persistence.loadFromFile(file);
|
||||
|
||||
if (messages.isEmpty()) {
|
||||
return AnsiStyle.red(" ✗ 加载对话失败: " + summary.filename());
|
||||
return AnsiStyle.red(" ✗ Failed to load conversation: " + summary.filename());
|
||||
}
|
||||
|
||||
// 替换当前消息历史
|
||||
@@ -77,12 +77,12 @@ public class ResumeCommand implements SlashCommand {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("\n");
|
||||
sb.append(AnsiStyle.green(" ✓ 对话已恢复\n"));
|
||||
sb.append(AnsiStyle.green(" ✓ Conversation restored\n"));
|
||||
sb.append(" ").append("─".repeat(50)).append("\n");
|
||||
sb.append(" ").append(AnsiStyle.bold("摘要: ")).append(summary.summary()).append("\n");
|
||||
sb.append(" ").append(AnsiStyle.bold("时间: ")).append(summary.savedAt()).append("\n");
|
||||
sb.append(" ").append(AnsiStyle.bold("消息数: ")).append(summary.messageCount()).append("\n");
|
||||
sb.append(" ").append(AnsiStyle.bold("目录: ")).append(AnsiStyle.dim(summary.workingDir())).append("\n");
|
||||
sb.append(" ").append(AnsiStyle.bold("Summary: ")).append(summary.summary()).append("\n");
|
||||
sb.append(" ").append(AnsiStyle.bold("Time: ")).append(summary.savedAt()).append("\n");
|
||||
sb.append(" ").append(AnsiStyle.bold("Messages: ")).append(summary.messageCount()).append("\n");
|
||||
sb.append(" ").append(AnsiStyle.bold("Dir: ")).append(AnsiStyle.dim(summary.workingDir())).append("\n");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
@@ -104,10 +104,10 @@ public class ResumeCommand implements SlashCommand {
|
||||
}
|
||||
|
||||
if (conversations.size() > maxShow) {
|
||||
sb.append(AnsiStyle.dim("\n ... 还有 " + (conversations.size() - maxShow) + " 个对话\n"));
|
||||
sb.append(AnsiStyle.dim("\n ... and " + (conversations.size() - maxShow) + " more conversations\n"));
|
||||
}
|
||||
|
||||
sb.append(AnsiStyle.dim("\n 使用 /resume [序号] 恢复指定对话\n"));
|
||||
sb.append(AnsiStyle.dim("\n Use /resume [index] to restore a conversation\n"));
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ public class ReviewCommand implements SlashCommand {
|
||||
@Override
|
||||
public String execute(String args, CommandContext context) {
|
||||
if (context.agentLoop() == null) {
|
||||
return AnsiStyle.red(" ✗ AgentLoop 不可用,无法执行代码审查。");
|
||||
return AnsiStyle.red(" ✗ AgentLoop unavailable, cannot perform code review.");
|
||||
}
|
||||
|
||||
String trimmedArgs = args != null ? args.trim() : "";
|
||||
@@ -55,16 +55,16 @@ public class ReviewCommand implements SlashCommand {
|
||||
|
||||
// 检查 diff 是否为空
|
||||
if (diffOutput.isBlank()) {
|
||||
return AnsiStyle.yellow(" ⚠ 没有检测到代码变更。") + "\n"
|
||||
+ AnsiStyle.dim(" 提示: 使用 --staged 审查已暂存的变更,或指定文件路径。");
|
||||
return AnsiStyle.yellow(" ⚠ No code changes detected.") + "\n"
|
||||
+ AnsiStyle.dim(" Tip: Use --staged to review staged changes, or specify a file path.");
|
||||
}
|
||||
|
||||
// 构建审查提示
|
||||
String reviewPrompt = buildReviewPrompt(trimmedArgs, diffOutput);
|
||||
|
||||
// 输出审查进行中的提示
|
||||
context.out().println(AnsiStyle.cyan(" 🔍 正在审查代码变更..."));
|
||||
context.out().println(AnsiStyle.dim(" diff 大小: " + diffOutput.lines().count() + " 行"));
|
||||
context.out().println(AnsiStyle.cyan(" 🔍 Reviewing code changes..."));
|
||||
context.out().println(AnsiStyle.dim(" diff size: " + diffOutput.lines().count() + " lines"));
|
||||
context.out().println();
|
||||
|
||||
// 发送给 AI 进行审查
|
||||
@@ -72,8 +72,8 @@ public class ReviewCommand implements SlashCommand {
|
||||
return result;
|
||||
|
||||
} catch (Exception e) {
|
||||
return AnsiStyle.red(" ✗ 代码审查失败: " + e.getMessage()) + "\n"
|
||||
+ AnsiStyle.dim(" 请确保当前目录是一个 Git 仓库。");
|
||||
return AnsiStyle.red(" ✗ Code review failed: " + e.getMessage()) + "\n"
|
||||
+ AnsiStyle.dim(" Please ensure the current directory is a Git repository.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ public class ReviewCommand implements SlashCommand {
|
||||
|
||||
int exitCode = process.waitFor();
|
||||
if (exitCode != 0) {
|
||||
throw new RuntimeException("git diff 执行失败 (exit=" + exitCode + "): " + errorOutput);
|
||||
throw new RuntimeException("git diff failed (exit=" + exitCode + "): " + errorOutput);
|
||||
}
|
||||
|
||||
return output;
|
||||
|
||||
@@ -38,21 +38,21 @@ public class RewindCommand implements SlashCommand {
|
||||
@Override
|
||||
public String execute(String args, CommandContext context) {
|
||||
if (context.agentLoop() == null) {
|
||||
return AnsiStyle.red(" ✗ AgentLoop 不可用。");
|
||||
return AnsiStyle.red(" ✗ AgentLoop unavailable.");
|
||||
}
|
||||
|
||||
// 解析要回滚的消息对数量
|
||||
int pairsToRemove = parseRewindCount(args);
|
||||
if (pairsToRemove < 0) {
|
||||
return AnsiStyle.red(" ✗ 无效的回滚数量。请输入一个正整数。") + "\n"
|
||||
+ AnsiStyle.dim(" 用法: /rewind [n] (n 为要移除的消息对数,默认为 1)");
|
||||
return AnsiStyle.red(" ✗ Invalid rewind count. Please enter a positive integer.") + "\n"
|
||||
+ AnsiStyle.dim(" Usage: /rewind [n] (n = number of message pairs to remove, default 1)");
|
||||
}
|
||||
|
||||
List<Message> currentHistory = context.agentLoop().getMessageHistory();
|
||||
int currentSize = currentHistory.size();
|
||||
|
||||
if (currentSize == 0) {
|
||||
return AnsiStyle.yellow(" ⚠ 对话历史为空,无法回滚。");
|
||||
return AnsiStyle.yellow(" ⚠ Conversation history is empty, cannot rewind.");
|
||||
}
|
||||
|
||||
// 计算需要移除的消息数量
|
||||
@@ -61,8 +61,8 @@ public class RewindCommand implements SlashCommand {
|
||||
// 如果要移除的消息数超过总消息数,则清除所有消息
|
||||
if (messagesToRemove >= currentSize) {
|
||||
context.agentLoop().replaceHistory(new ArrayList<>());
|
||||
return AnsiStyle.green(" ✓ 已清除全部 " + currentSize + " 条消息。") + "\n"
|
||||
+ AnsiStyle.dim(" (请求移除 " + pairsToRemove + " 对,实际清除全部消息)");
|
||||
return AnsiStyle.green(" ✓ Cleared all " + currentSize + " messages.") + "\n"
|
||||
+ AnsiStyle.dim(" (Requested " + pairsToRemove + " pairs, cleared all messages)");
|
||||
}
|
||||
|
||||
// 截断消息历史
|
||||
@@ -72,9 +72,9 @@ public class RewindCommand implements SlashCommand {
|
||||
|
||||
// 构建结果输出
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(AnsiStyle.green(" ✓ 已回滚 " + pairsToRemove + " 个消息对")).append("\n");
|
||||
sb.append(AnsiStyle.dim(" 移除: " + messagesToRemove + " 条消息")).append("\n");
|
||||
sb.append(AnsiStyle.dim(" 剩余: " + newSize + " 条消息")).append("\n");
|
||||
sb.append(AnsiStyle.green(" ✓ Rewound " + pairsToRemove + " message pairs")).append("\n");
|
||||
sb.append(AnsiStyle.dim(" Removed: " + messagesToRemove + " messages")).append("\n");
|
||||
sb.append(AnsiStyle.dim(" Remaining: " + newSize + " messages")).append("\n");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ public class SecurityReviewCommand implements SlashCommand {
|
||||
@Override
|
||||
public String execute(String args, CommandContext context) {
|
||||
if (context.agentLoop() == null) {
|
||||
return AnsiStyle.red(" ✗ AgentLoop 不可用,无法执行安全审查。");
|
||||
return AnsiStyle.red(" ✗ AgentLoop unavailable, cannot perform security review.");
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -53,13 +53,13 @@ public class SecurityReviewCommand implements SlashCommand {
|
||||
String diffOutput = executeGitDiff();
|
||||
|
||||
if (diffOutput.isBlank()) {
|
||||
return AnsiStyle.yellow(" ⚠ 没有检测到代码变更。") + "\n"
|
||||
+ AnsiStyle.dim(" git diff HEAD 未返回任何内容。请确认是否有提交记录。");
|
||||
return AnsiStyle.yellow(" ⚠ No code changes detected.") + "\n"
|
||||
+ AnsiStyle.dim(" git diff HEAD returned nothing. Please verify there are commits.");
|
||||
}
|
||||
|
||||
// 输出审查进行中的提示
|
||||
context.out().println(AnsiStyle.magenta(" 🔒 正在进行安全审查..."));
|
||||
context.out().println(AnsiStyle.dim(" diff 大小: " + diffOutput.lines().count() + " 行"));
|
||||
context.out().println(AnsiStyle.magenta(" 🔒 Performing security review..."));
|
||||
context.out().println(AnsiStyle.dim(" diff size: " + diffOutput.lines().count() + " lines"));
|
||||
context.out().println();
|
||||
|
||||
// 构建安全审查提示词
|
||||
@@ -70,8 +70,8 @@ public class SecurityReviewCommand implements SlashCommand {
|
||||
return result;
|
||||
|
||||
} catch (Exception e) {
|
||||
return AnsiStyle.red(" ✗ 安全审查失败: " + e.getMessage()) + "\n"
|
||||
+ AnsiStyle.dim(" 请确保当前目录是一个 Git 仓库且有提交历史。");
|
||||
return AnsiStyle.red(" ✗ Security review failed: " + e.getMessage()) + "\n"
|
||||
+ AnsiStyle.dim(" Please ensure the current directory is a Git repository with commit history.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ public class SecurityReviewCommand implements SlashCommand {
|
||||
|
||||
int exitCode = process.waitFor();
|
||||
if (exitCode != 0) {
|
||||
throw new RuntimeException("git diff HEAD 执行失败 (exit=" + exitCode + "): " + errorOutput);
|
||||
throw new RuntimeException("git diff HEAD failed (exit=" + exitCode + "): " + errorOutput);
|
||||
}
|
||||
|
||||
return output;
|
||||
|
||||
@@ -37,20 +37,20 @@ public class SkillsCommand implements SlashCommand {
|
||||
sb.append(" ").append("─".repeat(50)).append("\n\n");
|
||||
|
||||
if (skills.isEmpty()) {
|
||||
sb.append(AnsiStyle.dim(" (无可用技能)\n\n"));
|
||||
sb.append(AnsiStyle.dim(" 技能文件放置位置:\n"));
|
||||
sb.append(AnsiStyle.dim(" 用户级: ~/.claude/skills/*.md\n"));
|
||||
sb.append(AnsiStyle.dim(" 项目级: ./.claude/skills/*.md\n"));
|
||||
sb.append(AnsiStyle.dim(" 命令级: ./.claude/commands/*.md\n"));
|
||||
sb.append(AnsiStyle.dim(" (No available skills)\n\n"));
|
||||
sb.append(AnsiStyle.dim(" Skill file locations:\n"));
|
||||
sb.append(AnsiStyle.dim(" User: ~/.claude/skills/*.md\n"));
|
||||
sb.append(AnsiStyle.dim(" Project: ./.claude/skills/*.md\n"));
|
||||
sb.append(AnsiStyle.dim(" Command: ./.claude/commands/*.md\n"));
|
||||
} else {
|
||||
for (SkillLoader.Skill skill : skills) {
|
||||
sb.append(" ").append(AnsiStyle.cyan("▸ ")).append(AnsiStyle.bold(skill.name()));
|
||||
|
||||
// 来源标签
|
||||
String sourceLabel = switch (skill.source()) {
|
||||
case "user" -> AnsiStyle.dim(" [用户级]");
|
||||
case "project" -> AnsiStyle.dim(" [项目级]");
|
||||
case "command" -> AnsiStyle.dim(" [命令]");
|
||||
case "user" -> AnsiStyle.dim(" [user]");
|
||||
case "project" -> AnsiStyle.dim(" [project]");
|
||||
case "command" -> AnsiStyle.dim(" [command]");
|
||||
default -> AnsiStyle.dim(" [" + skill.source() + "]");
|
||||
};
|
||||
sb.append(sourceLabel).append("\n");
|
||||
@@ -64,7 +64,7 @@ public class SkillsCommand implements SlashCommand {
|
||||
sb.append(" ").append(AnsiStyle.dim("File: " + skill.filePath())).append("\n");
|
||||
sb.append("\n");
|
||||
}
|
||||
sb.append(AnsiStyle.dim(" 共 " + skills.size() + " 个技能\n"));
|
||||
sb.append(AnsiStyle.dim(" Total " + skills.size() + " skills\n"));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
|
||||
@@ -38,12 +38,12 @@ public class StatsCommand implements SlashCommand {
|
||||
@Override
|
||||
public String execute(String args, CommandContext context) {
|
||||
if (context.agentLoop() == null) {
|
||||
return AnsiStyle.red(" ✗ AgentLoop 不可用。");
|
||||
return AnsiStyle.red(" ✗ AgentLoop unavailable.");
|
||||
}
|
||||
|
||||
TokenTracker tracker = context.agentLoop().getTokenTracker();
|
||||
if (tracker == null) {
|
||||
return AnsiStyle.yellow(" ⚠ Token 追踪器不可用。");
|
||||
return AnsiStyle.yellow(" ⚠ Token tracker unavailable.");
|
||||
}
|
||||
|
||||
// 收集统计数据
|
||||
|
||||
@@ -43,7 +43,7 @@ public class TagCommand implements SlashCommand {
|
||||
@Override
|
||||
public String execute(String args, CommandContext context) {
|
||||
if (context.agentLoop() == null) {
|
||||
return AnsiStyle.red(" ✗ AgentLoop 不可用。");
|
||||
return AnsiStyle.red(" ✗ AgentLoop unavailable.");
|
||||
}
|
||||
|
||||
String trimmedArgs = args != null ? args.trim() : "";
|
||||
@@ -78,7 +78,7 @@ public class TagCommand implements SlashCommand {
|
||||
*/
|
||||
private String createTag(String tagName, CommandContext context) {
|
||||
if (tagName.isEmpty()) {
|
||||
return AnsiStyle.red(" ✗ 请指定标签名称。");
|
||||
return AnsiStyle.red(" ✗ Please specify tag name.");
|
||||
}
|
||||
|
||||
// 标签名称不能与子命令冲突(虽然 list/goto 已在 switch 中处理)
|
||||
@@ -88,9 +88,9 @@ public class TagCommand implements SlashCommand {
|
||||
boolean isOverwrite = tags.containsKey(tagName);
|
||||
tags.put(tagName, new TagInfo(position, timestamp));
|
||||
|
||||
String action = isOverwrite ? "已更新" : "已创建";
|
||||
return AnsiStyle.green(" ✓ 标签" + action + ": ") + AnsiStyle.bold(tagName) + "\n"
|
||||
+ AnsiStyle.dim(" 位置: 第 " + position + " 条消息 时间: " + timestamp);
|
||||
String action = isOverwrite ? "updated" : "created";
|
||||
return AnsiStyle.green(" ✓ Tag " + action + ": ") + AnsiStyle.bold(tagName) + "\n"
|
||||
+ AnsiStyle.dim(" Position: message " + position + " Time: " + timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,8 +101,8 @@ public class TagCommand implements SlashCommand {
|
||||
*/
|
||||
private String listTags(CommandContext context) {
|
||||
if (tags.isEmpty()) {
|
||||
return AnsiStyle.dim(" 没有保存的标签。") + "\n"
|
||||
+ AnsiStyle.dim(" 使用 /tag <name> 为当前位置打标签。");
|
||||
return AnsiStyle.dim(" No saved tags.") + "\n"
|
||||
+ AnsiStyle.dim(" Use /tag <name> to tag the current position.");
|
||||
}
|
||||
|
||||
int currentPosition = context.agentLoop().getMessageHistory().size();
|
||||
@@ -127,7 +127,7 @@ public class TagCommand implements SlashCommand {
|
||||
}
|
||||
|
||||
sb.append("\n")
|
||||
.append(AnsiStyle.dim(" 当前位置: " + currentPosition + " 条消息 | 共 " + tags.size() + " 个标签"))
|
||||
.append(AnsiStyle.dim(" Current position: " + currentPosition + " messages | Total " + tags.size() + " tags"))
|
||||
.append("\n");
|
||||
return sb.toString();
|
||||
}
|
||||
@@ -144,14 +144,14 @@ public class TagCommand implements SlashCommand {
|
||||
*/
|
||||
private String gotoTag(String tagName, CommandContext context) {
|
||||
if (tagName.isEmpty()) {
|
||||
return AnsiStyle.red(" ✗ 请指定标签名称。") + "\n"
|
||||
+ AnsiStyle.dim(" 用法: /tag goto <name>");
|
||||
return AnsiStyle.red(" ✗ Please specify tag name.") + "\n"
|
||||
+ AnsiStyle.dim(" Usage: /tag goto <name>");
|
||||
}
|
||||
|
||||
TagInfo info = tags.get(tagName);
|
||||
if (info == null) {
|
||||
return AnsiStyle.red(" ✗ 标签不存在: " + tagName) + "\n"
|
||||
+ AnsiStyle.dim(" 使用 /tag list 查看所有可用标签。");
|
||||
return AnsiStyle.red(" ✗ Tag not found: " + tagName) + "\n"
|
||||
+ AnsiStyle.dim(" Use /tag list to see all available tags.");
|
||||
}
|
||||
|
||||
List<Message> currentHistory = context.agentLoop().getMessageHistory();
|
||||
@@ -159,8 +159,8 @@ public class TagCommand implements SlashCommand {
|
||||
int targetPosition = info.position();
|
||||
|
||||
if (targetPosition >= currentSize) {
|
||||
return AnsiStyle.yellow(" ⚠ 标签位置 (" + targetPosition + ") 不小于当前消息数 ("
|
||||
+ currentSize + "),无需回溯。");
|
||||
return AnsiStyle.yellow(" ⚠ Tag position (" + targetPosition + ") is not less than current message count ("
|
||||
+ currentSize + "), no rewind needed.");
|
||||
}
|
||||
|
||||
// 截断到标签位置
|
||||
@@ -168,8 +168,8 @@ public class TagCommand implements SlashCommand {
|
||||
context.agentLoop().replaceHistory(truncated);
|
||||
|
||||
int removedCount = currentSize - targetPosition;
|
||||
return AnsiStyle.green(" ✓ 已回溯到标签: ") + AnsiStyle.bold(tagName) + "\n"
|
||||
+ AnsiStyle.dim(" 移除了 " + removedCount + " 条消息,当前消息数: " + targetPosition);
|
||||
return AnsiStyle.green(" ✓ Rewound to tag: ") + AnsiStyle.bold(tagName) + "\n"
|
||||
+ AnsiStyle.dim(" Removed " + removedCount + " messages, current count: " + targetPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,10 +179,10 @@ public class TagCommand implements SlashCommand {
|
||||
*/
|
||||
private String showUsage() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(AnsiStyle.bold("\n 🏷️ Tag — 对话位置标签\n\n"));
|
||||
sb.append(" ").append(AnsiStyle.cyan("/tag <name>")).append(" 为当前位置打标签\n");
|
||||
sb.append(" ").append(AnsiStyle.cyan("/tag list")).append(" 列出所有标签\n");
|
||||
sb.append(" ").append(AnsiStyle.cyan("/tag goto <name>")).append(" 回溯到指定标签位置\n");
|
||||
sb.append(AnsiStyle.bold("\n 🏷️ Tag — Conversation position tags\n\n"));
|
||||
sb.append(" ").append(AnsiStyle.cyan("/tag <name>")).append(" Tag current position\n");
|
||||
sb.append(" ").append(AnsiStyle.cyan("/tag list")).append(" List all tags\n");
|
||||
sb.append(" ").append(AnsiStyle.cyan("/tag goto <name>")).append(" Rewind to tag position\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user