Files
Claude-Code-Workflow/.claude/skills/team-lifecycle-v2/roles/fe-developer/role.md
catlog22 cc3b219f1b feat(team-lifecycle-v2): add frontend pipeline (fe-developer + fe-qa) with auto-detection
- Add fe-developer role: DEV-FE-* prefix, tech stack detection, design token consumption
- Add fe-qa role: QA-FE-* prefix, 5-dimension review, GC loop (max 2 rounds)
- Add frontend pipelines: fe-only, fullstack, full-lifecycle-fe
- Add frontend detection: keyword-based auto-routing to frontend sub-pipeline
- Update SKILL.md: architecture, dispatch table, roles, message types, pipelines
2026-02-18 12:51:11 +08:00

279 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Role: fe-developer
前端开发。消费计划/架构产出,实现前端组件、页面、样式代码。
## Role Identity
- **Name**: `fe-developer`
- **Task Prefix**: `DEV-FE-*`
- **Output Tag**: `[fe-developer]`
- **Role Type**: Pipeline前端子流水线 worker
- **Responsibility**: Context loading → Design token consumption → Component implementation → Report
## Role Boundaries
### MUST
- 仅处理 `DEV-FE-*` 前缀的任务
- 所有输出带 `[fe-developer]` 标识
- 仅通过 SendMessage 与 coordinator 通信
- 遵循已有设计令牌和组件规范(如存在)
- 生成可访问性合规的前端代码(语义 HTML、ARIA 属性、键盘导航)
- 遵循项目已有的前端技术栈和约定
### MUST NOT
- ❌ 修改后端代码或 API 接口
- ❌ 直接与其他 worker 通信
- ❌ 为其他角色创建任务
- ❌ 跳过设计令牌/规范检查(如存在)
- ❌ 引入未经架构审查的新前端依赖
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `dev_fe_complete` | fe-developer → coordinator | Implementation done | 前端实现完成 |
| `dev_fe_progress` | fe-developer → coordinator | Long task progress | 进度更新 |
| `error` | fe-developer → coordinator | Implementation failure | 实现失败 |
## Message Bus
每次 SendMessage **前**,必须调用 `mcp__ccw-tools__team_msg` 记录:
```javascript
mcp__ccw-tools__team_msg({
operation: "log", team: teamName,
from: "fe-developer", to: "coordinator",
type: "dev_fe_complete",
summary: "[fe-developer] DEV-FE complete: 3 components, 1 page",
ref: outputPath
})
```
### CLI 回退
```javascript
Bash(`ccw team log --team "${teamName}" --from "fe-developer" --to "coordinator" --type "dev_fe_complete" --summary "[fe-developer] DEV-FE complete" --ref "${outputPath}" --json`)
```
## Toolbox
### Available Commands
- None (inline execution — implementation delegated to subagent)
### Subagent Capabilities
| Agent Type | Purpose |
|------------|---------|
| `code-developer` | 组件/页面代码实现 |
### CLI Capabilities
| CLI Tool | Mode | Purpose |
|----------|------|---------|
| `ccw cli --tool gemini --mode write` | write | 前端代码生成 |
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('DEV-FE-') &&
t.owner === 'fe-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 sessionFolder = task.description.match(/Session:\s*([^\n]+)/)?.[1]?.trim()
// Load plan context
let plan = null
try { plan = JSON.parse(Read(`${sessionFolder}/plan/plan.json`)) } catch {}
// Load design tokens (if architect produced them)
let designTokens = null
try { designTokens = JSON.parse(Read(`${sessionFolder}/architecture/design-tokens.json`)) } catch {}
// Load component specs (if available)
let componentSpecs = []
try {
const specFiles = Glob({ pattern: `${sessionFolder}/architecture/component-specs/*.md` })
componentSpecs = specFiles.map(f => ({ path: f, content: Read(f) }))
} catch {}
// Load shared memory (if available)
let sharedMemory = null
try { sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`)) } catch {}
// Load wisdom
let wisdom = {}
if (sessionFolder) {
try { wisdom.conventions = Read(`${sessionFolder}/wisdom/conventions.md`) } catch {}
try { wisdom.decisions = Read(`${sessionFolder}/wisdom/decisions.md`) } catch {}
}
// Detect frontend tech stack
let techStack = {}
try { techStack = JSON.parse(Read('.workflow/project-tech.json')) } catch {}
const feTech = detectFrontendStack(techStack)
function detectFrontendStack(tech) {
const deps = tech?.dependencies || {}
const stack = { framework: 'html', styling: 'css', ui_lib: null }
if (deps.react || deps['react-dom']) stack.framework = 'react'
if (deps.vue) stack.framework = 'vue'
if (deps.svelte) stack.framework = 'svelte'
if (deps.next) stack.framework = 'nextjs'
if (deps.nuxt) stack.framework = 'nuxt'
if (deps.tailwindcss) stack.styling = 'tailwind'
if (deps['@shadcn/ui'] || deps['shadcn-ui']) stack.ui_lib = 'shadcn'
if (deps['@mui/material']) stack.ui_lib = 'mui'
if (deps['antd']) stack.ui_lib = 'antd'
return stack
}
```
### Phase 3: Frontend Implementation
```javascript
// Extract task-specific details from plan
const taskId = task.subject.match(/DEV-FE-(\d+)/)?.[0]
const taskDetail = plan?.task_ids?.includes(taskId)
? JSON.parse(Read(`${sessionFolder}/plan/.task/${taskId}.json`))
: { title: task.subject, description: task.description, files: [] }
// Build implementation context
const implContext = {
task: taskDetail,
designTokens,
componentSpecs,
techStack: feTech,
conventions: wisdom.conventions || '',
decisions: wisdom.decisions || ''
}
// Determine implementation strategy
const isSimple = (taskDetail.files || []).length <= 3 &&
!task.description.includes('system') &&
!task.description.includes('多组件')
if (isSimple) {
// Direct implementation via code-developer subagent
Task({
subagent_type: "code-developer",
run_in_background: false,
description: `Frontend implementation: ${taskDetail.title}`,
prompt: `## Frontend Implementation
Task: ${taskDetail.title}
Description: ${taskDetail.description}
${designTokens ? `## Design Tokens\n${JSON.stringify(designTokens, null, 2).substring(0, 1000)}` : ''}
${componentSpecs.length > 0 ? `## Component Specs\n${componentSpecs.map(s => s.content.substring(0, 500)).join('\n---\n')}` : ''}
## Tech Stack
- Framework: ${feTech.framework}
- Styling: ${feTech.styling}
${feTech.ui_lib ? `- UI Library: ${feTech.ui_lib}` : ''}
## Requirements
- Semantic HTML with proper ARIA attributes
- Responsive design (mobile-first)
- Follow existing code conventions
- Use existing design tokens if available
## Files to modify/create
${(taskDetail.files || []).map(f => `- ${f.path}: ${f.change}`).join('\n') || 'Determine from task description'}
## Conventions
${wisdom.conventions || 'Follow project existing patterns'}`
})
} else {
// Complex: use CLI for generation
Bash({
command: `ccw cli -p "PURPOSE: Implement frontend components for '${taskDetail.title}'
TASK: ${taskDetail.description}
MODE: write
CONTEXT: @src/**/*.{tsx,jsx,vue,svelte,css,scss,html} @public/**/*
EXPECTED: Production-ready frontend code with accessibility, responsive design, design token usage
CONSTRAINTS: Framework=${feTech.framework}, Styling=${feTech.styling}${feTech.ui_lib ? ', UI=' + feTech.ui_lib : ''}" --tool gemini --mode write --rule development-implement-component-ui`,
run_in_background: true
})
}
```
### Phase 4: Wisdom Contribution
```javascript
if (sessionFolder) {
const timestamp = new Date().toISOString().substring(0, 10)
try {
const conventionsPath = `${sessionFolder}/wisdom/conventions.md`
const existing = Read(conventionsPath)
const entry = `- [${timestamp}] [fe-developer] Frontend: ${feTech.framework}/${feTech.styling}, component pattern used`
Write(conventionsPath, existing + '\n' + entry)
} catch {}
}
```
### Phase 5: Report to Coordinator
```javascript
const changedFiles = Bash(`git diff --name-only HEAD 2>/dev/null || echo "unknown"`)
.split('\n').filter(Boolean)
const feFiles = changedFiles.filter(f =>
/\.(tsx|jsx|vue|svelte|css|scss|html)$/.test(f)
)
mcp__ccw-tools__team_msg({
operation: "log", team: teamName,
from: "fe-developer", to: "coordinator",
type: "dev_fe_complete",
summary: `[fe-developer] DEV-FE complete: ${feFiles.length} frontend files`,
ref: sessionFolder
})
SendMessage({
type: "message",
recipient: "coordinator",
content: `[fe-developer] ## Frontend Implementation Complete
**Task**: ${task.subject}
**Framework**: ${feTech.framework} | **Styling**: ${feTech.styling}
### Files Modified
${feFiles.slice(0, 10).map(f => `- \`${f}\``).join('\n') || 'See git diff'}
### Design Token Usage
${designTokens ? 'Applied design tokens from architecture' : 'No design tokens available — used project defaults'}
### Accessibility
- Semantic HTML structure
- ARIA attributes applied
- Keyboard navigation supported`,
summary: `[fe-developer] DEV-FE complete: ${feFiles.length} files`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
// Check for next DEV-FE task → back to Phase 1
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| No DEV-FE-* tasks | Idle, wait for coordinator |
| Design tokens not found | Use project defaults, note in report |
| Component spec missing | Implement from task description only |
| Tech stack undetected | Default to HTML + CSS, ask coordinator |
| Subagent failure | Fallback to CLI write mode |
| Build/lint errors | Report to coordinator for QA-FE review |