feat: P2全部功能 - MCP协议+插件系统+任务管理+CLI增强
A组 CLI增强: - DiffRenderer: 彩色diff渲染(行号/stat摘要/unified格式) - /hooks: 查看已注册Hook列表 - /review: AI代码审查(支持--staged/文件路径) - /stats: 会话使用统计(tokens/费用/API调用/运行时长) - /branch: 对话分支管理(save/load/list/delete) - /rewind: 回退对话历史 - /tag: 对话位置标签 - /security-review: AI安全审查 B组 任务系统: - TaskManager: 后台任务管理(线程安全/自动执行/手动管理) - TaskCreate/TaskGet/TaskList/TaskUpdate 4个工具 - ConfigTool: 配置读写工具 C组 MCP协议: - McpClient: MCP客户端(JSON-RPC 2.0/工具发现/资源读取) - McpTransport: 传输层接口 - StdioTransport: StdIO传输实现(子进程/异步读写) - McpManager: 多MCP服务器管理(配置加载/生命周期) - McpToolBridge: MCP工具桥接为本地Tool - /mcp: MCP服务器管理命令 D组 插件系统: - Plugin接口 + PluginContext + PluginManager - JAR插件加载(ClassLoader隔离/Manifest读取) - OutputStylePlugin: 内置输出样式插件 - /plugin: 插件管理命令 集成: AppConfig注册全部18工具+28命令 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
package com.claudecode.tool.impl;
|
||||
|
||||
import com.claudecode.core.TaskManager;
|
||||
import com.claudecode.core.TaskManager.TaskInfo;
|
||||
import com.claudecode.core.TaskManager.TaskStatus;
|
||||
import com.claudecode.tool.Tool;
|
||||
import com.claudecode.tool.ToolContext;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* TaskUpdate 工具 —— 更新指定任务的状态和结果。
|
||||
* <p>
|
||||
* 对应 claude-code 中的 TaskUpdate 命令。用于推动手动管理任务的状态流转,
|
||||
* 例如从 PENDING → RUNNING → COMPLETED。
|
||||
* </p>
|
||||
*
|
||||
* <h3>参数</h3>
|
||||
* <ul>
|
||||
* <li><b>task_id</b>(必填)—— 要更新的任务 ID</li>
|
||||
* <li><b>status</b>(必填)—— 新状态:PENDING / RUNNING / COMPLETED / FAILED / CANCELLED</li>
|
||||
* <li><b>result</b>(可选)—— 任务执行结果或附加信息</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h3>返回</h3>
|
||||
* <p>JSON 格式的更新确认,包含更新后的任务信息。</p>
|
||||
*
|
||||
* <h3>状态约束</h3>
|
||||
* <p>已处于终态(COMPLETED / FAILED / CANCELLED)的任务不允许再次更新。</p>
|
||||
*/
|
||||
public class TaskUpdateTool implements Tool {
|
||||
|
||||
/** ToolContext 中 TaskManager 的存储键 */
|
||||
private static final String TASK_MANAGER_KEY = "TASK_MANAGER";
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "TaskUpdate";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return "Update a task's status and optional result";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String inputSchema() {
|
||||
return """
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"task_id": {
|
||||
"type": "string",
|
||||
"description": "要更新的任务 ID"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"description": "新状态:PENDING / RUNNING / COMPLETED / FAILED / CANCELLED",
|
||||
"enum": ["PENDING", "RUNNING", "COMPLETED", "FAILED", "CANCELLED"]
|
||||
},
|
||||
"result": {
|
||||
"type": "string",
|
||||
"description": "任务执行结果或附加信息(可选)"
|
||||
}
|
||||
},
|
||||
"required": ["task_id", "status"]
|
||||
}""";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String execute(Map<String, Object> input, ToolContext context) {
|
||||
// 获取 TaskManager 实例
|
||||
TaskManager manager = context.get(TASK_MANAGER_KEY);
|
||||
if (manager == null) {
|
||||
return errorJson("TaskManager 未初始化,请检查上下文配置");
|
||||
}
|
||||
|
||||
// 解析必填参数: task_id
|
||||
String taskId = (String) input.get("task_id");
|
||||
if (taskId == null || taskId.isBlank()) {
|
||||
return errorJson("参数 'task_id' 是必填项且不能为空");
|
||||
}
|
||||
|
||||
// 解析必填参数: status
|
||||
String statusStr = (String) input.get("status");
|
||||
if (statusStr == null || statusStr.isBlank()) {
|
||||
return errorJson("参数 'status' 是必填项且不能为空");
|
||||
}
|
||||
|
||||
TaskStatus newStatus;
|
||||
try {
|
||||
newStatus = TaskStatus.valueOf(statusStr.trim().toUpperCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
return errorJson("无效的状态值: '" + statusStr
|
||||
+ "'。可选值: PENDING, RUNNING, COMPLETED, FAILED, CANCELLED");
|
||||
}
|
||||
|
||||
// 解析可选参数: result
|
||||
String result = (String) input.get("result");
|
||||
|
||||
// 在更新前先获取旧状态(用于返回信息)
|
||||
Optional<TaskInfo> beforeOpt = manager.getTask(taskId);
|
||||
if (beforeOpt.isEmpty()) {
|
||||
return errorJson("未找到 ID 为 '" + taskId + "' 的任务");
|
||||
}
|
||||
|
||||
TaskInfo before = beforeOpt.get();
|
||||
String oldStatus = before.status().name();
|
||||
|
||||
// 执行更新
|
||||
boolean success = manager.updateTask(taskId, newStatus, result);
|
||||
if (!success) {
|
||||
return errorJson("更新失败:任务 '" + taskId + "' 当前状态为 "
|
||||
+ oldStatus + ",可能已处于终态,无法再次更新");
|
||||
}
|
||||
|
||||
// 获取更新后的任务信息
|
||||
Optional<TaskInfo> afterOpt = manager.getTask(taskId);
|
||||
if (afterOpt.isEmpty()) {
|
||||
// 理论上不会出现,防御性编程
|
||||
return errorJson("更新后未能获取任务信息");
|
||||
}
|
||||
|
||||
TaskInfo after = afterOpt.get();
|
||||
|
||||
// 返回更新确认 JSON
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("{\n");
|
||||
sb.append(" \"success\": true,\n");
|
||||
sb.append(" \"task_id\": \"").append(escapeJson(after.id())).append("\",\n");
|
||||
sb.append(" \"previous_status\": \"").append(oldStatus).append("\",\n");
|
||||
sb.append(" \"current_status\": \"").append(after.status().name()).append("\",\n");
|
||||
|
||||
if (after.result() != null) {
|
||||
sb.append(" \"result\": \"").append(escapeJson(after.result())).append("\",\n");
|
||||
} else {
|
||||
sb.append(" \"result\": null,\n");
|
||||
}
|
||||
|
||||
sb.append(" \"updated_at\": \"").append(after.updatedAt()).append("\",\n");
|
||||
sb.append(" \"message\": \"任务状态已从 ").append(oldStatus)
|
||||
.append(" 更新为 ").append(after.status().name()).append("\"\n");
|
||||
sb.append("}");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String activityDescription(Map<String, Object> input) {
|
||||
String taskId = (String) input.getOrDefault("task_id", "unknown");
|
||||
String status = (String) input.getOrDefault("status", "?");
|
||||
return "✏️ Updating task " + taskId + " → " + status;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 辅助方法 */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* 转义 JSON 特殊字符。
|
||||
*/
|
||||
private String escapeJson(String s) {
|
||||
if (s == null) return "";
|
||||
return s.replace("\\", "\\\\")
|
||||
.replace("\"", "\\\"")
|
||||
.replace("\n", "\\n")
|
||||
.replace("\r", "\\r")
|
||||
.replace("\t", "\\t");
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建错误 JSON 响应。
|
||||
*/
|
||||
private String errorJson(String message) {
|
||||
return """
|
||||
{
|
||||
"error": true,
|
||||
"message": "%s"
|
||||
}""".formatted(escapeJson(message));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user