到 s11, 智能体已经能自主认领和完成任务。但所有任务共享一个目录。两个智能体同时重构不同模块 -- A 改 config.py, B 也改 config.py, 未提交的改动互相污染, 谁也没法干净回滚。
任务板管 "做什么" 但不管 "在哪做"。解法: 给每个任务一个独立的 git worktree 目录, 用任务 ID 把两边关联起来。"各干各的目录, 互不干扰",任务管目标,,worktree 管目录,按 ID 绑定。
Java实现代码
java
public class WorktreeTaskIsolationSystem {
// --- 新增配置 ---
private static final Path REPO_ROOT = detectRepoRoot(WORKDIR); // Git仓库根目录
private static final Path TASKS_DIR = REPO_ROOT.resolve(".tasks");
private static final Path WORKTREES_DIR = REPO_ROOT.resolve(".worktrees");
private static final Path EVENTS_LOG_PATH = WORKTREES_DIR.resolve("events.jsonl");
// --- 新增:Git 仓库检测 ---
private static Path detectRepoRoot(Path cwd) {
try {
ProcessBuilder pb = new ProcessBuilder("git", "rev-parse", "--show-toplevel");
pb.directory(cwd.toFile());
Process process = pb.start();
boolean finished = process.waitFor(10, TimeUnit.SECONDS);
if (!finished) {
return cwd;
}
String output = new String(process.getInputStream().readAllBytes()).trim();
Path root = Paths.get(output);
return Files.exists(root) ? root : cwd;
// 自动检测:自动发现Git仓库根目录
// 向后兼容:如果不是Git仓库,使用当前目录
} catch (Exception e) {
return cwd;
}
}
// --- 新增:事件总线(EventBus)---
static class EventBus {
private final Path eventLogPath;
public EventBus(Path eventLogPath) {
this.eventLogPath = eventLogPath;
try {
Files.createDirectories(eventLogPath.getParent());
if (!Files.exists(eventLogPath)) {
Files.writeString(eventLogPath, "");
}
} catch (IOException e) {
throw new RuntimeException("Failed to create event bus", e);
}
}
/**
* 发出事件
*/
public void emit(String event, Map<String, Object> task,
Map<String, Object> worktree, String error) {
Map<String, Object> payload = new LinkedHashMap<>();
payload.put("event", event);
payload.put("ts", System.currentTimeMillis() / 1000.0);
payload.put("task", task != null ? task : Map.of());
payload.put("worktree", worktree != null ? worktree : Map.of());
if (error != null) {
payload.put("error", error);
}
// 结构化事件:事件类型、时间戳、关联数据
// 错误跟踪:支持记录操作失败信息
try {
String jsonLine = gson.toJson(payload) + "\n";
Files.writeString(eventLogPath, jsonLine,
StandardOpenOption.CREATE, StandardOpenOption.APPEND);
// JSONL格式:每行一个事件,便于流式处理
// 追加写入:支持长时间运行的事件记录
} catch (IOException e) {
System.err.println("Failed to emit event: " + e.getMessage());
}
}
/**
* 列出最近事件
*/
public String listRecent(int limit) {
int n = Math.max(1, Math.min(limit, 200));
try {
List<String> lines = Files.readAllLines(eventLogPath);
List<Map<String, Object>> events = new ArrayList<>();
int start = Math.max(0, lines.size() - n);
for (int i = start; i < lines.size(); i++) {
try {
Type type = new TypeToken<Map<String, Object>>(){}.getType();
Map<String, Object> event = gson.fromJson(lines.get(i), type);
events.add(event);
} catch (Exception e) {
Map<String, Object> errorEvent = new HashMap<>();
errorEvent.put("event", "parse_error");
errorEvent.put("raw", lines.get(i));
events.add(errorEvent);
// 容错处理:即使解析失败也记录原始数据
}
}
return gson.toJson(events);
} catch (IOException e) {
return "[]";
}
}
}
// 初始化事件总线
private static final EventBus EVENTS = new EventBus(EVENTS_LOG_PATH);
// --- 新增:任务管理器(支持工作树绑定)---
static class TaskManager {
private final Path tasksDir;
private int nextId = 1;
public TaskManager(Path tasksDir) {
this.tasksDir = tasksDir;
try {
Files.createDirectories(tasksDir);
this.nextId = getMaxId() + 1;
} catch (IOException e) {
throw new RuntimeException("Failed to initialize task manager", e);
}
}
/**
* 绑定任务到工作树
*/
public String bindWorktree(int taskId, String worktree, String owner) throws IOException {
Map<String, Object> task = loadTask(taskId);
task.put("worktree", worktree);
// 任务-工作树关联:建立任务和工作树的双向链接
if (owner != null && !owner.isEmpty()) {
task.put("owner", owner);
}
if ("pending".equals(task.get("status"))) {
task.put("status", "in_progress");
// 状态自动转换:绑定工作树时自动开始任务
}
task.put("updated_at", System.currentTimeMillis() / 1000.0);
saveTask(task);
return gson.toJson(task);
}
/**
* 解绑工作树
*/
public String unbindWorktree(int taskId) throws IOException {
Map<String, Object> task = loadTask(taskId);
task.put("worktree", "");
task.put("updated_at", System.currentTimeMillis() / 1000.0);
saveTask(task);
return gson.toJson(task);
// 解绑机制:支持任务和工作树的解耦
}
/**
* 列出所有任务
*/
public String listAllTasks() throws IOException {
// ... 列出任务逻辑,包含工作树绑定信息
sb.append(String.format("%s #%d: %s%s%s\n",
marker, id, subject, ownerStr, worktreeStr));
// 可视化展示:显示任务状态、所有者、工作树绑定
}
}
// 初始化任务管理器
private static final TaskManager TASKS = new TaskManager(TASKS_DIR);
// --- 新增:工作树管理器(WorktreeManager)---
static class WorktreeManager {
private final Path repoRoot;
private final TaskManager taskManager;
private final EventBus eventBus;
private final Path worktreesDir;
private final Path indexPath;
private final boolean gitAvailable;
public WorktreeManager(Path repoRoot, TaskManager taskManager, EventBus eventBus) {
this.repoRoot = repoRoot;
this.taskManager = taskManager;
this.eventBus = eventBus;
this.worktreesDir = repoRoot.resolve(".worktrees");
this.indexPath = worktreesDir.resolve("index.json");
// 集成架构:工作树管理器与任务管理器、事件总线集成
try {
Files.createDirectories(worktreesDir);
if (!Files.exists(indexPath)) {
Map<String, Object> index = new HashMap<>();
index.put("worktrees", new ArrayList<Map<String, Object>>());
Files.writeString(indexPath, gson.toJson(index));
}
} catch (IOException e) {
throw new RuntimeException("Failed to initialize worktree manager", e);
}
this.gitAvailable = isGitRepo();
}
/**
* 检查是否是Git仓库
*/
private boolean isGitRepo() {
try {
ProcessBuilder pb = new ProcessBuilder("git", "rev-parse", "--is-inside-work-tree");
pb.directory(repoRoot.toFile());
Process process = pb.start();
return process.exitValue() == 0;
} catch (Exception e) {
return false;
}
}
/**
* 执行Git命令
*/
private String runGit(List<String> args) throws Exception {
if (!gitAvailable) {
throw new RuntimeException("Not in a git repository. worktree tools require git.");
}
ProcessBuilder pb = new ProcessBuilder("git");
pb.command().addAll(args);
pb.directory(repoRoot.toFile());
Process process = pb.start();
boolean finished = process.waitFor(120, TimeUnit.SECONDS);
if (!finished) {
process.destroy();
throw new RuntimeException("git command timeout");
}
int exitCode = process.exitValue();
if (exitCode != 0) {
String error = new String(process.getErrorStream().readAllBytes()).trim();
String output = new String(process.getInputStream().readAllBytes()).trim();
String message = error.isEmpty() ? output : error;
if (message.isEmpty()) {
message = "git " + String.join(" ", args) + " failed";
}
throw new RuntimeException(message);
}
String output = new String(process.getInputStream().readAllBytes()).trim();
String error = new String(process.getErrorStream().readAllBytes()).trim();
String result = output + (error.isEmpty() ? "" : "\n" + error);
return result.isEmpty() ? "(no output)" : result;
}
/**
* 加载索引文件
*/
@SuppressWarnings("unchecked")
private Map<String, Object> loadIndex() throws IOException {
String content = Files.readString(indexPath);
Type type = new TypeToken<Map<String, Object>>(){}.getType();
return gson.fromJson(content, type);
}
/**
* 保存索引文件
*/
private void saveIndex(Map<String, Object> index) throws IOException {
Files.writeString(indexPath, gson.toJson(index));
}
/**
* 验证工作树名称
*/
private void validateName(String name) {
if (name == null || name.isEmpty() || name.length() > 40) {
throw new IllegalArgumentException("Worktree name must be 1-40 characters");
}
if (!name.matches("[A-Za-z0-9._-]+")) {
throw new IllegalArgumentException(
"Invalid worktree name. Use letters, numbers, ., _, - only"
);
}
// 名称规范:确保工作树名称安全且规范
}
/**
* 创建工作树
*/
public String createWorktree(String name, Integer taskId, String baseRef) throws Exception {
validateName(name);
Map<String, Object> existing = findWorktree(name);
if (existing != null) {
throw new IllegalArgumentException("Worktree '" + name + "' already exists");
}
if (taskId != null && !taskManager.taskExists(taskId)) {
throw new IllegalArgumentException("Task " + taskId + " not found");
}
// 发出创建前事件
Map<String, Object> taskInfo = taskId != null ?
Map.of("id", taskId) : Map.of();
Map<String, Object> worktreeInfo = Map.of("name", name, "base_ref", baseRef);
eventBus.emit("worktree.create.before", taskInfo, worktreeInfo, null);
try {
Path worktreePath = worktreesDir.resolve(name);
String branch = "wt/" + name; // 自动生成分支名
// Git工作树创建
runGit(Arrays.asList("worktree", "add", "-b", branch,
worktreePath.toString(), baseRef));
// Git工作树:独立的代码工作目录
// 自动分支:为每个工作树创建独立分支
// 创建索引条目
Map<String, Object> entry = new LinkedHashMap<>();
entry.put("name", name);
entry.put("path", worktreePath.toString());
entry.put("branch", branch);
entry.put("task_id", taskId);
entry.put("status", "active");
entry.put("created_at", System.currentTimeMillis() / 1000.0);
// 保存到索引
Map<String, Object> index = loadIndex();
@SuppressWarnings("unchecked")
List<Map<String, Object>> worktrees = (List<Map<String, Object>>) index.get("worktrees");
worktrees.add(entry);
saveIndex(index);
// 绑定任务
if (taskId != null) {
taskManager.bindWorktree(taskId, name, "");
}
// 发出创建后事件
Map<String, Object> worktreeAfter = new LinkedHashMap<>();
worktreeAfter.put("name", name);
worktreeAfter.put("path", worktreePath.toString());
worktreeAfter.put("branch", branch);
worktreeAfter.put("status", "active");
eventBus.emit("worktree.create.after", taskInfo, worktreeAfter, null);
return gson.toJson(entry);
} catch (Exception e) {
eventBus.emit("worktree.create.failed", taskInfo,
Map.of("name", name, "base_ref", baseRef), e.getMessage());
throw e;
}
}
/**
* 获取工作树状态
*/
public String getWorktreeStatus(String name) throws IOException {
Map<String, Object> worktree = findWorktree(name);
if (worktree == null) {
return "Error: Unknown worktree '" + name + "'";
}
Path worktreePath = Paths.get((String) worktree.get("path"));
if (!Files.exists(worktreePath)) {
return "Error: Worktree path missing: " + worktreePath;
}
try {
ProcessBuilder pb = new ProcessBuilder("git", "status", "--short", "--branch");
pb.directory(worktreePath.toFile());
Process process = pb.start();
boolean finished = process.waitFor(60, TimeUnit.SECONDS);
if (!finished) {
process.destroy();
return "Error: Git status timeout";
}
String output = new String(process.getInputStream().readAllBytes()).trim();
String error = new String(process.getErrorStream().readAllBytes()).trim();
String result = output + (error.isEmpty() ? "" : "\n" + error);
return result.isEmpty() ? "Clean worktree" : result;
// Git状态检查:提供详细的工作树状态信息
} catch (Exception e) {
return "Error: " + e.getMessage();
}
}
/**
* 在工作树中运行命令
*/
public String runInWorktree(String name, String command) throws Exception {
// 安全检查
String[] dangerous = {"rm -rf /", "sudo", "shutdown", "reboot", "> /dev/"};
for (String d : dangerous) {
if (command.contains(d)) {
return "Error: Dangerous command blocked";
}
}
Map<String, Object> worktree = findWorktree(name);
if (worktree == null) {
return "Error: Unknown worktree '" + name + "'";
}
Path worktreePath = Paths.get((String) worktree.get("path"));
if (!Files.exists(worktreePath)) {
return "Error: Worktree path missing: " + worktreePath;
}
try {
ProcessBuilder pb = new ProcessBuilder("bash", "-c", command);
pb.directory(worktreePath.toFile());
// 目录隔离:命令在工作树的独立目录中执行
Process process = pb.start();
boolean finished = process.waitFor(300, TimeUnit.SECONDS);
if (!finished) {
process.destroy();
return "Error: Timeout (300s)";
}
String output = new String(process.getInputStream().readAllBytes()).trim();
String error = new String(process.getErrorStream().readAllBytes()).trim();
String result = output + (error.isEmpty() ? "" : "\n" + error);
return result.isEmpty() ? "(no output)" :
result.substring(0, Math.min(result.length(), 50000));
} catch (Exception e) {
return "Error: " + e.getMessage();
}
}
/**
* 删除工作树
*/
public String removeWorktree(String name, boolean force, boolean completeTask) throws Exception {
Map<String, Object> worktree = findWorktree(name);
if (worktree == null) {
return "Error: Unknown worktree '" + name + "'";
}
// 发出删除前事件
Integer taskId = (Integer) worktree.get("task_id");
Map<String, Object> taskInfo = taskId != null ?
Map.of("id", taskId) : Map.of();
Map<String, Object> worktreeInfo = Map.of(
"name", name,
"path", worktree.get("path")
);
eventBus.emit("worktree.remove.before", taskInfo, worktreeInfo, null);
try {
List<String> args = new ArrayList<>();
args.addAll(Arrays.asList("worktree", "remove"));
if (force) {
args.add("--force");
}
args.add((String) worktree.get("path"));
runGit(args);
// Git工作树删除:清理Git工作树
// 完成任务
if (completeTask && taskId != null) {
Map<String, Object> task = gson.fromJson(taskManager.getTask(taskId),
new TypeToken<Map<String, Object>>(){}.getType());
taskManager.updateTask(taskId, "completed", null);
taskManager.unbindWorktree(taskId);
// 任务-工作树生命周期协同:删除工作树时自动完成任务
Map<String, Object> taskEvent = new HashMap<>();
taskEvent.put("id", taskId);
taskEvent.put("subject", task.get("subject"));
taskEvent.put("status", "completed");
eventBus.emit("task.completed", taskEvent,
Map.of("name", name), null);
}
// 更新索引
Map<String, Object> index = loadIndex();
@SuppressWarnings("unchecked")
List<Map<String, Object>> worktrees = (List<Map<String, Object>>) index.get("worktrees");
for (Map<String, Object> wt : worktrees) {
if (name.equals(wt.get("name"))) {
wt.put("status", "removed");
wt.put("removed_at", System.currentTimeMillis() / 1000.0);
break;
}
}
saveIndex(index);
// 索引更新:标记工作树为已删除状态
// 发出删除后事件
Map<String, Object> worktreeAfter = new HashMap<>();
worktreeAfter.put("name", name);
worktreeAfter.put("path", worktree.get("path"));
worktreeAfter.put("status", "removed");
eventBus.emit("worktree.remove.after", taskInfo, worktreeAfter, null);
return "Removed worktree '" + name + "'";
} catch (Exception e) {
eventBus.emit("worktree.remove.failed", taskInfo, worktreeInfo, e.getMessage());
throw e;
}
}
/**
* 保留工作树(标记为保留状态)
*/
public String keepWorktree(String name) throws IOException {
Map<String, Object> worktree = findWorktree(name);
if (worktree == null) {
return "Error: Unknown worktree '" + name + "'";
}
Map<String, Object> index = loadIndex();
@SuppressWarnings("unchecked")
List<Map<String, Object>> worktrees = (List<Map<String, Object>>) index.get("worktrees");
Map<String, Object> keptWorktree = null;
for (Map<String, Object> wt : worktrees) {
if (name.equals(wt.get("name"))) {
wt.put("status", "kept");
wt.put("kept_at", System.currentTimeMillis() / 1000.0);
keptWorktree = wt;
break;
}
}
saveIndex(index);
// 保留状态:标记工作树为需要保留,不自动清理
// 发出保留事件
Integer taskId = (Integer) worktree.get("task_id");
Map<String, Object> taskInfo = taskId != null ?
Map.of("id", taskId) : Map.of();
Map<String, Object> worktreeInfo = new HashMap<>();
worktreeInfo.put("name", name);
worktreeInfo.put("path", worktree.get("path"));
worktreeInfo.put("status", "kept");
eventBus.emit("worktree.keep", taskInfo, worktreeInfo, null);
return keptWorktree != null ? gson.toJson(keptWorktree) :
"Error: Unknown worktree '" + name + "'";
}
}
// 初始化工作树管理器
private static final WorktreeManager WORKTREES = new WorktreeManager(REPO_ROOT, TASKS, EVENTS);
// --- 新增:工具处理器 ---
static {
// 新增任务工具
TOOL_HANDLERS.put("task_create", args -> {
String subject = (String) args.get("subject");
String description = (String) args.get("description");
return TASKS.createTask(subject, description);
});
TOOL_HANDLERS.put("task_list", args -> TASKS.listAllTasks());
TOOL_HANDLERS.put("task_get", args -> {
int taskId = ((Number) args.get("task_id")).intValue();
return TASKS.getTask(taskId);
});
TOOL_HANDLERS.put("task_update", args -> {
int taskId = ((Number) args.get("task_id")).intValue();
String status = (String) args.get("status");
String owner = (String) args.get("owner");
return TASKS.updateTask(taskId, status, owner);
});
TOOL_HANDLERS.put("task_bind_worktree", args -> {
int taskId = ((Number) args.get("task_id")).intValue();
String worktree = (String) args.get("worktree");
String owner = (String) args.get("owner");
return TASKS.bindWorktree(taskId, worktree, owner);
});
// 新增工作树工具
TOOL_HANDLERS.put("worktree_create", args -> {
String name = (String) args.get("name");
Integer taskId = args.get("task_id") != null ?
((Number) args.get("task_id")).intValue() : null;
String baseRef = (String) args.get("base_ref");
if (baseRef == null) baseRef = "HEAD";
return WORKTREES.createWorktree(name, taskId, baseRef);
});
TOOL_HANDLERS.put("worktree_list", args -> WORKTREES.listWorktrees());
TOOL_HANDLERS.put("worktree_status", args -> {
String name = (String) args.get("name");
return WORKTREES.getWorktreeStatus(name);
});
TOOL_HANDLERS.put("worktree_run", args -> {
String name = (String) args.get("name");
String command = (String) args.get("command");
return WORKTREES.runInWorktree(name, command);
});
TOOL_HANDLERS.put("worktree_keep", args -> {
String name = (String) args.get("name");
return WORKTREES.keepWorktree(name);
});
TOOL_HANDLERS.put("worktree_remove", args -> {
String name = (String) args.get("name");
boolean force = args.get("force") != null && (Boolean) args.get("force");
boolean completeTask = args.get("complete_task") != null && (Boolean) args.get("complete_task");
return WORKTREES.removeWorktree(name, force, completeTask);
});
TOOL_HANDLERS.put("worktree_events", args -> {
int limit = args.get("limit") != null ? ((Number) args.get("limit")).intValue() : 20;
return EVENTS.listRecent(limit);
});
}
// --- 新增:工具定义 ---
private static List<Map<String, Object>> getToolSpecs() {
List<Map<String, Object>> tools = new ArrayList<>();
// 任务工具定义...
// 工作树工具定义...
return tools;
}
}
这段代码引入了工作树任务隔离系统,实现了:
- 目录级隔离:每个任务在自己的工作树中执行
- 控制平面与执行平面分离 :
- 控制平面:任务管理(.tasks/)
- 执行平面:工作树管理(.worktrees/)
- 事件总线:记录完整生命周期事件
- Git 工作树集成:利用 git worktree 实现隔离
关键洞察:通过目录隔离并行任务,通过任务ID进行协调。
Git工作树隔离架构
核心思想 :从文件系统隔离升级为Git仓库级别的代码隔离 ,通过Git工作树实现完全隔离的并行开发环境,为每个任务提供独立的代码工作空间,避免冲突,支持真正的并行开发。
java
// 核心路径配置
private static final Path REPO_ROOT = detectRepoRoot(WORKDIR); // Git仓库根目录
private static final Path WORKTREES_DIR = REPO_ROOT.resolve(".worktrees"); // 工作树目录
// Git仓库感知:自动检测Git仓库根目录
// 工作树管理:专门的工作树存储目录
// 版本控制集成:与Git深度集成
java
// Git仓库检测
private static Path detectRepoRoot(Path cwd) {
try {
ProcessBuilder pb = new ProcessBuilder("git", "rev-parse", "--show-toplevel");
pb.directory(cwd.toFile());
Process process = pb.start();
String output = new String(process.getInputStream().readAllBytes()).trim();
Path root = Paths.get(output);
return Files.exists(root) ? root : cwd;
// 自动发现:自动定位Git仓库根目录
// 兼容处理:非Git仓库时回退到当前目录
} catch (Exception e) {
return cwd;
}
}
- Git原生集成:深度集成Git版本控制系统
- 仓库感知:自动识别和适应Git仓库结构
- 向后兼容:非Git环境也能工作
- 专业级隔离:为专业软件开发设计
工作树管理系统
java
// 工作树管理器核心
static class WorktreeManager {
private final Path repoRoot;
private final TaskManager taskManager;
private final EventBus eventBus;
private final Path worktreesDir;
private final Path indexPath;
private final boolean gitAvailable;
// 三组件集成:仓库、任务、事件总线
// 索引管理:工作树元数据索引
// 可用性检查:检测Git环境
}
- 集成架构:与任务管理和事件系统深度集成
- 元数据管理:工作树元数据集中管理
- 环境感知:自动检测和适应Git环境
- 专业级管理:企业级的工作树生命周期管理
Git工作树创建机制
java
// 创建工作树
public String createWorktree(String name, Integer taskId, String baseRef) throws Exception {
validateName(name);
Path worktreePath = worktreesDir.resolve(name);
String branch = "wt/" + name; // 自动生成分支名
// Git工作树创建
runGit(Arrays.asList("worktree", "add", "-b", branch,
worktreePath.toString(), baseRef));
// Git工作树:独立的工作目录
// 自动分支:为每个工作树创建独立分支
// 创建索引条目
Map<String, Object> entry = new LinkedHashMap<>();
entry.put("name", name);
entry.put("path", worktreePath.toString());
entry.put("branch", branch);
entry.put("task_id", taskId);
entry.put("status", "active");
entry.put("created_at", System.currentTimeMillis() / 1000.0);
// 完整元数据:名称、路径、分支、关联任务
// 状态管理:明确的工作树生命周期状态
// 保存到索引
Map<String, Object> index = loadIndex();
@SuppressWarnings("unchecked")
List<Map<String, Object>> worktrees = (List<Map<String, Object>>) index.get("worktrees");
worktrees.add(entry);
saveIndex(index);
// 索引管理:集中式工作树元数据管理
// 持久化:工作树信息持久化存储
}
- Git原生:使用Git工作树实现真正的代码隔离
- 自动分支:为每个工作树自动创建分支
- 元数据完整:完整的工作树元数据记录
- 持久化索引:工作树信息持久化存储
- 状态管理:明确的工作树生命周期状态
任务-工作树双向绑定
java
// 任务管理器中的工作树绑定
public String bindWorktree(int taskId, String worktree, String owner) throws IOException {
Map<String, Object> task = loadTask(taskId);
task.put("worktree", worktree);
// 双向绑定:任务记录工作树,工作树记录任务
// 关联管理:建立任务和工作树的一对一关系
if (owner != null && !owner.isEmpty()) {
task.put("owner", owner);
}
if ("pending".equals(task.get("status"))) {
task.put("status", "in_progress");
// 状态自动转换:绑定工作树时自动开始任务
// 工作流优化:简化任务启动流程
}
task.put("updated_at", System.currentTimeMillis() / 1000.0);
saveTask(task);
return gson.toJson(task);
}
java
// 工作树管理器中的任务绑定
if (taskId != null) {
taskManager.bindWorktree(taskId, name, "");
// 协同绑定:创建工作树时自动绑定任务
// 双向同步:确保任务和工作树状态一致
}
- 双向关联:任务和工作树相互引用
- 状态协同:任务和工作树状态自动同步
- 工作流简化:自动的状态转换和绑定
- 数据一致性:确保关联数据的一致性
工作树操作隔离
java
// 在工作树中运行命令
public String runInWorktree(String name, String command) throws Exception {
Map<String, Object> worktree = findWorktree(name);
Path worktreePath = Paths.get((String) worktree.get("path"));
try {
ProcessBuilder pb = new ProcessBuilder("bash", "-c", command);
pb.directory(worktreePath.toFile());
// 目录隔离:命令在工作树的独立目录中执行
// 环境隔离:每个工作树有自己的Git环境
Process process = pb.start();
boolean finished = process.waitFor(300, TimeUnit.SECONDS);
String output = new String(process.getInputStream().readAllBytes()).trim();
String error = new String(process.getErrorStream().readAllBytes()).trim();
String result = output + (error.isEmpty() ? "" : "\n" + error);
return result.isEmpty() ? "(no output)" :
result.substring(0, Math.min(result.length(), 50000));
} catch (Exception e) {
return "Error: " + e.getMessage();
}
}
- 完全隔离:每个工作树是独立的文件系统目录
- Git环境隔离:每个工作树有自己的Git配置和历史
- 安全执行:命令在隔离环境中执行
- 结果返回:返回完整的命令执行结果
Git状态检查
java
// 获取工作树状态
public String getWorktreeStatus(String name) throws IOException {
Path worktreePath = Paths.get((String) worktree.get("path"));
try {
ProcessBuilder pb = new ProcessBuilder("git", "status", "--short", "--branch");
pb.directory(worktreePath.toFile());
// Git状态:获取详细的工作树Git状态
// 信息丰富:包括分支信息、变更状态等
Process process = pb.start();
boolean finished = process.waitFor(60, TimeUnit.SECONDS);
String output = new String(process.getInputStream().readAllBytes()).trim();
String error = new String(process.getErrorStream().readAllBytes()).trim();
String result = output + (error.isEmpty() ? "" : "\n" + error);
return result.isEmpty() ? "Clean worktree" : result;
} catch (Exception e) {
return "Error: " + e.getMessage();
}
}
- Git专业:提供专业的Git状态信息
- 实时状态:实时检查工作树的Git状态
- 变更追踪:跟踪代码变更情况
- 问题诊断:便于诊断Git相关问题
工作树生命周期管理
java
// 删除工作树
public String removeWorktree(String name, boolean force, boolean completeTask) throws Exception {
// Git工作树删除
List<String> args = new ArrayList<>();
args.addAll(Arrays.asList("worktree", "remove"));
if (force) {
args.add("--force");
}
args.add((String) worktree.get("path"));
runGit(args);
// Git清理:使用Git命令清理工作树
// 选项支持:支持强制删除等选项
// 完成任务
if (completeTask && taskId != null) {
taskManager.updateTask(taskId, "completed", null);
taskManager.unbindWorktree(taskId);
// 生命周期协同:删除工作树时自动完成任务
// 状态清理:清理任务和工作树的关联
Map<String, Object> taskEvent = new HashMap<>();
taskEvent.put("id", taskId);
taskEvent.put("subject", task.get("subject"));
taskEvent.put("status", "completed");
eventBus.emit("task.completed", taskEvent,
Map.of("name", name), null);
}
// 更新索引
for (Map<String, Object> wt : worktrees) {
if (name.equals(wt.get("name"))) {
wt.put("status", "removed");
wt.put("removed_at", System.currentTimeMillis() / 1000.0);
break;
}
}
saveIndex(index);
// 状态更新:标记工作树为已删除状态
// 历史保留:保留工作树的删除记录
}
- 完整生命周期:创建、使用、保留、删除的完整生命周期
- Git原生:使用Git命令管理工作树
- 任务协同:工作树删除时自动处理关联任务
- 状态管理:明确的工作树状态管理
- 历史追踪:保留工作树的历史记录
工作树保留机制
java
// 保留工作树
public String keepWorktree(String name) throws IOException {
for (Map<String, Object> wt : worktrees) {
if (name.equals(wt.get("name"))) {
wt.put("status", "kept");
wt.put("kept_at", System.currentTimeMillis() / 1000.0);
keptWorktree = wt;
break;
}
}
saveIndex(index);
// 保留状态:标记工作树为需要保留
// 不自动清理:保留的工作树不会被自动清理
// 时间戳记录:记录保留时间
}
- 选择性保留:可以保留有价值的工作树
- 长期存储:保留的工作树可以长期存在
- 状态明确:明确的保留状态标记
- 时间追踪:记录保留时间
事件总线集成
java
// 事件总线
static class EventBus {
public void emit(String event, Map<String, Object> task,
Map<String, Object> worktree, String error) {
Map<String, Object> payload = new LinkedHashMap<>();
payload.put("event", event);
payload.put("ts", System.currentTimeMillis() / 1000.0);
payload.put("task", task != null ? task : Map.of());
payload.put("worktree", worktree != null ? worktree : Map.of());
if (error != null) {
payload.put("error", error);
}
// 结构化事件:标准的事件格式
// 时间戳:精确的事件时间
// 关联数据:关联的任务和工作树信息
// 错误信息:支持错误事件记录
String jsonLine = gson.toJson(payload) + "\n";
Files.writeString(eventLogPath, jsonLine,
StandardOpenOption.CREATE, StandardOpenOption.APPEND);
// JSONL格式:便于流式处理和分析
// 追加写入:支持长时间运行的事件记录
}
}
- 全面审计:所有工作树操作都有完整的事件记录
- 结构化日志:标准化的JSON事件格式
- 时间序列:精确的时间戳序列
- 错误追踪:完整的错误事件追踪
- 可分析性:便于后续的数据分析
架构演进与价值
从 AutonomousAgentsSystem 到 WorktreeTaskIsolationSystem 的升级:
| 维度 | AutonomousAgentsSystem | WorktreeTaskIsolationSystem |
|---|---|---|
| 代码隔离 | 文件系统级 | Git仓库级 |
| 并行开发 | 有限并行 | 完全并行 |
| 版本控制 | 外部集成 | 原生集成 |
| 冲突避免 | 手动管理 | 自动隔离 |
| 专业程度 | 通用系统 | 专业开发系统 |
总结
完结撒花。。。
总体来说,这个开源网站系统性地拆解了一个高级AI编程智能体的构建过程,展现了一条清晰的能力演进路径:从具备基础感知和执行能力的单一智能体(工具与执行),发展到能够进行内部规划、分解任务、调用外部知识的协调者(规划与协调),再升级为可以管理资源、并行处理、支撑长时对话的高效执行者(内存管理与并发),最终演化为一个角色分明、通信顺畅、协同作战的智能体团队(协作)。
这条路径揭示了一个核心范式:强大的AI Agent系统并非一蹴而就,可以说是通过不断叠加精心设计的、模块化的机制(如状态管理、上下文隔离、知识外挂、异步处理、消息传递)逐步构建而成。
每个阶段都解决了前一阶段遇到的关键瓶颈,最终将这些模块像积木一样组合,形成一个既可应对复杂项目开发,又能高效管理自身资源与协作的成熟智能体系统。这为我们构建自己的生产级AI Agent提供了宝贵的蓝图和实战指南。