惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Fortinet All Blogs
C
Check Point Blog
GbyAI
GbyAI
博客园 - 司徒正美
爱范儿
爱范儿
N
Netflix TechBlog - Medium
H
Hacker News: Front Page
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Security Latest
Security Latest
C
Cyber Attacks, Cyber Crime and Cyber Security
博客园 - Franky
Recent Announcements
Recent Announcements
P
Privacy International News Feed
T
Tor Project blog
Y
Y Combinator Blog
有赞技术团队
有赞技术团队
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
G
GRAHAM CLULEY
The Hacker News
The Hacker News
N
News and Events Feed by Topic
I
Intezer
The GitHub Blog
The GitHub Blog
S
SegmentFault 最新的问题
T
The Blog of Author Tim Ferriss
PCI Perspectives
PCI Perspectives
S
Secure Thoughts
P
Proofpoint News Feed
Microsoft Security Blog
Microsoft Security Blog
IT之家
IT之家
T
Threat Research - Cisco Blogs
J
Java Code Geeks
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
D
DataBreaches.Net
Hacker News - Newest:
Hacker News - Newest: "LLM"
Last Week in AI
Last Week in AI
H
Help Net Security
L
LangChain Blog
大猫的无限游戏
大猫的无限游戏
Help Net Security
Help Net Security
S
Schneier on Security
T
The Exploit Database - CXSecurity.com
Google Online Security Blog
Google Online Security Blog
Cyberwarzone
Cyberwarzone
T
Tailwind CSS Blog
V
Vulnerabilities – Threatpost
Forbes - Security
Forbes - Security
Apple Machine Learning Research
Apple Machine Learning Research
O
OpenAI News
AWS News Blog
AWS News Blog
月光博客
月光博客

博客园_首页

Linux实操--组管理、权限管理和定时任务 Java + EasyExcel 实现单个接口导出多个Excel Mem0 源码解析系列(二):提示词工程的深度剖析 Openclaw TaskFlow究竟是什么?和普通Skill技能有什么区别 博文阅读密码验证 - 博客园 嘉立创开源:应该是全网MicroPython教程最多的开发板 Hermes Agent 集成实践:从协议到生产 2026年AI编程工具横评:Cursor、Codex、Claude Code、Zed、Windsurf Java程序员必看的RAG入门教程 2026 AI效率神器:Superpowers + Claude Code 保姆级教程 本地大模型部署全攻略:从 0 到 1 玩转 Ollama 【从0到1构建一个ClaudeAgent】内存管理-上下文压缩 .NET 高级开发 | 设计、实现一个事件总线框架 电子小白入门之NE555 3. WorkBuddy:隐藏玩法,一键召唤专家,让 AI 以"专家身份"给你干活 和AI一起搞事情#3:Claude Teammate 游戏开发翻车实录 【OpenClaw】通过 Nanobot 源码学习架构---(7)Memory C# .NET 周刊|2026年3月3期 我在 Debian 11 上把 K8s 单机搭起来了,过程没你想的那么顺(/opt 目录版) 深度学习进阶(七)Data-efficient Image Transformer CLI+Skill搭建浏览器AI自动化框架,告别一切重复枯燥任务 告别Token账单无底洞:OpenClaw本地部署,重塑企业数据主权的唯一解 FastAPI+Vue:文件分片上传+秒传+断点续传,这坑我帮你踩平了! SBTI 爆火后,我做了个程序员版的 CBTI。。已开源 + 附开发过程 多模态检索开始进入工程期:用 Sentence Transformers 搭建可落地的 Multimodal RAG 100多行代码实现一个最简单的Agent(用ReAct) Claude Code 通关手册(八):推荐 5 个 Hooks,代码质量提升 3 倍 老板:“有人截图了!”。安全部门:“收到,马上查暗水印!” - why技术 技术之外,皆是人间 C#/.NET/.NET Core技术前沿周刊 | 第 69 期(2026年4.01-4.12) Snack JSONPath 项目架构分析 Claude Code Buddy 小析:一个非核心功能,如何体现产品的细节完成度 AI新时代下的图床管理方案-Cloudflare图床+MCP+Skills方案指南 化繁为简:顺丰速运App如何通过 HarmonyOS SDK实现专业级空间测量 从零实现富文本编辑器#13-React非编辑节点的内容渲染 AI开发-python-langchain框架(3-23-OpenAI Functions风格Tool Calling智能助手) .NET + AI 进阶实战:基于类的技能开发 - 打造可治理的 Agent 能力模块 【从0到1构建一个ClaudeAgent】规划与协调-技能 上周热点回顾(4.6-4.12) 电子小白的工具三件套:面包板、杜邦线、万能板 单表五亿数据的查询优化 | Mysql、StarRocks 2. WorkBuddy:从“我是谁”到“帮我干活” C# 如何减少代码运行时间:7 个实战技巧 基于HelixToolkit.SharpDX 渲染3D模型 - 笺上知微 从零开始的双臂具身VLA起源及现阶段发展综述 - SkyXZ 记对 xonsh shell 的使用, 脚本编写, 迁移及调优 - pluvium27 受够了Vibe Coding的失控?换个起点,让AI事半功倍 从开始配置漏洞环境到漏洞复现流程 - 難しい 关于10年工作经验的程序员对OpenClaw的实战经验分享以及看法 - 虚无境 Any metadata 的内存布局 C# .NET 周刊|2026年3月2期 - InCerry 我帮你测过了,测试圈排名第二的 Skill 依然很牛逼 Skill Discovery | 无监督技能发现的经典工作总结 - MoonOut PbootCMS 网站内容数量多导致访问慢?这些实用优化方案帮你提速! - 家兴网络技术工作室 上下文工程是什么?过时了么?一文讲明白! - 一枫说码 网站漏洞怎么发现并修复?一篇实用指南(附完整流程) - 家兴网络技术工作室 开了 TUN 模式还是直连?90% 的人都踩过这个坑 Github日报|2026年04月12日 - AI一族 AScript扩展多种脚本语言 - rockey627 AI 学习笔记:Agent 的记忆机制 你能被装进一个文件里吗?——7 万人把同事"蒸馏"成了 AI - 我没有三颗心脏 Claude Code 通关手册(七):给 AI 装上技能包——Skills 完全指南 - 暮色之狐 在浏览器中快速编辑代码:VSCode Web 集成实践 - Newbe36524 蒸馏自己 skill?基于 Deepseek 的蒸馏器,丐版蒸馏方式,简单便捷 - To_Carpe_Diem Spring AI Aliababa和AgentScope,哪个更好? - 苏三说技术 Etsy 把 1000 个 MySQL 分片迁进 Vitess:425TB 数据背后的真正问题不是性能,而是运维规模 MicroPython LVGL基础知识和概念:底层渲染与性能优化 - FreakStudio 数据库草图算法 Python 潮流周刊#146:CPython 引入 Rust 的进展 - 豌豆花下猫 最小生成树 - mofei1116 红日靶场七:从外网入口、容器逃逸到 AD 接管的完整利用链复盘 - YouDiscovered1t 分享四款开源且实用的 Kafka 管理工具 - 追逐时光者 vLLM 权重加载机制全解析:从挑战到理想架构 LCT 学习笔记 - ACehomoxue Avalonia UI 12.0.0 正式发布:架构演进和性能飞跃 - 张善友 当 AI Agent 把调用链拉长,延迟开始成为一门生意 conhost.exe 无法显示 U+2717 - 145a 太秀了,我把自己蒸馏成了 Skill!已开源 - 程序员鱼皮 ASP.NET Core 内存缓存实战:一篇搞懂该怎么配、怎么避坑 基于 Ghostty 带有分割标签页和为 Claude 编程设计的通知终端 - BugShare AI 焊死入口:教育的“操作系统级”重塑 - 郝hai 初级Java开发工程师使用sql脚本编写代码的过程是简单而且不糊涂 - CoderOilStation Claude Code通关手册(六):MCP协议完全指南 - 暮色之狐 边框灯光环绕动画特效实现指南 - Newbe36524 开源:子木蒸馏版的 SEO 审计工具 seo-audit-skill v1.0 我所理解的Python元模型 【从0到1构建一个ClaudeAgent】规划与协调-TodoWrite - 程序员Seven Claude 和 Codex 在审计 Skill 上性能差异探究 - ACai_sec AScript如何实现中文脚本引擎 - rockey627 【渗透测试】HTB Season10 Garfield 全过程wp - dynasty_chenzi Android 开发者为什么必须掌握 AI 能力?端侧视角下的技术变革 树状数组正确性证明 - AC-wyr 你的 AI 焦虑,可能比 AI 本身更危险——ATM 机没有消灭银行柜员,但恐慌消灭了你的判断力 - 我没有三颗心脏 一个拉胯的分库分表方案有多绝望?整个部门都在救火! - 冰河团队 动态规划入门必学之走方格问题 - Ofnoname PostgREST 与 PostgreSQL 角色权限配置全解析(生产级实践) - SheepDog1998 使用 UEFI 图形输出协议 GOP 在屏幕上显示图像的方法 - 阿源- Claude Code通关手册(五):组建你的AI专家团队,子代理系统 - 暮色之狐 一个程序员到架构师的催婚路之感悟(整整10年后的催婚相亲感悟) - MisterLip 用 Agent Skill 自动生成工作周报 - 赵康
【从0到1构建一个ClaudeAgent】协作-Worktree+任务隔离
程序员Seven · 2026-04-20 · via 博客园_首页

到 s11, 智能体已经能自主认领和完成任务。但所有任务共享一个目录。两个智能体同时重构不同模块 -- A 改 config.py, B 也改 config.py, 未提交的改动互相污染, 谁也没法干净回滚。

任务板管 "做什么" 但不管 "在哪做"。解法: 给每个任务一个独立的 git worktree 目录, 用任务 ID 把两边关联起来。"各干各的目录, 互不干扰",任务管目标,,worktree 管目录,按 ID 绑定。

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;
    }
}

这段代码引入了工作树任务隔离系统,实现了:

  1. 目录级隔离:每个任务在自己的工作树中执行
  2. 控制平面与执行平面分离
    • 控制平面:任务管理(.tasks/)
    • 执行平面:工作树管理(.worktrees/)
  3. 事件总线:记录完整生命周期事件
  4. Git 工作树集成:利用 git worktree 实现隔离

关键洞察:通过目录隔离并行任务,通过任务ID进行协调。

Git工作树隔离架构

核心思想:从文件系统隔离升级为Git仓库级别的代码隔离,通过Git工作树实现完全隔离的并行开发环境,为每个任务提供独立的代码工作空间,避免冲突,支持真正的并行开发。

// 核心路径配置
private static final Path REPO_ROOT = detectRepoRoot(WORKDIR);  // Git仓库根目录
private static final Path WORKTREES_DIR = REPO_ROOT.resolve(".worktrees");  // 工作树目录
// Git仓库感知:自动检测Git仓库根目录
// 工作树管理:专门的工作树存储目录
// 版本控制集成:与Git深度集成
// 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环境也能工作
  • 专业级隔离:为专业软件开发设计

工作树管理系统

// 工作树管理器核心
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工作树创建机制

// 创建工作树
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工作树实现真正的代码隔离
  • 自动分支:为每个工作树自动创建分支
  • 元数据完整:完整的工作树元数据记录
  • 持久化索引:工作树信息持久化存储
  • 状态管理:明确的工作树生命周期状态

任务-工作树双向绑定

// 任务管理器中的工作树绑定
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);
}
// 工作树管理器中的任务绑定
if (taskId != null) {
    taskManager.bindWorktree(taskId, name, "");
    // 协同绑定:创建工作树时自动绑定任务
    // 双向同步:确保任务和工作树状态一致
}
  • 双向关联:任务和工作树相互引用
  • 状态协同:任务和工作树状态自动同步
  • 工作流简化:自动的状态转换和绑定
  • 数据一致性:确保关联数据的一致性

工作树操作隔离

// 在工作树中运行命令
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状态检查

// 获取工作树状态
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相关问题

工作树生命周期管理

// 删除工作树
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命令管理工作树
  • 任务协同:工作树删除时自动处理关联任务
  • 状态管理:明确的工作树状态管理
  • 历史追踪:保留工作树的历史记录

工作树保留机制

// 保留工作树
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);
    // 保留状态:标记工作树为需要保留
    // 不自动清理:保留的工作树不会被自动清理
    // 时间戳记录:记录保留时间
}
  • 选择性保留:可以保留有价值的工作树
  • 长期存储:保留的工作树可以长期存在
  • 状态明确:明确的保留状态标记
  • 时间追踪:记录保留时间

事件总线集成

// 事件总线
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提供了宝贵的蓝图和实战指南。