feat(dev-workflow): 添加 Cross-Debate 和 Cross-Review 模式
- 更新 SKILL.md:完整的 Cross 模式流程文档 - 更新 dev_workflow.py:新增 record-debate、record-review 命令 - 新增 debate-template.md:Cross-Debate 模板 - 用户介入点:Phase 1 方案选择 + Phase 6 最终审核 - 六条铁律:Briefing 原则、安全约束等 - 禁止 auto-merge:防止流程错误
This commit is contained in:
+249
-49
@@ -1,9 +1,9 @@
|
||||
---
|
||||
name: dev-workflow
|
||||
description: "Spec-Driven 开发流程技能。当用户说'添加功能'、'开发XXX'时使用。"
|
||||
description: "Spec-Driven 开发流程技能,支持 Cross-Debate 和 Cross-Review。当用户说'添加功能'、'开发XXX'时使用。"
|
||||
---
|
||||
|
||||
# dev-workflow - Spec-Driven 开发流程
|
||||
# dev-workflow - Agent Engineering 开发流程
|
||||
|
||||
## 什么时候使用
|
||||
|
||||
@@ -11,7 +11,7 @@ description: "Spec-Driven 开发流程技能。当用户说'添加功能'、'开
|
||||
|
||||
| 触发词 | 行为 |
|
||||
|--------|------|
|
||||
| `添加功能` + 描述 | 开始 Spec-Driven 开发流程 |
|
||||
| `添加功能` + 描述 | 开始 Agent Engineering 开发流程 |
|
||||
| `开发` + 描述 | 同上 |
|
||||
| `实现` + 描述 | 同上 |
|
||||
|
||||
@@ -23,15 +23,17 @@ description: "Spec-Driven 开发流程技能。当用户说'添加功能'、'开
|
||||
| `GITEA_URL` | Gitea 服务地址 | 否(默认 http://192.168.1.22:8418) |
|
||||
| `GITEA_REPO` | 仓库路径 | 否(默认 starmen1265/kb-skills) |
|
||||
|
||||
## 工作流程
|
||||
## 工作流程(Cross 模式)
|
||||
|
||||
```
|
||||
用户描述需求
|
||||
↓
|
||||
┌─────────────────────────────────────┐
|
||||
│ Phase 1: Spec 生成 │
|
||||
│ - 澄清需求 │
|
||||
│ - 生成 .planning/spec.md │
|
||||
│ Phase 1: Cross-Debate(方案辩论) │
|
||||
│ - 3个 Agent 分别出方案 │
|
||||
│ - 汇总辩论结果 │
|
||||
│ - 用户选择/调整方案 │
|
||||
│ - 生成统一 spec.md │
|
||||
└─────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────┐
|
||||
@@ -44,49 +46,119 @@ description: "Spec-Driven 开发流程技能。当用户说'添加功能'、'开
|
||||
│ Phase 3: 子代理开发 │
|
||||
│ - 基于 spec 启动开发子代理 │
|
||||
│ - 子代理执行开发任务 │
|
||||
│ - 本地测试通过 │
|
||||
│ - 提交代码到功能分支 │
|
||||
└─────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────┐
|
||||
│ Phase 4: 创建 PR │
|
||||
│ Phase 4: Cross-Review(交叉审核) │
|
||||
│ - 3个 Agent 交叉审核代码 │
|
||||
│ - 汇总问题列表 │
|
||||
│ - 自动修复(或请求用户确认) │
|
||||
│ - 多轮迭代直到通过 │
|
||||
└─────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────┐
|
||||
│ Phase 5: 安全审计 │
|
||||
│ - 搜索安全最佳实践 │
|
||||
│ - 审计权限/注入/密钥等问题 │
|
||||
│ - 修复安全漏洞 │
|
||||
└─────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────┐
|
||||
│ Phase 6: 创建 PR │
|
||||
│ - 调用 Gitea API 创建 PR │
|
||||
│ - ⚠️ 禁止 auto-merge │
|
||||
│ - 返回 PR 编号 │
|
||||
└─────────────────────────────────────┘
|
||||
↓
|
||||
通知 pr-review-gate 开始审查
|
||||
通知 pr-review-gate 最终审查
|
||||
```
|
||||
|
||||
## 执行步骤
|
||||
## 用户介入点
|
||||
|
||||
### Step 1: 需求澄清
|
||||
| 阶段 | 介入方式 | 说明 |
|
||||
|------|---------|------|
|
||||
| **Phase 1** | 方案选择 | Cross-Debate 后选择或调整方案 |
|
||||
| **Phase 4** | 可选确认 | 有无法决定的问题时介入 |
|
||||
| **Phase 6** | 最终审核 | 查看 PR,决定是否合并 |
|
||||
|
||||
使用 GSD 风格的深度提问:
|
||||
---
|
||||
|
||||
1. 理解用户要做什么
|
||||
2. 探索边界条件
|
||||
3. 确认技术约束
|
||||
4. 识别依赖关系
|
||||
## 执行步骤详解
|
||||
|
||||
**示例问题:**
|
||||
- "这个功能解决什么问题?"
|
||||
- "期望的输入/输出是什么?"
|
||||
- "有什么技术约束?"
|
||||
- "需要与现有哪些模块交互?"
|
||||
### Phase 1: Cross-Debate(方案辩论)
|
||||
|
||||
### Step 2: 生成 Spec
|
||||
#### Step 1.1: 启动多 Agent 辩论
|
||||
|
||||
创建 `.planning/spec.md` 文件:
|
||||
使用 `sessions_spawn` 并行启动 3 个 Agent:
|
||||
|
||||
```bash
|
||||
python3 dev_workflow.py --create-spec --title "功能名称" --description "详细描述"
|
||||
```
|
||||
# Agent 1: Claude Code(偏保守,重视安全)
|
||||
sessions_spawn(
|
||||
task="为以下需求设计方案。你是保守派,重视安全性和稳定性。
|
||||
需求:{{用户需求}}
|
||||
输出:1) 技术方案 2) 潜在风险 3) 实现步骤",
|
||||
agentId="claude-code",
|
||||
runtime="acp"
|
||||
)
|
||||
|
||||
# Agent 2: Codex(偏全面,考虑边界情况)
|
||||
sessions_spawn(
|
||||
task="为以下需求设计方案。你是全面派,考虑所有边界情况。
|
||||
需求:{{用户需求}}
|
||||
输出:1) 技术方案 2) 边界情况 3) 实现步骤",
|
||||
agentId="codex",
|
||||
runtime="acp"
|
||||
)
|
||||
|
||||
# Agent 3: Gemini CLI(偏快速,先出方案再补细节)
|
||||
sessions_spawn(
|
||||
task="为以下需求设计方案。你是快速派,优先快速实现。
|
||||
需求:{{用户需求}}
|
||||
输出:1) 技术方案 2) MVP范围 3) 实现步骤",
|
||||
agentId="gemini",
|
||||
runtime="acp"
|
||||
)
|
||||
```
|
||||
|
||||
Spec 文件结构参考 `templates/spec-template.md`。
|
||||
#### Step 1.2: 汇总辩论结果
|
||||
|
||||
### Step 3: 创建功能分支
|
||||
收集三个方案后:
|
||||
1. 提取共同点(通常是正确的方向)
|
||||
2. 列出分歧点(需要用户决策)
|
||||
3. 生成辩论汇总报告
|
||||
|
||||
#### Step 1.3: 用户选择方案
|
||||
|
||||
向用户展示:
|
||||
```
|
||||
## 🗳️ Cross-Debate 结果
|
||||
|
||||
### 共识点
|
||||
- ✅ 使用 XX 技术栈
|
||||
- ✅ 需要 YY 数据结构
|
||||
|
||||
### 分歧点
|
||||
| Agent | 方案 | 理由 |
|
||||
|-------|------|------|
|
||||
| Claude Code | 方案A | 安全性更高 |
|
||||
| Codex | 方案B | 考虑边界情况 |
|
||||
| Gemini | 方案C | 实现更快 |
|
||||
|
||||
请选择方案(A/B/C)或提出调整:
|
||||
```
|
||||
|
||||
#### Step 1.4: 生成 Spec
|
||||
|
||||
用户确认后,创建 `.planning/spec.md` 文件。
|
||||
|
||||
---
|
||||
|
||||
### Phase 2: 分支创建
|
||||
|
||||
```bash
|
||||
python3 dev_workflow.py --create-branch --spec .planning/spec.md
|
||||
python3 dev_workflow.py create-branch --spec .planning/spec.md
|
||||
```
|
||||
|
||||
分支命名规则:
|
||||
@@ -94,36 +166,135 @@ python3 dev_workflow.py --create-branch --spec .planning/spec.md
|
||||
- `fix/<简短描述>` - Bug 修复
|
||||
- `refactor/<简短描述>` - 重构
|
||||
|
||||
### Step 4: 启动开发子代理
|
||||
---
|
||||
|
||||
### Phase 3: 子代理开发
|
||||
|
||||
使用 `sessions_spawn` 启动开发子代理:
|
||||
|
||||
```
|
||||
sessions_spawn(
|
||||
task="根据 spec 开发 <功能名称>",
|
||||
task="""根据 spec 开发 {{功能名称}}
|
||||
|
||||
## Spec 文件
|
||||
读取 .planning/spec.md
|
||||
|
||||
## 要求
|
||||
1. 只写目标,不指定具体文件(自己探索)
|
||||
2. 本地测试通过后再提交
|
||||
3. 提交信息遵循 Conventional Commits
|
||||
|
||||
## 安全约束
|
||||
- 不能 fail-open
|
||||
- 并发请求不能超额
|
||||
""",
|
||||
cwd="~/work/kb-skills",
|
||||
runtime="subagent"
|
||||
runtime="acp"
|
||||
)
|
||||
```
|
||||
|
||||
子代理会:
|
||||
1. 读取 spec 文件
|
||||
2. 执行开发任务
|
||||
3. 提交代码到功能分支
|
||||
**Briefing 原则:**
|
||||
- ✅ 写目标:Pro 用户改成月度字符预算
|
||||
- ✅ 写约束:砍掉所有按次计费逻辑
|
||||
- ❌ 不写文件:改 src/api/user.ts
|
||||
|
||||
### Step 5: 创建 PR
|
||||
---
|
||||
|
||||
### Phase 4: Cross-Review(交叉审核)
|
||||
|
||||
#### Step 4.1: 启动多 Agent 审核
|
||||
|
||||
```
|
||||
# Agent 1: 纯代码审查
|
||||
sessions_spawn(
|
||||
task="审查当前分支的代码变更。纯看代码,不给参考文档。
|
||||
检查:1) 逻辑错误 2) 边界情况 3) 代码风格",
|
||||
agentId="claude-code",
|
||||
runtime="acp"
|
||||
)
|
||||
|
||||
# Agent 2: 带文档审查
|
||||
sessions_spawn(
|
||||
task="审查当前分支的代码变更。先搜索相关官方文档,再审代码。
|
||||
检查:1) API使用正确性 2) 最佳实践 3) 文档一致性",
|
||||
agentId="codex",
|
||||
runtime="acp"
|
||||
)
|
||||
|
||||
# Agent 3: 测试覆盖审查
|
||||
sessions_spawn(
|
||||
task="审查当前分支的测试覆盖。检查:
|
||||
1) 单元测试覆盖 2) 边界情况测试 3) 集成测试",
|
||||
agentId="gemini",
|
||||
runtime="acp"
|
||||
)
|
||||
```
|
||||
|
||||
#### Step 4.2: 汇总问题并修复
|
||||
|
||||
```json
|
||||
{
|
||||
"critical": [
|
||||
"外键顺序 bug:扣费逻辑先写子表再写父表"
|
||||
],
|
||||
"high": [
|
||||
"RPC 权限暴露:任何登录用户都能直接调"
|
||||
],
|
||||
"medium": [
|
||||
"Booster 购买没验证 payment_status"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
自动修复或请求用户确认。
|
||||
|
||||
#### Step 4.3: 多轮迭代
|
||||
|
||||
如果发现问题:
|
||||
1. 修复后重新触发 Cross-Review
|
||||
2. 重复直到无 Critical/High 问题
|
||||
|
||||
---
|
||||
|
||||
### Phase 5: 安全审计
|
||||
|
||||
```
|
||||
sessions_spawn(
|
||||
task="""安全审计当前分支代码。
|
||||
|
||||
## 审计清单
|
||||
1. 搜索 OWASP Top 10 相关最佳实践
|
||||
2. 搜索平台(如 Stripe/Supabase)安全文档
|
||||
3. 检查以下问题:
|
||||
- SQL 注入
|
||||
- 权限暴露(如 PostgreSQL 函数权限)
|
||||
- 密钥泄露(检查日志、错误信息)
|
||||
- fail-open 问题
|
||||
- 并发竞态条件
|
||||
|
||||
## 输出
|
||||
- Critical 漏洞(必须修复)
|
||||
- High 风险(建议修复)
|
||||
- 安全建议
|
||||
""",
|
||||
agentId="claude-code",
|
||||
runtime="acp"
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 6: 创建 PR
|
||||
|
||||
开发完成后:
|
||||
|
||||
```bash
|
||||
python3 dev_workflow.py --create-pr --branch feature/xxx --title "PR 标题"
|
||||
python3 dev_workflow.py create-pr --branch feature/xxx --title "PR 标题"
|
||||
```
|
||||
|
||||
调用 Gitea API 创建 PR,返回 PR 编号。
|
||||
**⚠️ 禁止 auto-merge**:必须等待用户最终审核。
|
||||
|
||||
### Step 6: 通知审查
|
||||
|
||||
PR 创建后,告知用户:
|
||||
PR 创建后告知用户:
|
||||
|
||||
```
|
||||
✅ PR #xxx 已创建
|
||||
@@ -131,36 +302,65 @@ PR 创建后,告知用户:
|
||||
**分支:** feature/xxx
|
||||
**链接:** http://192.168.1.22:8418/starmen1265/kb-skills/pulls/xxx
|
||||
|
||||
正在启动 pr-review-gate 审查流程...
|
||||
**已完成:**
|
||||
- ✅ Cross-Debate(3个Agent辩论)
|
||||
- ✅ Cross-Review(3个Agent审核,X轮)
|
||||
- ✅ 安全审计
|
||||
|
||||
**下一步:** 请审核 PR,确认无误后合并。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CLI 命令
|
||||
|
||||
```bash
|
||||
# 创建 spec
|
||||
python3 dev_workflow.py --create-spec --title "标题" --description "描述"
|
||||
# 创建 spec(从 Cross-Debate 结果)
|
||||
python3 dev_workflow.py create-spec --title "标题" --description "描述"
|
||||
|
||||
# 从 spec 创建分支
|
||||
python3 dev_workflow.py --create-branch --spec .planning/spec.md
|
||||
python3 dev_workflow.py create-branch --spec .planning/spec.md
|
||||
|
||||
# 创建 PR
|
||||
python3 dev_workflow.py --create-pr --branch feature/xxx --title "PR标题"
|
||||
# 创建 PR(禁止 auto-merge)
|
||||
python3 dev_workflow.py create-pr --branch feature/xxx --title "PR标题"
|
||||
|
||||
# 查看当前状态
|
||||
python3 dev_workflow.py --status
|
||||
python3 dev_workflow.py status
|
||||
|
||||
# 记录 Cross-Debate 结果
|
||||
python3 dev_workflow.py record-debate --file .planning/debate.md
|
||||
|
||||
# 记录 Cross-Review 结果
|
||||
python3 dev_workflow.py record-review --round 1 --issues '[{"level":"critical","desc":"..."}]'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 与其他技能的协作
|
||||
|
||||
| 技能 | 协作方式 |
|
||||
|------|----------|
|
||||
| **pr-review-gate** | PR 创建后自动触发审查 |
|
||||
| **pr-review-gate** | PR 创建后触发最终审查 |
|
||||
| **kb-workflow** | 可复用其目录结构 |
|
||||
| **GSD** | 采用其 Spec-Driven 方法论 |
|
||||
|
||||
---
|
||||
|
||||
## 六条铁律
|
||||
|
||||
1. **Briefing 写目标,不写文件** - 你是 PM,Agent 是工程师
|
||||
2. **Agent 共识需要人类验证** - 三个 AI 同意不代表正确
|
||||
3. **本地完成所有工作再推远端** - 实现、测试、审核、修复全在本地
|
||||
4. **安全约束要写进 Briefing** - "不能 fail-open"、"并发不能超额"
|
||||
5. **密钥永远不过聊天** - 用环境变量文件,命令里用变量名
|
||||
6. **Briefing 必须包含产品上下文** - 用户画像、产品定位、商业模式
|
||||
|
||||
---
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 确保 `GITEA_TOKEN` 已配置
|
||||
2. 功能分支命名遵循规范
|
||||
3. 提交信息遵循 Conventional Commits
|
||||
4. 开发前先 pull 最新代码
|
||||
5. **禁止 auto-merge** - 流程错误比代码 bug 更贵
|
||||
|
||||
+213
-16
@@ -1,13 +1,15 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
dev_workflow.py - Spec-Driven 开发流程辅助工具
|
||||
dev_workflow.py - Agent Engineering 开发流程辅助工具
|
||||
|
||||
用法:
|
||||
python3 dev_workflow.py --create-spec --title "标题" --description "描述"
|
||||
python3 dev_workflow.py --create-branch --spec .planning/spec.md
|
||||
python3 dev_workflow.py --create-pr --branch feature/xxx --title "PR标题"
|
||||
python3 dev_workflow.py --status
|
||||
python3 dev_workflow.py create-spec --title "标题" --description "描述"
|
||||
python3 dev_workflow.py create-branch --spec .planning/spec.md
|
||||
python3 dev_workflow.py create-pr --branch feature/xxx --title "PR标题"
|
||||
python3 dev_workflow.py record-debate --file .planning/debate.md
|
||||
python3 dev_workflow.py record-review --round 1 --issues '[...]'
|
||||
python3 dev_workflow.py status
|
||||
"""
|
||||
|
||||
import os
|
||||
@@ -27,6 +29,11 @@ GITEA_REPO = os.environ.get('GITEA_REPO', 'starmen1265/kb-skills')
|
||||
REPO_PATH = Path.home() / 'work' / 'kb-skills'
|
||||
PLANNING_DIR = REPO_PATH / '.planning'
|
||||
|
||||
# Cross 模式配置
|
||||
CROSS_AGENTS = ['claude-code', 'codex', 'gemini']
|
||||
DEBATE_FILE = PLANNING_DIR / 'debate.md'
|
||||
REVIEW_FILE = PLANNING_DIR / 'review.json'
|
||||
|
||||
|
||||
def run_cmd(cmd, cwd=None, capture=True):
|
||||
"""执行 shell 命令"""
|
||||
@@ -40,7 +47,7 @@ def run_cmd(cmd, cwd=None, capture=True):
|
||||
return result
|
||||
|
||||
|
||||
def create_spec(title: str, description: str) -> dict:
|
||||
def create_spec(title: str, description: str, from_debate: bool = False) -> dict:
|
||||
"""创建 spec 文件"""
|
||||
PLANNING_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
@@ -57,6 +64,7 @@ def create_spec(title: str, description: str) -> dict:
|
||||
**创建时间:** {{DATE}}
|
||||
**状态:** draft
|
||||
**分支:** feature/{{BRANCH_NAME}}
|
||||
**来源:** {{SOURCE}}
|
||||
|
||||
---
|
||||
|
||||
@@ -76,6 +84,12 @@ def create_spec(title: str, description: str) -> dict:
|
||||
|
||||
---
|
||||
|
||||
## Cross-Debate 汇总
|
||||
|
||||
{{DEBATE_SUMMARY}}
|
||||
|
||||
---
|
||||
|
||||
## 变更日志
|
||||
|
||||
| 日期 | 变更 |
|
||||
@@ -89,6 +103,19 @@ def create_spec(title: str, description: str) -> dict:
|
||||
content = content.replace('{{DATE}}', now)
|
||||
content = content.replace('{{BRANCH_NAME}}', branch_name)
|
||||
content = content.replace('{{DESCRIPTION}}', description)
|
||||
content = content.replace('{{SOURCE}}', 'Cross-Debate' if from_debate else '用户需求')
|
||||
|
||||
# 如果有 debate 文件,提取汇总
|
||||
if from_debate and DEBATE_FILE.exists():
|
||||
debate_content = DEBATE_FILE.read_text(encoding='utf-8')
|
||||
# 提取共识点部分
|
||||
match = re.search(r'## 共识点\n(.*?)(?=\n## |$)', debate_content, re.DOTALL)
|
||||
if match:
|
||||
content = content.replace('{{DEBATE_SUMMARY}}', match.group(1).strip())
|
||||
else:
|
||||
content = content.replace('{{DEBATE_SUMMARY}}', '见 .planning/debate.md')
|
||||
else:
|
||||
content = content.replace('{{DEBATE_SUMMARY}}', '无')
|
||||
|
||||
# 写入文件
|
||||
spec_file = PLANNING_DIR / 'spec.md'
|
||||
@@ -98,7 +125,8 @@ def create_spec(title: str, description: str) -> dict:
|
||||
"success": True,
|
||||
"spec_file": str(spec_file),
|
||||
"branch_name": branch_name,
|
||||
"title": title
|
||||
"title": title,
|
||||
"from_debate": from_debate
|
||||
}
|
||||
|
||||
|
||||
@@ -138,7 +166,7 @@ def create_branch(spec_file: str) -> dict:
|
||||
|
||||
|
||||
def create_pr(branch: str, title: str, body: str = "") -> dict:
|
||||
"""调用 Gitea API 创建 PR"""
|
||||
"""调用 Gitea API 创建 PR(禁止 auto-merge)"""
|
||||
if not GITEA_TOKEN:
|
||||
return {"success": False, "error": "GITEA_TOKEN 未配置"}
|
||||
|
||||
@@ -147,6 +175,20 @@ def create_pr(branch: str, title: str, body: str = "") -> dict:
|
||||
result = run_cmd('git log -1 --pretty=%B')
|
||||
body = result.stdout.strip() if result.returncode == 0 else ""
|
||||
|
||||
# 添加 Cross 模式说明
|
||||
review_info = ""
|
||||
if REVIEW_FILE.exists():
|
||||
try:
|
||||
review_data = json.loads(REVIEW_FILE.read_text())
|
||||
total_issues = sum(len(v) for v in review_data.get('rounds', {}).values())
|
||||
rounds = len(review_data.get('rounds', {}))
|
||||
review_info = f"\n\n**Cross-Review:** {rounds} 轮审核,修复 {total_issues} 个问题"
|
||||
except:
|
||||
pass
|
||||
|
||||
body += review_info
|
||||
body += "\n\n⚠️ **禁止 auto-merge** - 等待人工最终审核"
|
||||
|
||||
# 调用 Gitea API
|
||||
import urllib.request
|
||||
import urllib.parse
|
||||
@@ -177,7 +219,8 @@ def create_pr(branch: str, title: str, body: str = "") -> dict:
|
||||
"success": True,
|
||||
"pr_number": result.get("number"),
|
||||
"pr_url": result.get("html_url"),
|
||||
"branch": branch
|
||||
"branch": branch,
|
||||
"warning": "禁止设置 auto-merge"
|
||||
}
|
||||
except urllib.error.HTTPError as e:
|
||||
error_body = e.read().decode('utf-8') if e.fp else str(e)
|
||||
@@ -186,13 +229,144 @@ def create_pr(branch: str, title: str, body: str = "") -> dict:
|
||||
return {"success": False, "error": f"请求失败: {str(e)}"}
|
||||
|
||||
|
||||
def record_debate(file: str = None) -> dict:
|
||||
"""记录 Cross-Debate 结果"""
|
||||
PLANNING_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
debate_content = None
|
||||
if file:
|
||||
file_path = Path(file)
|
||||
if file_path.exists():
|
||||
debate_content = file_path.read_text(encoding='utf-8')
|
||||
|
||||
if debate_content:
|
||||
DEBATE_FILE.write_text(debate_content, encoding='utf-8')
|
||||
return {
|
||||
"success": True,
|
||||
"file": str(DEBATE_FILE),
|
||||
"message": "Cross-Debate 结果已记录"
|
||||
}
|
||||
else:
|
||||
# 创建模板
|
||||
template = f"""# Cross-Debate 结果
|
||||
|
||||
**创建时间:** {datetime.now().strftime('%Y-%m-%d %H:%M')}
|
||||
**需求:** <!-- 填写需求 -->
|
||||
|
||||
---
|
||||
|
||||
## Agent 方案
|
||||
|
||||
### Claude Code(保守派)
|
||||
|
||||
**方案:**
|
||||
<!-- 填写 -->
|
||||
|
||||
**理由:**
|
||||
<!-- 填写 -->
|
||||
|
||||
---
|
||||
|
||||
### Codex(全面派)
|
||||
|
||||
**方案:**
|
||||
<!-- 填写 -->
|
||||
|
||||
**理由:**
|
||||
<!-- 填写 -->
|
||||
|
||||
---
|
||||
|
||||
### Gemini(快速派)
|
||||
|
||||
**方案:**
|
||||
<!-- 填写 -->
|
||||
|
||||
**理由:**
|
||||
<!-- 填写 -->
|
||||
|
||||
---
|
||||
|
||||
## 共识点
|
||||
|
||||
- ✅ <!-- 共识1 -->
|
||||
- ✅ <!-- 共识2 -->
|
||||
|
||||
## 分歧点
|
||||
|
||||
| Agent | 方案 | 理由 |
|
||||
|-------|------|------|
|
||||
| <!-- Agent --> | <!-- 方案 --> | <!-- 理由 --> |
|
||||
|
||||
## 用户决策
|
||||
|
||||
**选择方案:** <!-- A/B/C 或调整 -->
|
||||
|
||||
---
|
||||
"""
|
||||
DEBATE_FILE.write_text(template, encoding='utf-8')
|
||||
return {
|
||||
"success": True,
|
||||
"file": str(DEBATE_FILE),
|
||||
"message": "Cross-Debate 模板已创建,请填写"
|
||||
}
|
||||
|
||||
|
||||
def record_review(round_num: int, issues: str = None) -> dict:
|
||||
"""记录 Cross-Review 结果"""
|
||||
PLANNING_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# 读取现有数据
|
||||
review_data = {"rounds": {}}
|
||||
if REVIEW_FILE.exists():
|
||||
try:
|
||||
review_data = json.loads(REVIEW_FILE.read_text())
|
||||
except:
|
||||
pass
|
||||
|
||||
# 解析 issues
|
||||
issues_list = []
|
||||
if issues:
|
||||
try:
|
||||
issues_list = json.loads(issues)
|
||||
except:
|
||||
# 简单格式:每行一个问题
|
||||
issues_list = [{"level": "medium", "desc": line} for line in issues.split('\n') if line.strip()]
|
||||
|
||||
# 添加本轮结果
|
||||
round_key = f"round_{round_num}"
|
||||
review_data["rounds"][round_key] = {
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"issues": issues_list
|
||||
}
|
||||
|
||||
# 统计
|
||||
review_data["stats"] = {
|
||||
"total_rounds": len(review_data["rounds"]),
|
||||
"total_issues": sum(len(v.get("issues", [])) for v in review_data["rounds"].values())
|
||||
}
|
||||
|
||||
REVIEW_FILE.write_text(json.dumps(review_data, ensure_ascii=False, indent=2), encoding='utf-8')
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"file": str(REVIEW_FILE),
|
||||
"round": round_num,
|
||||
"issues_count": len(issues_list),
|
||||
"stats": review_data["stats"]
|
||||
}
|
||||
|
||||
|
||||
def get_status() -> dict:
|
||||
"""获取当前开发状态"""
|
||||
result = {
|
||||
"current_branch": None,
|
||||
"spec_exists": False,
|
||||
"debate_exists": False,
|
||||
"review_exists": False,
|
||||
"planning_exists": False,
|
||||
"uncommitted_changes": False
|
||||
"uncommitted_changes": False,
|
||||
"cross_mode": False
|
||||
}
|
||||
|
||||
# 当前分支
|
||||
@@ -200,49 +374,72 @@ def get_status() -> dict:
|
||||
if branch_result.returncode == 0:
|
||||
result["current_branch"] = branch_result.stdout.strip()
|
||||
|
||||
# spec 文件
|
||||
# 各种文件状态
|
||||
result["spec_exists"] = (PLANNING_DIR / 'spec.md').exists()
|
||||
|
||||
# planning 目录
|
||||
result["debate_exists"] = DEBATE_FILE.exists()
|
||||
result["review_exists"] = REVIEW_FILE.exists()
|
||||
result["planning_exists"] = PLANNING_DIR.exists()
|
||||
result["cross_mode"] = result["debate_exists"] or result["review_exists"]
|
||||
|
||||
# 未提交的更改
|
||||
status_result = run_cmd('git status --porcelain')
|
||||
result["uncommitted_changes"] = bool(status_result.stdout.strip())
|
||||
|
||||
# 如果有 review 数据,显示统计
|
||||
if REVIEW_FILE.exists():
|
||||
try:
|
||||
review_data = json.loads(REVIEW_FILE.read_text())
|
||||
result["review_stats"] = review_data.get("stats", {})
|
||||
except:
|
||||
pass
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='dev-workflow 辅助工具')
|
||||
parser = argparse.ArgumentParser(description='dev-workflow 辅助工具(Cross 模式)')
|
||||
subparsers = parser.add_subparsers(dest='command', help='命令')
|
||||
|
||||
# create-spec
|
||||
spec_parser = subparsers.add_parser('create-spec', help='创建 spec 文件')
|
||||
spec_parser.add_argument('--title', required=True, help='功能标题')
|
||||
spec_parser.add_argument('--description', default='', help='功能描述')
|
||||
spec_parser.add_argument('--from-debate', action='store_true', help='从 Cross-Debate 结果生成')
|
||||
|
||||
# create-branch
|
||||
branch_parser = subparsers.add_parser('create-branch', help='创建功能分支')
|
||||
branch_parser.add_argument('--spec', required=True, help='spec 文件路径')
|
||||
|
||||
# create-pr
|
||||
pr_parser = subparsers.add_parser('create-pr', help='创建 PR')
|
||||
pr_parser = subparsers.add_parser('create-pr', help='创建 PR(禁止 auto-merge)')
|
||||
pr_parser.add_argument('--branch', required=True, help='分支名')
|
||||
pr_parser.add_argument('--title', required=True, help='PR 标题')
|
||||
pr_parser.add_argument('--body', default='', help='PR 描述')
|
||||
|
||||
# record-debate
|
||||
debate_parser = subparsers.add_parser('record-debate', help='记录 Cross-Debate 结果')
|
||||
debate_parser.add_argument('--file', help='输入文件路径(可选)')
|
||||
|
||||
# record-review
|
||||
review_parser = subparsers.add_parser('record-review', help='记录 Cross-Review 结果')
|
||||
review_parser.add_argument('--round', type=int, required=True, help='审核轮次')
|
||||
review_parser.add_argument('--issues', help='问题列表(JSON 或简单文本)')
|
||||
|
||||
# status
|
||||
subparsers.add_parser('status', help='查看状态')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.command == 'create-spec':
|
||||
result = create_spec(args.title, args.description)
|
||||
result = create_spec(args.title, args.description, args.from_debate)
|
||||
elif args.command == 'create-branch':
|
||||
result = create_branch(args.spec)
|
||||
elif args.command == 'create-pr':
|
||||
result = create_pr(args.branch, args.title, args.body)
|
||||
elif args.command == 'record-debate':
|
||||
result = record_debate(args.file)
|
||||
elif args.command == 'record-review':
|
||||
result = record_review(args.round, args.issues)
|
||||
elif args.command == 'status':
|
||||
result = get_status()
|
||||
else:
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
# Cross-Debate 结果
|
||||
|
||||
**创建时间:** {{DATE}}
|
||||
**需求:** {{REQUIREMENT}}
|
||||
|
||||
---
|
||||
|
||||
## Agent 方案
|
||||
|
||||
### Claude Code(保守派)
|
||||
|
||||
> 偏保守,重视安全性和稳定性
|
||||
|
||||
**方案:**
|
||||
<!-- 填写技术方案 -->
|
||||
|
||||
**理由:**
|
||||
<!-- 填写选择理由 -->
|
||||
|
||||
**风险提示:**
|
||||
<!-- 填写潜在风险 -->
|
||||
|
||||
---
|
||||
|
||||
### Codex(全面派)
|
||||
|
||||
> 偏全面,考虑所有边界情况
|
||||
|
||||
**方案:**
|
||||
<!-- 填写技术方案 -->
|
||||
|
||||
**理由:**
|
||||
<!-- 填写选择理由 -->
|
||||
|
||||
**边界情况:**
|
||||
<!-- 填写考虑的边界情况 -->
|
||||
|
||||
---
|
||||
|
||||
### Gemini(快速派)
|
||||
|
||||
> 偏快速,优先快速实现
|
||||
|
||||
**方案:**
|
||||
<!-- 填写技术方案 -->
|
||||
|
||||
**理由:**
|
||||
<!-- 填写选择理由 -->
|
||||
|
||||
**MVP 范围:**
|
||||
<!-- 填写最小可行范围 -->
|
||||
|
||||
---
|
||||
|
||||
## 共识点
|
||||
|
||||
> 三个 Agent 都同意的点(通常是正确的方向)
|
||||
|
||||
- ✅ <!-- 共识1 -->
|
||||
- ✅ <!-- 共识2 -->
|
||||
- ✅ <!-- 共识3 -->
|
||||
|
||||
## 分歧点
|
||||
|
||||
> 需要用户决策的地方
|
||||
|
||||
| Agent | 方案 | 理由 |
|
||||
|-------|------|------|
|
||||
| Claude Code | <!-- 方案A --> | <!-- 理由 --> |
|
||||
| Codex | <!-- 方案B --> | <!-- 理由 --> |
|
||||
| Gemini | <!-- 方案C --> | <!-- 理由 --> |
|
||||
|
||||
---
|
||||
|
||||
## 用户决策
|
||||
|
||||
**选择方案:** <!-- A/B/C 或自定义调整 -->
|
||||
|
||||
**调整说明:** <!-- 如果调整,说明调整内容 -->
|
||||
|
||||
---
|
||||
|
||||
## 下一步
|
||||
|
||||
- [ ] 根据 user decision 生成 spec.md
|
||||
- [ ] 创建功能分支
|
||||
- [ ] 启动开发子代理
|
||||
Reference in New Issue
Block a user