Initial documentation for route A (port claude-code-action to Gitea Actions). Research complete, no implementation code yet. See docs/02-roadmap.md for milestones.
4.1 KiB
4.1 KiB
02 - 路线图
调研结论(2026-05-25)
调研了 4 个候选 OSS:
| 项目 | Stars | 契合度 | 结论 |
|---|---|---|---|
| anthropics/claude-code-action | 7.7k | ⭐⭐⭐⭐⭐ | GitHub Only,移植到 Gitea 是这次项目的核心工作 |
| All-Hands-AI/OpenHands | 40k+ | ⭐⭐⭐ | 非 Claude 原生,Gitea 支持弱,引入了大量不需要的东西 |
| SWE-agent/SWE-agent | 19.3k | ⭐⭐ | 学术为主,一次性自动修,不擅长多轮交互 |
| Turrain/claude-gitea-app | 1 | ⭐⭐⭐ | 名字对路但太小(20KB),不能依赖 |
Gitea 生态周边可复用:
- Sqcows/forgejo-mcp — Forgejo/Gitea MCP server,103 工具
- pkulik0/gitea-skill —
teaCLI 的 Claude Code Skill
结论:复刻 claude-code-action 是最直接的路径,OpenHands 等通用方案在交互性上不及。
路线 A:移植 claude-code-action 到 Gitea Actions(当前阶段)
目标:端到端跑通最小可用版本,体感先达到 "issue 里说话 → Claude 在评论里回复 → 同意后 PR 自动开"。
Milestone A1:基础设施(第 1 周)
- fork upstream,确定 TS/Bun 工具链能在 act_runner 里跑
- 在 Gitea 控制面板创建
@claudebot 用户 + 对应 access token - 验证 Gitea webhook → workflow_dispatch 链路
- 写 Gitea API 客户端(
src/gitea/api/),覆盖:- 评论 CRUD
- issue/PR 读取
- 分支创建 + push
- PR 创建
Milestone A2:tag 模式跑通(第 2 周)
- 移植
src/modes/tag/(@claude 触发的最常用模式) - 移植
src/create-prompt/(基本不动,确认 context 字段映射) - 移植
src/entrypoints/(适配 Gitea 事件载荷格式) .gitea/workflows/claude.yml示例工作流- 在本仓库自己开 issue 验证"对话+提 PR"流程
验收标准
1. 我在某个 Gitea 仓库开 issue:「加一个返回当前时间的 /now 接口」
2. issue 正文末尾 @claude
3. 1 分钟内出现 Claude 评论:「先确认几点... a/b/c」
4. 我回复评论:「a 这样,b 那样」
5. Claude 再回复对齐 + 开始执行
6. Claude push 分支 + 开 PR,PR 描述里贴着完整对话和实现说明
路线 B:长驻 webhook 服务(未来)
触发条件:路线 A 跑通后,发现每轮交互 30s+ 冷启动太难受,再启动 B。
架构差异
路线 A:每次评论 → 启动 Action → 加载 context → 退出 (冷)
路线 B:每次评论 → POST 到长驻服务 → 复用 Claude session → 立刻回复 (热)
主要工作
- 用 Python 或 Node 写一个常驻 webhook server(FastAPI / Hono)
- 用
@anthropic-ai/claude-agent-sdk维护{issue_id: ClaudeSession}字典 - 每条 Gitea 评论 webhook → 找到对应 session →
session.send_message()→ 回写评论 - 长会话超时回收策略(24h 不活跃释放)
- 加载 superpowers skills(skills 目录注入)
- 部署:和 Gitea 同机 docker-compose,加一个
claude-agent服务
升级路径
设计路线 A 代码时已保留两个抽象接口:
interface EventDispatcher {
// A: read GITEA_EVENT_PATH file
// B: subscribe to webhook stream
next(): Promise<GiteaEvent>
}
interface SessionStore {
// A: fresh prompt each run
// B: persistent ClaudeSession per issue
get(key: string): Promise<Session>
save(key: string, session: Session): Promise<void>
}
切换路线时只需新实现这两个接口,核心业务逻辑(trigger 解析、Gitea API、PR 流程)不动。
不做的事(明确拒绝)
- ❌ 不追求支持 GitHub + Gitea + GitLab 多平台。Gitea-only,避免抽象税
- ❌ 不在路线 A 阶段做 Web UI / dashboard。命令行 + Gitea 评论已够
- ❌ 不做"全自动决策合并 PR"。Claude 提 PR,人审核合并
- ❌ 不移植上游所有 mode(review/agent 等),只做 tag mode
决策记录
非显然的设计选择记在 04-decisions.md。