
任务板管 做什么 但不管 在哪做。解法: 给每个任务一个独立的 git worktree 目录, 用任务 ID 把两边关联起来。各干各的目录, 互不干扰任务管目标,worktree 管目录按 ID 绑定。Java实现代码javapublic 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, MapString, Object task, MapString, Object worktree, String error) { MapString, 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 { ListString lines Files.readAllLines(eventLogPath); ListMapString, Object events new ArrayList(); int start Math.max(0, lines.size() - n); for (int i start; i lines.size(); i) { try { Type type new TypeTokenMapString, Object(){}.getType(); MapString, Object event gson.fromJson(lines.get(i), type); events.add(event); } catch (Exception e) { MapString, 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 { MapString, 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 { MapString, 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)) { MapString, Object index new HashMap(); index.put(worktrees, new ArrayListMapString, 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(ListString 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 MapString, Object loadIndex() throws IOException { String content Files.readString(indexPath); Type type new TypeTokenMapString, Object(){}.getType(); return gson.fromJson(content, type); } /** * 保存索引文件 */ private void saveIndex(MapString, Object index) throws IOException { Files.writeString(indexPath, gson.toJson(index)); } /** * 验证工作树名称 */