任务板管 "做什么" 但不管 "在哪做"。解法: 给每个任务一个独立的 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));
        }
        
        /**
         * 验证工作树名称
         */
Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐