From ff734d6b0d7d66bf64c683c0ca371fab368f94f8 Mon Sep 17 00:00:00 2001 From: liuzh Date: Thu, 2 Apr 2026 00:30:47 +0800 Subject: [PATCH] =?UTF-8?q?i18n:=20=E5=85=A8=E9=83=A8=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=8F=AF=E8=A7=81=E5=AD=97=E7=AC=A6=E4=B8=B2=E7=BB=9F=E4=B8=80?= =?UTF-8?q?=E4=B8=BA=E8=8B=B1=E6=96=87=EF=BC=8846=E4=B8=AA=E6=96=87?= =?UTF-8?q?=E4=BB=B6=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 所有Command/Tool/Core/MCP/Plugin中的中文提示改为英文 - Javadoc注释和行内注释保留中文不变 - AI提示词(compact/commit/review等)改为英文 - 编译验证通过 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../com/claudecode/cli/ClaudeCodeRunner.java | 2 +- .../claudecode/command/CommandRegistry.java | 2 +- .../command/impl/BranchCommand.java | 48 +++++----- .../command/impl/CommitCommand.java | 32 +++---- .../command/impl/CompactCommand.java | 36 +++---- .../claudecode/command/impl/CopyCommand.java | 12 +-- .../claudecode/command/impl/DiffCommand.java | 12 +-- .../command/impl/ExportCommand.java | 6 +- .../command/impl/HistoryCommand.java | 10 +- .../claudecode/command/impl/HooksCommand.java | 10 +- .../claudecode/command/impl/McpCommand.java | 94 +++++++++---------- .../command/impl/MemoryCommand.java | 30 +++--- .../command/impl/PluginCommand.java | 40 ++++---- .../command/impl/ResumeCommand.java | 24 ++--- .../command/impl/ReviewCommand.java | 16 ++-- .../command/impl/RewindCommand.java | 18 ++-- .../command/impl/SecurityReviewCommand.java | 16 ++-- .../command/impl/SkillsCommand.java | 18 ++-- .../claudecode/command/impl/StatsCommand.java | 4 +- .../claudecode/command/impl/TagCommand.java | 40 ++++---- .../java/com/claudecode/config/AppConfig.java | 6 +- .../claudecode/context/ClaudeMdLoader.java | 6 +- .../com/claudecode/context/GitContext.java | 4 +- .../com/claudecode/context/SkillLoader.java | 8 +- .../java/com/claudecode/core/AgentLoop.java | 20 ++-- .../core/ConversationPersistence.java | 12 +-- .../java/com/claudecode/core/HookManager.java | 10 +- .../java/com/claudecode/core/TaskManager.java | 12 +-- .../java/com/claudecode/mcp/McpClient.java | 54 +++++------ .../java/com/claudecode/mcp/McpManager.java | 64 ++++++------- .../com/claudecode/mcp/StdioTransport.java | 48 +++++----- .../claudecode/plugin/OutputStylePlugin.java | 34 +++---- .../com/claudecode/plugin/PluginContext.java | 6 +- .../com/claudecode/plugin/PluginManager.java | 40 ++++---- .../java/com/claudecode/repl/ReplSession.java | 32 +++---- .../claudecode/tool/ToolCallbackAdapter.java | 6 +- .../com/claudecode/tool/ToolRegistry.java | 6 +- .../com/claudecode/tool/impl/AgentTool.java | 8 +- .../tool/impl/AskUserQuestionTool.java | 10 +- .../com/claudecode/tool/impl/ConfigTool.java | 18 ++-- .../claudecode/tool/impl/McpToolBridge.java | 8 +- .../claudecode/tool/impl/TaskCreateTool.java | 10 +- .../com/claudecode/tool/impl/TaskGetTool.java | 8 +- .../claudecode/tool/impl/TaskListTool.java | 8 +- .../claudecode/tool/impl/TaskUpdateTool.java | 28 +++--- .../claudecode/tool/impl/WebSearchTool.java | 2 +- 46 files changed, 469 insertions(+), 469 deletions(-) diff --git a/src/main/java/com/claudecode/cli/ClaudeCodeRunner.java b/src/main/java/com/claudecode/cli/ClaudeCodeRunner.java index e9ff323..278acb8 100644 --- a/src/main/java/com/claudecode/cli/ClaudeCodeRunner.java +++ b/src/main/java/com/claudecode/cli/ClaudeCodeRunner.java @@ -24,7 +24,7 @@ public class ClaudeCodeRunner implements CommandLineRunner { @Override public void run(String... args) { - log.info("Claude Code (Java) 启动中..."); + log.info("Claude Code (Java) starting..."); replSession.start(); } } diff --git a/src/main/java/com/claudecode/command/CommandRegistry.java b/src/main/java/com/claudecode/command/CommandRegistry.java index ac6905c..ee5c164 100644 --- a/src/main/java/com/claudecode/command/CommandRegistry.java +++ b/src/main/java/com/claudecode/command/CommandRegistry.java @@ -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()); } /** 批量注册 */ diff --git a/src/main/java/com/claudecode/command/impl/BranchCommand.java b/src/main/java/com/claudecode/command/impl/BranchCommand.java index cd7fadc..2c0b354 100644 --- a/src/main/java/com/claudecode/command/impl/BranchCommand.java +++ b/src/main/java/com/claudecode/command/impl/BranchCommand.java @@ -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 "); + return AnsiStyle.red(" ✗ Please specify branch name.") + "\n" + + AnsiStyle.dim(" Usage: /branch save "); } List 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 "); + return AnsiStyle.red(" ✗ Please specify branch name.") + "\n" + + AnsiStyle.dim(" Usage: /branch load "); } 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 保存当前对话。"); + return AnsiStyle.dim(" No saved branches.") + "\n" + + AnsiStyle.dim(" Use /branch save 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 "); + return AnsiStyle.red(" ✗ Please specify branch name.") + "\n" + + AnsiStyle.dim(" Usage: /branch delete "); } 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 ")).append(" 保存当前对话为分支\n"); - sb.append(" ").append(AnsiStyle.cyan("/branch load ")).append(" 恢复到指定分支\n"); - sb.append(" ").append(AnsiStyle.cyan("/branch list")).append(" 列出所有分支\n"); - sb.append(" ").append(AnsiStyle.cyan("/branch delete ")).append(" 删除指定分支\n"); + sb.append(AnsiStyle.bold("\n 🌿 Branch — Conversation branch management\n\n")); + sb.append(" ").append(AnsiStyle.cyan("/branch save ")).append(" Save current conversation as branch\n"); + sb.append(" ").append(AnsiStyle.cyan("/branch load ")).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 ")).append(" Delete specified branch\n"); return sb.toString(); } diff --git a/src/main/java/com/claudecode/command/impl/CommitCommand.java b/src/main/java/com/claudecode/command/impl/CommitCommand.java index 54aa4f4..23c90a1 100644 --- a/src/main/java/com/claudecode/command/impl/CommitCommand.java +++ b/src/main/java/com/claudecode/command/impl/CommitCommand.java @@ -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: ``` diff --git a/src/main/java/com/claudecode/command/impl/CompactCommand.java b/src/main/java/com/claudecode/command/impl/CompactCommand.java index 91c181d..9b74646 100644 --- a/src/main/java/com/claudecode/command/impl/CompactCommand.java +++ b/src/main/java/com/claudecode/command/impl/CompactCommand.java @@ -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 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"); } } } diff --git a/src/main/java/com/claudecode/command/impl/CopyCommand.java b/src/main/java/com/claudecode/command/impl/CopyCommand.java index c74e278..29138e4 100644 --- a/src/main/java/com/claudecode/command/impl/CopyCommand.java +++ b/src/main/java/com/claudecode/command/impl/CopyCommand.java @@ -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()); } } } diff --git a/src/main/java/com/claudecode/command/impl/DiffCommand.java b/src/main/java/com/claudecode/command/impl/DiffCommand.java index 7e283dc..cf77664 100644 --- a/src/main/java/com/claudecode/command/impl/DiffCommand.java +++ b/src/main/java/com/claudecode/command/impl/DiffCommand.java @@ -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()); } } diff --git a/src/main/java/com/claudecode/command/impl/ExportCommand.java b/src/main/java/com/claudecode/command/impl/ExportCommand.java index 7a5c61e..1cef675 100644 --- a/src/main/java/com/claudecode/command/impl/ExportCommand.java +++ b/src/main/java/com/claudecode/command/impl/ExportCommand.java @@ -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()); } } diff --git a/src/main/java/com/claudecode/command/impl/HistoryCommand.java b/src/main/java/com/claudecode/command/impl/HistoryCommand.java index 0d66674..6b9b7a9 100644 --- a/src/main/java/com/claudecode/command/impl/HistoryCommand.java +++ b/src/main/java/com/claudecode/command/impl/HistoryCommand.java @@ -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(); } diff --git a/src/main/java/com/claudecode/command/impl/HooksCommand.java b/src/main/java/com/claudecode/command/impl/HooksCommand.java index af6d1f8..3e2f60f 100644 --- a/src/main/java/com/claudecode/command/impl/HooksCommand.java +++ b/src/main/java/com/claudecode/command/impl/HooksCommand.java @@ -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)"; }; } } diff --git a/src/main/java/com/claudecode/command/impl/McpCommand.java b/src/main/java/com/claudecode/command/impl/McpCommand.java index 97c9bdf..cba18f0 100644 --- a/src/main/java/com/claudecode/command/impl/McpCommand.java +++ b/src/main/java/com/claudecode/command/impl/McpCommand.java @@ -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 clients = manager.getClients(); if (clients.isEmpty()) { - sb.append(" 无已连接的 MCP 服务器\n\n"); - sb.append(AnsiStyle.dim(" 提示: 使用 /mcp connect [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 [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 [args...]"); + return AnsiStyle.red(" Usage: /mcp connect [args...]"); } String[] parts = args.split("\\s+"); if (parts.length < 2) { - return AnsiStyle.red(" 用法: /mcp connect [args...]"); + return AnsiStyle.red(" Usage: /mcp connect [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 "); + return AnsiStyle.red(" Usage: /mcp disconnect "); } 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 [args] 连接到 MCP 服务器 - /mcp disconnect 断开 MCP 服务器 - /mcp tools [server] 列出 MCP 工具 - /mcp resources [server] 列出 MCP 资源 - /mcp reload 从配置文件重新加载 - /mcp help 显示此帮助信息 + /mcp List all MCP server status + /mcp connect [args] Connect to MCP server + /mcp disconnect 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 """; } diff --git a/src/main/java/com/claudecode/command/impl/MemoryCommand.java b/src/main/java/com/claudecode/command/impl/MemoryCommand.java index b9a2177..0ebcf2f 100644 --- a/src/main/java/com/claudecode/command/impl/MemoryCommand.java +++ b/src/main/java/com/claudecode/command/impl/MemoryCommand.java @@ -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 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 "); } 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()); } } } diff --git a/src/main/java/com/claudecode/command/impl/PluginCommand.java b/src/main/java/com/claudecode/command/impl/PluginCommand.java index ea3266d..7a0125d 100644 --- a/src/main/java/com/claudecode/command/impl/PluginCommand.java +++ b/src/main/java/com/claudecode/command/impl/PluginCommand.java @@ -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 "); + return AnsiStyle.yellow(" Usage: /plugin load "); } 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 "); + return AnsiStyle.yellow(" Usage: /plugin unload "); } 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 "); + return AnsiStyle.yellow(" Usage: /plugin info "); } 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 加载 JAR 插件 - /plugin unload 卸载插件 - /plugin reload 重载所有插件 - /plugin info 查看插件详情"""); + Usage: + /plugin List all plugins + /plugin load Load JAR plugin + /plugin unload Unload plugin + /plugin reload Reload all plugins + /plugin info View plugin details"""); } } diff --git a/src/main/java/com/claudecode/command/impl/ResumeCommand.java b/src/main/java/com/claudecode/command/impl/ResumeCommand.java index 87f44e4..ebf9dc7 100644 --- a/src/main/java/com/claudecode/command/impl/ResumeCommand.java +++ b/src/main/java/com/claudecode/command/impl/ResumeCommand.java @@ -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 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(); } diff --git a/src/main/java/com/claudecode/command/impl/ReviewCommand.java b/src/main/java/com/claudecode/command/impl/ReviewCommand.java index d49fc9a..edb9260 100644 --- a/src/main/java/com/claudecode/command/impl/ReviewCommand.java +++ b/src/main/java/com/claudecode/command/impl/ReviewCommand.java @@ -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; diff --git a/src/main/java/com/claudecode/command/impl/RewindCommand.java b/src/main/java/com/claudecode/command/impl/RewindCommand.java index e0515ba..8b19c75 100644 --- a/src/main/java/com/claudecode/command/impl/RewindCommand.java +++ b/src/main/java/com/claudecode/command/impl/RewindCommand.java @@ -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 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(); } diff --git a/src/main/java/com/claudecode/command/impl/SecurityReviewCommand.java b/src/main/java/com/claudecode/command/impl/SecurityReviewCommand.java index 1f7f51e..2c19428 100644 --- a/src/main/java/com/claudecode/command/impl/SecurityReviewCommand.java +++ b/src/main/java/com/claudecode/command/impl/SecurityReviewCommand.java @@ -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; diff --git a/src/main/java/com/claudecode/command/impl/SkillsCommand.java b/src/main/java/com/claudecode/command/impl/SkillsCommand.java index e97437a..bf4b9ea 100644 --- a/src/main/java/com/claudecode/command/impl/SkillsCommand.java +++ b/src/main/java/com/claudecode/command/impl/SkillsCommand.java @@ -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(); diff --git a/src/main/java/com/claudecode/command/impl/StatsCommand.java b/src/main/java/com/claudecode/command/impl/StatsCommand.java index 7e6532b..df6c639 100644 --- a/src/main/java/com/claudecode/command/impl/StatsCommand.java +++ b/src/main/java/com/claudecode/command/impl/StatsCommand.java @@ -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."); } // 收集统计数据 diff --git a/src/main/java/com/claudecode/command/impl/TagCommand.java b/src/main/java/com/claudecode/command/impl/TagCommand.java index d7b5fff..3d9b093 100644 --- a/src/main/java/com/claudecode/command/impl/TagCommand.java +++ b/src/main/java/com/claudecode/command/impl/TagCommand.java @@ -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 为当前位置打标签。"); + return AnsiStyle.dim(" No saved tags.") + "\n" + + AnsiStyle.dim(" Use /tag 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 "); + return AnsiStyle.red(" ✗ Please specify tag name.") + "\n" + + AnsiStyle.dim(" Usage: /tag goto "); } 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 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 ")).append(" 为当前位置打标签\n"); - sb.append(" ").append(AnsiStyle.cyan("/tag list")).append(" 列出所有标签\n"); - sb.append(" ").append(AnsiStyle.cyan("/tag goto ")).append(" 回溯到指定标签位置\n"); + sb.append(AnsiStyle.bold("\n 🏷️ Tag — Conversation position tags\n\n")); + sb.append(" ").append(AnsiStyle.cyan("/tag ")).append(" Tag current position\n"); + sb.append(" ").append(AnsiStyle.cyan("/tag list")).append(" List all tags\n"); + sb.append(" ").append(AnsiStyle.cyan("/tag goto ")).append(" Rewind to tag position\n"); return sb.toString(); } diff --git a/src/main/java/com/claudecode/config/AppConfig.java b/src/main/java/com/claudecode/config/AppConfig.java index da73340..2b7a76e 100644 --- a/src/main/java/com/claudecode/config/AppConfig.java +++ b/src/main/java/com/claudecode/config/AppConfig.java @@ -56,7 +56,7 @@ public class AppConfig { try { manager.loadFromConfig(); } catch (Exception e) { - log.warn("MCP 配置加载失败(可忽略): {}", e.getMessage()); + log.warn("MCP config loading failed (ignorable): {}", e.getMessage()); } return manager; } @@ -168,10 +168,10 @@ public class AppConfig { @Qualifier("anthropicChatModel") ChatModel anthropicModel) { if ("anthropic".equalsIgnoreCase(provider)) { - log.info("使用 Anthropic 原生 API"); + log.info("Using Anthropic native API"); return anthropicModel; } else { - log.info("使用 OpenAI 兼容 API"); + log.info("Using OpenAI compatible API"); return openAiModel; } } diff --git a/src/main/java/com/claudecode/context/ClaudeMdLoader.java b/src/main/java/com/claudecode/context/ClaudeMdLoader.java index fa9bb27..89a67fd 100644 --- a/src/main/java/com/claudecode/context/ClaudeMdLoader.java +++ b/src/main/java/com/claudecode/context/ClaudeMdLoader.java @@ -62,7 +62,7 @@ public class ClaudeMdLoader { .sorted() .forEach(p -> loadFile(p, "rule").ifPresent(sections::add)); } catch (IOException e) { - log.debug("加载规则目录失败: {}", e.getMessage()); + log.debug("Failed to load rules directory: {}", e.getMessage()); } } @@ -80,11 +80,11 @@ public class ClaudeMdLoader { try { String content = Files.readString(path, StandardCharsets.UTF_8).strip(); if (!content.isEmpty()) { - log.debug("已加载 {} 级 CLAUDE.md: {}", level, path); + log.debug("Loaded {} level CLAUDE.md: {}", level, path); return java.util.Optional.of(content); } } catch (IOException e) { - log.warn("读取 {} 失败: {}", path, e.getMessage()); + log.warn("Failed to read {}: {}", path, e.getMessage()); } return java.util.Optional.empty(); } diff --git a/src/main/java/com/claudecode/context/GitContext.java b/src/main/java/com/claudecode/context/GitContext.java index cf74538..a92914a 100644 --- a/src/main/java/com/claudecode/context/GitContext.java +++ b/src/main/java/com/claudecode/context/GitContext.java @@ -36,7 +36,7 @@ public class GitContext { */ public GitContext collect() { if (!isGitRepo) { - log.debug("当前目录不是 Git 仓库: {}", projectDir); + log.debug("Current directory is not a Git repository: {}", projectDir); return this; } @@ -114,7 +114,7 @@ public class GitContext { return output.toString().stripTrailing(); } catch (Exception e) { - log.debug("Git 命令执行失败: {}", e.getMessage()); + log.debug("Git command execution failed: {}", e.getMessage()); return ""; } } diff --git a/src/main/java/com/claudecode/context/SkillLoader.java b/src/main/java/com/claudecode/context/SkillLoader.java index aa5e474..c33f42d 100644 --- a/src/main/java/com/claudecode/context/SkillLoader.java +++ b/src/main/java/com/claudecode/context/SkillLoader.java @@ -58,7 +58,7 @@ public class SkillLoader { Path commandsDir = projectDir.resolve(".claude").resolve("commands"); loadFromDirectory(commandsDir, "command"); - log.debug("共加载 {} 个技能", skills.size()); + log.debug("Loaded {} skills in total", skills.size()); return Collections.unmodifiableList(skills); } @@ -77,13 +77,13 @@ public class SkillLoader { try { Skill skill = parseSkillFile(p, source); skills.add(skill); - log.debug("加载技能: {} [{}] from {}", skill.name(), source, p.getFileName()); + log.debug("Loaded skill: {} [{}] from {}", skill.name(), source, p.getFileName()); } catch (IOException e) { - log.warn("加载技能文件失败: {}: {}", p, e.getMessage()); + log.warn("Failed to load skill file: {}: {}", p, e.getMessage()); } }); } catch (IOException e) { - log.debug("扫描技能目录失败: {}: {}", dir, e.getMessage()); + log.debug("Failed to scan skill directory: {}: {}", dir, e.getMessage()); } } diff --git a/src/main/java/com/claudecode/core/AgentLoop.java b/src/main/java/com/claudecode/core/AgentLoop.java index 58a833f..33c2760 100644 --- a/src/main/java/com/claudecode/core/AgentLoop.java +++ b/src/main/java/com/claudecode/core/AgentLoop.java @@ -146,7 +146,7 @@ public class AgentLoop { while (iteration < MAX_ITERATIONS) { iteration++; - log.debug("Agent 循环 第{}轮 ({})", iteration, streaming ? "流式" : "阻塞"); + log.debug("Agent loop iteration {} ({})", iteration, streaming ? "streaming" : "blocking"); Prompt prompt = new Prompt(List.copyOf(messageHistory), options); @@ -177,7 +177,7 @@ public class AgentLoop { // 无工具调用 → 结束 if (!result.assistant.hasToolCalls()) { - log.debug("无工具调用,循环结束(共{}轮)", iteration); + log.debug("No tool calls, loop ended (total {} iterations)", iteration); break; } @@ -186,8 +186,8 @@ public class AgentLoop { } if (iteration >= MAX_ITERATIONS) { - log.warn("Agent 循环已达最大迭代次数 {},强制终止", MAX_ITERATIONS); - lastAssistantText += "\n\n[WARNING: 达到最大循环次数限制]"; + log.warn("Agent loop reached max iterations {}, force stopping", MAX_ITERATIONS); + lastAssistantText += "\n\n[WARNING: Maximum loop iteration limit reached]"; } return lastAssistantText; @@ -256,7 +256,7 @@ public class AgentLoop { } catch (Exception e) { // 流式调用失败 → 降级到阻塞模式 - log.warn("流式调用失败,降级到阻塞模式: {}", e.getMessage()); + log.warn("Streaming call failed, falling back to blocking mode: {}", e.getMessage()); return blockingIteration(prompt); } @@ -290,7 +290,7 @@ public class AgentLoop { // PreToolUse Hook var preHookCtx = new HookManager.HookContext(toolName, parsedArgs); if (hookManager.execute(HookManager.HookType.PRE_TOOL_USE, preHookCtx) == HookManager.HookResult.ABORT) { - log.info("[{}] PreToolUse Hook 中止了执行", toolName); + log.info("[{}] PreToolUse Hook aborted execution", toolName); toolResponses.add(new ToolResponseMessage.ToolResponse(callId, toolName, "Aborted by hook")); continue; } @@ -313,12 +313,12 @@ public class AgentLoop { if (permitted) { result = adapter.call(toolArgs); } else { - result = "Permission denied: 用户拒绝了此操作"; - log.info("[{}] 用户拒绝工具执行", toolName); + result = "Permission denied: User rejected this operation"; + log.info("[{}] User denied tool execution", toolName); } } else { result = "Error: Unknown tool '" + toolName + "'"; - log.warn("未知工具: {}", toolName); + log.warn("Unknown tool: {}", toolName); } // PostToolUse Hook @@ -433,7 +433,7 @@ public class AgentLoop { } } catch (Exception e) { // thinking 提取失败不影响主流程 - log.debug("Thinking 内容提取异常(可忽略): {}", e.getMessage()); + log.debug("Thinking content extraction exception (can be ignored): {}", e.getMessage()); } } diff --git a/src/main/java/com/claudecode/core/ConversationPersistence.java b/src/main/java/com/claudecode/core/ConversationPersistence.java index 6ce7fee..9cf9b84 100644 --- a/src/main/java/com/claudecode/core/ConversationPersistence.java +++ b/src/main/java/com/claudecode/core/ConversationPersistence.java @@ -43,7 +43,7 @@ public class ConversationPersistence { try { Files.createDirectories(conversationsDir); } catch (IOException e) { - log.warn("无法创建对话存储目录: {}", e.getMessage()); + log.warn("Failed to create conversation storage directory: {}", e.getMessage()); } } @@ -76,10 +76,10 @@ public class ConversationPersistence { ); MAPPER.writeValue(file.toFile(), conv); - log.info("对话已保存: {}", file.getFileName()); + log.info("Conversation saved: {}", file.getFileName()); return file; } catch (IOException e) { - log.error("保存对话失败: {}", e.getMessage()); + log.error("Failed to save conversation: {}", e.getMessage()); return null; } } @@ -106,7 +106,7 @@ public class ConversationPersistence { .filter(Objects::nonNull) .toList(); } catch (IOException e) { - log.error("加载对话失败: {}", e.getMessage()); + log.error("Failed to load conversation: {}", e.getMessage()); return List.of(); } } @@ -131,11 +131,11 @@ public class ConversationPersistence { conv.messages().size() )); } catch (IOException e) { - log.debug("跳过无效对话文件: {}", file.getFileName()); + log.debug("Skipping invalid conversation file: {}", file.getFileName()); } }); } catch (IOException e) { - log.warn("列出对话失败: {}", e.getMessage()); + log.warn("Failed to list conversations: {}", e.getMessage()); } return summaries; diff --git a/src/main/java/com/claudecode/core/HookManager.java b/src/main/java/com/claudecode/core/HookManager.java index 0211380..9a9e592 100644 --- a/src/main/java/com/claudecode/core/HookManager.java +++ b/src/main/java/com/claudecode/core/HookManager.java @@ -39,7 +39,7 @@ public class HookManager { */ public void register(HookType type, String name, HookHandler handler) { hooks.add(new HookRegistration(type, name, handler, 0)); - log.debug("注册 Hook: {} [{}]", name, type); + log.debug("Registered Hook: {} [{}]", name, type); } /** @@ -47,7 +47,7 @@ public class HookManager { */ public void register(HookType type, String name, HookHandler handler, int priority) { hooks.add(new HookRegistration(type, name, handler, priority)); - log.debug("注册 Hook: {} [{}] priority={}", name, type, priority); + log.debug("Registered Hook: {} [{}] priority={}", name, type, priority); } /** @@ -72,15 +72,15 @@ public class HookManager { for (HookRegistration reg : matching) { try { - log.debug("执行 Hook: {} [{}]", reg.name(), type); + log.debug("Executing Hook: {} [{}]", reg.name(), type); HookResult result = reg.handler().handle(context); if (result == HookResult.ABORT) { - log.info("Hook [{}] 中止了操作", reg.name()); + log.info("Hook [{}] aborted the operation", reg.name()); return HookResult.ABORT; } } catch (Exception e) { - log.warn("Hook [{}] 执行异常: {}", reg.name(), e.getMessage()); + log.warn("Hook [{}] execution exception: {}", reg.name(), e.getMessage()); // Hook 异常不影响主流程 } } diff --git a/src/main/java/com/claudecode/core/TaskManager.java b/src/main/java/com/claudecode/core/TaskManager.java index e0b0b04..89cbe27 100644 --- a/src/main/java/com/claudecode/core/TaskManager.java +++ b/src/main/java/com/claudecode/core/TaskManager.java @@ -119,8 +119,8 @@ public class TaskManager { * @throws NullPointerException 若 description 或 work 为 null */ public String createTask(String description, Callable work) { - Objects.requireNonNull(description, "任务描述不能为 null"); - Objects.requireNonNull(work, "任务工作体不能为 null"); + Objects.requireNonNull(description, "Task description cannot be null"); + Objects.requireNonNull(work, "Task work body cannot be null"); String taskId = generateId(); Instant now = Instant.now(); @@ -162,7 +162,7 @@ public class TaskManager { */ public String createTask(String description, Callable work, Map metadata) { - Objects.requireNonNull(metadata, "元数据不能为 null"); + Objects.requireNonNull(metadata, "Metadata cannot be null"); String taskId = createTask(description, work); // 把元数据补充进去(创建时尚处于 PENDING/RUNNING 初期阶段) tasks.computeIfPresent(taskId, (id, old) -> new TaskInfo( @@ -194,7 +194,7 @@ public class TaskManager { * @return 生成的任务 ID */ public String createManualTask(String description, Map metadata) { - Objects.requireNonNull(description, "任务描述不能为 null"); + Objects.requireNonNull(description, "Task description cannot be null"); String taskId = generateId(); Instant now = Instant.now(); @@ -332,14 +332,14 @@ public class TaskManager { */ public String getSummary() { if (tasks.isEmpty()) { - return "当前没有任何任务。"; + return "No tasks at the moment."; } Map counts = tasks.values().stream() .collect(Collectors.groupingBy(TaskInfo::status, Collectors.counting())); StringBuilder sb = new StringBuilder(); - sb.append("任务汇总 (共 ").append(tasks.size()).append(" 个):\n"); + sb.append("Task summary (total ").append(tasks.size()).append("):\n"); for (TaskStatus status : TaskStatus.values()) { long count = counts.getOrDefault(status, 0L); if (count > 0) { diff --git a/src/main/java/com/claudecode/mcp/McpClient.java b/src/main/java/com/claudecode/mcp/McpClient.java index c75ee0c..076e99c 100644 --- a/src/main/java/com/claudecode/mcp/McpClient.java +++ b/src/main/java/com/claudecode/mcp/McpClient.java @@ -61,8 +61,8 @@ public class McpClient implements AutoCloseable { * @param transport 传输层实现 */ public McpClient(String serverName, McpTransport transport) { - this.serverName = Objects.requireNonNull(serverName, "服务器名称不能为空"); - this.transport = Objects.requireNonNull(transport, "传输层不能为空"); + this.serverName = Objects.requireNonNull(serverName, "Server name cannot be null"); + this.transport = Objects.requireNonNull(transport, "Transport cannot be null"); } /** @@ -79,7 +79,7 @@ public class McpClient implements AutoCloseable { * @throws McpException 初始化失败 */ public void initialize() throws McpException { - log.info("正在初始化 MCP 服务器 '{}'...", serverName); + log.info("Initializing MCP server '{}'...", serverName); // 1. 发送 initialize 请求 int initId = nextId(); @@ -101,7 +101,7 @@ public class McpClient implements AutoCloseable { try { response = transport.sendRequest(MAPPER.writeValueAsString(initRequest)); } catch (Exception e) { - throw new McpException("MCP initialize 请求失败: " + e.getMessage(), e); + throw new McpException("MCP initialize request failed: " + e.getMessage(), e); } // 2. 解析服务器能力 @@ -111,9 +111,9 @@ public class McpClient implements AutoCloseable { serverInfo = result.get("serverInfo"); String serverVersion = result.has("protocolVersion") ? result.get("protocolVersion").asText() : "unknown"; - log.info("MCP 服务器 '{}' 协议版本: {}", serverName, serverVersion); + log.info("MCP server '{}' protocol version: {}", serverName, serverVersion); if (serverInfo != null) { - log.info("MCP 服务器信息: {}", serverInfo); + log.info("MCP server info: {}", serverInfo); } } @@ -125,7 +125,7 @@ public class McpClient implements AutoCloseable { try { transport.sendNotification(MAPPER.writeValueAsString(initializedNotif)); } catch (Exception e) { - throw new McpException("发送 initialized 通知失败: " + e.getMessage(), e); + throw new McpException("Failed to send initialized notification: " + e.getMessage(), e); } // 4. 发现工具 @@ -135,7 +135,7 @@ public class McpClient implements AutoCloseable { discoverResources(); initialized = true; - log.info("MCP 服务器 '{}' 初始化完成: {} 个工具, {} 个资源", + log.info("MCP server '{}' initialization complete: {} tools, {} resources", serverName, tools.size(), resources.size()); } @@ -149,7 +149,7 @@ public class McpClient implements AutoCloseable { && serverCapabilities.get("tools").isObject()) { // 服务器声明支持工具 } else if (serverCapabilities != null && !serverCapabilities.has("tools")) { - log.debug("MCP 服务器 '{}' 未声明 tools 能力,尝试发现工具", serverName); + log.debug("MCP server '{}' did not declare tools capability, attempting discovery", serverName); } int id = nextId(); @@ -173,19 +173,19 @@ public class McpClient implements AutoCloseable { JsonNode inputSchema = toolNode.get("inputSchema"); tools.put(name, new McpTool(name, description, inputSchema)); - log.debug("发现 MCP 工具: {} - {}", name, description); + log.debug("Discovered MCP tool: {} - {}", name, description); } } } } catch (McpException e) { // tools/list 可能不被支持,记录警告但不中断初始化 if (e.isJsonRpcError() && e.getErrorCode() == -32601) { - log.debug("MCP 服务器 '{}' 不支持 tools/list", serverName); + log.debug("MCP server '{}' does not support tools/list", serverName); } else { - log.warn("发现 MCP 工具失败: {}", e.getMessage()); + log.warn("Failed to discover MCP tools: {}", e.getMessage()); } } catch (Exception e) { - log.warn("发现 MCP 工具时序列化异常: {}", e.getMessage()); + log.warn("MCP tool discovery serialization exception: {}", e.getMessage()); } } @@ -199,7 +199,7 @@ public class McpClient implements AutoCloseable { && serverCapabilities.get("resources").isObject()) { // 服务器声明支持资源 } else if (serverCapabilities != null && !serverCapabilities.has("resources")) { - log.debug("MCP 服务器 '{}' 未声明 resources 能力,跳过资源发现", serverName); + log.debug("MCP server '{}' did not declare resources capability, skipping discovery", serverName); return; } @@ -226,18 +226,18 @@ public class McpClient implements AutoCloseable { ? resNode.get("mimeType").asText() : "text/plain"; resources.put(uri, new McpResource(uri, name, description, mimeType)); - log.debug("发现 MCP 资源: {} ({})", name, uri); + log.debug("Discovered MCP resource: {} ({})", name, uri); } } } } catch (McpException e) { if (e.isJsonRpcError() && e.getErrorCode() == -32601) { - log.debug("MCP 服务器 '{}' 不支持 resources/list", serverName); + log.debug("MCP server '{}' does not support resources/list", serverName); } else { - log.warn("发现 MCP 资源失败: {}", e.getMessage()); + log.warn("Failed to discover MCP resources: {}", e.getMessage()); } } catch (Exception e) { - log.warn("发现 MCP 资源时序列化异常: {}", e.getMessage()); + log.warn("MCP resource discovery serialization exception: {}", e.getMessage()); } } @@ -251,10 +251,10 @@ public class McpClient implements AutoCloseable { */ public String callTool(String toolName, Map arguments) throws McpException { if (!initialized) { - throw new McpException("MCP 客户端尚未初始化"); + throw new McpException("MCP client not yet initialized"); } if (!tools.containsKey(toolName)) { - throw new McpException("MCP 工具不存在: " + toolName); + throw new McpException("MCP tool does not exist: " + toolName); } int id = nextId(); @@ -269,7 +269,7 @@ public class McpClient implements AutoCloseable { ); try { - log.debug("调用 MCP 工具: {} (参数: {})", toolName, arguments); + log.debug("Calling MCP tool: {} (args: {})", toolName, arguments); JsonNode response = transport.sendRequest(MAPPER.writeValueAsString(request)); JsonNode result = response.get("result"); @@ -292,7 +292,7 @@ public class McpClient implements AutoCloseable { // 检查 isError 标志 if (result.has("isError") && result.get("isError").asBoolean()) { - throw new McpException("MCP 工具 '" + toolName + "' 执行出错: " + sb); + throw new McpException("MCP tool '" + toolName + "' execution error: " + sb); } return sb.toString(); @@ -304,7 +304,7 @@ public class McpClient implements AutoCloseable { } catch (McpException e) { throw e; } catch (Exception e) { - throw new McpException("调用 MCP 工具 '" + toolName + "' 失败: " + e.getMessage(), e); + throw new McpException("Failed to call MCP tool '" + toolName + "': " + e.getMessage(), e); } } @@ -317,7 +317,7 @@ public class McpClient implements AutoCloseable { */ public String readResource(String uri) throws McpException { if (!initialized) { - throw new McpException("MCP 客户端尚未初始化"); + throw new McpException("MCP client not yet initialized"); } int id = nextId(); @@ -329,7 +329,7 @@ public class McpClient implements AutoCloseable { ); try { - log.debug("读取 MCP 资源: {}", uri); + log.debug("Reading MCP resource: {}", uri); JsonNode response = transport.sendRequest(MAPPER.writeValueAsString(request)); JsonNode result = response.get("result"); @@ -356,7 +356,7 @@ public class McpClient implements AutoCloseable { } catch (McpException e) { throw e; } catch (Exception e) { - throw new McpException("读取 MCP 资源 '" + uri + "' 失败: " + e.getMessage(), e); + throw new McpException("Failed to read MCP resource '" + uri + "': " + e.getMessage(), e); } } @@ -415,7 +415,7 @@ public class McpClient implements AutoCloseable { tools.clear(); resources.clear(); transport.close(); - log.info("MCP 客户端 '{}' 已关闭", serverName); + log.info("MCP client '{}' closed", serverName); } /** 生成下一个 JSON-RPC 请求 ID */ diff --git a/src/main/java/com/claudecode/mcp/McpManager.java b/src/main/java/com/claudecode/mcp/McpManager.java index 83e4d35..f327d92 100644 --- a/src/main/java/com/claudecode/mcp/McpManager.java +++ b/src/main/java/com/claudecode/mcp/McpManager.java @@ -69,17 +69,17 @@ public class McpManager implements AutoCloseable { // 项目级配置 Path projectConfig = Path.of(System.getProperty("user.dir"), PROJECT_CONFIG); if (Files.exists(projectConfig)) { - loadConfigFile(projectConfig, "项目级"); + loadConfigFile(projectConfig, "project"); } // 全局配置 Path globalConfig = Path.of(System.getProperty("user.home"), GLOBAL_CONFIG); if (Files.exists(globalConfig)) { - loadConfigFile(globalConfig, "全局"); + loadConfigFile(globalConfig, "global"); } if (clients.isEmpty()) { - log.debug("未找到 MCP 配置文件或无服务器定义"); + log.debug("No MCP config file found or no server definitions"); } } @@ -87,7 +87,7 @@ public class McpManager implements AutoCloseable { * 加载单个配置文件中的 MCP 服务器定义。 */ private void loadConfigFile(Path configPath, String label) { - log.info("加载 {} MCP 配置: {}", label, configPath); + log.info("Loading {} MCP config: {}", label, configPath); try { String content = Files.readString(configPath); @@ -95,7 +95,7 @@ public class McpManager implements AutoCloseable { JsonNode serversNode = root.get("servers"); if (serversNode == null || !serversNode.isObject()) { - log.warn("{} 配置文件缺少 'servers' 字段: {}", label, configPath); + log.warn("{} config file missing 'servers' field: {}", label, configPath); return; } @@ -107,7 +107,7 @@ public class McpManager implements AutoCloseable { // 跳过已存在的服务器(项目级优先于全局) if (clients.containsKey(name)) { - log.debug("MCP 服务器 '{}' 已连接,跳过 {} 配置中的重复定义", name, label); + log.debug("MCP server '{}' already connected, skipping duplicate definition in {} config", name, label); continue; } @@ -132,11 +132,11 @@ public class McpManager implements AutoCloseable { connect(name, command, args, env); } catch (Exception e) { - log.error("从配置连接 MCP 服务器 '{}' 失败: {}", name, e.getMessage()); + log.error("Failed to connect MCP server '{}' from config: {}", name, e.getMessage()); } } } catch (IOException e) { - log.error("读取 MCP 配置文件失败: {}", configPath, e); + log.error("Failed to read MCP config file: {}", configPath, e); } } @@ -154,15 +154,15 @@ public class McpManager implements AutoCloseable { throws McpException { // 如果已存在,先断开 if (clients.containsKey(name)) { - log.info("MCP 服务器 '{}' 已存在,先断开旧连接", name); + log.info("MCP server '{}' already exists, disconnecting old connection", name); try { disconnect(name); } catch (Exception e) { - log.warn("断开旧 MCP 连接 '{}' 时异常: {}", name, e.getMessage()); + log.warn("Exception disconnecting old MCP connection '{}': {}", name, e.getMessage()); } } - log.info("连接 MCP 服务器 '{}': {} {}", name, command, String.join(" ", args)); + log.info("Connecting MCP server '{}': {} {}", name, command, String.join(" ", args)); // 创建传输层并启动(确保初始化失败时清理资源) StdioTransport transport = new StdioTransport(command, args, env); @@ -179,7 +179,7 @@ public class McpManager implements AutoCloseable { e.addSuppressed(suppressed); } throw (e instanceof McpException mcp) ? mcp - : new McpException("连接 MCP 服务器 '" + name + "' 失败: " + e.getMessage(), e); + : new McpException("Failed to connect MCP server '" + name + "': " + e.getMessage(), e); } // 注册客户端 @@ -189,13 +189,13 @@ public class McpManager implements AutoCloseable { for (McpClient.McpTool tool : client.getTools()) { String existingServer = toolToServer.get(tool.name()); if (existingServer != null) { - log.warn("MCP 工具名称冲突: '{}' 同时存在于服务器 '{}' 和 '{}',使用后者", + log.warn("MCP tool name conflict: '{}' exists in both server '{}' and '{}', using latter", tool.name(), existingServer, name); } toolToServer.put(tool.name(), name); } - log.info("MCP 服务器 '{}' 连接成功", name); + log.info("MCP server '{}' connected successfully", name); return client; } @@ -208,7 +208,7 @@ public class McpManager implements AutoCloseable { public void disconnect(String name) throws McpException { McpClient client = clients.remove(name); if (client == null) { - throw new McpException("MCP 服务器 '" + name + "' 不存在"); + throw new McpException("MCP server '" + name + "' does not exist"); } // 清理工具映射 @@ -216,9 +216,9 @@ public class McpManager implements AutoCloseable { try { client.close(); - log.info("MCP 服务器 '{}' 已断开", name); + log.info("MCP server '{}' disconnected", name); } catch (Exception e) { - throw new McpException("断开 MCP 服务器 '" + name + "' 时异常: " + e.getMessage(), e); + throw new McpException("Exception disconnecting MCP server '" + name + "': " + e.getMessage(), e); } } @@ -302,7 +302,7 @@ public class McpManager implements AutoCloseable { public String callTool(String toolName, Map args) throws McpException { String serverName = toolToServer.get(toolName); if (serverName == null) { - throw new McpException("未找到 MCP 工具: " + toolName); + throw new McpException("MCP tool not found: " + toolName); } return callTool(serverName, toolName, args); } @@ -320,10 +320,10 @@ public class McpManager implements AutoCloseable { throws McpException { McpClient client = clients.get(serverName); if (client == null) { - throw new McpException("MCP 服务器 '" + serverName + "' 不存在"); + throw new McpException("MCP server '" + serverName + "' does not exist"); } if (!client.isInitialized()) { - throw new McpException("MCP 服务器 '" + serverName + "' 尚未初始化"); + throw new McpException("MCP server '" + serverName + "' not yet initialized"); } return client.callTool(toolName, args); } @@ -344,7 +344,7 @@ public class McpManager implements AutoCloseable { * 先断开所有已有连接,再重新加载配置。 */ public void reload() { - log.info("重新加载 MCP 配置..."); + log.info("Reloading MCP config..."); // 断开所有现有连接 List serverNames = new ArrayList<>(clients.keySet()); @@ -352,13 +352,13 @@ public class McpManager implements AutoCloseable { try { disconnect(name); } catch (Exception e) { - log.warn("重载时断开 MCP 服务器 '{}' 失败: {}", name, e.getMessage()); + log.warn("Failed to disconnect MCP server '{}' during reload: {}", name, e.getMessage()); } } // 重新加载 loadFromConfig(); - log.info("MCP 配置重载完成: {} 个服务器已连接", clients.size()); + log.info("MCP config reload complete: {} servers connected", clients.size()); } /** @@ -368,7 +368,7 @@ public class McpManager implements AutoCloseable { */ public String getSummary() { if (clients.isEmpty()) { - return " 无已连接的 MCP 服务器"; + return " No connected MCP servers"; } StringBuilder sb = new StringBuilder(); @@ -378,14 +378,14 @@ public class McpManager implements AutoCloseable { String status; if (client.isConnected() && client.isInitialized()) { - status = "✅ 已连接"; + status = "✅ Connected"; } else if (client.isConnected()) { - status = "🔄 连接中"; + status = "🔄 Connecting"; } else { - status = "❌ 已断开"; + status = "❌ Disconnected"; } - sb.append(String.format(" %-20s %s (%d 工具, %d 资源)%n", + sb.append(String.format(" %-20s %s (%d tools, %d resources)%n", name, status, client.getTools().size(), client.getResources().size())); } return sb.toString().stripTrailing(); @@ -393,7 +393,7 @@ public class McpManager implements AutoCloseable { @Override public void close() throws Exception { - log.info("关闭所有 MCP 连接..."); + log.info("Closing all MCP connections..."); List errors = new ArrayList<>(); for (Map.Entry entry : clients.entrySet()) { @@ -401,18 +401,18 @@ public class McpManager implements AutoCloseable { entry.getValue().close(); } catch (Exception e) { errors.add(e); - log.error("关闭 MCP 服务器 '{}' 时异常: {}", entry.getKey(), e.getMessage()); + log.error("Exception closing MCP server '{}': {}", entry.getKey(), e.getMessage()); } } clients.clear(); toolToServer.clear(); if (!errors.isEmpty()) { - McpException ex = new McpException("关闭 MCP 管理器时有 " + errors.size() + " 个错误"); + McpException ex = new McpException("Errors closing MCP manager: " + errors.size() + " errors"); errors.forEach(ex::addSuppressed); throw ex; } - log.info("所有 MCP 连接已关闭"); + log.info("All MCP connections closed"); } } diff --git a/src/main/java/com/claudecode/mcp/StdioTransport.java b/src/main/java/com/claudecode/mcp/StdioTransport.java index 90e3b38..244420d 100644 --- a/src/main/java/com/claudecode/mcp/StdioTransport.java +++ b/src/main/java/com/claudecode/mcp/StdioTransport.java @@ -85,7 +85,7 @@ public class StdioTransport implements McpTransport { cmdList.add(command); cmdList.addAll(args); - log.info("启动 MCP 服务器进程: {}", String.join(" ", cmdList)); + log.info("Starting MCP server process: {}", String.join(" ", cmdList)); ProcessBuilder pb = new ProcessBuilder(cmdList); pb.redirectErrorStream(false); // stderr 单独处理 @@ -108,10 +108,10 @@ public class StdioTransport implements McpTransport { stderrThread = Thread.ofVirtual().name("mcp-stdio-stderr").start(this::stderrLoop); connected = true; - log.info("MCP 服务器进程已启动 (PID: {})", process.pid()); + log.info("MCP server process started (PID: {})", process.pid()); } catch (IOException e) { - throw new McpException("启动 MCP 服务器进程失败: " + e.getMessage(), e); + throw new McpException("Failed to start MCP server process: " + e.getMessage(), e); } } @@ -133,18 +133,18 @@ public class StdioTransport implements McpTransport { JsonNode message = MAPPER.readTree(line); handleMessage(message); } catch (Exception e) { - log.warn("解析 MCP 响应失败: {}", line, e); + log.warn("Failed to parse MCP response: {}", line, e); } } } catch (IOException e) { if (connected) { - log.warn("MCP stdout 读取中断: {}", e.getMessage()); + log.warn("MCP stdout read interrupted: {}", e.getMessage()); } } finally { connected = false; // 清理所有等待中的请求 pendingRequests.forEach((id, future) -> - future.completeExceptionally(new McpException("MCP 连接已断开"))); + future.completeExceptionally(new McpException("MCP connection disconnected"))); pendingRequests.clear(); } } @@ -182,19 +182,19 @@ public class StdioTransport implements McpTransport { if (future != null) { future.complete(message); } else { - log.warn("收到未匹配的 MCP 响应 (id={}): {}", id, message); + log.warn("Received unmatched MCP response (id={}): {}", id, message); } } else { // 服务器主动通知(如 notifications/tools/list_changed) String method = message.has("method") ? message.get("method").asText() : "unknown"; - log.debug("收到 MCP 服务器通知: {}", method); + log.debug("Received MCP server notification: {}", method); } } @Override public JsonNode sendRequest(String jsonRpcRequest) throws McpException { if (!connected) { - throw new McpException("MCP 传输层未连接"); + throw new McpException("MCP transport not connected"); } String id = null; @@ -203,7 +203,7 @@ public class StdioTransport implements McpTransport { JsonNode requestNode = MAPPER.readTree(jsonRpcRequest); JsonNode idNode = requestNode.get("id"); if (idNode == null || idNode.isNull()) { - throw new McpException("JSON-RPC 请求缺少 id 字段"); + throw new McpException("JSON-RPC request missing id field"); } id = idNode.asText(); @@ -218,7 +218,7 @@ public class StdioTransport implements McpTransport { processStdin.flush(); } - log.debug("发送 MCP 请求 (id={}): {}", id, truncate(jsonRpcRequest, 200)); + log.debug("Sent MCP request (id={}): {}", id, truncate(jsonRpcRequest, 200)); // 等待响应 JsonNode response = future.get(DEFAULT_TIMEOUT_SECONDS, TimeUnit.SECONDS); @@ -227,8 +227,8 @@ public class StdioTransport implements McpTransport { JsonNode errorNode = response.get("error"); if (errorNode != null && !errorNode.isNull()) { int code = errorNode.has("code") ? errorNode.get("code").asInt() : -1; - String msg = errorNode.has("message") ? errorNode.get("message").asText() : "未知错误"; - throw new McpException("MCP 服务器返回错误: " + msg, code); + String msg = errorNode.has("message") ? errorNode.get("message").asText() : "Unknown error"; + throw new McpException("MCP server returned error: " + msg, code); } return response; @@ -236,15 +236,15 @@ public class StdioTransport implements McpTransport { } catch (McpException e) { throw e; } catch (TimeoutException e) { - throw new McpException("MCP 请求超时 (" + DEFAULT_TIMEOUT_SECONDS + "s)", e); + throw new McpException("MCP request timeout (" + DEFAULT_TIMEOUT_SECONDS + "s)", e); } catch (ExecutionException e) { Throwable cause = e.getCause(); if (cause instanceof McpException mcp) { throw mcp; } - throw new McpException("MCP 请求执行异常: " + cause.getMessage(), cause); + throw new McpException("MCP request execution exception: " + cause.getMessage(), cause); } catch (Exception e) { - throw new McpException("MCP 请求发送失败: " + e.getMessage(), e); + throw new McpException("MCP request send failed: " + e.getMessage(), e); } finally { // 无论成功、超时或异常,都清理待处理请求,防止内存泄漏 if (id != null) { @@ -256,7 +256,7 @@ public class StdioTransport implements McpTransport { @Override public void sendNotification(String jsonRpcNotification) throws McpException { if (!connected) { - throw new McpException("MCP 传输层未连接"); + throw new McpException("MCP transport not connected"); } try { @@ -265,9 +265,9 @@ public class StdioTransport implements McpTransport { processStdin.newLine(); processStdin.flush(); } - log.debug("发送 MCP 通知: {}", truncate(jsonRpcNotification, 200)); + log.debug("Sent MCP notification: {}", truncate(jsonRpcNotification, 200)); } catch (IOException e) { - throw new McpException("MCP 通知发送失败: " + e.getMessage(), e); + throw new McpException("MCP notification send failed: " + e.getMessage(), e); } } @@ -279,14 +279,14 @@ public class StdioTransport implements McpTransport { @Override public void close() throws Exception { connected = false; - log.info("关闭 MCP StdIO 传输..."); + log.info("Closing MCP StdIO transport..."); // 关闭 stdin(通知服务器退出) if (processStdin != null) { try { processStdin.close(); } catch (IOException e) { - log.debug("关闭 stdin 时异常: {}", e.getMessage()); + log.debug("Exception closing stdin: {}", e.getMessage()); } } @@ -294,7 +294,7 @@ public class StdioTransport implements McpTransport { if (process != null && process.isAlive()) { boolean exited = process.waitFor(5, TimeUnit.SECONDS); if (!exited) { - log.warn("MCP 服务器进程未在 5s 内退出,强制终止"); + log.warn("MCP server process did not exit within 5s, force terminating"); process.destroyForcibly(); process.waitFor(3, TimeUnit.SECONDS); } @@ -310,10 +310,10 @@ public class StdioTransport implements McpTransport { // 清理待处理请求 pendingRequests.forEach((id, future) -> - future.completeExceptionally(new McpException("MCP 传输已关闭"))); + future.completeExceptionally(new McpException("MCP transport closed"))); pendingRequests.clear(); - log.info("MCP StdIO 传输已关闭"); + log.info("MCP StdIO transport closed"); } /** diff --git a/src/main/java/com/claudecode/plugin/OutputStylePlugin.java b/src/main/java/com/claudecode/plugin/OutputStylePlugin.java index 621fb05..ff57ca2 100644 --- a/src/main/java/com/claudecode/plugin/OutputStylePlugin.java +++ b/src/main/java/com/claudecode/plugin/OutputStylePlugin.java @@ -55,13 +55,13 @@ public class OutputStylePlugin implements Plugin { @Override public String description() { - return "自定义输出样式"; + return "Custom output styles"; } @Override public void initialize(PluginContext context) { this.context = context; - context.getLogger().info("输出样式插件已初始化,当前样式: {}", currentStyle.get()); + context.getLogger().info("Output style plugin initialized, current style: {}", currentStyle.get()); } @Override @@ -95,7 +95,7 @@ public class OutputStylePlugin implements Plugin { @Override public void destroy() { if (context != null) { - context.getLogger().info("输出样式插件已销毁"); + context.getLogger().info("Output style plugin destroyed"); } } @@ -135,8 +135,8 @@ public class OutputStylePlugin implements Plugin { // 切换样式 if (!SUPPORTED_STYLES.contains(trimmed)) { - return AnsiStyle.red(" ✗ 未知样式: " + trimmed) + "\n" - + AnsiStyle.dim(" 可用样式: default, minimal, verbose, markdown"); + return AnsiStyle.red(" ✗ Unknown style: " + trimmed) + "\n" + + AnsiStyle.dim(" Available styles: default, minimal, verbose, markdown"); } String oldStyle = currentStyle.getAndSet(trimmed); @@ -151,10 +151,10 @@ public class OutputStylePlugin implements Plugin { } if (context != null) { - context.getLogger().info("输出样式切换: {} → {}", oldStyle, trimmed); + context.getLogger().info("Output style switched: {} → {}", oldStyle, trimmed); } - return AnsiStyle.green(" ✓ 输出样式已切换: ") + return AnsiStyle.green(" ✓ Output style switched: ") + AnsiStyle.bold(oldStyle) + " → " + AnsiStyle.bold(AnsiStyle.cyan(trimmed)) @@ -182,7 +182,7 @@ public class OutputStylePlugin implements Plugin { .append(AnsiStyle.dim(" - " + desc)).append("\n"); } - sb.append("\n").append(AnsiStyle.dim(" 用法: /style ")).append("\n"); + sb.append("\n").append(AnsiStyle.dim(" Usage: /style ")).append("\n"); return sb.toString(); } @@ -191,11 +191,11 @@ public class OutputStylePlugin implements Plugin { */ private String getStyleBrief(String style) { return switch (style) { - case "default" -> "默认彩色输出"; - case "minimal" -> "精简输出,无颜色"; - case "verbose" -> "详细输出,含调试信息"; - case "markdown" -> "纯 Markdown 输出"; - default -> "未知样式"; + case "default" -> "Default colorful output"; + case "minimal" -> "Minimal output, no colors"; + case "verbose" -> "Verbose output with debug info"; + case "markdown" -> "Pure Markdown output"; + default -> "Unknown style"; }; } @@ -204,10 +204,10 @@ public class OutputStylePlugin implements Plugin { */ private String getStyleDescription(String style) { return switch (style) { - case "default" -> AnsiStyle.dim(" 使用 ANSI 颜色和格式的标准输出模式"); - case "minimal" -> AnsiStyle.dim(" 无颜色无装饰的精简输出,适合管道和日志"); - case "verbose" -> AnsiStyle.dim(" 包含时间戳、调试信息的详细输出模式"); - case "markdown" -> AnsiStyle.dim(" 纯 Markdown 格式,适合导出到文档"); + case "default" -> AnsiStyle.dim(" Standard output mode with ANSI colors and formatting"); + case "minimal" -> AnsiStyle.dim(" Minimal output without colors, suitable for pipes and logs"); + case "verbose" -> AnsiStyle.dim(" Verbose output mode with timestamps and debug info"); + case "markdown" -> AnsiStyle.dim(" Pure Markdown format, suitable for export to documents"); default -> ""; }; } diff --git a/src/main/java/com/claudecode/plugin/PluginContext.java b/src/main/java/com/claudecode/plugin/PluginContext.java index 0805443..0945d1f 100644 --- a/src/main/java/com/claudecode/plugin/PluginContext.java +++ b/src/main/java/com/claudecode/plugin/PluginContext.java @@ -35,9 +35,9 @@ public class PluginContext { * @throws NullPointerException 如果任何参数为 null */ public PluginContext(ToolContext toolContext, String workDir, String pluginId) { - this.toolContext = Objects.requireNonNull(toolContext, "toolContext 不能为 null"); - this.workDir = Objects.requireNonNull(workDir, "workDir 不能为 null"); - Objects.requireNonNull(pluginId, "pluginId 不能为 null"); + this.toolContext = Objects.requireNonNull(toolContext, "toolContext cannot be null"); + this.workDir = Objects.requireNonNull(workDir, "workDir cannot be null"); + Objects.requireNonNull(pluginId, "pluginId cannot be null"); this.pluginLogger = LoggerFactory.getLogger("plugin." + pluginId); } diff --git a/src/main/java/com/claudecode/plugin/PluginManager.java b/src/main/java/com/claudecode/plugin/PluginManager.java index 9bb8c48..252865a 100644 --- a/src/main/java/com/claudecode/plugin/PluginManager.java +++ b/src/main/java/com/claudecode/plugin/PluginManager.java @@ -69,7 +69,7 @@ public class PluginManager { * @throws NullPointerException 如果 toolContext 为 null */ public PluginManager(ToolContext toolContext) { - this.toolContext = Objects.requireNonNull(toolContext, "toolContext 不能为 null"); + this.toolContext = Objects.requireNonNull(toolContext, "toolContext cannot be null"); this.globalPluginDir = Path.of( System.getProperty("user.home"), ".claude-code-java", "plugins"); this.projectPluginDir = toolContext.getWorkDir().resolve(".claude-code").resolve("plugins"); @@ -84,7 +84,7 @@ public class PluginManager { public void loadAll() { loadFromDirectory(globalPluginDir, "global"); loadFromDirectory(projectPluginDir, "project"); - log.info("共加载 {} 个插件", plugins.size()); + log.info("Loaded {} plugins in total", plugins.size()); } /** @@ -95,14 +95,14 @@ public class PluginManager { */ private void loadFromDirectory(Path dir, String scope) { if (!Files.isDirectory(dir)) { - log.debug("插件目录不存在,跳过: {}", dir); + log.debug("Plugin directory does not exist, skipping: {}", dir); return; } try (var stream = Files.list(dir)) { stream.filter(p -> p.toString().endsWith(".jar")) .forEach(jar -> loadJarPlugin(jar, scope)); } catch (IOException e) { - log.warn("扫描插件目录失败: {}", dir, e); + log.warn("Failed to scan plugin directory: {}", dir, e); } } @@ -130,12 +130,12 @@ public class PluginManager { ? manifest.getMainAttributes().getValue("Plugin-Class") : null; } catch (IOException e) { - log.error("读取 JAR 清单失败: {}", jarPath.getFileName(), e); + log.error("Failed to read JAR manifest: {}", jarPath.getFileName(), e); return; } if (pluginClassName == null) { - log.warn("JAR {} 缺少 Plugin-Class 属性,跳过", jarPath.getFileName()); + log.warn("JAR {} missing Plugin-Class attribute, skipping", jarPath.getFileName()); return; } @@ -151,7 +151,7 @@ public class PluginManager { Class clazz = loader.loadClass(pluginClassName); if (!Plugin.class.isAssignableFrom(clazz)) { - log.warn("{} 未实现 Plugin 接口,跳过", pluginClassName); + log.warn("{} does not implement Plugin interface, skipping", pluginClassName); return; } @@ -159,7 +159,7 @@ public class PluginManager { // 检查插件 ID 是否重复 if (findPlugin(plugin.id()) != null) { - log.warn("插件 ID '{}' 已存在,跳过重复加载: {}", plugin.id(), jarPath.getFileName()); + log.warn("Plugin ID '{}' already exists, skipping duplicate load: {}", plugin.id(), jarPath.getFileName()); return; } @@ -169,11 +169,11 @@ public class PluginManager { plugin.initialize(ctx); plugins.add(new PluginInfo(plugin, scope, jarPath, loader)); - log.info("加载插件: {} v{} [{}] ({})", plugin.name(), plugin.version(), plugin.id(), scope); + log.info("Loaded plugin: {} v{} [{}] ({})", plugin.name(), plugin.version(), plugin.id(), scope); success = true; } catch (Exception e) { - log.error("加载插件失败: {}", jarPath.getFileName(), e); + log.error("Failed to load plugin: {}", jarPath.getFileName(), e); } finally { // 仅在加载失败时关闭类加载器;成功时由 PluginInfo 持有 if (!success) { @@ -190,7 +190,7 @@ public class PluginManager { */ public boolean loadPlugin(Path jarPath) { if (!Files.isRegularFile(jarPath) || !jarPath.toString().endsWith(".jar")) { - log.warn("无效的插件路径: {}", jarPath); + log.warn("Invalid plugin path: {}", jarPath); return false; } loadJarPlugin(jarPath, "dynamic"); @@ -207,7 +207,7 @@ public class PluginManager { for (PluginInfo info : plugins) { for (Tool tool : info.plugin().getTools()) { toolRegistry.register(tool); - log.debug("注册插件工具: {} (来自 {})", tool.name(), info.plugin().name()); + log.debug("Registered plugin tool: {} (from {})", tool.name(), info.plugin().name()); } } } @@ -221,7 +221,7 @@ public class PluginManager { for (PluginInfo info : plugins) { for (SlashCommand cmd : info.plugin().getCommands()) { commandRegistry.register(cmd); - log.debug("注册插件命令: /{} (来自 {})", cmd.name(), info.plugin().name()); + log.debug("Registered plugin command: /{} (from {})", cmd.name(), info.plugin().name()); } } } @@ -244,15 +244,15 @@ public class PluginManager { try { info.plugin().destroy(); } catch (Exception e) { - log.warn("插件 {} 销毁时异常", pluginId, e); + log.warn("Plugin {} exception during destroy", pluginId, e); } safeClose(info.classLoader()); plugins.remove(info); // CopyOnWriteArrayList.remove(Object) 是安全的 - log.info("已卸载插件: {} ({})", info.plugin().name(), pluginId); + log.info("Unloaded plugin: {} ({})", info.plugin().name(), pluginId); return true; } } - log.warn("未找到插件: {}", pluginId); + log.warn("Plugin not found: {}", pluginId); return false; } @@ -306,17 +306,17 @@ public class PluginManager { * 然后关闭对应的类加载器。此方法应在应用关闭时调用。 */ public void shutdown() { - log.info("正在关闭 {} 个插件...", plugins.size()); + log.info("Shutting down {} plugins...", plugins.size()); for (PluginInfo info : plugins) { try { info.plugin().destroy(); } catch (Exception e) { - log.warn("插件 {} 销毁异常", info.plugin().id(), e); + log.warn("Plugin {} exception during destroy", info.plugin().id(), e); } safeClose(info.classLoader()); } plugins.clear(); - log.info("所有插件已关闭"); + log.info("All plugins shut down"); } /** @@ -329,7 +329,7 @@ public class PluginManager { try { closeable.close(); } catch (Exception e) { - log.debug("关闭资源时异常 ({}): {}", + log.debug("Exception closing resource ({}): {}", closeable.getClass().getSimpleName(), e.getMessage()); } } diff --git a/src/main/java/com/claudecode/repl/ReplSession.java b/src/main/java/com/claudecode/repl/ReplSession.java index 70efd87..849547e 100644 --- a/src/main/java/com/claudecode/repl/ReplSession.java +++ b/src/main/java/com/claudecode/repl/ReplSession.java @@ -132,7 +132,7 @@ public class ReplSession { try { startWithJLine(); } catch (Exception e) { - log.warn("JLine 初始化失败,降级到 Scanner 模式: {}", e.getMessage()); + log.warn("JLine initialization failed, downgrading to Scanner mode: {}", e.getMessage()); startWithScanner(); } } @@ -150,7 +150,7 @@ public class ReplSession { boolean isDumb = "dumb".equals(terminal.getType()); if (isDumb) { - log.info("当前为 dumb 终端模式,建议使用 Windows Terminal / PowerShell / cmd 获得完整体验"); + log.info("Dumb terminal mode, use Windows Terminal / PowerShell / cmd for full experience"); } // 配置 Parser:支持反斜杠续行 (\) 和 三引号块 (""") @@ -172,7 +172,7 @@ public class ReplSession { String vimMode = System.getenv("CLAUDE_CODE_VIM"); if ("1".equals(vimMode) || "true".equalsIgnoreCase(vimMode)) { reader.setVariable(LineReader.EDITING_MODE, "vi"); - log.info("已启用 Vim 编辑模式"); + log.info("Vim editing mode enabled"); } // 主提示符 @@ -241,7 +241,7 @@ public class ReplSession { + AnsiStyle.dim(" Model: ") + AnsiStyle.cyan(providerInfo.model())); out.println(AnsiStyle.dim(" Work Dir: " + System.getProperty("user.dir"))); if (isDumb) { - out.println(AnsiStyle.yellow(" ⚠ Dumb 终端模式:建议在 Windows Terminal / PowerShell 中运行")); + out.println(AnsiStyle.yellow(" ⚠ Dumb terminal mode: run in Windows Terminal / PowerShell for best experience")); } } else { // 标准终端用带边框的 Banner @@ -343,7 +343,7 @@ public class ReplSession { } catch (Exception e) { spinner.stop(); out.println(AnsiStyle.RED + "\n ● Error: " + AnsiStyle.RESET + e.getMessage()); - log.error("Agent 循环异常", e); + log.error("Agent loop exception", e); out.println(); } } @@ -355,7 +355,7 @@ public class ReplSession { if (history.size() > 2) { var file = persistence.save(history, conversationSummary); if (file != null) { - out.println(AnsiStyle.dim(" 💾 对话已保存: " + file.getFileName())); + out.println(AnsiStyle.dim(" 💾 Conversation saved: " + file.getFileName())); } } } @@ -377,10 +377,10 @@ public class ReplSession { */ private boolean promptPermission(AgentLoop.PermissionRequest request) { out.println(); - out.println(AnsiStyle.yellow(" ⚠ 权限确认")); + out.println(AnsiStyle.yellow(" ⚠ Permission Required")); out.println(" " + "─".repeat(50)); - out.println(" " + AnsiStyle.bold("工具: ") + AnsiStyle.cyan(request.toolName())); - out.println(" " + AnsiStyle.bold("操作: ") + request.activityDescription()); + out.println(" " + AnsiStyle.bold("Tool: ") + AnsiStyle.cyan(request.toolName())); + out.println(" " + AnsiStyle.bold("Action: ") + request.activityDescription()); // 显示参数摘要(截断过长的参数) String argsPreview = request.arguments(); @@ -388,11 +388,11 @@ public class ReplSession { argsPreview = argsPreview.substring(0, 200) + "..."; } if (argsPreview != null && !argsPreview.isBlank()) { - out.println(" " + AnsiStyle.dim("参数: " + argsPreview)); + out.println(" " + AnsiStyle.dim("Args: " + argsPreview)); } out.println(" " + "─".repeat(50)); - out.print(" " + AnsiStyle.bold("允许执行?") + AnsiStyle.dim(" [Y/n/always] ") + AnsiStyle.BOLD + AnsiStyle.BRIGHT_CYAN + "→ " + AnsiStyle.RESET); + out.print(" " + AnsiStyle.bold("Allow execution?") + AnsiStyle.dim(" [Y/n/always] ") + AnsiStyle.BOLD + AnsiStyle.BRIGHT_CYAN + "→ " + AnsiStyle.RESET); out.flush(); String answer = readLineForPermission(); @@ -403,7 +403,7 @@ public class ReplSession { // "always" → 禁用后续权限确认 if (answer.equals("always") || answer.equals("a")) { agentLoop.setOnPermissionRequest(null); // 移除权限回调 - out.println(AnsiStyle.green(" ✓ 已授权所有后续操作")); + out.println(AnsiStyle.green(" ✓ All subsequent operations authorized")); return true; } @@ -413,7 +413,7 @@ public class ReplSession { } // 其他输入 → 拒绝 - out.println(AnsiStyle.red(" ✗ 操作已拒绝")); + out.println(AnsiStyle.red(" ✗ Operation denied")); return false; } @@ -426,7 +426,7 @@ public class ReplSession { return activeScanner.nextLine(); } } catch (Exception e) { - log.debug("读取权限确认输入异常: {}", e.getMessage()); + log.debug("Permission confirmation input exception: {}", e.getMessage()); } return null; } @@ -450,9 +450,9 @@ public class ReplSession { return activeScanner.nextLine(); } } catch (UserInterruptException e) { - return "(用户取消)"; + return "(User cancelled)"; } catch (Exception e) { - log.debug("读取用户输入异常: {}", e.getMessage()); + log.debug("User input read exception: {}", e.getMessage()); } return null; } diff --git a/src/main/java/com/claudecode/tool/ToolCallbackAdapter.java b/src/main/java/com/claudecode/tool/ToolCallbackAdapter.java index 1b75df2..426841d 100644 --- a/src/main/java/com/claudecode/tool/ToolCallbackAdapter.java +++ b/src/main/java/com/claudecode/tool/ToolCallbackAdapter.java @@ -51,17 +51,17 @@ public class ToolCallbackAdapter implements ToolCallback { // 权限前置检查 PermissionResult perm = tool.checkPermission(input, context); if (!perm.allowed()) { - log.warn("[{}] 权限拒绝: {}", tool.name(), perm.message()); + log.warn("[{}] Permission denied: {}", tool.name(), perm.message()); return "Permission denied: " + perm.message(); } log.debug("[{}] {}", tool.name(), tool.activityDescription(input)); return tool.execute(input, context); } catch (JsonProcessingException e) { - log.warn("[{}] JSON 解析失败: {}", tool.name(), e.getMessage()); + log.warn("[{}] JSON parse failed: {}", tool.name(), e.getMessage()); return "Error: Invalid JSON input: " + e.getMessage(); } catch (Exception e) { - log.warn("[{}] 执行异常: {}", tool.name(), e.getMessage()); + log.warn("[{}] Execution exception: {}", tool.name(), e.getMessage()); return "Error: " + e.getMessage(); } } diff --git a/src/main/java/com/claudecode/tool/ToolRegistry.java b/src/main/java/com/claudecode/tool/ToolRegistry.java index 1e8f9a1..2c76fe0 100644 --- a/src/main/java/com/claudecode/tool/ToolRegistry.java +++ b/src/main/java/com/claudecode/tool/ToolRegistry.java @@ -22,14 +22,14 @@ public class ToolRegistry { */ public void register(Tool tool) { if (!tool.isEnabled()) { - log.debug("工具 [{}] 未启用,跳过注册", tool.name()); + log.debug("Tool [{}] not enabled, skipping registration", tool.name()); return; } if (tools.containsKey(tool.name())) { - log.warn("工具 [{}] 已注册,将被覆盖", tool.name()); + log.warn("Tool [{}] already registered, will be overridden", tool.name()); } tools.put(tool.name(), tool); - log.debug("注册工具: [{}]", tool.name()); + log.debug("Registered tool: [{}]", tool.name()); } /** 批量注册 */ diff --git a/src/main/java/com/claudecode/tool/impl/AgentTool.java b/src/main/java/com/claudecode/tool/impl/AgentTool.java index df97ad6..ca2cee8 100644 --- a/src/main/java/com/claudecode/tool/impl/AgentTool.java +++ b/src/main/java/com/claudecode/tool/impl/AgentTool.java @@ -77,7 +77,7 @@ public class AgentTool implements Tool { context.getOrDefault(AGENT_FACTORY_KEY, null); if (agentFactory == null) { - log.warn("AgentTool: 未配置 Agent 工厂,无法创建子 Agent"); + log.warn("AgentTool: Agent factory not configured, cannot create sub-agent"); return "Error: Sub-agent capability is not configured. " + "The Agent tool requires an agent factory to be registered in the ToolContext."; } @@ -85,14 +85,14 @@ public class AgentTool implements Tool { // 构建完整的子 Agent 提示 String fullPrompt = buildSubAgentPrompt(prompt, additionalContext); - log.info("启动子 Agent,任务: {}", truncate(prompt, 80)); + log.info("Starting sub-agent, task: {}", truncate(prompt, 80)); try { String result = agentFactory.apply(fullPrompt); - log.info("子 Agent 完成,结果长度: {} chars", result.length()); + log.info("Sub-agent completed, result length: {} chars", result.length()); return result; } catch (Exception e) { - log.error("子 Agent 执行失败", e); + log.error("Sub-agent execution failed", e); return "Error: Sub-agent failed: " + e.getMessage(); } } diff --git a/src/main/java/com/claudecode/tool/impl/AskUserQuestionTool.java b/src/main/java/com/claudecode/tool/impl/AskUserQuestionTool.java index c78d52d..88c09de 100644 --- a/src/main/java/com/claudecode/tool/impl/AskUserQuestionTool.java +++ b/src/main/java/com/claudecode/tool/impl/AskUserQuestionTool.java @@ -78,7 +78,7 @@ public class AskUserQuestionTool implements Tool { // 获取用户输入回调 Object callback = context.get(USER_INPUT_CALLBACK); if (callback == null) { - log.warn("未注册用户输入回调(USER_INPUT_CALLBACK),返回默认回复"); + log.warn("User input callback not registered (USER_INPUT_CALLBACK), returning default response"); return "Error: User input not available in current environment"; } @@ -91,7 +91,7 @@ public class AskUserQuestionTool implements Tool { // 构建提问文本 StringBuilder prompt = new StringBuilder(); - prompt.append("\n 🤔 AI 正在向你提问:\n"); + prompt.append("\n 🤔 AI is asking you a question:\n"); prompt.append(" ").append("─".repeat(50)).append("\n"); prompt.append(" ").append(question).append("\n"); @@ -99,7 +99,7 @@ public class AskUserQuestionTool implements Tool { if (input.containsKey("options")) { var options = (java.util.List) input.get("options"); if (options != null && !options.isEmpty()) { - prompt.append("\n 可选项:\n"); + prompt.append("\n Options:\n"); for (int i = 0; i < options.size(); i++) { prompt.append(" ").append(i + 1).append(". ").append(options.get(i)).append("\n"); } @@ -115,11 +115,11 @@ public class AskUserQuestionTool implements Tool { return "(User provided no response)"; } - log.debug("用户回答: {}", userResponse); + log.debug("User response: {}", userResponse); return "User response: " + userResponse; } catch (Exception e) { - log.error("获取用户输入失败", e); + log.error("Failed to get user input", e); return "Error: Failed to get user input - " + e.getMessage(); } } diff --git a/src/main/java/com/claudecode/tool/impl/ConfigTool.java b/src/main/java/com/claudecode/tool/impl/ConfigTool.java index 339e42f..da3619e 100644 --- a/src/main/java/com/claudecode/tool/impl/ConfigTool.java +++ b/src/main/java/com/claudecode/tool/impl/ConfigTool.java @@ -49,16 +49,16 @@ public class ConfigTool implements Tool { "properties": { "action": { "type": "string", - "description": "操作类型:get(获取)或 set(设置)", + "description": "Action type: get or set", "enum": ["get", "set"] }, "key": { "type": "string", - "description": "配置项的键名" + "description": "Configuration key name" }, "value": { "type": "string", - "description": "配置项的值(仅 set 操作时需要)" + "description": "Configuration value (required for set operation)" } }, "required": ["action", "key"] @@ -79,14 +79,14 @@ public class ConfigTool implements Tool { // 解析必填参数: action String action = (String) input.get("action"); if (action == null || action.isBlank()) { - return errorJson("参数 'action' 是必填项,可选值: get, set"); + return errorJson("Parameter 'action' is required, valid values: get, set"); } action = action.trim().toLowerCase(); // 解析必填参数: key String key = (String) input.get("key"); if (key == null || key.isBlank()) { - return errorJson("参数 'key' 是必填项且不能为空"); + return errorJson("Parameter 'key' is required and cannot be empty"); } // 获取或初始化配置存储 @@ -102,7 +102,7 @@ public class ConfigTool implements Tool { return switch (action) { case "get" -> executeGet(key, configStore); case "set" -> executeSet(key, input, configStore); - default -> errorJson("无效的 action 值: '" + action + "'。可选值: get, set"); + default -> errorJson("Invalid action value: '" + action + "'. Valid values: get, set"); }; } @@ -143,7 +143,7 @@ public class ConfigTool implements Tool { "key": "%s", "value": null, "found": false, - "message": "配置项 '%s' 未找到" + "message": "Config key '%s' not found" }""".formatted(escapeJson(key), escapeJson(key)); } @@ -168,7 +168,7 @@ public class ConfigTool implements Tool { ConcurrentHashMap configStore) { String value = (String) input.get("value"); if (value == null) { - return errorJson("set 操作需要提供 'value' 参数"); + return errorJson("set operation requires 'value' parameter"); } // 获取旧值(用于返回信息) @@ -200,7 +200,7 @@ public class ConfigTool implements Tool { } sb.append(" \"success\": true,\n"); - sb.append(" \"message\": \"配置项 '").append(escapeJson(key)).append("' 已设置\"\n"); + sb.append(" \"message\": \"Config key '").append(escapeJson(key)).append("' has been set\"\n"); sb.append("}"); return sb.toString(); diff --git a/src/main/java/com/claudecode/tool/impl/McpToolBridge.java b/src/main/java/com/claudecode/tool/impl/McpToolBridge.java index b10af28..2d515f7 100644 --- a/src/main/java/com/claudecode/tool/impl/McpToolBridge.java +++ b/src/main/java/com/claudecode/tool/impl/McpToolBridge.java @@ -55,8 +55,8 @@ public class McpToolBridge implements Tool { * @param mcpTool MCP 工具定义 */ public McpToolBridge(String serverName, McpClient.McpTool mcpTool) { - this.serverName = Objects.requireNonNull(serverName, "服务器名称不能为空"); - Objects.requireNonNull(mcpTool, "MCP 工具定义不能为空"); + this.serverName = Objects.requireNonNull(serverName, "Server name cannot be null"); + Objects.requireNonNull(mcpTool, "MCP tool definition cannot be null"); this.mcpToolName = mcpTool.name(); this.mcpDescription = mcpTool.description(); @@ -100,13 +100,13 @@ public class McpToolBridge implements Tool { // 从上下文获取 McpManager McpManager mcpManager = context.get(MCP_MANAGER_KEY); if (mcpManager == null) { - return "错误: MCP 管理器未在上下文中注册 (key=" + MCP_MANAGER_KEY + ")"; + return "Error: MCP manager not registered in context (key=" + MCP_MANAGER_KEY + ")"; } try { return mcpManager.callTool(serverName, mcpToolName, input); } catch (McpException e) { - return "MCP 工具调用失败 [" + serverName + "/" + mcpToolName + "]: " + e.getMessage(); + return "MCP tool call failed [" + serverName + "/" + mcpToolName + "]: " + e.getMessage(); } } diff --git a/src/main/java/com/claudecode/tool/impl/TaskCreateTool.java b/src/main/java/com/claudecode/tool/impl/TaskCreateTool.java index bb2f5b7..e8ca61b 100644 --- a/src/main/java/com/claudecode/tool/impl/TaskCreateTool.java +++ b/src/main/java/com/claudecode/tool/impl/TaskCreateTool.java @@ -47,11 +47,11 @@ public class TaskCreateTool implements Tool { "properties": { "description": { "type": "string", - "description": "任务描述,说明这个任务要做什么" + "description": "Task description, what this task should accomplish" }, "metadata": { "type": "string", - "description": "可选的 JSON 格式元数据字符串,例如 {\\"priority\\":\\"high\\"}" + "description": "Optional JSON metadata string, e.g. {\\"priority\\":\\"high\\"}" } }, "required": ["description"] @@ -68,13 +68,13 @@ public class TaskCreateTool implements Tool { // 获取 TaskManager 实例 TaskManager manager = context.get(TASK_MANAGER_KEY); if (manager == null) { - return errorJson("TaskManager 未初始化,请检查上下文配置"); + return errorJson("TaskManager not initialized, check context configuration"); } // 解析必填参数: description String desc = (String) input.get("description"); if (desc == null || desc.isBlank()) { - return errorJson("参数 'description' 是必填项且不能为空"); + return errorJson("Parameter 'description' is required and cannot be empty"); } // 解析可选参数: metadata @@ -94,7 +94,7 @@ public class TaskCreateTool implements Tool { "task_id": "%s", "description": "%s", "status": "PENDING", - "message": "任务已创建" + "message": "Task created" }""".formatted(escapeJson(taskId), escapeJson(desc)); } diff --git a/src/main/java/com/claudecode/tool/impl/TaskGetTool.java b/src/main/java/com/claudecode/tool/impl/TaskGetTool.java index 90412f9..345f923 100644 --- a/src/main/java/com/claudecode/tool/impl/TaskGetTool.java +++ b/src/main/java/com/claudecode/tool/impl/TaskGetTool.java @@ -46,7 +46,7 @@ public class TaskGetTool implements Tool { "properties": { "task_id": { "type": "string", - "description": "要查询的任务 ID" + "description": "Task ID to query" } }, "required": ["task_id"] @@ -63,19 +63,19 @@ public class TaskGetTool implements Tool { // 获取 TaskManager 实例 TaskManager manager = context.get(TASK_MANAGER_KEY); if (manager == null) { - return errorJson("TaskManager 未初始化,请检查上下文配置"); + return errorJson("TaskManager not initialized, check context configuration"); } // 解析必填参数: task_id String taskId = (String) input.get("task_id"); if (taskId == null || taskId.isBlank()) { - return errorJson("参数 'task_id' 是必填项且不能为空"); + return errorJson("Parameter 'task_id' is required and cannot be empty"); } // 查询任务 Optional taskOpt = manager.getTask(taskId); if (taskOpt.isEmpty()) { - return errorJson("未找到 ID 为 '" + taskId + "' 的任务"); + return errorJson("Task with ID '" + taskId + "' not found"); } // 返回任务详情 JSON diff --git a/src/main/java/com/claudecode/tool/impl/TaskListTool.java b/src/main/java/com/claudecode/tool/impl/TaskListTool.java index 8670389..5888de3 100644 --- a/src/main/java/com/claudecode/tool/impl/TaskListTool.java +++ b/src/main/java/com/claudecode/tool/impl/TaskListTool.java @@ -47,7 +47,7 @@ public class TaskListTool implements Tool { "properties": { "status": { "type": "string", - "description": "按状态过滤:PENDING / RUNNING / COMPLETED / FAILED / CANCELLED", + "description": "Filter by status: PENDING / RUNNING / COMPLETED / FAILED / CANCELLED", "enum": ["PENDING", "RUNNING", "COMPLETED", "FAILED", "CANCELLED"] } }, @@ -65,7 +65,7 @@ public class TaskListTool implements Tool { // 获取 TaskManager 实例 TaskManager manager = context.get(TASK_MANAGER_KEY); if (manager == null) { - return errorJson("TaskManager 未初始化,请检查上下文配置"); + return errorJson("TaskManager not initialized, check context configuration"); } // 解析可选参数: status @@ -75,8 +75,8 @@ public class TaskListTool implements Tool { try { statusFilter = TaskStatus.valueOf(statusStr.trim().toUpperCase()); } catch (IllegalArgumentException e) { - return errorJson("无效的状态值: '" + statusStr - + "'。可选值: PENDING, RUNNING, COMPLETED, FAILED, CANCELLED"); + return errorJson("Invalid status value: '" + statusStr + + "'. Valid values: PENDING, RUNNING, COMPLETED, FAILED, CANCELLED"); } } diff --git a/src/main/java/com/claudecode/tool/impl/TaskUpdateTool.java b/src/main/java/com/claudecode/tool/impl/TaskUpdateTool.java index 90c395d..8f024c8 100644 --- a/src/main/java/com/claudecode/tool/impl/TaskUpdateTool.java +++ b/src/main/java/com/claudecode/tool/impl/TaskUpdateTool.java @@ -52,16 +52,16 @@ public class TaskUpdateTool implements Tool { "properties": { "task_id": { "type": "string", - "description": "要更新的任务 ID" + "description": "Task ID to update" }, "status": { "type": "string", - "description": "新状态:PENDING / RUNNING / COMPLETED / FAILED / CANCELLED", + "description": "New status: PENDING / RUNNING / COMPLETED / FAILED / CANCELLED", "enum": ["PENDING", "RUNNING", "COMPLETED", "FAILED", "CANCELLED"] }, "result": { "type": "string", - "description": "任务执行结果或附加信息(可选)" + "description": "Task execution result or additional info (optional)" } }, "required": ["task_id", "status"] @@ -78,27 +78,27 @@ public class TaskUpdateTool implements Tool { // 获取 TaskManager 实例 TaskManager manager = context.get(TASK_MANAGER_KEY); if (manager == null) { - return errorJson("TaskManager 未初始化,请检查上下文配置"); + return errorJson("TaskManager not initialized, check context configuration"); } // 解析必填参数: task_id String taskId = (String) input.get("task_id"); if (taskId == null || taskId.isBlank()) { - return errorJson("参数 'task_id' 是必填项且不能为空"); + return errorJson("Parameter 'task_id' is required and cannot be empty"); } // 解析必填参数: status String statusStr = (String) input.get("status"); if (statusStr == null || statusStr.isBlank()) { - return errorJson("参数 'status' 是必填项且不能为空"); + return errorJson("Parameter 'status' is required and cannot be empty"); } TaskStatus newStatus; try { newStatus = TaskStatus.valueOf(statusStr.trim().toUpperCase()); } catch (IllegalArgumentException e) { - return errorJson("无效的状态值: '" + statusStr - + "'。可选值: PENDING, RUNNING, COMPLETED, FAILED, CANCELLED"); + return errorJson("Invalid status value: '" + statusStr + + "'. Valid values: PENDING, RUNNING, COMPLETED, FAILED, CANCELLED"); } // 解析可选参数: result @@ -107,7 +107,7 @@ public class TaskUpdateTool implements Tool { // 在更新前先获取旧状态(用于返回信息) Optional beforeOpt = manager.getTask(taskId); if (beforeOpt.isEmpty()) { - return errorJson("未找到 ID 为 '" + taskId + "' 的任务"); + return errorJson("Task with ID '" + taskId + "' not found"); } TaskInfo before = beforeOpt.get(); @@ -116,15 +116,15 @@ public class TaskUpdateTool implements Tool { // 执行更新 boolean success = manager.updateTask(taskId, newStatus, result); if (!success) { - return errorJson("更新失败:任务 '" + taskId + "' 当前状态为 " - + oldStatus + ",可能已处于终态,无法再次更新"); + return errorJson("Update failed: task '" + taskId + "' current status is " + + oldStatus + ", may be in terminal state and cannot be updated"); } // 获取更新后的任务信息 Optional afterOpt = manager.getTask(taskId); if (afterOpt.isEmpty()) { // 理论上不会出现,防御性编程 - return errorJson("更新后未能获取任务信息"); + return errorJson("Failed to get task info after update"); } TaskInfo after = afterOpt.get(); @@ -144,8 +144,8 @@ public class TaskUpdateTool implements Tool { } sb.append(" \"updated_at\": \"").append(after.updatedAt()).append("\",\n"); - sb.append(" \"message\": \"任务状态已从 ").append(oldStatus) - .append(" 更新为 ").append(after.status().name()).append("\"\n"); + sb.append(" \"message\": \"Task status updated from ").append(oldStatus) + .append(" to ").append(after.status().name()).append("\"\n"); sb.append("}"); return sb.toString(); diff --git a/src/main/java/com/claudecode/tool/impl/WebSearchTool.java b/src/main/java/com/claudecode/tool/impl/WebSearchTool.java index a71e7cb..1201155 100644 --- a/src/main/java/com/claudecode/tool/impl/WebSearchTool.java +++ b/src/main/java/com/claudecode/tool/impl/WebSearchTool.java @@ -92,7 +92,7 @@ public class WebSearchTool implements Tool { String html = fetchSearchPage(query); return parseResults(html, maxResults); } catch (Exception e) { - log.error("搜索失败: query={}", query, e); + log.error("Search failed: query={}", query, e); return "Error: Search failed - " + e.getMessage(); } }