Compare commits
18 Commits
a1972c7ff9
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| b9327f3dea | |||
| 03a3d9ae5e | |||
| cc3d9e380d | |||
| 47df41043b | |||
| 9c6eaa2ebd | |||
| abb50cbce5 | |||
| 2195bb4542 | |||
| 70c140f5a7 | |||
| 02afe37412 | |||
| 7d6b82efd2 | |||
| 449eec9df7 | |||
| ddccd8fbfa | |||
| a8ac23f699 | |||
| 5d85c080e4 | |||
| 0187809460 | |||
| 0829b34b92 | |||
| eda99309ed | |||
| 1c8a4ff95c |
@@ -0,0 +1,128 @@
|
||||
# Main Agent 配置
|
||||
|
||||
## 角色
|
||||
|
||||
你是 **Main Agent(任务编排者)**,负责与用户讨论需求、动态安排 Sub Agents、验收整合。
|
||||
|
||||
## 核心职责
|
||||
|
||||
### 1. 需求讨论
|
||||
- 使用 **deep-interview** skill 进行需求澄清
|
||||
- ASK → LISTEN → WRITE → DEEPEN → REPEAT
|
||||
- 将需求记录到 `requirements/` 目录
|
||||
|
||||
### 2. 工程决策
|
||||
- 使用 **Linus 三问** 进行审慎决策:
|
||||
1. 这是现实问题还是想象问题?
|
||||
2. 这个问题真的需要解决吗?
|
||||
3. 这个方案真的能解决问题吗?
|
||||
- 拒绝过度设计、伪需求、自嗨方案
|
||||
|
||||
### 3. 任务分析
|
||||
- 评估任务复杂度(简单/中等/复杂)
|
||||
- 确定需要的 Sub Agents(Execute/Review/Test)
|
||||
- 制定编排策略
|
||||
|
||||
### 4. 编排执行
|
||||
- 通过 **Agent 工具**动态安排 Sub Agents
|
||||
- 使用 **Gitea Issue** 作为协作中心
|
||||
- 通过 **Comment 标记**追踪进度
|
||||
- 根据 Sub Agent 完成标记编排下一阶段
|
||||
|
||||
### 5. 验收整合
|
||||
- 执行**三向一致性检查**(需求↔设计↔编码)
|
||||
- 发现偏差时进入偏差处理流程
|
||||
- 整合 Sub Agent 结果
|
||||
- 向用户汇报最终结果
|
||||
|
||||
## 严格限制
|
||||
|
||||
- ❌ **不亲自编写代码**
|
||||
- ❌ **不亲自执行具体实现**
|
||||
- ❌ **不进行具体的代码修改**
|
||||
- ✅ **只负责编排、协调、验收**
|
||||
|
||||
## 可用能力
|
||||
|
||||
### Superpowers 五技能体系
|
||||
- **writing-plans** - 编写实现计划
|
||||
- **executing-plans** - 执行计划
|
||||
- **requesting-code-review** - 请求代码审查
|
||||
- **systematic-debugging** - 系统化调试
|
||||
- **finishing-a-development-branch** - 完成收尾
|
||||
|
||||
### 内置工具
|
||||
- **Agent 工具** - 编排 Sub Agents
|
||||
- **Gitea MCP 工具** - Issue/PR/分支管理
|
||||
- **Comment 标记系统** - Sub Agent 完成标记
|
||||
|
||||
## 工作流程
|
||||
|
||||
### 标准工作流
|
||||
|
||||
```
|
||||
用户需求
|
||||
↓
|
||||
Linus 三问过滤
|
||||
↓
|
||||
需求讨论(如需要)
|
||||
↓
|
||||
任务分析
|
||||
↓
|
||||
创建 Gitea Issue
|
||||
↓
|
||||
编排 Sub Agents
|
||||
↓
|
||||
等待 Sub Agent 完成标记
|
||||
↓
|
||||
三向一致性检查
|
||||
↓
|
||||
验收整合
|
||||
↓
|
||||
向用户汇报
|
||||
```
|
||||
|
||||
### Sub Agent 完成标记
|
||||
|
||||
| Sub Agent | 完成标记格式 |
|
||||
|-----------|-------------|
|
||||
| Execute | `@main-agent ✅ EXECUTE_DONE` |
|
||||
| Review | `@main-agent ✅ REVIEW_DONE verdict=approved` |
|
||||
| Test | `@main-agent ✅ TEST_DONE result=passed` |
|
||||
| Main | `@main-agent ✅ VERIFICATION_PASSED` |
|
||||
|
||||
### 编排策略
|
||||
|
||||
| 复杂度 | 策略 |
|
||||
|--------|------|
|
||||
| **简单** | Execute → 验收 |
|
||||
| **中等** | Execute → Review → 验收 |
|
||||
| **复杂** | 需求讨论 → 规划 → Execute → Review → Test → 验收 |
|
||||
| **调试** | 定位 → Execute → Test → 验收 |
|
||||
|
||||
## 偏差处理
|
||||
|
||||
发现偏差时:
|
||||
1. 发布 `CONSISTENCY_ISSUE` 标记
|
||||
2. 通知相关 Sub Agent
|
||||
3. 重新进入 Superpowers 工作流
|
||||
4. 重新验收
|
||||
|
||||
## Gitea 协作
|
||||
|
||||
### Issue 结构
|
||||
- 标题格式:`[sanguo_moziplus_v3] 功能描述`
|
||||
- 包含工作清单
|
||||
- 包含状态表
|
||||
- 包含完成标记约定
|
||||
|
||||
### Comment 约定
|
||||
- 进度更新:`@main-agent 📝 进度更新`
|
||||
- 完成标记:`@main-agent ✅ 阶段_DONE`
|
||||
- 偏差报告:`@main-agent ❌ CONSISTENCY_ISSUE`
|
||||
|
||||
## 参考文档
|
||||
|
||||
- 设计文档:`docs/design/07-design-v0.5-dynamic-orchestration-integrated.md`
|
||||
- Gitea 配置:`.claude/gitea-config.json`
|
||||
- 工作流脚本:`.claude/workflows/`
|
||||
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"gitea": {
|
||||
"baseUrl": "http://192.168.2.154:3000",
|
||||
"owner": "sanguo",
|
||||
"repo": "sanguo_moziplus_v3",
|
||||
"defaultBranch": "main"
|
||||
},
|
||||
"rules": {
|
||||
"branchNaming": {
|
||||
"feature": "feature/{task-name}",
|
||||
"fix": "fix/{issue-number}-{description}",
|
||||
"hotfix": "hotfix/{description}"
|
||||
},
|
||||
"commitNaming": {
|
||||
"feature": "feat: {description}",
|
||||
"fix": "fix: {description}",
|
||||
"refactor": "refactor: {description}",
|
||||
"docs": "docs: {description}",
|
||||
"test": "test: {description}"
|
||||
},
|
||||
"prTemplate": {
|
||||
"title": "{task-type}: {description}",
|
||||
"description": "## 任务\n\n{task-description}\n\n## 技术方案\n\n{approach}\n\n## 实现内容\n\n{changes}\n\n## 测试\n\n{tests}"
|
||||
}
|
||||
},
|
||||
"review": {
|
||||
"checklist": [
|
||||
"代码质量",
|
||||
"安全性",
|
||||
"性能",
|
||||
"测试覆盖",
|
||||
"文档完整性"
|
||||
],
|
||||
"approval": "至少 2 个 Reviewer 通过"
|
||||
},
|
||||
"agents": {
|
||||
"main": {
|
||||
"role": "编排者",
|
||||
"responsibilities": [
|
||||
"分析任务",
|
||||
"安排 Sub Agents",
|
||||
"验收整合",
|
||||
"合并 PR"
|
||||
]
|
||||
},
|
||||
"execute": {
|
||||
"role": "执行者",
|
||||
"responsibilities": [
|
||||
"实现功能",
|
||||
"编写测试",
|
||||
"创建 PR"
|
||||
],
|
||||
"skills": ["backend-dev", "frontend-dev"]
|
||||
},
|
||||
"review": {
|
||||
"role": "审查者",
|
||||
"responsibilities": [
|
||||
"代码审查",
|
||||
"添加 Review 评论",
|
||||
"提供修改建议"
|
||||
],
|
||||
"skills": ["CODE-REVIEW", "security-reviewer"]
|
||||
},
|
||||
"test": {
|
||||
"role": "测试者",
|
||||
"responsibilities": [
|
||||
"编写测试",
|
||||
"执行测试",
|
||||
"验证修复"
|
||||
],
|
||||
"skills": ["test-engineer", "e2e-tester"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* Feature Development Workflow
|
||||
*
|
||||
* 使用 Main + Sub Agent 架构完成功能开发
|
||||
*
|
||||
* 用法: Agent({ scriptPath: ".claude/workflows/feature-development.js", args: "实现用户认证功能" })
|
||||
*/
|
||||
|
||||
export const meta = {
|
||||
name: 'feature-development',
|
||||
description: 'Main Agent 协调 Sub Agent 完成功能开发',
|
||||
phases: [
|
||||
{ title: '分析需求', detail: 'Main Agent 分析并拆分任务' },
|
||||
{ title: '执行开发', detail: 'Executor Sub Agent 编写代码和测试' },
|
||||
{ title: '代码审查', detail: 'Reviewer Sub Agent 审查代码质量' },
|
||||
{ title: '整合验收', detail: 'Main Agent 整合结果并验收' }
|
||||
]
|
||||
}
|
||||
|
||||
// 工作流主逻辑
|
||||
export default async function (feature) {
|
||||
phase('分析需求')
|
||||
|
||||
log(`📋 功能需求: ${feature}`)
|
||||
|
||||
// Main Agent 分析需求
|
||||
const analysis = await agent(`
|
||||
作为架构师,分析以下功能需求:
|
||||
|
||||
"${feature}"
|
||||
|
||||
请提供:
|
||||
1. 技术方案概述
|
||||
2. 需要的文件列表
|
||||
3. Executor 任务描述
|
||||
4. Reviewer 审查点
|
||||
|
||||
返回结构化 JSON:
|
||||
{
|
||||
"approach": "技术方案概述",
|
||||
"files": ["预计需要的文件"],
|
||||
"executorTask": "详细任务描述",
|
||||
"reviewPoints": ["审查要点"]
|
||||
}
|
||||
`, { schema: AnalysisSchema })
|
||||
|
||||
log(`✅ 分析完成: ${analysis.approach}`)
|
||||
|
||||
phase('执行开发')
|
||||
|
||||
// 指派 Executor Sub Agent
|
||||
const executorResult = await agent(`
|
||||
作为后端开发专家,执行以下任务:
|
||||
|
||||
${analysis.executorTask}
|
||||
|
||||
技术要求:
|
||||
- 使用项目现有代码风格
|
||||
- 编写完整的单元测试
|
||||
- 测试覆盖率 > 80%
|
||||
|
||||
完成后返回结构化 JSON:
|
||||
{
|
||||
"files": ["修改的文件列表"],
|
||||
"tests": "测试结果",
|
||||
"changes": "主要改动说明",
|
||||
"status": "完成|部分完成|失败"
|
||||
}
|
||||
`, {
|
||||
label: 'Executor',
|
||||
schema: ExecutorResultSchema
|
||||
})
|
||||
|
||||
log(`✅ Executor 完成: ${executorResult.status}`)
|
||||
log(`📁 修改文件: ${executorResult.files.join(', ')}`)
|
||||
|
||||
phase('代码审查')
|
||||
|
||||
// 指派 Reviewer Sub Agent
|
||||
const reviewResult = await agent(`
|
||||
作为代码审查专家,审查以下改动:
|
||||
|
||||
文件: ${executorResult.files.join(', ')}
|
||||
改动: ${executorResult.changes}
|
||||
|
||||
审查要点:
|
||||
${analysis.reviewPoints.map(p => `- ${p}`).join('\n')}
|
||||
|
||||
检查项目:
|
||||
1. 代码质量和可读性
|
||||
2. 测试覆盖是否充分
|
||||
3. 是否有潜在的 bug
|
||||
4. 安全性考虑
|
||||
5. 性能影响
|
||||
|
||||
返回结构化 JSON:
|
||||
{
|
||||
"findings": ["发现的问题"],
|
||||
"severity": "low|medium|high|critical",
|
||||
"approval": true|false,
|
||||
"suggestions": ["改进建议"]
|
||||
}
|
||||
`, {
|
||||
label: 'Reviewer',
|
||||
schema: ReviewResultSchema
|
||||
})
|
||||
|
||||
log(`📊 审查结果: ${reviewResult.approval ? '✅ 通过' : '❌ 需修改'}`)
|
||||
|
||||
if (reviewResult.findings.length > 0) {
|
||||
log(`⚠️ 发现 ${reviewResult.findings.length} 个问题:`)
|
||||
reviewResult.findings.forEach(f => log(` - ${f}`))
|
||||
}
|
||||
|
||||
phase('整合验收')
|
||||
|
||||
// Main Agent 整合结果
|
||||
const final = {
|
||||
feature,
|
||||
approach: analysis.approach,
|
||||
files: executorResult.files,
|
||||
tests: executorResult.tests,
|
||||
review: reviewResult,
|
||||
status: reviewResult.approval ? '完成' : '需修改'
|
||||
}
|
||||
|
||||
log(`🎯 最终状态: ${final.status}`)
|
||||
|
||||
return final
|
||||
}
|
||||
|
||||
// JSON Schema 定义
|
||||
const AnalysisSchema = {
|
||||
type: "object",
|
||||
properties: {
|
||||
approach: { type: "string", description: "技术方案概述" },
|
||||
files: { type: "array", items: { type: "string" }, description: "预计需要的文件" },
|
||||
executorTask: { type: "string", description: "详细任务描述" },
|
||||
reviewPoints: { type: "array", items: { type: "string" }, description: "审查要点" }
|
||||
},
|
||||
required: ["approach", "files", "executorTask", "reviewPoints"]
|
||||
}
|
||||
|
||||
const ExecutorResultSchema = {
|
||||
type: "object",
|
||||
properties: {
|
||||
files: { type: "array", items: { type: "string" }, description: "修改的文件列表" },
|
||||
tests: { type: "string", description: "测试结果" },
|
||||
changes: { type: "string", description: "主要改动说明" },
|
||||
status: { type: "string", enum: ["完成", "部分完成", "失败"], description: "执行状态" }
|
||||
},
|
||||
required: ["files", "tests", "changes", "status"]
|
||||
}
|
||||
|
||||
const ReviewResultSchema = {
|
||||
type: "object",
|
||||
properties: {
|
||||
findings: { type: "array", items: { type: "string" }, description: "发现的问题" },
|
||||
severity: { type: "string", enum: ["low", "medium", "high", "critical"], description: "严重程度" },
|
||||
approval: { type: "boolean", description: "是否通过审查" },
|
||||
suggestions: { type: "array", items: { type: "string" }, description: "改进建议" }
|
||||
},
|
||||
required: ["findings", "severity", "approval", "suggestions"]
|
||||
}
|
||||
|
||||
// 导出 phase 函数供脚本使用
|
||||
function phase(title) {
|
||||
// 在实际使用中,这会被 Workflow 工具的 phase() 替换
|
||||
console.log(`\n=== ${title} ===`)
|
||||
}
|
||||
|
||||
function log(message) {
|
||||
console.log(message)
|
||||
}
|
||||
@@ -0,0 +1,550 @@
|
||||
/**
|
||||
* Gitea 协作工作流
|
||||
*
|
||||
* Main Agent 通过 Gitea 协调 Sub Agents 完成任务
|
||||
*/
|
||||
|
||||
import { generateGiteaRules, getRepoUrl, getBranchName, getCommitTemplate } from '../helpers/gitea-rules-generator.js'
|
||||
import { createGiteaAdapter } from '../helpers/gitea-mcp-adapter.js'
|
||||
import { generateProgressUpdate, generateExecuteMarker, generateReviewMarker, generateTestMarker, generateVerificationMarker } from '../helpers/comment-markers.js'
|
||||
import { findLatestMarker, MarkerType } from '../helpers/comment-parser.js'
|
||||
|
||||
export const meta = {
|
||||
name: 'gitea-orchestration',
|
||||
description: '通过 Gitea 协调 Sub Agents 完成开发任务',
|
||||
phases: [
|
||||
{ title: '分析', detail: 'Main Agent 分析任务并创建 Issue' },
|
||||
{ title: '执行', detail: 'Execute Sub Agent 实现并创建 PR' },
|
||||
{ title: '审查', detail: 'Review Sub Agent 审查代码' },
|
||||
{ title: '修复', detail: '如需要,Execute Sub Agent 修复问题' },
|
||||
{ title: '验收', detail: 'Main Agent 验收并合并 PR' }
|
||||
]
|
||||
}
|
||||
|
||||
export default async function giteaOrchestration(task, options = {}) {
|
||||
// 生成 Gitea 规则(从配置文件读取)
|
||||
const giteaRules = generateGiteaRules()
|
||||
const repoUrl = getRepoUrl()
|
||||
|
||||
// 初始化 Gitea 适配器
|
||||
const gitea = createGiteaAdapter()
|
||||
|
||||
log(`📦 仓库: ${repoUrl}`)
|
||||
log(`🔌 已连接 Gitea: ${gitea.getRepoInfo().baseUrl}`)
|
||||
|
||||
// ===== Phase 1: 分析 =====
|
||||
phase('分析')
|
||||
|
||||
// 创建 Issue 记录任务
|
||||
const issue = await createIssue(task, giteaRules, gitea)
|
||||
log(`✅ Issue 创建: ${issue.url}`)
|
||||
|
||||
// 分析任务
|
||||
const analysis = await analyzeTask(task)
|
||||
log(`📊 任务复杂度: ${analysis.complexity}`)
|
||||
log(`👥 需要的 Sub Agents: ${analysis.requiredAgents.join(', ')}`)
|
||||
|
||||
// ===== Phase 2: 执行 =====
|
||||
phase('执行')
|
||||
|
||||
const executeResults = []
|
||||
|
||||
// 安排 Execute Sub Agents
|
||||
if (analysis.requiredAgents.includes('backend')) {
|
||||
const backend = await agent({
|
||||
subagent_type: 'claude',
|
||||
label: 'Backend Execute',
|
||||
prompt: `
|
||||
作为后端开发专家,实现以下任务:
|
||||
|
||||
**任务描述**: ${analysis.backendTask}
|
||||
|
||||
**Issue**: ${issue.url}
|
||||
|
||||
${giteaRules}
|
||||
|
||||
执行步骤:
|
||||
1. Clone 仓库
|
||||
2. 创建分支: ${getBranchName('feature', 'backend-' + task.slug)}
|
||||
3. 实现代码
|
||||
4. 编写测试
|
||||
5. Commit 并 Push
|
||||
6. 创建 PR
|
||||
|
||||
完成后返回 PR URL。
|
||||
`
|
||||
})
|
||||
executeResults.push({ type: 'backend', ...backend })
|
||||
log(`✅ Backend Execute 完成: ${backend.prUrl}`)
|
||||
}
|
||||
|
||||
if (analysis.requiredAgents.includes('frontend')) {
|
||||
const frontend = await agent({
|
||||
subagent_type: 'claude',
|
||||
label: 'Frontend Execute',
|
||||
prompt: `
|
||||
作为前端开发专家,实现以下任务:
|
||||
|
||||
**任务描述**: ${analysis.frontendTask}
|
||||
|
||||
**Issue**: ${issue.url}
|
||||
|
||||
${giteaRules}
|
||||
|
||||
执行步骤:
|
||||
1. Clone 仓库
|
||||
2. 创建分支: ${getBranchName('feature', 'frontend-' + task.slug)}
|
||||
3. 实现代码
|
||||
4. 编写测试
|
||||
5. Commit 并 Push
|
||||
6. 创建 PR
|
||||
|
||||
完成后返回 PR URL。
|
||||
`
|
||||
})
|
||||
executeResults.push({ type: 'frontend', ...frontend })
|
||||
log(`✅ Frontend Execute 完成: ${frontend.prUrl}`)
|
||||
}
|
||||
|
||||
// ===== Phase 3: 审查 =====
|
||||
phase('审查')
|
||||
|
||||
if (analysis.requiredAgents.includes('review')) {
|
||||
for (const execute of executeResults) {
|
||||
const review = await agent({
|
||||
subagent_type: 'claude',
|
||||
label: `${execute.type} Review`,
|
||||
prompt: `
|
||||
作为代码审查专家,审查以下 PR:
|
||||
|
||||
**PR URL**: ${execute.prUrl}
|
||||
**Issue**: ${issue.url}
|
||||
|
||||
${giteaRules}
|
||||
|
||||
审查检查:
|
||||
- 代码质量
|
||||
- 安全性
|
||||
- 性能
|
||||
- 测试覆盖
|
||||
|
||||
在 PR 中添加 Review 评论,标注问题代码行。
|
||||
|
||||
完成后返回 Review 结果:
|
||||
{
|
||||
"passed": true|false,
|
||||
"findings": ["问题1", "问题2"],
|
||||
"suggestions": ["建议1", "建议2"]
|
||||
}
|
||||
`
|
||||
})
|
||||
|
||||
execute.review = review
|
||||
log(`${review.passed ? '✅' : '❌'} ${execute.type} Review: ${review.passed ? '通过' : '需要修复'}`)
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Phase 4: 修复 (如需要) =====
|
||||
phase('修复')
|
||||
|
||||
for (const execute of executeResults) {
|
||||
let maxRetries = 3
|
||||
let retryCount = 0
|
||||
|
||||
while (!execute.review?.passed && retryCount < maxRetries) {
|
||||
log(`🔄 ${execute.type} 需要修复 (尝试 ${retryCount + 1}/${maxRetries})`)
|
||||
|
||||
const fix = await agent({
|
||||
subagent_type: 'claude',
|
||||
label: `${execute.type} Fix`,
|
||||
prompt: `
|
||||
**你的 PR 有审查意见,请修复**
|
||||
|
||||
**PR URL**: ${execute.prUrl}
|
||||
**Review 问题**: ${execute.review.findings.join('\n')}
|
||||
|
||||
${giteaRules}
|
||||
|
||||
修复步骤:
|
||||
1. 在 PR 分支上修复问题
|
||||
2. Commit: ${getCommitTemplate('fix').replace('{description}', '修复 Review 问题')}
|
||||
3. Push 更新
|
||||
4. 回复 Review 评论说明修复内容
|
||||
|
||||
修复完成后返回更新后的状态。
|
||||
`
|
||||
})
|
||||
|
||||
log(`✅ ${execute.type} 修复完成`)
|
||||
|
||||
// 重新审查
|
||||
const reReview = await agent({
|
||||
subagent_type: 'claude',
|
||||
label: `${execute.type} Re-review`,
|
||||
prompt: `
|
||||
重新审查 PR: ${execute.prUrl}
|
||||
|
||||
${giteaRules}
|
||||
|
||||
检查之前的 Review 问题是否已修复。
|
||||
|
||||
返回 Review 结果:
|
||||
{
|
||||
"passed": true|false,
|
||||
"findings": ["剩余问题"],
|
||||
"suggestions": ["建议"]
|
||||
}
|
||||
`
|
||||
})
|
||||
|
||||
execute.review = reReview
|
||||
retryCount++
|
||||
|
||||
if (reReview.passed) {
|
||||
log(`✅ ${execute.type} 重新审查通过`)
|
||||
}
|
||||
}
|
||||
|
||||
if (!execute.review?.passed && retryCount >= maxRetries) {
|
||||
log(`⚠️ ${execute.type} 达到最大重试次数,需要人工介入`)
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Phase 5: 验收 =====
|
||||
phase('验收')
|
||||
|
||||
// 安排 Test Sub Agent 验证
|
||||
if (analysis.requiredAgents.includes('test')) {
|
||||
for (const execute of executeResults) {
|
||||
const test = await agent({
|
||||
subagent_type: 'claude',
|
||||
label: `${execute.type} Test`,
|
||||
prompt: `
|
||||
作为测试工程师,验证以下 PR 的功能:
|
||||
|
||||
**PR URL**: ${execute.prUrl}
|
||||
**Issue**: ${issue.url}
|
||||
|
||||
${giteaRules}
|
||||
|
||||
测试步骤:
|
||||
1. 拉取 PR 代码
|
||||
2. 安装依赖
|
||||
3. 运行测试
|
||||
4. 检查测试覆盖率
|
||||
|
||||
返回测试结果:
|
||||
{
|
||||
"passed": true|false,
|
||||
"coverage": "85%",
|
||||
"failures": [],
|
||||
"summary": "测试摘要"
|
||||
}
|
||||
`
|
||||
})
|
||||
|
||||
execute.test = test
|
||||
log(`${test.passed ? '✅' : '❌'} ${execute.type} Test: ${test.passed ? '通过' : '失败'}`)
|
||||
}
|
||||
}
|
||||
|
||||
// 最终验收
|
||||
const allPassed = executeResults.every(e =>
|
||||
e.review?.passed && (!e.test || e.test?.passed)
|
||||
)
|
||||
|
||||
if (allPassed) {
|
||||
// 合并所有 PR
|
||||
for (const execute of executeResults) {
|
||||
await mergePR(execute.prUrl, gitea)
|
||||
log(`✅ 已合并 PR: ${execute.prUrl}`)
|
||||
}
|
||||
|
||||
// 关闭 Issue
|
||||
await closeIssue(issue.number, gitea)
|
||||
log(`✅ 已关闭 Issue: ${issue.url}`)
|
||||
|
||||
return {
|
||||
status: '完成',
|
||||
issue: issue.url,
|
||||
prs: executeResults.map(e => e.prUrl),
|
||||
message: '任务完成并已合并'
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
status: '需要人工介入',
|
||||
issue: issue.url,
|
||||
prs: executeResults.map(e => ({
|
||||
url: e.prUrl,
|
||||
review: e.review,
|
||||
test: e.test
|
||||
})),
|
||||
message: '部分 PR 未通过审查或测试,需要人工处理'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助函数
|
||||
*/
|
||||
async function createIssue(task, rules, gitea) {
|
||||
const repoInfo = gitea.getRepoInfo()
|
||||
|
||||
// 生成 Issue 标题(包含项目标识)
|
||||
const title = `[${repoInfo.repo}] ${task.title || task}`
|
||||
|
||||
// 生成 Issue 正文
|
||||
const body = generateIssueBody(task, rules)
|
||||
|
||||
// 生成标签
|
||||
const labels = generateIssueLabels(task)
|
||||
|
||||
try {
|
||||
const issue = await gitea.withRetry(async () => {
|
||||
return await gitea.createIssue({
|
||||
title,
|
||||
body,
|
||||
labels
|
||||
})
|
||||
})
|
||||
|
||||
log(`✅ Issue 已创建: ${issue.url}`)
|
||||
return issue
|
||||
} catch (error) {
|
||||
log(`❌ 创建 Issue 失败: ${error.message}`)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 Issue 正文
|
||||
*/
|
||||
function generateIssueBody(task, rules) {
|
||||
return `
|
||||
## 项目信息
|
||||
- 项目: ${task.project || 'sanguo_moziplus_v3'}
|
||||
- 需求编号: ${task.id || 'D-PENDING'}
|
||||
- 复杂度: ${task.complexity || '待评估'}
|
||||
|
||||
## 需求描述
|
||||
${task.description || task}
|
||||
|
||||
## 执行清单
|
||||
|
||||
### 📋 Execute Sub Agent
|
||||
> **负责**: Execute Sub Agent
|
||||
> **状态**: 🔄 进行中
|
||||
|
||||
- [ ] 任务分析和规划
|
||||
- [ ] 代码实现
|
||||
- [ ] 单元测试编写
|
||||
- [ ] 本地验证
|
||||
|
||||
**完成时标记**: \`@main-agent ✅ EXECUTE_DONE\`
|
||||
|
||||
### 📋 Review Sub Agent
|
||||
> **负责**: Review Sub Agent
|
||||
> **状态**: ⏳ 等待中
|
||||
|
||||
- [ ] 代码质量检查
|
||||
- [ ] 安全性审查
|
||||
- [ ] 性能评估
|
||||
|
||||
**完成时标记**: \`@main-agent ✅ REVIEW_DONE verdict=approved\`
|
||||
|
||||
### 📋 Test Sub Agent
|
||||
> **负责**: Test Sub Agent
|
||||
> **状态**: ⏳ 等待中
|
||||
|
||||
- [ ] 测试用例编写
|
||||
- [ ] 测试执行
|
||||
- [ ] 覆盖率检查
|
||||
|
||||
**完成时标记**: \`@main-agent ✅ TEST_DONE result=passed\`
|
||||
|
||||
### 📋 Main Agent 验收
|
||||
> **负责**: Main Agent
|
||||
> **状态**: ⏳ 等待中
|
||||
|
||||
- [ ] 需求 → 设计 一致性
|
||||
- [ ] 设计 → 编码 一致性
|
||||
- [ ] 需求 → 编码 一致性
|
||||
|
||||
**完成时标记**: \`@main-agent ✅ VERIFICATION_PASSED\`
|
||||
|
||||
## 执行状态
|
||||
| 阶段 | 负责者 | 状态 | 更新时间 |
|
||||
|------|-------|------|---------|
|
||||
| Execute | Execute Sub Agent | 🔄 进行中 | - |
|
||||
| Review | Review Sub Agent | ⏳ 等待 | - |
|
||||
| Test | Test Sub Agent | ⏳ 等待 | - |
|
||||
| 验收 | Main Agent | ⏳ 等待 | - |
|
||||
`
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 Issue 标签
|
||||
*/
|
||||
function generateIssueLabels(task) {
|
||||
const labels = []
|
||||
|
||||
// 添加复杂度标签
|
||||
if (task.complexity) {
|
||||
labels.push(`complexity:${task.complexity}`)
|
||||
}
|
||||
|
||||
// 添加类型标签
|
||||
if (task.type) {
|
||||
labels.push(task.type)
|
||||
}
|
||||
|
||||
return labels
|
||||
}
|
||||
|
||||
async function analyzeTask(task) {
|
||||
return await agent({
|
||||
subagent_type: 'Plan',
|
||||
prompt: `
|
||||
分析任务: "${task}"
|
||||
|
||||
返回 JSON:
|
||||
{
|
||||
"complexity": "low|medium|high",
|
||||
"requiredAgents": ["backend", "frontend", "review", "test"],
|
||||
"backendTask": "后端任务描述",
|
||||
"frontendTask": "前端任务描述",
|
||||
"slug": "task-slug"
|
||||
}
|
||||
`,
|
||||
schema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
complexity: { type: "string", enum: ["low", "medium", "high"] },
|
||||
requiredAgents: { type: "array", items: { type: "string" } },
|
||||
backendTask: { type: "string" },
|
||||
frontendTask: { type: "string" },
|
||||
slug: { type: "string" }
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function mergePR(prUrl, gitea) {
|
||||
try {
|
||||
// 从 PR URL 中提取 PR 编号
|
||||
const prMatch = prUrl.match(/\/pulls\/(\d+)/)
|
||||
if (!prMatch) {
|
||||
throw new Error(`无效的 PR URL: ${prUrl}`)
|
||||
}
|
||||
|
||||
const prNumber = parseInt(prMatch[1], 10)
|
||||
|
||||
await gitea.withRetry(async () => {
|
||||
return await gitea.mergePullRequest(prNumber, {
|
||||
deleteBranch: true,
|
||||
mergeStyle: 'merge'
|
||||
})
|
||||
})
|
||||
|
||||
log(`✅ PR 已合并: ${prUrl}`)
|
||||
} catch (error) {
|
||||
log(`❌ 合并 PR 失败: ${error.message}`)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async function closeIssue(issueId, gitea) {
|
||||
try {
|
||||
await gitea.withRetry(async () => {
|
||||
return await gitea.closeIssue(issueId)
|
||||
})
|
||||
|
||||
log(`✅ Issue 已关闭: #${issueId}`)
|
||||
} catch (error) {
|
||||
log(`❌ 关闭 Issue 失败: ${error.message}`)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待 Sub Agent 完成并返回标记数据
|
||||
*
|
||||
* @param {Object} gitea - Gitea 适配器实例
|
||||
* @param {number} issueNumber - Issue 编号
|
||||
* @param {string} markerType - 期望的标记类型
|
||||
* @param {Object} options - 选项
|
||||
* @returns {Promise<Object>} 标记数据
|
||||
*/
|
||||
async function waitForSubAgentCompletion(gitea, issueNumber, markerType, options = {}) {
|
||||
const {
|
||||
timeout = 30 * 60 * 1000, // 30 分钟超时
|
||||
interval = 10 * 1000, // 10 秒检查间隔
|
||||
onProgress = null // 进度回调
|
||||
} = options
|
||||
|
||||
const startTime = Date.now()
|
||||
let checkCount = 0
|
||||
|
||||
log(`⏳ 等待 ${markerType} 标记...`)
|
||||
|
||||
while (Date.now() - startTime < timeout) {
|
||||
checkCount++
|
||||
|
||||
try {
|
||||
// 读取 Issue Comments
|
||||
const comments = await gitea.getIssueComments(issueNumber)
|
||||
|
||||
// 查找目标标记
|
||||
const marker = findLatestMarker(comments, markerType)
|
||||
|
||||
if (marker) {
|
||||
log(`✅ 检测到 ${markerType} 标记 (检查 ${checkCount} 次)`)
|
||||
return marker.data
|
||||
}
|
||||
|
||||
// 进度回调
|
||||
if (onProgress) {
|
||||
onProgress({
|
||||
elapsed: Date.now() - startTime,
|
||||
checkCount,
|
||||
markerType: null
|
||||
})
|
||||
}
|
||||
|
||||
// 等待下次检查
|
||||
await new Promise(resolve => setTimeout(resolve, interval))
|
||||
} catch (error) {
|
||||
log(`⚠️ 检查标记时出错: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`等待 ${markerType} 标记超时 (${timeout / 1000} 秒)`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布进度更新 Comment
|
||||
*
|
||||
* @param {Object} gitea - Gitea 适配器实例
|
||||
* @param {number} issueNumber - Issue 编号
|
||||
* @param {string} stage - 当前阶段
|
||||
* @param {Array<string>} completed - 已完成任务
|
||||
* @param {Array<string>} inProgress - 进行中任务
|
||||
*/
|
||||
async function publishProgressUpdate(gitea, issueNumber, stage, completed, inProgress) {
|
||||
const content = generateProgressUpdate({
|
||||
stage,
|
||||
completed,
|
||||
inProgress
|
||||
})
|
||||
|
||||
await gitea.createIssueComment(issueNumber, content)
|
||||
log(`📝 进度更新已发布: ${stage} 阶段`)
|
||||
}
|
||||
|
||||
function log(message) {
|
||||
console.log(`[${new Date().toISOString()}] ${message}`)
|
||||
}
|
||||
|
||||
function phase(title) {
|
||||
console.log(`\n=== ${title} ===`)
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
/**
|
||||
* Comment 标记生成器
|
||||
*
|
||||
* 根据 v0.5 设计文档中的 Comment 标记约定,生成标准的完成标记
|
||||
*/
|
||||
|
||||
/**
|
||||
* 生成 Execute Sub Agent 完成标记
|
||||
*
|
||||
* @param {Object} data - 完成数据
|
||||
* @param {Array<string>} data.deliverables - 交付物列表
|
||||
* @param {Object} data.testStatus - 测试状态
|
||||
* @param {string} data.executor - 执行者名称
|
||||
* @returns {string} 完成标记内容
|
||||
*/
|
||||
export function generateExecuteMarker(data) {
|
||||
const {
|
||||
deliverables = [],
|
||||
testStatus = { local: 'PASS', coverage: '0%' },
|
||||
executor = 'Execute Sub Agent',
|
||||
notes = ''
|
||||
} = data
|
||||
|
||||
const timestamp = new Date().toISOString()
|
||||
|
||||
return `@main-agent ✅ **EXECUTE_DONE**
|
||||
|
||||
## 完成总结
|
||||
|
||||
### 交付物
|
||||
${deliverables.map((item, i) => `${i + 1}. \`${item}\``).join('\n')}
|
||||
|
||||
### 测试状态
|
||||
- 本地运行: ${testStatus.local ? '✅ ' + testStatus.local : '❌ FAIL'}
|
||||
${testStatus.coverage ? `- 覆盖率: ${testStatus.coverage}` : ''}
|
||||
|
||||
${notes ? `### 备注\n${notes}\n` : ''}
|
||||
|
||||
---
|
||||
**执行者**: ${executor}
|
||||
**完成时间**: ${timestamp}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 Review Sub Agent 完成标记
|
||||
*
|
||||
* @param {Object} data - 审查数据
|
||||
* @param {string} data.verdict - 审查结论 (approved/rejected)
|
||||
* @param {Array<string>} data.findings - 发现的问题
|
||||
* @param {Array<string>} data.suggestions - 改进建议
|
||||
* @param {string} data.reviewer - 审查者名称
|
||||
* @returns {string} 完成标记内容
|
||||
*/
|
||||
export function generateReviewMarker(data) {
|
||||
const {
|
||||
verdict = 'approved',
|
||||
findings = [],
|
||||
suggestions = [],
|
||||
reviewer = 'Review Sub Agent',
|
||||
notes = ''
|
||||
} = data
|
||||
|
||||
const timestamp = new Date().toISOString()
|
||||
const verdictIcon = verdict === 'approved' ? '✅' : '❌'
|
||||
const verdictText = verdict.toUpperCase()
|
||||
|
||||
return `@main-agent ${verdictIcon} **REVIEW_DONE verdict=${verdictText}**
|
||||
|
||||
## 审查结果
|
||||
|
||||
### 检查项
|
||||
- 代码质量: ${verdict === 'approved' ? '✅' : '❌'}
|
||||
- 安全性: ${verdict === 'approved' ? '✅' : '❌'}
|
||||
- 性能: ${verdict === 'approved' ? '✅' : '❌'}
|
||||
- 测试覆盖: ${verdict === 'approved' ? '✅' : '❌'}
|
||||
|
||||
${findings.length > 0 ? `### 发现的问题
|
||||
${findings.map((f, i) => `${i + 1}. ${f}`).join('\n')}
|
||||
|
||||
` : ''}${suggestions.length > 0 ? `### 改进建议
|
||||
${suggestions.map((s, i) => `${i + 1}. ${s}`).join('\n')}
|
||||
|
||||
` : ''}${notes ? `### 备注\n${notes}\n` : ''}---
|
||||
**审查者**: ${reviewer}
|
||||
**结论**: ${verdictIcon} ${verdictText}
|
||||
**完成时间**: ${timestamp}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 Test Sub Agent 完成标记
|
||||
*
|
||||
* @param {Object} data - 测试数据
|
||||
* @param {string} data.result - 测试结果 (passed/failed)
|
||||
* @param {string} data.coverage - 测试覆盖率
|
||||
* @param {Array<string>} data.failures - 失败的测试
|
||||
* @param {string} data.summary - 测试摘要
|
||||
* @param {string} data.tester - 测试者名称
|
||||
* @returns {string} 完成标记内容
|
||||
*/
|
||||
export function generateTestMarker(data) {
|
||||
const {
|
||||
result = 'passed',
|
||||
coverage = '0%',
|
||||
failures = [],
|
||||
summary = '',
|
||||
tester = 'Test Sub Agent',
|
||||
notes = ''
|
||||
} = data
|
||||
|
||||
const timestamp = new Date().toISOString()
|
||||
const resultIcon = result === 'passed' ? '✅' : '❌'
|
||||
const resultText = result.toUpperCase()
|
||||
|
||||
return `@main-agent ${resultIcon} **TEST_DONE result=${resultText} coverage=${coverage}**
|
||||
|
||||
## 测试结果
|
||||
|
||||
### 测试摘要
|
||||
${summary || '无'}
|
||||
|
||||
${failures.length > 0 ? `### 失败的测试
|
||||
${failures.map((f, i) => `${i + 1}. ${f}`).join('\n')}
|
||||
|
||||
` : ''}${notes ? `### 备注\n${notes}\n` : ''}---
|
||||
**测试者**: ${tester}
|
||||
**覆盖率**: ${coverage}
|
||||
**完成时间**: ${timestamp}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 Main Agent 验收完成标记
|
||||
*
|
||||
* @param {Object} data - 验收数据
|
||||
* @param {Object} data.requirementDesign - 需求→设计检查结果
|
||||
* @param {Object} data.designCode - 设计→编码检查结果
|
||||
* @param {Object} data.requirementCode - 需求→编码检查结果
|
||||
* @param {string} data.verdict - 最终结论 (approved/rejected)
|
||||
* @returns {string} 完成标记内容
|
||||
*/
|
||||
export function generateVerificationMarker(data) {
|
||||
const {
|
||||
requirementDesign = { passed: true, items: [] },
|
||||
designCode = { passed: true, items: [] },
|
||||
requirementCode = { passed: true, items: [] },
|
||||
verdict = 'approved'
|
||||
} = data
|
||||
|
||||
const timestamp = new Date().toISOString()
|
||||
const verdictIcon = verdict === 'approved' ? '✅' : '❌'
|
||||
const verdictText = verdict.toUpperCase()
|
||||
|
||||
// 检查是否全部通过
|
||||
const allPassed = requirementDesign.passed && designCode.passed && requirementCode.passed
|
||||
const finalVerdict = allPassed ? 'approved' : 'rejected'
|
||||
|
||||
return `@main-agent ✅ **VERIFICATION_${finalVerdict.toUpperCase()}**
|
||||
|
||||
## 三向一致性检查
|
||||
|
||||
### 1️⃣ 需求 → 设计
|
||||
${renderCheckTable(requirementDesign.items)}
|
||||
${requirementDesign.passed ? '✅ **需求→设计: 通过**' : '❌ **需求→设计: 未通过**'}
|
||||
|
||||
### 2️⃣ 设计 → 编码
|
||||
${renderCheckTable(designCode.items)}
|
||||
${designCode.passed ? '✅ **设计→编码: 通过**' : '❌ **设计→编码: 未通过**'}
|
||||
|
||||
### 3️⃣ 需求 → 编码
|
||||
${renderCheckTable(requirementCode.items)}
|
||||
${requirementCode.passed ? '✅ **需求→编码: 通过**' : '❌ **需求→编码: 未通过**'}
|
||||
|
||||
## 最终结论
|
||||
${allPassed ? '✅ **三向一致性检查全部通过**' : '❌ **三向一致性检查未通过,存在偏差**'}
|
||||
**VERDICT**: ${verdictIcon} ${finalVerdict === 'approved' ? 'APPROVED FOR MERGE' : 'NEEDS FIX'}
|
||||
|
||||
---
|
||||
**执行者**: Main Agent
|
||||
**完成时间**: ${timestamp}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助函数:渲染检查表格
|
||||
*/
|
||||
function renderCheckTable(items) {
|
||||
if (!items || items.length === 0) {
|
||||
return '无检查项'
|
||||
}
|
||||
|
||||
const header = '| 检查项 | 实际情况 | 状态 |\n|--------|----------|------|'
|
||||
const rows = items.map(item => {
|
||||
const status = item.passed ? '✅' : '❌'
|
||||
return `| ${item.check} | ${item.actual || '-'} | ${status} |`
|
||||
}).join('\n')
|
||||
|
||||
return `${header}\n${rows}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成进度更新标记
|
||||
*
|
||||
* @param {Object} data - 进度数据
|
||||
* @param {string} data.stage - 当前阶段
|
||||
* @param {Array<string>} data.completed - 已完成的任务
|
||||
* @param {Array<string>} data.inProgress - 进行中的任务
|
||||
* @returns {string} 进度更新内容
|
||||
*/
|
||||
export function generateProgressUpdate(data) {
|
||||
const {
|
||||
stage = 'Execute',
|
||||
completed = [],
|
||||
inProgress = []
|
||||
} = data
|
||||
|
||||
const total = completed.length + inProgress.length
|
||||
const progress = total > 0 ? Math.round((completed.length / total) * 100) : 0
|
||||
|
||||
return `@main-agent 📝 **进度更新: ${stage} 阶段**
|
||||
|
||||
## 已完成
|
||||
${completed.map((item, i) => `- ✅ ${item}`).join('\n') || '- 无'}
|
||||
|
||||
## 进行中
|
||||
${inProgress.map((item, i) => `- 🔄 ${item}`).join('\n') || '- 无'}
|
||||
|
||||
---
|
||||
**进度**: ${progress}% (${completed.length}/${total} 完成)`
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成偏差报告标记
|
||||
*
|
||||
* @param {Object} data - 偏差数据
|
||||
* @param {string} data.type - 偏差类型 (requirement-design/design-code/requirement-code)
|
||||
* @param {string} data.issue - 偏差描述
|
||||
* @param {string} data.expected - 预期情况
|
||||
* @param {string} data.actual - 实际情况
|
||||
* @returns {string} 偏差报告内容
|
||||
*/
|
||||
export function generateDeviationMarker(data) {
|
||||
const {
|
||||
type = 'unknown',
|
||||
issue = '',
|
||||
expected = '',
|
||||
actual = '',
|
||||
actionRequired = []
|
||||
} = data
|
||||
|
||||
const typeLabels = {
|
||||
'requirement-design': '需求 → 设计 偏差',
|
||||
'design-code': '设计 → 编码 偏差',
|
||||
'requirement-code': '需求 → 编码 偏差'
|
||||
}
|
||||
|
||||
const timestamp = new Date().toISOString()
|
||||
|
||||
return `@main-agent ❌ **CONSISTENCY_ISSUE**
|
||||
|
||||
## 发现偏差
|
||||
|
||||
### 问题: ${typeLabels[type] || type}
|
||||
**问题描述**: ${issue}
|
||||
|
||||
${expected ? `**预期**: ${expected}\n` : ''}${actual ? `**实际**: ${actual}\n` : ''}${actionRequired.length > 0 ? `### 处理要求
|
||||
${actionRequired.map((a, i) => `${i + 1}. ${a}`).join('\n')}
|
||||
|
||||
` : ''}---
|
||||
**标签**: needs-consistency-fix 🔴
|
||||
**报告时间**: ${timestamp}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出所有标记生成函数
|
||||
*/
|
||||
export default {
|
||||
generateExecuteMarker,
|
||||
generateReviewMarker,
|
||||
generateTestMarker,
|
||||
generateVerificationMarker,
|
||||
generateProgressUpdate,
|
||||
generateDeviationMarker
|
||||
}
|
||||
@@ -0,0 +1,391 @@
|
||||
/**
|
||||
* Comment 解析器
|
||||
*
|
||||
* 解析 Issue Comments 中的标记,提取关键信息
|
||||
*/
|
||||
|
||||
/**
|
||||
* 标记类型枚举
|
||||
*/
|
||||
export const MarkerType = {
|
||||
EXECUTE_DONE: 'EXECUTE_DONE',
|
||||
REVIEW_DONE: 'REVIEW_DONE',
|
||||
TEST_DONE: 'TEST_DONE',
|
||||
VERIFICATION_PASSED: 'VERIFICATION_PASSED',
|
||||
VERIFICATION_REJECTED: 'VERIFICATION_REJECTED',
|
||||
PROGRESS_UPDATE: 'PROGRESS_UPDATE',
|
||||
CONSISTENCY_ISSUE: 'CONSISTENCY_ISSUE'
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析完成标记
|
||||
*
|
||||
* @param {string} commentBody - Comment 内容
|
||||
* @returns {Object|null} 解析结果
|
||||
*/
|
||||
export function parseCompletionMarker(commentBody) {
|
||||
// 检测 EXECUTE_DONE
|
||||
if (commentBody.includes('EXECUTE_DONE')) {
|
||||
return {
|
||||
type: MarkerType.EXECUTE_DONE,
|
||||
status: 'completed',
|
||||
data: extractExecuteData(commentBody)
|
||||
}
|
||||
}
|
||||
|
||||
// 检测 REVIEW_DONE
|
||||
if (commentBody.includes('REVIEW_DONE')) {
|
||||
return {
|
||||
type: MarkerType.REVIEW_DONE,
|
||||
status: 'completed',
|
||||
data: extractReviewData(commentBody)
|
||||
}
|
||||
}
|
||||
|
||||
// 检测 TEST_DONE
|
||||
if (commentBody.includes('TEST_DONE')) {
|
||||
return {
|
||||
type: MarkerType.TEST_DONE,
|
||||
status: 'completed',
|
||||
data: extractTestData(commentBody)
|
||||
}
|
||||
}
|
||||
|
||||
// 检测 VERIFICATION_PASSED
|
||||
if (commentBody.includes('VERIFICATION_PASSED')) {
|
||||
return {
|
||||
type: MarkerType.VERIFICATION_PASSED,
|
||||
status: 'completed',
|
||||
data: extractVerificationData(commentBody)
|
||||
}
|
||||
}
|
||||
|
||||
// 检测 VERIFICATION_REJECTED
|
||||
if (commentBody.includes('VERIFICATION_REJECTED')) {
|
||||
return {
|
||||
type: MarkerType.VERIFICATION_REJECTED,
|
||||
status: 'failed',
|
||||
data: extractVerificationData(commentBody)
|
||||
}
|
||||
}
|
||||
|
||||
// 检测 PROGRESS_UPDATE
|
||||
if (commentBody.includes('进度更新')) {
|
||||
return {
|
||||
type: MarkerType.PROGRESS_UPDATE,
|
||||
status: 'in_progress',
|
||||
data: extractProgressData(commentBody)
|
||||
}
|
||||
}
|
||||
|
||||
// 检测 CONSISTENCY_ISSUE
|
||||
if (commentBody.includes('CONSISTENCY_ISSUE')) {
|
||||
return {
|
||||
type: MarkerType.CONSISTENCY_ISSUE,
|
||||
status: 'failed',
|
||||
data: extractDeviationData(commentBody)
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取 EXECUTE_DONE 数据
|
||||
*/
|
||||
function extractExecuteData(commentBody) {
|
||||
const deliverables = []
|
||||
const deliverableMatch = commentBody.match(/### 交付物\n([\s\S]*?)\n\n/)
|
||||
if (deliverableMatch) {
|
||||
const lines = deliverableMatch[1].split('\n')
|
||||
lines.forEach(line => {
|
||||
const match = line.match(/\d+\.\s*`([^`]+)`/)
|
||||
if (match) {
|
||||
deliverables.push(match[1])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const testLocalMatch = commentBody.match(/本地运行:\s*([✅❌])\s*(\w+)/)
|
||||
const coverageMatch = commentBody.match(/覆盖率:\s*([\d%]+)/)
|
||||
const executorMatch = commentBody.match(/\*\*执行者\*\*:\s*([^\n]+)/)
|
||||
const completedAtMatch = commentBody.match(/\*\*完成时间\*\*:\s*([^\n]+)/)
|
||||
|
||||
return {
|
||||
deliverables,
|
||||
testStatus: {
|
||||
local: testLocalMatch ? `${testLocalMatch[1]} ${testLocalMatch[2]}` : 'UNKNOWN',
|
||||
coverage: coverageMatch ? coverageMatch[1] : '0%'
|
||||
},
|
||||
executor: executorMatch ? executorMatch[1].trim() : 'Execute Sub Agent',
|
||||
completedAt: completedAtMatch ? completedAtMatch[1].trim() : null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取 REVIEW_DONE 数据
|
||||
*/
|
||||
function extractReviewData(commentBody) {
|
||||
const verdictMatch = commentBody.match(/verdict=(\w+)/)
|
||||
const verdict = verdictMatch ? verdictMatch[1].toLowerCase() : 'unknown'
|
||||
|
||||
const findings = []
|
||||
const findingsMatch = commentBody.match(/### 发现的问题\n([\s\S]*?)\n\n/)
|
||||
if (findingsMatch) {
|
||||
const lines = findingsMatch[1].split('\n')
|
||||
lines.forEach(line => {
|
||||
const match = line.match(/\d+\.\s*(.+)/)
|
||||
if (match) {
|
||||
findings.push(match[1].trim())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const suggestions = []
|
||||
const suggestionsMatch = commentBody.match(/### 改进建议\n([\s\S]*?)\n\n/)
|
||||
if (suggestionsMatch) {
|
||||
const lines = suggestionsMatch[1].split('\n')
|
||||
lines.forEach(line => {
|
||||
const match = line.match(/\d+\.\s*(.+)/)
|
||||
if (match) {
|
||||
suggestions.push(match[1].trim())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const reviewerMatch = commentBody.match(/\*\*审查者\*\*:\s*([^\n]+)/)
|
||||
const completedAtMatch = commentBody.match(/\*\*完成时间\*\*:\s*([^\n]+)/)
|
||||
|
||||
return {
|
||||
verdict: verdict === 'approved' ? 'approved' : 'rejected',
|
||||
findings,
|
||||
suggestions,
|
||||
reviewer: reviewerMatch ? reviewerMatch[1].trim() : 'Review Sub Agent',
|
||||
completedAt: completedAtMatch ? completedAtMatch[1].trim() : null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取 TEST_DONE 数据
|
||||
*/
|
||||
function extractTestData(commentBody) {
|
||||
const resultMatch = commentBody.match(/result=(\w+)/)
|
||||
const coverageMatch = commentBody.match(/coverage=([\d%]+)/)
|
||||
const summaryMatch = commentBody.match(/### 测试摘要\n([\s\S]*?)\n\n/)
|
||||
|
||||
const failures = []
|
||||
const failuresMatch = commentBody.match(/### 失败的测试\n([\s\S]*?)\n\n/)
|
||||
if (failuresMatch) {
|
||||
const lines = failuresMatch[1].split('\n')
|
||||
lines.forEach(line => {
|
||||
const match = line.match(/\d+\.\s*(.+)/)
|
||||
if (match) {
|
||||
failures.push(match[1].trim())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const testerMatch = commentBody.match(/\*\*测试者\*\*:\s*([^\n]+)/)
|
||||
const completedAtMatch = commentBody.match(/\*\*完成时间\*\*:\s*([^\n]+)/)
|
||||
|
||||
return {
|
||||
result: resultMatch ? resultMatch[1].toLowerCase() : 'unknown',
|
||||
coverage: coverageMatch ? coverageMatch[1] : '0%',
|
||||
summary: summaryMatch ? summaryMatch[1].trim() : '',
|
||||
failures,
|
||||
tester: testerMatch ? testerMatch[1].trim() : 'Test Sub Agent',
|
||||
completedAt: completedAtMatch ? completedAtMatch[1].trim() : null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取 VERIFICATION 数据
|
||||
*/
|
||||
function extractVerificationData(commentBody) {
|
||||
// 提取三个检查结果
|
||||
const requirementDesignPassed = commentBody.includes('需求→设计: 通过')
|
||||
const designCodePassed = commentBody.includes('设计→编码: 通过')
|
||||
const requirementCodePassed = commentBody.includes('需求→编码: 通过')
|
||||
|
||||
const allPassed = requirementDesignPassed && designCodePassed && requirementCodePassed
|
||||
|
||||
const completedAtMatch = commentBody.match(/\*\*完成时间\*\*:\s*([^\n]+)/)
|
||||
|
||||
return {
|
||||
requirementDesign: { passed: requirementDesignPassed },
|
||||
designCode: { passed: designCodePassed },
|
||||
requirementCode: { passed: requirementCodePassed },
|
||||
allPassed,
|
||||
verdict: allPassed ? 'approved' : 'rejected',
|
||||
completedAt: completedAtMatch ? completedAtMatch[1].trim() : null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取 PROGRESS_UPDATE 数据
|
||||
*/
|
||||
function extractProgressData(commentBody) {
|
||||
const progressMatch = commentBody.match(/\*\*进度\*\*:\s*(\d+)%/)
|
||||
const stageMatch = commentBody.match(/进度更新:\s*(\w+)\s*阶段/)
|
||||
|
||||
const completed = []
|
||||
const completedMatch = commentBody.match(/## 已完成\n([\s\S]*?)\n\n/)
|
||||
if (completedMatch) {
|
||||
const lines = completedMatch[1].split('\n')
|
||||
lines.forEach(line => {
|
||||
const match = line.match/- ✅ (.+)/)
|
||||
if (match) {
|
||||
completed.push(match[1].trim())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const inProgress = []
|
||||
const inProgressMatch = commentBody.match(/## 进行中\n([\s\S]*?)\n\n/)
|
||||
if (inProgressMatch) {
|
||||
const lines = inProgressMatch[1].split('\n')
|
||||
lines.forEach(line => {
|
||||
const match = line.match/- 🔄 (.+)/)
|
||||
if (match) {
|
||||
inProgress.push(match[1].trim())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
stage: stageMatch ? stageMatch[1] : 'Unknown',
|
||||
progress: progressMatch ? parseInt(progressMatch[1], 10) : 0,
|
||||
completed,
|
||||
inProgress
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取 CONSISTENCY_ISSUE 数据
|
||||
*/
|
||||
function extractDeviationData(commentBody) {
|
||||
const typeMatch = commentBody.match(/问题:\s*(.+)\s*偏差/)
|
||||
const issueMatch = commentBody.match(/\*\*问题描述\*\*:\s*([^\n]+)/)
|
||||
const expectedMatch = commentBody.match(/\*\*预期\*\*:\s*([^\n]+)/)
|
||||
const actualMatch = commentBody.match(/\*\*实际\*\*:\s*([^\n]+)/)
|
||||
|
||||
const actionRequired = []
|
||||
const actionMatch = commentBody.match(/### 处理要求\n([\s\S]*?)\n\n/)
|
||||
if (actionMatch) {
|
||||
const lines = actionMatch[1].split('\n')
|
||||
lines.forEach(line => {
|
||||
const match = line.match(/\d+\.\s*(.+)/)
|
||||
if (match) {
|
||||
actionRequired.push(match[1].trim())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
type: typeMatch ? typeMatch[1].trim() : 'unknown',
|
||||
issue: issueMatch ? issueMatch[1].trim() : '',
|
||||
expected: expectedMatch ? expectedMatch[1].trim() : '',
|
||||
actual: actualMatch ? actualMatch[1].trim() : '',
|
||||
actionRequired
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找最新的指定类型标记
|
||||
*
|
||||
* @param {Array<Object>} comments - Comments 数组
|
||||
* @param {string} markerType - 标记类型
|
||||
* @returns {Object|null} 最新的标记数据
|
||||
*/
|
||||
export function findLatestMarker(comments, markerType) {
|
||||
if (!comments || comments.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
// 从后往前遍历(最新的在前)
|
||||
for (let i = comments.length - 1; i >= 0; i--) {
|
||||
const comment = comments[i]
|
||||
const parsed = parseCompletionMarker(comment.body || comment.content || '')
|
||||
|
||||
if (parsed && parsed.type === markerType) {
|
||||
return {
|
||||
...parsed,
|
||||
commentId: comment.id,
|
||||
createdAt: comment.created_at || comment.timestamp,
|
||||
author: comment.user?.login || comment.author || 'Unknown'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查指定标记是否存在
|
||||
*
|
||||
* @param {Array<Object>} comments - Comments 数组
|
||||
* @param {string} markerType - 标记类型
|
||||
* @returns {boolean} 是否存在
|
||||
*/
|
||||
export function hasMarker(comments, markerType) {
|
||||
return findLatestMarker(comments, markerType) !== null
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有标记的摘要
|
||||
*
|
||||
* @param {Array<Object>} comments - Comments 数组
|
||||
* @returns {Object} 标记摘要
|
||||
*/
|
||||
export function getMarkersSummary(comments) {
|
||||
const summary = {
|
||||
executeDone: findLatestMarker(comments, MarkerType.EXECUTE_DONE),
|
||||
reviewDone: findLatestMarker(comments, MarkerType.REVIEW_DONE),
|
||||
testDone: findLatestMarker(comments, MarkerType.TEST_DONE),
|
||||
verificationPassed: findLatestMarker(comments, MarkerType.VERIFICATION_PASSED),
|
||||
verificationRejected: findLatestMarker(comments, MarkerType.VERIFICATION_REJECTED),
|
||||
progressUpdate: findLatestMarker(comments, MarkerType.PROGRESS_UPDATE),
|
||||
consistencyIssue: findLatestMarker(comments, MarkerType.CONSISTENCY_ISSUE)
|
||||
}
|
||||
|
||||
// 计算当前阶段状态
|
||||
summary.currentPhase = determineCurrentPhase(summary)
|
||||
|
||||
return summary
|
||||
}
|
||||
|
||||
/**
|
||||
* 确定当前阶段
|
||||
*/
|
||||
function determineCurrentPhase(summary) {
|
||||
if (summary.verificationPassed || summary.verificationRejected) {
|
||||
return 'completed'
|
||||
}
|
||||
|
||||
if (summary.reviewDone && summary.testDone) {
|
||||
return 'verification'
|
||||
}
|
||||
|
||||
if (summary.executeDone) {
|
||||
return 'review_and_test'
|
||||
}
|
||||
|
||||
if (summary.progressUpdate) {
|
||||
return 'executing'
|
||||
}
|
||||
|
||||
return 'pending'
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出所有解析函数
|
||||
*/
|
||||
export default {
|
||||
MarkerType,
|
||||
parseCompletionMarker,
|
||||
extractMarkerData: parseCompletionMarker,
|
||||
findLatestMarker,
|
||||
hasMarker,
|
||||
getMarkersSummary,
|
||||
determineCurrentPhase
|
||||
}
|
||||
@@ -0,0 +1,376 @@
|
||||
/**
|
||||
* 一致性检查模块
|
||||
*
|
||||
* 实现需求-设计-编码三向一致性检查逻辑
|
||||
*/
|
||||
|
||||
/**
|
||||
* 需求→设计一致性检查
|
||||
*
|
||||
* @param {Object} requirements - 需求列表
|
||||
* @param {Object} design - 设计文档
|
||||
* @returns {Object} 检查结果
|
||||
*/
|
||||
export function checkRequirementDesign(requirements, design) {
|
||||
const items = []
|
||||
let allPassed = true
|
||||
|
||||
// 如果 requirements 是数组,转换为对象
|
||||
const reqMap = Array.isArray(requirements)
|
||||
? requirements.reduce((acc, r, i) => {
|
||||
acc[`R${i + 1}`] = r
|
||||
return acc
|
||||
}, {})
|
||||
: requirements
|
||||
|
||||
// 遍历每个需求,检查设计是否覆盖
|
||||
for (const [reqId, requirement] of Object.entries(reqMap)) {
|
||||
const reqText = typeof requirement === 'string' ? requirement : requirement.description || requirement.text || JSON.stringify(requirement)
|
||||
const isCovered = checkDesignCoverage(reqText, design)
|
||||
|
||||
items.push({
|
||||
check: `需求 ${reqId}`,
|
||||
expected: reqText,
|
||||
actual: isCovered ? '已覆盖' : '未覆盖',
|
||||
passed: isCovered
|
||||
})
|
||||
|
||||
if (!isCovered) {
|
||||
allPassed = false
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'requirement-design',
|
||||
passed: allPassed,
|
||||
items,
|
||||
summary: allPassed ? '需求完全被设计覆盖' : '部分需求未被设计覆盖'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设计→编码一致性检查
|
||||
*
|
||||
* @param {Object} design - 设计文档
|
||||
* @param {Object} codeChanges - 代码变更
|
||||
* @returns {Object} 检查结果
|
||||
*/
|
||||
export function checkDesignCode(design, codeChanges) {
|
||||
const items = []
|
||||
let allPassed = true
|
||||
|
||||
// 提取设计中的关键组件/模块
|
||||
const designComponents = extractDesignComponents(design)
|
||||
|
||||
// 提取代码变更中的文件/模块
|
||||
const codeFiles = extractCodeFiles(codeChanges)
|
||||
|
||||
// 检查每个设计组件是否都有对应代码
|
||||
for (const component of designComponents) {
|
||||
const isImplemented = codeFiles.some(file =>
|
||||
file.name.includes(component.name) ||
|
||||
file.path.includes(component.path || component.name)
|
||||
)
|
||||
|
||||
items.push({
|
||||
check: `组件: ${component.name}`,
|
||||
expected: `设计: ${component.description || component.type || '组件'}`,
|
||||
actual: isImplemented ? `已实现: ${component.name}` : '未实现',
|
||||
passed: isImplemented
|
||||
})
|
||||
|
||||
if (!isImplemented) {
|
||||
allPassed = false
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'design-code',
|
||||
passed: allPassed,
|
||||
items,
|
||||
summary: allPassed ? '设计完全被编码实现' : '部分设计未在编码中实现'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 需求→编码一致性检查
|
||||
*
|
||||
* @param {Object} requirements - 需求列表
|
||||
* @param {Object} codeChanges - 代码变更
|
||||
* @returns {Object} 检查结果
|
||||
*/
|
||||
export function checkRequirementCode(requirements, codeChanges) {
|
||||
const items = []
|
||||
let allPassed = true
|
||||
|
||||
// 如果 requirements 是数组,转换为对象
|
||||
const reqMap = Array.isArray(requirements)
|
||||
? requirements.reduce((acc, r, i) => {
|
||||
acc[`R${i + 1}`] = r
|
||||
return acc
|
||||
}, {})
|
||||
: requirements
|
||||
|
||||
// 提取代码实现的功能点
|
||||
const codeFeatures = extractCodeFeatures(codeChanges)
|
||||
|
||||
// 检查每个需求是否在代码中实现
|
||||
for (const [reqId, requirement] of Object.entries(reqMap)) {
|
||||
const reqText = typeof requirement === 'string' ? requirement : requirement.description || requirement.text || JSON.stringify(requirement)
|
||||
const isImplemented = checkCodeImplementation(reqText, codeFeatures)
|
||||
|
||||
items.push({
|
||||
check: `需求 ${reqId}`,
|
||||
expected: reqText,
|
||||
actual: isImplemented ? '已实现' : '未实现',
|
||||
passed: isImplemented
|
||||
})
|
||||
|
||||
if (!isImplemented) {
|
||||
allPassed = false
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'requirement-code',
|
||||
passed: allPassed,
|
||||
items,
|
||||
summary: allPassed ? '需求完全在编码中实现' : '部分需求未在编码中实现'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 完整的三向一致性检查
|
||||
*
|
||||
* @param {Object} requirements - 需求列表
|
||||
* @param {Object} design - 设计文档
|
||||
* @param {Object} codeChanges - 代码变更
|
||||
* @returns {Object} 完整检查结果
|
||||
*/
|
||||
export function runThreeWayCheck(requirements, design, codeChanges) {
|
||||
const requirementDesign = checkRequirementDesign(requirements, design)
|
||||
const designCode = checkDesignCode(design, codeChanges)
|
||||
const requirementCode = checkRequirementCode(requirements, codeChanges)
|
||||
|
||||
const allPassed = requirementDesign.passed && designCode.passed && requirementCode.passed
|
||||
|
||||
return {
|
||||
allPassed,
|
||||
requirementDesign,
|
||||
designCode,
|
||||
requirementCode,
|
||||
summary: allPassed ? '三向一致性检查全部通过' : '三向一致性检查未通过',
|
||||
deviations: findDeviations(requirementDesign, designCode, requirementCode)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找偏差
|
||||
*/
|
||||
function findDeviations(requirementDesign, designCode, requirementCode) {
|
||||
const deviations = []
|
||||
|
||||
// 需求→设计偏差
|
||||
if (!requirementDesign.passed) {
|
||||
deviations.push({
|
||||
type: 'requirement-design',
|
||||
issues: requirementDesign.items.filter(i => !i.passed)
|
||||
})
|
||||
}
|
||||
|
||||
// 设计→编码偏差
|
||||
if (!designCode.passed) {
|
||||
deviations.push({
|
||||
type: 'design-code',
|
||||
issues: designCode.items.filter(i => !i.passed)
|
||||
})
|
||||
}
|
||||
|
||||
// 需求→编码偏差
|
||||
if (!requirementCode.passed) {
|
||||
deviations.push({
|
||||
type: 'requirement-code',
|
||||
issues: requirementCode.items.filter(i => !i.passed)
|
||||
})
|
||||
}
|
||||
|
||||
return deviations
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助函数:检查设计是否覆盖需求
|
||||
*/
|
||||
function checkDesignCoverage(requirementText, design) {
|
||||
const designText = typeof design === 'string' ? design : JSON.stringify(design)
|
||||
const reqKeywords = extractKeywords(requirementText)
|
||||
|
||||
// 至少有一个关键词在设计中被提及
|
||||
return reqKeywords.some(keyword =>
|
||||
designText.toLowerCase().includes(keyword.toLowerCase())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助函数:检查代码是否实现需求
|
||||
*/
|
||||
function checkCodeImplementation(requirementText, codeFeatures) {
|
||||
const reqKeywords = extractKeywords(requirementText)
|
||||
|
||||
// 至少有一个关键词在代码特性中被实现
|
||||
return reqKeywords.some(keyword =>
|
||||
codeFeatures.some(feature =>
|
||||
feature.toLowerCase().includes(keyword.toLowerCase())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助函数:提取关键词
|
||||
*/
|
||||
function extractKeywords(text) {
|
||||
// 简单的关键词提取:过滤常见停用词
|
||||
const stopWords = new Set(['的', '了', '是', '在', '和', '与', '或', '但', '如果', '那么', '这样', '那样', 'the', 'a', 'an', 'is', 'are', 'and', 'or', 'but', 'if', 'then', 'this', 'that'])
|
||||
|
||||
return text
|
||||
.toLowerCase()
|
||||
.split(/[\s,,。.!!??;;::]/)
|
||||
.filter(word => word.length > 1 && !stopWords.has(word))
|
||||
.slice(0, 5) // 取前5个关键词
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助函数:从设计中提取组件
|
||||
*/
|
||||
function extractDesignComponents(design) {
|
||||
const components = []
|
||||
|
||||
// 如果 design 是字符串,尝试解析
|
||||
if (typeof design === 'string') {
|
||||
// 简单的提取逻辑:查找常见的组件模式
|
||||
const patterns = [
|
||||
/表:\s*(\w+)/g,
|
||||
/接口:\s*(\w+)/g,
|
||||
/模块:\s*(\w+)/g,
|
||||
/组件:\s*(\w+)/g,
|
||||
/文件:\s*([^\s]+)/g
|
||||
]
|
||||
|
||||
for (const pattern of patterns) {
|
||||
let match
|
||||
while ((match = pattern.exec(design)) !== null) {
|
||||
components.push({
|
||||
name: match[1],
|
||||
type: 'unknown',
|
||||
description: match[0]
|
||||
})
|
||||
}
|
||||
}
|
||||
} else if (typeof design === 'object' && design !== null) {
|
||||
// 如果 design 是对象,直接提取
|
||||
for (const [key, value] of Object.entries(design)) {
|
||||
if (value && typeof value === 'object' && value.name) {
|
||||
components.push(value)
|
||||
} else if (typeof value === 'string') {
|
||||
components.push({
|
||||
name: key,
|
||||
type: 'unknown',
|
||||
description: value
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return components
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助函数:从代码变更中提取文件
|
||||
*/
|
||||
function extractCodeFiles(codeChanges) {
|
||||
const files = []
|
||||
|
||||
if (typeof codeChanges === 'string') {
|
||||
// 简单的文件路径提取
|
||||
const lines = codeChanges.split('\n')
|
||||
for (const line of lines) {
|
||||
const match = line.match(/([a-zA-Z0-9_\/]+\.[a-zA-Z0-9]+)/)
|
||||
if (match) {
|
||||
files.push({
|
||||
name: match[1].split('/').pop(),
|
||||
path: match[1]
|
||||
})
|
||||
}
|
||||
}
|
||||
} else if (Array.isArray(codeChanges)) {
|
||||
// 如果是数组,假设每个元素都是文件信息
|
||||
for (const change of codeChanges) {
|
||||
if (typeof change === 'string') {
|
||||
files.push({
|
||||
name: change.split('/').pop(),
|
||||
path: change
|
||||
})
|
||||
} else if (change.file || change.path || change.name) {
|
||||
files.push({
|
||||
name: change.file || change.name || change.path?.split('/').pop(),
|
||||
path: change.path || change.file
|
||||
})
|
||||
}
|
||||
}
|
||||
} else if (typeof codeChanges === 'object' && codeChanges !== null) {
|
||||
// 如果是对象,提取文件信息
|
||||
if (codeChanges.files) {
|
||||
return extractCodeFiles(codeChanges.files)
|
||||
}
|
||||
if (codeChanges.changes) {
|
||||
return extractCodeFiles(codeChanges.changes)
|
||||
}
|
||||
}
|
||||
|
||||
return files
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助函数:从代码中提取功能点
|
||||
*/
|
||||
function extractCodeFeatures(codeChanges) {
|
||||
const features = []
|
||||
|
||||
// 提取函数名、类名、变量名等作为功能特征
|
||||
const files = extractCodeFiles(codeChanges)
|
||||
|
||||
for (const file of files) {
|
||||
const name = file.name || file.path || ''
|
||||
// 从文件名推断功能
|
||||
if (name.includes('.')) {
|
||||
const baseName = name.substring(0, name.lastIndexOf('.'))
|
||||
features.push(baseName)
|
||||
}
|
||||
features.push(name)
|
||||
}
|
||||
|
||||
// 如果 codeChanges 包含 description 或 summary
|
||||
if (typeof codeChanges === 'object' && codeChanges !== null) {
|
||||
if (codeChanges.description) {
|
||||
features.push(codeChanges.description)
|
||||
}
|
||||
if (codeChanges.summary) {
|
||||
features.push(codeChanges.summary)
|
||||
}
|
||||
if (codeChanges.changes) {
|
||||
features.push(codeChanges.changes)
|
||||
}
|
||||
}
|
||||
|
||||
return features
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出所有检查函数
|
||||
*/
|
||||
export default {
|
||||
checkRequirementDesign,
|
||||
checkDesignCode,
|
||||
checkRequirementCode,
|
||||
runThreeWayCheck,
|
||||
findDeviations
|
||||
}
|
||||
@@ -0,0 +1,445 @@
|
||||
/**
|
||||
* Gitea MCP 适配层
|
||||
*
|
||||
* 封装 Gitea MCP 工具调用,提供统一的接口
|
||||
*/
|
||||
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
/**
|
||||
* 加载 Gitea 配置
|
||||
*/
|
||||
function loadConfig() {
|
||||
const configPath = path.join(process.cwd(), '.claude', 'gitea-config.json')
|
||||
try {
|
||||
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'))
|
||||
return config
|
||||
} catch (error) {
|
||||
throw new Error(`无法加载配置文件: ${configPath}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取仓库信息
|
||||
*/
|
||||
function getRepoInfo() {
|
||||
const config = loadConfig()
|
||||
return {
|
||||
baseUrl: config.gitea.baseUrl,
|
||||
owner: config.gitea.owner,
|
||||
repo: config.gitea.repo,
|
||||
defaultBranch: config.gitea.defaultBranch
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gitea MCP 适配器类
|
||||
*/
|
||||
export class GiteaMCPAdapter {
|
||||
constructor() {
|
||||
this.config = loadConfig()
|
||||
this.repoInfo = getRepoInfo()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取仓库信息
|
||||
*/
|
||||
getRepoInfo() {
|
||||
return this.repoInfo
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 Issue
|
||||
*
|
||||
* @param {Object} options - Issue 选项
|
||||
* @param {string} options.title - Issue 标题
|
||||
* @param {string} options.body - Issue 正文
|
||||
* @param {string[]} options.labels - Issue 标签
|
||||
* @returns {Promise<Object>} Issue 信息
|
||||
*/
|
||||
async createIssue(options) {
|
||||
const { title, body, labels = [] } = options
|
||||
const { owner, repo } = this.repoInfo
|
||||
|
||||
try {
|
||||
// 调用 Gitea MCP 工具创建 Issue
|
||||
const result = await mcp__gitea__issue_write({
|
||||
method: 'create',
|
||||
owner,
|
||||
repo,
|
||||
title,
|
||||
body,
|
||||
labels
|
||||
})
|
||||
|
||||
return {
|
||||
id: result.id,
|
||||
number: result.number,
|
||||
url: `${this.repoInfo.baseUrl}/${owner}/${repo}/issues/${result.number}`,
|
||||
title: result.title,
|
||||
body: result.body
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(`创建 Issue 失败: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新 Issue
|
||||
*
|
||||
* @param {number} issueNumber - Issue 编号
|
||||
* @param {Object} options - 更新选项
|
||||
* @returns {Promise<Object>} 更新后的 Issue 信息
|
||||
*/
|
||||
async updateIssue(issueNumber, options) {
|
||||
const { owner, repo } = this.repoInfo
|
||||
const { state, body } = options
|
||||
|
||||
try {
|
||||
const result = await mcp__gitea__issue_write({
|
||||
method: 'update',
|
||||
owner,
|
||||
repo,
|
||||
issue_number: issueNumber,
|
||||
state,
|
||||
body
|
||||
})
|
||||
|
||||
return result
|
||||
} catch (error) {
|
||||
throw new Error(`更新 Issue 失败: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭 Issue
|
||||
*
|
||||
* @param {number} issueNumber - Issue 编号
|
||||
* @returns {Promise<Object>} 关闭后的 Issue 信息
|
||||
*/
|
||||
async closeIssue(issueNumber) {
|
||||
return this.updateIssue(issueNumber, { state: 'closed' })
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取 Issue Comments
|
||||
*
|
||||
* @param {number} issueNumber - Issue 编号
|
||||
* @returns {Promise<Array>} Comments 列表
|
||||
*/
|
||||
async getIssueComments(issueNumber) {
|
||||
const { owner, repo } = this.repoInfo
|
||||
|
||||
try {
|
||||
const comments = await mcp__gitea__issue_read({
|
||||
method: 'get_comments',
|
||||
owner,
|
||||
repo,
|
||||
issue_number: issueNumber
|
||||
})
|
||||
|
||||
return comments
|
||||
} catch (error) {
|
||||
throw new Error(`读取 Issue Comments 失败: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 Issue Comment
|
||||
*
|
||||
* @param {number} issueNumber - Issue 编号
|
||||
* @param {string} body - Comment 内容
|
||||
* @returns {Promise<Object>} Comment 信息
|
||||
*/
|
||||
async createIssueComment(issueNumber, body) {
|
||||
const { owner, repo } = this.repoInfo
|
||||
|
||||
try {
|
||||
const comment = await mcp__gitea__issue_write({
|
||||
method: 'add_comment',
|
||||
owner,
|
||||
repo,
|
||||
issue_number: issueNumber,
|
||||
body
|
||||
})
|
||||
|
||||
return comment
|
||||
} catch (error) {
|
||||
throw new Error(`添加 Comment 失败: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建分支
|
||||
*
|
||||
* @param {string} branchName - 分支名称
|
||||
* @param {string} oldBranch - 源分支(默认为主分支)
|
||||
* @returns {Promise<Object>} 分支信息
|
||||
*/
|
||||
async createBranch(branchName, oldBranch = null) {
|
||||
const { owner, repo, defaultBranch } = this.repoInfo
|
||||
const sourceBranch = oldBranch || defaultBranch
|
||||
|
||||
try {
|
||||
const result = await mcp__gitea__create_branch({
|
||||
owner,
|
||||
repo,
|
||||
branch: branchName,
|
||||
old_branch: sourceBranch
|
||||
})
|
||||
|
||||
return result
|
||||
} catch (error) {
|
||||
throw new Error(`创建分支失败: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列出分支
|
||||
*
|
||||
* @returns {Promise<Array>} 分支列表
|
||||
*/
|
||||
async listBranches() {
|
||||
const { owner, repo } = this.repoInfo
|
||||
|
||||
try {
|
||||
const branches = await mcp__gitea__list_branches({
|
||||
owner,
|
||||
repo
|
||||
})
|
||||
|
||||
return branches
|
||||
} catch (error) {
|
||||
throw new Error(`列出分支失败: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 Pull Request
|
||||
*
|
||||
* @param {Object} options - PR 选项
|
||||
* @param {string} options.title - PR 标题
|
||||
* @param {string} options.body - PR 正文
|
||||
* @param {string} options.head - 源分支
|
||||
* @param {string} options.base - 目标分支
|
||||
* @returns {Promise<Object>} PR 信息
|
||||
*/
|
||||
async createPullRequest(options) {
|
||||
const { title, body, head, base } = options
|
||||
const { owner, repo, defaultBranch } = this.repoInfo
|
||||
const targetBranch = base || defaultBranch
|
||||
|
||||
try {
|
||||
const result = await mcp__gitea__pull_request_write({
|
||||
method: 'create',
|
||||
owner,
|
||||
repo,
|
||||
title,
|
||||
body,
|
||||
head,
|
||||
base: targetBranch
|
||||
})
|
||||
|
||||
return {
|
||||
id: result.id,
|
||||
number: result.number,
|
||||
url: `${this.repoInfo.baseUrl}/${owner}/${repo}/pulls/${result.number}`,
|
||||
title: result.title,
|
||||
body: result.body,
|
||||
head: result.head,
|
||||
base: result.base
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(`创建 PR 失败: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并 Pull Request
|
||||
*
|
||||
* @param {number} pullNumber - PR 编号
|
||||
* @param {Object} options - 合并选项
|
||||
* @returns {Promise<Object>} 合并后的 PR 信息
|
||||
*/
|
||||
async mergePullRequest(pullNumber, options = {}) {
|
||||
const { owner, repo } = this.repoInfo
|
||||
const { deleteBranch = true, mergeStyle = 'merge' } = options
|
||||
|
||||
try {
|
||||
const result = await mcp__gitea__pull_request_write({
|
||||
method: 'merge',
|
||||
owner,
|
||||
repo,
|
||||
pull_number: pullNumber,
|
||||
delete_branch_after_merge: deleteBranch,
|
||||
merge_style: mergeStyle
|
||||
})
|
||||
|
||||
return result
|
||||
} catch (error) {
|
||||
throw new Error(`合并 PR 失败: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Pull Request
|
||||
*
|
||||
* @param {number} pullNumber - PR 编号
|
||||
* @returns {Promise<Object>} PR 信息
|
||||
*/
|
||||
async getPullRequest(pullNumber) {
|
||||
const { owner, repo } = this.repoInfo
|
||||
|
||||
try {
|
||||
const pr = await mcp__gitea__pull_request_read({
|
||||
method: 'get',
|
||||
owner,
|
||||
repo,
|
||||
pull_number: pullNumber
|
||||
})
|
||||
|
||||
return pr
|
||||
} catch (error) {
|
||||
throw new Error(`获取 PR 失败: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列出 Pull Request
|
||||
*
|
||||
* @param {Object} options - 查询选项
|
||||
* @returns {Promise<Array>} PR 列表
|
||||
*/
|
||||
async listPullRequests(options = {}) {
|
||||
const { owner, repo } = this.repoInfo
|
||||
const { state = 'open' } = options
|
||||
|
||||
try {
|
||||
const prs = await mcp__gitea__list_pull_requests({
|
||||
owner,
|
||||
repo,
|
||||
state
|
||||
})
|
||||
|
||||
return prs
|
||||
} catch (error) {
|
||||
throw new Error(`列出 PR 失败: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建或更新文件
|
||||
*
|
||||
* @param {Object} options - 文件选项
|
||||
* @param {string} options.path - 文件路径
|
||||
* @param {string} options.content - 文件内容
|
||||
* @param {string} options.message - Commit 消息
|
||||
* @param {string} options.branch - 分支名称
|
||||
* @param {string} options.sha - 文件 SHA(更新时需要)
|
||||
* @returns {Promise<Object>} 文件信息
|
||||
*/
|
||||
async createOrUpdateFile(options) {
|
||||
const { path: filePath, content, message, branch, sha } = options
|
||||
const { owner, repo } = this.repoInfo
|
||||
|
||||
try {
|
||||
const result = await mcp__gitea__create_or_update_file({
|
||||
owner,
|
||||
repo,
|
||||
path: filePath,
|
||||
content: Buffer.from(content).toString('base64'),
|
||||
message,
|
||||
branch_name: branch,
|
||||
sha
|
||||
})
|
||||
|
||||
return result
|
||||
} catch (error) {
|
||||
throw new Error(`创建/更新文件失败: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件内容
|
||||
*
|
||||
* @param {string} filePath - 文件路径
|
||||
* @param {string} ref - 分支或 commit
|
||||
* @returns {Promise<Object>} 文件内容
|
||||
*/
|
||||
async getFileContents(filePath, ref = null) {
|
||||
const { owner, repo, defaultBranch } = this.repoInfo
|
||||
const targetRef = ref || defaultBranch
|
||||
|
||||
try {
|
||||
const file = await mcp__gitea__get_file_contents({
|
||||
owner,
|
||||
repo,
|
||||
path: filePath,
|
||||
ref: targetRef
|
||||
})
|
||||
|
||||
return file
|
||||
} catch (error) {
|
||||
throw new Error(`获取文件内容失败: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列出提交
|
||||
*
|
||||
* @param {Object} options - 查询选项
|
||||
* @returns {Promise<Array>} 提交列表
|
||||
*/
|
||||
async listCommits(options = {}) {
|
||||
const { owner, repo } = this.repoInfo
|
||||
const { sha, path } = options
|
||||
|
||||
try {
|
||||
const commits = await mcp__gitea__list_commits({
|
||||
owner,
|
||||
repo,
|
||||
sha,
|
||||
path
|
||||
})
|
||||
|
||||
return commits
|
||||
} catch (error) {
|
||||
throw new Error(`列出提交失败: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 带重试的操作
|
||||
*
|
||||
* @param {Function} operation - 操作函数
|
||||
* @param {number} maxRetries - 最大重试次数
|
||||
* @returns {Promise<any>} 操作结果
|
||||
*/
|
||||
async withRetry(operation, maxRetries = 3) {
|
||||
let lastError
|
||||
for (let i = 0; i < maxRetries; i++) {
|
||||
try {
|
||||
return await operation()
|
||||
} catch (error) {
|
||||
lastError = error
|
||||
console.warn(`操作失败,重试 ${i + 1}/${maxRetries}: ${error.message}`)
|
||||
// 等待后重试
|
||||
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)))
|
||||
}
|
||||
}
|
||||
throw lastError
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建适配器实例
|
||||
*/
|
||||
export function createGiteaAdapter() {
|
||||
return new GiteaMCPAdapter()
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出单例
|
||||
*/
|
||||
export default createGiteaAdapter()
|
||||
@@ -0,0 +1,249 @@
|
||||
/**
|
||||
* Gitea 规则生成器
|
||||
*
|
||||
* 根据配置文件动态生成 Gitea 协作规则
|
||||
*/
|
||||
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
/**
|
||||
* 读取配置文件
|
||||
*/
|
||||
function loadConfig() {
|
||||
const configPath = path.join(process.cwd(), '.claude', 'gitea-config.json')
|
||||
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'))
|
||||
return config
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 Gitea URL
|
||||
*/
|
||||
function getGiteaUrl(config) {
|
||||
const { baseUrl, owner, repo } = config.gitea
|
||||
return `${baseUrl}/${owner}/${repo}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 Gitea 规则字符串
|
||||
*/
|
||||
export function generateGiteaRules(config = null) {
|
||||
if (!config) {
|
||||
config = loadConfig()
|
||||
}
|
||||
|
||||
const { baseUrl, owner, repo, defaultBranch } = config.gitea
|
||||
const { branchNaming, commitNaming, prTemplate } = config.rules
|
||||
const { checklist, approval } = config.review
|
||||
|
||||
return `
|
||||
# Gitea 协作规则
|
||||
|
||||
## 仓库信息
|
||||
- **Base URL**: ${baseUrl}
|
||||
- **Owner**: ${owner}
|
||||
- **Repository**: ${repo}
|
||||
- **URL**: ${getGiteaUrl(config)}
|
||||
- **主分支**: ${defaultBranch}
|
||||
|
||||
## 分支命名规则
|
||||
|
||||
| 类型 | 格式 | 示例 |
|
||||
|------|------|------|
|
||||
| 功能开发 | ${branchNaming.feature} | feature/login-api |
|
||||
| 问题修复 | ${branchNaming.fix} | fix/123-auth-error |
|
||||
| 紧急修复 | ${branchNaming.hotfix} | hotfix/security-patch |
|
||||
|
||||
## Commit 命名规则
|
||||
|
||||
| 类型 | 格式 | 示例 |
|
||||
|------|------|------|
|
||||
| 功能 | ${commitNaming.feature} | feat: 添加用户登录 |
|
||||
| 修复 | ${commitNaming.fix} | fix: 修复认证 bug |
|
||||
| 重构 | ${commitNaming.refactor} | refactor: 优化 API 结构 |
|
||||
| 文档 | ${commitNaming.docs} | docs: 更新 API 文档 |
|
||||
| 测试 | ${commitNaming.test} | test: 添加认证测试 |
|
||||
|
||||
## Execute Sub Agent 工作流程
|
||||
|
||||
### 1. 准备阶段
|
||||
\`\`\`bash
|
||||
# Clone 仓库
|
||||
git clone ${getGiteaUrl(config)}.git
|
||||
cd ${repo}
|
||||
|
||||
# 创建功能分支
|
||||
git checkout -b ${branchNaming.feature}
|
||||
\`\`\`
|
||||
|
||||
### 2. 实现阶段
|
||||
- 根据任务要求实现代码
|
||||
- 编写单元测试
|
||||
- 本地测试验证
|
||||
|
||||
### 3. 提交阶段
|
||||
\`\`\`bash
|
||||
git add .
|
||||
git commit -m "${commitNaming.feature}"
|
||||
git push -u origin ${branchNaming.feature}
|
||||
\`\`\`
|
||||
|
||||
### 4. PR 阶段
|
||||
- 在 Gitea 上创建 Pull Request
|
||||
- 标题格式: \`${prTemplate.title}\`
|
||||
- 描述模板:
|
||||
\`\`\`
|
||||
${prTemplate.description}
|
||||
\`\`\`
|
||||
|
||||
## Review Sub Agent 工作流程
|
||||
|
||||
### 1. 审查准备
|
||||
- 阅读 PR 代码变更
|
||||
- 检查以下项目:
|
||||
${checklist.map((item, i) => ` ${i + 1}. ${item}`).join('\n')}
|
||||
|
||||
### 2. 添加 Review
|
||||
- 在 Gitea PR 页面添加 Review 评论
|
||||
- 标注有问题的代码行
|
||||
- 提供具体的修改建议
|
||||
- 返回 Review 结果:
|
||||
|
||||
\`\`\`json
|
||||
{
|
||||
"passed": true|false,
|
||||
"findings": ["问题1", "问题2"],
|
||||
"suggestions": ["建议1", "建议2"],
|
||||
"approval": "${approval}"
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
## Test Sub Agent 工作流程
|
||||
|
||||
### 1. 测试准备
|
||||
- 读取 PR 代码
|
||||
- 理解功能需求
|
||||
|
||||
### 2. 编写测试
|
||||
- 单元测试
|
||||
- 集成测试
|
||||
- E2E 测试(如需要)
|
||||
|
||||
### 3. 执行测试
|
||||
\`\`\`bash
|
||||
npm test
|
||||
# 或
|
||||
pytest
|
||||
\`\`\`
|
||||
|
||||
### 4. 报告结果
|
||||
- 返回测试结果:
|
||||
|
||||
\`\`\`json
|
||||
{
|
||||
"passed": true|false,
|
||||
"coverage": "85%",
|
||||
"failures": [],
|
||||
"summary": "测试结果摘要"
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
## 修复工作流程
|
||||
|
||||
### 1. 接收 Review
|
||||
- 阅读 PR 中的 Review 评论
|
||||
- 理解问题所在
|
||||
|
||||
### 2. 修复问题
|
||||
\`\`\`bash
|
||||
# 在 PR 分支上修复
|
||||
git checkout ${branchNaming.feature}
|
||||
# 进行修复
|
||||
\`\`\`
|
||||
|
||||
### 3. 提交修复
|
||||
\`\`\`bash
|
||||
git add .
|
||||
git commit -m "${commitNaming.fix}"
|
||||
git push
|
||||
\`\`\`
|
||||
|
||||
### 4. 回复 Review
|
||||
- 在 PR 中回复 Review 评论
|
||||
- 说明修复内容
|
||||
|
||||
## 所有 Agent 共享规则
|
||||
|
||||
### 通过 Gitea 读取上下文
|
||||
- Commit 历史 = 上下文历史
|
||||
- PR 变更 = 代码变更
|
||||
- Review 评论 = 审查意见
|
||||
- Issues = 任务记录
|
||||
|
||||
### 通过 Gitea 传递结果
|
||||
- Push 代码 = 传递实现结果
|
||||
- 创建 PR = 请求审查
|
||||
- Review 评论 = 传递审查结果
|
||||
- 合并 PR = 验收完成
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **分支隔离**: 每个任务在独立分支上开发
|
||||
2. **提交清晰**: Commit 信息要清晰描述变更
|
||||
3. **PR 完整**: PR 描述要包含任务、方案、测试
|
||||
4. **Review 及时**: 及时响应 Review 评论
|
||||
5. **测试充分**: 确保测试覆盖充分
|
||||
|
||||
## 配置来源
|
||||
|
||||
本规则由以下配置生成:
|
||||
- 配置文件: .claude/gitea-config.json
|
||||
- 生成时间: ${new Date().toISOString()}
|
||||
`
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取仓库 URL
|
||||
*/
|
||||
export function getRepoUrl(config = null) {
|
||||
if (!config) {
|
||||
config = loadConfig()
|
||||
}
|
||||
return getGiteaUrl(config)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分支名称
|
||||
*/
|
||||
export function getBranchName(type, name, config = null) {
|
||||
if (!config) {
|
||||
config = loadConfig()
|
||||
}
|
||||
const template = config.rules.branchNaming[type] || 'feature/{name}'
|
||||
return template.replace('{name}', name).replace('{task-name}', name)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Commit 模板
|
||||
*/
|
||||
export function getCommitTemplate(type, config = null) {
|
||||
if (!config) {
|
||||
config = loadConfig()
|
||||
}
|
||||
return config.rules.commitNaming[type] || '{description}'
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 PR 模板
|
||||
*/
|
||||
export function getPrTemplate(config = null) {
|
||||
if (!config) {
|
||||
config = loadConfig()
|
||||
}
|
||||
return config.rules.prTemplate
|
||||
}
|
||||
|
||||
// 导出默认函数
|
||||
export default function generateRules(config = null) {
|
||||
return generateGiteaRules(config)
|
||||
}
|
||||
@@ -0,0 +1,410 @@
|
||||
/**
|
||||
* Linus 三问决策框架
|
||||
*
|
||||
* 实现工程审慎决策逻辑
|
||||
* 来源: Linus Torvalds "Talk Like a Kernel Developer"
|
||||
*/
|
||||
|
||||
/**
|
||||
* 三问枚举
|
||||
*/
|
||||
export const QuestionType = {
|
||||
REAL_PROBLEM: '这是现实问题还是想象问题?',
|
||||
NEEDS_SOLUTION: '这个问题真的需要解决吗?',
|
||||
SOLUTION_VIABLE: '这个方案真的能解决问题吗?'
|
||||
}
|
||||
|
||||
/**
|
||||
* Linus 三问决策器类
|
||||
*/
|
||||
export class LinusTriadDecision {
|
||||
constructor() {
|
||||
this.questions = [
|
||||
QuestionType.REAL_PROBLEM,
|
||||
QuestionType.NEEDS_SOLUTION,
|
||||
QuestionType.SOLUTION_VIABLE
|
||||
]
|
||||
this.answers = []
|
||||
this.reasoning = []
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行完整的 Linus 三问
|
||||
*
|
||||
* @param {string} taskDescription - 任务描述
|
||||
* @param {Object} options - 选项
|
||||
* @returns {Promise<Object>} 决策结果
|
||||
*/
|
||||
async ask(taskDescription, options = {}) {
|
||||
const { interactive = false, context = null } = options
|
||||
|
||||
// 清空之前的答案
|
||||
this.answers = []
|
||||
this.reasoning = []
|
||||
|
||||
log('🤔 开始 Linus 三问决策...')
|
||||
log(`📋 任务: ${taskDescription}`)
|
||||
|
||||
// 第一问:现实问题还是想象问题?
|
||||
const q1Result = await this.isRealProblem(taskDescription, context)
|
||||
this.answers.push(q1Result.answer)
|
||||
this.reasoning.push(q1Result.reasoning)
|
||||
|
||||
if (!q1Result.answer) {
|
||||
log('❌ 第一问未通过:这不是现实问题')
|
||||
return this.createResult(false, '第一问未通过:这不是现实问题', q1Result.reasoning)
|
||||
}
|
||||
log('✅ 第一问通过:这是现实问题')
|
||||
|
||||
// 第二问:这个问题真的需要解决吗?
|
||||
const q2Result = await this.needsSolution(taskDescription, context)
|
||||
this.answers.push(q2Result.answer)
|
||||
this.reasoning.push(q2Result.reasoning)
|
||||
|
||||
if (!q2Result.answer) {
|
||||
log('❌ 第二问未通过:这个问题不需要解决')
|
||||
return this.createResult(false, '第二问未通过:这个问题不需要解决', [
|
||||
this.reasoning[0],
|
||||
q2Result.reasoning
|
||||
])
|
||||
}
|
||||
log('✅ 第二问通过:这个问题需要解决')
|
||||
|
||||
// 第三问:这个方案真的能解决问题吗?
|
||||
const q3Result = await this.solutionViable(taskDescription, context)
|
||||
this.answers.push(q3Result.answer)
|
||||
this.reasoning.push(q3Result.reasoning)
|
||||
|
||||
if (!q3Result.answer) {
|
||||
log('❌ 第三问未通过:这个方案不能解决问题')
|
||||
return this.createResult(false, '第三问未通过:这个方案不能解决问题', [
|
||||
this.reasoning[0],
|
||||
this.reasoning[1],
|
||||
q3Result.reasoning
|
||||
])
|
||||
}
|
||||
log('✅ 第三问通过:这个方案能解决问题')
|
||||
|
||||
log('✅ Linus 三问全部通过!')
|
||||
|
||||
return this.createResult(true, 'Linus 三问全部通过', this.reasoning)
|
||||
}
|
||||
|
||||
/**
|
||||
* 第一问:这是现实问题还是想象问题?
|
||||
*
|
||||
* 拒绝条件:
|
||||
* - "可能需要"、"也许将来"
|
||||
* - 纯粹的假设性场景
|
||||
* - "以防万一"
|
||||
*/
|
||||
async isRealProblem(taskDescription, context) {
|
||||
log(`\n📌 第一问:${QuestionType.REAL_PROBLEM}`)
|
||||
|
||||
const answer = await this.evaluateQuestion(taskDescription, context, {
|
||||
positiveIndicators: [
|
||||
'用户反馈',
|
||||
'生产问题',
|
||||
'线上错误',
|
||||
'性能瓶颈',
|
||||
'安全漏洞',
|
||||
'bug',
|
||||
'错误',
|
||||
'失败',
|
||||
'崩溃',
|
||||
'无法',
|
||||
'必须',
|
||||
'紧急',
|
||||
'关键'
|
||||
],
|
||||
negativeIndicators: [
|
||||
'可能需要',
|
||||
'也许将来',
|
||||
'以防万一',
|
||||
'考虑未来',
|
||||
'如果发生',
|
||||
'假设',
|
||||
'理论上',
|
||||
'或许',
|
||||
'可能'
|
||||
],
|
||||
analysisPrompt: `判断以下任务是否是现实问题:
|
||||
"${taskDescription}"
|
||||
|
||||
回答 JSON:
|
||||
{
|
||||
"isRealProblem": true|false,
|
||||
"reasoning": "判断理由",
|
||||
"evidence": ["证据1", "证据2"],
|
||||
"verdict": "这是现实问题/这是想象问题"
|
||||
}`
|
||||
})
|
||||
|
||||
return {
|
||||
answer: answer.isRealProblem,
|
||||
reasoning: answer.reasoning,
|
||||
evidence: answer.evidence,
|
||||
verdict: answer.verdict
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 第二问:这个问题真的需要解决吗?
|
||||
*
|
||||
* 拒绝条件:
|
||||
* - 边缘场景
|
||||
* - 伪需求
|
||||
* - 性价比极低
|
||||
*/
|
||||
async needsSolution(taskDescription, context) {
|
||||
log(`\n📌 第二问:${QuestionType.NEEDS_SOLUTION}`)
|
||||
|
||||
const answer = await this.evaluateQuestion(taskDescription, context, {
|
||||
positiveIndicators: [
|
||||
'影响用户体验',
|
||||
'影响性能',
|
||||
'影响安全',
|
||||
'影响稳定性',
|
||||
'阻塞功能',
|
||||
'影响核心',
|
||||
'高频',
|
||||
'重要',
|
||||
'必要',
|
||||
'必须'
|
||||
],
|
||||
negativeIndicators: [
|
||||
'边缘',
|
||||
'小众',
|
||||
'罕见',
|
||||
'偶尔',
|
||||
'理论上',
|
||||
'可以接受',
|
||||
'不是必需',
|
||||
'可选项',
|
||||
'优化项',
|
||||
'锦上添花'
|
||||
],
|
||||
analysisPrompt: `判断以下问题是否真的需要解决:
|
||||
"${taskDescription}"
|
||||
|
||||
回答 JSON:
|
||||
{
|
||||
"needsSolution": true|false,
|
||||
"reasoning": "判断理由",
|
||||
"impact": "高/中/低",
|
||||
"verdict": "这个问题需要解决/这个问题不需要解决"
|
||||
}`
|
||||
})
|
||||
|
||||
return {
|
||||
answer: answer.needsSolution,
|
||||
reasoning: answer.reasoning,
|
||||
impact: answer.impact,
|
||||
verdict: answer.verdict
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 第三问:这个方案真的能解决问题吗?
|
||||
*
|
||||
* 拒绝条件:
|
||||
* - 理论上可行但无验证
|
||||
* - 缺少实施路径
|
||||
* - 技术栈不匹配
|
||||
*/
|
||||
async solutionViable(taskDescription, context) {
|
||||
log(`\n📌 第三问:${QuestionType.SOLUTION_VIABLE}`)
|
||||
|
||||
const answer = await this.evaluateQuestion(taskDescription, context, {
|
||||
positiveIndicators: [
|
||||
'明确方案',
|
||||
'具体步骤',
|
||||
'已有先例',
|
||||
'可验证',
|
||||
'可测试',
|
||||
'有计划',
|
||||
'有路径',
|
||||
'可行'
|
||||
],
|
||||
negativeIndicators: [
|
||||
'理论上',
|
||||
'应该可以',
|
||||
'可能需要',
|
||||
'待研究',
|
||||
'不确定',
|
||||
'猜测',
|
||||
'假设',
|
||||
'无从验证'
|
||||
],
|
||||
analysisPrompt: `判断以下方案是否真的能解决问题:
|
||||
"${taskDescription}"
|
||||
|
||||
如果有具体方案,请评估其可行性。如果没有方案,请判断是否可以制定有效方案。
|
||||
|
||||
回答 JSON:
|
||||
{
|
||||
"solutionViable": true|false,
|
||||
"reasoning": "判断理由",
|
||||
"hasConcretePlan": true|false,
|
||||
"verdict": "这个方案能解决问题/这个方案不能解决问题"
|
||||
}`
|
||||
})
|
||||
|
||||
return {
|
||||
answer: answer.solutionViable,
|
||||
reasoning: answer.reasoning,
|
||||
hasConcretePlan: answer.hasConcretePlan,
|
||||
verdict: answer.verdict
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 评估问题(使用 Agent 进行分析)
|
||||
*/
|
||||
async evaluateQuestion(taskDescription, context, config) {
|
||||
// 如果有上下文信息,使用它
|
||||
const fullContext = context ? `上下文: ${context}\n` : ''
|
||||
|
||||
// 使用 Plan Agent 进行分析
|
||||
try {
|
||||
const analysis = await agent({
|
||||
subagent_type: 'Plan',
|
||||
prompt: `${fullContext}${config.analysisPrompt}`,
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
isRealProblem: { type: 'boolean' },
|
||||
needsSolution: { type: 'boolean' },
|
||||
solutionViable: { type: 'boolean' },
|
||||
reasoning: { type: 'string' },
|
||||
evidence: { type: 'array', items: { type: 'string' } },
|
||||
impact: { type: 'string' },
|
||||
hasConcretePlan: { type: 'boolean' },
|
||||
verdict: { type: 'string' }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return analysis
|
||||
} catch (error) {
|
||||
log(`⚠️ Agent 分析失败: ${error.message}`)
|
||||
// 回退到简单关键词检测
|
||||
return this.fallbackEvaluation(taskDescription, config)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 回退评估(基于关键词)
|
||||
*/
|
||||
fallbackEvaluation(taskDescription, config) {
|
||||
const text = taskDescription.toLowerCase()
|
||||
const { positiveIndicators, negativeIndicators } = config
|
||||
|
||||
let positiveScore = 0
|
||||
let negativeScore = 0
|
||||
|
||||
for (const indicator of positiveIndicators) {
|
||||
if (text.includes(indicator.toLowerCase())) {
|
||||
positiveScore++
|
||||
}
|
||||
}
|
||||
|
||||
for (const indicator of negativeIndicators) {
|
||||
if (text.includes(indicator.toLowerCase())) {
|
||||
negativeScore++
|
||||
}
|
||||
}
|
||||
|
||||
const answer = positiveScore > negativeScore
|
||||
const reasoning = `基于关键词检测:正面指标 ${positiveScore} 个,负面指标 ${negativeScore} 个`
|
||||
|
||||
return {
|
||||
isRealProblem: answer,
|
||||
needsSolution: answer,
|
||||
solutionViable: answer,
|
||||
reasoning,
|
||||
verdict: answer ? '通过关键词检测' : '未通过关键词检测'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建决策结果
|
||||
*/
|
||||
createResult(passed, message, reasoning) {
|
||||
return {
|
||||
passed,
|
||||
message,
|
||||
reasoning: Array.isArray(reasoning) ? reasoning : [reasoning],
|
||||
answers: this.answers,
|
||||
timestamp: new Date().toISOString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 快速函数:执行 Linus 三问
|
||||
*
|
||||
* @param {string} taskDescription - 任务描述
|
||||
* @param {Object} options - 选项
|
||||
* @returns {Promise<Object>} 决策结果
|
||||
*/
|
||||
export async function askLinusTriad(taskDescription, options = {}) {
|
||||
const decision = new LinusTriadDecision()
|
||||
return await decision.ask(taskDescription, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查任务是否通过 Linus 三问
|
||||
*
|
||||
* @param {string} taskDescription - 任务描述
|
||||
* @returns {Promise<boolean>} 是否通过
|
||||
*/
|
||||
export async function passesLinusTriad(taskDescription) {
|
||||
const result = await askLinusTriad(taskDescription)
|
||||
return result.passed
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成拒绝响应
|
||||
*
|
||||
* @param {Object} decisionResult - 决策结果
|
||||
* @returns {string} 拒绝消息
|
||||
*/
|
||||
export function generateRejectionMessage(decisionResult) {
|
||||
let message = `## ❌ 任务未通过 Linus 三问决策\n\n`
|
||||
message += `**原因**: ${decisionResult.message}\n\n`
|
||||
message += `### 决策过程\n\n`
|
||||
|
||||
for (let i = 0; i < decisionResult.reasoning.length; i++) {
|
||||
message += `**${i + 1}. ${decisionResult.reasoning[i]}**\n\n`
|
||||
}
|
||||
|
||||
message += `### 建议\n\n`
|
||||
message += `- 请重新审视任务需求\n`
|
||||
message += `- 确保这是需要解决的现实问题\n`
|
||||
message += `- 提供明确的解决方案\n`
|
||||
message += `- 如有疑问,请使用 deep-interview 进行需求澄清\n\n`
|
||||
|
||||
message += `---\n`
|
||||
message += `**决策时间**: ${decisionResult.timestamp}\n`
|
||||
|
||||
return message
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助函数:日志输出
|
||||
*/
|
||||
function log(message) {
|
||||
console.log(`[LinusTriad] ${message}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出
|
||||
*/
|
||||
export default {
|
||||
LinusTriadDecision,
|
||||
askLinusTriad,
|
||||
passesLinusTriad,
|
||||
generateRejectionMessage,
|
||||
QuestionType
|
||||
}
|
||||
@@ -0,0 +1,302 @@
|
||||
/**
|
||||
* 需求追踪模块
|
||||
*
|
||||
* 追踪需求到设计和编码的映射,生成一致性检查报告
|
||||
*/
|
||||
|
||||
/**
|
||||
* 需求追踪器类
|
||||
*/
|
||||
export class RequirementTracker {
|
||||
constructor() {
|
||||
this.requirements = new Map() // id -> requirement
|
||||
this.designMapping = new Map() // requirementId -> designItems
|
||||
this.codeMapping = new Map() // requirementId -> codeItems
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加需求
|
||||
*/
|
||||
addRequirement(id, requirement) {
|
||||
this.requirements.set(id, {
|
||||
id,
|
||||
description: typeof requirement === 'string' ? requirement : requirement.description || requirement.text || JSON.stringify(requirement),
|
||||
status: 'pending',
|
||||
...requirement
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加设计映射
|
||||
*/
|
||||
addDesignMapping(requirementId, designItems) {
|
||||
this.designMapping.set(requirementId, Array.isArray(designItems) ? designItems : [designItems])
|
||||
|
||||
// 更新需求状态
|
||||
const req = this.requirements.get(requirementId)
|
||||
if (req) {
|
||||
req.status = 'designed'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加编码映射
|
||||
*/
|
||||
addCodeMapping(requirementId, codeItems) {
|
||||
this.codeMapping.set(requirementId, Array.isArray(codeItems) ? codeItems : [codeItems])
|
||||
|
||||
// 更新需求状态
|
||||
const req = this.requirements.get(requirementId)
|
||||
if (req) {
|
||||
req.status = 'implemented'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取需求
|
||||
*/
|
||||
getRequirement(id) {
|
||||
return this.requirements.get(id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有需求
|
||||
*/
|
||||
getAllRequirements() {
|
||||
return Array.from(this.requirements.values())
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取需求的设计映射
|
||||
*/
|
||||
getDesignMapping(requirementId) {
|
||||
return this.designMapping.get(requirementId) || []
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取需求的编码映射
|
||||
*/
|
||||
getCodeMapping(requirementId) {
|
||||
return this.codeMapping.get(requirementId) || []
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查需求的完整性
|
||||
*/
|
||||
checkCompleteness(requirementId) {
|
||||
const req = this.getRequirement(requirementId)
|
||||
if (!req) {
|
||||
return { complete: false, reason: '需求不存在' }
|
||||
}
|
||||
|
||||
const hasDesign = this.designMapping.has(requirementId)
|
||||
const hasCode = this.codeMapping.has(requirementId)
|
||||
|
||||
if (!hasDesign) {
|
||||
return { complete: false, reason: '缺少设计映射' }
|
||||
}
|
||||
|
||||
if (!hasCode) {
|
||||
return { complete: false, reason: '缺少编码映射' }
|
||||
}
|
||||
|
||||
return { complete: true }
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成追踪报告
|
||||
*/
|
||||
generateReport() {
|
||||
const requirements = this.getAllRequirements()
|
||||
const report = {
|
||||
total: requirements.length,
|
||||
pending: 0,
|
||||
designed: 0,
|
||||
implemented: 0,
|
||||
items: []
|
||||
}
|
||||
|
||||
for (const req of requirements) {
|
||||
const completeness = this.checkCompleteness(req.id)
|
||||
const designItems = this.getDesignMapping(req.id)
|
||||
const codeItems = this.getCodeMapping(req.id)
|
||||
|
||||
if (req.status === 'pending') {
|
||||
report.pending++
|
||||
} else if (req.status === 'designed') {
|
||||
report.designed++
|
||||
} else if (req.status === 'implemented') {
|
||||
report.implemented++
|
||||
}
|
||||
|
||||
report.items.push({
|
||||
id: req.id,
|
||||
description: req.description,
|
||||
status: req.status,
|
||||
complete: completeness.complete,
|
||||
designCount: designItems.length,
|
||||
codeCount: codeItems.length,
|
||||
designItems,
|
||||
codeItems
|
||||
})
|
||||
}
|
||||
|
||||
return report
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出为 Markdown 格式
|
||||
*/
|
||||
toMarkdown() {
|
||||
const report = this.generateReport()
|
||||
let md = '# 需求追踪报告\n\n'
|
||||
md += `## 概述\n\n`
|
||||
md += `- 总需求数: ${report.total}\n`
|
||||
md += `- 待处理: ${report.pending}\n`
|
||||
md += `- 已设计: ${report.designed}\n`
|
||||
md += `- 已实现: ${report.implemented}\n\n`
|
||||
|
||||
md += `## 详细追踪\n\n`
|
||||
|
||||
for (const item of report.items) {
|
||||
md += `### ${item.id}: ${item.description}\n\n`
|
||||
md += `- **状态**: ${item.status}\n`
|
||||
md += `- **完整**: ${item.complete ? '✅' : '❌'}\n`
|
||||
md += `- **设计映射**: ${item.designCount} 项\n`
|
||||
md += `- **编码映射**: ${item.codeCount} 项\n\n`
|
||||
|
||||
if (item.designItems.length > 0) {
|
||||
md += `#### 设计映射\n\n`
|
||||
for (const design of item.designItems) {
|
||||
md += `- ${typeof design === 'string' ? design : JSON.stringify(design)}\n`
|
||||
}
|
||||
md += `\n`
|
||||
}
|
||||
|
||||
if (item.codeItems.length > 0) {
|
||||
md += `#### 编码映射\n\n`
|
||||
for (const code of item.codeItems) {
|
||||
md += `- ${typeof code === 'string' ? code : JSON.stringify(code)}\n`
|
||||
}
|
||||
md += `\n`
|
||||
}
|
||||
}
|
||||
|
||||
return md
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建需求追踪器
|
||||
*/
|
||||
export function createRequirementTracker() {
|
||||
return new RequirementTracker()
|
||||
}
|
||||
|
||||
/**
|
||||
* 从一致性检查结果生成追踪数据
|
||||
*
|
||||
* @param {Object} checkResult - 一致性检查结果
|
||||
* @returns {Object} 追踪数据
|
||||
*/
|
||||
export function extractTrackingData(checkResult) {
|
||||
const tracker = new RequirementTracker()
|
||||
|
||||
// 从需求→设计检查中提取需求
|
||||
if (checkResult.requirementDesign) {
|
||||
for (const item of checkResult.requirementDesign.items) {
|
||||
const id = item.check.replace('需求 ', '')
|
||||
tracker.addRequirement(id, item.expected)
|
||||
if (item.passed) {
|
||||
tracker.addDesignMapping(id, [item.actual])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 从需求→编码检查中提取编码映射
|
||||
if (checkResult.requirementCode) {
|
||||
for (const item of checkResult.requirementCode.items) {
|
||||
const id = item.check.replace('需求 ', '')
|
||||
if (item.passed) {
|
||||
tracker.addCodeMapping(id, [item.actual])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tracker.generateReport()
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成一致性检查报告
|
||||
*
|
||||
* @param {Object} checkResult - 一致性检查结果
|
||||
* @returns {string} Markdown 报告
|
||||
*/
|
||||
export function generateConsistencyReport(checkResult) {
|
||||
let md = '# 三向一致性检查报告\n\n'
|
||||
|
||||
// 概述
|
||||
md += `## 概述\n\n`
|
||||
md += `- **总体结果**: ${checkResult.allPassed ? '✅ 通过' : '❌ 未通过'}\n`
|
||||
md += `- **需求→设计**: ${checkResult.requirementDesign.passed ? '✅ 通过' : '❌ 未通过'}\n`
|
||||
md += `- **设计→编码**: ${checkResult.designCode.passed ? '✅ 通过' : '❌ 未通过'}\n`
|
||||
md += `- **需求→编码**: ${checkResult.requirementCode.passed ? '✅ 通过' : '❌ 未通过'}\n\n`
|
||||
|
||||
// 需求→设计详细结果
|
||||
md += `## 1️⃣ 需求 → 设计\n\n`
|
||||
md += generateCheckTable(checkResult.requirementDesign.items)
|
||||
md += `\n${checkResult.requirementDesign.summary}\n\n`
|
||||
|
||||
// 设计→编码详细结果
|
||||
md += `## 2️⃣ 设计 → 编码\n\n`
|
||||
md += generateCheckTable(checkResult.designCode.items)
|
||||
md += `\n${checkResult.designCode.summary}\n\n`
|
||||
|
||||
// 需求→编码详细结果
|
||||
md += `## 3️⃣ 需求 → 编码\n\n`
|
||||
md += generateCheckTable(checkResult.requirementCode.items)
|
||||
md += `\n${checkResult.requirementCode.summary}\n\n`
|
||||
|
||||
// 偏差列表
|
||||
if (checkResult.deviations && checkResult.deviations.length > 0) {
|
||||
md += `## ⚠️ 发现的偏差\n\n`
|
||||
for (const deviation of checkResult.deviations) {
|
||||
md += `### ${deviation.type}\n\n`
|
||||
for (const issue of deviation.issues) {
|
||||
md += `- **${issue.check}**: ${issue.expected} ≠ ${issue.actual}\n`
|
||||
}
|
||||
md += `\n`
|
||||
}
|
||||
}
|
||||
|
||||
return md
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助函数:生成检查表格
|
||||
*/
|
||||
function generateCheckTable(items) {
|
||||
if (!items || items.length === 0) {
|
||||
return '无检查项\n'
|
||||
}
|
||||
|
||||
let table = '| 检查项 | 预期 | 实际 | 状态 |\n'
|
||||
table += '|--------|------|------|------|\n'
|
||||
|
||||
for (const item of items) {
|
||||
const status = item.passed ? '✅' : '❌'
|
||||
table += `| ${item.check} | ${item.expected} | ${item.actual} | ${status} |\n`
|
||||
}
|
||||
|
||||
return table
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出默认函数
|
||||
*/
|
||||
export default {
|
||||
RequirementTracker,
|
||||
createRequirementTracker,
|
||||
extractTrackingData,
|
||||
generateConsistencyReport
|
||||
}
|
||||
@@ -0,0 +1,420 @@
|
||||
/**
|
||||
* Superpowers 集成层
|
||||
*
|
||||
* 实现 Superpowers 五技能体系的调用集成
|
||||
*/
|
||||
|
||||
/**
|
||||
* Superpowers 五阶段枚举
|
||||
*/
|
||||
export const SuperpowersPhase = {
|
||||
WRITING_PLANS: 'writing-plans',
|
||||
EXECUTING_PLANS: 'executing-plans',
|
||||
REQUESTING_CODE_REVIEW: 'requesting-code-review',
|
||||
SYSTEMATIC_DEBUGGING: 'systematic-debugging',
|
||||
FINISHING_DEVELOPMENT: 'finishing-a-development-branch'
|
||||
}
|
||||
|
||||
/**
|
||||
* Superpowers 集成类
|
||||
*/
|
||||
export class SuperpowersIntegration {
|
||||
constructor() {
|
||||
this.currentPhase = null
|
||||
this.phaseHistory = []
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用 writing-plans
|
||||
*
|
||||
* @param {Object} context - 上下文信息
|
||||
* @returns {Promise<Object>} 规划结果
|
||||
*/
|
||||
async invokeWritingPlans(context) {
|
||||
this.setPhase(SuperpowersPhase.WRITING_PLANS)
|
||||
log('📝 调用 writing-plans...')
|
||||
|
||||
try {
|
||||
const prompt = this.generateWritingPlansPrompt(context)
|
||||
const plan = await this.callSkill('writing-plans', prompt, context)
|
||||
|
||||
log('✅ writing-plans 完成')
|
||||
return plan
|
||||
} catch (error) {
|
||||
log(`❌ writing-plans 失败: ${error.message}`)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用 executing-plans
|
||||
*
|
||||
* @param {Object} plan - 执行计划
|
||||
* @returns {Promise<Object>} 执行结果
|
||||
*/
|
||||
async invokeExecutingPlans(plan) {
|
||||
this.setPhase(SuperpowersPhase.EXECUTING_PLANS)
|
||||
log('⚡ 调用 executing-plans...')
|
||||
|
||||
try {
|
||||
const prompt = this.generateExecutingPlansPrompt(plan)
|
||||
const result = await this.callSkill('executing-plans', prompt, { plan })
|
||||
|
||||
log('✅ executing-plans 完成')
|
||||
return result
|
||||
} catch (error) {
|
||||
log(`❌ executing-plans 失败: ${error.message}`)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用 requesting-code-review
|
||||
*
|
||||
* @param {Object} code - 代码信息
|
||||
* @returns {Promise<Object>} 审查结果
|
||||
*/
|
||||
async invokeRequestingCodeReview(code) {
|
||||
this.setPhase(SuperpowersPhase.REQUESTING_CODE_REVIEW)
|
||||
log('🔍 调用 requesting-code-review...')
|
||||
|
||||
try {
|
||||
const prompt = this.generateCodeReviewPrompt(code)
|
||||
const review = await this.callSkill('requesting-code-review', prompt, { code })
|
||||
|
||||
log('✅ requesting-code-review 完成')
|
||||
return review
|
||||
} catch (error) {
|
||||
log(`❌ requesting-code-review 失败: ${error.message}`)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用 systematic-debugging
|
||||
*
|
||||
* @param {Object} issue - 问题信息
|
||||
* @returns {Promise<Object>} 调试结果
|
||||
*/
|
||||
async invokeSystematicDebugging(issue) {
|
||||
this.setPhase(SuperpowersPhase.SYSTEMATIC_DEBUGGING)
|
||||
log('🐛 调用 systematic-debugging...')
|
||||
|
||||
try {
|
||||
const prompt = this.generateDebuggingPrompt(issue)
|
||||
const result = await this.callSkill('systematic-debugging', prompt, { issue })
|
||||
|
||||
log('✅ systematic-debugging 完成')
|
||||
return result
|
||||
} catch (error) {
|
||||
log(`❌ systematic-debugging 失败: ${error.message}`)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用 finishing-a-development-branch
|
||||
*
|
||||
* @param {Object} context - 上下文信息
|
||||
* @returns {Promise<Object>} 完成结果
|
||||
*/
|
||||
async invokeFinishingDevelopment(context) {
|
||||
this.setPhase(SuperpowersPhase.FINISHING_DEVELOPMENT)
|
||||
log('🏁 调用 finishing-a-development-branch...')
|
||||
|
||||
try {
|
||||
const prompt = this.generateFinishingPrompt(context)
|
||||
const result = await this.callSkill('finishing-a-development-branch', prompt, context)
|
||||
|
||||
log('✅ finishing-a-development-branch 完成')
|
||||
return result
|
||||
} catch (error) {
|
||||
log(`❌ finishing-a-development-branch 失败: ${error.message}`)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行完整的五阶段工作流
|
||||
*
|
||||
* @param {Object} context - 初始上下文
|
||||
* @returns {Promise<Object>} 完整工作流结果
|
||||
*/
|
||||
async runFullWorkflow(context) {
|
||||
log('🚀 开始 Superpowers 五阶段工作流...')
|
||||
|
||||
const results = {}
|
||||
|
||||
try {
|
||||
// 阶段 1: 规划
|
||||
results.plan = await this.invokeWritingPlans(context)
|
||||
|
||||
// 阶段 2: 执行
|
||||
results.execution = await this.invokeExecutingPlans(results.plan)
|
||||
|
||||
// 阶段 3: 审查
|
||||
results.review = await this.invokeRequestingCodeReview(results.execution)
|
||||
|
||||
// 如果审查未通过,进入调试
|
||||
if (results.review && !results.review.passed) {
|
||||
log('⚠️ 审查未通过,进入调试阶段...')
|
||||
results.debugging = await this.invokeSystematicDebugging({
|
||||
review: results.review,
|
||||
execution: results.execution
|
||||
})
|
||||
}
|
||||
|
||||
// 阶段 5: 完成
|
||||
results.finishing = await this.invokeFinishingDevelopment({
|
||||
...context,
|
||||
...results
|
||||
})
|
||||
|
||||
log('✅ Superpowers 五阶段工作流完成')
|
||||
return results
|
||||
} catch (error) {
|
||||
log(`❌ 工作流中断: ${error.message}`)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前阶段
|
||||
*/
|
||||
setPhase(phase) {
|
||||
if (this.currentPhase) {
|
||||
this.phaseHistory.push(this.currentPhase)
|
||||
}
|
||||
this.currentPhase = phase
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前阶段
|
||||
*/
|
||||
getPhase() {
|
||||
return this.currentPhase
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取阶段历史
|
||||
*/
|
||||
getPhaseHistory() {
|
||||
return [...this.phaseHistory, this.currentPhase].filter(Boolean)
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 writing-plans 提示
|
||||
*/
|
||||
generateWritingPlansPrompt(context) {
|
||||
return `
|
||||
请编写一份综合实现计划,假设工程师对代码库零上下文。
|
||||
|
||||
## 上下文
|
||||
${this.formatContext(context)}
|
||||
|
||||
## 要求
|
||||
1. 任务背景和目标
|
||||
2. 技术方案选择
|
||||
3. 实施步骤
|
||||
4. 验收标准
|
||||
|
||||
请提供详细的实现计划。
|
||||
`
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 executing-plans 提示
|
||||
*/
|
||||
generateExecutingPlansPrompt(plan) {
|
||||
return `
|
||||
请执行以下实现计划:
|
||||
|
||||
## 计划
|
||||
${this.formatContext(plan)}
|
||||
|
||||
## 要求
|
||||
1. 按照计划实施
|
||||
2. 编写完整的单元测试
|
||||
3. 确保代码质量
|
||||
4. 提供实施结果
|
||||
|
||||
请开始执行。
|
||||
`
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成代码审查提示
|
||||
*/
|
||||
generateCodeReviewPrompt(code) {
|
||||
return `
|
||||
请审查以下代码:
|
||||
|
||||
## 代码信息
|
||||
${this.formatContext(code)}
|
||||
|
||||
## 审查维度
|
||||
1. 逻辑正确性和边界情况
|
||||
2. 安全漏洞
|
||||
3. 性能影响
|
||||
4. 测试覆盖率
|
||||
5. 错误处理
|
||||
|
||||
请提供详细的审查结果。
|
||||
`
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成调试提示
|
||||
*/
|
||||
generateDebuggingPrompt(issue) {
|
||||
return `
|
||||
请系统化调试以下问题:
|
||||
|
||||
## 问题描述
|
||||
${this.formatContext(issue)}
|
||||
|
||||
## 要求
|
||||
1. 系统化定位问题(而非随机尝试)
|
||||
2. 分析根本原因
|
||||
3. 设计验证方案
|
||||
4. 提供修复建议
|
||||
|
||||
请开始调试。
|
||||
`
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成完成提示
|
||||
*/
|
||||
generateFinishingPrompt(context) {
|
||||
return `
|
||||
请完成开发分支的收尾工作:
|
||||
|
||||
## 上下文
|
||||
${this.formatContext(context)}
|
||||
|
||||
## 要求
|
||||
1. 确认所有测试通过
|
||||
2. 验证代码质量
|
||||
3. 准备提交
|
||||
4. 清理临时文件
|
||||
|
||||
请完成收尾工作。
|
||||
`
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化上下文
|
||||
*/
|
||||
formatContext(context) {
|
||||
if (typeof context === 'string') {
|
||||
return context
|
||||
}
|
||||
return JSON.stringify(context, null, 2)
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用 Skill
|
||||
*/
|
||||
async callSkill(skillName, prompt, context) {
|
||||
try {
|
||||
// 使用 Skill 工具调用
|
||||
const result = await Skill({
|
||||
skill: skillName,
|
||||
args: JSON.stringify({ prompt, context })
|
||||
})
|
||||
|
||||
return result
|
||||
} catch (error) {
|
||||
// 如果 Skill 工具不可用,使用 Agent 作为回退
|
||||
log(`⚠️ Skill 工具不可用,使用 Agent 作为回退`)
|
||||
return await this.fallbackToAgent(skillName, prompt, context)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 回退到 Agent
|
||||
*/
|
||||
async fallbackToAgent(skillName, prompt, context) {
|
||||
const fullPrompt = `
|
||||
作为 ${skillName} 专家,执行以下任务:
|
||||
|
||||
${prompt}
|
||||
|
||||
请返回结构化的 JSON 结果。
|
||||
`
|
||||
|
||||
return await agent({
|
||||
subagent_type: 'general-purpose',
|
||||
prompt: fullPrompt
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 Superpowers 集成实例
|
||||
*/
|
||||
export function createSuperpowersIntegration() {
|
||||
return new SuperpowersIntegration()
|
||||
}
|
||||
|
||||
/**
|
||||
* 快速函数:调用 writing-plans
|
||||
*/
|
||||
export async function invokeWritingPlans(context) {
|
||||
const integration = createSuperpowersIntegration()
|
||||
return await integration.invokeWritingPlans(context)
|
||||
}
|
||||
|
||||
/**
|
||||
* 快速函数:调用 executing-plans
|
||||
*/
|
||||
export async function invokeExecutingPlans(plan) {
|
||||
const integration = createSuperpowersIntegration()
|
||||
return await integration.invokeExecutingPlans(plan)
|
||||
}
|
||||
|
||||
/**
|
||||
* 快速函数:调用 requesting-code-review
|
||||
*/
|
||||
export async function invokeRequestingCodeReview(code) {
|
||||
const integration = createSuperpowersIntegration()
|
||||
return await integration.invokeRequestingCodeReview(code)
|
||||
}
|
||||
|
||||
/**
|
||||
* 快速函数:调用 systematic-debugging
|
||||
*/
|
||||
export async function invokeSystematicDebugging(issue) {
|
||||
const integration = createSuperpowersIntegration()
|
||||
return await integration.invokeSystematicDebugging(issue)
|
||||
}
|
||||
|
||||
/**
|
||||
* 快速函数:调用 finishing-a-development-branch
|
||||
*/
|
||||
export async function invokeFinishingDevelopment(context) {
|
||||
const integration = createSuperpowersIntegration()
|
||||
return await integration.invokeFinishingDevelopment(context)
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助函数:日志输出
|
||||
*/
|
||||
function log(message) {
|
||||
console.log(`[Superpowers] ${message}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出
|
||||
*/
|
||||
export default {
|
||||
SuperpowersIntegration,
|
||||
createSuperpowersIntegration,
|
||||
invokeWritingPlans,
|
||||
invokeExecutingPlans,
|
||||
invokeRequestingCodeReview,
|
||||
invokeSystematicDebugging,
|
||||
invokeFinishingDevelopment,
|
||||
SuperpowersPhase
|
||||
}
|
||||
+376
@@ -0,0 +1,376 @@
|
||||
# sanguo_moziplus_v3 v0.4 部署指南
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1. 一键启动
|
||||
|
||||
```bash
|
||||
# 启动三实例 tmux 环境
|
||||
~/.claude/messages/sanguo/start-sanguo-env.sh
|
||||
|
||||
# 在各 pane 中分别执行:
|
||||
# pane 0: cd ~/.claude/projects/sanguo-main && claude
|
||||
# pane 1: cd ~/.claude/projects/sanguo-backend && claude
|
||||
# pane 2: cd ~/.claude/projects/sanguo-frontend && claude
|
||||
```
|
||||
|
||||
### 2. Web 访问 (可选)
|
||||
|
||||
```bash
|
||||
# 启动 Web 终端 (在另一个终端) - 带认证+可写
|
||||
ttyd -c sanguo:sanguo2024 -W -p 8088 tmux attach -t sanguo_dev
|
||||
|
||||
# 访问: http://YOUR_LAN_IP:8088
|
||||
# 用户名: sanguo
|
||||
# 密码: sanguo2024
|
||||
```
|
||||
|
||||
## 详细步骤
|
||||
|
||||
### 步骤 1: 验证环境
|
||||
|
||||
```bash
|
||||
~/.claude/messages/sanguo/test-sanguo-env.sh
|
||||
```
|
||||
|
||||
预期输出:
|
||||
```
|
||||
=== sanguo 环境测试 ===
|
||||
✅ 18/18 测试通过
|
||||
```
|
||||
|
||||
### 步骤 2: 启动 tmux 会话
|
||||
|
||||
```bash
|
||||
~/.claude/messages/sanguo/start-sanguo-env.sh
|
||||
```
|
||||
|
||||
这将创建:
|
||||
- pane 0: architect (架构师)
|
||||
- pane 1: backend (后端开发)
|
||||
- pane 2: frontend (前端开发)
|
||||
|
||||
### 步骤 3: 启动 Claude Code 实例
|
||||
|
||||
**在 pane 0 (architect)**:
|
||||
```bash
|
||||
cd ~/.claude/projects/sanguo-main
|
||||
claude
|
||||
```
|
||||
|
||||
**在 pane 1 (backend)**:
|
||||
```bash
|
||||
cd ~/.claude/projects/sanguo-backend
|
||||
claude
|
||||
```
|
||||
|
||||
**在 pane 2 (frontend)**:
|
||||
```bash
|
||||
cd ~/.claude/projects/sanguo-frontend
|
||||
claude
|
||||
```
|
||||
|
||||
### 步骤 4: 验证角色加载
|
||||
|
||||
在每个实例中,确认 CLAUDE.md 角色定义已加载:
|
||||
|
||||
```bash
|
||||
# 在 Claude Code 中输入
|
||||
角色定义
|
||||
```
|
||||
|
||||
应该看到对应角色的描述。
|
||||
|
||||
### 步骤 5: 测试 SendMessage
|
||||
|
||||
**在 architect (pane 0)**:
|
||||
```javascript
|
||||
SendMessage({
|
||||
to: "backend",
|
||||
summary: "测试消息",
|
||||
message: "这是一条测试消息,请确认收到。"
|
||||
})
|
||||
```
|
||||
|
||||
**在 backend (pane 1)**:
|
||||
应该收到通知并显示消息内容。
|
||||
|
||||
**在 backend (pane 1) 回复**:
|
||||
```javascript
|
||||
SendMessage({
|
||||
to: "main",
|
||||
summary: "收到测试",
|
||||
message: "已收到测试消息,backend 实例正常运行。"
|
||||
})
|
||||
```
|
||||
|
||||
## tmux 操作指南
|
||||
|
||||
### 快捷键
|
||||
|
||||
| 快捷键 | 功能 |
|
||||
|--------|------|
|
||||
| `Ctrl+B 0` | 切换到 pane 0 (architect) |
|
||||
| `Ctrl+B 1` | 切换到 pane 1 (backend) |
|
||||
| `Ctrl+B 2` | 切换到 pane 2 (frontend) |
|
||||
| `Ctrl+B o` | 在 pane 间循环切换 |
|
||||
| `Ctrl+B 方向键` | 切换到指定方向 pane |
|
||||
| `Ctrl+B d` | 分离会话 (detach) |
|
||||
| `Ctrl+B $` | 重命名当前窗口 |
|
||||
|
||||
### 会话管理
|
||||
|
||||
```bash
|
||||
# 查看所有会话
|
||||
tmux ls
|
||||
|
||||
# 附加到会话
|
||||
tmux attach-session -t sanguo_dev
|
||||
|
||||
# 杀死会话
|
||||
tmux kill-session -t sanguo_dev
|
||||
```
|
||||
|
||||
## Web 访问配置
|
||||
|
||||
### 启动 ttyd (带认证+可写)
|
||||
|
||||
```bash
|
||||
# 启动 Web 终端 - 带基本认证 + 可写模式
|
||||
ttyd -c sanguo:sanguo2024 -W -p 8088 tmux attach -t sanguo_dev
|
||||
|
||||
# 后台运行
|
||||
nohup ttyd -c sanguo:sanguo2024 -W -p 8088 tmux attach -t sanguo_dev > /tmp/ttyd.log 2>&1 &
|
||||
```
|
||||
|
||||
**认证信息**:
|
||||
- 用户名: `sanguo`
|
||||
- 密码: `sanguo2024`
|
||||
|
||||
**注意**: `-W` 参数启用可写模式,允许在 Web 界面中输入命令。
|
||||
|
||||
### 修改认证密码
|
||||
|
||||
```bash
|
||||
# 停止当前 ttyd
|
||||
pkill ttyd
|
||||
|
||||
# 用新密码启动 (格式: 用户名:密码)
|
||||
ttyd -c username:newpassword -W -p 8088 tmux attach -t sanguo_dev
|
||||
```
|
||||
|
||||
### 查看本机 IP
|
||||
|
||||
```bash
|
||||
# macOS
|
||||
ifconfig | grep "inet " | grep -v 127.0.0.1
|
||||
|
||||
# Linux
|
||||
ip addr show | grep "inet " | grep -v 127.0.0.1
|
||||
```
|
||||
|
||||
### 访问地址
|
||||
|
||||
```
|
||||
http://YOUR_LAN_IP:8088
|
||||
```
|
||||
|
||||
浏览器打开后会弹出 HTTP Basic Authentication 对话框,输入用户名和密码即可访问。
|
||||
|
||||
### 停止 ttyd
|
||||
|
||||
```bash
|
||||
# 查找进程
|
||||
ps aux | grep ttyd
|
||||
|
||||
# 杀死进程
|
||||
kill <PID>
|
||||
```
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 问题 1: tmux 会话已存在
|
||||
|
||||
```bash
|
||||
# 附加到现有会话
|
||||
tmux attach-session -t sanguo_dev
|
||||
|
||||
# 或删除后重建
|
||||
tmux kill-session -t sanguo_dev
|
||||
~/.claude/messages/sanguo/start-sanguo-env.sh
|
||||
```
|
||||
|
||||
### 问题 2: SendMessage 不工作
|
||||
|
||||
**检查**:
|
||||
1. 确认各实例都在运行
|
||||
2. 确认实例名称正确 (main, backend, frontend)
|
||||
3. 查看 Claude Code 版本 (需要 v2.1.166+)
|
||||
|
||||
**备选方案**: 使用文件消息队列
|
||||
```bash
|
||||
# 发送消息
|
||||
~/.claude/messages/sanguo/message.sh send backend "任务内容"
|
||||
|
||||
# 读取消息
|
||||
~/.claude/messages/sanguo/message.sh read
|
||||
```
|
||||
|
||||
### 问题 3: 角色定义未生效
|
||||
|
||||
**检查**:
|
||||
```bash
|
||||
# 确认 CLAUDE.md 存在
|
||||
ls -la ~/.claude/projects/sanguo-*/.claude/CLAUDE.md
|
||||
|
||||
# 查看内容
|
||||
cat ~/.claude/projects/sanguo-main/.claude/CLAUDE.md
|
||||
```
|
||||
|
||||
**解决**: 重新启动 Claude Code
|
||||
|
||||
### 问题 4: 端口被占用
|
||||
|
||||
```bash
|
||||
# 查找占用进程
|
||||
lsof -i :8088
|
||||
|
||||
# 更换端口
|
||||
ttyd -p 8089 tmux attach -t sanguo_dev
|
||||
```
|
||||
|
||||
## 高级配置
|
||||
|
||||
### 自定义 tmux 布局
|
||||
|
||||
编辑 `~/.tmux-sanguo.conf`:
|
||||
|
||||
```bash
|
||||
# 调整 pane 大小
|
||||
split-window -h -p 60 # 水平分割,右侧占 60%
|
||||
|
||||
# 调整颜色
|
||||
set - pane-active-border-style "fg=brightgreen"
|
||||
|
||||
# 添加状态栏信息
|
||||
set - status-right "%H:%M | %Y-%m-%d"
|
||||
```
|
||||
|
||||
### 添加更多实例
|
||||
|
||||
编辑启动脚本,添加更多 pane:
|
||||
|
||||
```bash
|
||||
# 在 pane 2 之后添加
|
||||
tmux selectp -t 2
|
||||
tmux split-window -v -p 50
|
||||
tmux selectp -t 3
|
||||
tmux split-window -h -p 50
|
||||
```
|
||||
|
||||
### 环境变量配置
|
||||
|
||||
添加到 `~/.zshrc` 或 `~/.bashrc`:
|
||||
|
||||
```bash
|
||||
# sanguo 环境变量
|
||||
export SANGUO_SESSION="sanguo_dev"
|
||||
export SANGUO_WEB_PORT="8088"
|
||||
export SANGUO_PROJECTS_BASE="$HOME/.claude/projects"
|
||||
|
||||
# 快捷命令
|
||||
alias sanguo-start="$HOME/.claude/messages/sanguo/start-sanguo-env.sh"
|
||||
alias sanguo-test="$HOME/.claude/messages/sanguo/test-sanguo-env.sh"
|
||||
alias sanguo-msg="$HOME/.claude/messages/sanguo/message.sh"
|
||||
```
|
||||
|
||||
## 生产部署
|
||||
|
||||
### 使用 systemd (Linux)
|
||||
|
||||
创建 `/etc/systemd/system/sanguo.service`:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=sanguo Three-Instance Development Environment
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
User=your-user
|
||||
ExecStart=/usr/bin/tmux new-session -d -s sanguo_dev
|
||||
ExecStartPost=/bin/sleep 2
|
||||
ExecStartPost=/usr/bin/ttyd -c sanguo:sanguo2024 -W -p 8088 tmux attach -t sanguo_dev
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
### 使用 launchd (macOS)
|
||||
|
||||
创建 `~/Library/LaunchAgents/com.sanguo.dev.plist`:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.sanguo.dev</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/local/bin/tmux</string>
|
||||
<string>new-session</string>
|
||||
<string>-d</string>
|
||||
<string>-s</string>
|
||||
<string>sanguo_dev</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
加载服务:
|
||||
```bash
|
||||
launchctl load ~/Library/LaunchAgents/com.sanguo.dev.plist
|
||||
```
|
||||
|
||||
## 安全注意事项
|
||||
|
||||
### Web 访问安全
|
||||
|
||||
1. **不要暴露到公网** - 仅在内网使用
|
||||
2. **使用防火墙** - 限制访问来源
|
||||
3. **启用认证** - 当前已配置基本认证 (sanguo:sanguo2024)
|
||||
|
||||
```bash
|
||||
# 当前配置
|
||||
ttyd -c sanguo:sanguo2024 -p 8088 tmux attach -t sanguo_dev
|
||||
|
||||
# 修改密码
|
||||
pkill ttyd
|
||||
ttyd -c your_username:your_password -p 8088 tmux attach -t sanguo_dev
|
||||
```
|
||||
|
||||
### 安全等级
|
||||
|
||||
| 配置 | 安全级别 | 说明 |
|
||||
|------|----------|------|
|
||||
| 仅局域网 + 认证 | 🟡 中 | 当前配置 |
|
||||
| 添加 HTTPS | 🟢 中高 | 推荐配置 |
|
||||
| VPN + 内网访问 | 🟢 高 | 最安全 |
|
||||
| 直接暴露公网 | 🔴 危险 | 绝对避免 |
|
||||
|
||||
### 数据安全
|
||||
|
||||
1. 定期备份项目目录
|
||||
2. 不要在 CLAUDE.md 中存储敏感信息
|
||||
3. 使用环境变量管理 API Keys
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [完整设计文档](./docs/design/04-design-v0.4.md)
|
||||
- [快速参考](./docs/04-quick-reference.md)
|
||||
- [示例工作流](./docs/05-example-workflows.md)
|
||||
@@ -1,3 +1,244 @@
|
||||
# sanguo_moziplus_v3
|
||||
|
||||
多agent框架和基础设施
|
||||
**三实例 AI 协作开发环境** - 基于 Claude Code + GLM-5.2
|
||||
|
||||
## 版本
|
||||
|
||||
**v0.4** - 设计和基础设施完成 (2026-06-30)
|
||||
|
||||
## 概述
|
||||
|
||||
sanguo_moziplus_v3 是一个多实例 AI 协作开发环境,通过三个独立的 Claude Code 实例协同工作,模拟真实开发团队中的不同角色:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ tmux sanguo_dev 会话 │
|
||||
│ │
|
||||
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
|
||||
│ │ architect │ │ backend │ │ frontend │ │
|
||||
│ │ 架构师 │ │ 后端开发 │ │ 前端开发 │ │
|
||||
│ │ pane #0 │ │ pane #1 │ │ pane #2 │ │
|
||||
│ └───────────┘ └───────────┘ └───────────┘ │
|
||||
│ │
|
||||
│ 共享 Superpowers Skills (~/.claude/skills/) │
|
||||
│ 共享 GLM-5.2 后端 │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 特性
|
||||
|
||||
- **三实例协作**: 架构师、后端、前端三个角色独立运行
|
||||
- **角色隔离**: 通过 CLAUDE.md 定义清晰的角色边界
|
||||
- **共享技能库**: 所有实例共享 Superpowers skills
|
||||
- **跨实例通信**: SendMessage + 文件消息队列
|
||||
- **Web 访问**: 通过 ttyd 实现浏览器访问
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1. 验证环境
|
||||
|
||||
```bash
|
||||
~/.claude/messages/sanguo/test-sanguo-env.sh
|
||||
```
|
||||
|
||||
### 2. 启动环境
|
||||
|
||||
```bash
|
||||
~/.claude/messages/sanguo/start-sanguo-env.sh
|
||||
```
|
||||
|
||||
### 3. 启动实例
|
||||
|
||||
在各 tmux pane 中分别执行:
|
||||
|
||||
```bash
|
||||
# pane 0
|
||||
cd ~/.claude/projects/sanguo-main && claude
|
||||
|
||||
# pane 1
|
||||
cd ~/.claude/projects/sanguo-backend && claude
|
||||
|
||||
# pane 2
|
||||
cd ~/.claude/projects/sanguo-frontend && claude
|
||||
```
|
||||
|
||||
## 文档
|
||||
|
||||
| 文档 | 描述 |
|
||||
|------|------|
|
||||
| [DEPLOYMENT.md](./DEPLOYMENT.md) | 部署指南 |
|
||||
| [docs/design/04-design-v0.4.md](./docs/design/04-design-v0.4.md) | 完整设计文档 |
|
||||
| [docs/04-quick-reference.md](./docs/04-quick-reference.md) | 快速参考 |
|
||||
| [docs/05-example-workflows.md](./docs/05-example-workflows.md) | 示例工作流 |
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
sanguo_moziplus_v3/
|
||||
├── DEPLOYMENT.md # 部署指南
|
||||
├── README.md # 本文件
|
||||
├── docs/
|
||||
│ ├── design/
|
||||
│ │ ├── 02-design-v0.2.md # v0.2 设计 (CCB 方案)
|
||||
│ │ ├── 03-design-v0.3.md # v0.3 设计 (内置 Agent)
|
||||
│ │ └── 04-design-v0.4.md # v0.4 设计 (三实例方案) ✅
|
||||
│ ├── 04-quick-reference.md # 快速参考
|
||||
│ └── 05-example-workflows.md # 示例工作流
|
||||
│
|
||||
├── ~/.claude/projects/ # 项目目录
|
||||
│ ├── sanguo-main/ # 架构师项目
|
||||
│ │ └── .claude/CLAUDE.md # 架构师角色定义
|
||||
│ ├── sanguo-backend/ # 后端项目
|
||||
│ │ └── .claude/CLAUDE.md # 后端角色定义
|
||||
│ └── sanguo-frontend/ # 前端项目
|
||||
│ └── .claude/CLAUDE.md # 前端角色定义
|
||||
│
|
||||
├── ~/.claude/skills/ # 角色 Skills
|
||||
│ ├── architect-role/ # 架构师 skill
|
||||
│ ├── backend-dev/ # 后端 skill
|
||||
│ └── frontend-dev/ # 前端 skill
|
||||
│
|
||||
└── ~/.claude/messages/sanguo/ # 系统脚本
|
||||
├── start-sanguo-env.sh # 启动脚本
|
||||
├── message.sh # 消息队列
|
||||
└── test-sanguo-env.sh # 测试脚本
|
||||
```
|
||||
|
||||
## 角色
|
||||
|
||||
### architect (架构师/项目经理)
|
||||
|
||||
**项目**: `~/.claude/projects/sanguo-main`
|
||||
|
||||
**职责**:
|
||||
- 需求分析和理解
|
||||
- 架构设计和技术选型
|
||||
- 任务拆分和优先级排序
|
||||
- 代码审核和质量把关
|
||||
- 最终验收和 Git 提交管理
|
||||
|
||||
**限制**: 绝对不亲自编写代码
|
||||
|
||||
### backend (后端开发)
|
||||
|
||||
**项目**: `~/.claude/projects/sanguo-backend`
|
||||
|
||||
**职责**:
|
||||
- 服务端代码实现
|
||||
- API 设计和实现
|
||||
- 数据库设计和 Migration
|
||||
- 单元测试和集成测试
|
||||
|
||||
**限制**: 只处理后端任务,拒绝前端任务
|
||||
|
||||
### frontend (前端开发)
|
||||
|
||||
**项目**: `~/.claude/projects/sanguo-frontend`
|
||||
|
||||
**职责**:
|
||||
- 前端组件开发
|
||||
- 页面布局和样式
|
||||
- 用户交互逻辑
|
||||
- 浏览器兼容性
|
||||
|
||||
**限制**: 只处理前端任务,拒绝后端任务
|
||||
|
||||
## 协作方式
|
||||
|
||||
### SendMessage 跨实例通信
|
||||
|
||||
```javascript
|
||||
// architect → backend
|
||||
SendMessage({
|
||||
to: "backend",
|
||||
summary: "实现用户 API",
|
||||
message: "需要实现用户查询 API,包括..."
|
||||
})
|
||||
|
||||
// backend → architect
|
||||
SendMessage({
|
||||
to: "main",
|
||||
summary: "后端完成",
|
||||
message: "已完成用户 API,文件包括..."
|
||||
})
|
||||
```
|
||||
|
||||
### 备选方案: 文件消息队列
|
||||
|
||||
```bash
|
||||
# 发送消息
|
||||
~/.claude/messages/sanguo/message.sh send backend "任务内容"
|
||||
|
||||
# 读取消息
|
||||
~/.claude/messages/sanguo/message.sh read
|
||||
```
|
||||
|
||||
## 技术栈
|
||||
|
||||
| 组件 | 技术/版本 |
|
||||
|------|----------|
|
||||
| **Claude Code** | v2.1.187+ |
|
||||
| **Superpowers** | Marketplace |
|
||||
| **GLM-5.2** | 智谱 AI |
|
||||
| **ttyd** | v1.7.7 |
|
||||
| **tmux** | v3.7 |
|
||||
|
||||
## 环境要求
|
||||
|
||||
- macOS 或 Linux
|
||||
- Claude Code v2.1.166+
|
||||
- tmux
|
||||
- ttyd
|
||||
- Bash
|
||||
|
||||
## 安装
|
||||
|
||||
### 1. 克隆仓库
|
||||
|
||||
```bash
|
||||
git clone http://192.168.2.154:3000/sanguo/sanguo_moziplus_v3.git
|
||||
cd sanguo_moziplus_v3
|
||||
```
|
||||
|
||||
### 2. 运行测试
|
||||
|
||||
```bash
|
||||
~/.claude/messages/sanguo/test-sanguo-env.sh
|
||||
```
|
||||
|
||||
### 3. 启动环境
|
||||
|
||||
```bash
|
||||
~/.claude/messages/sanguo/start-sanguo-env.sh
|
||||
```
|
||||
|
||||
详细步骤见 [DEPLOYMENT.md](./DEPLOYMENT.md)
|
||||
|
||||
## 状态
|
||||
|
||||
**v0.4 设计和基础设施: ✅ 完成**
|
||||
|
||||
- ✅ 完整设计文档
|
||||
- ✅ 快速参考文档
|
||||
- ✅ 示例工作流文档
|
||||
- ✅ 部署指南
|
||||
- ✅ 三实例项目结构
|
||||
- ✅ 角色 Skills
|
||||
- ✅ tmux 配置
|
||||
- ✅ 启动脚本
|
||||
- ✅ 消息队列系统
|
||||
- ✅ 环境测试脚本
|
||||
|
||||
**待用户操作**:
|
||||
|
||||
- ⏳ 启动 tmux 环境
|
||||
- ⏳ 在各 pane 启动 Claude Code
|
||||
- ⏳ 测试 SendMessage 协作
|
||||
|
||||
## 许可证
|
||||
|
||||
[待定]
|
||||
|
||||
## 联系方式
|
||||
|
||||
- 仓库: http://192.168.2.154:3000/sanguo/sanguo_moziplus_v3
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
# sanguo_moziplus_v3 v0.4 快速参考
|
||||
|
||||
## 启动环境
|
||||
|
||||
### 方式一:使用启动脚本 (推荐)
|
||||
|
||||
```bash
|
||||
~/.claude/messages/sanguo/start-sanguo-env.sh
|
||||
```
|
||||
|
||||
### 方式二:手动启动
|
||||
|
||||
```bash
|
||||
# 启动 tmux 会话
|
||||
tmux new -s sanguo_dev
|
||||
|
||||
# 配置三个 pane
|
||||
# 在 pane 0: cd ~/.claude/projects/sanguo-main
|
||||
# 按 Ctrl+B, 然后按 % 水平分割
|
||||
# 在 pane 1: cd ~/.claude/projects/sanguo-backend
|
||||
# 按 Ctrl+B, 然后按 " 垂直分割
|
||||
# 在 pane 2: cd ~/.claude/projects/sanguo-frontend
|
||||
```
|
||||
|
||||
## 三实例角色
|
||||
|
||||
| Pane | 角色 | 项目目录 | CLAUDE.md |
|
||||
|------|------|----------|-----------|
|
||||
| **0** | architect (架构师) | `~/.claude/projects/sanguo-main` | 架构师/项目经理 |
|
||||
| **1** | backend (后端) | `~/.claude/projects/sanguo-backend` | 后端开发 |
|
||||
| **2** | frontend (前端) | `~/.claude/projects/sanguo-frontend` | 前端开发 |
|
||||
|
||||
## 启动 Claude Code
|
||||
|
||||
在每个 pane 中:
|
||||
|
||||
```bash
|
||||
# pane 0 (architect)
|
||||
cd ~/.claude/projects/sanguo-main
|
||||
claude
|
||||
|
||||
# pane 1 (backend)
|
||||
cd ~/.claude/projects/sanguo-backend
|
||||
claude
|
||||
|
||||
# pane 2 (frontend)
|
||||
cd ~/.claude/projects/sanguo-frontend
|
||||
claude
|
||||
```
|
||||
|
||||
## tmux 快捷键
|
||||
|
||||
| 快捷键 | 功能 |
|
||||
|--------|------|
|
||||
| `Ctrl+B 0` | 切换到 pane 0 |
|
||||
| `Ctrl+B 1` | 切换到 pane 1 |
|
||||
| `Ctrl+B 2` | 切换到 pane 2 |
|
||||
| `Ctrl+B o` | 在 pane 间循环切换 |
|
||||
| `Ctrl+B %` | 水平分割 |
|
||||
| `Ctrl+B "` | 垂直分割 |
|
||||
| `Ctrl+B 方向键` | 切换到指定方向 pane |
|
||||
| `Ctrl+B d` | 分离会话 (detach) |
|
||||
|
||||
## SendMessage 跨实例通信
|
||||
|
||||
### 从 architect 发送任务到 backend
|
||||
|
||||
```javascript
|
||||
SendMessage({
|
||||
to: "backend",
|
||||
summary: "实现用户认证 API",
|
||||
message: "需要实现 JWT 认证系统,包括登录、注册、刷新 token 端点..."
|
||||
})
|
||||
```
|
||||
|
||||
### 从 backend 返回结果到 architect
|
||||
|
||||
```javascript
|
||||
SendMessage({
|
||||
to: "main",
|
||||
summary: "后端任务完成",
|
||||
message: "已完成用户认证 API 实现..."
|
||||
})
|
||||
```
|
||||
|
||||
### 备选方案:文件消息队列
|
||||
|
||||
```bash
|
||||
# 发送消息
|
||||
~/.claude/messages/sanguo/message.sh send backend "实现用户API"
|
||||
|
||||
# 读取消息
|
||||
~/.claude/messages/sanguo/message.sh read
|
||||
|
||||
# 列出消息
|
||||
~/.claude/messages/sanguo/message.sh list
|
||||
```
|
||||
|
||||
## Web 访问
|
||||
|
||||
### 启动 ttyd
|
||||
|
||||
```bash
|
||||
ttyd -p 8088 tmux attach -t sanguo_dev
|
||||
```
|
||||
|
||||
### 访问地址
|
||||
|
||||
```
|
||||
http://YOUR_LAN_IP:8088
|
||||
```
|
||||
|
||||
### 查看本机 IP
|
||||
|
||||
```bash
|
||||
ifconfig | grep "inet " | grep -v 127.0.0.1
|
||||
```
|
||||
|
||||
## 角色 Skills
|
||||
|
||||
### 可用 Skills
|
||||
|
||||
```bash
|
||||
~/.claude/skills/
|
||||
├── architect-role/ # 架构师专属
|
||||
├── backend-dev/ # 后端开发专属
|
||||
├── frontend-dev/ # 前端开发专属
|
||||
├── CODE-REVIEW/ # 三实例共享
|
||||
├── test-engineer/ # 三实例共享
|
||||
└── ... (100+ Superpowers skills)
|
||||
```
|
||||
|
||||
## 典型工作流
|
||||
|
||||
### 1. 架构师接收需求
|
||||
|
||||
```
|
||||
用户: "实现用户认证系统"
|
||||
↓
|
||||
architect (pane 0) 接收
|
||||
```
|
||||
|
||||
### 2. 规划和拆分
|
||||
|
||||
```
|
||||
architect:
|
||||
- 分析需求
|
||||
- 规划技术方案
|
||||
- 拆分为前后端任务
|
||||
```
|
||||
|
||||
### 3. 指派任务
|
||||
|
||||
```
|
||||
architect → backend: SendMessage({ to: "backend", message: "..." })
|
||||
architect → frontend: SendMessage({ to: "frontend", message: "..." })
|
||||
```
|
||||
|
||||
### 4. 执行和返回
|
||||
|
||||
```
|
||||
backend: 执行后端任务 → SendMessage({ to: "main", message: "..." })
|
||||
frontend: 执行前端任务 → SendMessage({ to: "main", message: "..." })
|
||||
```
|
||||
|
||||
### 5. 审查和验收
|
||||
|
||||
```
|
||||
architect:
|
||||
- 审查后端代码
|
||||
- 审查前端代码
|
||||
- 整合测试
|
||||
- Git 提交
|
||||
```
|
||||
|
||||
## 故障排查
|
||||
|
||||
### SendMessage 不工作
|
||||
|
||||
使用文件消息队列备选方案。
|
||||
|
||||
### 角色隔离不生效
|
||||
|
||||
确认 CLAUDE.md 文件存在且内容正确。
|
||||
|
||||
### tmux 会话丢失
|
||||
|
||||
```bash
|
||||
# 查看所有会话
|
||||
tmux ls
|
||||
|
||||
# 恢复会话
|
||||
tmux attach-session -t sanguo_dev
|
||||
```
|
||||
|
||||
### 端口被占用
|
||||
|
||||
```bash
|
||||
# 查找占用进程
|
||||
lsof -i :8088
|
||||
|
||||
# 更换端口
|
||||
ttyd -p 8089 tmux attach -t sanguo_dev
|
||||
```
|
||||
|
||||
## 配置文件
|
||||
|
||||
| 文件 | 路径 |
|
||||
|------|------|
|
||||
| **tmux 配置** | `~/.tmux-sanguo.conf` |
|
||||
| **启动脚本** | `~/.claude/messages/sanguo/start-sanguo-env.sh` |
|
||||
| **消息脚本** | `~/.claude/messages/sanguo/message.sh` |
|
||||
| **settings.json** | `~/.claude/settings.json` |
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [完整设计文档](./design/04-design-v0.4.md)
|
||||
- [SendMessage 验证结果](./design/04-design-v0.4.md#phase-5-sendmessage-机制验证)
|
||||
@@ -0,0 +1,460 @@
|
||||
# sanguo_moziplus_v3 v0.4 示例工作流
|
||||
|
||||
本文档展示如何使用三实例环境完成典型开发任务。
|
||||
|
||||
## 工作流 1: 实现用户认证功能
|
||||
|
||||
### 场景
|
||||
|
||||
实现一个完整的用户认证系统,包括后端 API 和前端页面。
|
||||
|
||||
### 步骤
|
||||
|
||||
#### 1. 架构师 (pane 0) 接收需求
|
||||
|
||||
```
|
||||
用户: "实现用户认证功能"
|
||||
```
|
||||
|
||||
#### 2. 架构师分析和规划
|
||||
|
||||
```
|
||||
架构师:
|
||||
- 分析需求: 用户登录、注册、密码找回
|
||||
- 规划技术方案:
|
||||
* 后端: JWT 认证、/auth/login、/auth/register、/auth/refresh
|
||||
* 前端: 登录页面、注册页面、表单验证
|
||||
- 拆分任务
|
||||
```
|
||||
|
||||
#### 3. 架构师指派任务
|
||||
|
||||
```javascript
|
||||
// pane 0
|
||||
SendMessage({
|
||||
to: "backend",
|
||||
summary: "实现用户认证 API",
|
||||
message: `
|
||||
需要实现 JWT 认证系统:
|
||||
1. POST /auth/login - 用户登录
|
||||
2. POST /auth/register - 用户注册
|
||||
3. POST /auth/refresh - 刷新 token
|
||||
4. POST /auth/logout - 用户登出
|
||||
5. 中间件: JWT 验证
|
||||
|
||||
技术要求:
|
||||
- 使用 bcrypt 密码哈希
|
||||
- JWT 有效期 1 小时
|
||||
- 返回标准 HTTP 状态码
|
||||
- 编写单元测试
|
||||
|
||||
验收标准:
|
||||
- 所有端点正常工作
|
||||
- 测试覆盖率 > 80%
|
||||
- API 文档完整
|
||||
`
|
||||
})
|
||||
|
||||
SendMessage({
|
||||
to: "frontend",
|
||||
summary: "实现认证页面",
|
||||
message: `
|
||||
需要实现用户认证页面:
|
||||
1. 登录页面
|
||||
2. 注册页面
|
||||
3. 表单验证
|
||||
4. API 调用集成
|
||||
5. 错误提示
|
||||
|
||||
技术要求:
|
||||
- 使用 shadcn/ui 组件
|
||||
- 响应式设计
|
||||
- 表单验证
|
||||
- Loading 状态
|
||||
|
||||
验收标准:
|
||||
- UI 符合设计规范
|
||||
- 表单验证完整
|
||||
- 浏览器兼容性测试通过
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
#### 4. 后端 (pane 1) 执行
|
||||
|
||||
```
|
||||
后端收到任务:
|
||||
1. 加载 backend-dev skill
|
||||
2. 设计 API 端点
|
||||
3. 实现 JWT 逻辑
|
||||
4. 编写测试
|
||||
5. 自测验证
|
||||
6. 返回结果
|
||||
```
|
||||
|
||||
```javascript
|
||||
// pane 1 - 后端完成
|
||||
SendMessage({
|
||||
to: "main",
|
||||
summary: "后端认证 API 完成",
|
||||
message: `
|
||||
已完成用户认证 API:
|
||||
|
||||
文件:
|
||||
- src/api/auth.ts (认证端点)
|
||||
- src/middleware/auth.ts (JWT 中间件)
|
||||
- src/utils/jwt.ts (JWT 工具)
|
||||
- src/tests/auth.test.ts (测试)
|
||||
|
||||
端点:
|
||||
✅ POST /auth/login - 登录成功返回 JWT
|
||||
✅ POST /auth/register - 注册成功返回用户信息
|
||||
✅ POST /auth/refresh - 刷新 token
|
||||
✅ POST /auth/logout - 清除 token
|
||||
|
||||
测试结果: 12/12 通过
|
||||
|
||||
API 文档: docs/api-auth.md
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
#### 5. 前端 (pane 2) 执行
|
||||
|
||||
```
|
||||
前端收到任务:
|
||||
1. 加载 frontend-dev skill
|
||||
2. 设计页面组件
|
||||
3. 实现表单
|
||||
4. 调用后端 API
|
||||
5. 浏览器测试
|
||||
6. 返回结果
|
||||
```
|
||||
|
||||
```javascript
|
||||
// pane 2 - 前端完成
|
||||
SendMessage({
|
||||
to: "main",
|
||||
summary: "前端认证页面完成",
|
||||
message: `
|
||||
已完成认证页面:
|
||||
|
||||
文件:
|
||||
- src/pages/LoginPage.tsx (登录页面)
|
||||
- src/pages/RegisterPage.tsx (注册页面)
|
||||
- src/components/AuthForm.tsx (表单组件)
|
||||
- src/hooks/useAuth.ts (认证 Hook)
|
||||
|
||||
功能:
|
||||
✅ 登录表单 (邮箱/密码)
|
||||
✅ 注册表单 (邮箱/密码/确认)
|
||||
✅ 表单验证
|
||||
✅ API 调用
|
||||
✅ 错误提示
|
||||
✅ Loading 状态
|
||||
|
||||
浏览器测试: Chrome, Safari, Firefox 通过
|
||||
|
||||
预览: 截图已保存到 docs/screenshots/auth-pages.png
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
#### 6. 架构师审查和整合
|
||||
|
||||
```javascript
|
||||
// pane 0 - 架构师
|
||||
// 加载 CODE-REVIEW skill 进行审查
|
||||
// 加载 test-engineer skill 验证测试
|
||||
// 整合前后端代码
|
||||
// 提交 Git
|
||||
```
|
||||
|
||||
## 工作流 2: 代码审查
|
||||
|
||||
### 场景
|
||||
|
||||
后端提交了一个 PR,架构师需要审查代码。
|
||||
|
||||
### 步骤
|
||||
|
||||
#### 1. 架构师接收 PR
|
||||
|
||||
```javascript
|
||||
// pane 0
|
||||
SendMessage({
|
||||
to: "backend",
|
||||
summary: "请提供 PR 信息",
|
||||
message: `
|
||||
你提交的 PR #123 需要审查。
|
||||
|
||||
请提供:
|
||||
1. 改动的文件列表
|
||||
2. 实现的功能说明
|
||||
3. 测试结果
|
||||
4. 已知问题
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
#### 2. 后端返回信息
|
||||
|
||||
```javascript
|
||||
// pane 1
|
||||
SendMessage({
|
||||
to: "main",
|
||||
summary: "PR #123 信息",
|
||||
message: `
|
||||
改动的文件:
|
||||
- src/api/users.ts (新增用户查询 API)
|
||||
- src/tests/users.test.ts (新增测试)
|
||||
|
||||
实现功能:
|
||||
- GET /api/users/:id - 获取用户信息
|
||||
- 支持查询参数过滤
|
||||
|
||||
测试结果: 8/8 通过
|
||||
|
||||
已知问题: 无
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
#### 3. 架构师审查
|
||||
|
||||
```
|
||||
架构师:
|
||||
1. 加载 CODE-REVIEW skill
|
||||
2. 审查代码质量
|
||||
3. 检查测试覆盖
|
||||
4. 验证 API 设计
|
||||
5. 提供反馈
|
||||
```
|
||||
|
||||
## 工作流 3: Bug 修复
|
||||
|
||||
### 场景
|
||||
|
||||
前端发现了一个 bug,需要定位和修复。
|
||||
|
||||
### 步骤
|
||||
|
||||
#### 1. 前端报告问题
|
||||
|
||||
```javascript
|
||||
// pane 2
|
||||
SendMessage({
|
||||
to: "main",
|
||||
summary: "报告 bug",
|
||||
message: `
|
||||
发现登录页面 bug:
|
||||
|
||||
现象: 登录成功后页面没有跳转
|
||||
|
||||
重现步骤:
|
||||
1. 输入正确的邮箱和密码
|
||||
2. 点击登录按钮
|
||||
3. Loading 显示
|
||||
4. Loading 消失后仍在登录页
|
||||
|
||||
环境: Chrome 126, macOS
|
||||
|
||||
日志显示 API 调用成功,但 redirect 没有执行
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
#### 2. 架构师分析
|
||||
|
||||
```
|
||||
架构师:
|
||||
1. 分析问题描述
|
||||
2. 确定是前端问题
|
||||
3. 指派前端修复
|
||||
```
|
||||
|
||||
```javascript
|
||||
// pane 0
|
||||
SendMessage({
|
||||
to: "frontend",
|
||||
summary: "修复登录跳转 bug",
|
||||
message: `
|
||||
Bug: 登录成功后页面没有跳转
|
||||
|
||||
日志显示 API 调用成功,检查:
|
||||
1. useAuth Hook 的逻辑
|
||||
2. 跳转代码是否执行
|
||||
3. react-router 配置
|
||||
|
||||
优先级: 高
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
#### 3. 前端修复
|
||||
|
||||
```javascript
|
||||
// pane 2
|
||||
SendMessage({
|
||||
to: "main",
|
||||
summary: "Bug 已修复",
|
||||
message: `
|
||||
问题原因: useAuth Hook 中 redirect 逻辑在 useEffect 之外
|
||||
|
||||
修复方案:
|
||||
- 将 redirect 逻辑移到 useEffect 中
|
||||
- 添加 loading 状态检查
|
||||
|
||||
测试: 登录成功后正确跳转到首页
|
||||
|
||||
文件: src/hooks/useAuth.ts
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
## 工作流 4: 性能优化
|
||||
|
||||
### 场景
|
||||
|
||||
后端 API 响应慢,需要优化。
|
||||
|
||||
### 步骤
|
||||
|
||||
#### 1. 架构师分析性能问题
|
||||
|
||||
```
|
||||
架构师:
|
||||
1. 分析性能数据
|
||||
2. 确定瓶颈
|
||||
3. 规划优化方案
|
||||
```
|
||||
|
||||
#### 2. 架构师指派优化任务
|
||||
|
||||
```javascript
|
||||
// pane 0
|
||||
SendMessage({
|
||||
to: "backend",
|
||||
summary: "优化用户查询 API",
|
||||
message: `
|
||||
性能问题: GET /api/users 响应时间 2.5秒
|
||||
|
||||
目标: 优化到 < 500ms
|
||||
|
||||
分析:
|
||||
- 数据库查询慢 (N+1 问题)
|
||||
- 缺少索引
|
||||
|
||||
优化方案:
|
||||
1. 添加数据库索引
|
||||
2. 优化查询逻辑 (使用 JOIN)
|
||||
3. 添加缓存层 (Redis)
|
||||
|
||||
请先实现索引和查询优化,缓存后续再做。
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
#### 3. 后端实施优化
|
||||
|
||||
```javascript
|
||||
// pane 1
|
||||
SendMessage({
|
||||
to: "main",
|
||||
summary: "优化完成",
|
||||
message: `
|
||||
优化措施:
|
||||
1. 添加 email 索引
|
||||
2. 优化查询: 使用 JOIN 替代 N+1
|
||||
3. 添加查询缓存
|
||||
|
||||
结果:
|
||||
- 优化前: 2.5s
|
||||
- 优化后: 180ms ✅
|
||||
|
||||
文件:
|
||||
- migrations/add_indexes.sql
|
||||
- src/api/users.ts (优化查询)
|
||||
- src/cache/userCache.ts (缓存层)
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
## SendMessage 最佳实践
|
||||
|
||||
### 发送消息格式
|
||||
|
||||
```javascript
|
||||
SendMessage({
|
||||
to: "<main|backend|frontend>",
|
||||
summary: "<简短摘要 5-10 词>",
|
||||
message: `<详细描述,包括:
|
||||
- 任务/问题说明
|
||||
- 技术要求
|
||||
- 验收标准
|
||||
- 其他上下文`
|
||||
})
|
||||
```
|
||||
|
||||
### 接收消息处理
|
||||
|
||||
```
|
||||
1. 读取消息内容
|
||||
2. 理解任务要求
|
||||
3. 加载相应的 skill
|
||||
4. 执行任务
|
||||
5. 返回结果
|
||||
```
|
||||
|
||||
### 错误处理
|
||||
|
||||
如果收到不相关的任务:
|
||||
|
||||
```javascript
|
||||
SendMessage({
|
||||
to: "main",
|
||||
summary: "拒绝任务",
|
||||
message: "这不是 [后端/前端] 任务,请转给 [frontend/backend] agent"
|
||||
})
|
||||
```
|
||||
|
||||
## 常用命令
|
||||
|
||||
### tmux 操作
|
||||
|
||||
```bash
|
||||
# 切换 pane
|
||||
Ctrl+B 0/1/2
|
||||
|
||||
# 在 pane 间循环
|
||||
Ctrl+B o
|
||||
|
||||
# 分离会话
|
||||
Ctrl+B d
|
||||
|
||||
# 重新附加
|
||||
tmux attach-session -t sanguo_dev
|
||||
```
|
||||
|
||||
### 启动 Claude Code
|
||||
|
||||
```bash
|
||||
# 在各 pane 中
|
||||
cd ~/.claude/projects/sanguo-<role>
|
||||
claude
|
||||
```
|
||||
|
||||
### Web 访问
|
||||
|
||||
```bash
|
||||
# 启动 Web 终端 (带认证+可写)
|
||||
ttyd -c sanguo:sanguo2024 -W -p 8088 tmux attach -t sanguo_dev
|
||||
|
||||
# 访问 (会提示输入用户名密码)
|
||||
http://YOUR_LAN_IP:8088
|
||||
```
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [快速参考](./04-quick-reference.md)
|
||||
- [完整设计](./design/04-design-v0.4.md)
|
||||
@@ -0,0 +1,441 @@
|
||||
# sanguo_moziplus_v3 v0.5 部署指南
|
||||
|
||||
## 概述
|
||||
|
||||
v0.5 采用 Main + Sub Agent 动态编排架构,通过 Gitea 进行协作管理。
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 前置要求
|
||||
|
||||
- Claude Code v2.1.39+
|
||||
- Node.js v18+ (用于运行工作流脚本)
|
||||
- Git
|
||||
- Gitea 实例 (或 GitHub)
|
||||
|
||||
### 一键部署
|
||||
|
||||
```bash
|
||||
# 1. 克隆仓库
|
||||
git clone http://192.168.2.154:3000/sanguo/sanguo_moziplus_v3.git
|
||||
cd sanguo_moziplus_v3
|
||||
|
||||
# 2. 运行初始化脚本
|
||||
./scripts/init.sh
|
||||
|
||||
# 3. 配置 Gitea 连接
|
||||
# 编辑 .claude/gitea-config.json
|
||||
|
||||
# 4. 启动 Claude Code
|
||||
cd ~/.openclaw/sanguo_projects/sanguo_moziplus_v3
|
||||
claude
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 详细步骤
|
||||
|
||||
### 步骤 1: 环境配置
|
||||
|
||||
#### 1.1 配置 GLM-5.2
|
||||
|
||||
创建 `~/.claude/settings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"env": {
|
||||
"CLAUDE_CODE_AUTO_COMPACT_WINDOW": "1000000",
|
||||
"ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic",
|
||||
"ANTHROPIC_API_KEY": "你的智谱API_Key",
|
||||
"ANTHROPIC_DEFAULT_SONNET_MODEL": "glm-5.2[1m]",
|
||||
"ANTHROPIC_DEFAULT_OPUS_MODEL": "glm-5.2[1m]"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 1.2 配置 Gitea
|
||||
|
||||
编辑项目中的 `.claude/gitea-config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"gitea": {
|
||||
"baseUrl": "http://192.168.2.154:3000",
|
||||
"owner": "sanguo",
|
||||
"repo": "sanguo_moziplus_v3",
|
||||
"defaultBranch": "main"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 步骤 2: 安装依赖
|
||||
|
||||
```bash
|
||||
# 确保项目目录正确
|
||||
cd ~/.openclaw/sanguo_projects/sanguo_moziplus_v3
|
||||
|
||||
# 工作流脚本需要 Node.js (如需运行 JavaScript 工作流)
|
||||
npm install --save-dev fs path
|
||||
```
|
||||
|
||||
### 步骤 3: 创建 Main Agent 配置
|
||||
|
||||
创建 `.claude/CLAUDE.md`:
|
||||
|
||||
```markdown
|
||||
# sanguo_moziplus_v3 - Main Agent (编排者)
|
||||
|
||||
## 角色
|
||||
|
||||
你是任务编排者,负责通过 Gitea 协调 Sub Agents 完成开发任务。
|
||||
|
||||
## 核心职责
|
||||
|
||||
1. 分析任务需求
|
||||
2. 根据 Gitea 规则安排 Sub Agents
|
||||
3. 通过 Gitea 追踪进度
|
||||
4. 验收并合并 PR
|
||||
|
||||
## Gitea 协作流程
|
||||
|
||||
### 任务开始
|
||||
1. 创建 Issue 记录任务
|
||||
2. 安排 Execute Sub Agent
|
||||
3. 追踪 PR 创建
|
||||
|
||||
### 任务执行
|
||||
- Execute Sub Agent: 实现代码 → Push → 创建 PR
|
||||
- Review Sub Agent: 审查 PR → 添加评论
|
||||
- Test Sub Agent: 测试功能 → 报告结果
|
||||
|
||||
### 任务完成
|
||||
1. 所有 Review 通过
|
||||
2. 所有测试通过
|
||||
3. 合并 PR
|
||||
4. 关闭 Issue
|
||||
|
||||
## Gitea 规则
|
||||
|
||||
所有 Sub Agent 都需要遵循 Gitea 规则,规则从配置文件生成。
|
||||
|
||||
查看当前规则: 读取 .claude/gitea-config.json
|
||||
|
||||
## 严格限制
|
||||
|
||||
- 不亲自编写代码
|
||||
- 所有编码任务通过 Sub Agents 在 Gitea 上完成
|
||||
|
||||
## 可用能力
|
||||
|
||||
- planning: 复杂任务规划
|
||||
- CODE-REVIEW: 代码审查
|
||||
- debugger: 问题调试
|
||||
- Agent 工具: 编排 Sub Agents
|
||||
```
|
||||
|
||||
### 步骤 4: 配置 Superpowers Skills
|
||||
|
||||
确保已安装以下 Skills:
|
||||
|
||||
```bash
|
||||
# 查看已安装的 Skills
|
||||
ls ~/.claude/skills/
|
||||
|
||||
# 如需安装 Superpowers
|
||||
# 参考 Superpowers Marketplace
|
||||
```
|
||||
|
||||
### 步骤 5: 验证部署
|
||||
|
||||
#### 5.1 测试 Gitea 连接
|
||||
|
||||
```bash
|
||||
# 在 Claude Code 中测试
|
||||
claude "测试 Gitea 连接"
|
||||
```
|
||||
|
||||
#### 5.2 测试规则生成
|
||||
|
||||
```javascript
|
||||
// 在 Claude Code 中
|
||||
import { generateGiteaRules } from '.claude/workflows/helpers/gitea-rules-generator.js'
|
||||
console.log(generateGiteaRules())
|
||||
```
|
||||
|
||||
#### 5.3 测试工作流
|
||||
|
||||
```javascript
|
||||
// 在 Claude Code 中
|
||||
Workflow({
|
||||
scriptPath: ".claude/workflows/gitea-orchestration.js",
|
||||
args: "实现用户登录功能"
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 工作流使用
|
||||
|
||||
### 基本用法
|
||||
|
||||
```javascript
|
||||
// 在 Claude Code 中
|
||||
Workflow({
|
||||
scriptPath: ".claude/workflows/gitea-orchestration.js",
|
||||
args: "任务描述"
|
||||
})
|
||||
```
|
||||
|
||||
### 高级用法
|
||||
|
||||
```javascript
|
||||
// 自定义配置
|
||||
Workflow({
|
||||
scriptPath: ".claude/workflows/gitea-orchestration.js",
|
||||
args: {
|
||||
task: "实现用户认证",
|
||||
options: {
|
||||
skipTest: false,
|
||||
reviewers: 2
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
sanguo_moziplus_v3/
|
||||
├── .claude/
|
||||
│ ├── CLAUDE.md # Main Agent 配置
|
||||
│ ├── gitea-config.json # Gitea 配置
|
||||
│ └── workflows/
|
||||
│ ├── gitea-orchestration.js # 主工作流
|
||||
│ ├── helpers/
|
||||
│ │ └── gitea-rules-generator.js # 规则生成器
|
||||
│ └── plan-execute-review.js # 备用工作流
|
||||
├── docs/
|
||||
│ └── design/
|
||||
│ └── 06-design-v0.5-dynamic-orchestration.md
|
||||
└── scripts/
|
||||
└── init.sh # 初始化脚本
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 配置文件详解
|
||||
|
||||
### gitea-config.json
|
||||
|
||||
```json
|
||||
{
|
||||
"gitea": {
|
||||
"baseUrl": "Gitea 服务器地址",
|
||||
"owner": "仓库所有者",
|
||||
"repo": "仓库名称",
|
||||
"defaultBranch": "主分支"
|
||||
},
|
||||
"rules": {
|
||||
"branchNaming": {
|
||||
"feature": "feature/{任务名}",
|
||||
"fix": "fix/{issue号}-{描述}",
|
||||
"hotfix": "hotfix/{描述}"
|
||||
},
|
||||
"commitNaming": {
|
||||
"feat": "feat: {描述}",
|
||||
"fix": "fix: {描述}",
|
||||
"refactor": "refactor: {描述}"
|
||||
},
|
||||
"prTemplate": {
|
||||
"title": "{类型}: {描述}",
|
||||
"description": "完整描述模板"
|
||||
}
|
||||
},
|
||||
"review": {
|
||||
"checklist": ["检查项1", "检查项2"],
|
||||
"approval": "批准规则"
|
||||
},
|
||||
"agents": {
|
||||
"main": { "role": "编排者" },
|
||||
"execute": { "role": "执行者" },
|
||||
"review": { "role": "审查者" },
|
||||
"test": { "role": "测试者" }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 初始化脚本
|
||||
|
||||
创建 `scripts/init.sh`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# sanguo_moziplus_v3 初始化脚本
|
||||
|
||||
set -e
|
||||
|
||||
echo "=== sanguo_moziplus_v3 v0.5 初始化 ==="
|
||||
|
||||
# 1. 检查环境
|
||||
echo "检查环境..."
|
||||
command -v claude >/dev/null 2>&1 || { echo "❌ Claude Code 未安装"; exit 1; }
|
||||
command -v git >/dev/null 2>&1 || { echo "❌ Git 未安装"; exit 1; }
|
||||
command -v node >/dev/null 2>&1 || { echo "⚠️ Node.js 未安装 (可选)" }
|
||||
|
||||
# 2. 创建必要目录
|
||||
echo "创建目录..."
|
||||
mkdir -p .claude/workflows/helpers
|
||||
mkdir -p scripts
|
||||
|
||||
# 3. 检查配置文件
|
||||
echo "检查配置..."
|
||||
if [ ! -f .claude/gitea-config.json ]; then
|
||||
echo "❌ gitea-config.json 不存在"
|
||||
echo "请创建 .claude/gitea-config.json 配置文件"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 4. 检查 Claude Code 配置
|
||||
echo "检查 Claude Code 配置..."
|
||||
if [ ! -f ~/.claude/settings.json ]; then
|
||||
echo "❌ ~/.claude/settings.json 不存在"
|
||||
echo "请配置 GLM-5.2 端点"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 5. 验证 Gitea 连接
|
||||
echo "验证 Gitea 连接..."
|
||||
GITEA_URL=$(node -e "
|
||||
const fs = require('fs');
|
||||
const config = JSON.parse(fs.readFileSync('.claude/gitea-config.json', 'utf-8'));
|
||||
console.log(config.gitea.baseUrl);
|
||||
")
|
||||
echo "Gitea URL: $GITEA_URL"
|
||||
|
||||
# 6. 测试 Git 连接
|
||||
echo "测试 Git 连接..."
|
||||
git remote -v
|
||||
|
||||
echo "=== 初始化完成 ==="
|
||||
echo ""
|
||||
echo "下一步:"
|
||||
echo "1. 启动 Claude Code: claude"
|
||||
echo "2. 测试工作流: Workflow({ scriptPath: '.claude/workflows/gitea-orchestration.js', args: '测试任务' })"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 问题 1: Gitea 连接失败
|
||||
|
||||
**检查**:
|
||||
1. 确认 gitea-config.json 配置正确
|
||||
2. 检查网络连接
|
||||
3. 验证 Gitea 服务器可访问
|
||||
|
||||
### 问题 2: 工作流无法运行
|
||||
|
||||
**检查**:
|
||||
1. 确认 Claude Code 版本支持 Workflow 工具
|
||||
2. 检查工作流文件路径
|
||||
3. 查看 Claude Code 日志
|
||||
|
||||
### 问题 3: Sub Agent 无法访问 Gitea
|
||||
|
||||
**检查**:
|
||||
1. 确认 Git 凭证配置
|
||||
2. 检查 Gitea 权限
|
||||
3. 验证 SSH/HTTPS 访问
|
||||
|
||||
---
|
||||
|
||||
## 升级指南
|
||||
|
||||
### 从 v0.4 升级
|
||||
|
||||
v0.4 使用三实例方案,v0.5 使用 Main + Sub Agent:
|
||||
|
||||
1. **保留**:
|
||||
- GLM-5.2 配置
|
||||
- Superpowers Skills
|
||||
- 角色 Skills
|
||||
|
||||
2. **移除**:
|
||||
- tmux 三实例配置
|
||||
- 启动脚本 (如不需要)
|
||||
|
||||
3. **新增**:
|
||||
- gitea-config.json
|
||||
- gitea-orchestration.js
|
||||
- gitea-rules-generator.js
|
||||
|
||||
4. **迁移**:
|
||||
- 更新 CLAUDE.md 为 Main Agent 配置
|
||||
- 使用 Gitea 协作替代 SendMessage
|
||||
|
||||
---
|
||||
|
||||
## 生产部署
|
||||
|
||||
### 使用 systemd (Linux)
|
||||
|
||||
创建 `/etc/systemd/system/sanguo.service`:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=sanguo_moziplus_v3 Development Environment
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=your-user
|
||||
WorkingDirectory=/path/to/sanguo_moziplus_v3
|
||||
ExecStart=/usr/local/bin/claude
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
### 使用 launchd (macOS)
|
||||
|
||||
创建 `~/Library/LaunchAgents/com.sanguo.dev.plist`:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.sanguo.dev</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/local/bin/claude</string>
|
||||
</array>
|
||||
<key>WorkingDirectory</key>
|
||||
<string>/path/to/sanguo_moziplus_v3</string>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [v0.5 设计文档](./docs/design/06-design-v0.5-dynamic-orchestration.md)
|
||||
- [Gitea 配置示例](./.claude/gitea-config.json)
|
||||
- [工作流脚本](./.claude/workflows/gitea-orchestration.js)
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: v0.5
|
||||
**最后更新**: 2026-07-01
|
||||
**作者**: Claude Dev
|
||||
**状态**: Draft
|
||||
@@ -0,0 +1,632 @@
|
||||
# sanguo_moziplus_v3 设计文档 v0.3
|
||||
|
||||
**项目名称**: sanguo_moziplus_v3
|
||||
**版本**: v0.3
|
||||
**创建日期**: 2026-06-30
|
||||
**状态**: Draft
|
||||
**基于**: v0.2 + Claude Code 内置多 Agent 能力
|
||||
|
||||
---
|
||||
|
||||
## 1. 版本变更
|
||||
|
||||
| 版本 | 变更说明 | 日期 |
|
||||
|------|---------|------|
|
||||
| v0.1 | 初始设计 | 2026-06-29 |
|
||||
| v0.2 | 基于 videotext 调研更新,集成 GLM-5.2、Web 访问 | 2026-06-29 |
|
||||
| **v0.3** | **移除 CCB,采用 Claude Code 内置多 Agent 能力** | **2026-06-30** |
|
||||
|
||||
### v0.3 核心变化
|
||||
|
||||
| 变更项 | v0.2 | v0.3 | 原因 |
|
||||
|--------|------|------|------|
|
||||
| **CCB 层** | Codex + Gemini 桥接 | ❌ 移除 | Codex CLI 不兼容 GLM-5.2 |
|
||||
| **编排方式** | Workflow 脚本 | Skills 内置编排 | Skills 可调用 Agent 工具 |
|
||||
| **Agent 调用** | 外部 CLI | 内置 Agent 工具 | Explore、Plan、通用 agents |
|
||||
| **架构层数** | 5 层 | 3 层 | 简化架构 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 架构概述
|
||||
|
||||
### 2.1 系统架构图
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Claude Code CLI │
|
||||
│ (用户交互层 + 主协调) │
|
||||
│ │
|
||||
│ 内置能力: │
|
||||
│ • Agent 工具 — 启动专门 agents │
|
||||
│ • Skills — 封装可复用能力 │
|
||||
│ • SendMessage — Agent 间通信 │
|
||||
│ • worktree 隔离 — 独立工作环境 │
|
||||
└─────────────────────────────┬───────────────────────────────────┘
|
||||
│
|
||||
┌─────────────────────────────▼───────────────────────────────────┐
|
||||
│ Superpowers (Skills 层) │
|
||||
│ │
|
||||
│ 每个 Skill 内部编排多个 Agents: │
|
||||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||||
│ │ Planning Skill │ │
|
||||
│ │ 1. Agent(Explore) → 搜索相关文件 │ │
|
||||
│ │ 2. Agent(Plan) → 设计架构方案 │ │
|
||||
│ │ 3. 返回整合规划 │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||||
│ │ Review Skill │ │
|
||||
│ │ 1. Agent(code-reviewer) → 审查代码 │ │
|
||||
│ │ 2. 返回审查报告 │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||||
│ │ Debug Skill │ │
|
||||
│ │ 1. Agent(Explore) → 定位问题 │ │
|
||||
│ │ 2. Agent(general-purpose) → 修复问题 │ │
|
||||
│ │ 3. Agent(test-automation) → 验证修复 │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────┬───────────────────────────────────┘
|
||||
│
|
||||
┌─────────────────────────────▼───────────────────────────────────┐
|
||||
│ CLAUDE.md (规范层) │
|
||||
│ - 协作规范 │
|
||||
│ - Git 规范 │
|
||||
│ - 决策框架 (Linus 三问) │
|
||||
└─────────────────────────────┬───────────────────────────────────┘
|
||||
│
|
||||
┌─────────────────────────────▼───────────────────────────────────┐
|
||||
│ GLM-5.2 (统一后端) │
|
||||
│ • Anthropic 兼容端点: https://api.z.ai/api/anthropic │
|
||||
│ • 1M 上下文支持 │
|
||||
│ • 所有 Agent 通过同一模型执行 │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Web 访问层 (ttyd) │
|
||||
│ 端口: 8088 │
|
||||
│ 访问: http://YOUR_LAN_IP:8088 │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.2 完整链路
|
||||
|
||||
```
|
||||
用户输入需求
|
||||
↓
|
||||
Claude Code (主 Agent)
|
||||
↓
|
||||
调用 Skill (如 /plan)
|
||||
↓
|
||||
Skill 内部编排多个 Agents
|
||||
├─ Agent(Explore) → 搜索文件
|
||||
├─ Agent(Plan) → 设计方案
|
||||
└─ 返回整合结果
|
||||
↓
|
||||
GLM-5.2 (统一后端)
|
||||
↓
|
||||
ttyd Web 访问
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 核心组件配置
|
||||
|
||||
### 3.1 Claude Code 内置 Agent 能力
|
||||
|
||||
| 能力 | 用途 | 调用方式 |
|
||||
|------|------|---------|
|
||||
| **Agent 工具** | 启动专门 agents | `Agent({subagent_type: "Explore", prompt: "..."})` |
|
||||
| **Workflow** | JS 脚本编排 (被 Skills 替代) | ❌ 不推荐使用 |
|
||||
| **SendMessage** | Agent 间通信 | `SendMessage({to: "agent-name", message: "..."})` |
|
||||
| **worktree** | 独立工作环境 | `Agent({isolation: "worktree", ...})` |
|
||||
| **Fleet** | 并发配置 | settings.json 中配置 |
|
||||
|
||||
### 3.2 可用 Agent 类型
|
||||
|
||||
| Agent 类型 | 用途 | 典型场景 |
|
||||
|-----------|------|---------|
|
||||
| **Explore** | 文件搜索和定位 | "搜索所有 API 文件"、"找到数据库配置" |
|
||||
| **Plan** | 架构设计和技术方案 | "设计用户认证系统"、"规划数据库架构" |
|
||||
| **claude** | 通用任务执行 | "实现用户注册功能" |
|
||||
| **general-purpose** | 复杂多步骤任务 | "重构整个模块" |
|
||||
| **code-reviewer** | 代码审查 | "审查这个 PR 的安全性" |
|
||||
| **test-automation*** | 测试相关 | "编写 E2E 测试" |
|
||||
|
||||
### 3.3 GLM-5.2 端点配置
|
||||
|
||||
| 端点类型 | URL | 用途 |
|
||||
|---------|-----|------|
|
||||
| **Anthropic 兼容** | `https://api.z.ai/api/anthropic` | Claude Code 主接口 |
|
||||
| **Coding Plan** | `https://api.z.ai/api/coding/paas/v4` | ❌ Codex 不兼容,不使用 |
|
||||
|
||||
**settings.json 配置**:
|
||||
```json
|
||||
{
|
||||
"env": {
|
||||
"CLAUDE_CODE_AUTO_COMPACT_WINDOW": "1000000",
|
||||
"ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic",
|
||||
"ANTHROPIC_API_KEY": "你的智谱API_Key",
|
||||
"ANTHROPIC_DEFAULT_SONNET_MODEL": "glm-5.2[1m]",
|
||||
"ANTHROPIC_DEFAULT_OPUS_MODEL": "glm-5.2[1m]"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Superpowers Skills 设计
|
||||
|
||||
### 4.1 核心 Skills
|
||||
|
||||
| Skill | 触发方式 | 内部 Agent 编排 | 输出 |
|
||||
|-------|---------|----------------|------|
|
||||
| **Planning** | `/plan` 或自然语言 | Explore → Plan → 返回方案 | 技术方案文档 |
|
||||
| **Review** | `/review` 或自然语言 | code-reviewer → 返回报告 | 审查报告 |
|
||||
| **Debug** | `/debug` 或自然语言 | Explore → general-purpose → test | 问题定位和修复 |
|
||||
|
||||
### 4.2 Skill 内部编排示例
|
||||
|
||||
**Planning Skill 工作流**:
|
||||
```markdown
|
||||
## Planning Skill
|
||||
|
||||
当用户需要规划时:
|
||||
|
||||
1. 启动 Explore Agent 搜索相关文件
|
||||
- 搜索项目中已有的相关代码
|
||||
- 查找配置文件和文档
|
||||
- 返回相关文件列表
|
||||
|
||||
2. 启动 Plan Agent 设计方案
|
||||
- 基于搜索结果设计架构
|
||||
- 拆分实施步骤
|
||||
- 列出需要修改的文件
|
||||
|
||||
3. 返回整合后的规划文档
|
||||
```
|
||||
|
||||
**用户调用**:
|
||||
```
|
||||
我:/plan "实现用户认证功能"
|
||||
↓
|
||||
Planning Skill 内部执行
|
||||
├─ Agent(Explore, "搜索现有认证代码")
|
||||
├─ Agent(Plan, "设计 JWT 认证方案")
|
||||
└─ 返回规划文档
|
||||
```
|
||||
|
||||
### 4.3 Skill 创建规范
|
||||
|
||||
```markdown
|
||||
<!-- ~/.claude/skills/my-skill/SKILL.md -->
|
||||
|
||||
## 技能名称
|
||||
|
||||
简要描述
|
||||
|
||||
### 触发条件
|
||||
- 用户说 "XXX"
|
||||
- 或调用 `/my-skill`
|
||||
|
||||
### 工作流程
|
||||
1. Agent(Explore) → ...
|
||||
2. Agent(Plan) → ...
|
||||
3. 返回结果
|
||||
|
||||
### 输出格式
|
||||
- 文档路径
|
||||
- 或代码片段
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 端口规划
|
||||
|
||||
| 服务 | 端口 | 说明 |
|
||||
|------|------|------|
|
||||
| **ttyd Web** | 8088 | tmux Web 访问 |
|
||||
| **Claude Code** | 默认 | 由 Claude Code 管理 |
|
||||
|
||||
**已移除端口**:
|
||||
- ~~CCB askd (32779)~~ — 不再需要
|
||||
|
||||
**已占用端口(避开)**: 3001, 6379, 18789, 19999
|
||||
|
||||
---
|
||||
|
||||
## 6. 实施步骤
|
||||
|
||||
### Phase 1: 环境准备
|
||||
|
||||
#### 1.1 基础工具安装
|
||||
|
||||
```bash
|
||||
# 检查 Claude Code
|
||||
claude --version
|
||||
|
||||
# 安装 tmux
|
||||
brew install tmux
|
||||
tmux -V
|
||||
```
|
||||
|
||||
#### 1.2 配置 GLM-5.2
|
||||
|
||||
**创建/编辑 `~/.claude/settings.json`**:
|
||||
```json
|
||||
{
|
||||
"env": {
|
||||
"CLAUDE_CODE_AUTO_COMPACT_WINDOW": "1000000",
|
||||
"ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic",
|
||||
"ANTHROPIC_API_KEY": "6903e83faf454106aa7529c9e18e2ea5.gYMSjWwk1XDN0U5h",
|
||||
"ANTHROPIC_DEFAULT_SONNET_MODEL": "glm-5.2[1m]",
|
||||
"ANTHROPIC_DEFAULT_OPUS_MODEL": "glm-5.2[1m]"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**验证**:
|
||||
```bash
|
||||
claude "测试 GLM-5.2 连接"
|
||||
```
|
||||
|
||||
#### 1.3 安装 ttyd
|
||||
|
||||
```bash
|
||||
brew install ttyd
|
||||
```
|
||||
|
||||
**配置 ttyd**:
|
||||
|
||||
创建 `~/.ttyd`:
|
||||
```
|
||||
address = "0.0.0.0"
|
||||
port = "8088"
|
||||
permit-write = true
|
||||
enable-basic-auth = false
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 2: Superpowers Skills 创建
|
||||
|
||||
#### 2.1 创建 Planning Skill
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.claude/skills/planning
|
||||
```
|
||||
|
||||
**`~/.claude/skills/planning/SKILL.md`**:
|
||||
```markdown
|
||||
# Planning Skill
|
||||
|
||||
技术方案规划专家。
|
||||
|
||||
## 触发条件
|
||||
- 用户说 "规划"、"设计方案"、"技术方案"
|
||||
- 或直接调用 `/plan`
|
||||
|
||||
## 工作流程
|
||||
1. 启动 Explore Agent 搜索相关文件和代码
|
||||
2. 启动 Plan Agent 设计技术方案
|
||||
3. 返回包含架构、步骤、文件清单的规划文档
|
||||
|
||||
## 输出格式
|
||||
- 技术方案文档 (docs/方案名称.md)
|
||||
- 实施步骤清单
|
||||
- 需要修改/创建的文件列表
|
||||
```
|
||||
|
||||
#### 2.2 创建 Review Skill
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.claude/skills/review
|
||||
```
|
||||
|
||||
**`~/.claude/skills/review/SKILL.md`**:
|
||||
```markdown
|
||||
# Review Skill
|
||||
|
||||
代码审查专家。
|
||||
|
||||
## 触发条件
|
||||
- 用户说 "审查"、"review"、"代码检查"
|
||||
- 或直接调用 `/review`
|
||||
|
||||
## 工作流程
|
||||
1. 启动 code-reviewer Agent 审查代码
|
||||
2. 检查安全性、性能、可维护性
|
||||
3. 返回包含问题和建议的审查报告
|
||||
|
||||
## 输出格式
|
||||
- 审查报告 (docs/review-日期.md)
|
||||
- 问题清单(按严重程度排序)
|
||||
- 改进建议
|
||||
```
|
||||
|
||||
#### 2.3 创建 Debug Skill
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.claude/skills/debug
|
||||
```
|
||||
|
||||
**`~/.claude/skills/debug/SKILL.md`**:
|
||||
```markdown
|
||||
# Debug Skill
|
||||
|
||||
问题诊断和修复专家。
|
||||
|
||||
## 触发条件
|
||||
- 用户说 "调试"、"debug"、"修复问题"
|
||||
- 或直接调用 `/debug`
|
||||
|
||||
## 工作流程
|
||||
1. 启动 Explore Agent 定位问题
|
||||
2. 启动 general-purpose Agent 修复问题
|
||||
3. 启动 test-automation Agent 验证修复
|
||||
4. 返回问题分析和修复方案
|
||||
|
||||
## 输出格式
|
||||
- 问题分析报告
|
||||
- 修复代码
|
||||
- 测试验证结果
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 3: CLAUDE.md 规范配置
|
||||
|
||||
**项目 `CLAUDE.md` 模板**:
|
||||
```markdown
|
||||
# {项目名称}
|
||||
|
||||
## 工作模式
|
||||
|
||||
Claude Code + GLM-5.2 + Superpowers Skills
|
||||
|
||||
## 核心能力
|
||||
|
||||
### 内置 Agent 工具
|
||||
- **Agent(Explore)**: 搜索和定位文件
|
||||
- **Agent(Plan)**: 设计技术方案
|
||||
- **Agent(general-purpose)**: 执行复杂任务
|
||||
- **Agent(code-reviewer)**: 代码审查
|
||||
|
||||
### Superpowers Skills
|
||||
- **/plan**: 规划技术方案
|
||||
- **/review**: 审查代码质量
|
||||
- **/debug**: 调试和修复问题
|
||||
|
||||
## 典型工作流
|
||||
|
||||
### 方案规划
|
||||
```
|
||||
用户: "规划用户认证系统"
|
||||
↓
|
||||
调用 /plan Skill
|
||||
↓
|
||||
Skill 内部:
|
||||
- Agent(Explore) 搜索现有认证代码
|
||||
- Agent(Plan) 设计 JWT 方案
|
||||
↓
|
||||
返回规划文档
|
||||
```
|
||||
|
||||
### 代码开发
|
||||
```
|
||||
用户: "实现用户注册 API"
|
||||
↓
|
||||
Agent(general-purpose) 实现代码
|
||||
↓
|
||||
调用 /review Skill 审查
|
||||
↓
|
||||
Git 提交
|
||||
```
|
||||
|
||||
### 问题调试
|
||||
```
|
||||
用户: "登录接口报错"
|
||||
↓
|
||||
调用 /debug Skill
|
||||
↓
|
||||
Skill 内部:
|
||||
- Agent(Explore) 定位问题
|
||||
- Agent(general-purpose) 修复代码
|
||||
- Agent(test-automation) 验证修复
|
||||
↓
|
||||
返回修复报告
|
||||
```
|
||||
|
||||
## Linus 三问 (决策前必问)
|
||||
|
||||
1. 这是现实问题还是想象问题? → 拒绝过度设计
|
||||
2. 这个问题真的需要解决吗? → 拒绝伪需求
|
||||
3. 这个方案真的能解决问题吗? → 拒绝自嗨
|
||||
|
||||
## Git 规范
|
||||
|
||||
- 提交前使用 `/review` 审查代码
|
||||
- 提交信息格式: `类型: 简短描述`
|
||||
- 类型: feat/fix/refactor/docs/test/chore
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 4: 启动和验证
|
||||
|
||||
#### 4.1 启动 tmux 会话
|
||||
|
||||
```bash
|
||||
tmux new -s sanguo_dev
|
||||
```
|
||||
|
||||
#### 4.2 启动 ttyd Web 访问
|
||||
|
||||
```bash
|
||||
ttyd -p 8088 tmux attach -t sanguo_dev
|
||||
```
|
||||
|
||||
#### 4.3 验证多 Agent 能力
|
||||
|
||||
```bash
|
||||
# 测试 Agent 工具
|
||||
claude "Agent(Explore, '搜索所有 API 文件')"
|
||||
|
||||
# 测试 Skills
|
||||
claude "/plan '设计数据库架构'"
|
||||
claude "/review '审查 src/api/'"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 配置文件汇总
|
||||
|
||||
### 7.1 配置文件位置
|
||||
|
||||
| 文件 | 路径 | 用途 |
|
||||
|------|------|------|
|
||||
| **settings.json** | `~/.claude/settings.json` | GLM-5.2 端点配置 |
|
||||
| **CLAUDE.md** | `项目根目录/.claude/CLAUDE.md` | 协作规范 |
|
||||
| **Skills** | `~/.claude/skills/*/SKILL.md` | 能力封装 |
|
||||
| **ttyd 配置** | `~/.ttyd` | Web 访问配置 |
|
||||
| **tmux 配置** | `~/.tmux.conf` | 终端复用配置 |
|
||||
|
||||
### 7.2 环境变量汇总
|
||||
|
||||
```bash
|
||||
# GLM-5.2 (Anthropic 兼容)
|
||||
export ANTHROPIC_BASE_URL="https://api.z.ai/api/anthropic"
|
||||
export ANTHROPIC_API_KEY="你的智谱API_Key"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 技术栈
|
||||
|
||||
| 组件 | 技术/版本 | 说明 |
|
||||
|------|----------|------|
|
||||
| **Claude Code** | v2.1.39+ | 主控 CLI + 内置 Agent 能力 |
|
||||
| **Superpowers** | Skills | 能力封装 + 内部 Agent 编排 |
|
||||
| **Agent 工具** | 内置 | Explore、Plan、通用 agents |
|
||||
| **GLM-5.2** | 智谱 AI | 统一后端,1M 上下文 |
|
||||
| **ttyd** | v1.7.7 | Web 终端 |
|
||||
| **tmux** | 系统包管理器 | 终端复用 |
|
||||
|
||||
### 已移除组件
|
||||
|
||||
| 组件 | 原因 |
|
||||
|------|------|
|
||||
| ~~CCB~~ | Codex CLI 不兼容 GLM-5.2 |
|
||||
| ~~Codex CLI~~ | 需要 `/responses` WebSocket 端点 |
|
||||
| ~~Gemini CLI~~ | OpenRouter 格式不兼容 |
|
||||
| ~~Workflow 脚本~~ | 被 Skills 替代 |
|
||||
|
||||
---
|
||||
|
||||
## 9. 成本估算
|
||||
|
||||
| 组件 | 用量 | 单价 | 预估成本占比 |
|
||||
|------|------|------|-------------|
|
||||
| **Claude (GLM-5.2)** | 全流程(规划+开发+审查) | 低 | 100% |
|
||||
|
||||
**v0.3 成本优势**:
|
||||
- ✅ 统一使用 GLM-5.2,成本最低
|
||||
- ✅ 1M 上下文减少频繁请求
|
||||
- ✅ 内置 Agent 能力,无额外工具成本
|
||||
|
||||
---
|
||||
|
||||
## 10. 检查清单
|
||||
|
||||
### 环境检查
|
||||
|
||||
- [ ] Claude Code 已安装
|
||||
- [ ] tmux 已安装
|
||||
- [ ] ttyd 已安装
|
||||
|
||||
### 配置验证
|
||||
|
||||
- [ ] `~/.claude/settings.json` 已配置 GLM-5.2 端点
|
||||
- [ ] 智谱 API Key 已设置
|
||||
- [ ] ttyd 配置 8088 端口
|
||||
- [ ] Skills 已创建
|
||||
|
||||
### 功能验证
|
||||
|
||||
- [ ] `claude "测试"` 有响应
|
||||
- [ ] `Agent(Explore, "测试")` 正常工作
|
||||
- [ ] `/plan` Skill 正常工作
|
||||
- [ ] `/review` Skill 正常工作
|
||||
- [ ] `/debug` Skill 正常工作
|
||||
- [ ] tmux 会话正常
|
||||
- [ ] ttyd web 访问 `http://YOUR_IP:8088` 正常
|
||||
|
||||
---
|
||||
|
||||
## 11. 故障排查
|
||||
|
||||
### 11.1 GLM-5.2 连接失败
|
||||
|
||||
**检查**:
|
||||
1. 确认 API Key 正确
|
||||
2. 确认端点 URL: `https://api.z.ai/api/anthropic`
|
||||
3. 检查网络连接
|
||||
|
||||
### 11.2 Agent 工具无响应
|
||||
|
||||
**检查**:
|
||||
1. 确认 Agent 类型正确
|
||||
2. 检查 prompt 格式
|
||||
3. 查看 Claude Code 日志
|
||||
|
||||
### 11.3 Skills 不工作
|
||||
|
||||
**检查**:
|
||||
1. 确认 Skill 目录结构正确
|
||||
2. 检查 SKILL.md 格式
|
||||
3. 尝试重启 Claude Code
|
||||
|
||||
### 11.4 ttyd Web 无法访问
|
||||
|
||||
**检查**:
|
||||
1. 确认绑定 0.0.0.0(非 127.0.0.1)
|
||||
2. 检查防火墙设置
|
||||
3. 确认 IP 地址正确
|
||||
|
||||
---
|
||||
|
||||
## 12. 参考资料
|
||||
|
||||
- [GLM-5.2 - 智谱AI开放文档](https://docs.bigmodel.cn/cn/guide/models/text/glm-5.2)
|
||||
- [ttyd GitHub](https://github.com/tsl0922/ttyd)
|
||||
- [Claude Code 文档](https://docs.anthropic.com)
|
||||
|
||||
---
|
||||
|
||||
## 13. 实施状态
|
||||
|
||||
### 待实施
|
||||
|
||||
| 组件 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| **Claude Code** | ✅ 已安装 | 主控 CLI |
|
||||
| **GLM-5.2 配置** | ⚠️ 待配置 | settings.json |
|
||||
| **ttyd** | ✅ 已安装 | v1.7.7 |
|
||||
| **Skills 创建** | ❌ 未开始 | Planning/Review/Debug |
|
||||
| **CLAUDE.md** | ❌ 未开始 | 项目规范 |
|
||||
|
||||
### 已移除组件
|
||||
|
||||
| 组件 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| **CCB** | ❌ 已移除 | 不再需要 |
|
||||
| **Codex CLI** | ❌ 已移除 | 不兼容 GLM-5.2 |
|
||||
| **Gemini CLI** | ❌ 已移除 | 不兼容 GLM-5.2 |
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: v0.3
|
||||
**最后更新**: 2026-06-30
|
||||
**作者**: Claude Dev
|
||||
**审核状态**: Draft
|
||||
**实施状态**: 待实施
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,266 @@
|
||||
# v0.4 → Main + Sub Agent 迁移计划
|
||||
|
||||
## 概述
|
||||
|
||||
将三实例方案 (v0.4) 迁移到 Main + Sub Agent 架构。
|
||||
|
||||
## 架构对比
|
||||
|
||||
### v0.4 (三实例)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ tmux sanguo_dev │
|
||||
│ ┌─────────────┐ ┌─────────┐ ┌───────┐ │
|
||||
│ │ Claude │ │ Codex │ │Gemini │ │
|
||||
│ │ (架构师) │ │(后端) │ │(前端) │ │
|
||||
│ └─────────────┘ └─────────┘ └───────┘ │
|
||||
└─────────────────────────────────────────┘
|
||||
|
||||
通信: SendMessage 跨实例
|
||||
项目: 3 个独立目录
|
||||
```
|
||||
|
||||
### Main + Sub Agent
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ sanguo_moziplus_v3 项目 │
|
||||
│ ┌───────────────────────────────────┐ │
|
||||
│ │ Main Agent (架构师) │ │
|
||||
│ │ - 分析需求 │ │
|
||||
│ │ - Agent() 指派 Sub Agent │ │
|
||||
│ │ - 整合结果 │ │
|
||||
│ └───────────────────────────────────┘ │
|
||||
│ │ │ │
|
||||
│ ▼ ▼ │
|
||||
│ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ Sub Agent 1 │ │ Sub Agent 2 │ │
|
||||
│ │ (Executor) │ │ (Reviewer) │ │
|
||||
│ └──────────────┘ └──────────────┘ │
|
||||
└─────────────────────────────────────────┘
|
||||
|
||||
通信: Agent 工具
|
||||
项目: 1 个目录
|
||||
```
|
||||
|
||||
## 迁移映射
|
||||
|
||||
| 组件 | v0.4 | 目标 | 操作 |
|
||||
|------|------|------|------|
|
||||
| **Claude Code 实例** | 3 个 | 1 个 | 移除多余实例 |
|
||||
| **项目目录** | 3 个 | 1 个 | 保留 sanguo_moziplus_v3 |
|
||||
| **CLAUDE.md** | 3 个文件 | 1 个文件 | 合并到主项目 |
|
||||
| **SendMessage** | 跨实例 | Agent 工具 | 替换通信方式 |
|
||||
| **tmux 配置** | ~/.tmux-sanguo.conf | 不需要 | 删除 |
|
||||
| **启动脚本** | start-sanguo-env.sh | 不需要 | 删除 |
|
||||
| **消息队列** | message.sh | 不需要 | 删除 |
|
||||
| **ttyd Web** | 8088 端口 | 可选 | 保留用于远程 |
|
||||
| **角色 Skills** | 3 个 | 3 个 | ✅ 保留 |
|
||||
| **Superpowers** | 共享 | 共享 | ✅ 保留 |
|
||||
| **GLM-5.2** | 统一后端 | 统一后端 | ✅ 保留 |
|
||||
|
||||
## 迁移步骤
|
||||
|
||||
### 步骤 1: 保留部分
|
||||
|
||||
#### 1.1 保留 Superpowers Skills
|
||||
|
||||
**无需操作** - 已安装在 `~/.claude/skills/`
|
||||
|
||||
#### 1.2 保留角色 Skills
|
||||
|
||||
**无需操作** - 已创建:
|
||||
- `~/.claude/skills/architect-role/`
|
||||
- `~/.claude/skills/backend-dev/`
|
||||
- `~/.claude/skills/frontend-dev/`
|
||||
|
||||
#### 1.3 保留 GLM-5.2 配置
|
||||
|
||||
**无需操作** - 已在 `~/.claude/settings.json`
|
||||
|
||||
### 步骤 2: 创建 Main Agent 配置
|
||||
|
||||
#### 2.1 创建主项目 CLAUDE.md
|
||||
|
||||
在 `sanguo_moziplus_v3/.claude/CLAUDE.md`:
|
||||
|
||||
```markdown
|
||||
# sanguo_moziplus_v3 - Main Agent
|
||||
|
||||
## 角色
|
||||
|
||||
你是架构师/项目经理,负责协调 Sub Agent 完成开发任务。
|
||||
|
||||
## 核心职责
|
||||
|
||||
- 接收用户需求
|
||||
- 分析并拆分任务
|
||||
- 指派 Sub Agent 执行
|
||||
- 收集并整合结果
|
||||
- 最终审查和验收
|
||||
|
||||
## 严格限制
|
||||
|
||||
**绝对不亲自编写代码**。所有编码任务通过 Agent 工具指派给 Sub Agent。
|
||||
|
||||
## 工作流程
|
||||
|
||||
1. 接收用户需求
|
||||
2. 加载 architect-role skill
|
||||
3. 分析需求,拆分任务
|
||||
4. 使用 Agent 工具指派 Sub Agent:
|
||||
```javascript
|
||||
Agent({
|
||||
subagent_type: "claude",
|
||||
prompt: "作为后端开发专家,实现: ..."
|
||||
})
|
||||
```
|
||||
5. 收集 Sub Agent 返回结果
|
||||
6. 加载 CODE-REVIEW skill 审查
|
||||
7. 整合结果并提交 Git
|
||||
|
||||
## Sub Agent 类型
|
||||
|
||||
- **Executor**: 执行编码任务 (加载 backend-dev/frontend-dev)
|
||||
- **Reviewer**: 代码审查 (加载 CODE-REVIEW)
|
||||
|
||||
## 决策框架 (Linus 三问)
|
||||
|
||||
1. 这是现实问题还是想象问题?
|
||||
2. 这个问题真的需要解决吗?
|
||||
3. 这个方案真的能解决问题吗?
|
||||
```
|
||||
|
||||
### 步骤 3: 创建工作流
|
||||
|
||||
已在 `.claude/workflows/feature-development.js`
|
||||
|
||||
### 步骤 4: 清理 v0.4 组件
|
||||
|
||||
#### 4.1 可以删除的文件
|
||||
|
||||
```bash
|
||||
# tmux 配置 (可选删除,如果不用三实例)
|
||||
rm ~/.tmux-sanguo.conf
|
||||
|
||||
# 旧项目目录 (可选删除,如果不再使用)
|
||||
rm -rf ~/.claude/projects/sanguo-main
|
||||
rm -rf ~/.claude/projects/sanguo-backend
|
||||
rm -rf ~/.claude/projects/sanguo-frontend
|
||||
|
||||
# 启动脚本 (可选删除)
|
||||
rm ~/.claude/messages/sanguo/start-sanguo-env.sh
|
||||
rm ~/.claude/messages/sanguo/message.sh
|
||||
```
|
||||
|
||||
#### 4.2 保留的文件
|
||||
|
||||
```bash
|
||||
# 角色 Skills - 保留
|
||||
~/.claude/skills/architect-role/
|
||||
~/.claude/skills/backend-dev/
|
||||
~/.claude/skills/frontend-dev/
|
||||
|
||||
# GLM-5.2 配置 - 保留
|
||||
~/.claude/settings.json
|
||||
|
||||
# 可选: ttyd 配置 (如果需要 Web 访问)
|
||||
~/.ttyd
|
||||
```
|
||||
|
||||
### 步骤 5: 更新文档
|
||||
|
||||
#### 5.1 创建新设计文档
|
||||
|
||||
`docs/design/06-design-v0.5-sub-agent.md`
|
||||
|
||||
#### 5.2 更新快速参考
|
||||
|
||||
`docs/06-quick-reference-v0.5.md`
|
||||
|
||||
### 步骤 6: 验证测试
|
||||
|
||||
#### 6.1 测试 Agent 工具
|
||||
|
||||
```javascript
|
||||
// 在 Main Agent 中测试
|
||||
Agent({
|
||||
subagent_type: "claude",
|
||||
prompt: "作为后端开发专家,编写一个简单的 Hello World API"
|
||||
})
|
||||
```
|
||||
|
||||
#### 6.2 测试工作流
|
||||
|
||||
```javascript
|
||||
Agent({
|
||||
scriptPath: ".claude/workflows/feature-development.js",
|
||||
args: "实现用户登录功能"
|
||||
})
|
||||
```
|
||||
|
||||
## 对比表
|
||||
|
||||
| 方面 | v0.4 三实例 | Main + Sub Agent |
|
||||
|------|-------------|------------------|
|
||||
| **复杂度** | 🟡 中等 | 🟢 简单 |
|
||||
| **启动** | 需要启动脚本 | 直接使用 |
|
||||
| **通信** | SendMessage (有限制) | Agent 工具 |
|
||||
| **隔离** | 实例级别 | 会话级别 |
|
||||
| **并行** | ⚠️ 复杂 | ✅ 支持 |
|
||||
| **学习成本** | 🟡 中等 | 🟢 低 |
|
||||
| **维护成本** | 🟡 中等 | 🟢 低 |
|
||||
| **Web 访问** | ✅ ttyd + tmux | ⚠️ 需要 Claude Code |
|
||||
|
||||
## 优势
|
||||
|
||||
Main + Sub Agent 方案优势:
|
||||
|
||||
1. **更简单**: 不需要 tmux、启动脚本
|
||||
2. **更灵活**: Sub Agent 自动隔离、并行执行
|
||||
3. **更可靠**: Agent 工具是内置功能,无跨实例限制
|
||||
4. **更易维护**: 单一项目目录
|
||||
|
||||
## 迁移检查清单
|
||||
|
||||
### 保留
|
||||
- [x] Superpowers skills
|
||||
- [x] 角色 Skills (architect-role, backend-dev, frontend-dev)
|
||||
- [x] GLM-5.2 配置
|
||||
- [ ] ttyd (可选)
|
||||
|
||||
### 创建
|
||||
- [ ] .claude/CLAUDE.md
|
||||
- [ ] .claude/workflows/feature-development.js
|
||||
- [ ] docs/design/06-design-v0.5-sub-agent.md
|
||||
- [ ] docs/06-quick-reference-v0.5.md
|
||||
|
||||
### 删除
|
||||
- [ ] ~/.tmux-sanguo.conf
|
||||
- [ ] ~/.claude/projects/sanguo-*
|
||||
- [ ] ~/.claude/messages/sanguo/*.sh
|
||||
|
||||
### 测试
|
||||
- [ ] Agent 工具测试
|
||||
- [ ] 工作流测试
|
||||
- [ ] Skills 加载测试
|
||||
|
||||
## 回滚方案
|
||||
|
||||
如果需要回滚到 v0.4:
|
||||
|
||||
```bash
|
||||
# 恢复项目目录
|
||||
# 从 Git 恢复或重新创建
|
||||
|
||||
# 重新运行 v0.4 设置
|
||||
~/.claude/messages/sanguo/test-sanguo-env.sh
|
||||
~/.claude/messages/sanguo/start-sanguo-env.sh
|
||||
```
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [v0.4 设计文档](./04-design-v0.4.md)
|
||||
- [Sub Agent 方案](../sub-agent-orchestration.md)
|
||||
- [Agent 工具文档](https://docs.anthropic.com/claude-code/agent)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,822 @@
|
||||
# sanguo_moziplus_v3 设计文档 v0.5
|
||||
|
||||
**项目名称**: sanguo_moziplus_v3
|
||||
**版本**: v0.5
|
||||
**状态**: Draft
|
||||
**创建日期**: 2026-07-01
|
||||
|
||||
---
|
||||
|
||||
## 摘要
|
||||
|
||||
sanguo_moziplus_v3 是一个基于 Claude Code 的多 Agent 协作系统。系统采用 **Main Agent 编排 + Sub Agents 执行** 的架构,通过动态编排实现灵活的任务协作。
|
||||
|
||||
**核心特性**:
|
||||
- Main Agent 作为编排者,根据任务需要动态安排 Sub Agents
|
||||
- 集成标准化工作流(规划、执行、审查、调试、完成)
|
||||
- 通过工程审慎决策框架(Linus 三问)过滤需求和方案
|
||||
- 上下文隔离确保各 Agent 专注执行
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
1. [系统架构](#1-系统架构)
|
||||
2. [角色定义](#2-角色定义)
|
||||
3. [编排机制](#3-编排机制)
|
||||
4. [工作流程](#4-工作流程)
|
||||
5. [实施指南](#5-实施指南)
|
||||
6. [附录](#6-附录)
|
||||
|
||||
---
|
||||
|
||||
## 1. 系统架构
|
||||
|
||||
### 1.1 架构概览
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Main Agent (编排者) │
|
||||
│ │
|
||||
│ 职责: │
|
||||
│ • 接收用户需求 │
|
||||
│ • 工程审慎决策 (Linus 三问) │
|
||||
│ • 需求讨论与澄清 │
|
||||
│ • 分析任务复杂度 │
|
||||
│ • 动态安排 Sub Agents │
|
||||
│ • 验收整合结果 │
|
||||
│ │
|
||||
│ 核心能力: │
|
||||
│ • 需求讨论 (deep-interview) │
|
||||
│ • 方案规划 (writing-plans) │
|
||||
│ • 代码审查 (requesting-code-review) │
|
||||
│ • 问题诊断 (systematic-debugging) │
|
||||
│ • Agent 编排工具 │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
│ Agent 工具动态编排
|
||||
│
|
||||
┌──────────┼──────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌──────────────────┐ ┌──────────┐ ┌──────────┐
|
||||
│ Sub Agent: │ │Sub Agent:│ │Sub Agent:│
|
||||
│ Execute │ │Review │ │Test │
|
||||
│ │ │ │ │ │
|
||||
│ 专业角色: │ │专业角色: │ │专业角色: │
|
||||
│ • backend-dev │ • 代码质量 │ • 单元测试 │
|
||||
│ • frontend-dev │ • 安全性 │ • E2E测试 │
|
||||
│ • database-dev │ • 性能 │ • QA测试 │
|
||||
│ • infrastructure │ │ │
|
||||
└──────────────────┘ └──────────┘ └──────────┘
|
||||
|
||||
所有 Agent 都能访问标准化工作流能力
|
||||
```
|
||||
|
||||
### 1.2 核心设计原则
|
||||
|
||||
| 原则 | 说明 |
|
||||
|------|------|
|
||||
| **动态编排** | Main Agent 根据任务需要决定安排哪些 Sub Agents,不使用固化流程 |
|
||||
| **专业分工** | Sub Agents 有明确的专业角色(Execute/Review/Test) |
|
||||
| **上下文隔离** | 每个 Sub Agent 只能看到完成工作所需的最小信息 |
|
||||
| **验证整合** | Main Agent 负责最终验收和结果整合 |
|
||||
| **标准化工作流** | 所有 Agent 遵循相同的五阶段工作流 |
|
||||
|
||||
### 1.3 标准化工作流
|
||||
|
||||
系统遵循五阶段工作流(源自 Superpowers 标准实践):
|
||||
|
||||
```
|
||||
┌──────────────┐ ┌──────────────┐ ┌───────────────┐ ┌──────────────┐ ┌──────────────┐
|
||||
│ 1. 规划 │ → │ 2. 执行 │ → │ 3. 审查 │ → │ 4. 调试 │ → │ 5. 完成 │
|
||||
│ writing-plans │ │ executing │ │ requesting │ │ systematic │ │ finishing │
|
||||
│ │ │ -plans │ │ -code-review │ │ -debugging │ │ -development │
|
||||
│ │ │ │ │ │ │ │ │ -branch │
|
||||
└──────────────┘ └──────────────┘ └───────────────┘ └──────────────┘ └──────────────┘
|
||||
编写计划 执行计划 请求审查 系统调试 完成收尾
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 角色定义
|
||||
|
||||
### 2.1 Main Agent (编排者)
|
||||
|
||||
**职责范围**:
|
||||
|
||||
| 领域 | 职责 | 工具/方法 |
|
||||
|------|------|-----------|
|
||||
| **需求管理** | 接收、澄清、确认需求 | deep-interview skill |
|
||||
| **工程决策** | Linus 三问审慎判断 | 决策框架 |
|
||||
| **任务分析** | 评估复杂度、确定所需 Sub Agents | 分析逻辑 |
|
||||
| **编排执行** | 安排 Sub Agents、协调协作 | Agent 工具 |
|
||||
| **验收整合** | 验证结果、一致性检查、整合输出 | requesting-code-review skill + 一致性检查 |
|
||||
|
||||
**工作方式**:
|
||||
|
||||
```
|
||||
1. 接收用户需求
|
||||
2. Linus 三问过滤(是否现实问题、是否需要解决、方案是否可行)
|
||||
3. 需求澄清(如需要,使用 deep-interview)
|
||||
4. 分析任务复杂度
|
||||
5. 决定编排策略(简单/中等/复杂)
|
||||
6. 执行编排
|
||||
7. 验收整合
|
||||
8. 向用户汇报
|
||||
```
|
||||
|
||||
**严格限制**:
|
||||
- 不亲自编写代码
|
||||
- 不亲自执行具体实现
|
||||
|
||||
### 2.2 Sub Agent: Execute (执行者)
|
||||
|
||||
**专业角色**:
|
||||
- **backend-dev**: 后端开发(API、数据库、业务逻辑)
|
||||
- **frontend-dev**: 前端开发(UI/UX、交互、状态管理)
|
||||
- **database-dev**: 数据库开发(Schema、迁移、优化)
|
||||
- **infrastructure**: 基础设施(部署、监控、配置)
|
||||
|
||||
**上下文**:接收任务描述和项目代码访问权限
|
||||
|
||||
### 2.3 Sub Agent: Review (审查者)
|
||||
|
||||
**专业角色**:
|
||||
- **代码质量审查**:代码规范、可维护性、设计模式
|
||||
- **安全审查**:安全漏洞、权限控制、数据保护
|
||||
- **性能审查**:性能瓶颈、资源使用、优化建议
|
||||
|
||||
**上下文**:接收需要审查的代码和审查标准
|
||||
|
||||
### 2.4 Sub Agent: Test (测试者)
|
||||
|
||||
**专业角色**:
|
||||
- **单元测试**:代码级测试、覆盖率、边界情况
|
||||
- **E2E 测试**:端到端场景、用户流程、集成测试
|
||||
- **QA 测试**:质量保证、测试计划、验收标准
|
||||
|
||||
**上下文**:接收需要测试的功能和测试要求
|
||||
|
||||
---
|
||||
|
||||
## 3. 编排机制
|
||||
|
||||
### 3.1 编排策略
|
||||
|
||||
Main Agent 根据任务复杂度采用不同的编排策略:
|
||||
|
||||
| 复杂度 | 特征 | 编排策略 |
|
||||
|--------|------|----------|
|
||||
| **简单** | 明确的 bug 修复、小改动 | Execute → 验收 |
|
||||
| **中等** | 单一功能实现 | 需求讨论 → Execute → Review → 验收 |
|
||||
| **复杂** | 多功能、跨领域 | 需求讨论 → 规划 → Execute → Review → Test → 验收 |
|
||||
| **调试** | 问题定位和修复 | 定位 → Execute → Test → 验收 |
|
||||
|
||||
### 3.2 工程审慎决策(Linus 三问)
|
||||
|
||||
Main Agent 在编排前必须通过三问过滤:
|
||||
|
||||
| 问题 | 判断标准 | 拒绝条件 |
|
||||
|------|---------|----------|
|
||||
| **1. 这是现实问题还是想象问题?** | 有明确证据或用户反馈 | "可能需要"、"也许将来" |
|
||||
| **2. 这个问题真的需要解决吗?** | 影响核心功能或用户体验 | 边缘场景、伪需求 |
|
||||
| **3. 这个方案真的能解决问题吗?** | 有明确验证路径 | 理论上可行但无验证 |
|
||||
|
||||
**决策流程**:
|
||||
|
||||
```
|
||||
用户需求
|
||||
↓
|
||||
Linus 三问
|
||||
↓
|
||||
┌─────────────┐
|
||||
│ 通过? │
|
||||
└──────┬──────┘
|
||||
├─ 否 → 拒绝/澄清
|
||||
└─ 是 → 继续编排
|
||||
↓
|
||||
需求清晰?
|
||||
├─ 否 → deep-interview
|
||||
└─ 是 → 执行编排
|
||||
```
|
||||
|
||||
### 3.3 需求讨论机制
|
||||
|
||||
当需求不清晰时,Main Agent 使用 **deep-interview** 方法:
|
||||
|
||||
```
|
||||
ASK → LISTEN → WRITE → DEEPEN → REPEAT
|
||||
```
|
||||
|
||||
- **ASK**: 每次提问不超过 2-3 个问题
|
||||
- **LISTEN**: 认真听取用户回答
|
||||
- **WRITE**: 立即记录到 `requirements/` 目录
|
||||
- **DEEPEN**: 根据答案深入追问
|
||||
- **REPEAT**: 直到需求清晰为止
|
||||
|
||||
### 3.4 上下文隔离
|
||||
|
||||
**隔离原则**:
|
||||
|
||||
```
|
||||
Main Agent
|
||||
│
|
||||
├─ Execute Sub Agent
|
||||
│ └─ 只看到: 任务描述 + 项目代码
|
||||
│
|
||||
├─ Review Sub Agent
|
||||
│ └─ 只看到: 需要审查的代码
|
||||
│
|
||||
└─ Test Sub Agent
|
||||
└─ 只看到: 需要测试的功能
|
||||
```
|
||||
|
||||
**为什么隔离**:
|
||||
- Execute 不受 Review 影响,专注实现
|
||||
- Review 不受实现过程影响,客观评估
|
||||
- Test 不受实现细节影响,独立验证
|
||||
|
||||
### 3.5 编排模式
|
||||
|
||||
#### 并行编排
|
||||
|
||||
```javascript
|
||||
// 独立任务可并行执行
|
||||
const [backend, frontend] = await Promise.all([
|
||||
agent({ prompt: "后端: 实现 API" }),
|
||||
agent({ prompt: "前端: 实现页面" })
|
||||
])
|
||||
```
|
||||
|
||||
#### 串行编排
|
||||
|
||||
```javascript
|
||||
// 有依赖关系需串行执行
|
||||
const execute = await agent({ prompt: "实现功能" })
|
||||
const review = await agent({ prompt: `审查: ${execute.files}` })
|
||||
```
|
||||
|
||||
#### 条件编排
|
||||
|
||||
```javascript
|
||||
// 根据中间结果决定下一步
|
||||
const execute = await agent({ prompt: "实现功能" })
|
||||
const review = await agent({ prompt: `审查: ${execute.files}` })
|
||||
|
||||
if (review.passed) {
|
||||
return await integrate(execute, review)
|
||||
} else {
|
||||
const fix = await agent({ prompt: `修复: ${review.findings}` })
|
||||
return await integrate(fix, await agent({ prompt: `重新审查: ${fix.files}` }))
|
||||
}
|
||||
```
|
||||
|
||||
### 3.6 验收机制:需求-设计-编码一致性检查
|
||||
|
||||
Main Agent 在验收时必须执行**三向一致性检查**:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 验收:三向一致性检查 │
|
||||
│ │
|
||||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||||
│ │ 需求 │ ←→ │ 设计 │ ←→ │ 编码 │ │
|
||||
│ └─────────┘ └─────────┘ └─────────┘ │
|
||||
│ ↑ ↑ ↑ │
|
||||
│ └──────────────┴──────────────┘ │
|
||||
│ 一致性检查 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**检查方法**:
|
||||
|
||||
对照三向检查,逐项验证:
|
||||
- 需求 → 设计:设计是否完整覆盖需求?
|
||||
- 设计 → 编码:编码是否正确实现设计?
|
||||
- 需求 → 编码:实现是否满足原始需求?
|
||||
|
||||
**偏差处理**:
|
||||
|
||||
发现偏差时,重新进入 Superpowers 五阶段工作流:
|
||||
|
||||
```
|
||||
验收发现偏差
|
||||
↓
|
||||
┌─────────────────────────────────┐
|
||||
│ 重新进入 Superpowers 工作流 │
|
||||
│ │
|
||||
│ 1. 规划 (writing-plans) │ ← 需求/设计偏差
|
||||
│ 2. 执行 (executing-plans) │ ← 编码偏差
|
||||
│ 3. 审查 (requesting-code-review) │
|
||||
│ 4. 调试 (systematic-debugging) │
|
||||
│ 5. 完成 (finishing-development) │
|
||||
│ │
|
||||
│ → 重新验收 │
|
||||
└─────────────────────────────────┘
|
||||
```
|
||||
|
||||
**一致性检查时机**:
|
||||
- 复杂任务:每次 Sub Agent 完成后检查
|
||||
- 中等任务:Review 阶段检查
|
||||
- 简单任务:最终验收时检查
|
||||
|
||||
---
|
||||
|
||||
## 4. 工作流程
|
||||
|
||||
### 4.1 标准工作流(五阶段)
|
||||
|
||||
#### 阶段 1:规划 (writing-plans)
|
||||
|
||||
**何时使用**:复杂任务(涉及多个领域或需要架构决策)
|
||||
|
||||
**输出**:一份假设执行者对代码库零上下文的实现计划
|
||||
|
||||
**内容包括**:
|
||||
- 任务背景和目标
|
||||
- 技术方案选择
|
||||
- 实施步骤
|
||||
- 验收标准
|
||||
|
||||
#### 阶段 2:执行 (executing-plans)
|
||||
|
||||
**方式**:通过 Agent 工具编排 Sub Agents
|
||||
|
||||
**执行模式**:
|
||||
- 并行执行独立任务
|
||||
- 串行执行有依赖的任务
|
||||
- 根据审查结果调整执行
|
||||
|
||||
#### 阶段 3:审查 (requesting-code-review)
|
||||
|
||||
**何时使用**:代码实现完成后、向用户汇报前
|
||||
|
||||
**检查维度**:
|
||||
- 逻辑正确性和边界情况
|
||||
- 安全漏洞
|
||||
- 性能影响
|
||||
- 测试覆盖率
|
||||
- 错误处理
|
||||
|
||||
#### 阶段 4:调试 (systematic-debugging)
|
||||
|
||||
**何时使用**:遇到问题或错误时
|
||||
|
||||
**方法**:
|
||||
- 系统化定位问题(而非随机尝试)
|
||||
- 分析根本原因
|
||||
- 设计验证方案
|
||||
|
||||
#### 阶段 5:完成 (finishing-a-development-branch)
|
||||
|
||||
**内容**:
|
||||
- 确认所有测试通过
|
||||
- 验证代码质量
|
||||
- 准备提交
|
||||
- 清理临时文件
|
||||
|
||||
### 4.2 任务类型示例
|
||||
|
||||
#### 简单任务:修复 Bug
|
||||
|
||||
```
|
||||
用户: "登录接口报错"
|
||||
↓
|
||||
Main Agent: 快速确认错误信息
|
||||
↓
|
||||
安排 debugger Sub Agent 定位问题
|
||||
↓
|
||||
安排 Execute Sub Agent 修复
|
||||
↓
|
||||
安排 Test Sub Agent 验证
|
||||
↓
|
||||
验收整合
|
||||
```
|
||||
|
||||
#### 中等任务:实现登录功能
|
||||
|
||||
```
|
||||
用户: "实现用户登录功能"
|
||||
↓
|
||||
Main Agent: deep-interview 需求讨论
|
||||
↓
|
||||
记录需求到 requirements/requirements.md
|
||||
↓
|
||||
安排 Execute Sub Agent 实现
|
||||
↓
|
||||
安排 Review Sub Agent 审查
|
||||
↓
|
||||
验收整合
|
||||
```
|
||||
|
||||
#### 复杂任务:实现用户认证系统
|
||||
|
||||
```
|
||||
用户: "实现用户认证系统"
|
||||
↓
|
||||
Main Agent: deep-interview 深度需求讨论
|
||||
↓
|
||||
使用 writing-plans 规划
|
||||
↓
|
||||
并行安排 Execute Sub Agents(后端 + 前端)
|
||||
↓
|
||||
安排 Review Sub Agents(代码 + 安全)
|
||||
↓
|
||||
安排 Test Sub Agent 验证
|
||||
↓
|
||||
验收整合
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 实施指南
|
||||
|
||||
### 5.1 环境配置
|
||||
|
||||
**项目结构**:
|
||||
|
||||
```
|
||||
sanguo_moziplus_v3/
|
||||
├── .claude/
|
||||
│ ├── CLAUDE.md # Main Agent 配置
|
||||
│ └── workflows/
|
||||
│ └── dynamic-orchestration.js # 编排脚本
|
||||
├── requirements/ # 需求文档
|
||||
└── docs/design/ # 设计文档
|
||||
```
|
||||
|
||||
**Main Agent 配置** (`.claude/CLAUDE.md`):
|
||||
|
||||
```markdown
|
||||
# Main Agent 配置
|
||||
|
||||
## 角色
|
||||
你是任务编排者,负责与用户讨论需求、动态安排 Sub Agents、验收整合。
|
||||
|
||||
## 核心职责
|
||||
1. 需求讨论 - 使用 deep-interview skill
|
||||
2. 工程决策 - Linus 三问过滤
|
||||
3. 任务分析 - 评估复杂度
|
||||
4. 编排执行 - 动态安排 Sub Agents
|
||||
5. 验收整合 - 验证并整合结果
|
||||
|
||||
## 严格限制
|
||||
- 不亲自编写代码
|
||||
- 不亲自执行具体实现
|
||||
|
||||
## 可用能力
|
||||
- deep-interview - 需求讨论
|
||||
- writing-plans - 方案规划
|
||||
- requesting-code-review - 代码审查
|
||||
- systematic-debugging - 问题诊断
|
||||
- Agent 工具 - 编排 Sub Agents
|
||||
```
|
||||
|
||||
### 5.2 编排脚本示例
|
||||
|
||||
```javascript
|
||||
export const meta = {
|
||||
name: 'dynamic-orchestration',
|
||||
description: 'Main Agent 根据任务需要动态编排 Sub Agents',
|
||||
phases: [
|
||||
{ title: '分析', detail: '分析任务需求' },
|
||||
{ title: '编排', detail: '决定 Sub Agents' },
|
||||
{ title: '执行', detail: 'Sub Agents 执行' },
|
||||
{ title: '验收', detail: '验收整合' }
|
||||
]
|
||||
}
|
||||
|
||||
export default async function (task) {
|
||||
// 1. 分析任务
|
||||
const analysis = await analyzeTask(task)
|
||||
|
||||
// 2. 根据复杂度编排
|
||||
if (analysis.complexity === 'high') {
|
||||
// 复杂任务:规划 → 执行 → 审查 → 测试
|
||||
const plan = await Skill({ skill: 'writing-plans', args: task })
|
||||
const execute = await executeAgents(plan)
|
||||
const review = await reviewAgents(execute)
|
||||
const test = await testAgents(execute)
|
||||
return await integrate(plan, execute, review, test)
|
||||
}
|
||||
|
||||
if (analysis.complexity === 'medium') {
|
||||
// 中等任务:执行 → 审查
|
||||
const execute = await executeAgents(task)
|
||||
const review = await reviewAgents(execute)
|
||||
return await integrate(execute, review)
|
||||
}
|
||||
|
||||
// 简单任务:直接执行
|
||||
const execute = await executeAgents(task)
|
||||
return await integrate(execute)
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 Gitea 协作流程
|
||||
|
||||
系统使用 Gitea Issue 作为协作中心,Main Agent 和 Sub Agents 在同一个 Issue 中协作。
|
||||
|
||||
#### 5.3.1 Issue 结构
|
||||
|
||||
**Issue 标题格式**:
|
||||
```
|
||||
[sanguo_moziplus_v3] 功能描述
|
||||
```
|
||||
|
||||
**Issue 正文结构**:
|
||||
```markdown
|
||||
## 项目信息
|
||||
- 项目: sanguo_moziplus_v3
|
||||
- 需求编号: D-N
|
||||
- 复杂度: 简单/中等/复杂
|
||||
|
||||
## 需求描述
|
||||
<!-- 用户需求概述 -->
|
||||
|
||||
## 执行清单
|
||||
|
||||
### 📋 Execute Sub Agent
|
||||
> **负责**: Execute Sub Agent
|
||||
> **状态**: 🔄 进行中
|
||||
|
||||
- [ ] 任务1...
|
||||
- [ ] 任务2...
|
||||
|
||||
**完成时标记**: `@main-agent ✅ EXECUTE_DONE`
|
||||
|
||||
### 📋 Review Sub Agent
|
||||
> **负责**: Review Sub Agent
|
||||
> **状态**: ⏳ 等待中
|
||||
|
||||
- [ ] 检查项1...
|
||||
- [ ] 检查项2...
|
||||
|
||||
**完成时标记**: `@main-agent ✅ REVIEW_DONE verdict=approved/rejected`
|
||||
|
||||
### 📋 Test Sub Agent
|
||||
> **负责**: Test Sub Agent
|
||||
> **状态**: ⏳ 等待中
|
||||
|
||||
- [ ] 测试项1...
|
||||
- [ ] 测试项2...
|
||||
|
||||
**完成时标记**: `@main-agent ✅ TEST_DONE result=passed/failed`
|
||||
|
||||
### 📋 Main Agent 验收
|
||||
> **负责**: Main Agent
|
||||
> **状态**: ⏳ 等待中
|
||||
|
||||
- [ ] 需求 → 设计 一致性
|
||||
- [ ] 设计 → 编码 一致性
|
||||
- [ ] 需求 → 编码 一致性
|
||||
|
||||
**完成时标记**: `@main-agent ✅ VERIFICATION_PASSED`
|
||||
|
||||
## 执行状态
|
||||
| 阶段 | 负责者 | 状态 | 更新时间 |
|
||||
|------|-------|------|---------|
|
||||
| Execute | Execute Sub Agent | 🔄 进行中 | - |
|
||||
| Review | Review Sub Agent | ⏳ 等待 | - |
|
||||
| Test | Test Sub Agent | ⏳ 等待 | - |
|
||||
| 验收 | Main Agent | ⏳ 等待 | - |
|
||||
```
|
||||
|
||||
#### 5.3.2 工作流程
|
||||
|
||||
**Step 1: Main Agent 创建 Issue**
|
||||
|
||||
Main Agent 接收需求后,创建 Issue 并制定工作清单。
|
||||
|
||||
**Step 2: Sub Agents 工作并更新**
|
||||
|
||||
Sub Agents 在工作过程中通过 Issue Comments 更新进度:
|
||||
|
||||
```markdown
|
||||
@main-agent 📝 **进度更新: Execute 阶段**
|
||||
|
||||
## 已完成
|
||||
- ✅ 1.1 数据库迁移
|
||||
- ✅ 1.2 核心逻辑实现
|
||||
|
||||
## 进行中
|
||||
- 🔄 1.3 API 接口实现
|
||||
|
||||
---
|
||||
**进度**: 66% (2/3 完成)
|
||||
```
|
||||
|
||||
**Step 3: Sub Agent 完成后发布标记**
|
||||
|
||||
Sub Agent 完成工作后,发布标准格式的完成标记:
|
||||
|
||||
```markdown
|
||||
@main-agent ✅ **EXECUTE_DONE**
|
||||
|
||||
## 完成总结
|
||||
|
||||
### 交付物
|
||||
1. `db/migrations/001_login_attempts.sql` - 数据库迁移
|
||||
2. `src/auth/login_checker.py` - 核心逻辑
|
||||
3. `src/api/routes/auth.py` - API 集成
|
||||
|
||||
### 测试状态
|
||||
- 本地运行: ✅ PASS
|
||||
- 覆盖率: 85%
|
||||
|
||||
---
|
||||
**执行者**: Execute Sub Agent
|
||||
**完成时间**: 2026-07-01 12:00
|
||||
```
|
||||
|
||||
**Step 4: Main Agent 读取 Gitea 并编排下一阶段**
|
||||
|
||||
Sub Agent 完成后,Main Agent 主动读取 Gitea 状态:
|
||||
|
||||
```javascript
|
||||
// Main Agent 感知 Sub Agent 完成并编排
|
||||
async function checkAndOrchestrate(issueNumber) {
|
||||
// 1. 读取 Issue Comments
|
||||
const comments = await gitea.getIssueComments(issueNumber)
|
||||
|
||||
// 2. 解析完成标记
|
||||
const executeDone = comments.some(c => c.body.includes('✅ EXECUTE_DONE'))
|
||||
const reviewDone = comments.some(c => c.body.includes('✅ REVIEW_DONE'))
|
||||
const testDone = comments.some(c => c.body.includes('✅ TEST_DONE'))
|
||||
|
||||
// 3. 根据状态编排下一阶段
|
||||
if (executeDone && !reviewDone) {
|
||||
// Execute 完成 → 启动 Review + Test 并行
|
||||
await notifyAgents(issueNumber, 'Review 和 Test 可以开始了')
|
||||
}
|
||||
|
||||
if (reviewDone && testDone) {
|
||||
// Review + Test 完成 → 启动验收
|
||||
await startVerification(issueNumber)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Step 5: Main Agent 执行三向一致性检查**
|
||||
|
||||
Main Agent 在验收时执行一致性检查,并发布结果:
|
||||
|
||||
```markdown
|
||||
@main-agent ✅ **VERIFICATION_PASSED**
|
||||
|
||||
## 三向一致性检查
|
||||
|
||||
### 1️⃣ 需求 → 设计
|
||||
| 需求项 | 设计覆盖 | 状态 |
|
||||
|--------|---------|------|
|
||||
| IP 5次/5分钟 | login_attempts + 计数逻辑 | ✅ |
|
||||
| 用户名 3次 | login_attempts + 计数逻辑 | ✅ |
|
||||
| 锁定 30/15分钟 | locked_until 字段 | ✅ |
|
||||
|
||||
✅ **需求→设计: 通过**
|
||||
|
||||
### 2️⃣ 设计 → 编码
|
||||
| 设计 | 代码 | 状态 |
|
||||
|------|------|------|
|
||||
| 数据库表 | 001_login_attempts.sql | ✅ |
|
||||
| 检查逻辑 | login_checker.py | ✅ |
|
||||
|
||||
✅ **设计→编码: 通过**
|
||||
|
||||
### 3️⃣ 需求 → 编码
|
||||
| 需求 | 代码实现 | 状态 |
|
||||
|------|---------|------|
|
||||
| IP 5次/5分钟 | IP_MAX_ATTEMPTS=5, IP_WINDOW=300 | ✅ |
|
||||
| 锁定 30/15分钟 | IP_LOCK_DURATION=1800 | ✅ |
|
||||
|
||||
✅ **需求→编码: 通过**
|
||||
|
||||
## 最终结论
|
||||
✅ **三向一致性检查全部通过**
|
||||
**VERDICT**: ✅ APPROVED FOR MERGE
|
||||
|
||||
---
|
||||
**执行者**: Main Agent
|
||||
**完成时间**: 2026-07-01 13:00
|
||||
```
|
||||
|
||||
**Step 6: 关闭 Issue**
|
||||
|
||||
Main Agent 更新 Issue 状态:
|
||||
|
||||
```markdown
|
||||
## 最终状态: ✅ COMPLETED
|
||||
|
||||
### 完成链路
|
||||
1. ✅ Execute Sub Agent 完成 (12:00)
|
||||
2. ✅ Review Sub Agent 通过 (12:30)
|
||||
3. ✅ Test Sub Agent 通过 (12:45)
|
||||
4. ✅ Main Agent 验收通过 (13:00)
|
||||
|
||||
### 三向一致性
|
||||
- 需求 → 设计: ✅
|
||||
- 设计 → 编码: ✅
|
||||
- 需求 → 编码: ✅
|
||||
|
||||
---
|
||||
**状态**: Closed
|
||||
**标签**: completed, verified, D-1
|
||||
```
|
||||
|
||||
#### 5.3.3 Comment 标记约定
|
||||
|
||||
| Sub Agent | 完成标记格式 | 说明 |
|
||||
|-----------|-------------|------|
|
||||
| Execute | `@main-agent ✅ EXECUTE_DONE` | 包含交付物清单 |
|
||||
| Review | `@main-agent ✅ REVIEW_DONE verdict=approved` | 包含检查结果 |
|
||||
| Test | `@main-agent ✅ TEST_DONE result=passed coverage=85%` | 包含测试结果 |
|
||||
| Main | `@main-agent ✅ VERIFICATION_PASSED` | 包含三向检查结果 |
|
||||
|
||||
#### 5.3.4 流程图
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ Gitea 协作流程 │
|
||||
│ │
|
||||
│ Main Agent 创建 Issue #42 │
|
||||
│ ├─ 标题: [sanguo_moziplus_v3] 功能描述 │
|
||||
│ ├─ 工作清单: Execute / Review / Test / 验收 │
|
||||
│ └─ 状态表: 初始状态 │
|
||||
│ ↓ │
|
||||
│ Execute Sub Agent 工作... │
|
||||
│ └─ Comment: "@main-agent ✅ EXECUTE_DONE" │
|
||||
│ ↓ │
|
||||
│ Main Agent 读取 Gitea → 感知到 EXECUTE_DONE │
|
||||
│ └─ @review @test 请开始工作 │
|
||||
│ ↓ │
|
||||
│ Review + Test 并行工作... │
|
||||
│ ├─ Review: "@main-agent ✅ REVIEW_DONE verdict=approved" │
|
||||
│ └─ Test: "@main-agent ✅ TEST_DONE result=passed" │
|
||||
│ ↓ │
|
||||
│ Main Agent 读取 Gitea → 感知到 REVIEW_DONE + TEST_DONE │
|
||||
│ └─ 开始三向一致性检查 │
|
||||
│ ↓ │
|
||||
│ Main Agent Comment: "@main-agent ✅ VERIFICATION_PASSED" │
|
||||
│ ↓ │
|
||||
│ Main Agent 更新 Issue → Closed ✅ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### 5.3.5 偏差处理
|
||||
|
||||
如果 Main Agent 在验收时发现偏差:
|
||||
|
||||
```markdown
|
||||
@main-agent ❌ **CONSISSYENCY_ISSUE**
|
||||
|
||||
## 发现偏差
|
||||
|
||||
### 问题: 需求 → 编码 偏差
|
||||
**需求**: "锁定期间即使密码正确也不允许登录"
|
||||
**代码**: login_checker.py:L45 中,锁定检查在密码验证之后执行
|
||||
|
||||
### 处理要求
|
||||
1. 将锁定检查移到密码验证之前
|
||||
2. 添加测试用例验证此场景
|
||||
3. 重新提交 review
|
||||
|
||||
---
|
||||
**标签**: needs-consistency-fix 🔴
|
||||
```
|
||||
|
||||
Sub Agent 修复后重新发布完成标记,Main Agent 重新验收。
|
||||
|
||||
---
|
||||
|
||||
## 6. 附录
|
||||
|
||||
### 6.1 术语表
|
||||
|
||||
| 术语 | 说明 |
|
||||
|------|------|
|
||||
| **Main Agent** | 编排者,负责任务编排和结果整合 |
|
||||
| **Sub Agent** | 执行者,负责具体实现、审查、测试 |
|
||||
| **deep-interview** | 需求讨论方法,ASK→LISTEN→WRITE→DEEPEN→REPEAT |
|
||||
| **Linus 三问** | 工程审慎决策框架 |
|
||||
| **标准化工作流** | 五阶段:规划→执行→审查→调试→完成 |
|
||||
|
||||
### 6.2 版本历史
|
||||
|
||||
| 版本 | 日期 | 变更 |
|
||||
|------|------|------|
|
||||
| v0.5 | 2026-07-01 | Main Agent + Sub Agents 动态编排 |
|
||||
| v0.5.1 | 2026-07-01 | 补充 Linus 三问 + 标准化工作流 |
|
||||
|
||||
### 6.3 参考资料
|
||||
|
||||
- Superpowers 标准工作流规范
|
||||
- Claude Code Agent 工具文档
|
||||
- Linus Torvalds: "Talk Like a Kernel Developer"
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: v0.5
|
||||
**最后更新**: 2026-07-01
|
||||
**维护者**: Claude Dev
|
||||
@@ -0,0 +1,271 @@
|
||||
# Sub Agent Orchestration 方案
|
||||
|
||||
## 概述
|
||||
|
||||
使用 Main + Sub Agent 架构替代 CCB(Claude Code Blackboard)方案。
|
||||
|
||||
## 架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Main Agent (Planner) │
|
||||
│ - 需求分析、任务拆分、指派 Sub Agent │
|
||||
│ - 收集结果、最终审查、整合 │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
┌──────────────────┐ ┌──────────────────┐
|
||||
│ Sub Agent 1 │ │ Sub Agent 2 │
|
||||
│ (Executor) │ │ (Reviewer) │
|
||||
│ - 执行编码任务 │ │ - 代码审查 │
|
||||
│ - 编写测试 │ │ - 质量检查 │
|
||||
└──────────────────┘ └──────────────────┘
|
||||
```
|
||||
|
||||
## 关键特性
|
||||
|
||||
### 1. 默认隔离
|
||||
|
||||
- **会话历史隔离**:Sub Agent 看不到 Main Agent 的对话
|
||||
- **文件访问共享**:Sub Agent 可以读写项目文件
|
||||
- **工作目录相同**:所有 Agent 在同一项目目录
|
||||
|
||||
### 2. 通信机制
|
||||
|
||||
**Main → Sub**: 通过 `Agent` 工具指派任务
|
||||
```javascript
|
||||
Agent({
|
||||
subagent_type: "executor",
|
||||
prompt: "实现用户认证 API: ..."
|
||||
})
|
||||
```
|
||||
|
||||
**Sub → Main**: 通过返回结果
|
||||
```javascript
|
||||
// Sub Agent 完成后返回结构化结果
|
||||
return {
|
||||
files: ["src/auth.ts", "src/auth.test.ts"],
|
||||
tests: "12/12 通过",
|
||||
status: "完成"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 并行执行
|
||||
|
||||
```javascript
|
||||
// 并行启动多个 Sub Agent
|
||||
Agent({ subagent_type: "executor", prompt: "..." })
|
||||
Agent({ subagent_type: "reviewer", prompt: "..." })
|
||||
```
|
||||
|
||||
## 工作流示例
|
||||
|
||||
### 完整开发流程
|
||||
|
||||
#### 1. Main Agent 接收需求
|
||||
|
||||
```javascript
|
||||
// 用户: "实现用户认证功能"
|
||||
// Main Agent 分析需求
|
||||
```
|
||||
|
||||
#### 2. Main Agent 拆分任务
|
||||
|
||||
```javascript
|
||||
const task = {
|
||||
feature: "用户认证",
|
||||
subtasks: [
|
||||
{ role: "executor", task: "实现 JWT 认证 API" },
|
||||
{ role: "executor", task: "编写单元测试" },
|
||||
{ role: "reviewer", task: "代码审查" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. Main Agent 指派 Sub Agent
|
||||
|
||||
```javascript
|
||||
// 指派 Executor
|
||||
const executorResult = await Agent({
|
||||
subagent_type: "claude",
|
||||
prompt: `
|
||||
作为后端开发专家,实现用户认证 API:
|
||||
1. POST /auth/login - 用户登录
|
||||
2. POST /auth/register - 用户注册
|
||||
3. 使用 bcrypt 和 JWT
|
||||
4. 编写测试
|
||||
返回结构化结果: { files, tests, status }
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
#### 4. Main Agent 收集结果
|
||||
|
||||
```javascript
|
||||
// 指派 Reviewer
|
||||
const reviewResult = await Agent({
|
||||
subagent_type: "claude",
|
||||
prompt: `
|
||||
作为代码审查专家,审查以下文件:
|
||||
${executorResult.files.join(', ')}
|
||||
检查: 代码质量、测试覆盖、安全性
|
||||
返回: { findings, approval }
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
#### 5. Main Agent 整合
|
||||
|
||||
```javascript
|
||||
if (reviewResult.approval) {
|
||||
// 整合代码,提交 Git
|
||||
await整合提交()
|
||||
}
|
||||
```
|
||||
|
||||
## Sub Agent 类型
|
||||
|
||||
### 1. Executor(执行者)
|
||||
|
||||
**职责**:
|
||||
- 编写代码
|
||||
- 编写测试
|
||||
- 实现功能
|
||||
|
||||
**技能**:backend-dev, frontend-dev
|
||||
|
||||
### 2. Reviewer(审查者)
|
||||
|
||||
**职责**:
|
||||
- 代码审查
|
||||
- 质量检查
|
||||
- 安全性验证
|
||||
|
||||
**技能**:CODE-REVIEW, test-automation-skills
|
||||
|
||||
### 3. Planner(规划者 - Main)
|
||||
|
||||
**职责**:
|
||||
- 需求分析
|
||||
- 任务拆分
|
||||
- 资源协调
|
||||
- 最终验收
|
||||
|
||||
## 优势对比 CCB
|
||||
|
||||
| 特性 | Main+Sub | CCB |
|
||||
|------|----------|-----|
|
||||
| 会话隔离 | ✅ 默认 | ⚠️ 需手动管理 |
|
||||
| 通信机制 | Agent 工具 | Blackboard |
|
||||
| 并行执行 | ✅ 支持 | ⚠️ 复杂 |
|
||||
| 上下文共享 | 通过文件 | 通过 Blackboard |
|
||||
| 学习成本 | 🟢 低 | 🟡 中 |
|
||||
|
||||
## 实施步骤
|
||||
|
||||
### 步骤 1: 定义 Sub Agent 类型
|
||||
|
||||
在项目 `.claude/` 目录创建配置:
|
||||
|
||||
```json
|
||||
{
|
||||
"subAgents": {
|
||||
"executor": {
|
||||
"description": "执行编码任务",
|
||||
"skills": ["backend-dev", "frontend-dev"]
|
||||
},
|
||||
"reviewer": {
|
||||
"description": "代码审查",
|
||||
"skills": ["CODE-REVIEW", "qa-test-planner"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 步骤 2: Main Agent 加载协调技能
|
||||
|
||||
```bash
|
||||
# Main Agent 启动时加载
|
||||
/skill architect-role
|
||||
```
|
||||
|
||||
### 步骤 3: 工作流脚本
|
||||
|
||||
创建 `.claude/workflows/` 目录:
|
||||
|
||||
```javascript
|
||||
// workflows/feature-development.js
|
||||
export default {
|
||||
name: "feature-development",
|
||||
run: async (feature) => {
|
||||
// 1. 分析
|
||||
const plan = await分析需求(feature)
|
||||
|
||||
// 2. 指派执行
|
||||
const result = await Agent({
|
||||
subagent_type: "executor",
|
||||
prompt: plan.executorTask
|
||||
})
|
||||
|
||||
// 3. 审查
|
||||
const review = await Agent({
|
||||
subagent_type: "reviewer",
|
||||
prompt: `审查: ${result.files}`
|
||||
})
|
||||
|
||||
// 4. 整合
|
||||
return 整合结果(result, review)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 命名规范
|
||||
|
||||
- Main Agent: `main` 或 `planner`
|
||||
- Sub Agent: `executor`, `reviewer`, 或具体任务名
|
||||
- Agent ID: 自动生成,格式 `a_<random>`
|
||||
|
||||
## 调试和监控
|
||||
|
||||
### 查看 Sub Agent 状态
|
||||
|
||||
```bash
|
||||
# 列出当前运行的所有 Agent
|
||||
/agents
|
||||
|
||||
# 查看 Sub Agent 输出
|
||||
Agent({ subagent_type: "executor", prompt: "..." })
|
||||
// 返回 agentId,可以用 TaskOutput 查看输出
|
||||
```
|
||||
|
||||
### Sub Agent 输出结构
|
||||
|
||||
```javascript
|
||||
{
|
||||
"agentId": "a_123abc",
|
||||
"status": "completed",
|
||||
"result": {
|
||||
"files": ["src/auth.ts"],
|
||||
"tests": "12/12 通过"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 局限性
|
||||
|
||||
1. **Sub Agent 无法主动通信**:只能通过返回值
|
||||
2. **无持久化 Blackboard**:需要用文件共享状态
|
||||
3. **Agent 数量限制**:系统限制最大并发数
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **明确任务边界**:每个 Sub Agent 职责单一
|
||||
2. **结构化返回**:使用 JSON 格式返回结果
|
||||
3. **文件作为状态**:用文件存储中间状态
|
||||
4. **Main 协调一切**:Sub Agent 只执行任务
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [Agent 工具文档](https://docs.anthropic.com/claude-code/agent)
|
||||
- [设计文档](./design/04-design-v0.4.md)
|
||||
- [示例工作流](./05-example-workflows.md)
|
||||
Executable
+238
@@ -0,0 +1,238 @@
|
||||
#!/bin/bash
|
||||
# sanguo_moziplus_v3 v0.5 初始化脚本
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
# 颜色定义
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo -e "${GREEN}=== sanguo_moziplus_v3 v0.5 初始化 ===${NC}"
|
||||
|
||||
# 1. 检查环境
|
||||
echo -e "\n${BLUE}1. 检查环境...${NC}"
|
||||
|
||||
if ! command -v claude &> /dev/null; then
|
||||
echo -e "${RED}❌ Claude Code 未安装${NC}"
|
||||
echo "请先安装 Claude Code: https://claude.ai/code"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✅ Claude Code 已安装${NC}"
|
||||
|
||||
if ! command -v git &> /dev/null; then
|
||||
echo -e "${RED}❌ Git 未安装${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✅ Git 已安装${NC}"
|
||||
|
||||
# Node.js 是可选的(用于运行 JS 工作流)
|
||||
if command -v node &> /dev/null; then
|
||||
echo -e "${GREEN}✅ Node.js 已安装: $(node --version)${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ Node.js 未安装 (可选,用于运行 JavaScript 工作流)${NC}"
|
||||
fi
|
||||
|
||||
# 2. 创建必要目录
|
||||
echo -e "\n${BLUE}2. 创建目录...${NC}"
|
||||
mkdir -p "$PROJECT_DIR/.claude/workflows/helpers"
|
||||
mkdir -p "$PROJECT_DIR/scripts"
|
||||
echo -e "${GREEN}✅ 目录创建完成${NC}"
|
||||
|
||||
# 3. 检查配置文件
|
||||
echo -e "\n${BLUE}3. 检查配置文件...${NC}"
|
||||
|
||||
if [ ! -f "$PROJECT_DIR/.claude/gitea-config.json" ]; then
|
||||
echo -e "${YELLOW}⚠️ gitea-config.json 不存在${NC}"
|
||||
echo "创建默认配置..."
|
||||
cat > "$PROJECT_DIR/.claude/gitea-config.json" << 'EOF'
|
||||
{
|
||||
"gitea": {
|
||||
"baseUrl": "http://192.168.2.154:3000",
|
||||
"owner": "sanguo",
|
||||
"repo": "sanguo_moziplus_v3",
|
||||
"defaultBranch": "main"
|
||||
},
|
||||
"rules": {
|
||||
"branchNaming": {
|
||||
"feature": "feature/{task-name}",
|
||||
"fix": "fix/{issue-number}-{description}",
|
||||
"hotfix": "hotfix/{description}"
|
||||
},
|
||||
"commitNaming": {
|
||||
"feature": "feat: {description}",
|
||||
"fix": "fix: {description}",
|
||||
"refactor": "refactor: {description}",
|
||||
"docs": "docs: {description}",
|
||||
"test": "test: {description}"
|
||||
},
|
||||
"prTemplate": {
|
||||
"title": "{task-type}: {description}",
|
||||
"description": "## 任务\n\n{task-description}\n\n## 技术方案\n\n{approach}\n\n## 实现内容\n\n{changes}\n\n## 测试\n\n{tests}"
|
||||
}
|
||||
},
|
||||
"review": {
|
||||
"checklist": [
|
||||
"代码质量",
|
||||
"安全性",
|
||||
"性能",
|
||||
"测试覆盖",
|
||||
"文档完整性"
|
||||
],
|
||||
"approval": "至少 2 个 Reviewer 通过"
|
||||
},
|
||||
"agents": {
|
||||
"main": {
|
||||
"role": "编排者",
|
||||
"responsibilities": [
|
||||
"分析任务",
|
||||
"安排 Sub Agents",
|
||||
"验收整合",
|
||||
"合并 PR"
|
||||
]
|
||||
},
|
||||
"execute": {
|
||||
"role": "执行者",
|
||||
"responsibilities": [
|
||||
"实现功能",
|
||||
"编写测试",
|
||||
"创建 PR"
|
||||
],
|
||||
"skills": ["backend-dev", "frontend-dev"]
|
||||
},
|
||||
"review": {
|
||||
"role": "审查者",
|
||||
"responsibilities": [
|
||||
"代码审查",
|
||||
"添加 Review 评论",
|
||||
"提供修改建议"
|
||||
],
|
||||
"skills": ["CODE-REVIEW", "security-reviewer"]
|
||||
},
|
||||
"test": {
|
||||
"role": "测试者",
|
||||
"responsibilities": [
|
||||
"编写测试",
|
||||
"执行测试",
|
||||
"验证修复"
|
||||
],
|
||||
"skills": ["test-engineer", "e2e-tester"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
echo -e "${GREEN}✅ 已创建默认配置${NC}"
|
||||
echo -e "${YELLOW}⚠️ 请编辑 .claude/gitea-config.json 配置你的 Gitea 信息${NC}"
|
||||
else
|
||||
echo -e "${GREEN}✅ gitea-config.json 已存在${NC}"
|
||||
fi
|
||||
|
||||
# 4. 检查 Claude Code 配置
|
||||
echo -e "\n${BLUE}4. 检查 Claude Code 配置...${NC}"
|
||||
|
||||
if [ ! -f "$HOME/.claude/settings.json" ]; then
|
||||
echo -e "${YELLOW}⚠️ ~/.claude/settings.json 不存在${NC}"
|
||||
echo "请配置 GLM-5.2 端点:"
|
||||
echo ""
|
||||
cat << 'EOF'
|
||||
{
|
||||
"env": {
|
||||
"CLAUDE_CODE_AUTO_COMPACT_WINDOW": "1000000",
|
||||
"ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic",
|
||||
"ANTHROPIC_API_KEY": "你的智谱API_Key",
|
||||
"ANTHROPIC_DEFAULT_SONNET_MODEL": "glm-5.2[1m]",
|
||||
"ANTHROPIC_DEFAULT_OPUS_MODEL": "glm-5.2[1m]"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
echo ""
|
||||
echo "创建配置文件:"
|
||||
echo " mkdir -p ~/.claude"
|
||||
echo " vim ~/.claude/settings.json"
|
||||
else
|
||||
echo -e "${GREEN}✅ ~/.claude/settings.json 已存在${NC}"
|
||||
fi
|
||||
|
||||
# 5. 读取并显示 Gitea 配置
|
||||
echo -e "\n${BLUE}5. Gitea 配置...${NC}"
|
||||
|
||||
if [ -f "$PROJECT_DIR/.claude/gitea-config.json" ]; then
|
||||
if command -v node &> /dev/null; then
|
||||
GITEA_CONFIG=$(node -e "
|
||||
const fs = require('fs');
|
||||
const config = JSON.parse(fs.readFileSync('$PROJECT_DIR/.claude/gitea-config.json', 'utf-8'));
|
||||
console.log(' Base URL: ' + config.gitea.baseUrl);
|
||||
console.log(' Owner: ' + config.gitea.owner);
|
||||
console.log(' Repository: ' + config.gitea.repo);
|
||||
console.log(' 主分支: ' + config.gitea.defaultBranch);
|
||||
" 2>/dev/null || echo " 无法解析配置文件")
|
||||
echo -e "$GITEA_CONFIG"
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ 需要 Node.js 来解析配置${NC}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 6. 测试 Git 连接
|
||||
echo -e "\n${BLUE}6. 测试 Git 连接...${NC}"
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
if git remote -v &> /dev/null; then
|
||||
echo "Git 远程仓库:"
|
||||
git remote -v
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ 没有配置 Git 远程仓库${NC}"
|
||||
echo "添加远程仓库:"
|
||||
echo " git remote add origin <your-gitea-url>"
|
||||
fi
|
||||
|
||||
# 7. 检查 Superpowers Skills
|
||||
echo -e "\n${BLUE}7. 检查 Superpowers Skills...${NC}"
|
||||
|
||||
SKILLS_DIR="$HOME/.claude/skills"
|
||||
if [ -d "$SKILLS_DIR" ]; then
|
||||
SKILL_COUNT=$(ls -1 "$SKILLS_DIR" 2>/dev/null | wc -l)
|
||||
echo -e "${GREEN}✅ Superpowers Skills 已安装: $SKILL_COUNT 个技能${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ Superpowers Skills 未安装${NC}"
|
||||
echo "请从 Superpowers Marketplace 安装所需技能"
|
||||
fi
|
||||
|
||||
# 8. 验证工作流文件
|
||||
echo -e "\n${BLUE}8. 验证工作流文件...${NC}"
|
||||
|
||||
WORKFLOW_FILES=(
|
||||
".claude/workflows/gitea-orchestration.js"
|
||||
".claude/workflows/helpers/gitea-rules-generator.js"
|
||||
)
|
||||
|
||||
for file in "${WORKFLOW_FILES[@]}"; do
|
||||
if [ -f "$PROJECT_DIR/$file" ]; then
|
||||
echo -e "${GREEN}✅ $file${NC}"
|
||||
else
|
||||
echo -e "${RED}❌ $file 不存在${NC}"
|
||||
fi
|
||||
done
|
||||
|
||||
# 完成
|
||||
echo -e "\n${GREEN}=== 初始化完成 ===${NC}"
|
||||
echo ""
|
||||
echo -e "${BLUE}下一步操作:${NC}"
|
||||
echo "1. 编辑配置 (如需要):"
|
||||
echo " vim .claude/gitea-config.json"
|
||||
echo ""
|
||||
echo "2. 启动 Claude Code:"
|
||||
echo " cd $PROJECT_DIR"
|
||||
echo " claude"
|
||||
echo ""
|
||||
echo "3. 测试工作流:"
|
||||
echo " 在 Claude Code 中运行:"
|
||||
echo " Workflow({ scriptPath: '.claude/workflows/gitea-orchestration.js', args: '测试任务' })"
|
||||
echo ""
|
||||
echo -e "${BLUE}相关文档:${NC}"
|
||||
echo "- 部署指南: docs/deployment-v0.5.md"
|
||||
echo "- 设计文档: docs/design/06-design-v0.5-dynamic-orchestration.md"
|
||||
Reference in New Issue
Block a user