2025-10 Update: The legacy task/agent workflow described here has been deprecated. The dashboard now focuses solely on worktree management; the notes below are retained for historical context.
项目目标
创建一个名为 agentdev ui 的 Web 应用,为 agentdev 工具提供一个直观、易用的图形化界面。此 UI 旨在彻底摆脱对 tmux 知识的依赖,让任何用户都能方便地对多个命令行 AI Agent 在同一任务上的表现进行并排的“体感对比 (vibe eval)”。
核心工作流
- 启动 (Launch): 用户在终端中运行
agentdev ui。该命令会启动一个本地 Web 服务器,并自动在浏览器中打开http://localhost:xxxx,展现agentdev的图形化主界面。 - 任务概览 (Overview): UI 主界面采用经典的三栏式布局:
- 左侧边栏: 以可折叠的树状结构展示所有评测任务 (
Task) 及其包含的 Agent 实例。提供一个醒目的“新建任务”按钮。 - 主编辑区: 根据用户的选择,动态展示
git diff视图。 - 底部面板: 提供一个嵌入式的终端,用于与选定的 Agent 进行实时交互。
- 左侧边栏: 以可折叠的树状结构展示所有评测任务 (
- 创建任务 (Create): 用户点击“新建任务”按钮,在弹出的模态框中输入初始指令 (
prompt)。后端会为配置中的每个 Agent 创建独立的git worktree和tmux会话,并在左侧边栏实时更新任务列表。 - 评估对比 (Evaluate & Compare):
- 宏观对比: 当用户在左侧边栏点击一个任务节点时,主编辑区会显示一个合并后的
diff视图,将该任务下所有 Agent 产生的代码变更并排展示,方便快速横向比较。 - 微观审查: 当用户点击一个具体的 Agent 节点时,主编辑区仅显示这一个 Agent 的
git diff,方便深入审查其方案。
- 宏观对比: 当用户在左侧边栏点击一个任务节点时,主编辑区会显示一个合并后的
- 深度交互 (Engage): 当用户在左侧边栏选中一个 Agent 并点击“连接”后,底部面板的嵌入式终端将激活,实时“投射”出该 Agent 所在的
tmux会话内容。用户可以直接在该终端中输入命令,与 Agent 进行完整的、原生的交互。 - 清理 (Clean Up): 用户可以通过 UI 上的按钮或菜单项,一键删除某个评测任务,后端将自动清理所有相关的
git worktree和tmux会话。
技术架构
- 统一二进制: 前端 (Next.js/React) 的静态资源(HTML, CSS, JS)将被编译并嵌入到后端 Rust 二进制文件中。
- 后端 (Rust): 使用
axum框架。它既负责提供 API 和 WebSocket 服务,也负责托管前端静态文件。 - 核心引擎: 后端保留并封装对
git和tmux的调用,作为实现 Agent 并发运行和交互的核心引擎。
为了实现上述需求,我们将项目分解为后端和前端两大模块,共计八个核心任务。
后端 (Rust)
- Task B1: 静态文件嵌入与服务: 使用
rust-embed或类似库将前端编译产物打包进二进制文件,并配置axum来提供这些文件。 - Task B2: API 与 WebSocket 路由: 设计并实现
axum的路由,包括用于数据查询的 RESTful API 和用于实时交互的 WebSocket 端点。 - Task B3:
tmux交互服务: 编写服务逻辑,通过tmux命令实现捕获窗格内容、发送按键等功能,并通过 WebSocket 与前端通信。
前端 (Next.js/React)
4. Task F1: 项目初始化与布局: 创建 Next.js 项目,集成 Tailwind CSS,并搭建三栏式 UI 骨架。
5. Task F2: 左侧任务树实现: 开发 TaskTree 组件,负责从后端获取数据、渲染树状列表,并处理用户选择事件。
6. Task F3: diff 视图实现: 基于 apps/frontend/components/ui/diff 中的 shadcn/Fredrika 组件堆栈渲染 git patch,提供合并行与内联字符高亮,替代旧的 @git-diff-view/react 方案(不再提供 split/wrap 模式切换)。
7. Task F4: 嵌入式终端实现: 开发 TmuxTerminal 组件,集成 xterm.js,并实现与后端 WebSocket 的双向通信。
8. Task F5: 客户端逻辑与状态管理: 开发自定义 Hooks (useTasks, useAgentDevSocket) 来封装 API 调用和 WebSocket 通信,管理客户端状态。
环境设置
- 在
agentdev项目中创建一个monorepo结构,包含apps/backend和apps/frontend两个目录。 - 配置根
package.json以便能同时管理前后端项目的依赖和启动脚本。
编码步骤
-
Step 1: 后端 - 静态文件嵌入 (Task B1)
- 在
apps/backend/Cargo.toml中添加axum-embed和rust-embed依赖。 - 在
apps/backend/src/main.rs中,定义一个struct来嵌入前端build目录的产物。#[derive(RustEmbed)] #[folder = "../../frontend/out"] // 指向 Next.js 静态导出目录 struct FrontendAssets;
- 配置
axum路由,使用axum_embed::Serve<FrontendAssets>来服务静态文件。设置一个fallback路由,将所有未匹配的路径都指向index.html,以支持前端路由。
- 在
-
Step 2: 后端 - API 与 WebSocket (Task B2 & B3)
- 在
apps/backend/src/routes/中定义 API 路由:GET /api/tasks: 返回所有任务及其下的 Agent 列表。POST /api/tasks: 接收prompt,创建新任务,返回新任务信息。DELETE /api/tasks/{task_id}: 删除指定任务。GET /api/tasks/{task_id}/agents/{agent_id}/diff: 返回指定 Agent 的git diff原始文本。
- 定义 WebSocket 路由
GET /ws/tasks/{task_id}/agents/{agent_id}/attach。 - 实现 WebSocket 的
handler函数:- 连接建立: 启动一个循环任务(如每 200ms)。
- 循环任务: 调用
tmux服务,执行tmux capture-pane -p -t <session>捕获窗格内容,并通过 WebSocket 发送给客户端。 - 接收消息: 当从客户端收到消息(用户输入)时,调用
tmux服务,执行tmux send-keys -t <session> '<input>'。
- 在
-
Step 3: 前端 - 初始化与布局 (Task F1)
- 在
apps/frontend目录中,使用create-next-app创建项目,并配置为静态导出模式 (output: 'export'innext.config.js)。 - 集成
Tailwind CSS,并参考专业设计,在tailwind.config.ts和globals.css中定义好颜色、字体等主题变量。 - 创建
components/layout/MainLayout.tsx,使用 Flexbox 或 CSS Grid 实现三栏布局的骨架。
- 在
-
Step 4: 前端 - 核心组件开发 (Task F2, F3, F4)
TaskTree.tsx:- 使用
useEffect在组件挂载时调用fetch('/api/tasks')获取任务列表。 - 使用
useState管理任务列表数据和当前选中的条目 ID。 - 将数据渲染成一个嵌套的
<ul>/<li>列表,并处理点击事件来更新选中状态。
- 使用
- Diff 视图组件:
- 基于
apps/frontend/components/ui/diff中的<Diff>/<Hunk>实现,接收diffText: string并在客户端解析。 - 默认渲染统一视图(无 split/wrap 开关),提供复制补丁、上下文折叠与内联字符编辑高亮,并在大文件上配合虚拟滚动保持 60fps 体验。
- 基于
TmuxTerminal.tsx:- 集成
xterm.js和xterm-addon-fit(用于自适应容器大小)。 - 在组件挂载时初始化
Terminal实例。 - 提供一个
connect(url)方法,该方法内部会创建WebSocket实例,并设置好onmessage和onopen等回调。 - 实现
terminal.onData(data => ws.send(data))将用户输入转发到后端。
- 集成
-
Step 5: 前端 - 逻辑与状态管理 (Task F5)
- 创建
hooks/useTasks.ts:- 封装获取、创建、删除任务的
fetch调用。 - 暴露
tasks,isLoading,error,createTask,deleteTask等状态和方法。
- 封装获取、创建、删除任务的
- 创建
hooks/useAgentDevSocket.ts:- 封装
WebSocket的完整生命周期管理(连接、断开、消息收发、自动重连)。 - 暴露
isConnected,lastMessage,sendMessage等状态和方法。
- 封装
- 在顶层页面组件 (
app/page.tsx) 中使用这些 Hooks,并将状态和方法通过 props 或 React Context 传递给子组件。
- 创建
测试计划
- 后端单元测试: 针对
git和tmux服务的封装进行测试。 - 前后端集成测试:
- 启动流程: 运行
cargo run --bin agentdev -- ui,验证浏览器能成功打开并加载 UI。 - 核心工作流: 手动测试“创建任务 -> 查看合并 Diff -> 查看单个 Diff -> 连接终端交互 -> 删除任务”的完整流程。
- 网络鲁棒性: 在 UI 运行时,手动
kill后端进程,验证前端 WebSocket 是否尝试重连;重启后端后,验证连接是否能自动恢复。
- 启动流程: 运行
- UI/UX 测试: 检查 UI 在不同屏幕尺寸下的响应式表现,验证所有按钮、动画和状态转换是否流畅、符合预期。