基于 Plan.md 拆分的细粒度开发任务。 每条任务尽量做到「单次可完成、可独立验证」。
依赖指必须先完成的任务编号。
任务编号规则:M{里程碑}-{序号}。
| 编号 | 任务 | 产出物 | 依赖 | 验证方式 |
|---|---|---|---|---|
| ✅ M0-1 | 初始化 go.mod(module 名 jcode-cli,Go 1.22+) |
go.mod |
— | go mod verify 通过 |
| ✅ M0-2 | 引入 eino / eino-ext 依赖 | go.mod go.sum |
M0-1 | go build ./... 无报错 |
| ✅ M0-3 | 搭建目录骨架 cmd/jcode/、internal/{agent,tools,llm}/ |
目录 + 空 main.go |
M0-1 | go run ./cmd/jcode 能启动 |
| ✅ M0-4 | internal/llm:OpenAI 兼容 ChatModel,读 env(OPENAI_API_KEY/OPENAI_BASE_URL/MODEL) |
llm/openai.go |
M0-2,M0-3 | 单测调用 Generate 返回文本 |
| ✅ M0-5 | internal/tools:用 utils.NewTool 实现假工具 get_time |
tools/get_time.go |
M0-2 | 单测直接调用工具返回当前时间 |
| ✅ M0-6 | internal/agent:用 react.NewAgent 组装 Agent,挂 get_time |
agent/agent.go |
M0-4,M0-5 | 构造 Agent 不报错 |
| ✅ M0-7 | main.go:stdin → agent.Stream() → Recv() 循环打印 |
cmd/jcode/main.go |
M0-6 | 输入「现在几点」→ Agent 调用 get_time 并作答 ✅ M0 验收 |
| 编号 | 任务 | 产出物 | 依赖 | 验证方式 |
|---|---|---|---|---|
| ✅ M1-1 | 定义工具统一约定:入参 JSON Schema、统一错误返回结构 | tools/types.go |
M0-7 | 约定文档 + 编译通过 |
| ✅ M1-2 | read_file 工具 |
tools/read_file.go |
M1-1 | 读取已知文件内容正确 |
| ✅ M1-3 | write_file 工具(创建/覆盖) |
tools/write_file.go |
M1-1 | 写入后内容一致 |
| ✅ M1-4 | edit_file 工具(按字符串替换编辑) |
tools/edit_file.go |
M1-2,M1-3 | 编辑后 diff 符合预期 |
| ✅ M1-5 | run_shell 工具(捕获 stdout/stderr/exit code) |
tools/run_shell.go |
M1-1 | echo hello 返回正确输出与退出码 |
| ✅ M1-6 | http_request 工具(GET/POST,超时控制) |
tools/http_request.go |
M1-1 | 请求公开 API 返回正常 |
| ✅ M1-7 | 把以上工具全部注册进 Agent | 改 agent/agent.go |
M1-2~M1-6 | Agent 工具列表包含全部工具 |
| ✅ M1-8 | 集成验证:隔离临时目录完成「创建→写→shell 验证」连续任务 | — | M1-7 | 多步任务一次跑通 ✅ M1 验收 |
| 编号 | 任务 | 产出物 | 依赖 | 验证方式 |
|---|---|---|---|---|
| ✅ M2-1 | 定义权限三态枚举(自动允许/单次确认/拒绝)与工具风险等级 | tools/permission.go |
M1-8 | 编译通过 + 单测覆盖三态 |
| ✅ M2-2 | 实现「权限网关」拦截层,包装工具执行 | tools/gateway.go |
M2-1 | 只读工具放行,写/执行类拦截 |
| ✅ M2-3 | 命令行 y/n 确认交互 | 改 main.go |
M2-2 | run_shell 弹出确认提示 |
| ✅ M2-4 | 拒绝路径:把「用户拒绝」结果回传 Agent | 改 gateway.go |
M2-3 | 拒绝后 Agent 不执行且能继续对话 ✅ M2 验收 |
| 编号 | 任务 | 产出物 | 依赖 | 验证方式 |
|---|---|---|---|---|
| ✅ M3-1 | 引入 bubbletea/lipgloss 依赖 | go.mod |
M2-4 | go build 通过 |
| ✅ M3-2 | 基础 Model:输入框 + 消息流视图 + 退出键 | internal/tui/model.go |
M3-1 | 能输入、显示、退出 |
| ✅ M3-3 | 定义 Agent→TUI 事件类型(文本片段/工具调用/工具结果) | tui/events.go |
M3-2 | 类型定义 + 编译通过 |
| ✅ M3-4 | Agent 在 goroutine 跑,事件写入 channel | tui/runner.go |
M3-3 | channel 能收到事件 |
| ✅ M3-5 | tea.Cmd 从 channel 读事件转 tea.Msg 驱动渲染 |
改 model.go |
M3-4 | 消息流随事件更新 |
| ✅ M3-6 | 流式打字机渲染效果 | 改 model.go |
M3-5 | 文本逐片段呈现 |
| ✅ M3-7 | 工具确认弹窗组件,替换 M2 命令行 y/n | tui/confirm.go |
M3-6,M2-4 | 弹窗可选择允许/拒绝 |
| ✅ M3-8 | 工具确认双 channel(请求授权+接收结果),排查死锁 | 改 gateway.go+runner.go |
M3-7 | 允许/拒绝/超时三路径均不卡死 ✅ M3 验收 |
| 编号 | 任务 | 产出物 | 依赖 | 验证方式 |
|---|---|---|---|---|
| ✅ M4-1 | 设计配置文件结构(provider/key/base_url/工具开关) | internal/config/config.go |
M3-8 | 加载示例配置无误 |
| ✅ M4-2 | provider 工厂抽象:openai / ark / claude / ollama | llm/factory.go |
M4-1 | 各 provider 可按配置实例化 |
| ✅ M4-3 | 按模型配置 StreamToolCallChecker(Claude 先吐文本) |
改 llm/factory.go |
M4-2 | Claude 与 OpenAI 流式 tool call 均正确 |
| ✅ M4-4 | 运行时切换模型命令/快捷键 | 改 tui/model.go |
M4-2 | 会话中切换 provider 生效 |
| ✅ M4-5 | MessageRewriter 做长对话上下文压缩 |
agent/rewriter.go |
M4-2 | 超长对话不超限且连贯 |
| ✅ M4-6 | 集成验证:同会话切换两个 provider | — | M4-3,M4-4 | 两 provider 均正常工具调用与流式 ✅ M4 验收 |
| 编号 | 任务 | 产出物 | 依赖 | 验证方式 |
|---|---|---|---|---|
| ✅ M5-1 | 引入 eino-ext MCP 工具适配依赖 | go.mod |
M4-6 | go build 通过 |
| ✅ M5-2 | MCP server 连接配置(stdio / SSE) | 改 config.go |
M5-1 | 配置可解析 |
| ✅ M5-3 | 连接 MCP server 并发现其工具 | tools/mcp.go |
M5-2 | 列出远端工具清单 |
| ✅ M5-4 | 把 MCP 工具桥接为 eino tool 并注册进 Agent | 改 tools/mcp.go+agent.go |
M5-3 | Agent 工具列表含 MCP 工具 |
| ✅ M5-5 | MCP 工具纳入 M2 权限网关 | 改 gateway.go |
M5-4,M2-2 | MCP 工具执行前触发确认 |
| ✅ M5-6 | 集成验证:外部 MCP server 工具被正常调用 | — | M5-5 | 端到端调用成功 ✅ M5 验收 |
- M0 最小闭环(M0-1 ~ M0-7)
- M1 真实工具集(M1-1 ~ M1-8)
- M2 权限网关(M2-1 ~ M2-4)
- M3 TUI 接入(M3-1 ~ M3-8)
- M4 多模型 + 配置(M4-1 ~ M4-6)
- M5 MCP 扩展(M5-1 ~ M5-6)