feat: Add 4 new team skills with Generator-Critic loops, shared memory, and dynamic pipelines

Create team-brainstorm (ideator↔challenger GC, quick/deep/full pipelines),
team-testing (generator↔executor GC, L1/L2/L3 test layers),
team-iterdev (developer↔reviewer GC, task-ledger sprint tracking),
and team-uidesign (designer↔reviewer GC, CP-9 dual-track with sync points).
Each team includes SKILL.md router, 5 roles, and team-config.json.
This commit is contained in:
catlog22
2026-02-15 18:09:57 +08:00
parent 29ad3b0558
commit 0d56396710
28 changed files with 6576 additions and 0 deletions

View File

@@ -0,0 +1,356 @@
---
name: team-brainstorm
description: Unified team skill for brainstorming team. All roles invoke this skill with --role arg for role-specific execution. Triggers on "team brainstorm".
allowed-tools: TeamCreate(*), TeamDelete(*), SendMessage(*), TaskCreate(*), TaskUpdate(*), TaskList(*), TaskGet(*), Task(*), AskUserQuestion(*), Read(*), Write(*), Edit(*), Bash(*), Glob(*), Grep(*)
---
# Team Brainstorm
头脑风暴团队技能。通过 Generator-Critic 循环、共享记忆和动态管道选择,实现多角度创意发散、挑战验证和收敛筛选。所有团队成员通过 `--role=xxx` 路由到角色执行逻辑。
## Architecture Overview
```
┌───────────────────────────────────────────────────┐
│ Skill(skill="team-brainstorm", args="--role=xxx") │
└───────────────────┬───────────────────────────────┘
│ Role Router
┌───────────┬───┼───────────┬───────────┐
↓ ↓ ↓ ↓ ↓
┌──────────┐┌───────┐┌──────────┐┌──────────┐┌─────────┐
│coordinator││ideator││challenger││synthesizer││evaluator│
│ roles/ ││roles/ ││ roles/ ││ roles/ ││ roles/ │
└──────────┘└───────┘└──────────┘└──────────┘└─────────┘
```
## Role Router
### Input Parsing
Parse `$ARGUMENTS` to extract `--role`:
```javascript
const args = "$ARGUMENTS"
const roleMatch = args.match(/--role[=\s]+(\w+)/)
if (!roleMatch) {
throw new Error("Missing --role argument. Available roles: coordinator, ideator, challenger, synthesizer, evaluator")
}
const role = roleMatch[1]
const teamName = args.match(/--team[=\s]+([\w-]+)/)?.[1] || "brainstorm"
```
### Role Dispatch
```javascript
const VALID_ROLES = {
"coordinator": { file: "roles/coordinator.md", prefix: null },
"ideator": { file: "roles/ideator.md", prefix: "IDEA" },
"challenger": { file: "roles/challenger.md", prefix: "CHALLENGE" },
"synthesizer": { file: "roles/synthesizer.md", prefix: "SYNTH" },
"evaluator": { file: "roles/evaluator.md", prefix: "EVAL" }
}
if (!VALID_ROLES[role]) {
throw new Error(`Unknown role: ${role}. Available: ${Object.keys(VALID_ROLES).join(', ')}`)
}
// Read and execute role-specific logic
Read(VALID_ROLES[role].file)
// → Execute the 5-phase process defined in that file
```
### Available Roles
| Role | Task Prefix | Responsibility | Role File |
|------|-------------|----------------|-----------|
| `coordinator` | N/A | 话题澄清、复杂度评估、管道选择、收敛监控 | [roles/coordinator.md](roles/coordinator.md) |
| `ideator` | IDEA-* | 多角度创意生成、概念探索、发散思维 | [roles/ideator.md](roles/ideator.md) |
| `challenger` | CHALLENGE-* | 魔鬼代言人、假设挑战、可行性质疑 | [roles/challenger.md](roles/challenger.md) |
| `synthesizer` | SYNTH-* | 跨想法整合、主题提取、冲突解决 | [roles/synthesizer.md](roles/synthesizer.md) |
| `evaluator` | EVAL-* | 评分排序、优先级推荐、最终筛选 | [roles/evaluator.md](roles/evaluator.md) |
## Shared Infrastructure
### Role Isolation Rules
**核心原则**: 每个角色仅能执行自己职责范围内的工作。
#### Output Tagging强制
所有角色的输出必须带 `[role_name]` 标识前缀:
```javascript
// SendMessage — content 和 summary 都必须带标识
SendMessage({
content: `## [${role}] ...`,
summary: `[${role}] ...`
})
// team_msg — summary 必须带标识
mcp__ccw-tools__team_msg({
summary: `[${role}] ...`
})
```
#### Coordinator 隔离
| 允许 | 禁止 |
|------|------|
| 需求澄清 (AskUserQuestion) | ❌ 直接生成创意 |
| 创建任务链 (TaskCreate) | ❌ 直接评估/挑战想法 |
| 分发任务给 worker | ❌ 直接执行分析/综合 |
| 监控进度 (消息总线) | ❌ 绕过 worker 自行完成任务 |
| 汇报结果给用户 | ❌ 修改源代码或产物文件 |
#### Worker 隔离
| 允许 | 禁止 |
|------|------|
| 处理自己前缀的任务 | ❌ 处理其他角色前缀的任务 |
| SendMessage 给 coordinator | ❌ 直接与其他 worker 通信 |
| 读取 shared-memory.json | ❌ 为其他角色创建任务 (TaskCreate) |
| 写入 shared-memory.json (自己的字段) | ❌ 修改不属于本职责的资源 |
### Team Configuration
```javascript
const TEAM_CONFIG = {
name: "brainstorm",
sessionDir: ".workflow/.team/BRS-{slug}-{date}/",
msgDir: ".workflow/.team-msg/brainstorm/",
sharedMemory: "shared-memory.json"
}
```
### Shared Memory (创新模式)
所有角色在 Phase 2 读取、Phase 5 写入 `shared-memory.json`
```javascript
// Phase 2: 读取共享记忆
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
// Phase 5: 写入共享记忆(仅更新自己负责的字段)
// ideator → sharedMemory.generated_ideas
// challenger → sharedMemory.critique_insights
// synthesizer → sharedMemory.synthesis_themes
// evaluator → sharedMemory.evaluation_scores
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
```
### Message Bus (All Roles)
Every SendMessage **before**, must call `mcp__ccw-tools__team_msg` to log:
```javascript
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: role,
to: "coordinator",
type: "<type>",
summary: `[${role}] <summary>`,
ref: "<file_path>"
})
```
**Message types by role**:
| Role | Types |
|------|-------|
| coordinator | `pipeline_selected`, `gc_loop_trigger`, `task_unblocked`, `error`, `shutdown` |
| ideator | `ideas_ready`, `ideas_revised`, `error` |
| challenger | `critique_ready`, `error` |
| synthesizer | `synthesis_ready`, `error` |
| evaluator | `evaluation_ready`, `error` |
### CLI Fallback
When `mcp__ccw-tools__team_msg` MCP is unavailable:
```javascript
Bash(`ccw team log --team "${teamName}" --from "${role}" --to "coordinator" --type "<type>" --summary "<summary>" --json`)
```
### Task Lifecycle (All Worker Roles)
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith(`${VALID_ROLES[role].prefix}-`) &&
t.owner === role &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (myTasks.length === 0) return // idle
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
// Phase 2-4: Role-specific (see roles/{role}.md)
// Phase 5: Report + Loop — 所有输出必须带 [role] 标识
mcp__ccw-tools__team_msg({ operation: "log", team: teamName, from: role, to: "coordinator", type: "...", summary: `[${role}] ...` })
SendMessage({ type: "message", recipient: "coordinator", content: `## [${role}] ...`, summary: `[${role}] ...` })
TaskUpdate({ taskId: task.id, status: 'completed' })
// Check for next task → back to Phase 1
```
## Three-Pipeline Architecture
```
Quick:
IDEA-001 → CHALLENGE-001 → SYNTH-001
Deep (Generator-Critic Loop):
IDEA-001 → CHALLENGE-001 → IDEA-002(fix) → CHALLENGE-002 → SYNTH-001 → EVAL-001
Full (Fan-out + Generator-Critic):
[IDEA-001 + IDEA-002 + IDEA-003](parallel) → CHALLENGE-001(batch) → IDEA-004(fix) → SYNTH-001 → EVAL-001
```
### Generator-Critic Loop
ideator ↔ challenger 循环最多2轮
```
IDEA → CHALLENGE → (if critique.severity >= HIGH) → IDEA-fix → CHALLENGE-2 → SYNTH
(if critique.severity < HIGH) → SYNTH
```
## Unified Session Directory
```
.workflow/.team/BRS-{slug}-{YYYY-MM-DD}/
├── team-session.json # Session state
├── shared-memory.json # 累积: generated_ideas / critique_insights / synthesis_themes / evaluation_scores
├── ideas/ # Ideator output
│ ├── idea-001.md
│ ├── idea-002.md
│ └── idea-003.md
├── critiques/ # Challenger output
│ ├── critique-001.md
│ └── critique-002.md
├── synthesis/ # Synthesizer output
│ └── synthesis-001.md
└── evaluation/ # Evaluator output
└── evaluation-001.md
```
## Coordinator Spawn Template
```javascript
TeamCreate({ team_name: teamName })
// Ideator
Task({
subagent_type: "general-purpose",
team_name: teamName,
name: "ideator",
prompt: `你是 team "${teamName}" 的 IDEATOR。
当你收到 IDEA-* 任务时,调用 Skill(skill="team-brainstorm", args="--role=ideator") 执行。
当前话题: ${taskDescription}
约束: ${constraints}
## 角色准则(强制)
- 你只能处理 IDEA-* 前缀的任务,不得执行其他角色的工作
- 所有输出SendMessage、team_msg必须带 [ideator] 标识前缀
- 仅与 coordinator 通信,不得直接联系其他 worker
- 不得使用 TaskCreate 为其他角色创建任务
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 IDEA-* 任务
2. Skill(skill="team-brainstorm", args="--role=ideator") 执行
3. team_msg log + SendMessage 结果给 coordinator带 [ideator] 标识)
4. TaskUpdate completed → 检查下一个任务`
})
// Challenger
Task({
subagent_type: "general-purpose",
team_name: teamName,
name: "challenger",
prompt: `你是 team "${teamName}" 的 CHALLENGER。
当你收到 CHALLENGE-* 任务时,调用 Skill(skill="team-brainstorm", args="--role=challenger") 执行。
当前话题: ${taskDescription}
## 角色准则(强制)
- 你只能处理 CHALLENGE-* 前缀的任务
- 所有输出必须带 [challenger] 标识前缀
- 仅与 coordinator 通信
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 CHALLENGE-* 任务
2. Skill(skill="team-brainstorm", args="--role=challenger") 执行
3. team_msg log + SendMessage 结果给 coordinator带 [challenger] 标识)
4. TaskUpdate completed → 检查下一个任务`
})
// Synthesizer
Task({
subagent_type: "general-purpose",
team_name: teamName,
name: "synthesizer",
prompt: `你是 team "${teamName}" 的 SYNTHESIZER。
当你收到 SYNTH-* 任务时,调用 Skill(skill="team-brainstorm", args="--role=synthesizer") 执行。
当前话题: ${taskDescription}
## 角色准则(强制)
- 你只能处理 SYNTH-* 前缀的任务
- 所有输出必须带 [synthesizer] 标识前缀
- 仅与 coordinator 通信
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 SYNTH-* 任务
2. Skill(skill="team-brainstorm", args="--role=synthesizer") 执行
3. team_msg log + SendMessage 结果给 coordinator带 [synthesizer] 标识)
4. TaskUpdate completed → 检查下一个任务`
})
// Evaluator
Task({
subagent_type: "general-purpose",
team_name: teamName,
name: "evaluator",
prompt: `你是 team "${teamName}" 的 EVALUATOR。
当你收到 EVAL-* 任务时,调用 Skill(skill="team-brainstorm", args="--role=evaluator") 执行。
当前话题: ${taskDescription}
## 角色准则(强制)
- 你只能处理 EVAL-* 前缀的任务
- 所有输出必须带 [evaluator] 标识前缀
- 仅与 coordinator 通信
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 EVAL-* 任务
2. Skill(skill="team-brainstorm", args="--role=evaluator") 执行
3. team_msg log + SendMessage 结果给 coordinator带 [evaluator] 标识)
4. TaskUpdate completed → 检查下一个任务`
})
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| Unknown --role value | Error with available role list |
| Missing --role arg | Error with usage hint |
| Role file not found | Error with expected path (roles/{name}.md) |
| Task prefix conflict | Log warning, proceed |
| Generator-Critic loop exceeds 2 rounds | Force convergence → SYNTH |
| No ideas generated | Coordinator prompts with seed questions |

View File

@@ -0,0 +1,208 @@
# Role: challenger
魔鬼代言人角色。负责假设挑战、可行性质疑、风险识别。作为 Generator-Critic 循环中的 Critic 角色。
## Role Identity
- **Name**: `challenger`
- **Task Prefix**: `CHALLENGE-*`
- **Responsibility**: Read-only analysis (批判性分析)
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[challenger]`
## Role Boundaries
### MUST
- 仅处理 `CHALLENGE-*` 前缀的任务
- 所有输出必须带 `[challenger]` 标识
- 仅通过 SendMessage 与 coordinator 通信
- Phase 2 读取 shared-memory.jsonPhase 5 写入 critique_insights
- 为每个创意标记挑战严重度 (LOW/MEDIUM/HIGH/CRITICAL)
### MUST NOT
- ❌ 生成创意、综合想法或评估排序
- ❌ 直接与其他 worker 角色通信
- ❌ 为其他角色创建任务
- ❌ 修改 shared-memory.json 中不属于自己的字段
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `critique_ready` | challenger → coordinator | Critique completed | 挑战分析完成 |
| `error` | challenger → coordinator | Processing failure | 错误上报 |
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('CHALLENGE-') &&
t.owner === 'challenger' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
```
### Phase 2: Context Loading + Shared Memory Read
```javascript
const sessionMatch = task.description.match(/Session:\s*([^\n]+)/)
const sessionFolder = sessionMatch?.[1]?.trim()
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
// Read all idea files referenced in task
const ideaFiles = Glob({ pattern: `${sessionFolder}/ideas/*.md` })
const ideas = ideaFiles.map(f => Read(f))
// Read previous critiques for context (avoid repeating)
const prevCritiques = sharedMemory.critique_insights || []
```
### Phase 3: Critical Analysis
```javascript
// For each idea, apply 4 challenge dimensions:
// 1. Assumption Validity — 核心假设是否成立?有什么反例?
// 2. Feasibility — 技术/资源/时间上是否可行?
// 3. Risk Assessment — 最坏情况是什么?有什么隐藏风险?
// 4. Competitive Analysis — 已有更好的替代方案吗?
// Severity classification:
// LOW — Minor concern, does not invalidate the idea
// MEDIUM — Notable weakness, needs consideration
// HIGH — Significant flaw, requires revision
// CRITICAL — Fundamental issue, idea may need replacement
const challengeNum = task.subject.match(/CHALLENGE-(\d+)/)?.[1] || '001'
const outputPath = `${sessionFolder}/critiques/critique-${challengeNum}.md`
const critiqueContent = `# Critique — Round ${challengeNum}
**Ideas Reviewed**: ${ideas.length} files
**Challenge Dimensions**: Assumption Validity, Feasibility, Risk, Competition
## Challenges
${challenges.map((c, i) => `### Idea: ${c.ideaTitle}
**Severity**: ${c.severity}
| Dimension | Finding |
|-----------|---------|
| Assumption Validity | ${c.assumption} |
| Feasibility | ${c.feasibility} |
| Risk Assessment | ${c.risk} |
| Competitive Analysis | ${c.competition} |
**Key Challenge**: ${c.keyChallenge}
**Suggested Direction**: ${c.suggestion}
`).join('\n')}
## Summary
| Severity | Count |
|----------|-------|
| CRITICAL | ${challenges.filter(c => c.severity === 'CRITICAL').length} |
| HIGH | ${challenges.filter(c => c.severity === 'HIGH').length} |
| MEDIUM | ${challenges.filter(c => c.severity === 'MEDIUM').length} |
| LOW | ${challenges.filter(c => c.severity === 'LOW').length} |
**Generator-Critic Signal**: ${
challenges.some(c => c.severity === 'CRITICAL' || c.severity === 'HIGH')
? 'REVISION_NEEDED — Critical/High issues require ideator revision'
: 'CONVERGED — No critical issues, ready for synthesis'
}
`
Write(outputPath, critiqueContent)
```
### Phase 4: Severity Summary
```javascript
// Aggregate severity counts for coordinator decision
const severitySummary = {
critical: challenges.filter(c => c.severity === 'CRITICAL').length,
high: challenges.filter(c => c.severity === 'HIGH').length,
medium: challenges.filter(c => c.severity === 'MEDIUM').length,
low: challenges.filter(c => c.severity === 'LOW').length,
signal: (challenges.some(c => c.severity === 'CRITICAL' || c.severity === 'HIGH'))
? 'REVISION_NEEDED' : 'CONVERGED'
}
```
### Phase 5: Report to Coordinator + Shared Memory Write
```javascript
// Update shared memory
sharedMemory.critique_insights = [
...sharedMemory.critique_insights,
...challenges.map(c => ({
idea: c.ideaTitle,
severity: c.severity,
key_challenge: c.keyChallenge,
round: parseInt(challengeNum)
}))
]
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: "challenger",
to: "coordinator",
type: "critique_ready",
summary: `[challenger] Critique complete: ${severitySummary.critical}C/${severitySummary.high}H/${severitySummary.medium}M/${severitySummary.low}L — Signal: ${severitySummary.signal}`,
ref: outputPath
})
SendMessage({
type: "message",
recipient: "coordinator",
content: `## [challenger] Critique Results
**Task**: ${task.subject}
**Signal**: ${severitySummary.signal}
**Severity**: ${severitySummary.critical} Critical, ${severitySummary.high} High, ${severitySummary.medium} Medium, ${severitySummary.low} Low
**Output**: ${outputPath}
${severitySummary.signal === 'REVISION_NEEDED'
? '### Requires Revision\n' + challenges.filter(c => ['CRITICAL', 'HIGH'].includes(c.severity)).map(c => `- **${c.ideaTitle}** (${c.severity}): ${c.keyChallenge}`).join('\n')
: '### All Clear — Ready for Synthesis'}`,
summary: `[challenger] Critique: ${severitySummary.signal}`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
// Check for next task
const nextTasks = TaskList().filter(t =>
t.subject.startsWith('CHALLENGE-') &&
t.owner === 'challenger' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (nextTasks.length > 0) {
// back to Phase 1
}
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| No CHALLENGE-* tasks | Idle, wait for assignment |
| Ideas file not found | Notify coordinator |
| All ideas trivially good | Mark all LOW, signal CONVERGED |
| Cannot assess feasibility | Mark MEDIUM with note, suggest deeper analysis |

View File

@@ -0,0 +1,304 @@
# Role: coordinator
头脑风暴团队协调者。负责话题澄清、复杂度评估、管道选择、Generator-Critic 循环控制和收敛监控。
## Role Identity
- **Name**: `coordinator`
- **Task Prefix**: N/A (coordinator creates tasks, doesn't receive them)
- **Responsibility**: Orchestration
- **Communication**: SendMessage to all teammates
- **Output Tag**: `[coordinator]`
## Role Boundaries
### MUST
- 所有输出SendMessage、team_msg、日志必须带 `[coordinator]` 标识
- 仅负责话题澄清、任务创建/分发、进度监控、结果汇报
- 通过 TaskCreate 创建任务并分配给 worker 角色
- 通过消息总线监控 worker 进度并路由消息
- 管理 Generator-Critic 循环计数,决定是否继续迭代
### MUST NOT
-**直接生成创意、挑战假设、综合想法或评估排序**
- ❌ 直接调用实现类 subagent
- ❌ 直接修改产物文件ideas/*.md, critiques/*.md 等)
- ❌ 绕过 worker 角色自行完成应委派的工作
- ❌ 在输出中省略 `[coordinator]` 标识
> **核心原则**: coordinator 是指挥者,不是执行者。所有实际工作必须通过 TaskCreate 委派给 worker 角色。
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `pipeline_selected` | coordinator → all | Pipeline decided | Notify selected pipeline mode |
| `gc_loop_trigger` | coordinator → ideator | Critique severity >= HIGH | Trigger ideator to revise |
| `task_unblocked` | coordinator → any | Dependency resolved | Notify worker of available task |
| `error` | coordinator → all | Critical system error | Escalation to user |
| `shutdown` | coordinator → all | Team being dissolved | Clean shutdown signal |
## Execution
### Phase 1: Topic Clarification + Complexity Assessment
```javascript
const args = "$ARGUMENTS"
const teamNameMatch = args.match(/--team-name[=\s]+([\w-]+)/)
const teamName = teamNameMatch ? teamNameMatch[1] : `brainstorm-${Date.now().toString(36)}`
const taskDescription = args.replace(/--team-name[=\s]+[\w-]+/, '').replace(/--role[=\s]+\w+/, '').trim()
```
Assess topic complexity and select pipeline:
```javascript
function assessComplexity(topic) {
let score = 0
if (/strategy|architecture|system|framework|paradigm/.test(topic)) score += 3
if (/multiple|compare|tradeoff|versus|alternative/.test(topic)) score += 2
if (/innovative|creative|novel|breakthrough/.test(topic)) score += 2
if (/simple|quick|straightforward|basic/.test(topic)) score -= 2
return score >= 4 ? 'high' : score >= 2 ? 'medium' : 'low'
}
const complexity = assessComplexity(taskDescription)
```
```javascript
AskUserQuestion({
questions: [
{
question: "选择头脑风暴模式:",
header: "Mode",
multiSelect: false,
options: [
{ label: complexity === 'low' ? "quick (推荐)" : "quick", description: "快速模式创意→挑战→综合3步" },
{ label: complexity === 'medium' ? "deep (推荐)" : "deep", description: "深度模式:含 Generator-Critic 循环6步" },
{ label: complexity === 'high' ? "full (推荐)" : "full", description: "完整模式:并行发散 + 循环 + 评估7步" }
]
},
{
question: "创意发散角度:",
header: "Angles",
multiSelect: true,
options: [
{ label: "技术视角", description: "技术可行性、实现方案、架构设计" },
{ label: "产品视角", description: "用户需求、市场定位、商业模式" },
{ label: "创新视角", description: "颠覆性思路、跨领域借鉴、未来趋势" },
{ label: "风险视角", description: "潜在问题、约束条件、替代方案" }
]
}
]
})
```
### Phase 2: Create Team + Spawn Workers
```javascript
TeamCreate({ team_name: teamName })
const topicSlug = taskDescription.toLowerCase().replace(/[^a-z0-9]+/g, '-').substring(0, 40)
const dateStr = new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString().substring(0, 10)
const sessionId = `BRS-${topicSlug}-${dateStr}`
const sessionFolder = `.workflow/.team/${sessionId}`
Bash(`mkdir -p "${sessionFolder}/ideas" "${sessionFolder}/critiques" "${sessionFolder}/synthesis" "${sessionFolder}/evaluation"`)
// Initialize shared memory
const sharedMemory = {
topic: taskDescription,
pipeline: selectedPipeline,
angles: selectedAngles,
gc_round: 0,
max_gc_rounds: 2,
generated_ideas: [],
critique_insights: [],
synthesis_themes: [],
evaluation_scores: []
}
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
// Create team-session.json
const teamSession = {
session_id: sessionId,
team_name: teamName,
topic: taskDescription,
pipeline: selectedPipeline,
status: "active",
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
gc_round: 0,
completed_tasks: []
}
Write(`${sessionFolder}/team-session.json`, JSON.stringify(teamSession, null, 2))
```
Spawn workers (see SKILL.md Coordinator Spawn Template).
### Phase 3: Create Task Chain
Task chain depends on the selected pipeline.
#### Quick Pipeline
```javascript
// IDEA-001: 创意生成
TaskCreate({ subject: "IDEA-001: 多角度创意生成", description: `话题: ${taskDescription}\n\nSession: ${sessionFolder}\n角度: ${selectedAngles.join(', ')}\n输出: ${sessionFolder}/ideas/idea-001.md\n\n要求: 每个角度至少产出3个创意总计不少于6个`, activeForm: "生成创意中" })
TaskUpdate({ taskId: ideaId, owner: "ideator" })
// CHALLENGE-001: 挑战质疑 (blockedBy IDEA-001)
TaskCreate({ subject: "CHALLENGE-001: 假设挑战与可行性质疑", description: `对 IDEA-001 的创意进行批判性分析\n\nSession: ${sessionFolder}\n输入: ${sessionFolder}/ideas/idea-001.md\n输出: ${sessionFolder}/critiques/critique-001.md\n\n要求: 标记每个创意的挑战严重度 (LOW/MEDIUM/HIGH/CRITICAL)`, activeForm: "挑战创意中" })
TaskUpdate({ taskId: challengeId, owner: "challenger", addBlockedBy: [ideaId] })
// SYNTH-001: 综合整合 (blockedBy CHALLENGE-001)
TaskCreate({ subject: "SYNTH-001: 跨想法整合与主题提取", description: `整合所有创意和挑战反馈\n\nSession: ${sessionFolder}\n输入: ideas/ + critiques/\n输出: ${sessionFolder}/synthesis/synthesis-001.md\n\n要求: 提取核心主题、解决冲突、生成整合方案`, activeForm: "综合整合中" })
TaskUpdate({ taskId: synthId, owner: "synthesizer", addBlockedBy: [challengeId] })
```
#### Deep Pipeline (with Generator-Critic Loop)
```javascript
// IDEA-001 → CHALLENGE-001 → IDEA-002(fix) → CHALLENGE-002 → SYNTH-001 → EVAL-001
TaskCreate({ subject: "IDEA-001: 初始创意生成", description: `话题: ${taskDescription}\n\nSession: ${sessionFolder}\n输出: ${sessionFolder}/ideas/idea-001.md`, activeForm: "生成创意中" })
TaskUpdate({ taskId: idea1Id, owner: "ideator" })
TaskCreate({ subject: "CHALLENGE-001: 第一轮挑战", description: `挑战 IDEA-001 的创意\n\nSession: ${sessionFolder}\n输入: ideas/idea-001.md\n输出: critiques/critique-001.md\n标记严重度`, activeForm: "挑战中" })
TaskUpdate({ taskId: challenge1Id, owner: "challenger", addBlockedBy: [idea1Id] })
TaskCreate({ subject: "IDEA-002: 创意修订Generator-Critic Round 1", description: `基于 CHALLENGE-001 的反馈修订创意\n\nSession: ${sessionFolder}\n输入: ideas/idea-001.md + critiques/critique-001.md\n输出: ideas/idea-002.md\n\n要求: 针对 HIGH/CRITICAL 严重度的挑战进行修订或替换`, activeForm: "修订创意中" })
TaskUpdate({ taskId: idea2Id, owner: "ideator", addBlockedBy: [challenge1Id] })
TaskCreate({ subject: "CHALLENGE-002: 第二轮验证", description: `验证修订后的创意\n\nSession: ${sessionFolder}\n输入: ideas/idea-002.md + critiques/critique-001.md\n输出: critiques/critique-002.md`, activeForm: "验证中" })
TaskUpdate({ taskId: challenge2Id, owner: "challenger", addBlockedBy: [idea2Id] })
TaskCreate({ subject: "SYNTH-001: 综合整合", description: `整合全部创意和挑战反馈\n\nSession: ${sessionFolder}\n输入: ideas/ + critiques/\n输出: synthesis/synthesis-001.md`, activeForm: "综合中" })
TaskUpdate({ taskId: synthId, owner: "synthesizer", addBlockedBy: [challenge2Id] })
TaskCreate({ subject: "EVAL-001: 评分排序与最终筛选", description: `对综合方案评分排序\n\nSession: ${sessionFolder}\n输入: synthesis/synthesis-001.md + shared-memory.json\n输出: evaluation/evaluation-001.md\n\n评分维度: 可行性(30%) + 创新性(25%) + 影响力(25%) + 实施成本(20%)`, activeForm: "评估中" })
TaskUpdate({ taskId: evalId, owner: "evaluator", addBlockedBy: [synthId] })
```
#### Full Pipeline (Fan-out + Generator-Critic)
```javascript
// 并行创意: IDEA-001 + IDEA-002 + IDEA-003 (no dependencies between them)
const ideaAngles = selectedAngles.slice(0, 3)
ideaAngles.forEach((angle, i) => {
TaskCreate({ subject: `IDEA-00${i+1}: ${angle}角度创意生成`, description: `话题: ${taskDescription}\n角度: ${angle}\n\nSession: ${sessionFolder}\n输出: ideas/idea-00${i+1}.md`, activeForm: `${angle}创意生成中` })
TaskUpdate({ taskId: ideaIds[i], owner: "ideator" })
})
// CHALLENGE-001: 批量挑战 (blockedBy all IDEA-001..003)
TaskCreate({ subject: "CHALLENGE-001: 批量创意挑战", description: `批量挑战所有角度的创意\n\nSession: ${sessionFolder}\n输入: ideas/idea-001..003.md\n输出: critiques/critique-001.md`, activeForm: "批量挑战中" })
TaskUpdate({ taskId: challenge1Id, owner: "challenger", addBlockedBy: ideaIds })
// IDEA-004: 修订 (blockedBy CHALLENGE-001)
TaskCreate({ subject: "IDEA-004: 创意修订", description: `基于批量挑战反馈修订\n\nSession: ${sessionFolder}\n输入: ideas/ + critiques/critique-001.md\n输出: ideas/idea-004.md`, activeForm: "修订中" })
TaskUpdate({ taskId: idea4Id, owner: "ideator", addBlockedBy: [challenge1Id] })
// SYNTH-001 (blockedBy IDEA-004)
TaskCreate({ subject: "SYNTH-001: 综合整合", description: `整合全部创意\n\nSession: ${sessionFolder}\n输入: ideas/ + critiques/\n输出: synthesis/synthesis-001.md`, activeForm: "综合中" })
TaskUpdate({ taskId: synthId, owner: "synthesizer", addBlockedBy: [idea4Id] })
// EVAL-001 (blockedBy SYNTH-001)
TaskCreate({ subject: "EVAL-001: 评分排序", description: `最终评估\n\nSession: ${sessionFolder}\n输入: synthesis/ + shared-memory.json\n输出: evaluation/evaluation-001.md`, activeForm: "评估中" })
TaskUpdate({ taskId: evalId, owner: "evaluator", addBlockedBy: [synthId] })
```
### Phase 4: Coordination Loop + Generator-Critic Control
| Received Message | Action |
|-----------------|--------|
| ideator: ideas_ready | Read ideas → team_msg log → TaskUpdate completed → unblock CHALLENGE |
| challenger: critique_ready | Read critique → **Generator-Critic 判断** → 决定是否触发 IDEA-fix |
| ideator: ideas_revised | Read revised ideas → team_msg log → TaskUpdate completed → unblock CHALLENGE-2 |
| synthesizer: synthesis_ready | Read synthesis → team_msg log → TaskUpdate completed → unblock EVAL (if exists) |
| evaluator: evaluation_ready | Read evaluation → team_msg log → TaskUpdate completed → Phase 5 |
| All tasks completed | → Phase 5 |
#### Generator-Critic Loop Control
```javascript
if (msgType === 'critique_ready') {
const critique = Read(`${sessionFolder}/critiques/critique-${round}.md`)
const sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`))
// Count HIGH/CRITICAL severity challenges
const criticalCount = (critique.match(/severity:\s*(HIGH|CRITICAL)/gi) || []).length
const gcRound = sharedMemory.gc_round || 0
if (criticalCount > 0 && gcRound < sharedMemory.max_gc_rounds) {
// Trigger another ideator round
sharedMemory.gc_round = gcRound + 1
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
mcp__ccw-tools__team_msg({
operation: "log", team: teamName, from: "coordinator", to: "ideator",
type: "gc_loop_trigger",
summary: `[coordinator] Generator-Critic round ${gcRound + 1}: ${criticalCount} critical challenges need revision`
})
// Unblock IDEA-fix task
} else {
// Converged → unblock SYNTH
mcp__ccw-tools__team_msg({
operation: "log", team: teamName, from: "coordinator", to: "synthesizer",
type: "task_unblocked",
summary: `[coordinator] Critique converged (round ${gcRound}), proceeding to synthesis`
})
}
}
```
### Phase 5: Report + Persist
```javascript
// Read final results
const synthesis = Read(`${sessionFolder}/synthesis/synthesis-001.md`)
const evaluation = selectedPipeline !== 'quick' ? Read(`${sessionFolder}/evaluation/evaluation-001.md`) : null
const sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`))
// Report to user
SendMessage({
content: `## [coordinator] 头脑风暴完成
**话题**: ${taskDescription}
**管道**: ${selectedPipeline}
**Generator-Critic 轮次**: ${sharedMemory.gc_round}
**创意总数**: ${sharedMemory.generated_ideas.length}
### 综合结果
${synthesis}
${evaluation ? `### 评估排序\n${evaluation}` : ''}`,
summary: `[coordinator] Brainstorm complete: ${sharedMemory.generated_ideas.length} ideas, ${sharedMemory.gc_round} GC rounds`
})
// Update session
updateSession(sessionFolder, { status: 'completed', completed_at: new Date().toISOString() })
AskUserQuestion({
questions: [{
question: "头脑风暴已完成。下一步:",
header: "Next",
multiSelect: false,
options: [
{ label: "新话题", description: "继续头脑风暴新话题" },
{ label: "深化探索", description: "对排名最高的创意进行深入分析" },
{ label: "关闭团队", description: "关闭所有 teammate 并清理" }
]
}]
})
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| Teammate 无响应 | 发追踪消息2次无响应 → 重新 spawn |
| Generator-Critic 循环超限 | 强制收敛到 SYNTH 阶段 |
| Ideator 无法产出 | Coordinator 提供种子问题引导 |
| Challenger 全部标记 LOW | 直接进入 SYNTH跳过修订 |
| 综合冲突无法解决 | 上报用户AskUserQuestion 决定方向 |

View File

@@ -0,0 +1,195 @@
# Role: evaluator
评分排序与最终筛选。负责对综合方案进行多维度评分、优先级推荐、生成最终排名。
## Role Identity
- **Name**: `evaluator`
- **Task Prefix**: `EVAL-*`
- **Responsibility**: Validation (评估验证)
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[evaluator]`
## Role Boundaries
### MUST
- 仅处理 `EVAL-*` 前缀的任务
- 所有输出必须带 `[evaluator]` 标识
- 仅通过 SendMessage 与 coordinator 通信
- Phase 2 读取 shared-memory.jsonPhase 5 写入 evaluation_scores
- 使用标准化评分维度,确保评分可追溯
### MUST NOT
- ❌ 生成新创意、挑战假设或综合整合
- ❌ 直接与其他 worker 角色通信
- ❌ 为其他角色创建任务
- ❌ 修改 shared-memory.json 中不属于自己的字段
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `evaluation_ready` | evaluator → coordinator | Evaluation completed | 评估排序完成 |
| `error` | evaluator → coordinator | Processing failure | 错误上报 |
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('EVAL-') &&
t.owner === 'evaluator' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
```
### Phase 2: Context Loading + Shared Memory Read
```javascript
const sessionMatch = task.description.match(/Session:\s*([^\n]+)/)
const sessionFolder = sessionMatch?.[1]?.trim()
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
// Read synthesis results
const synthesisFiles = Glob({ pattern: `${sessionFolder}/synthesis/*.md` })
const synthesis = synthesisFiles.map(f => Read(f))
// Read all ideas and critiques for full context
const ideaFiles = Glob({ pattern: `${sessionFolder}/ideas/*.md` })
const critiqueFiles = Glob({ pattern: `${sessionFolder}/critiques/*.md` })
```
### Phase 3: Evaluation & Scoring
```javascript
// Scoring dimensions:
// 1. Feasibility (30%) — 技术可行性、资源需求、时间框架
// 2. Innovation (25%) — 新颖性、差异化、突破性
// 3. Impact (25%) — 影响范围、价值创造、问题解决度
// 4. Cost (20%) — 实施成本、风险成本、机会成本
const evalNum = task.subject.match(/EVAL-(\d+)/)?.[1] || '001'
const outputPath = `${sessionFolder}/evaluation/evaluation-${evalNum}.md`
const evaluationContent = `# Evaluation — Round ${evalNum}
**Input**: ${synthesisFiles.length} synthesis files
**Scoring Dimensions**: Feasibility(30%), Innovation(25%), Impact(25%), Cost(20%)
## Scoring Matrix
| Rank | Proposal | Feasibility | Innovation | Impact | Cost | **Weighted Score** |
|------|----------|-------------|------------|--------|------|-------------------|
${scoredProposals.map((p, i) => `| ${i + 1} | ${p.title} | ${p.feasibility}/10 | ${p.innovation}/10 | ${p.impact}/10 | ${p.cost}/10 | **${p.weightedScore.toFixed(1)}** |`).join('\n')}
## Detailed Evaluation
${scoredProposals.map((p, i) => `### ${i + 1}. ${p.title} (Score: ${p.weightedScore.toFixed(1)}/10)
**Feasibility** (${p.feasibility}/10):
${p.feasibilityRationale}
**Innovation** (${p.innovation}/10):
${p.innovationRationale}
**Impact** (${p.impact}/10):
${p.impactRationale}
**Cost Efficiency** (${p.cost}/10):
${p.costRationale}
**Recommendation**: ${p.recommendation}
`).join('\n')}
## Final Recommendation
**Top Pick**: ${scoredProposals[0].title}
**Runner-up**: ${scoredProposals.length > 1 ? scoredProposals[1].title : 'N/A'}
### Action Items
${actionItems.map((item, i) => `${i + 1}. ${item}`).join('\n')}
### Risk Summary
${riskSummary.map(r => `- **${r.risk}**: ${r.mitigation}`).join('\n')}
`
Write(outputPath, evaluationContent)
```
### Phase 4: Consistency Check
```javascript
// Verify scoring consistency
// - No proposal should have all 10s
// - Scores should reflect critique findings
// - Rankings should be deterministic
const maxScore = Math.max(...scoredProposals.map(p => p.weightedScore))
const minScore = Math.min(...scoredProposals.map(p => p.weightedScore))
const spread = maxScore - minScore
if (spread < 0.5 && scoredProposals.length > 1) {
// Too close — re-evaluate differentiators
}
```
### Phase 5: Report to Coordinator + Shared Memory Write
```javascript
sharedMemory.evaluation_scores = scoredProposals.map(p => ({
title: p.title,
weighted_score: p.weightedScore,
rank: p.rank,
recommendation: p.recommendation
}))
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: "evaluator",
to: "coordinator",
type: "evaluation_ready",
summary: `[evaluator] Evaluation complete: Top pick "${scoredProposals[0].title}" (${scoredProposals[0].weightedScore.toFixed(1)}/10)`,
ref: outputPath
})
SendMessage({
type: "message",
recipient: "coordinator",
content: `## [evaluator] Evaluation Results
**Task**: ${task.subject}
**Proposals Evaluated**: ${scoredProposals.length}
**Output**: ${outputPath}
### Rankings
${scoredProposals.map((p, i) => `${i + 1}. **${p.title}** — ${p.weightedScore.toFixed(1)}/10 (${p.recommendation})`).join('\n')}
### Top Pick: ${scoredProposals[0].title}
${scoredProposals[0].feasibilityRationale}`,
summary: `[evaluator] Top: ${scoredProposals[0].title} (${scoredProposals[0].weightedScore.toFixed(1)}/10)`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| No EVAL-* tasks | Idle, wait for assignment |
| Synthesis files not found | Notify coordinator |
| Only one proposal | Evaluate against absolute criteria, recommend or reject |
| All proposals score below 5 | Flag all as weak, recommend re-brainstorming |

View File

@@ -0,0 +1,225 @@
# Role: ideator
多角度创意生成者。负责发散思维、概念探索、创意修订。作为 Generator-Critic 循环中的 Generator 角色。
## Role Identity
- **Name**: `ideator`
- **Task Prefix**: `IDEA-*`
- **Responsibility**: Read-only analysis (创意生成不修改代码)
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[ideator]`
## Role Boundaries
### MUST
- 仅处理 `IDEA-*` 前缀的任务
- 所有输出SendMessage、team_msg、日志必须带 `[ideator]` 标识
- 仅通过 SendMessage 与 coordinator 通信
- Phase 2 读取 shared-memory.jsonPhase 5 写入 generated_ideas
### MUST NOT
- ❌ 执行挑战/评估/综合等其他角色工作
- ❌ 直接与其他 worker 角色通信
- ❌ 为其他角色创建任务TaskCreate 是 coordinator 专属)
- ❌ 修改 shared-memory.json 中不属于自己的字段
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `ideas_ready` | ideator → coordinator | Initial ideas generated | 初始创意完成 |
| `ideas_revised` | ideator → coordinator | Ideas revised after critique | 修订创意完成 (GC 循环) |
| `error` | ideator → coordinator | Processing failure | 错误上报 |
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('IDEA-') &&
t.owner === 'ideator' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (myTasks.length === 0) return // idle
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
```
### Phase 2: Context Loading + Shared Memory Read
```javascript
// Extract session folder from task description
const sessionMatch = task.description.match(/Session:\s*([^\n]+)/)
const sessionFolder = sessionMatch?.[1]?.trim()
// Read shared memory
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
const topic = sharedMemory.topic || task.description
const angles = sharedMemory.angles || ['技术', '产品', '创新']
const gcRound = sharedMemory.gc_round || 0
// If this is a revision task (GC loop), read previous critique
let previousCritique = null
if (task.subject.includes('修订') || task.subject.includes('fix')) {
const critiqueFiles = Glob({ pattern: `${sessionFolder}/critiques/*.md` })
if (critiqueFiles.length > 0) {
previousCritique = Read(critiqueFiles[critiqueFiles.length - 1])
}
}
// Read previous ideas for context
const previousIdeas = sharedMemory.generated_ideas || []
```
### Phase 3: Idea Generation
```javascript
// Determine generation mode
const isRevision = !!previousCritique
if (isRevision) {
// === Generator-Critic Revision Mode ===
// Focus on HIGH/CRITICAL severity challenges
// Revise or replace challenged ideas
// Keep unchallenged ideas intact
// Output structure:
// - Retained ideas (unchallenged)
// - Revised ideas (with revision rationale)
// - New replacement ideas (for unsalvageable ones)
} else {
// === Initial Generation Mode ===
// For each angle, generate 3+ ideas
// Each idea includes:
// - Title
// - Description (2-3 sentences)
// - Key assumption
// - Potential impact
// - Implementation hint
}
// Write ideas to file
const ideaNum = task.subject.match(/IDEA-(\d+)/)?.[1] || '001'
const outputPath = `${sessionFolder}/ideas/idea-${ideaNum}.md`
const ideaContent = `# ${isRevision ? 'Revised' : 'Initial'} Ideas — Round ${ideaNum}
**Topic**: ${topic}
**Angles**: ${angles.join(', ')}
**Mode**: ${isRevision ? 'Generator-Critic Revision (Round ' + gcRound + ')' : 'Initial Generation'}
${isRevision ? `## Revision Context\n\nBased on critique feedback:\n${previousCritique}\n\n` : ''}
## Ideas
${generatedIdeas.map((idea, i) => `### Idea ${i + 1}: ${idea.title}
**Description**: ${idea.description}
**Key Assumption**: ${idea.assumption}
**Potential Impact**: ${idea.impact}
**Implementation Hint**: ${idea.implementation}
${isRevision ? `**Revision Note**: ${idea.revision_note || 'New idea'}` : ''}
`).join('\n')}
## Summary
- Total ideas: ${generatedIdeas.length}
- ${isRevision ? `Retained: ${retainedCount}, Revised: ${revisedCount}, New: ${newCount}` : `Per angle: ${angles.map(a => `${a}: ${countByAngle[a]}`).join(', ')}`}
`
Write(outputPath, ideaContent)
```
### Phase 4: Self-Review
```javascript
// Verify minimum idea count
const ideaCount = generatedIdeas.length
const minimumRequired = isRevision ? 3 : 6
if (ideaCount < minimumRequired) {
// Generate additional ideas to meet minimum
}
// Verify no duplicate ideas
const titles = generatedIdeas.map(i => i.title.toLowerCase())
const duplicates = titles.filter((t, i) => titles.indexOf(t) !== i)
if (duplicates.length > 0) {
// Replace duplicates
}
```
### Phase 5: Report to Coordinator + Shared Memory Write
```javascript
// Update shared memory
sharedMemory.generated_ideas = [
...sharedMemory.generated_ideas,
...generatedIdeas.map(i => ({
id: `idea-${ideaNum}-${i.index}`,
title: i.title,
round: parseInt(ideaNum),
revised: isRevision
}))
]
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
// Log message
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: "ideator",
to: "coordinator",
type: isRevision ? "ideas_revised" : "ideas_ready",
summary: `[ideator] ${isRevision ? 'Revised' : 'Generated'} ${ideaCount} ideas (round ${ideaNum})`,
ref: outputPath
})
SendMessage({
type: "message",
recipient: "coordinator",
content: `## [ideator] ${isRevision ? 'Ideas Revised' : 'Ideas Generated'}
**Task**: ${task.subject}
**Ideas**: ${ideaCount}
**Output**: ${outputPath}
### Highlights
${generatedIdeas.slice(0, 3).map(i => `- **${i.title}**: ${i.description.substring(0, 100)}...`).join('\n')}`,
summary: `[ideator] ${ideaCount} ideas ${isRevision ? 'revised' : 'generated'}`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
// Check for next task
const nextTasks = TaskList().filter(t =>
t.subject.startsWith('IDEA-') &&
t.owner === 'ideator' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (nextTasks.length > 0) {
// Continue with next task → back to Phase 1
}
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| No IDEA-* tasks available | Idle, wait for coordinator assignment |
| Session folder not found | Notify coordinator, request path |
| Shared memory read fails | Initialize empty, proceed with generation |
| Topic too vague | Generate meta-questions as seed ideas |
| Previous critique not found (revision) | Generate new ideas instead of revising |

View File

@@ -0,0 +1,205 @@
# Role: synthesizer
跨想法整合者。负责从多个创意和挑战反馈中提取主题、解决冲突、生成整合方案。
## Role Identity
- **Name**: `synthesizer`
- **Task Prefix**: `SYNTH-*`
- **Responsibility**: Read-only analysis (综合整合)
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[synthesizer]`
## Role Boundaries
### MUST
- 仅处理 `SYNTH-*` 前缀的任务
- 所有输出必须带 `[synthesizer]` 标识
- 仅通过 SendMessage 与 coordinator 通信
- Phase 2 读取 shared-memory.jsonPhase 5 写入 synthesis_themes
### MUST NOT
- ❌ 生成新创意、挑战假设或评分排序
- ❌ 直接与其他 worker 角色通信
- ❌ 为其他角色创建任务
- ❌ 修改 shared-memory.json 中不属于自己的字段
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `synthesis_ready` | synthesizer → coordinator | Synthesis completed | 综合整合完成 |
| `error` | synthesizer → coordinator | Processing failure | 错误上报 |
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('SYNTH-') &&
t.owner === 'synthesizer' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
```
### Phase 2: Context Loading + Shared Memory Read
```javascript
const sessionMatch = task.description.match(/Session:\s*([^\n]+)/)
const sessionFolder = sessionMatch?.[1]?.trim()
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
// Read all ideas and critiques
const ideaFiles = Glob({ pattern: `${sessionFolder}/ideas/*.md` })
const critiqueFiles = Glob({ pattern: `${sessionFolder}/critiques/*.md` })
const allIdeas = ideaFiles.map(f => Read(f))
const allCritiques = critiqueFiles.map(f => Read(f))
```
### Phase 3: Synthesis Execution
```javascript
// Synthesis process:
// 1. Theme Extraction — 识别跨创意的共同主题
// 2. Conflict Resolution — 解决相互矛盾的想法
// 3. Complementary Grouping — 将互补的创意组合
// 4. Gap Identification — 发现未覆盖的视角
// 5. Integrated Proposal — 生成1-3个整合方案
const synthNum = task.subject.match(/SYNTH-(\d+)/)?.[1] || '001'
const outputPath = `${sessionFolder}/synthesis/synthesis-${synthNum}.md`
const synthesisContent = `# Synthesis — Round ${synthNum}
**Input**: ${ideaFiles.length} idea files, ${critiqueFiles.length} critique files
**GC Rounds Completed**: ${sharedMemory.gc_round || 0}
## Extracted Themes
${themes.map((theme, i) => `### Theme ${i + 1}: ${theme.name}
**Description**: ${theme.description}
**Supporting Ideas**: ${theme.supportingIdeas.join(', ')}
**Strength**: ${theme.strength}/10
`).join('\n')}
## Conflict Resolution
${conflicts.map(c => `### ${c.idea1} vs ${c.idea2}
**Nature**: ${c.nature}
**Resolution**: ${c.resolution}
**Rationale**: ${c.rationale}
`).join('\n')}
## Integrated Proposals
${proposals.map((p, i) => `### Proposal ${i + 1}: ${p.title}
**Core Concept**: ${p.concept}
**Combines**: ${p.sourceIdeas.join(' + ')}
**Addresses Challenges**: ${p.addressedChallenges.join(', ')}
**Feasibility**: ${p.feasibility}/10
**Innovation**: ${p.innovation}/10
**Description**:
${p.description}
**Key Benefits**:
${p.benefits.map(b => `- ${b}`).join('\n')}
**Remaining Risks**:
${p.risks.map(r => `- ${r}`).join('\n')}
`).join('\n')}
## Coverage Analysis
| Aspect | Covered | Gaps |
|--------|---------|------|
${coverageAnalysis.map(a => `| ${a.aspect} | ${a.covered ? '✅' : '❌'} | ${a.gap || '—'} |`).join('\n')}
`
Write(outputPath, synthesisContent)
```
### Phase 4: Quality Check
```javascript
// Verify synthesis quality
const proposalCount = proposals.length
const themeCount = themes.length
if (proposalCount === 0) {
// At least one proposal required
}
if (themeCount < 2) {
// May need to look for more patterns
}
```
### Phase 5: Report to Coordinator + Shared Memory Write
```javascript
sharedMemory.synthesis_themes = themes.map(t => ({
name: t.name,
strength: t.strength,
supporting_ideas: t.supportingIdeas
}))
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: "synthesizer",
to: "coordinator",
type: "synthesis_ready",
summary: `[synthesizer] Synthesis complete: ${themeCount} themes, ${proposalCount} proposals`,
ref: outputPath
})
SendMessage({
type: "message",
recipient: "coordinator",
content: `## [synthesizer] Synthesis Results
**Task**: ${task.subject}
**Themes**: ${themeCount}
**Proposals**: ${proposalCount}
**Conflicts Resolved**: ${conflicts.length}
**Output**: ${outputPath}
### Top Proposals
${proposals.slice(0, 3).map((p, i) => `${i + 1}. **${p.title}** — ${p.concept} (Feasibility: ${p.feasibility}/10, Innovation: ${p.innovation}/10)`).join('\n')}`,
summary: `[synthesizer] ${themeCount} themes, ${proposalCount} proposals`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
const nextTasks = TaskList().filter(t =>
t.subject.startsWith('SYNTH-') && t.owner === 'synthesizer' &&
t.status === 'pending' && t.blockedBy.length === 0
)
if (nextTasks.length > 0) { /* back to Phase 1 */ }
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| No SYNTH-* tasks | Idle, wait for assignment |
| No ideas/critiques found | Notify coordinator |
| Irreconcilable conflicts | Present both sides, recommend user decision |
| Only one idea survives | Create single focused proposal |

View File

@@ -0,0 +1,86 @@
{
"team_name": "team-brainstorm",
"team_display_name": "Team Brainstorm",
"description": "Head brainstorming team with Generator-Critic loop, shared memory, and dynamic pipeline selection",
"version": "1.0.0",
"roles": {
"coordinator": {
"task_prefix": null,
"responsibility": "Topic clarification, complexity assessment, pipeline selection, convergence monitoring",
"message_types": ["pipeline_selected", "gc_loop_trigger", "task_unblocked", "error", "shutdown"]
},
"ideator": {
"task_prefix": "IDEA",
"responsibility": "Multi-angle idea generation, concept exploration, divergent thinking",
"message_types": ["ideas_ready", "ideas_revised", "error"]
},
"challenger": {
"task_prefix": "CHALLENGE",
"responsibility": "Devil's advocate, assumption challenging, feasibility questioning",
"message_types": ["critique_ready", "error"]
},
"synthesizer": {
"task_prefix": "SYNTH",
"responsibility": "Cross-idea integration, theme extraction, conflict resolution",
"message_types": ["synthesis_ready", "error"]
},
"evaluator": {
"task_prefix": "EVAL",
"responsibility": "Scoring and ranking, priority recommendation, final selection",
"message_types": ["evaluation_ready", "error"]
}
},
"pipelines": {
"quick": {
"description": "Simple topic: generate → challenge → synthesize",
"task_chain": ["IDEA-001", "CHALLENGE-001", "SYNTH-001"],
"gc_loops": 0
},
"deep": {
"description": "Complex topic with Generator-Critic loop (max 2 rounds)",
"task_chain": ["IDEA-001", "CHALLENGE-001", "IDEA-002", "CHALLENGE-002", "SYNTH-001", "EVAL-001"],
"gc_loops": 2
},
"full": {
"description": "Parallel fan-out ideation + Generator-Critic + evaluation",
"task_chain": ["IDEA-001", "IDEA-002", "IDEA-003", "CHALLENGE-001", "IDEA-004", "SYNTH-001", "EVAL-001"],
"gc_loops": 1,
"parallel_groups": [["IDEA-001", "IDEA-002", "IDEA-003"]]
}
},
"innovation_patterns": {
"generator_critic": {
"generator": "ideator",
"critic": "challenger",
"max_rounds": 2,
"convergence_trigger": "critique.severity < HIGH"
},
"shared_memory": {
"file": "shared-memory.json",
"fields": {
"ideator": "generated_ideas",
"challenger": "critique_insights",
"synthesizer": "synthesis_themes",
"evaluator": "evaluation_scores"
}
},
"dynamic_pipeline": {
"selector": "coordinator",
"criteria": "topic_complexity + scope + time_constraint"
}
},
"collaboration_patterns": ["CP-1", "CP-3", "CP-7"],
"session_dirs": {
"base": ".workflow/.team/BRS-{slug}-{YYYY-MM-DD}/",
"ideas": "ideas/",
"critiques": "critiques/",
"synthesis": "synthesis/",
"evaluation": "evaluation/",
"messages": ".workflow/.team-msg/{team-name}/"
}
}

View File

@@ -0,0 +1,372 @@
---
name: team-iterdev
description: Unified team skill for iterative development team. All roles invoke this skill with --role arg for role-specific execution. Triggers on "team iterdev".
allowed-tools: TeamCreate(*), TeamDelete(*), SendMessage(*), TaskCreate(*), TaskUpdate(*), TaskList(*), TaskGet(*), Task(*), AskUserQuestion(*), Read(*), Write(*), Edit(*), Bash(*), Glob(*), Grep(*)
---
# Team IterDev
持续迭代开发团队技能。通过 Generator-Critic 循环developer↔reviewer最多3轮、任务账本task-ledger.json实时进度追踪、共享记忆Sprint间学习和动态管道选择实现增量交付开发。所有团队成员通过 `--role=xxx` 路由。
## Architecture Overview
```
┌──────────────────────────────────────────────────┐
│ Skill(skill="team-iterdev", args="--role=xxx") │
└───────────────────┬──────────────────────────────┘
│ Role Router
┌───────────┬───┼───────────┬───────────┐
↓ ↓ ↓ ↓ ↓
┌──────────┐┌─────────┐┌─────────┐┌──────┐┌────────┐
│coordinator││architect││developer││tester││reviewer│
│ roles/ ││ roles/ ││ roles/ ││roles/││ roles/ │
└──────────┘└─────────┘└─────────┘└──────┘└────────┘
```
## Role Router
### Input Parsing
```javascript
const args = "$ARGUMENTS"
const roleMatch = args.match(/--role[=\s]+(\w+)/)
if (!roleMatch) {
throw new Error("Missing --role argument. Available roles: coordinator, architect, developer, tester, reviewer")
}
const role = roleMatch[1]
const teamName = args.match(/--team[=\s]+([\w-]+)/)?.[1] || "iterdev"
```
### Role Dispatch
```javascript
const VALID_ROLES = {
"coordinator": { file: "roles/coordinator.md", prefix: null },
"architect": { file: "roles/architect.md", prefix: "DESIGN" },
"developer": { file: "roles/developer.md", prefix: "DEV" },
"tester": { file: "roles/tester.md", prefix: "VERIFY" },
"reviewer": { file: "roles/reviewer.md", prefix: "REVIEW" }
}
if (!VALID_ROLES[role]) {
throw new Error(`Unknown role: ${role}. Available: ${Object.keys(VALID_ROLES).join(', ')}`)
}
Read(VALID_ROLES[role].file)
```
### Available Roles
| Role | Task Prefix | Responsibility | Role File |
|------|-------------|----------------|-----------|
| `coordinator` | N/A | Sprint规划、积压管理、任务账本维护 | [roles/coordinator.md](roles/coordinator.md) |
| `architect` | DESIGN-* | 技术设计、任务分解、架构决策 | [roles/architect.md](roles/architect.md) |
| `developer` | DEV-* | 代码实现、增量交付 | [roles/developer.md](roles/developer.md) |
| `tester` | VERIFY-* | 测试执行、修复循环、回归检测 | [roles/tester.md](roles/tester.md) |
| `reviewer` | REVIEW-* | 代码审查、质量评分、改进建议 | [roles/reviewer.md](roles/reviewer.md) |
## Shared Infrastructure
### Role Isolation Rules
#### Output Tagging强制
```javascript
SendMessage({ content: `## [${role}] ...`, summary: `[${role}] ...` })
mcp__ccw-tools__team_msg({ summary: `[${role}] ...` })
```
#### Coordinator 隔离
| 允许 | 禁止 |
|------|------|
| Sprint 规划 (AskUserQuestion) | ❌ 直接编写代码 |
| 创建任务链 (TaskCreate) | ❌ 直接执行测试/审查 |
| 维护任务账本 (task-ledger.json) | ❌ 调用 code-developer 等实现类 subagent |
| 监控进度 | ❌ 绕过 worker 自行完成 |
#### Worker 隔离
| 允许 | 禁止 |
|------|------|
| 处理自己前缀的任务 | ❌ 处理其他角色前缀的任务 |
| 读写 shared-memory.json (自己的字段) | ❌ 为其他角色创建任务 |
| SendMessage 给 coordinator | ❌ 直接与其他 worker 通信 |
### Team Configuration
```javascript
const TEAM_CONFIG = {
name: "iterdev",
sessionDir: ".workflow/.team/IDS-{slug}-{date}/",
msgDir: ".workflow/.team-msg/iterdev/",
sharedMemory: "shared-memory.json",
taskLedger: "task-ledger.json"
}
```
### Task Ledger (创新模式 — 任务账本)
实时追踪所有 Sprint 任务进度:
```javascript
// task-ledger.json structure
{
"sprint_id": "sprint-1",
"sprint_goal": "...",
"tasks": [
{
"id": "DEV-001",
"title": "...",
"owner": "developer",
"status": "completed", // pending | in_progress | completed | blocked
"started_at": "...",
"completed_at": "...",
"gc_rounds": 0, // Generator-Critic iterations
"review_score": null, // reviewer 评分
"test_pass_rate": null // tester 通过率
}
],
"metrics": {
"total": 5,
"completed": 3,
"in_progress": 1,
"blocked": 0,
"velocity": 3 // tasks completed this sprint
}
}
// Coordinator updates ledger at each task transition
function updateLedger(sessionFolder, taskId, updates) {
const ledger = JSON.parse(Read(`${sessionFolder}/task-ledger.json`))
const task = ledger.tasks.find(t => t.id === taskId)
if (task) Object.assign(task, updates)
// Recalculate metrics
ledger.metrics.completed = ledger.tasks.filter(t => t.status === 'completed').length
ledger.metrics.in_progress = ledger.tasks.filter(t => t.status === 'in_progress').length
Write(`${sessionFolder}/task-ledger.json`, JSON.stringify(ledger, null, 2))
}
```
### Shared Memory (Sprint间学习)
```javascript
// shared-memory.json — accumulated across sprints
{
"sprint_history": [
{
"sprint_id": "sprint-1",
"what_worked": ["..."],
"what_failed": ["..."],
"patterns_learned": ["..."]
}
],
"architecture_decisions": [],
"implementation_context": [],
"review_feedback_trends": []
}
```
### Message Bus
```javascript
mcp__ccw-tools__team_msg({
operation: "log", team: teamName, from: role, to: "coordinator",
type: "<type>", summary: `[${role}] <summary>`, ref: "<file_path>"
})
```
| Role | Types |
|------|-------|
| coordinator | `sprint_started`, `gc_loop_trigger`, `sprint_complete`, `task_unblocked`, `error`, `shutdown` |
| architect | `design_ready`, `design_revision`, `error` |
| developer | `dev_complete`, `dev_progress`, `error` |
| tester | `verify_passed`, `verify_failed`, `fix_required`, `error` |
| reviewer | `review_passed`, `review_revision`, `review_critical`, `error` |
### CLI Fallback
```javascript
Bash(`ccw team log --team "${teamName}" --from "${role}" --to "coordinator" --type "<type>" --summary "<summary>" --json`)
```
### Task Lifecycle (All Worker Roles)
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith(`${VALID_ROLES[role].prefix}-`) &&
t.owner === role && t.status === 'pending' && t.blockedBy.length === 0
)
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
// Phase 2-4: Role-specific
// Phase 5: Report + Loop
```
## Three-Pipeline Architecture
```
Patch (简单修复):
DEV-001 → VERIFY-001
Sprint (标准特性):
DESIGN-001 → DEV-001 → [VERIFY-001 + REVIEW-001](parallel)
Multi-Sprint (大型特性):
Sprint 1: DESIGN-001 → DEV-001 → DEV-002(incremental) → VERIFY-001 → DEV-fix → REVIEW-001
Sprint 2: DESIGN-002(refined) → DEV-003 → VERIFY-002 → REVIEW-002
...
```
### Generator-Critic Loop
developer ↔ reviewer 循环最多3轮
```
DEV → REVIEW → (if review.critical_count > 0 || review.score < 7)
→ DEV-fix → REVIEW-2 → (if still issues) → DEV-fix-2 → REVIEW-3
→ (max 3 rounds, then accept with warning)
```
### Multi-Sprint Dynamic Downgrade
```javascript
// If Sprint N is progressing well, downgrade Sprint N+1 complexity
if (sprintMetrics.velocity >= expectedVelocity && sprintMetrics.review_avg >= 8) {
// Next sprint: skip detailed design, use simplified pipeline
nextPipeline = 'sprint' // downgrade from multi-sprint
}
```
## Unified Session Directory
```
.workflow/.team/IDS-{slug}-{YYYY-MM-DD}/
├── team-session.json
├── shared-memory.json # Sprint间学习: what_worked / what_failed / patterns_learned
├── task-ledger.json # 实时任务进度账本
├── design/ # Architect output
│ ├── design-001.md
│ └── task-breakdown.json
├── code/ # Developer tracking
│ └── dev-log.md
├── verify/ # Tester output
│ └── verify-001.json
└── review/ # Reviewer output
└── review-001.md
```
## Coordinator Spawn Template
```javascript
TeamCreate({ team_name: teamName })
// Architect
Task({
subagent_type: "general-purpose",
team_name: teamName,
name: "architect",
prompt: `你是 team "${teamName}" 的 ARCHITECT。
当你收到 DESIGN-* 任务时,调用 Skill(skill="team-iterdev", args="--role=architect") 执行。
当前需求: ${taskDescription}
约束: ${constraints}
## 角色准则(强制)
- 你只能处理 DESIGN-* 前缀的任务
- 所有输出必须带 [architect] 标识前缀
- 仅与 coordinator 通信
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 DESIGN-* 任务
2. Skill(skill="team-iterdev", args="--role=architect") 执行
3. team_msg log + SendMessage
4. TaskUpdate completed → 检查下一个任务`
})
// Developer
Task({
subagent_type: "general-purpose",
team_name: teamName,
name: "developer",
prompt: `你是 team "${teamName}" 的 DEVELOPER。
当你收到 DEV-* 任务时,调用 Skill(skill="team-iterdev", args="--role=developer") 执行。
当前需求: ${taskDescription}
## 角色准则(强制)
- 你只能处理 DEV-* 前缀的任务
- 所有输出必须带 [developer] 标识前缀
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 DEV-* 任务
2. Skill(skill="team-iterdev", args="--role=developer") 执行
3. team_msg log + SendMessage
4. TaskUpdate completed → 检查下一个任务`
})
// Tester
Task({
subagent_type: "general-purpose",
team_name: teamName,
name: "tester",
prompt: `你是 team "${teamName}" 的 TESTER。
当你收到 VERIFY-* 任务时,调用 Skill(skill="team-iterdev", args="--role=tester") 执行。
当前需求: ${taskDescription}
## 角色准则(强制)
- 你只能处理 VERIFY-* 前缀的任务
- 所有输出必须带 [tester] 标识前缀
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 VERIFY-* 任务
2. Skill(skill="team-iterdev", args="--role=tester") 执行
3. team_msg log + SendMessage
4. TaskUpdate completed → 检查下一个任务`
})
// Reviewer
Task({
subagent_type: "general-purpose",
team_name: teamName,
name: "reviewer",
prompt: `你是 team "${teamName}" 的 REVIEWER。
当你收到 REVIEW-* 任务时,调用 Skill(skill="team-iterdev", args="--role=reviewer") 执行。
当前需求: ${taskDescription}
## 角色准则(强制)
- 你只能处理 REVIEW-* 前缀的任务
- 所有输出必须带 [reviewer] 标识前缀
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 REVIEW-* 任务
2. Skill(skill="team-iterdev", args="--role=reviewer") 执行
3. team_msg log + SendMessage
4. TaskUpdate completed → 检查下一个任务`
})
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| Unknown --role value | Error with available role list |
| Missing --role arg | Error with usage hint |
| Role file not found | Error with expected path |
| GC loop exceeds 3 rounds | Accept with warning, record in shared memory |
| Sprint velocity drops below 50% | Coordinator alerts user, suggests scope reduction |
| Task ledger corrupted | Rebuild from TaskList state |

View File

@@ -0,0 +1,179 @@
# Role: architect
技术架构师。负责技术设计、任务分解、架构决策记录。
## Role Identity
- **Name**: `architect`
- **Task Prefix**: `DESIGN-*`
- **Responsibility**: Read-only analysis (技术设计)
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[architect]`
## Role Boundaries
### MUST
- 仅处理 `DESIGN-*` 前缀的任务
- 所有输出必须带 `[architect]` 标识
- Phase 2 读取 shared-memory.jsonPhase 5 写入 architecture_decisions
### MUST NOT
- ❌ 编写实现代码、执行测试或代码审查
- ❌ 直接与其他 worker 通信
- ❌ 为其他角色创建任务
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `design_ready` | architect → coordinator | Design completed | 设计完成 |
| `design_revision` | architect → coordinator | Design revised | 设计修订 |
| `error` | architect → coordinator | Processing failure | 错误上报 |
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('DESIGN-') && t.owner === 'architect' &&
t.status === 'pending' && t.blockedBy.length === 0
)
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
```
### Phase 2: Context Loading + Codebase Exploration
```javascript
const sessionMatch = task.description.match(/Session:\s*([^\n]+)/)
const sessionFolder = sessionMatch?.[1]?.trim()
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
// Multi-angle codebase exploration
Task({
subagent_type: "cli-explore-agent",
run_in_background: false,
description: "Explore architecture",
prompt: `Explore codebase architecture for: ${task.description}
Focus on: existing patterns, module structure, dependencies, similar implementations.
Report relevant files and integration points.`
})
```
### Phase 3: Technical Design + Task Decomposition
```javascript
const designNum = task.subject.match(/DESIGN-(\d+)/)?.[1] || '001'
const designPath = `${sessionFolder}/design/design-${designNum}.md`
const breakdownPath = `${sessionFolder}/design/task-breakdown.json`
// Generate design document
const designContent = `# Technical Design — ${designNum}
**Requirement**: ${task.description}
**Sprint**: ${sharedMemory.sprint_history?.length + 1 || 1}
## Architecture Decision
**Approach**: ${selectedApproach}
**Rationale**: ${rationale}
**Alternatives Considered**: ${alternatives.join(', ')}
## Component Design
${components.map(c => `### ${c.name}
- **Responsibility**: ${c.responsibility}
- **Dependencies**: ${c.dependencies.join(', ')}
- **Files**: ${c.files.join(', ')}
- **Complexity**: ${c.complexity}
`).join('\n')}
## Task Breakdown
${taskBreakdown.map((t, i) => `### Task ${i + 1}: ${t.title}
- **Files**: ${t.files.join(', ')}
- **Estimated Complexity**: ${t.complexity}
- **Dependencies**: ${t.dependencies.join(', ') || 'None'}
`).join('\n')}
## Integration Points
${integrationPoints.map(ip => `- **${ip.name}**: ${ip.description}`).join('\n')}
## Risks
${risks.map(r => `- **${r.risk}**: ${r.mitigation}`).join('\n')}
`
Write(designPath, designContent)
// Generate task breakdown JSON for developer
const breakdown = {
design_id: `design-${designNum}`,
tasks: taskBreakdown.map((t, i) => ({
id: `task-${i + 1}`,
title: t.title,
files: t.files,
complexity: t.complexity,
dependencies: t.dependencies,
acceptance_criteria: t.acceptance
})),
total_files: [...new Set(taskBreakdown.flatMap(t => t.files))].length,
execution_order: taskBreakdown.map((t, i) => `task-${i + 1}`)
}
Write(breakdownPath, JSON.stringify(breakdown, null, 2))
```
### Phase 4: Design Validation
```javascript
// Verify design completeness
const hasComponents = components.length > 0
const hasBreakdown = taskBreakdown.length > 0
const hasDependencies = components.every(c => c.dependencies !== undefined)
```
### Phase 5: Report to Coordinator + Shared Memory Write
```javascript
sharedMemory.architecture_decisions.push({
design_id: `design-${designNum}`,
approach: selectedApproach,
rationale: rationale,
components: components.map(c => c.name),
task_count: taskBreakdown.length
})
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
mcp__ccw-tools__team_msg({
operation: "log", team: teamName, from: "architect", to: "coordinator",
type: "design_ready",
summary: `[architect] Design complete: ${components.length} components, ${taskBreakdown.length} tasks`,
ref: designPath
})
SendMessage({
type: "message", recipient: "coordinator",
content: `## [architect] Design Ready\n\n**Components**: ${components.length}\n**Tasks**: ${taskBreakdown.length}\n**Design**: ${designPath}\n**Breakdown**: ${breakdownPath}`,
summary: `[architect] Design: ${taskBreakdown.length} tasks`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| No DESIGN-* tasks | Idle |
| Codebase exploration fails | Design based on task description alone |
| Too many components | Simplify, suggest phased approach |
| Conflicting patterns found | Document in design, recommend resolution |

View File

@@ -0,0 +1,266 @@
# Role: coordinator
持续迭代开发团队协调者。负责 Sprint 规划、积压管理、任务账本维护、Generator-Critic 循环控制developer↔reviewer最多3轮和 Sprint 间学习。
## Role Identity
- **Name**: `coordinator`
- **Task Prefix**: N/A
- **Responsibility**: Orchestration
- **Communication**: SendMessage to all teammates
- **Output Tag**: `[coordinator]`
## Role Boundaries
### MUST
- 所有输出必须带 `[coordinator]` 标识
- 维护 task-ledger.json 实时进度
- 管理 developer↔reviewer 的 GC 循环最多3轮
- Sprint 结束时记录学习到 shared-memory.json
### MUST NOT
- ❌ 直接编写代码、设计架构、执行测试或代码审查
- ❌ 直接调用实现类 subagent
- ❌ 修改源代码
## Execution
### Phase 1: Sprint Planning
```javascript
const args = "$ARGUMENTS"
const teamName = args.match(/--team-name[=\s]+([\w-]+)/)?.[1] || `iterdev-${Date.now().toString(36)}`
const taskDescription = args.replace(/--team-name[=\s]+[\w-]+/, '').replace(/--role[=\s]+\w+/, '').trim()
// Assess complexity for pipeline selection
function assessComplexity(desc) {
let score = 0
const changedFiles = Bash(`git diff --name-only HEAD~1 2>/dev/null || echo ""`).split('\n').filter(Boolean)
score += changedFiles.length > 10 ? 3 : changedFiles.length > 3 ? 2 : 0
if (/refactor|architect|restructure|system|module/.test(desc)) score += 3
if (/multiple|across|cross/.test(desc)) score += 2
if (/fix|bug|typo|patch/.test(desc)) score -= 2
return { score, fileCount: changedFiles.length }
}
const { score, fileCount } = assessComplexity(taskDescription)
const suggestedPipeline = score >= 5 ? 'multi-sprint' : score >= 2 ? 'sprint' : 'patch'
AskUserQuestion({
questions: [{
question: "选择开发模式:",
header: "Mode",
multiSelect: false,
options: [
{ label: suggestedPipeline === 'patch' ? "patch (推荐)" : "patch", description: "补丁模式:实现→验证(简单修复)" },
{ label: suggestedPipeline === 'sprint' ? "sprint (推荐)" : "sprint", description: "Sprint模式设计→实现→验证+审查" },
{ label: suggestedPipeline === 'multi-sprint' ? "multi-sprint (推荐)" : "multi-sprint", description: "多Sprint增量迭代交付大型特性" }
]
}]
})
```
### Phase 2: Create Team + Initialize Ledger
```javascript
TeamCreate({ team_name: teamName })
const topicSlug = taskDescription.toLowerCase().replace(/[^a-z0-9]+/g, '-').substring(0, 40)
const dateStr = new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString().substring(0, 10)
const sessionId = `IDS-${topicSlug}-${dateStr}`
const sessionFolder = `.workflow/.team/${sessionId}`
Bash(`mkdir -p "${sessionFolder}/design" "${sessionFolder}/code" "${sessionFolder}/verify" "${sessionFolder}/review"`)
// Initialize task ledger
const taskLedger = {
sprint_id: "sprint-1",
sprint_goal: taskDescription,
pipeline: selectedPipeline,
tasks: [],
metrics: { total: 0, completed: 0, in_progress: 0, blocked: 0, velocity: 0 }
}
Write(`${sessionFolder}/task-ledger.json`, JSON.stringify(taskLedger, null, 2))
// Initialize shared memory with sprint learning
const sharedMemory = {
sprint_history: [],
architecture_decisions: [],
implementation_context: [],
review_feedback_trends: [],
gc_round: 0,
max_gc_rounds: 3
}
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
const teamSession = {
session_id: sessionId, team_name: teamName, task: taskDescription,
pipeline: selectedPipeline, status: "active", sprint_number: 1,
created_at: new Date().toISOString(), updated_at: new Date().toISOString(),
completed_tasks: []
}
Write(`${sessionFolder}/team-session.json`, JSON.stringify(teamSession, null, 2))
```
Spawn workers (see SKILL.md Coordinator Spawn Template).
### Phase 3: Create Task Chain + Update Ledger
#### Patch Pipeline
```javascript
TaskCreate({ subject: "DEV-001: 实现修复", description: `${taskDescription}\n\nSession: ${sessionFolder}`, activeForm: "实现中" })
TaskUpdate({ taskId: devId, owner: "developer" })
TaskCreate({ subject: "VERIFY-001: 验证修复", description: `验证 DEV-001\n\nSession: ${sessionFolder}`, activeForm: "验证中" })
TaskUpdate({ taskId: verifyId, owner: "tester", addBlockedBy: [devId] })
// Update ledger
updateLedger(sessionFolder, null, {
tasks: [
{ id: "DEV-001", title: "实现修复", owner: "developer", status: "pending", gc_rounds: 0 },
{ id: "VERIFY-001", title: "验证修复", owner: "tester", status: "pending", gc_rounds: 0 }
],
metrics: { total: 2, completed: 0, in_progress: 0, blocked: 0, velocity: 0 }
})
```
#### Sprint Pipeline
```javascript
TaskCreate({ subject: "DESIGN-001: 技术设计与任务分解", description: `${taskDescription}\n\nSession: ${sessionFolder}\n输出: ${sessionFolder}/design/design-001.md + task-breakdown.json`, activeForm: "设计中" })
TaskUpdate({ taskId: designId, owner: "architect" })
TaskCreate({ subject: "DEV-001: 实现设计方案", description: `按设计方案实现\n\nSession: ${sessionFolder}\n设计: design/design-001.md\n分解: design/task-breakdown.json`, activeForm: "实现中" })
TaskUpdate({ taskId: devId, owner: "developer", addBlockedBy: [designId] })
// VERIFY-001 and REVIEW-001 parallel, both blockedBy DEV-001
TaskCreate({ subject: "VERIFY-001: 测试验证", description: `验证实现\n\nSession: ${sessionFolder}`, activeForm: "验证中" })
TaskUpdate({ taskId: verifyId, owner: "tester", addBlockedBy: [devId] })
TaskCreate({ subject: "REVIEW-001: 代码审查", description: `审查实现\n\nSession: ${sessionFolder}\n设计: design/design-001.md`, activeForm: "审查中" })
TaskUpdate({ taskId: reviewId, owner: "reviewer", addBlockedBy: [devId] })
```
#### Multi-Sprint Pipeline
```javascript
// Sprint 1 — created dynamically, subsequent sprints created after Sprint N completes
// Each sprint: DESIGN → DEV-1..N(incremental) → VERIFY → DEV-fix → REVIEW
```
### Phase 4: Coordination Loop + GC Control + Ledger Updates
| Received Message | Action |
|-----------------|--------|
| architect: design_ready | Read design → update ledger → unblock DEV |
| developer: dev_complete | Update ledger → unblock VERIFY + REVIEW |
| tester: verify_passed | Update ledger (test_pass_rate) |
| tester: verify_failed | Create DEV-fix task |
| tester: fix_required | Create DEV-fix task → assign developer |
| reviewer: review_passed | Update ledger (review_score) → mark complete |
| reviewer: review_revision | **GC loop** → create DEV-fix → REVIEW-next |
| reviewer: review_critical | **GC loop** → create DEV-fix → REVIEW-next |
#### Generator-Critic Loop Control (developer↔reviewer)
```javascript
if (msgType === 'review_revision' || msgType === 'review_critical') {
const sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`))
const gcRound = sharedMemory.gc_round || 0
if (gcRound < sharedMemory.max_gc_rounds) {
sharedMemory.gc_round = gcRound + 1
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
// Create DEV-fix task
TaskCreate({
subject: `DEV-fix-${gcRound + 1}: 根据审查修订代码`,
description: `审查反馈:\n${reviewFeedback}\n\nSession: ${sessionFolder}\n审查: review/review-${reviewNum}.md`,
activeForm: "修订代码中"
})
TaskUpdate({ taskId: fixId, owner: "developer" })
// Create REVIEW-next task
TaskCreate({
subject: `REVIEW-${reviewNum + 1}: 验证修订`,
description: `验证 DEV-fix-${gcRound + 1} 的修订\n\nSession: ${sessionFolder}`,
activeForm: "复审中"
})
TaskUpdate({ taskId: nextReviewId, owner: "reviewer", addBlockedBy: [fixId] })
// Update ledger
updateLedger(sessionFolder, `DEV-fix-${gcRound + 1}`, { status: 'pending', gc_rounds: gcRound + 1 })
mcp__ccw-tools__team_msg({
operation: "log", team: teamName, from: "coordinator", to: "developer",
type: "gc_loop_trigger",
summary: `[coordinator] GC round ${gcRound + 1}/${sharedMemory.max_gc_rounds}: review requires revision`
})
} else {
// Max rounds — accept with warning
mcp__ccw-tools__team_msg({
operation: "log", team: teamName, from: "coordinator", to: "all",
type: "sprint_complete",
summary: `[coordinator] GC loop exhausted (${gcRound} rounds), accepting current state`
})
}
}
```
### Phase 5: Sprint Retrospective + Persist
```javascript
const ledger = JSON.parse(Read(`${sessionFolder}/task-ledger.json`))
const sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`))
// Record sprint learning
const sprintRetro = {
sprint_id: ledger.sprint_id,
velocity: ledger.metrics.velocity,
gc_rounds: sharedMemory.gc_round,
what_worked: [], // extracted from review/verify feedback
what_failed: [], // extracted from failures
patterns_learned: [] // derived from GC loop patterns
}
sharedMemory.sprint_history.push(sprintRetro)
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
SendMessage({
content: `## [coordinator] Sprint 完成
**需求**: ${taskDescription}
**管道**: ${selectedPipeline}
**完成**: ${ledger.metrics.completed}/${ledger.metrics.total}
**GC 轮次**: ${sharedMemory.gc_round}
### 任务账本
${ledger.tasks.map(t => `- ${t.id}: ${t.status} ${t.review_score ? '(Review: ' + t.review_score + '/10)' : ''}`).join('\n')}`,
summary: `[coordinator] Sprint complete: ${ledger.metrics.completed}/${ledger.metrics.total}`
})
AskUserQuestion({
questions: [{
question: "Sprint 已完成。下一步:",
header: "Next",
multiSelect: false,
options: [
{ label: "下一个Sprint", description: "继续迭代(携带学习记忆)" },
{ label: "新需求", description: "新的开发需求" },
{ label: "关闭团队", description: "关闭所有 teammate" }
]
}]
})
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| GC 循环超限 (3轮) | 接受当前代码,记录到 sprint_history |
| Velocity 低于 50% | 上报用户,建议缩小范围 |
| 任务账本损坏 | 从 TaskList 重建 |
| 设计被拒 3+ 次 | Coordinator 介入简化设计 |
| 测试持续失败 | 创建 DEV-fix 给 developer |

View File

@@ -0,0 +1,212 @@
# Role: developer
代码实现者。负责按设计方案编码、增量交付。作为 Generator-Critic 循环中的 Generator 角色(与 reviewer 配对)。
## Role Identity
- **Name**: `developer`
- **Task Prefix**: `DEV-*`
- **Responsibility**: Code generation (代码实现)
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[developer]`
## Role Boundaries
### MUST
- 仅处理 `DEV-*` 前缀的任务
- 所有输出必须带 `[developer]` 标识
- Phase 2 读取 shared-memory.json + designPhase 5 写入 implementation_context
- 修订任务DEV-fix-*)时参考 review 反馈
### MUST NOT
- ❌ 执行测试、代码审查或架构设计
- ❌ 直接与其他 worker 通信
- ❌ 为其他角色创建任务
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `dev_complete` | developer → coordinator | Implementation done | 实现完成 |
| `dev_progress` | developer → coordinator | Incremental progress | 进度更新 |
| `error` | developer → coordinator | Processing failure | 错误上报 |
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('DEV-') && t.owner === 'developer' &&
t.status === 'pending' && t.blockedBy.length === 0
)
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
```
### Phase 2: Context Loading
```javascript
const sessionMatch = task.description.match(/Session:\s*([^\n]+)/)
const sessionFolder = sessionMatch?.[1]?.trim()
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
// Read design and breakdown
let design = null, breakdown = null
try {
design = Read(`${sessionFolder}/design/design-001.md`)
breakdown = JSON.parse(Read(`${sessionFolder}/design/task-breakdown.json`))
} catch {}
// Check if this is a fix task (GC loop)
const isFixTask = task.subject.includes('fix')
let reviewFeedback = null
if (isFixTask) {
const reviewFiles = Glob({ pattern: `${sessionFolder}/review/*.md` })
if (reviewFiles.length > 0) {
reviewFeedback = Read(reviewFiles[reviewFiles.length - 1])
}
}
// Previous implementation context from shared memory
const prevContext = sharedMemory.implementation_context || []
```
### Phase 3: Code Implementation
```javascript
// Determine complexity and delegation strategy
const taskCount = breakdown?.tasks?.length || 1
if (isFixTask) {
// === GC Fix Mode ===
// Focus on review feedback items
// Parse critical/high issues from review
// Fix each issue directly
Task({
subagent_type: "code-developer",
run_in_background: false,
description: "Fix review issues",
prompt: `Fix the following code review issues:
${reviewFeedback}
Focus on:
1. Critical issues (must fix)
2. High issues (should fix)
3. Medium issues (if time permits)
Do NOT change code that wasn't flagged.
Maintain existing code style and patterns.`
})
} else if (taskCount <= 2) {
// Direct implementation
for (const t of (breakdown?.tasks || [])) {
for (const file of (t.files || [])) {
try { Read(file) } catch {} // Read existing file
// Edit or Write as needed
}
}
} else {
// Delegate to code-developer
Task({
subagent_type: "code-developer",
run_in_background: false,
description: `Implement ${taskCount} tasks`,
prompt: `## Design
${design}
## Task Breakdown
${JSON.stringify(breakdown, null, 2)}
${prevContext.length > 0 ? `## Previous Context\n${prevContext.map(c => `- ${c}`).join('\n')}` : ''}
Implement each task following the design. Complete tasks in the specified execution order.`
})
}
```
### Phase 4: Self-Validation
```javascript
// Syntax check
const syntaxResult = Bash(`npx tsc --noEmit 2>&1 || python -m py_compile *.py 2>&1 || true`)
const hasSyntaxErrors = syntaxResult.includes('error')
// List changed files
const changedFiles = Bash(`git diff --name-only`).split('\n').filter(Boolean)
// Log implementation progress
const devLog = `# Dev Log — ${task.subject}
**Changed Files**: ${changedFiles.length}
**Syntax Clean**: ${!hasSyntaxErrors}
**Fix Task**: ${isFixTask}
## Files Changed
${changedFiles.map(f => `- ${f}`).join('\n')}
`
Write(`${sessionFolder}/code/dev-log.md`, devLog)
```
### Phase 5: Report to Coordinator + Shared Memory Write
```javascript
sharedMemory.implementation_context.push({
task: task.subject,
changed_files: changedFiles,
is_fix: isFixTask,
syntax_clean: !hasSyntaxErrors
})
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
mcp__ccw-tools__team_msg({
operation: "log", team: teamName, from: "developer", to: "coordinator",
type: "dev_complete",
summary: `[developer] ${isFixTask ? 'Fix' : 'Implementation'} complete: ${changedFiles.length} files changed`,
ref: `${sessionFolder}/code/dev-log.md`
})
SendMessage({
type: "message", recipient: "coordinator",
content: `## [developer] ${isFixTask ? 'Fix' : 'Implementation'} Complete
**Task**: ${task.subject}
**Changed Files**: ${changedFiles.length}
**Syntax Clean**: ${!hasSyntaxErrors}
${isFixTask ? `**GC Round**: ${sharedMemory.gc_round}` : ''}
### Files
${changedFiles.slice(0, 10).map(f => `- ${f}`).join('\n')}`,
summary: `[developer] ${changedFiles.length} files ${isFixTask ? 'fixed' : 'implemented'}`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
// Check for next task
const nextTasks = TaskList().filter(t =>
t.subject.startsWith('DEV-') && t.owner === 'developer' &&
t.status === 'pending' && t.blockedBy.length === 0
)
if (nextTasks.length > 0) { /* back to Phase 1 */ }
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| No DEV-* tasks | Idle |
| Design not found | Implement based on task description |
| Syntax errors after implementation | Attempt auto-fix, report remaining errors |
| Review feedback unclear | Implement best interpretation, note in dev-log |
| Code-developer agent fails | Retry once, then implement inline |

View File

@@ -0,0 +1,206 @@
# Role: reviewer
代码审查者。负责多维度审查、质量评分、改进建议。作为 Generator-Critic 循环中的 Critic 角色(与 developer 配对)。
## Role Identity
- **Name**: `reviewer`
- **Task Prefix**: `REVIEW-*`
- **Responsibility**: Read-only analysis (代码审查)
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[reviewer]`
## Role Boundaries
### MUST
- 仅处理 `REVIEW-*` 前缀的任务
- 所有输出必须带 `[reviewer]` 标识
- Phase 2 读取 shared-memory.json + designPhase 5 写入 review_feedback_trends
- 标记每个问题的严重度 (CRITICAL/HIGH/MEDIUM/LOW)
- 提供质量评分 (1-10)
### MUST NOT
- ❌ 编写实现代码、设计架构或执行测试
- ❌ 直接与其他 worker 通信
- ❌ 为其他角色创建任务
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `review_passed` | reviewer → coordinator | No critical issues, score >= 7 | 审查通过 |
| `review_revision` | reviewer → coordinator | Issues found, score < 7 | 需要修订 (触发GC) |
| `review_critical` | reviewer → coordinator | Critical issues found | 严重问题 (触发GC) |
| `error` | reviewer → coordinator | Processing failure | 错误上报 |
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('REVIEW-') && t.owner === 'reviewer' &&
t.status === 'pending' && t.blockedBy.length === 0
)
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
```
### Phase 2: Context Loading
```javascript
const sessionMatch = task.description.match(/Session:\s*([^\n]+)/)
const sessionFolder = sessionMatch?.[1]?.trim()
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
// Read design for requirements alignment
let design = null
try { design = Read(`${sessionFolder}/design/design-001.md`) } catch {}
// Get changed files
const changedFiles = Bash(`git diff --name-only HEAD~1 2>/dev/null || git diff --name-only --cached`).split('\n').filter(Boolean)
// Read file contents
const fileContents = {}
for (const file of changedFiles.slice(0, 20)) {
try { fileContents[file] = Read(file) } catch {}
}
// Previous review trends
const prevTrends = sharedMemory.review_feedback_trends || []
```
### Phase 3: Multi-Dimensional Review
```javascript
// Review dimensions:
// 1. Correctness — 逻辑正确性、边界处理
// 2. Completeness — 是否覆盖设计要求
// 3. Maintainability — 可读性、代码风格、DRY
// 4. Security — 安全漏洞、输入验证
// Optional: CLI-assisted review
Bash(`ccw cli -p "PURPOSE: Code review for correctness and security
TASK: Review changes in: ${changedFiles.join(', ')}
MODE: analysis
CONTEXT: @${changedFiles.join(' @')}
EXPECTED: Issues with severity (CRITICAL/HIGH/MEDIUM/LOW) and file:line
CONSTRAINTS: Focus on correctness and security" --tool gemini --mode analysis`, { run_in_background: true })
const reviewNum = task.subject.match(/REVIEW-(\d+)/)?.[1] || '001'
const outputPath = `${sessionFolder}/review/review-${reviewNum}.md`
// Scoring
const score = calculateScore(findings)
const criticalCount = findings.filter(f => f.severity === 'CRITICAL').length
const highCount = findings.filter(f => f.severity === 'HIGH').length
const reviewContent = `# Code Review — Round ${reviewNum}
**Files Reviewed**: ${changedFiles.length}
**Quality Score**: ${score}/10
**Critical Issues**: ${criticalCount}
**High Issues**: ${highCount}
## Findings
${findings.map((f, i) => `### ${i + 1}. [${f.severity}] ${f.title}
**File**: ${f.file}:${f.line}
**Dimension**: ${f.dimension}
**Description**: ${f.description}
**Suggestion**: ${f.suggestion}
`).join('\n')}
## Scoring Breakdown
| Dimension | Score | Notes |
|-----------|-------|-------|
| Correctness | ${scores.correctness}/10 | ${scores.correctnessNotes} |
| Completeness | ${scores.completeness}/10 | ${scores.completenessNotes} |
| Maintainability | ${scores.maintainability}/10 | ${scores.maintainabilityNotes} |
| Security | ${scores.security}/10 | ${scores.securityNotes} |
| **Overall** | **${score}/10** | |
## Signal
${criticalCount > 0 ? '**CRITICAL** — Critical issues must be fixed before merge'
: score < 7 ? '**REVISION_NEEDED** — Quality below threshold (7/10)'
: '**APPROVED** — Code meets quality standards'}
${design ? `## Design Alignment\n${designAlignmentNotes}` : ''}
`
Write(outputPath, reviewContent)
```
### Phase 4: Trend Analysis
```javascript
// Compare with previous reviews to detect trends
const currentIssueTypes = findings.map(f => f.dimension)
const trendNote = prevTrends.length > 0
? `Recurring: ${findRecurring(prevTrends, currentIssueTypes).join(', ')}`
: 'First review'
```
### Phase 5: Report to Coordinator + Shared Memory Write
```javascript
sharedMemory.review_feedback_trends.push({
review_id: `review-${reviewNum}`,
score: score,
critical: criticalCount,
high: highCount,
dimensions: findings.map(f => f.dimension),
gc_round: sharedMemory.gc_round || 0
})
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
const msgType = criticalCount > 0 ? "review_critical"
: score < 7 ? "review_revision"
: "review_passed"
mcp__ccw-tools__team_msg({
operation: "log", team: teamName, from: "reviewer", to: "coordinator",
type: msgType,
summary: `[reviewer] Review ${msgType}: score=${score}/10, ${criticalCount}C/${highCount}H`,
ref: outputPath
})
SendMessage({
type: "message", recipient: "coordinator",
content: `## [reviewer] Code Review Results
**Task**: ${task.subject}
**Score**: ${score}/10
**Signal**: ${msgType.toUpperCase()}
**Critical**: ${criticalCount}, **High**: ${highCount}
**Output**: ${outputPath}
### Top Issues
${findings.filter(f => ['CRITICAL', 'HIGH'].includes(f.severity)).slice(0, 5).map(f =>
`- **[${f.severity}]** ${f.title} (${f.file}:${f.line})`
).join('\n')}`,
summary: `[reviewer] ${msgType}: ${score}/10`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| No REVIEW-* tasks | Idle |
| No changed files | Review files referenced in design |
| CLI review fails | Fall back to inline analysis |
| All issues LOW | Score high, approve |
| Design not found | Review against general quality standards |

View File

@@ -0,0 +1,146 @@
# Role: tester
测试验证者。负责测试执行、修复循环、回归检测。
## Role Identity
- **Name**: `tester`
- **Task Prefix**: `VERIFY-*`
- **Responsibility**: Validation (测试验证)
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[tester]`
## Role Boundaries
### MUST
- 仅处理 `VERIFY-*` 前缀的任务
- 所有输出必须带 `[tester]` 标识
- Phase 2 读取 shared-memory.jsonPhase 5 写入 test_patterns
### MUST NOT
- ❌ 编写实现代码、设计架构或代码审查
- ❌ 直接与其他 worker 通信
- ❌ 为其他角色创建任务
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `verify_passed` | tester → coordinator | All tests pass | 验证通过 |
| `verify_failed` | tester → coordinator | Tests fail | 验证失败 |
| `fix_required` | tester → coordinator | Issues found needing fix | 需要修复 |
| `error` | tester → coordinator | Environment failure | 错误上报 |
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('VERIFY-') && t.owner === 'tester' &&
t.status === 'pending' && t.blockedBy.length === 0
)
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
```
### Phase 2: Context Loading
```javascript
const sessionMatch = task.description.match(/Session:\s*([^\n]+)/)
const sessionFolder = sessionMatch?.[1]?.trim()
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
// Detect test framework and test command
const testCommand = detectTestCommand()
const changedFiles = Bash(`git diff --name-only`).split('\n').filter(Boolean)
```
### Phase 3: Test Execution + Fix Cycle
```javascript
let iteration = 0
const MAX_ITERATIONS = 5
let lastResult = null
let passRate = 0
while (iteration < MAX_ITERATIONS) {
lastResult = Bash(`${testCommand} 2>&1 || true`)
passRate = parsePassRate(lastResult)
if (passRate >= 0.95) break
if (iteration < MAX_ITERATIONS - 1) {
// Delegate fix to code-developer
Task({
subagent_type: "code-developer",
run_in_background: false,
description: `Fix test failures (iteration ${iteration + 1})`,
prompt: `Test failures:\n${lastResult.substring(0, 3000)}\n\nFix failing tests. Changed files: ${changedFiles.join(', ')}`
})
}
iteration++
}
// Save verification results
const verifyNum = task.subject.match(/VERIFY-(\d+)/)?.[1] || '001'
const resultData = {
verify_id: `verify-${verifyNum}`,
pass_rate: passRate,
iterations: iteration,
passed: passRate >= 0.95,
timestamp: new Date().toISOString()
}
Write(`${sessionFolder}/verify/verify-${verifyNum}.json`, JSON.stringify(resultData, null, 2))
```
### Phase 4: Regression Check
```javascript
// Run full test suite for regression
const regressionResult = Bash(`${testCommand} --all 2>&1 || true`)
const regressionPassed = !regressionResult.includes('FAIL')
resultData.regression_passed = regressionPassed
```
### Phase 5: Report to Coordinator + Shared Memory Write
```javascript
sharedMemory.test_patterns = sharedMemory.test_patterns || []
if (passRate >= 0.95) {
sharedMemory.test_patterns.push(`verify-${verifyNum}: passed in ${iteration} iterations`)
}
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
const msgType = resultData.passed ? "verify_passed" : (iteration >= MAX_ITERATIONS ? "fix_required" : "verify_failed")
mcp__ccw-tools__team_msg({
operation: "log", team: teamName, from: "tester", to: "coordinator",
type: msgType,
summary: `[tester] ${msgType}: pass_rate=${(passRate*100).toFixed(1)}%, iterations=${iteration}`,
ref: `${sessionFolder}/verify/verify-${verifyNum}.json`
})
SendMessage({
type: "message", recipient: "coordinator",
content: `## [tester] Verification Results\n\n**Pass Rate**: ${(passRate*100).toFixed(1)}%\n**Iterations**: ${iteration}/${MAX_ITERATIONS}\n**Regression**: ${resultData.regression_passed ? '✅' : '❌'}\n**Status**: ${resultData.passed ? '✅ PASSED' : '❌ NEEDS FIX'}`,
summary: `[tester] ${resultData.passed ? 'PASSED' : 'FAILED'}: ${(passRate*100).toFixed(1)}%`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| No VERIFY-* tasks | Idle |
| Test command not found | Try common commands (npm test, pytest, vitest) |
| Max iterations exceeded | Report fix_required to coordinator |
| Test environment broken | Report error, suggest manual fix |

View File

@@ -0,0 +1,94 @@
{
"team_name": "team-iterdev",
"team_display_name": "Team IterDev",
"description": "Iterative development team with Generator-Critic loop, task ledger, sprint learning, and dynamic pipeline",
"version": "1.0.0",
"roles": {
"coordinator": {
"task_prefix": null,
"responsibility": "Sprint planning, backlog management, task ledger maintenance, GC loop control",
"message_types": ["sprint_started", "gc_loop_trigger", "sprint_complete", "task_unblocked", "error", "shutdown"]
},
"architect": {
"task_prefix": "DESIGN",
"responsibility": "Technical design, task decomposition, architecture decisions",
"message_types": ["design_ready", "design_revision", "error"]
},
"developer": {
"task_prefix": "DEV",
"responsibility": "Code implementation, incremental delivery",
"message_types": ["dev_complete", "dev_progress", "error"]
},
"tester": {
"task_prefix": "VERIFY",
"responsibility": "Test execution, fix cycle, regression detection",
"message_types": ["verify_passed", "verify_failed", "fix_required", "error"]
},
"reviewer": {
"task_prefix": "REVIEW",
"responsibility": "Code review, quality scoring, improvement suggestions",
"message_types": ["review_passed", "review_revision", "review_critical", "error"]
}
},
"pipelines": {
"patch": {
"description": "Simple fix: implement → verify",
"task_chain": ["DEV-001", "VERIFY-001"],
"gc_loops": 0
},
"sprint": {
"description": "Standard feature: design → implement → verify + review (parallel)",
"task_chain": ["DESIGN-001", "DEV-001", "VERIFY-001", "REVIEW-001"],
"gc_loops": 3,
"parallel_groups": [["VERIFY-001", "REVIEW-001"]]
},
"multi-sprint": {
"description": "Large feature: multiple sprint cycles with incremental delivery",
"task_chain": "dynamic — coordinator creates per-sprint chains",
"gc_loops": 3,
"sprint_count": "dynamic"
}
},
"innovation_patterns": {
"generator_critic": {
"generator": "developer",
"critic": "reviewer",
"max_rounds": 3,
"convergence_trigger": "review.critical_count === 0 && review.score >= 7"
},
"task_ledger": {
"file": "task-ledger.json",
"updated_by": "coordinator",
"tracks": ["status", "gc_rounds", "review_score", "test_pass_rate", "velocity"]
},
"shared_memory": {
"file": "shared-memory.json",
"fields": {
"architect": "architecture_decisions",
"developer": "implementation_context",
"tester": "test_patterns",
"reviewer": "review_feedback_trends"
},
"persistent_fields": ["sprint_history", "what_worked", "what_failed", "patterns_learned"]
},
"dynamic_pipeline": {
"selector": "coordinator",
"criteria": "file_count + module_count + complexity_assessment",
"downgrade_rule": "velocity >= expected && review_avg >= 8 → simplify next sprint"
}
},
"collaboration_patterns": ["CP-1", "CP-3", "CP-5", "CP-6"],
"session_dirs": {
"base": ".workflow/.team/IDS-{slug}-{YYYY-MM-DD}/",
"design": "design/",
"code": "code/",
"verify": "verify/",
"review": "review/",
"messages": ".workflow/.team-msg/{team-name}/"
}
}

View File

@@ -0,0 +1,331 @@
---
name: team-testing
description: Unified team skill for testing team. All roles invoke this skill with --role arg for role-specific execution. Triggers on "team testing".
allowed-tools: TeamCreate(*), TeamDelete(*), SendMessage(*), TaskCreate(*), TaskUpdate(*), TaskList(*), TaskGet(*), Task(*), AskUserQuestion(*), Read(*), Write(*), Edit(*), Bash(*), Glob(*), Grep(*)
---
# Team Testing
测试团队技能。通过 Generator-Critic 循环generator↔executor、共享记忆缺陷模式追踪和动态层级选择实现渐进式测试覆盖。所有团队成员通过 `--role=xxx` 路由到角色执行逻辑。
## Architecture Overview
```
┌──────────────────────────────────────────────────┐
│ Skill(skill="team-testing", args="--role=xxx") │
└───────────────────┬──────────────────────────────┘
│ Role Router
┌───────────┬───┼───────────┬───────────┐
↓ ↓ ↓ ↓ ↓
┌──────────┐┌──────────┐┌─────────┐┌────────┐┌────────┐
│coordinator││strategist││generator││executor││analyst │
│ roles/ ││ roles/ ││ roles/ ││ roles/ ││ roles/ │
└──────────┘└──────────┘└─────────┘└────────┘└────────┘
```
## Role Router
### Input Parsing
```javascript
const args = "$ARGUMENTS"
const roleMatch = args.match(/--role[=\s]+(\w+)/)
if (!roleMatch) {
throw new Error("Missing --role argument. Available roles: coordinator, strategist, generator, executor, analyst")
}
const role = roleMatch[1]
const teamName = args.match(/--team[=\s]+([\w-]+)/)?.[1] || "testing"
```
### Role Dispatch
```javascript
const VALID_ROLES = {
"coordinator": { file: "roles/coordinator.md", prefix: null },
"strategist": { file: "roles/strategist.md", prefix: "STRATEGY" },
"generator": { file: "roles/generator.md", prefix: "TESTGEN" },
"executor": { file: "roles/executor.md", prefix: "TESTRUN" },
"analyst": { file: "roles/analyst.md", prefix: "TESTANA" }
}
if (!VALID_ROLES[role]) {
throw new Error(`Unknown role: ${role}. Available: ${Object.keys(VALID_ROLES).join(', ')}`)
}
Read(VALID_ROLES[role].file)
```
### Available Roles
| Role | Task Prefix | Responsibility | Role File |
|------|-------------|----------------|-----------|
| `coordinator` | N/A | 变更范围分析、层级选择、质量门控 | [roles/coordinator.md](roles/coordinator.md) |
| `strategist` | STRATEGY-* | 分析 git diff、确定测试层级、定义覆盖率目标 | [roles/strategist.md](roles/strategist.md) |
| `generator` | TESTGEN-* | 按层级生成测试用例(单元/集成/E2E | [roles/generator.md](roles/generator.md) |
| `executor` | TESTRUN-* | 执行测试、收集覆盖率、自动修复 | [roles/executor.md](roles/executor.md) |
| `analyst` | TESTANA-* | 缺陷模式分析、覆盖率差距、质量报告 | [roles/analyst.md](roles/analyst.md) |
## Shared Infrastructure
### Role Isolation Rules
**核心原则**: 每个角色仅能执行自己职责范围内的工作。
#### Output Tagging强制
```javascript
SendMessage({ content: `## [${role}] ...`, summary: `[${role}] ...` })
mcp__ccw-tools__team_msg({ summary: `[${role}] ...` })
```
#### Coordinator 隔离
| 允许 | 禁止 |
|------|------|
| 变更范围分析 | ❌ 直接编写测试 |
| 创建任务链 (TaskCreate) | ❌ 直接执行测试 |
| 质量门控判断 | ❌ 直接分析覆盖率 |
| 监控进度 (消息总线) | ❌ 绕过 worker 自行完成 |
#### Worker 隔离
| 允许 | 禁止 |
|------|------|
| 处理自己前缀的任务 | ❌ 处理其他角色前缀的任务 |
| 读写 shared-memory.json (自己的字段) | ❌ 为其他角色创建任务 |
| SendMessage 给 coordinator | ❌ 直接与其他 worker 通信 |
### Team Configuration
```javascript
const TEAM_CONFIG = {
name: "testing",
sessionDir: ".workflow/.team/TST-{slug}-{date}/",
msgDir: ".workflow/.team-msg/testing/",
sharedMemory: "shared-memory.json",
testLayers: {
L1: { name: "Unit Tests", coverage_target: 80 },
L2: { name: "Integration Tests", coverage_target: 60 },
L3: { name: "E2E Tests", coverage_target: 40 }
}
}
```
### Shared Memory (创新模式)
```javascript
// Phase 2: 读取共享记忆
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
// Phase 5: 写入共享记忆(仅更新自己负责的字段)
// strategist → sharedMemory.test_strategy
// generator → sharedMemory.generated_tests
// executor → sharedMemory.execution_results + defect_patterns
// analyst → sharedMemory.analysis_report + coverage_history
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
```
### Message Bus (All Roles)
```javascript
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: role,
to: "coordinator",
type: "<type>",
summary: `[${role}] <summary>`,
ref: "<file_path>"
})
```
| Role | Types |
|------|-------|
| coordinator | `pipeline_selected`, `gc_loop_trigger`, `quality_gate`, `task_unblocked`, `error`, `shutdown` |
| strategist | `strategy_ready`, `error` |
| generator | `tests_generated`, `tests_revised`, `error` |
| executor | `tests_passed`, `tests_failed`, `coverage_report`, `error` |
| analyst | `analysis_ready`, `error` |
### CLI Fallback
```javascript
Bash(`ccw team log --team "${teamName}" --from "${role}" --to "coordinator" --type "<type>" --summary "<summary>" --json`)
```
### Task Lifecycle (All Worker Roles)
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith(`${VALID_ROLES[role].prefix}-`) &&
t.owner === role &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
// Phase 2-4: Role-specific
// Phase 5: Report + Loop
mcp__ccw-tools__team_msg({ operation: "log", team: teamName, from: role, to: "coordinator", type: "...", summary: `[${role}] ...` })
SendMessage({ type: "message", recipient: "coordinator", content: `## [${role}] ...`, summary: `[${role}] ...` })
TaskUpdate({ taskId: task.id, status: 'completed' })
```
## Three-Pipeline Architecture
```
Targeted (小范围变更):
STRATEGY-001 → TESTGEN-001(L1 unit) → TESTRUN-001
Standard (渐进式):
STRATEGY-001 → TESTGEN-001(L1) → TESTRUN-001(L1) → TESTGEN-002(L2) → TESTRUN-002(L2) → TESTANA-001
Comprehensive (全覆盖):
STRATEGY-001 → [TESTGEN-001(L1) + TESTGEN-002(L2)](parallel) → [TESTRUN-001(L1) + TESTRUN-002(L2)](parallel) → TESTGEN-003(L3) → TESTRUN-003(L3) → TESTANA-001
```
### Generator-Critic Loop
generator ↔ executor 循环(覆盖率不达标时修订测试):
```
TESTGEN → TESTRUN → (if coverage < target) → TESTGEN-fix → TESTRUN-2
(if coverage >= target) → next layer or TESTANA
```
## Unified Session Directory
```
.workflow/.team/TST-{slug}-{YYYY-MM-DD}/
├── team-session.json
├── shared-memory.json # 缺陷模式 / 有效测试模式 / 覆盖率历史
├── strategy/ # Strategist output
│ └── test-strategy.md
├── tests/ # Generator output
│ ├── L1-unit/
│ ├── L2-integration/
│ └── L3-e2e/
├── results/ # Executor output
│ ├── run-001.json
│ └── coverage-001.json
└── analysis/ # Analyst output
└── quality-report.md
```
## Coordinator Spawn Template
```javascript
TeamCreate({ team_name: teamName })
// Strategist
Task({
subagent_type: "general-purpose",
team_name: teamName,
name: "strategist",
prompt: `你是 team "${teamName}" 的 STRATEGIST。
当你收到 STRATEGY-* 任务时,调用 Skill(skill="team-testing", args="--role=strategist") 执行。
当前需求: ${taskDescription}
约束: ${constraints}
## 角色准则(强制)
- 你只能处理 STRATEGY-* 前缀的任务
- 所有输出必须带 [strategist] 标识前缀
- 仅与 coordinator 通信
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 STRATEGY-* 任务
2. Skill(skill="team-testing", args="--role=strategist") 执行
3. team_msg log + SendMessage 结果给 coordinator
4. TaskUpdate completed → 检查下一个任务`
})
// Generator
Task({
subagent_type: "general-purpose",
team_name: teamName,
name: "generator",
prompt: `你是 team "${teamName}" 的 GENERATOR。
当你收到 TESTGEN-* 任务时,调用 Skill(skill="team-testing", args="--role=generator") 执行。
当前需求: ${taskDescription}
## 角色准则(强制)
- 你只能处理 TESTGEN-* 前缀的任务
- 所有输出必须带 [generator] 标识前缀
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 TESTGEN-* 任务
2. Skill(skill="team-testing", args="--role=generator") 执行
3. team_msg log + SendMessage
4. TaskUpdate completed → 检查下一个任务`
})
// Executor
Task({
subagent_type: "general-purpose",
team_name: teamName,
name: "executor",
prompt: `你是 team "${teamName}" 的 EXECUTOR。
当你收到 TESTRUN-* 任务时,调用 Skill(skill="team-testing", args="--role=executor") 执行。
当前需求: ${taskDescription}
## 角色准则(强制)
- 你只能处理 TESTRUN-* 前缀的任务
- 所有输出必须带 [executor] 标识前缀
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 TESTRUN-* 任务
2. Skill(skill="team-testing", args="--role=executor") 执行
3. team_msg log + SendMessage
4. TaskUpdate completed → 检查下一个任务`
})
// Analyst
Task({
subagent_type: "general-purpose",
team_name: teamName,
name: "analyst",
prompt: `你是 team "${teamName}" 的 ANALYST。
当你收到 TESTANA-* 任务时,调用 Skill(skill="team-testing", args="--role=analyst") 执行。
当前需求: ${taskDescription}
## 角色准则(强制)
- 你只能处理 TESTANA-* 前缀的任务
- 所有输出必须带 [analyst] 标识前缀
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 TESTANA-* 任务
2. Skill(skill="team-testing", args="--role=analyst") 执行
3. team_msg log + SendMessage
4. TaskUpdate completed → 检查下一个任务`
})
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| Unknown --role value | Error with available role list |
| Missing --role arg | Error with usage hint |
| Role file not found | Error with expected path |
| Task prefix conflict | Log warning, proceed |
| Coverage never reaches target | After 3 GC loops, accept current coverage with warning |
| Test environment broken | Notify user, suggest manual fix |

View File

@@ -0,0 +1,228 @@
# Role: analyst
测试质量分析师。负责缺陷模式分析、覆盖率差距识别、质量报告生成。
## Role Identity
- **Name**: `analyst`
- **Task Prefix**: `TESTANA-*`
- **Responsibility**: Read-only analysis (质量分析)
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[analyst]`
## Role Boundaries
### MUST
- 仅处理 `TESTANA-*` 前缀的任务
- 所有输出必须带 `[analyst]` 标识
- Phase 2 读取 shared-memory.json (所有历史数据)Phase 5 写入 analysis_report
### MUST NOT
- ❌ 生成测试、执行测试或制定策略
- ❌ 直接与其他 worker 通信
- ❌ 为其他角色创建任务
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `analysis_ready` | analyst → coordinator | Analysis completed | 分析报告完成 |
| `error` | analyst → coordinator | Processing failure | 错误上报 |
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('TESTANA-') &&
t.owner === 'analyst' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
```
### Phase 2: Context Loading + Shared Memory Read
```javascript
const sessionMatch = task.description.match(/Session:\s*([^\n]+)/)
const sessionFolder = sessionMatch?.[1]?.trim()
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
// Read all execution results
const resultFiles = Glob({ pattern: `${sessionFolder}/results/run-*.json` })
const results = resultFiles.map(f => {
try { return JSON.parse(Read(f)) } catch { return null }
}).filter(Boolean)
// Read test strategy
const strategy = Read(`${sessionFolder}/strategy/test-strategy.md`)
// Read test files for pattern analysis
const testFiles = Glob({ pattern: `${sessionFolder}/tests/**/*` })
```
### Phase 3: Quality Analysis
```javascript
const outputPath = `${sessionFolder}/analysis/quality-report.md`
// 1. Coverage Analysis
const coverageHistory = sharedMemory.coverage_history || []
const layerCoverage = {}
coverageHistory.forEach(c => {
if (!layerCoverage[c.layer] || c.timestamp > layerCoverage[c.layer].timestamp) {
layerCoverage[c.layer] = c
}
})
// 2. Defect Pattern Analysis
const defectPatterns = sharedMemory.defect_patterns || []
const patternFrequency = {}
defectPatterns.forEach(p => {
patternFrequency[p] = (patternFrequency[p] || 0) + 1
})
const sortedPatterns = Object.entries(patternFrequency)
.sort(([,a], [,b]) => b - a)
// 3. GC Loop Effectiveness
const gcRounds = sharedMemory.gc_round || 0
const gcEffectiveness = coverageHistory.length >= 2
? coverageHistory[coverageHistory.length - 1].coverage - coverageHistory[0].coverage
: 0
// 4. Test Quality Metrics
const totalTests = sharedMemory.generated_tests?.length || 0
const effectivePatterns = sharedMemory.effective_test_patterns || []
const reportContent = `# Quality Analysis Report
**Session**: ${sessionFolder}
**Pipeline**: ${sharedMemory.pipeline}
**GC Rounds**: ${gcRounds}
**Total Test Files**: ${totalTests}
## Coverage Summary
| Layer | Coverage | Target | Status |
|-------|----------|--------|--------|
${Object.entries(layerCoverage).map(([layer, data]) =>
`| ${layer} | ${data.coverage}% | ${data.target}% | ${data.coverage >= data.target ? '✅ Met' : '❌ Below'} |`
).join('\n')}
## Defect Pattern Analysis
| Pattern | Frequency | Severity |
|---------|-----------|----------|
${sortedPatterns.map(([pattern, freq]) =>
`| ${pattern} | ${freq} | ${freq >= 3 ? 'HIGH' : freq >= 2 ? 'MEDIUM' : 'LOW'} |`
).join('\n')}
### Recurring Defect Categories
${categorizeDefects(defectPatterns).map(cat =>
`- **${cat.name}**: ${cat.count} occurrences — ${cat.recommendation}`
).join('\n')}
## Generator-Critic Loop Effectiveness
- **Rounds Executed**: ${gcRounds}
- **Coverage Improvement**: ${gcEffectiveness > 0 ? '+' : ''}${gcEffectiveness.toFixed(1)}%
- **Effectiveness**: ${gcEffectiveness > 10 ? 'HIGH' : gcEffectiveness > 5 ? 'MEDIUM' : 'LOW'}
- **Recommendation**: ${gcRounds > 2 && gcEffectiveness < 5 ? 'Diminishing returns — consider manual intervention' : 'GC loop effective'}
## Coverage Gaps
${identifyCoverageGaps(sharedMemory).map(gap =>
`### ${gap.area}\n- **Current**: ${gap.current}%\n- **Gap**: ${gap.gap}%\n- **Reason**: ${gap.reason}\n- **Recommendation**: ${gap.recommendation}\n`
).join('\n')}
## Effective Test Patterns
${effectivePatterns.map(p => `- ${p}`).join('\n')}
## Recommendations
### Immediate Actions
${immediateActions.map((a, i) => `${i + 1}. ${a}`).join('\n')}
### Long-term Improvements
${longTermActions.map((a, i) => `${i + 1}. ${a}`).join('\n')}
## Quality Score
| Dimension | Score | Weight | Weighted |
|-----------|-------|--------|----------|
| Coverage Achievement | ${coverageScore}/10 | 30% | ${(coverageScore * 0.3).toFixed(1)} |
| Test Effectiveness | ${effectivenessScore}/10 | 25% | ${(effectivenessScore * 0.25).toFixed(1)} |
| Defect Detection | ${defectScore}/10 | 25% | ${(defectScore * 0.25).toFixed(1)} |
| GC Loop Efficiency | ${gcScore}/10 | 20% | ${(gcScore * 0.2).toFixed(1)} |
| **Total** | | | **${totalScore.toFixed(1)}/10** |
`
Write(outputPath, reportContent)
```
### Phase 4: Trend Analysis (if historical data available)
```javascript
// Compare with previous sessions if available
const previousSessions = Glob({ pattern: '.workflow/.team/TST-*/shared-memory.json' })
if (previousSessions.length > 1) {
// Track coverage trends, defect pattern evolution
}
```
### Phase 5: Report to Coordinator + Shared Memory Write
```javascript
sharedMemory.analysis_report = {
quality_score: totalScore,
coverage_gaps: coverageGaps,
top_defect_patterns: sortedPatterns.slice(0, 5),
gc_effectiveness: gcEffectiveness,
recommendations: immediateActions
}
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
mcp__ccw-tools__team_msg({
operation: "log", team: teamName, from: "analyst", to: "coordinator",
type: "analysis_ready",
summary: `[analyst] Quality report: score ${totalScore.toFixed(1)}/10, ${sortedPatterns.length} defect patterns, ${coverageGaps.length} coverage gaps`,
ref: outputPath
})
SendMessage({
type: "message", recipient: "coordinator",
content: `## [analyst] Quality Analysis Complete
**Quality Score**: ${totalScore.toFixed(1)}/10
**Defect Patterns**: ${sortedPatterns.length}
**Coverage Gaps**: ${coverageGaps.length}
**GC Effectiveness**: ${gcEffectiveness > 0 ? '+' : ''}${gcEffectiveness.toFixed(1)}%
**Output**: ${outputPath}
### Top Issues
${immediateActions.slice(0, 3).map((a, i) => `${i + 1}. ${a}`).join('\n')}`,
summary: `[analyst] Quality: ${totalScore.toFixed(1)}/10`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| No TESTANA-* tasks | Idle |
| No execution results | Generate report based on strategy only |
| Incomplete data | Report available metrics, flag gaps |
| Previous session data corrupted | Analyze current session only |

View File

@@ -0,0 +1,284 @@
# Role: coordinator
测试团队协调者。负责变更范围分析、测试层级选择、Generator-Critic 循环控制generator↔executor和质量门控。
## Role Identity
- **Name**: `coordinator`
- **Task Prefix**: N/A (coordinator creates tasks, doesn't receive them)
- **Responsibility**: Orchestration
- **Communication**: SendMessage to all teammates
- **Output Tag**: `[coordinator]`
## Role Boundaries
### MUST
- 所有输出必须带 `[coordinator]` 标识
- 仅负责变更分析、任务创建/分发、质量门控、结果汇报
- 管理 Generator-Critic 循环计数generator↔executor
- 根据覆盖率结果决定是否触发修订循环
### MUST NOT
-**直接编写测试、执行测试或分析覆盖率**
- ❌ 直接调用实现类 subagent
- ❌ 直接修改测试文件或源代码
- ❌ 绕过 worker 角色自行完成应委派的工作
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `pipeline_selected` | coordinator → all | Pipeline decided | 通知选定管道模式 |
| `gc_loop_trigger` | coordinator → generator | Coverage < target | 触发 generator 修订测试 |
| `quality_gate` | coordinator → all | Quality assessment | 质量门控结果 |
| `task_unblocked` | coordinator → any | Dependency resolved | 通知 worker 可用任务 |
| `error` | coordinator → all | Critical error | 上报用户 |
| `shutdown` | coordinator → all | Team dissolving | 关闭信号 |
## Execution
### Phase 1: Change Scope Analysis
```javascript
const args = "$ARGUMENTS"
const teamName = args.match(/--team-name[=\s]+([\w-]+)/)?.[1] || `testing-${Date.now().toString(36)}`
const taskDescription = args.replace(/--team-name[=\s]+[\w-]+/, '').replace(/--role[=\s]+\w+/, '').trim()
// Analyze change scope
const changedFiles = Bash(`git diff --name-only HEAD~1 2>/dev/null || git diff --name-only --cached`).split('\n').filter(Boolean)
const changedModules = new Set(changedFiles.map(f => f.split('/').slice(0, 2).join('/')))
function selectPipeline(fileCount, moduleCount) {
if (fileCount <= 3 && moduleCount <= 1) return 'targeted'
if (fileCount <= 10 && moduleCount <= 3) return 'standard'
return 'comprehensive'
}
const suggestedPipeline = selectPipeline(changedFiles.length, changedModules.size)
```
```javascript
AskUserQuestion({
questions: [
{
question: `检测到 ${changedFiles.length} 个变更文件,${changedModules.size} 个模块。选择测试模式:`,
header: "Mode",
multiSelect: false,
options: [
{ label: suggestedPipeline === 'targeted' ? "targeted (推荐)" : "targeted", description: "目标模式策略→生成L1→执行小范围变更" },
{ label: suggestedPipeline === 'standard' ? "standard (推荐)" : "standard", description: "标准模式L1→L2 渐进式(含分析)" },
{ label: suggestedPipeline === 'comprehensive' ? "comprehensive (推荐)" : "comprehensive", description: "全覆盖并行L1+L2→L3含分析" }
]
},
{
question: "覆盖率目标:",
header: "Coverage",
multiSelect: false,
options: [
{ label: "标准", description: "L1:80% L2:60% L3:40%" },
{ label: "严格", description: "L1:90% L2:75% L3:60%" },
{ label: "最低", description: "L1:60% L2:40% L3:20%" }
]
}
]
})
```
### Phase 2: Create Team + Spawn Workers
```javascript
TeamCreate({ team_name: teamName })
const topicSlug = taskDescription.toLowerCase().replace(/[^a-z0-9]+/g, '-').substring(0, 40)
const dateStr = new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString().substring(0, 10)
const sessionId = `TST-${topicSlug}-${dateStr}`
const sessionFolder = `.workflow/.team/${sessionId}`
Bash(`mkdir -p "${sessionFolder}/strategy" "${sessionFolder}/tests/L1-unit" "${sessionFolder}/tests/L2-integration" "${sessionFolder}/tests/L3-e2e" "${sessionFolder}/results" "${sessionFolder}/analysis"`)
// Initialize shared memory
const sharedMemory = {
task: taskDescription,
pipeline: selectedPipeline,
changed_files: changedFiles,
changed_modules: [...changedModules],
coverage_targets: coverageTargets,
gc_round: 0,
max_gc_rounds: 3,
test_strategy: null,
generated_tests: [],
execution_results: [],
defect_patterns: [],
effective_test_patterns: [],
coverage_history: []
}
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
const teamSession = {
session_id: sessionId,
team_name: teamName,
task: taskDescription,
pipeline: selectedPipeline,
status: "active",
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
gc_round: 0,
completed_tasks: []
}
Write(`${sessionFolder}/team-session.json`, JSON.stringify(teamSession, null, 2))
```
Spawn workers (see SKILL.md Coordinator Spawn Template).
### Phase 3: Create Task Chain
#### Targeted Pipeline
```javascript
TaskCreate({ subject: "STRATEGY-001: 变更范围分析与测试策略", description: `分析变更: ${changedFiles.join(', ')}\n\nSession: ${sessionFolder}\n输出: ${sessionFolder}/strategy/test-strategy.md\n\n确定测试层级、覆盖目标、优先级`, activeForm: "制定策略中" })
TaskUpdate({ taskId: strategyId, owner: "strategist" })
TaskCreate({ subject: "TESTGEN-001: 生成 L1 单元测试", description: `基于策略生成单元测试\n\nSession: ${sessionFolder}\n层级: L1-unit\n输入: strategy/test-strategy.md\n输出: tests/L1-unit/\n覆盖率目标: ${coverageTargets.L1}%`, activeForm: "生成测试中" })
TaskUpdate({ taskId: genId, owner: "generator", addBlockedBy: [strategyId] })
TaskCreate({ subject: "TESTRUN-001: 执行 L1 单元测试", description: `执行生成的单元测试\n\nSession: ${sessionFolder}\n输入: tests/L1-unit/\n输出: results/run-001.json + coverage-001.json\n覆盖率目标: ${coverageTargets.L1}%`, activeForm: "执行测试中" })
TaskUpdate({ taskId: runId, owner: "executor", addBlockedBy: [genId] })
```
#### Standard Pipeline
```javascript
// STRATEGY-001 → TESTGEN-001(L1) → TESTRUN-001(L1) → TESTGEN-002(L2) → TESTRUN-002(L2) → TESTANA-001
// ... STRATEGY-001, TESTGEN-001, TESTRUN-001 same as targeted ...
TaskCreate({ subject: "TESTGEN-002: 生成 L2 集成测试", description: `基于 L1 结果生成集成测试\n\nSession: ${sessionFolder}\n层级: L2-integration\n输入: strategy/ + results/run-001.json\n输出: tests/L2-integration/\n覆盖率目标: ${coverageTargets.L2}%`, activeForm: "生成集成测试中" })
TaskUpdate({ taskId: gen2Id, owner: "generator", addBlockedBy: [run1Id] })
TaskCreate({ subject: "TESTRUN-002: 执行 L2 集成测试", description: `执行集成测试\n\nSession: ${sessionFolder}\n输入: tests/L2-integration/\n输出: results/run-002.json`, activeForm: "执行集成测试中" })
TaskUpdate({ taskId: run2Id, owner: "executor", addBlockedBy: [gen2Id] })
TaskCreate({ subject: "TESTANA-001: 质量分析报告", description: `分析所有测试结果\n\nSession: ${sessionFolder}\n输入: results/ + shared-memory.json\n输出: analysis/quality-report.md\n\n分析: 缺陷模式、覆盖率差距、测试有效性`, activeForm: "分析中" })
TaskUpdate({ taskId: anaId, owner: "analyst", addBlockedBy: [run2Id] })
```
#### Comprehensive Pipeline
```javascript
// STRATEGY-001 → [TESTGEN-001(L1) + TESTGEN-002(L2)] → [TESTRUN-001 + TESTRUN-002] → TESTGEN-003(L3) → TESTRUN-003 → TESTANA-001
// TESTGEN-001 and TESTGEN-002 are parallel (both blockedBy STRATEGY-001)
// TESTRUN-001 and TESTRUN-002 are parallel (blockedBy their respective TESTGEN)
// TESTGEN-003(L3) blockedBy both TESTRUN-001 and TESTRUN-002
// TESTRUN-003 blockedBy TESTGEN-003
// TESTANA-001 blockedBy TESTRUN-003
```
### Phase 4: Coordination Loop + Generator-Critic Control
| Received Message | Action |
|-----------------|--------|
| strategist: strategy_ready | Read strategy → team_msg log → TaskUpdate completed |
| generator: tests_generated | team_msg log → TaskUpdate completed → unblock TESTRUN |
| executor: tests_passed | Read coverage → **质量门控** → proceed to next layer |
| executor: tests_failed | **Generator-Critic 判断** → 决定是否触发修订 |
| executor: coverage_report | Read coverage data → update shared memory |
| analyst: analysis_ready | Read report → team_msg log → Phase 5 |
#### Generator-Critic Loop Control
```javascript
if (msgType === 'tests_failed' || msgType === 'coverage_report') {
const result = JSON.parse(Read(`${sessionFolder}/results/run-${runNum}.json`))
const sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`))
const passRate = result.pass_rate || 0
const coverage = result.coverage || 0
const target = coverageTargets[currentLayer]
const gcRound = sharedMemory.gc_round || 0
if ((passRate < 0.95 || coverage < target) && gcRound < sharedMemory.max_gc_rounds) {
// Trigger generator revision
sharedMemory.gc_round = gcRound + 1
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
// Create TESTGEN-fix task
TaskCreate({
subject: `TESTGEN-fix-${gcRound + 1}: 修订 ${currentLayer} 测试`,
description: `基于执行结果修订测试\n\nSession: ${sessionFolder}\n失败原因: ${result.failure_summary}\n覆盖率: ${coverage}% (目标: ${target}%)\n通过率: ${(passRate * 100).toFixed(1)}%`,
activeForm: "修订测试中"
})
TaskUpdate({ taskId: fixGenId, owner: "generator" })
mcp__ccw-tools__team_msg({
operation: "log", team: teamName, from: "coordinator", to: "generator",
type: "gc_loop_trigger",
summary: `[coordinator] GC round ${gcRound + 1}: coverage ${coverage}% < target ${target}%, revise tests`
})
} else if (gcRound >= sharedMemory.max_gc_rounds) {
// Max rounds exceeded — accept current coverage
mcp__ccw-tools__team_msg({
operation: "log", team: teamName, from: "coordinator", to: "all",
type: "quality_gate",
summary: `[coordinator] GC loop exhausted (${gcRound} rounds), accepting coverage ${coverage}%`
})
} else {
// Coverage met — proceed
mcp__ccw-tools__team_msg({
operation: "log", team: teamName, from: "coordinator", to: "all",
type: "quality_gate",
summary: `[coordinator] ${currentLayer} coverage ${coverage}% >= target ${target}%, proceeding`
})
}
}
```
### Phase 5: Report + Persist
```javascript
const sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`))
const analysisReport = Read(`${sessionFolder}/analysis/quality-report.md`)
SendMessage({
content: `## [coordinator] 测试完成
**任务**: ${taskDescription}
**管道**: ${selectedPipeline}
**GC 轮次**: ${sharedMemory.gc_round}
**变更文件**: ${changedFiles.length}
### 覆盖率
${sharedMemory.coverage_history.map(c => `- **${c.layer}**: ${c.coverage}% (目标: ${c.target}%)`).join('\n')}
### 质量报告
${analysisReport}`,
summary: `[coordinator] Testing complete: ${sharedMemory.gc_round} GC rounds`
})
updateSession(sessionFolder, { status: 'completed', completed_at: new Date().toISOString() })
AskUserQuestion({
questions: [{
question: "测试已完成。下一步:",
header: "Next",
multiSelect: false,
options: [
{ label: "新测试", description: "对新变更运行测试" },
{ label: "深化测试", description: "增加测试层级或提高覆盖率" },
{ label: "关闭团队", description: "关闭所有 teammate 并清理" }
]
}]
})
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| Teammate 无响应 | 发追踪消息2次 → 重新 spawn |
| GC 循环超限 (3轮) | 接受当前覆盖率,记录到 shared memory |
| 测试环境异常 | 上报用户,建议手动修复 |
| 所有测试失败 | 检查测试框架配置,通知 analyst 分析 |
| 覆盖率工具不可用 | 降级为通过率判断 |

View File

@@ -0,0 +1,204 @@
# Role: executor
测试执行者。执行测试、收集覆盖率、尝试自动修复失败。作为 Generator-Critic 循环中的 Critic 角色。
## Role Identity
- **Name**: `executor`
- **Task Prefix**: `TESTRUN-*`
- **Responsibility**: Validation (测试执行与验证)
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[executor]`
## Role Boundaries
### MUST
- 仅处理 `TESTRUN-*` 前缀的任务
- 所有输出必须带 `[executor]` 标识
- Phase 2 读取 shared-memory.jsonPhase 5 写入 execution_results + defect_patterns
- 报告覆盖率和通过率供 coordinator 做 GC 判断
### MUST NOT
- ❌ 生成新测试、制定策略或分析趋势
- ❌ 直接与其他 worker 通信
- ❌ 为其他角色创建任务
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `tests_passed` | executor → coordinator | All tests pass + coverage met | 测试通过 |
| `tests_failed` | executor → coordinator | Tests fail or coverage below target | 测试失败/覆盖不足 |
| `coverage_report` | executor → coordinator | Coverage data collected | 覆盖率数据 |
| `error` | executor → coordinator | Execution environment failure | 错误上报 |
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('TESTRUN-') &&
t.owner === 'executor' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
```
### Phase 2: Context Loading + Shared Memory Read
```javascript
const sessionMatch = task.description.match(/Session:\s*([^\n]+)/)
const sessionFolder = sessionMatch?.[1]?.trim()
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
const framework = sharedMemory.test_strategy?.framework || 'Jest'
const coverageTarget = parseInt(task.description.match(/覆盖率目标:\s*(\d+)/)?.[1] || '80')
// Find test files to execute
const testDir = task.description.match(/输入:\s*([^\n]+)/)?.[1]?.trim()
const testFiles = Glob({ pattern: `${sessionFolder}/${testDir || 'tests'}/**/*` })
```
### Phase 3: Test Execution + Fix Cycle
```javascript
// Determine test command based on framework
const testCommands = {
'Jest': `npx jest --coverage --json --outputFile=${sessionFolder}/results/jest-output.json`,
'Pytest': `python -m pytest --cov --cov-report=json:${sessionFolder}/results/coverage.json -v`,
'Vitest': `npx vitest run --coverage --reporter=json`
}
const testCommand = testCommands[framework] || testCommands['Jest']
// Execute tests with auto-fix cycle (max 3 iterations)
let iteration = 0
const MAX_FIX_ITERATIONS = 3
let lastResult = null
let passRate = 0
let coverage = 0
while (iteration < MAX_FIX_ITERATIONS) {
lastResult = Bash(`${testCommand} 2>&1 || true`)
// Parse results
const passed = !lastResult.includes('FAIL') && !lastResult.includes('FAILED')
passRate = parsePassRate(lastResult)
coverage = parseCoverage(lastResult)
if (passed && coverage >= coverageTarget) break
if (iteration < MAX_FIX_ITERATIONS - 1 && !passed) {
// Attempt auto-fix for simple failures (import errors, type mismatches)
Task({
subagent_type: "code-developer",
run_in_background: false,
description: `Fix test failures (iteration ${iteration + 1})`,
prompt: `Fix these test failures:\n${lastResult.substring(0, 3000)}\n\nOnly fix the test files, not the source code.`
})
}
iteration++
}
// Save results
const runNum = task.subject.match(/TESTRUN-(\d+)/)?.[1] || '001'
const resultData = {
run_id: `run-${runNum}`,
pass_rate: passRate,
coverage: coverage,
coverage_target: coverageTarget,
iterations: iteration,
passed: passRate >= 0.95 && coverage >= coverageTarget,
failure_summary: passRate < 0.95 ? extractFailures(lastResult) : null,
timestamp: new Date().toISOString()
}
Write(`${sessionFolder}/results/run-${runNum}.json`, JSON.stringify(resultData, null, 2))
```
### Phase 4: Defect Pattern Extraction
```javascript
// Extract defect patterns from failures
if (resultData.failure_summary) {
const newPatterns = extractDefectPatterns(lastResult)
// Common patterns: null reference, async timing, import errors, type mismatches
resultData.defect_patterns = newPatterns
}
// Record effective test patterns (from passing tests)
if (passRate > 0.8) {
const effectivePatterns = extractEffectivePatterns(testFiles)
resultData.effective_patterns = effectivePatterns
}
```
### Phase 5: Report to Coordinator + Shared Memory Write
```javascript
// Update shared memory
sharedMemory.execution_results.push(resultData)
if (resultData.defect_patterns) {
sharedMemory.defect_patterns = [
...sharedMemory.defect_patterns,
...resultData.defect_patterns
]
}
if (resultData.effective_patterns) {
sharedMemory.effective_test_patterns = [
...new Set([...sharedMemory.effective_test_patterns, ...resultData.effective_patterns])
]
}
sharedMemory.coverage_history.push({
layer: testDir,
coverage: coverage,
target: coverageTarget,
pass_rate: passRate,
timestamp: new Date().toISOString()
})
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
const msgType = resultData.passed ? "tests_passed" : "tests_failed"
mcp__ccw-tools__team_msg({
operation: "log", team: teamName, from: "executor", to: "coordinator",
type: msgType,
summary: `[executor] ${msgType}: pass=${(passRate*100).toFixed(1)}%, coverage=${coverage}% (target: ${coverageTarget}%), iterations=${iteration}`,
ref: `${sessionFolder}/results/run-${runNum}.json`
})
SendMessage({
type: "message", recipient: "coordinator",
content: `## [executor] Test Execution Results
**Task**: ${task.subject}
**Pass Rate**: ${(passRate * 100).toFixed(1)}%
**Coverage**: ${coverage}% (target: ${coverageTarget}%)
**Fix Iterations**: ${iteration}/${MAX_FIX_ITERATIONS}
**Status**: ${resultData.passed ? '✅ PASSED' : '❌ NEEDS REVISION'}
${resultData.defect_patterns ? `### Defect Patterns\n${resultData.defect_patterns.map(p => `- ${p}`).join('\n')}` : ''}`,
summary: `[executor] ${resultData.passed ? 'PASSED' : 'FAILED'}: ${coverage}% coverage`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| No TESTRUN-* tasks | Idle |
| Test command fails to start | Check framework installation, notify coordinator |
| Coverage tool unavailable | Report pass rate only |
| All tests timeout | Increase timeout, retry once |
| Auto-fix makes tests worse | Revert, report original failures |

View File

@@ -0,0 +1,192 @@
# Role: generator
测试用例生成者。按层级L1单元/L2集成/L3 E2E生成测试代码。作为 Generator-Critic 循环中的 Generator 角色。
## Role Identity
- **Name**: `generator`
- **Task Prefix**: `TESTGEN-*`
- **Responsibility**: Code generation (测试代码生成)
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[generator]`
## Role Boundaries
### MUST
- 仅处理 `TESTGEN-*` 前缀的任务
- 所有输出必须带 `[generator]` 标识
- Phase 2 读取 shared-memory.json + test strategyPhase 5 写入 generated_tests
- 生成可直接执行的测试代码
### MUST NOT
- ❌ 执行测试、分析覆盖率或制定策略
- ❌ 直接与其他 worker 通信
- ❌ 为其他角色创建任务
- ❌ 修改源代码(仅生成测试代码)
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `tests_generated` | generator → coordinator | Tests created | 测试生成完成 |
| `tests_revised` | generator → coordinator | Tests revised after failure | 修订测试完成 (GC 循环) |
| `error` | generator → coordinator | Processing failure | 错误上报 |
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('TESTGEN-') &&
t.owner === 'generator' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
```
### Phase 2: Context Loading + Shared Memory Read
```javascript
const sessionMatch = task.description.match(/Session:\s*([^\n]+)/)
const sessionFolder = sessionMatch?.[1]?.trim()
const layerMatch = task.description.match(/层级:\s*(\S+)/)
const layer = layerMatch?.[1] || 'L1-unit'
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
// Read strategy
const strategy = Read(`${sessionFolder}/strategy/test-strategy.md`)
// Read source files to test
const targetFiles = sharedMemory.test_strategy?.priority_files || sharedMemory.changed_files || []
const sourceContents = {}
for (const file of targetFiles.slice(0, 20)) {
try { sourceContents[file] = Read(file) } catch {}
}
// Check if this is a revision (GC loop)
const isRevision = task.subject.includes('fix') || task.subject.includes('修订')
let previousFailures = null
if (isRevision) {
const resultFiles = Glob({ pattern: `${sessionFolder}/results/*.json` })
if (resultFiles.length > 0) {
try { previousFailures = JSON.parse(Read(resultFiles[resultFiles.length - 1])) } catch {}
}
}
// Read existing test patterns from shared memory
const effectivePatterns = sharedMemory.effective_test_patterns || []
```
### Phase 3: Test Generation
```javascript
const framework = sharedMemory.test_strategy?.framework || 'Jest'
// Determine complexity for delegation
const fileCount = Object.keys(sourceContents).length
if (fileCount <= 3) {
// Direct generation — write test files inline
for (const [file, content] of Object.entries(sourceContents)) {
const testPath = generateTestPath(file, layer)
const testCode = generateTestCode(file, content, layer, framework, {
isRevision,
previousFailures,
effectivePatterns
})
Write(testPath, testCode)
}
} else {
// Delegate to code-developer for batch generation
Task({
subagent_type: "code-developer",
run_in_background: false,
description: `Generate ${layer} tests`,
prompt: `Generate ${layer} tests using ${framework} for the following files:
${Object.entries(sourceContents).map(([f, c]) => `### ${f}\n\`\`\`\n${c.substring(0, 2000)}\n\`\`\``).join('\n\n')}
${isRevision ? `\n## Previous Failures\n${JSON.stringify(previousFailures?.failures?.slice(0, 10), null, 2)}` : ''}
${effectivePatterns.length > 0 ? `\n## Effective Patterns (from previous rounds)\n${effectivePatterns.map(p => `- ${p}`).join('\n')}` : ''}
Write test files to: ${sessionFolder}/tests/${layer}/
Use ${framework} conventions.
Each test file should cover: happy path, edge cases, error handling.`
})
}
const generatedTestFiles = Glob({ pattern: `${sessionFolder}/tests/${layer}/**/*` })
```
### Phase 4: Self-Validation
```javascript
// Verify generated tests are syntactically valid
const syntaxCheck = Bash(`cd "${sessionFolder}" && npx tsc --noEmit tests/${layer}/**/*.ts 2>&1 || true`)
const hasSyntaxErrors = syntaxCheck.includes('error TS')
if (hasSyntaxErrors) {
// Attempt auto-fix for common issues (imports, types)
}
// Verify minimum test count
const testFileCount = generatedTestFiles.length
```
### Phase 5: Report to Coordinator + Shared Memory Write
```javascript
sharedMemory.generated_tests = [
...sharedMemory.generated_tests,
...generatedTestFiles.map(f => ({
file: f,
layer: layer,
round: isRevision ? sharedMemory.gc_round : 0,
revised: isRevision
}))
]
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
const msgType = isRevision ? "tests_revised" : "tests_generated"
mcp__ccw-tools__team_msg({
operation: "log", team: teamName, from: "generator", to: "coordinator",
type: msgType,
summary: `[generator] ${isRevision ? 'Revised' : 'Generated'} ${testFileCount} ${layer} test files`,
ref: `${sessionFolder}/tests/${layer}/`
})
SendMessage({
type: "message", recipient: "coordinator",
content: `## [generator] Tests ${isRevision ? 'Revised' : 'Generated'}
**Layer**: ${layer}
**Files**: ${testFileCount}
**Framework**: ${framework}
**Revision**: ${isRevision ? 'Yes (GC round ' + sharedMemory.gc_round + ')' : 'No'}
**Output**: ${sessionFolder}/tests/${layer}/`,
summary: `[generator] ${testFileCount} ${layer} tests ${isRevision ? 'revised' : 'generated'}`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| No TESTGEN-* tasks | Idle |
| Source file not found | Skip, notify coordinator |
| Test framework unknown | Default to Jest patterns |
| Revision with no failure data | Generate additional tests instead of revising |
| Syntax errors in generated tests | Auto-fix imports and types |

View File

@@ -0,0 +1,179 @@
# Role: strategist
测试策略制定者。分析 git diff、确定测试层级、定义覆盖率目标和测试优先级。
## Role Identity
- **Name**: `strategist`
- **Task Prefix**: `STRATEGY-*`
- **Responsibility**: Read-only analysis (策略分析)
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[strategist]`
## Role Boundaries
### MUST
- 仅处理 `STRATEGY-*` 前缀的任务
- 所有输出必须带 `[strategist]` 标识
- Phase 2 读取 shared-memory.jsonPhase 5 写入 test_strategy
### MUST NOT
- ❌ 生成测试代码、执行测试或分析结果
- ❌ 直接与其他 worker 通信
- ❌ 为其他角色创建任务
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `strategy_ready` | strategist → coordinator | Strategy completed | 策略制定完成 |
| `error` | strategist → coordinator | Processing failure | 错误上报 |
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('STRATEGY-') &&
t.owner === 'strategist' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
```
### Phase 2: Context Loading + Shared Memory Read
```javascript
const sessionMatch = task.description.match(/Session:\s*([^\n]+)/)
const sessionFolder = sessionMatch?.[1]?.trim()
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
const changedFiles = sharedMemory.changed_files || []
const changedModules = sharedMemory.changed_modules || []
// Read git diff for detailed analysis
const gitDiff = Bash(`git diff HEAD~1 -- ${changedFiles.join(' ')} 2>/dev/null || git diff --cached -- ${changedFiles.join(' ')}`)
// Detect test framework
const hasJest = Bash(`test -f jest.config.js || test -f jest.config.ts && echo "yes" || echo "no"`).trim() === 'yes'
const hasPytest = Bash(`test -f pytest.ini || test -f pyproject.toml && echo "yes" || echo "no"`).trim() === 'yes'
const hasVitest = Bash(`test -f vitest.config.ts || test -f vitest.config.js && echo "yes" || echo "no"`).trim() === 'yes'
```
### Phase 3: Strategy Formulation
```javascript
// Analyze changes by type:
// - New files → need new tests
// - Modified functions → need updated tests
// - Deleted files → need test cleanup
// - Config changes → may need integration tests
const outputPath = `${sessionFolder}/strategy/test-strategy.md`
const strategyContent = `# Test Strategy
**Changed Files**: ${changedFiles.length}
**Changed Modules**: ${changedModules.join(', ')}
**Test Framework**: ${hasJest ? 'Jest' : hasPytest ? 'Pytest' : hasVitest ? 'Vitest' : 'Unknown'}
## Change Analysis
| File | Change Type | Impact | Priority |
|------|------------|--------|----------|
${changeAnalysis.map(c => `| ${c.file} | ${c.type} | ${c.impact} | ${c.priority} |`).join('\n')}
## Test Layer Recommendations
### L1: Unit Tests
- **Scope**: ${l1Scope.join(', ')}
- **Coverage Target**: ${coverageTargets.L1}%
- **Priority Files**: ${l1Priority.join(', ')}
- **Test Patterns**: ${l1Patterns.join(', ')}
### L2: Integration Tests
- **Scope**: ${l2Scope.join(', ')}
- **Coverage Target**: ${coverageTargets.L2}%
- **Integration Points**: ${integrationPoints.join(', ')}
### L3: E2E Tests
- **Scope**: ${l3Scope.join(', ')}
- **Coverage Target**: ${coverageTargets.L3}%
- **User Scenarios**: ${userScenarios.join(', ')}
## Risk Assessment
| Risk | Probability | Impact | Mitigation |
|------|------------|--------|------------|
${risks.map(r => `| ${r.risk} | ${r.probability} | ${r.impact} | ${r.mitigation} |`).join('\n')}
## Test Execution Order
1. L1 unit tests for high-priority changed files
2. L1 unit tests for dependent modules
3. L2 integration tests for cross-module interactions
4. L3 E2E tests for affected user scenarios
`
Write(outputPath, strategyContent)
```
### Phase 4: Self-Validation
```javascript
// Verify strategy completeness
const hasAllLayers = l1Scope.length > 0
const hasCoverageTargets = coverageTargets.L1 > 0
const hasPriorityFiles = l1Priority.length > 0
if (!hasAllLayers || !hasCoverageTargets) {
// Fill gaps
}
```
### Phase 5: Report to Coordinator + Shared Memory Write
```javascript
sharedMemory.test_strategy = {
framework: hasJest ? 'Jest' : hasPytest ? 'Pytest' : hasVitest ? 'Vitest' : 'Unknown',
layers: { L1: l1Scope, L2: l2Scope, L3: l3Scope },
coverage_targets: coverageTargets,
priority_files: l1Priority,
risks: risks
}
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
mcp__ccw-tools__team_msg({
operation: "log", team: teamName, from: "strategist", to: "coordinator",
type: "strategy_ready",
summary: `[strategist] Strategy complete: ${changedFiles.length} files, L1-L3 layers defined`,
ref: outputPath
})
SendMessage({
type: "message", recipient: "coordinator",
content: `## [strategist] Test Strategy Ready\n\n**Files**: ${changedFiles.length}\n**Layers**: L1(${l1Scope.length} targets), L2(${l2Scope.length}), L3(${l3Scope.length})\n**Framework**: ${sharedMemory.test_strategy.framework}\n**Output**: ${outputPath}`,
summary: `[strategist] Strategy ready`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| No STRATEGY-* tasks | Idle |
| No changed files | Analyze full codebase, recommend smoke tests |
| Unknown test framework | Recommend Jest/Pytest based on project language |
| All files are config | Recommend integration tests only |

View File

@@ -0,0 +1,93 @@
{
"team_name": "team-testing",
"team_display_name": "Team Testing",
"description": "Testing team with Generator-Critic loop, shared defect memory, and progressive test layers",
"version": "1.0.0",
"roles": {
"coordinator": {
"task_prefix": null,
"responsibility": "Change scope analysis, layer selection, quality gating",
"message_types": ["pipeline_selected", "gc_loop_trigger", "quality_gate", "task_unblocked", "error", "shutdown"]
},
"strategist": {
"task_prefix": "STRATEGY",
"responsibility": "Analyze git diff, determine test layers, define coverage targets",
"message_types": ["strategy_ready", "error"]
},
"generator": {
"task_prefix": "TESTGEN",
"responsibility": "Generate test cases by layer (unit/integration/E2E)",
"message_types": ["tests_generated", "tests_revised", "error"]
},
"executor": {
"task_prefix": "TESTRUN",
"responsibility": "Execute tests, collect coverage, auto-fix failures",
"message_types": ["tests_passed", "tests_failed", "coverage_report", "error"]
},
"analyst": {
"task_prefix": "TESTANA",
"responsibility": "Defect pattern analysis, coverage gap analysis, quality report",
"message_types": ["analysis_ready", "error"]
}
},
"pipelines": {
"targeted": {
"description": "Small scope: strategy → generate L1 → run",
"task_chain": ["STRATEGY-001", "TESTGEN-001", "TESTRUN-001"],
"gc_loops": 0
},
"standard": {
"description": "Progressive: L1 → L2 with analysis",
"task_chain": ["STRATEGY-001", "TESTGEN-001", "TESTRUN-001", "TESTGEN-002", "TESTRUN-002", "TESTANA-001"],
"gc_loops": 1
},
"comprehensive": {
"description": "Full coverage: parallel L1+L2, then L3 with analysis",
"task_chain": ["STRATEGY-001", "TESTGEN-001", "TESTGEN-002", "TESTRUN-001", "TESTRUN-002", "TESTGEN-003", "TESTRUN-003", "TESTANA-001"],
"gc_loops": 2,
"parallel_groups": [["TESTGEN-001", "TESTGEN-002"], ["TESTRUN-001", "TESTRUN-002"]]
}
},
"innovation_patterns": {
"generator_critic": {
"generator": "generator",
"critic": "executor",
"max_rounds": 3,
"convergence_trigger": "coverage >= target && pass_rate >= 0.95"
},
"shared_memory": {
"file": "shared-memory.json",
"fields": {
"strategist": "test_strategy",
"generator": "generated_tests",
"executor": "execution_results",
"analyst": "analysis_report"
},
"persistent_fields": ["defect_patterns", "effective_test_patterns", "coverage_history"]
},
"dynamic_pipeline": {
"selector": "coordinator",
"criteria": "changed_file_count + module_count + change_type"
}
},
"test_layers": {
"L1": { "name": "Unit Tests", "coverage_target": 80, "description": "Function-level isolation tests" },
"L2": { "name": "Integration Tests", "coverage_target": 60, "description": "Module interaction tests" },
"L3": { "name": "E2E Tests", "coverage_target": 40, "description": "User scenario end-to-end tests" }
},
"collaboration_patterns": ["CP-1", "CP-3", "CP-5"],
"session_dirs": {
"base": ".workflow/.team/TST-{slug}-{YYYY-MM-DD}/",
"strategy": "strategy/",
"tests": "tests/",
"results": "results/",
"analysis": "analysis/",
"messages": ".workflow/.team-msg/{team-name}/"
}
}

View File

@@ -0,0 +1,378 @@
---
name: team-uidesign
description: Unified team skill for UI design team. All roles invoke this skill with --role arg for role-specific execution. CP-9 Dual-Track design+implementation.
allowed-tools: TeamCreate(*), TeamDelete(*), SendMessage(*), TaskCreate(*), TaskUpdate(*), TaskList(*), TaskGet(*), Task(*), AskUserQuestion(*), TodoWrite(*), Read(*), Write(*), Edit(*), Bash(*), Glob(*), Grep(*), WebFetch(*), WebSearch(*)
---
# Team UI Design
Unified team skill for UI design covering design system analysis, token definition, component specification, accessibility audit, and code implementation. All team members invoke this skill with `--role=xxx` to route to role-specific execution.
## Architecture Overview
```
┌─────────────────────────────────────────────────┐
│ Skill(skill="team-uidesign", args="--role=xxx") │
└───────────────────┬─────────────────────────────┘
│ Role Router
┌───────┬───────┼───────┬───────┐
↓ ↓ ↓ ↓ ↓
┌──────────┐┌──────────┐┌──────────┐┌──────────┐┌──────────┐
│coordinator││researcher││ designer ││ reviewer ││implementer│
│ roles/ ││ roles/ ││ roles/ ││ roles/ ││ roles/ │
└──────────┘└──────────┘└──────────┘└──────────┘└───────────┘
```
## Role Router
### Input Parsing
Parse `$ARGUMENTS` to extract `--role`:
```javascript
const args = "$ARGUMENTS"
const roleMatch = args.match(/--role[=\s]+(\w+)/)
if (!roleMatch) {
throw new Error("Missing --role argument. Available roles: coordinator, researcher, designer, reviewer, implementer")
}
const role = roleMatch[1]
const teamName = args.match(/--team[=\s]+([\w-]+)/)?.[1] || "uidesign"
```
### Role Dispatch
```javascript
const VALID_ROLES = {
"coordinator": { file: "roles/coordinator.md", prefix: null },
"researcher": { file: "roles/researcher.md", prefix: "RESEARCH" },
"designer": { file: "roles/designer.md", prefix: "DESIGN" },
"reviewer": { file: "roles/reviewer.md", prefix: "AUDIT" },
"implementer": { file: "roles/implementer.md", prefix: "BUILD" }
}
if (!VALID_ROLES[role]) {
throw new Error(`Unknown role: ${role}. Available: ${Object.keys(VALID_ROLES).join(', ')}`)
}
// Read and execute role-specific logic
Read(VALID_ROLES[role].file)
// → Execute the 5-phase process defined in that file
```
### Available Roles
| Role | Task Prefix | Responsibility | Role File |
|------|-------------|----------------|-----------|
| `coordinator` | N/A | Scope assessment, dual-track orchestration, sync point management | [roles/coordinator.md](roles/coordinator.md) |
| `researcher` | RESEARCH-* | Design system analysis, component inventory, accessibility audit | [roles/researcher.md](roles/researcher.md) |
| `designer` | DESIGN-* | Design token definition, component specs, layout design | [roles/designer.md](roles/designer.md) |
| `reviewer` | AUDIT-* | Design consistency, accessibility compliance, visual audit | [roles/reviewer.md](roles/reviewer.md) |
| `implementer` | BUILD-* | Component code implementation, CSS generation, design token consumption | [roles/implementer.md](roles/implementer.md) |
## Shared Infrastructure
### Role Isolation Rules
**核心原则**: 每个角色仅能执行自己职责范围内的工作。
#### Output Tagging强制
所有角色的输出必须带 `[role_name]` 标识前缀:
```javascript
SendMessage({
content: `## [${role}] ...`,
summary: `[${role}] ...`
})
mcp__ccw-tools__team_msg({
summary: `[${role}] ...`
})
```
#### Coordinator 隔离
| 允许 | 禁止 |
|------|------|
| 需求澄清 (AskUserQuestion) | ❌ 直接编写/修改代码 |
| 创建任务链 (TaskCreate) | ❌ 调用实现类 subagent |
| 分发任务给 worker | ❌ 直接执行分析/测试/审查 |
| 监控进度 (消息总线) | ❌ 绕过 worker 自行完成任务 |
| 汇报结果给用户 | ❌ 修改源代码或产物文件 |
#### Worker 隔离
| 允许 | 禁止 |
|------|------|
| 处理自己前缀的任务 | ❌ 处理其他角色前缀的任务 |
| SendMessage 给 coordinator | ❌ 直接与其他 worker 通信 |
| 使用 Toolbox 中声明的工具 | ❌ 为其他角色创建任务 (TaskCreate) |
### Message Bus (All Roles)
Every SendMessage **before**, must call `mcp__ccw-tools__team_msg` to log:
```javascript
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: role,
to: "coordinator",
type: "<type>",
summary: `[${role}] <summary>`,
ref: "<file_path>"
})
```
**Message types by role**:
| Role | Types |
|------|-------|
| coordinator | `task_unblocked`, `sync_checkpoint`, `fix_required`, `error`, `shutdown` |
| researcher | `research_ready`, `research_progress`, `error` |
| designer | `design_ready`, `design_revision`, `design_progress`, `error` |
| reviewer | `audit_result`, `audit_passed`, `fix_required`, `error` |
| implementer | `build_complete`, `build_progress`, `error` |
### CLI Fallback
`mcp__ccw-tools__team_msg` MCP 不可用时:
```javascript
Bash(`ccw team log --team "${teamName}" --from "${role}" --to "coordinator" --type "<type>" --summary "<summary>" --json`)
```
### Task Lifecycle (All Worker Roles)
```javascript
// Standard task lifecycle every worker role follows
// Phase 1: Discovery
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith(`${VALID_ROLES[role].prefix}-`) &&
t.owner === role &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (myTasks.length === 0) return // idle
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
// Phase 2-4: Role-specific (see roles/{role}.md)
// Phase 5: Report + Loop — 所有输出必须带 [role] 标识
mcp__ccw-tools__team_msg({ operation: "log", team: teamName, from: role, to: "coordinator", type: "...", summary: `[${role}] ...` })
SendMessage({ type: "message", recipient: "coordinator", content: `## [${role}] ...`, summary: `[${role}] ...` })
TaskUpdate({ taskId: task.id, status: 'completed' })
// Check for next task → back to Phase 1
```
## Three-Pipeline Architecture
### CP-9 Dual-Track Concept
```
Track A (Design): RESEARCH → DESIGN(tokens) → DESIGN(components) → ...
│ │
Sync Point 1 Sync Point 2
│ │
Track B (Build): BUILD(tokens) ──→ BUILD(components) → ...
```
Design and implementation proceed in parallel after sync checkpoints. Each sync point validates that design artifacts are stable enough for implementation to consume.
### Pipeline Modes
```
component (单组件):
RESEARCH-001 → DESIGN-001 → AUDIT-001 → BUILD-001
system (设计系统 - 双轨):
Track A: RESEARCH-001 → DESIGN-001(tokens) → DESIGN-002(components)
Sync-1: AUDIT-001 (tokens审查)
Track B: BUILD-001(tokens, blockedBy AUDIT-001) ∥ DESIGN-002(components)
Sync-2: AUDIT-002 (components审查)
Track B: BUILD-002(components, blockedBy AUDIT-002)
full-system (完整设计系统):
RESEARCH-001 → DESIGN-001(tokens) → AUDIT-001
→ [DESIGN-002(components) + BUILD-001(tokens)](并行, blockedBy AUDIT-001)
→ AUDIT-002 → BUILD-002(components) → AUDIT-003(最终)
```
### Generator-Critic Loop
designer ↔ reviewer 循环,确保设计一致性和可访问性:
```
┌──────────┐ DESIGN artifact ┌──────────┐
│ designer │ ──────────────────────→ │ reviewer │
│(Generator)│ │ (Critic) │
│ │ ←────────────────────── │ │
└──────────┘ AUDIT feedback └──────────┘
(max 2 rounds)
Convergence: audit.score >= 8 && audit.critical_count === 0
```
### Shared Memory
```json
{
"design_token_registry": {
"colors": {}, "typography": {}, "spacing": {}, "shadows": {}
},
"style_decisions": [],
"component_inventory": [],
"accessibility_patterns": [],
"audit_history": []
}
```
每个角色在 Phase 2 读取Phase 5 写入自己负责的字段。
## Session Directory
```
.workflow/.team/UDS-{slug}-{YYYY-MM-DD}/
├── team-session.json # Session state
├── shared-memory.json # Cross-role accumulated knowledge
├── research/ # Researcher output
│ ├── design-system-analysis.json
│ ├── component-inventory.json
│ └── accessibility-audit.json
├── design/ # Designer output
│ ├── design-tokens.json
│ ├── component-specs/
│ │ └── {component-name}.md
│ └── layout-specs/
│ └── {layout-name}.md
├── audit/ # Reviewer output
│ └── audit-{NNN}.md
└── build/ # Implementer output
├── token-files/
└── component-files/
```
## Coordinator Spawn Template
When coordinator creates teammates:
```javascript
TeamCreate({ team_name: teamName })
// Researcher
Task({
subagent_type: "general-purpose",
team_name: teamName,
name: "researcher",
prompt: `你是 team "${teamName}" 的 RESEARCHER。
当你收到 RESEARCH-* 任务时,调用 Skill(skill="team-uidesign", args="--role=researcher") 执行。
当前需求: ${taskDescription}
约束: ${constraints}
Session: ${sessionFolder}
## 角色准则(强制)
- 你只能处理 RESEARCH-* 前缀的任务
- 所有输出必须带 [researcher] 标识前缀
- 仅与 coordinator 通信
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 RESEARCH-* 任务
2. Skill(skill="team-uidesign", args="--role=researcher") 执行
3. team_msg log + SendMessage 结果给 coordinator
4. TaskUpdate completed → 检查下一个任务`
})
// Designer
Task({
subagent_type: "general-purpose",
team_name: teamName,
name: "designer",
prompt: `你是 team "${teamName}" 的 DESIGNER。
当你收到 DESIGN-* 任务时,调用 Skill(skill="team-uidesign", args="--role=designer") 执行。
当前需求: ${taskDescription}
Session: ${sessionFolder}
## 角色准则(强制)
- 你只能处理 DESIGN-* 前缀的任务
- 所有输出必须带 [designer] 标识前缀
- 仅与 coordinator 通信
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 DESIGN-* 任务
2. Skill(skill="team-uidesign", args="--role=designer") 执行
3. team_msg log + SendMessage 结果给 coordinator
4. TaskUpdate completed → 检查下一个任务`
})
// Reviewer (AUDIT)
Task({
subagent_type: "general-purpose",
team_name: teamName,
name: "reviewer",
prompt: `你是 team "${teamName}" 的 REVIEWER (审查员)。
当你收到 AUDIT-* 任务时,调用 Skill(skill="team-uidesign", args="--role=reviewer") 执行。
当前需求: ${taskDescription}
Session: ${sessionFolder}
## 角色准则(强制)
- 你只能处理 AUDIT-* 前缀的任务
- 所有输出必须带 [reviewer] 标识前缀
- 仅与 coordinator 通信
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 AUDIT-* 任务
2. Skill(skill="team-uidesign", args="--role=reviewer") 执行
3. team_msg log + SendMessage 结果给 coordinator
4. TaskUpdate completed → 检查下一个任务`
})
// Implementer (BUILD)
Task({
subagent_type: "general-purpose",
team_name: teamName,
name: "implementer",
prompt: `你是 team "${teamName}" 的 IMPLEMENTER (实现者)。
当你收到 BUILD-* 任务时,调用 Skill(skill="team-uidesign", args="--role=implementer") 执行。
当前需求: ${taskDescription}
Session: ${sessionFolder}
## 角色准则(强制)
- 你只能处理 BUILD-* 前缀的任务
- 所有输出必须带 [implementer] 标识前缀
- 仅与 coordinator 通信
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 BUILD-* 任务
2. Skill(skill="team-uidesign", args="--role=implementer") 执行
3. team_msg log + SendMessage 结果给 coordinator
4. TaskUpdate completed → 检查下一个任务`
})
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| Unknown --role value | Error with available role list |
| Missing --role arg | Error with usage hint |
| Role file not found | Error with expected path |
| AUDIT score < 6 超过 2 轮 GC | Coordinator 上报用户 |
| 双轨同步失败 | 回退到单轨顺序执行 |
| 设计令牌冲突 | Reviewer 仲裁Coordinator 介入 |
| BUILD 找不到设计文件 | 等待 Sync Point 或上报 |

View File

@@ -0,0 +1,377 @@
# Role: coordinator
UI Design team coordinator. Orchestrates design pipelines across three modes: component, system (dual-track), and full-system. Manages sync points between design and implementation tracks, controls Generator-Critic loops between designer and reviewer.
## Role Identity
- **Name**: `coordinator`
- **Task Prefix**: N/A (coordinator creates tasks, doesn't receive them)
- **Responsibility**: Dual-track orchestration, sync point management
- **Communication**: SendMessage to all teammates
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `task_unblocked` | coordinator → any | Dependency resolved / sync point passed | Notify worker of available task |
| `sync_checkpoint` | coordinator → all | Audit passed at sync point | Design artifacts stable for consumption |
| `fix_required` | coordinator → designer | Audit found issues | Create DESIGN-fix task |
| `error` | coordinator → all | Critical system error | Escalation to user |
| `shutdown` | coordinator → all | Team being dissolved | Clean shutdown signal |
## Execution
### Phase 0: Session Resume Check
```javascript
const args = "$ARGUMENTS"
const isResume = /--resume|--continue/.test(args)
if (isResume) {
const sessionDirs = Glob({ pattern: '.workflow/.team/UDS-*/team-session.json' })
const resumable = sessionDirs.map(f => {
try {
const session = JSON.parse(Read(f))
if (session.status === 'active' || session.status === 'paused') return session
} catch {}
return null
}).filter(Boolean)
if (resumable.length === 1) {
var resumedSession = resumable[0]
} else if (resumable.length > 1) {
AskUserQuestion({ questions: [{ question: "检测到多个可恢复的会话,请选择:", header: "Resume", multiSelect: false,
options: resumable.slice(0, 4).map(s => ({ label: s.session_id, description: `${s.topic} (${s.current_phase}, ${s.status})` }))
}]})
var resumedSession = resumable.find(s => s.session_id === userChoice)
}
if (resumedSession) {
// Restore and rebuild team, skip to Phase 4
const teamName = resumedSession.team_name
const sessionFolder = `.workflow/.team/${resumedSession.session_id}`
TeamCreate({ team_name: teamName })
// Spawn workers, create remaining tasks, jump to coordination loop
}
}
```
### Phase 1: Requirement Clarification
```javascript
const args = "$ARGUMENTS"
const teamNameMatch = args.match(/--team-name[=\s]+([\w-]+)/)
const teamName = teamNameMatch ? teamNameMatch[1] : `uidesign-${Date.now().toString(36)}`
const taskDescription = args.replace(/--team-name[=\s]+[\w-]+/, '').replace(/--role[=\s]+\w+/, '').replace(/--resume|--continue/, '').trim()
```
Assess scope and select pipeline:
```javascript
AskUserQuestion({
questions: [
{
question: "UI 设计范围:",
header: "Scope",
multiSelect: false,
options: [
{ label: "单组件", description: "设计并实现一个独立组件" },
{ label: "组件系统", description: "多组件 + 设计令牌系统" },
{ label: "完整设计系统", description: "从零构建完整设计系统(令牌 + 组件 + 布局)" }
]
},
{
question: "设计约束:",
header: "Constraint",
multiSelect: true,
options: [
{ label: "现有设计系统", description: "必须兼容现有设计令牌和组件" },
{ label: "WCAG AA", description: "必须满足 WCAG 2.1 AA 可访问性标准" },
{ label: "响应式", description: "必须支持 mobile/tablet/desktop" },
{ label: "暗色模式", description: "必须支持 light/dark 主题切换" }
]
}
]
})
// Map scope to pipeline
const pipelineMap = {
'单组件': 'component',
'组件系统': 'system',
'完整设计系统': 'full-system'
}
const pipeline = pipelineMap[scopeChoice]
```
### Phase 2: Create Team + Spawn Workers
```javascript
TeamCreate({ team_name: teamName })
// Session setup
const topicSlug = taskDescription.toLowerCase().replace(/[^a-z0-9]+/g, '-').substring(0, 40)
const dateStr = new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString().substring(0, 10)
const sessionId = `UDS-${topicSlug}-${dateStr}`
const sessionFolder = `.workflow/.team/${sessionId}`
// Create directory structure
Bash(`mkdir -p "${sessionFolder}/research" "${sessionFolder}/design/component-specs" "${sessionFolder}/design/layout-specs" "${sessionFolder}/audit" "${sessionFolder}/build/token-files" "${sessionFolder}/build/component-files"`)
// Initialize shared-memory.json
const sharedMemory = {
design_token_registry: { colors: {}, typography: {}, spacing: {}, shadows: {}, borders: {} },
style_decisions: [],
component_inventory: [],
accessibility_patterns: [],
audit_history: [],
_metadata: { created_at: new Date().toISOString(), pipeline: pipeline }
}
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
// Create team-session.json
const teamSession = {
session_id: sessionId,
team_name: teamName,
topic: taskDescription,
pipeline: pipeline,
status: "active",
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
current_phase: "research",
completed_tasks: [],
sync_points: [],
gc_state: { round: 0, max_rounds: 2, converged: false },
user_preferences: { scope: scopeChoice, constraints: constraintChoices },
pipeline_progress: {
total: pipeline === 'component' ? 4 : pipeline === 'system' ? 6 : 7,
completed: 0
}
}
Write(`${sessionFolder}/team-session.json`, JSON.stringify(teamSession, null, 2))
// Spawn 4 workers (see SKILL.md Coordinator Spawn Template)
```
### Phase 3: Create Task Chain
#### Component Pipeline
```javascript
// RESEARCH-001: Design system analysis
TaskCreate({ subject: "RESEARCH-001: 设计系统分析与组件调研", description: `${taskDescription}\n\nSession: ${sessionFolder}\n输出: ${sessionFolder}/research/\n\n任务:\n- 分析现有设计系统(如有)\n- 组件盘点\n- 可访问性基线审计\n- 竞品参考收集`, activeForm: "调研设计系统中" })
TaskUpdate({ taskId: researchId, owner: "researcher" })
// DESIGN-001: Component design
TaskCreate({ subject: "DESIGN-001: 组件设计与规格定义", description: `${taskDescription}\n\nSession: ${sessionFolder}\n输入: ${sessionFolder}/research/\n输出: ${sessionFolder}/design/component-specs/\n\n任务:\n- 定义设计令牌(如需)\n- 组件状态定义 (default/hover/focus/active/disabled)\n- 响应式断点\n- 交互规格`, activeForm: "设计组件中" })
TaskUpdate({ taskId: design1Id, owner: "designer", addBlockedBy: [researchId] })
// AUDIT-001: Design audit
TaskCreate({ subject: "AUDIT-001: 设计审查", description: `${taskDescription}\n\nSession: ${sessionFolder}\n输入: ${sessionFolder}/design/\n输出: ${sessionFolder}/audit/audit-001.md\n\n审查维度:\n- 设计一致性\n- 可访问性合规 (WCAG AA)\n- 状态完整性\n- 令牌使用规范`, activeForm: "审查设计中" })
TaskUpdate({ taskId: audit1Id, owner: "reviewer", addBlockedBy: [design1Id] })
// BUILD-001: Component build
TaskCreate({ subject: "BUILD-001: 组件代码实现", description: `${taskDescription}\n\nSession: ${sessionFolder}\n输入: ${sessionFolder}/design/component-specs/ + ${sessionFolder}/audit/audit-001.md\n输出: ${sessionFolder}/build/component-files/\n\n任务:\n- 消费设计令牌\n- 实现组件代码\n- CSS/样式生成\n- 可访问性属性 (ARIA)`, activeForm: "实现组件中" })
TaskUpdate({ taskId: build1Id, owner: "implementer", addBlockedBy: [audit1Id] })
```
#### System Pipeline (Dual-Track)
```javascript
// RESEARCH-001: same as component
TaskCreate({ subject: "RESEARCH-001: 设计系统全面分析", description: `...\n输出: ${sessionFolder}/research/`, activeForm: "调研设计系统中" })
TaskUpdate({ taskId: researchId, owner: "researcher" })
// DESIGN-001: Design Tokens
TaskCreate({ subject: "DESIGN-001: 设计令牌系统定义", description: `定义完整设计令牌系统\n\nSession: ${sessionFolder}\n输入: ${sessionFolder}/research/\n输出: ${sessionFolder}/design/design-tokens.json\n\n包含:\n- 颜色系统 (primary/secondary/neutral/semantic)\n- 排版系统 (font-family/size/weight/line-height)\n- 间距系统 (4px grid)\n- 阴影系统\n- 边框系统\n- 断点定义`, activeForm: "定义设计令牌中" })
TaskUpdate({ taskId: design1Id, owner: "designer", addBlockedBy: [researchId] })
// AUDIT-001: Token Audit (Sync Point 1)
TaskCreate({ subject: "AUDIT-001: 设计令牌审查 [同步点1]", description: `审查设计令牌系统\n\nSession: ${sessionFolder}\n⚡ 同步点: 通过后将解锁 BUILD-001(令牌实现) 和 DESIGN-002(组件设计) 并行执行\n\n审查维度:\n- 令牌命名规范\n- 值域合理性\n- 主题兼容性\n- 可访问性 (对比度比值)`, activeForm: "审查令牌系统中" })
TaskUpdate({ taskId: audit1Id, owner: "reviewer", addBlockedBy: [design1Id] })
// === 双轨并行段 (blockedBy AUDIT-001) ===
// DESIGN-002: Component Specs (Track A continues)
TaskCreate({ subject: "DESIGN-002: 组件规格设计", description: `基于令牌系统设计组件\n\nSession: ${sessionFolder}\n输入: ${sessionFolder}/design/design-tokens.json\n输出: ${sessionFolder}/design/component-specs/\n\n⚡ 双轨: 与 BUILD-001(令牌实现) 并行执行`, activeForm: "设计组件规格中" })
TaskUpdate({ taskId: design2Id, owner: "designer", addBlockedBy: [audit1Id] })
// BUILD-001: Token Implementation (Track B starts)
TaskCreate({ subject: "BUILD-001: 设计令牌代码实现", description: `实现设计令牌为 CSS/JS 代码\n\nSession: ${sessionFolder}\n输入: ${sessionFolder}/design/design-tokens.json\n输出: ${sessionFolder}/build/token-files/\n\n⚡ 双轨: 与 DESIGN-002(组件设计) 并行执行`, activeForm: "实现设计令牌中" })
TaskUpdate({ taskId: build1Id, owner: "implementer", addBlockedBy: [audit1Id] })
// AUDIT-002: Component Audit (Sync Point 2)
TaskCreate({ subject: "AUDIT-002: 组件设计审查 [同步点2]", description: `审查组件设计规格\n\nSession: ${sessionFolder}\n⚡ 同步点: 通过后解锁 BUILD-002(组件实现)\n\n审查维度:\n- 令牌引用正确性\n- 状态完整性\n- 响应式规格\n- 可访问性模式`, activeForm: "审查组件设计中" })
TaskUpdate({ taskId: audit2Id, owner: "reviewer", addBlockedBy: [design2Id] })
// BUILD-002: Component Implementation
TaskCreate({ subject: "BUILD-002: 组件代码实现", description: `实现组件代码\n\nSession: ${sessionFolder}\n输入: ${sessionFolder}/design/component-specs/ + ${sessionFolder}/build/token-files/\n输出: ${sessionFolder}/build/component-files/`, activeForm: "实现组件代码中" })
TaskUpdate({ taskId: build2Id, owner: "implementer", addBlockedBy: [audit2Id, build1Id] })
```
#### Full-System Pipeline
同 System Pipeline但增加 AUDIT-003 最终审查:
```javascript
// [Same as System Pipeline tasks above]
// + AUDIT-003: Final comprehensive audit
TaskCreate({ subject: "AUDIT-003: 最终设计系统审查", description: `全面审查设计系统\n\nSession: ${sessionFolder}\n\n审查维度:\n- 令牌 ↔ 组件一致性\n- 代码 ↔ 设计规格一致性\n- 跨组件一致性\n- 可访问性全面检查\n- 响应式全面检查\n\n输出: ${sessionFolder}/audit/audit-003.md + 最终评分`, activeForm: "最终审查中" })
TaskUpdate({ taskId: audit3Id, owner: "reviewer", addBlockedBy: [build2Id] })
```
### Phase 4: Coordination Loop
#### Message Handling
| Received Message | Action |
|-----------------|--------|
| Researcher: research_ready | Read research output → team_msg log → TaskUpdate completed (auto-unblocks DESIGN) |
| Designer: design_ready | Read design artifacts → team_msg log → TaskUpdate completed (auto-unblocks AUDIT) |
| Designer: design_revision | GC loop: update round count, re-assign DESIGN-fix task |
| Reviewer: audit_passed (score >= 8) | **Sync Point**: team_msg log(sync_checkpoint) → TaskUpdate completed → unblock parallel tasks |
| Reviewer: audit_result (score 6-7) | GC round < max → Create DESIGN-fix → assign designer |
| Reviewer: fix_required (score < 6) | GC round < max → Create DESIGN-fix with severity CRITICAL → assign designer |
| Reviewer: audit_result + GC round >= max | Escalate to user: "设计审查未通过 {max} 轮,需要人工介入" |
| Implementer: build_complete | team_msg log → TaskUpdate completed → check if next AUDIT unblocked |
| All tasks completed | → Phase 5 |
#### Generator-Critic Loop Control
```javascript
if (msgType === 'audit_result' || msgType === 'fix_required') {
const auditScore = msg.data.score
const criticalCount = msg.data.critical_count
const gcState = session.gc_state
if (auditScore >= 8 && criticalCount === 0) {
// Converged → proceed (mark as sync_checkpoint)
gcState.converged = true
team_msg({ type: 'sync_checkpoint', summary: `[coordinator] Sync point passed: ${msg.ref}` })
} else if (gcState.round < gcState.max_rounds) {
// Not converged → another round
gcState.round++
TaskCreate({
subject: `DESIGN-fix-${gcState.round}: 根据审查反馈修订设计`,
description: `审查反馈: ${msg.data.feedback}\n分数: ${auditScore}/10\n严重问题: ${criticalCount}\n\nSession: ${sessionFolder}\n修复后重新提交审查`,
activeForm: "修订设计中"
})
TaskUpdate({ taskId: fixTaskId, owner: "designer" })
// After designer completes fix → re-run same AUDIT task
} else {
// Exceeded max rounds → escalate
AskUserQuestion({
questions: [{
question: `设计审查 ${gcState.round} 轮后仍未通过 (分数: ${auditScore}/10, 严重问题: ${criticalCount})。如何处理?`,
header: "GC Escalation",
multiSelect: false,
options: [
{ label: "接受当前设计", description: "跳过剩余审查,继续实现" },
{ label: "再试一轮", description: "额外给一轮 GC 循环机会" },
{ label: "终止流程", description: "停止并手动处理" }
]
}]
})
}
updateSession(sessionFolder, { gc_state: gcState })
}
```
#### Dual-Track Sync Point Management
```javascript
// When AUDIT at a sync point completes with PASS:
if (isSyncPoint && auditPassed) {
// Record sync point
session.sync_points.push({
audit_task: auditTaskId,
timestamp: new Date().toISOString(),
score: auditScore
})
// Unblock parallel tasks on both tracks
// e.g., AUDIT-001 passed → unblock both DESIGN-002 and BUILD-001
team_msg({ type: 'sync_checkpoint', summary: `[coordinator] 同步点 ${auditTaskId} 通过,双轨任务已解锁` })
}
// Dual-track failure fallback:
if (dualTrackFailed) {
// Convert remaining parallel tasks to sequential
// Remove parallel dependencies, add sequential blockedBy
team_msg({ type: 'error', summary: '[coordinator] 双轨同步失败,回退到顺序执行' })
}
```
### Phase 5: Report
```javascript
// Summary based on pipeline
const report = {
pipeline: pipeline,
tasks_completed: session.completed_tasks.length,
gc_rounds: session.gc_state.round,
sync_points_passed: session.sync_points.length,
final_audit_score: lastAuditScore,
artifacts: {
research: `${sessionFolder}/research/`,
design: `${sessionFolder}/design/`,
audit: `${sessionFolder}/audit/`,
build: `${sessionFolder}/build/`
}
}
AskUserQuestion({
questions: [{
question: "UI 设计任务已完成。下一步:",
header: "Next",
multiSelect: false,
options: [
{ label: "新组件", description: "设计新的组件(复用团队)" },
{ label: "集成测试", description: "验证组件在实际页面中的表现" },
{ label: "关闭团队", description: "关闭所有 teammate 并清理" }
]
}]
})
// Update session
updateSession(sessionFolder, {
status: 'completed',
completed_at: new Date().toISOString()
})
```
## Session State Tracking
```javascript
function updateSession(sessionFolder, updates) {
const session = JSON.parse(Read(`${sessionFolder}/team-session.json`))
Object.assign(session, updates, { updated_at: new Date().toISOString() })
Write(`${sessionFolder}/team-session.json`, JSON.stringify(session, null, 2))
}
// On task completion:
updateSession(sessionFolder, {
completed_tasks: [...session.completed_tasks, taskPrefix],
pipeline_progress: { ...session.pipeline_progress, completed: session.pipeline_progress.completed + 1 }
})
// On sync point passed:
updateSession(sessionFolder, {
sync_points: [...session.sync_points, { audit: auditId, timestamp: new Date().toISOString() }]
})
// On GC round:
updateSession(sessionFolder, {
gc_state: { ...session.gc_state, round: session.gc_state.round + 1 }
})
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| 审查分数 < 6 且 GC 轮次耗尽 | 上报用户决定 |
| 双轨同步点失败 | 回退到单轨顺序执行 |
| BUILD 找不到设计文件 | 等待设计完成或上报 |
| 设计令牌冲突 | Reviewer 仲裁 |
| Worker 无响应 | 追踪消息2次无响应 → 重新 spawn |

View File

@@ -0,0 +1,330 @@
# Role: designer
Design token architect and component specification author. Defines visual language, component behavior, and responsive layouts. Acts as Generator in the designer↔reviewer Generator-Critic loop.
## Role Identity
- **Name**: `designer`
- **Task Prefix**: `DESIGN`
- **Responsibility Type**: Code generation (design artifacts)
- **Responsibility**: Design token definition, component specs, layout design
- **Toolbox**: Read, Write, Edit, Glob, Grep, Task(code-developer, universal-executor)
## Message Types
| Type | When | Content |
|------|------|---------|
| `design_ready` | Design artifact complete | Summary + file references |
| `design_revision` | GC fix iteration complete | What changed + audit feedback addressed |
| `design_progress` | Intermediate update | Current progress |
| `error` | Failure | Error details |
## Execution
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('DESIGN-') &&
t.owner === 'designer' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
// Detect task type
const isTokenTask = task.subject.includes('令牌') || task.subject.includes('token')
const isComponentTask = task.subject.includes('组件') || task.subject.includes('component')
const isFixTask = task.subject.includes('fix') || task.subject.includes('修订')
```
### Phase 2: Context Loading + Shared Memory Read
```javascript
const sessionFolder = task.description.match(/Session:\s*(.+)/)?.[1]?.trim()
// Read shared memory
let sharedMemory = {}
try {
sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`))
} catch {}
// Read research findings
let research = {}
try {
research = {
designSystem: JSON.parse(Read(`${sessionFolder}/research/design-system-analysis.json`)),
inventory: JSON.parse(Read(`${sessionFolder}/research/component-inventory.json`)),
a11y: JSON.parse(Read(`${sessionFolder}/research/accessibility-audit.json`))
}
} catch {}
// If GC fix task, read audit feedback
let auditFeedback = null
if (isFixTask) {
const feedbackMatch = task.description.match(/:\s*(.+)/s)
auditFeedback = feedbackMatch?.[1]?.trim()
// Also read the audit file
const auditFiles = Glob({ pattern: `${sessionFolder}/audit/audit-*.md` })
if (auditFiles.length > 0) {
auditFeedback = Read(auditFiles[auditFiles.length - 1])
}
}
```
### Phase 3: Core Execution
#### Token System Design (DESIGN-001 in system/full-system pipeline)
```javascript
if (isTokenTask) {
const existingTokens = research.designSystem?.existing_tokens || {}
const stylingApproach = research.designSystem?.styling_approach || 'css-variables'
// Generate design tokens following W3C Design Tokens Format
const designTokens = {
"$schema": "https://design-tokens.github.io/community-group/format/",
"color": {
"primary": {
"$type": "color",
"$value": { "light": "#1976d2", "dark": "#90caf9" }
},
"secondary": {
"$type": "color",
"$value": { "light": "#dc004e", "dark": "#f48fb1" }
},
"background": {
"$type": "color",
"$value": { "light": "#ffffff", "dark": "#121212" }
},
"surface": {
"$type": "color",
"$value": { "light": "#f5f5f5", "dark": "#1e1e1e" }
},
"text": {
"primary": {
"$type": "color",
"$value": { "light": "rgba(0,0,0,0.87)", "dark": "rgba(255,255,255,0.87)" }
},
"secondary": {
"$type": "color",
"$value": { "light": "rgba(0,0,0,0.6)", "dark": "rgba(255,255,255,0.6)" }
}
}
// ... extend based on research findings
},
"typography": {
"font-family": {
"base": { "$type": "fontFamily", "$value": ["Inter", "system-ui", "sans-serif"] },
"mono": { "$type": "fontFamily", "$value": ["JetBrains Mono", "monospace"] }
},
"font-size": {
"xs": { "$type": "dimension", "$value": "0.75rem" },
"sm": { "$type": "dimension", "$value": "0.875rem" },
"base": { "$type": "dimension", "$value": "1rem" },
"lg": { "$type": "dimension", "$value": "1.125rem" },
"xl": { "$type": "dimension", "$value": "1.25rem" },
"2xl": { "$type": "dimension", "$value": "1.5rem" },
"3xl": { "$type": "dimension", "$value": "1.875rem" }
}
},
"spacing": {
"unit": { "$type": "dimension", "$value": "4px" },
"xs": { "$type": "dimension", "$value": "4px" },
"sm": { "$type": "dimension", "$value": "8px" },
"md": { "$type": "dimension", "$value": "16px" },
"lg": { "$type": "dimension", "$value": "24px" },
"xl": { "$type": "dimension", "$value": "32px" },
"2xl": { "$type": "dimension", "$value": "48px" }
},
"shadow": {
"sm": { "$type": "shadow", "$value": "0 1px 2px rgba(0,0,0,0.05)" },
"md": { "$type": "shadow", "$value": "0 4px 6px rgba(0,0,0,0.1)" },
"lg": { "$type": "shadow", "$value": "0 10px 15px rgba(0,0,0,0.1)" }
},
"border": {
"radius": {
"sm": { "$type": "dimension", "$value": "4px" },
"md": { "$type": "dimension", "$value": "8px" },
"lg": { "$type": "dimension", "$value": "12px" },
"full": { "$type": "dimension", "$value": "9999px" }
}
},
"breakpoint": {
"mobile": { "$type": "dimension", "$value": "320px" },
"tablet": { "$type": "dimension", "$value": "768px" },
"desktop": { "$type": "dimension", "$value": "1024px" },
"wide": { "$type": "dimension", "$value": "1280px" }
}
}
// Adapt tokens based on existing design system if present
if (Object.keys(existingTokens).length > 0) {
// Merge/extend rather than replace
}
Write(`${sessionFolder}/design/design-tokens.json`, JSON.stringify(designTokens, null, 2))
}
```
#### Component Specification (DESIGN-002 or DESIGN-001 in component pipeline)
```javascript
if (isComponentTask) {
const tokens = JSON.parse(Read(`${sessionFolder}/design/design-tokens.json`))
const componentList = sharedMemory.component_inventory || []
// For each component to design, create a spec file
// Component spec includes: states, props, tokens consumed, responsive behavior, a11y
const componentSpec = `# Component Spec: {ComponentName}
## Overview
- **Type**: atom | molecule | organism
- **Purpose**: Brief description
## Design Tokens Consumed
| Token | Usage | Value Reference |
|-------|-------|-----------------|
| color.primary | Button background | {color.primary} |
| spacing.md | Internal padding | {spacing.md} |
## States
| State | Visual Changes | Interaction |
|-------|---------------|-------------|
| default | Base appearance | — |
| hover | Background lighten 10% | Mouse over |
| focus | 2px outline, offset 2px | Tab navigation |
| active | Background darken 5% | Mouse down |
| disabled | Opacity 0.5 | cursor: not-allowed |
## Responsive Behavior
| Breakpoint | Changes |
|------------|---------|
| mobile (<768px) | Full width, stacked |
| tablet (768-1024px) | Auto width |
| desktop (>1024px) | Fixed width |
## Accessibility
- **Role**: button | link | tab | ...
- **ARIA**: aria-label, aria-pressed (if toggle)
- **Keyboard**: Enter/Space to activate, Tab to focus
- **Focus indicator**: 2px solid {color.primary}, offset 2px
- **Contrast**: Text on background >= 4.5:1 (AA)
## Variants
| Variant | Description | Token Override |
|---------|-------------|----------------|
| primary | Main action | color.primary |
| secondary | Secondary action | color.secondary |
| outline | Ghost style | border only |
`
// Write spec for each component
// Actual implementation adapts to task requirements
Write(`${sessionFolder}/design/component-specs/{component-name}.md`, componentSpec)
}
```
#### GC Fix Mode (DESIGN-fix-N)
```javascript
if (isFixTask && auditFeedback) {
// Parse audit feedback for specific issues
// Re-read the affected design artifacts
// Apply fixes based on audit feedback:
// - Token value adjustments (contrast ratios, spacing)
// - Missing state definitions
// - Accessibility gaps
// - Naming convention fixes
// Re-write affected files with corrections
// Signal design_revision instead of design_ready
}
```
### Phase 4: Validation
```javascript
// Self-check design artifacts
const checks = {
tokens_valid: true, // All token values are valid
states_complete: true, // All interactive states defined
a11y_specified: true, // Accessibility attributes defined
responsive_defined: true, // Responsive breakpoints specified
token_refs_valid: true // All token references resolve
}
// Token reference integrity check
if (isTokenTask) {
// Verify all $value fields are non-empty
// Verify light/dark mode values exist for colors
}
if (isComponentTask) {
// Verify all token references ({token.path}) match defined tokens
// Verify all states are defined
// Verify a11y section is complete
}
```
### Phase 5: Report + Shared Memory Write
```javascript
// Update shared memory
if (isTokenTask) {
sharedMemory.design_token_registry = {
colors: Object.keys(designTokens.color || {}),
typography: Object.keys(designTokens.typography || {}),
spacing: Object.keys(designTokens.spacing || {}),
shadows: Object.keys(designTokens.shadow || {}),
borders: Object.keys(designTokens.border || {})
}
sharedMemory.style_decisions.push({
decision: `Token system defined with ${stylingApproach} approach`,
timestamp: new Date().toISOString()
})
}
if (isComponentTask) {
sharedMemory.style_decisions.push({
decision: `Component specs created for ${componentCount} components`,
timestamp: new Date().toISOString()
})
}
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
// Report
const msgType = isFixTask ? 'design_revision' : 'design_ready'
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: "designer",
to: "coordinator",
type: msgType,
summary: `[designer] ${isFixTask ? '设计修订完成' : '设计完成'}: ${isTokenTask ? '令牌系统' : '组件规格'}`,
ref: `${sessionFolder}/design/`
})
SendMessage({
type: "message",
recipient: "coordinator",
content: `## [designer] ${isFixTask ? '设计修订完成' : '设计产出就绪'}\n\n${isTokenTask ? '令牌系统已定义' : '组件规格已完成'}\n产出: ${sessionFolder}/design/`,
summary: `[designer] ${msgType}`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| 研究数据缺失 | 使用默认令牌 + 标记待确认 |
| 令牌冲突 | 记录决策依据,提交审查仲裁 |
| GC 修复无法满足所有审查意见 | 标记权衡取舍,让 coordinator 决定 |
| 组件数量过多 | 优先 MVP 组件,标记 post-MVP |

View File

@@ -0,0 +1,296 @@
# Role: implementer
Component code builder responsible for translating design specifications into production code. Consumes design tokens and component specs to generate CSS, JavaScript/TypeScript components, and accessibility implementations.
## Role Identity
- **Name**: `implementer`
- **Task Prefix**: `BUILD`
- **Responsibility Type**: Code generation
- **Responsibility**: Component code implementation, CSS generation, design token consumption
- **Toolbox**: Read, Write, Edit, Glob, Grep, Bash, Task(code-developer)
## Message Types
| Type | When | Content |
|------|------|---------|
| `build_complete` | Implementation finished | Changed files + summary |
| `build_progress` | Intermediate update | Current progress |
| `error` | Failure | Error details |
## Execution
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('BUILD-') &&
t.owner === 'implementer' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
// Detect build type
const isTokenBuild = task.subject.includes('令牌') || task.subject.includes('token')
const isComponentBuild = task.subject.includes('组件') || task.subject.includes('component')
```
### Phase 2: Context Loading + Shared Memory Read
```javascript
const sessionFolder = task.description.match(/Session:\s*(.+)/)?.[1]?.trim()
// Read shared memory
let sharedMemory = {}
try {
sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`))
} catch {}
const tokenRegistry = sharedMemory.design_token_registry || {}
const styleDecisions = sharedMemory.style_decisions || []
// Read design artifacts
let designTokens = null
try {
designTokens = JSON.parse(Read(`${sessionFolder}/design/design-tokens.json`))
} catch {}
// Read component specs (for component build)
let componentSpecs = []
if (isComponentBuild) {
const specFiles = Glob({ pattern: `${sessionFolder}/design/component-specs/*.md` })
componentSpecs = specFiles.map(f => ({ path: f, content: Read(f), name: f.match(/([^/\\]+)\.md$/)?.[1] }))
}
// Read audit reports for approved changes
const auditFiles = Glob({ pattern: `${sessionFolder}/audit/audit-*.md` })
const latestAudit = auditFiles.length > 0 ? Read(auditFiles[auditFiles.length - 1]) : null
// Detect project tech stack from codebase
// Read existing project patterns for code style alignment
```
### Phase 3: Core Execution
#### Token Implementation (BUILD-001: Token Files)
```javascript
if (isTokenBuild && designTokens) {
// Detect styling approach from codebase
const stylingApproach = sharedMemory.style_decisions?.find(d => d.decision.includes('approach'))
|| 'css-variables'
// Delegate to code-developer for implementation
Task({
subagent_type: "code-developer",
run_in_background: false,
prompt: `
## Design Token Implementation
Convert the following design tokens into production code.
### Design Tokens (W3C Format)
${JSON.stringify(designTokens, null, 2)}
### Requirements
1. Generate CSS custom properties (variables) for all tokens
2. Support light/dark themes via data-theme attribute or prefers-color-scheme
3. Generate TypeScript type definitions for token paths
4. Follow project's existing styling patterns
### Output Files
Write to: ${sessionFolder}/build/token-files/
Files to create:
- tokens.css — CSS custom properties with :root and [data-theme="dark"]
- tokens.ts — TypeScript constants/types for programmatic access
- README.md — Token usage guide
### Example CSS Output
:root {
--color-primary: #1976d2;
--color-text-primary: rgba(0,0,0,0.87);
--spacing-md: 16px;
/* ... */
}
[data-theme="dark"] {
--color-primary: #90caf9;
--color-text-primary: rgba(255,255,255,0.87);
/* ... */
}
### Constraints
- Use semantic token names matching the design tokens
- Ensure all color tokens have both light and dark values
- Use CSS custom properties for runtime theming
- TypeScript types should enable autocomplete
`
})
// Track output files
const tokenFiles = Glob({ pattern: `${sessionFolder}/build/token-files/*` })
}
```
#### Component Implementation (BUILD-002: Component Code)
```javascript
if (isComponentBuild && componentSpecs.length > 0) {
// For each component spec, generate implementation
for (const spec of componentSpecs) {
const componentName = spec.name
Task({
subagent_type: "code-developer",
run_in_background: false,
prompt: `
## Component Implementation: ${componentName}
### Design Specification
${spec.content}
### Design Tokens Available
Token file: ${sessionFolder}/build/token-files/tokens.css
Token types: ${sessionFolder}/build/token-files/tokens.ts
### Audit Feedback (if any)
${latestAudit ? 'Latest audit notes:\n' + latestAudit : 'No audit feedback'}
### Requirements
1. Implement component following the design spec exactly
2. Consume design tokens via CSS custom properties (var(--token-name))
3. Implement ALL states: default, hover, focus, active, disabled
4. Add ARIA attributes as specified in the design spec
5. Support responsive breakpoints from the spec
6. Follow project's component patterns (detect from existing codebase)
### Output
Write to: ${sessionFolder}/build/component-files/${componentName}/
Files:
- ${componentName}.tsx (or .vue/.svelte based on project)
- ${componentName}.css (or .module.css / styled-components)
- ${componentName}.test.tsx (basic render + state tests)
- index.ts (re-export)
### Accessibility Requirements
- Keyboard navigation must work
- Screen reader support via ARIA
- Focus indicator visible (use design token)
- Color contrast meets WCAG AA (4.5:1 text, 3:1 UI)
### Constraints
- NO hardcoded colors/spacing — all from design tokens
- Follow existing codebase patterns for component structure
- Include basic accessibility tests
`
})
}
const componentFiles = Glob({ pattern: `${sessionFolder}/build/component-files/**/*` })
}
```
### Phase 4: Validation
```javascript
// Verify build outputs exist
if (isTokenBuild) {
const requiredTokenFiles = ['tokens.css', 'tokens.ts']
const missing = requiredTokenFiles.filter(f => {
try { Read(`${sessionFolder}/build/token-files/${f}`); return false }
catch { return true }
})
if (missing.length > 0) {
// Re-run token generation for missing files
}
}
if (isComponentBuild) {
// Verify each component has at minimum: .tsx + .css + index.ts
componentSpecs.forEach(spec => {
const componentDir = `${sessionFolder}/build/component-files/${spec.name}`
const files = Glob({ pattern: `${componentDir}/*` })
if (files.length < 3) {
// Re-run component generation
}
})
}
// Token reference check: verify CSS uses var(--token-*) not hardcoded values
if (isComponentBuild) {
const cssFiles = Glob({ pattern: `${sessionFolder}/build/component-files/**/*.css` })
cssFiles.forEach(f => {
const content = Read(f)
// Check for hardcoded color values (#xxx, rgb(), etc.)
const hardcoded = content.match(/#[0-9a-fA-F]{3,8}|rgb\(|rgba\(/g) || []
if (hardcoded.length > 0) {
// Flag as warning — should use design tokens
}
})
}
```
### Phase 5: Report + Shared Memory Write
```javascript
// Update shared memory with implementation details
if (isComponentBuild) {
// Update component inventory with implementation paths
componentSpecs.forEach(spec => {
const existing = sharedMemory.component_inventory.find(c => c.name === spec.name)
if (existing) {
existing.implementation_path = `${sessionFolder}/build/component-files/${spec.name}/`
existing.implemented = true
} else {
sharedMemory.component_inventory.push({
name: spec.name,
implementation_path: `${sessionFolder}/build/component-files/${spec.name}/`,
implemented: true
})
}
})
}
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
// Collect output summary
const outputFiles = isTokenBuild
? Glob({ pattern: `${sessionFolder}/build/token-files/*` })
: Glob({ pattern: `${sessionFolder}/build/component-files/**/*` })
// Report
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: "implementer",
to: "coordinator",
type: "build_complete",
summary: `[implementer] ${isTokenBuild ? '令牌代码' : '组件代码'}实现完成, ${outputFiles.length} 个文件`,
ref: `${sessionFolder}/build/`
})
SendMessage({
type: "message",
recipient: "coordinator",
content: `## [implementer] 构建完成\n\n- 类型: ${isTokenBuild ? '设计令牌实现' : '组件代码实现'}\n- 输出文件: ${outputFiles.length}\n- 目录: ${sessionFolder}/build/${isTokenBuild ? 'token-files/' : 'component-files/'}\n\n### 产出文件\n${outputFiles.map(f => `- ${f}`).join('\n')}`,
summary: `[implementer] build_complete: ${outputFiles.length} files`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| 设计令牌文件不存在 | 等待 sync point 或报告 error |
| 组件规格不完整 | 使用默认值 + 标记待确认 |
| 代码生成失败 | 重试 1 次,仍失败则上报 |
| 检测到硬编码值 | 自动替换为令牌引用 |
| 项目技术栈未知 | 默认 React + CSS Modules |

View File

@@ -0,0 +1,229 @@
# Role: researcher
Design system analyst responsible for current state assessment, component inventory, accessibility baseline, and competitive research.
## Role Identity
- **Name**: `researcher`
- **Task Prefix**: `RESEARCH`
- **Responsibility Type**: Read-only analysis
- **Responsibility**: Design system analysis, component inventory, accessibility audit
- **Toolbox**: Read, Glob, Grep, Bash(read-only), Task(cli-explore-agent), WebSearch, WebFetch
## Message Types
| Type | When | Content |
|------|------|---------|
| `research_ready` | Research complete | Summary of findings + file references |
| `research_progress` | Intermediate update | Current progress status |
| `error` | Failure | Error details |
## Execution
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('RESEARCH-') &&
t.owner === 'researcher' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
```
### Phase 2: Context Loading + Shared Memory Read
```javascript
// Extract session folder from task description
const sessionFolder = task.description.match(/Session:\s*(.+)/)?.[1]?.trim()
// Read shared memory for accumulated knowledge
let sharedMemory = {}
try {
sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`))
} catch {}
// Read existing component inventory if any
const existingInventory = sharedMemory.component_inventory || []
const existingPatterns = sharedMemory.accessibility_patterns || []
```
### Phase 3: Core Execution
Research is divided into 3 parallel analysis streams:
#### Stream 1: Design System Analysis
```javascript
// Use cli-explore-agent for codebase analysis
Task({
subagent_type: "cli-explore-agent",
run_in_background: false,
prompt: `
## Design System Analysis
Topic: ${task.description}
Session: ${sessionFolder}
## Tasks
1. Search for existing design tokens (CSS variables, theme configs, token files)
2. Identify styling patterns (CSS-in-JS, CSS modules, utility classes, SCSS)
3. Map color palette, typography scale, spacing system
4. Find component library usage (MUI, Ant Design, custom, etc.)
## Output
Write to: ${sessionFolder}/research/design-system-analysis.json
Schema:
{
"existing_tokens": { "colors": [], "typography": [], "spacing": [], "shadows": [] },
"styling_approach": "css-modules | css-in-js | utility | scss | mixed",
"component_library": { "name": "", "version": "", "usage_count": 0 },
"custom_components": [],
"inconsistencies": [],
"_metadata": { "timestamp": "..." }
}
`
})
```
#### Stream 2: Component Inventory
```javascript
// Discover all UI components in the codebase
Task({
subagent_type: "Explore",
run_in_background: false,
prompt: `
Find all UI components in the codebase. For each component, identify:
- Component name and file path
- Props/API surface
- States supported (hover, focus, disabled, etc.)
- Accessibility attributes (ARIA labels, roles, etc.)
- Dependencies on other components
Write findings to: ${sessionFolder}/research/component-inventory.json
Schema:
{
"components": [{
"name": "", "path": "", "type": "atom|molecule|organism|template",
"props": [], "states": [], "aria_attributes": [],
"dependencies": [], "usage_count": 0
}],
"patterns": {
"naming_convention": "",
"file_structure": "",
"state_management": ""
}
}
`
})
```
#### Stream 3: Accessibility Baseline
```javascript
// Assess current accessibility state
Task({
subagent_type: "Explore",
run_in_background: false,
prompt: `
Perform accessibility baseline audit:
1. Check for ARIA attributes usage patterns
2. Identify keyboard navigation support
3. Check color contrast ratios (if design tokens found)
4. Find focus management patterns
5. Check semantic HTML usage
Write to: ${sessionFolder}/research/accessibility-audit.json
Schema:
{
"wcag_level": "none|partial-A|A|partial-AA|AA",
"aria_coverage": { "labeled": 0, "total": 0, "percentage": 0 },
"keyboard_nav": { "supported": [], "missing": [] },
"contrast_issues": [],
"focus_management": { "pattern": "", "coverage": "" },
"semantic_html": { "score": 0, "issues": [] },
"recommendations": []
}
`
})
```
### Phase 4: Validation
```javascript
// Verify all 3 research outputs exist
const requiredFiles = [
'design-system-analysis.json',
'component-inventory.json',
'accessibility-audit.json'
]
const missing = requiredFiles.filter(f => {
try { Read(`${sessionFolder}/research/${f}`); return false }
catch { return true }
})
if (missing.length > 0) {
// Re-run missing streams
}
// Compile research summary
const designAnalysis = JSON.parse(Read(`${sessionFolder}/research/design-system-analysis.json`))
const inventory = JSON.parse(Read(`${sessionFolder}/research/component-inventory.json`))
const a11yAudit = JSON.parse(Read(`${sessionFolder}/research/accessibility-audit.json`))
const researchSummary = {
design_system_exists: !!designAnalysis.component_library?.name,
styling_approach: designAnalysis.styling_approach,
total_components: inventory.components?.length || 0,
accessibility_level: a11yAudit.wcag_level,
key_findings: [],
recommendations: []
}
```
### Phase 5: Report + Shared Memory Write
```javascript
// Update shared memory
sharedMemory.component_inventory = inventory.components || []
sharedMemory.accessibility_patterns = a11yAudit.recommendations || []
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
// Log and report
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: "researcher",
to: "coordinator",
type: "research_ready",
summary: `[researcher] 调研完成: ${researchSummary.total_components} 个组件, 可访问性等级 ${researchSummary.accessibility_level}, 样式方案 ${researchSummary.styling_approach}`,
ref: `${sessionFolder}/research/`
})
SendMessage({
type: "message",
recipient: "coordinator",
content: `## [researcher] 设计系统调研完成\n\n- 现有组件: ${researchSummary.total_components}\n- 样式方案: ${researchSummary.styling_approach}\n- 可访问性等级: ${researchSummary.accessibility_level}\n- 组件库: ${designAnalysis.component_library?.name || '无'}\n\n产出目录: ${sessionFolder}/research/`,
summary: `[researcher] 调研完成`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
// Check for next task
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| 无法检测设计系统 | 报告为 "greenfield",建议从零构建 |
| 组件盘点超时 | 报告已发现部分 + 标记未扫描区域 |
| 可访问性工具不可用 | 手动抽样检查 + 降级报告 |

View File

@@ -0,0 +1,294 @@
# Role: reviewer
Design auditor responsible for consistency, accessibility compliance, and visual quality review. Acts as Critic in the designer↔reviewer Generator-Critic loop. Serves as sync point gatekeeper in dual-track pipelines.
## Role Identity
- **Name**: `reviewer`
- **Task Prefix**: `AUDIT`
- **Responsibility Type**: Read-only analysis (Validation)
- **Responsibility**: Design consistency audit, accessibility compliance, visual review
- **Toolbox**: Read, Glob, Grep, Bash(read-only), Task(Explore)
## Message Types
| Type | When | Content |
|------|------|---------|
| `audit_passed` | Score >= 8, no critical issues | Audit report + score |
| `audit_result` | Score 6-7, non-critical issues | Feedback for GC revision |
| `fix_required` | Score < 6, critical issues found | Critical issues list |
| `error` | Failure | Error details |
## Execution
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('AUDIT-') &&
t.owner === 'reviewer' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
// Detect audit type
const isTokenAudit = task.subject.includes('令牌') || task.subject.includes('token')
const isComponentAudit = task.subject.includes('组件') || task.subject.includes('component')
const isFinalAudit = task.subject.includes('最终') || task.subject.includes('final')
const isSyncPoint = task.subject.includes('同步点') || task.subject.includes('Sync')
```
### Phase 2: Context Loading + Shared Memory Read
```javascript
const sessionFolder = task.description.match(/Session:\s*(.+)/)?.[1]?.trim()
// Read shared memory for audit history
let sharedMemory = {}
try {
sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`))
} catch {}
const auditHistory = sharedMemory.audit_history || []
const tokenRegistry = sharedMemory.design_token_registry || {}
// Read design artifacts to audit
let designTokens = null
let componentSpecs = []
try {
designTokens = JSON.parse(Read(`${sessionFolder}/design/design-tokens.json`))
} catch {}
const specFiles = Glob({ pattern: `${sessionFolder}/design/component-specs/*.md` })
componentSpecs = specFiles.map(f => ({ path: f, content: Read(f) }))
// Read build artifacts if final audit
let buildArtifacts = []
if (isFinalAudit) {
const buildFiles = Glob({ pattern: `${sessionFolder}/build/**/*` })
buildArtifacts = buildFiles
}
```
### Phase 3: Core Execution
#### Audit Dimensions
4 dimensions scored on 1-10 scale:
| Dimension | Weight | Criteria |
|-----------|--------|----------|
| Consistency | 25% | Token usage, naming conventions, visual uniformity |
| Accessibility | 30% | WCAG AA compliance, ARIA attributes, keyboard nav, contrast |
| Completeness | 25% | All states defined, responsive specs, edge cases |
| Quality | 20% | Token reference integrity, documentation clarity, maintainability |
#### Token Audit (AUDIT for token systems)
```javascript
if (isTokenAudit && designTokens) {
const tokenAudit = {
consistency: { score: 0, issues: [] },
accessibility: { score: 0, issues: [] },
completeness: { score: 0, issues: [] },
quality: { score: 0, issues: [] }
}
// Consistency checks
// - Naming convention (kebab-case, semantic names)
// - Value patterns (consistent units: rem/px/%)
// - Theme completeness (light + dark for all colors)
// Accessibility checks
// - Color contrast ratios (text on background >= 4.5:1)
// - Focus indicator colors visible against backgrounds
// - Font sizes meet minimum (>= 12px / 0.75rem)
// Completeness checks
// - All token categories present (color, typography, spacing, shadow, border)
// - Breakpoints defined
// - Semantic color tokens (success, warning, error, info)
// Quality checks
// - $type metadata present (W3C format)
// - Values are valid (CSS-parseable)
// - No duplicate definitions
}
```
#### Component Audit
```javascript
if (isComponentAudit && componentSpecs.length > 0) {
componentSpecs.forEach(spec => {
// Consistency: token references resolve, naming matches convention
// Accessibility: ARIA roles defined, keyboard behavior specified, focus indicator
// Completeness: all 5 states (default/hover/focus/active/disabled), responsive breakpoints
// Quality: clear descriptions, variant system, interaction specs
})
}
```
#### Final Audit (Cross-cutting)
```javascript
if (isFinalAudit) {
// Token ↔ Component consistency
// - All token references in components resolve to defined tokens
// - No hardcoded values in component specs
// Code ↔ Design consistency (if build artifacts exist)
// - CSS variables match design tokens
// - Component implementation matches spec states
// - ARIA attributes implemented as specified
// Cross-component consistency
// - Consistent spacing patterns
// - Consistent color usage for similar elements
// - Consistent interaction patterns
}
```
#### Score Calculation
```javascript
const weights = { consistency: 0.25, accessibility: 0.30, completeness: 0.25, quality: 0.20 }
const overallScore = Math.round(
tokenAudit.consistency.score * weights.consistency +
tokenAudit.accessibility.score * weights.accessibility +
tokenAudit.completeness.score * weights.completeness +
tokenAudit.quality.score * weights.quality
)
// Severity classification
const criticalIssues = allIssues.filter(i => i.severity === 'CRITICAL')
const highIssues = allIssues.filter(i => i.severity === 'HIGH')
const mediumIssues = allIssues.filter(i => i.severity === 'MEDIUM')
// Determine signal
let signal
if (overallScore >= 8 && criticalIssues.length === 0) {
signal = 'audit_passed' // GC CONVERGED
} else if (overallScore >= 6 && criticalIssues.length === 0) {
signal = 'audit_result' // GC REVISION NEEDED
} else {
signal = 'fix_required' // GC CRITICAL FIX NEEDED
}
```
#### Audit Report Generation
```javascript
const auditNumber = task.subject.match(/AUDIT-(\d+)/)?.[1] || '001'
const auditReport = `# Audit Report: AUDIT-${auditNumber}
## Summary
- **Overall Score**: ${overallScore}/10
- **Signal**: ${signal}
- **Critical Issues**: ${criticalIssues.length}
- **High Issues**: ${highIssues.length}
- **Medium Issues**: ${mediumIssues.length}
${isSyncPoint ? `\n**⚡ Sync Point**: ${signal === 'audit_passed' ? 'PASSED — 双轨任务已解锁' : 'BLOCKED — 需要修订后重新审查'}` : ''}
## Dimension Scores
| Dimension | Score | Weight | Weighted |
|-----------|-------|--------|----------|
| Consistency | ${tokenAudit.consistency.score}/10 | 25% | ${(tokenAudit.consistency.score * 0.25).toFixed(1)} |
| Accessibility | ${tokenAudit.accessibility.score}/10 | 30% | ${(tokenAudit.accessibility.score * 0.30).toFixed(1)} |
| Completeness | ${tokenAudit.completeness.score}/10 | 25% | ${(tokenAudit.completeness.score * 0.25).toFixed(1)} |
| Quality | ${tokenAudit.quality.score}/10 | 20% | ${(tokenAudit.quality.score * 0.20).toFixed(1)} |
## Critical Issues
${criticalIssues.map(i => `- **[CRITICAL]** ${i.description}\n Location: ${i.location}\n Fix: ${i.suggestion}`).join('\n')}
## High Issues
${highIssues.map(i => `- **[HIGH]** ${i.description}\n Fix: ${i.suggestion}`).join('\n')}
## Medium Issues
${mediumIssues.map(i => `- [MEDIUM] ${i.description}`).join('\n')}
## Recommendations
${recommendations.join('\n')}
## GC Loop Status
- Signal: ${signal}
- ${signal === 'audit_passed' ? '✅ 设计通过审查' : `⚠️ 需要 designer 修订: ${criticalIssues.length + highIssues.length} 个问题需修复`}
`
Write(`${sessionFolder}/audit/audit-${auditNumber}.md`, auditReport)
```
### Phase 4: Validation
```javascript
// Verify audit report written
try {
Read(`${sessionFolder}/audit/audit-${auditNumber}.md`)
} catch {
// Re-write audit report
}
// Cross-reference with previous audits for trend
if (auditHistory.length > 0) {
const previousScore = auditHistory[auditHistory.length - 1].score
const trend = overallScore > previousScore ? 'improving' : overallScore === previousScore ? 'stable' : 'declining'
// Include trend in report
}
```
### Phase 5: Report + Shared Memory Write
```javascript
// Update shared memory
sharedMemory.audit_history.push({
audit_id: `AUDIT-${auditNumber}`,
score: overallScore,
critical_count: criticalIssues.length,
signal: signal,
is_sync_point: isSyncPoint,
timestamp: new Date().toISOString()
})
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
// Report to coordinator
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: "reviewer",
to: "coordinator",
type: signal,
summary: `[reviewer] AUDIT-${auditNumber}: 分数 ${overallScore}/10, 严重问题 ${criticalIssues.length}${isSyncPoint ? ' [同步点]' : ''}`,
ref: `${sessionFolder}/audit/audit-${auditNumber}.md`
})
SendMessage({
type: "message",
recipient: "coordinator",
content: `## [reviewer] 审查报告 AUDIT-${auditNumber}\n\n- 分数: ${overallScore}/10\n- 信号: ${signal}\n- 严重问题: ${criticalIssues.length}\n- 高级问题: ${highIssues.length}\n${isSyncPoint ? `\n⚡ **同步点**: ${signal === 'audit_passed' ? '通过' : '未通过'}` : ''}\n\n${signal !== 'audit_passed' ? `### 需修复:\n${criticalIssues.concat(highIssues).map(i => `- ${i.description}`).join('\n')}` : ''}`,
summary: `[reviewer] AUDIT-${auditNumber}: ${overallScore}/10, ${signal}`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
```
## Severity Classification
| Severity | Criteria | GC Impact |
|----------|----------|-----------|
| CRITICAL | 可访问性不合规 (对比度 <3:1), 缺少关键状态 | 阻塞 GC 收敛 |
| HIGH | 令牌引用不一致, 缺少 ARIA 属性, 部分状态缺失 | 计入 GC 评分 |
| MEDIUM | 命名不规范, 文档不完整, 次要样式问题 | 建议修复 |
| LOW | 代码风格, 可选优化 | 信息性 |
## Error Handling
| Scenario | Resolution |
|----------|------------|
| 设计文件不存在 | 报告 error通知 coordinator |
| 令牌格式无法解析 | 降级为文本审查 |
| 审查维度无法评估 | 标记为 N/A不计入总分 |

View File

@@ -0,0 +1,107 @@
{
"team_name": "uidesign",
"team_display_name": "UI Design",
"description": "UI design team with CP-9 Dual-Track for parallel design and implementation",
"version": "1.0.0",
"roles": {
"coordinator": {
"task_prefix": null,
"responsibility": "Scope assessment, dual-track orchestration, sync point management, GC loop control",
"message_types": ["task_unblocked", "sync_checkpoint", "fix_required", "error", "shutdown"]
},
"researcher": {
"task_prefix": "RESEARCH",
"responsibility": "Design system analysis, component inventory, accessibility baseline audit",
"message_types": ["research_ready", "research_progress", "error"]
},
"designer": {
"task_prefix": "DESIGN",
"responsibility": "Design token definition, component specifications, layout design",
"message_types": ["design_ready", "design_revision", "design_progress", "error"]
},
"reviewer": {
"task_prefix": "AUDIT",
"additional_prefixes": [],
"responsibility": "Design consistency audit, accessibility compliance, visual review",
"message_types": ["audit_result", "audit_passed", "fix_required", "error"]
},
"implementer": {
"task_prefix": "BUILD",
"responsibility": "Component code implementation, CSS generation, design token consumption",
"message_types": ["build_complete", "build_progress", "error"]
}
},
"pipelines": {
"component": {
"description": "Single component: research → design → audit → build",
"task_chain": ["RESEARCH-001", "DESIGN-001", "AUDIT-001", "BUILD-001"],
"complexity": "low"
},
"system": {
"description": "Design system with dual-track: design tokens → audit → parallel build+components → audit → build components",
"task_chain": [
"RESEARCH-001",
"DESIGN-001:tokens", "AUDIT-001",
"DESIGN-002:components || BUILD-001:tokens",
"AUDIT-002", "BUILD-002:components"
],
"sync_points": ["AUDIT-001", "AUDIT-002"],
"complexity": "medium"
},
"full-system": {
"description": "Complete design system with 3 audit checkpoints",
"task_chain": [
"RESEARCH-001",
"DESIGN-001:tokens", "AUDIT-001",
"DESIGN-002:components || BUILD-001:tokens",
"AUDIT-002",
"BUILD-002:components", "AUDIT-003"
],
"sync_points": ["AUDIT-001", "AUDIT-002", "AUDIT-003"],
"complexity": "high"
}
},
"innovation_patterns": {
"generator_critic": {
"generator": "designer",
"critic": "reviewer",
"max_rounds": 2,
"convergence": "audit.score >= 8 && audit.critical_count === 0",
"escalation": "Coordinator intervenes after max rounds"
},
"shared_memory": {
"file": "shared-memory.json",
"fields": {
"researcher": ["component_inventory", "accessibility_patterns"],
"designer": ["design_token_registry", "style_decisions"],
"reviewer": ["audit_history"],
"implementer": ["component_inventory"]
}
},
"dynamic_pipeline": {
"criteria": {
"component": "scope.component_count <= 1",
"system": "scope.component_count <= 5 && scope.has_token_system",
"full-system": "scope.component_count > 5 || scope.is_full_redesign"
}
},
"dual_track": {
"pattern": "CP-9",
"description": "Design and implementation proceed in parallel after sync checkpoints",
"sync_mechanism": "AUDIT tasks serve as sync points between tracks",
"fallback": "If dual-track fails, coordinator falls back to sequential execution"
}
},
"session_dirs": {
"base": ".workflow/.team/UDS-{slug}-{YYYY-MM-DD}/",
"research": "research/",
"design": "design/",
"audit": "audit/",
"build": "build/",
"messages": ".workflow/.team-msg/{team-name}/"
}
}