## 1. API 端点新增 - [ ] 1.1 实现 `POST /api/v1/tasks/dequeue`:Agent 主动拉取任务,根据 capabilities 匹配,原子分配(复用 EventStore::dequeue_and_assign) - [ ] 1.2 实现 `POST /api/v1/tasks/{task_id}/status`:Agent 更新任务状态(assigned→running 等),验证 agent 归属 - [ ] 1.3 实现 `GET /api/v1/tasks/{task_id}`:返回单个任务详情 JSON - [ ] 1.4 实现 `POST /api/v1/tasks/{task_id}/complete`:非 PR 任务显式完成 + receipt 验证 - [ ] 1.5 在 EventStore 中添加 `read_task_with_events(task_id)` 方法(任务详情 + 事件历史) - [ ] 1.6 在 `src/main.rs` 注册新路由 ## 2. Token 认证 - [ ] 2.1 在 register 响应中生成并返回 registry_token(随机 UUID 或 HMAC) - [ ] 2.2 在 EventStore 中存储 agent_id → token 映射 - [ ] 2.3 实现 axum middleware 验证 `Authorization: Bearer {token}` header - [ ] 2.4 将 middleware 应用于任务相关端点(dequeue、status、complete、receipt) - [ ] 2.5 heartbeat 和 deregister 端点也要求 token 认证 ## 3. Forgejo webhook 扩展 - [ ] 3.1 扩展 Forgejo webhook handler 支持 `pull_request` 事件(opened、merged) - [ ] 3.2 PR opened → 从分支名解析 task_id → 更新任务状态为 `review_pending` - [ ] 3.3 PR merged → 从分支名解析 task_id → 自动生成 receipt → 任务状态转为 `completed` → Issue 评论 - [ ] 3.4 扩展 Forgejo webhook handler 支持 `push` 事件:匹配 `task/*` 分支 → 更新 `last_activity_at` - [ ] 3.5 在 Task 模型中添加 `branch_name`、`pr_title`、`last_activity_at` 字段 ## 4. State machine 扩展 - [ ] 4.1 添加 `review_pending` 状态(running → review_pending → completed/running) - [ ] 4.2 添加 `review_count` 字段到 Task,跟踪 review 循环次数 - [ ] 4.3 review_count 超过 max_retries 时自动标记 failed ## 5. Adapter 模块重写 - [ ] 5.1 重写 `src/adapters/mod.rs`:移除 `AgentAdapter` trait 和 `AdapterRunner`,改为 Agent Protocol 文档 - [ ] 5.2 保留 `AdapterInstanceConfig` 和 `AdapterKind`(用于配置和文档生成) - [ ] 5.3 移除 `AdapterRunner`(Agent 自行管理生命周期) ## 6. 测试与验证 - [ ] 6.1 `cargo check` 通过 - [ ] 6.2 `cargo test` 全部通过 - [ ] 6.3 新增 dequeue 测试(匹配成功、无匹配任务、并发 dequeue) - [ ] 6.4 新增 status update 测试(正常更新、非所属 Agent 被拒) - [ ] 6.5 新增 token 认证测试(有效 token、无效 token、缺失 token) - [ ] 6.6 新增 complete 端点测试(正常完成、非 owner 被拒) - [ ] 6.7 新增 Forgejo PR webhook 测试(PR opened → review_pending、PR merged → completed) - [ ] 6.8 新增 push webhook 测试(task 分支 → last_activity_at 更新) - [ ] 6.9 新增 review loop limit 测试(超过 max_retries → failed)