mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-27 09:13:07 +08:00
feat: add team-tech-debt skill for tech debt identification and cleanup
6-role team (coordinator, scanner, assessor, planner, executor, validator) with 3 pipeline modes (scan, remediate, targeted) and fix-verify loop. Scanner performs 5-dimension analysis (code, architecture, testing, dependency, documentation) via CLI fan-out. Follows team-skill-designer patterns with self-contained role.md and command.md files.
This commit is contained in:
404
.claude/skills/team-tech-debt/SKILL.md
Normal file
404
.claude/skills/team-tech-debt/SKILL.md
Normal file
@@ -0,0 +1,404 @@
|
||||
---
|
||||
name: team-tech-debt
|
||||
description: Unified team skill for tech debt identification and cleanup. All roles invoke this skill with --role arg for role-specific execution. Triggers on "team tech-debt", "tech debt cleanup", "技术债务".
|
||||
allowed-tools: TeamCreate(*), TeamDelete(*), SendMessage(*), TaskCreate(*), TaskUpdate(*), TaskList(*), TaskGet(*), Task(*), AskUserQuestion(*), Read(*), Write(*), Edit(*), Bash(*), Glob(*), Grep(*)
|
||||
---
|
||||
|
||||
# Team Tech Debt
|
||||
|
||||
技术债务识别与清理团队。融合"债务扫描"、"量化评估"、"治理规划"、"清理执行"、"验证回归"五大能力域,形成"扫描→评估→规划→清理→验证"闭环。通过 Scanner 多维度扫描、Executor-Validator 修复验证循环、共享债务清单数据库,实现渐进式技术债务治理。所有成员通过 `--role=xxx` 路由到角色执行逻辑。
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ Skill(skill="team-tech-debt", args="--role=xxx") │
|
||||
└────────────────────────┬─────────────────────────────────┘
|
||||
│ Role Router
|
||||
┌────────┬───────────┼───────────┬──────────┬──────────┐
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
┌────────┐┌────────┐┌──────────┐┌─────────┐┌────────┐┌─────────┐
|
||||
│coordi- ││scanner ││assessor ││planner ││executor││validator│
|
||||
│nator ││TDSCAN-*││TDEVAL-* ││TDPLAN-* ││TDFIX-* ││TDVAL-* │
|
||||
│ roles/ ││ roles/ ││ roles/ ││ roles/ ││ roles/ ││ roles/ │
|
||||
└────────┘└────────┘└──────────┘└─────────┘└────────┘└─────────┘
|
||||
```
|
||||
|
||||
## Command Architecture
|
||||
|
||||
```
|
||||
roles/
|
||||
├── coordinator/
|
||||
│ ├── role.md # Pipeline 编排(模式选择、任务分发、监控)
|
||||
│ └── commands/
|
||||
│ ├── dispatch.md # 任务链创建
|
||||
│ └── monitor.md # 进度监控
|
||||
├── scanner/
|
||||
│ ├── role.md # 多维度技术债务扫描
|
||||
│ └── commands/
|
||||
│ └── scan-debt.md # 多维度 CLI Fan-out 扫描
|
||||
├── assessor/
|
||||
│ ├── role.md # 量化评估与优先级排序
|
||||
│ └── commands/
|
||||
│ └── evaluate.md # 影响/成本矩阵评估
|
||||
├── planner/
|
||||
│ ├── role.md # 治理方案规划
|
||||
│ └── commands/
|
||||
│ └── create-plan.md # 分阶段治理方案生成
|
||||
├── executor/
|
||||
│ ├── role.md # 债务清理执行
|
||||
│ └── commands/
|
||||
│ └── remediate.md # 重构/清理/更新执行
|
||||
└── validator/
|
||||
├── role.md # 清理结果验证
|
||||
└── commands/
|
||||
└── verify.md # 回归测试与质量验证
|
||||
```
|
||||
|
||||
**设计原则**: role.md 保留 Phase 1(Task Discovery)和 Phase 5(Report)内联。Phase 2-4 根据复杂度决定内联或委派到 `commands/*.md`。
|
||||
|
||||
## Role Router
|
||||
|
||||
### Input Parsing
|
||||
|
||||
Parse `$ARGUMENTS` to extract `--role` and optional `--agent-name`:
|
||||
|
||||
```javascript
|
||||
const args = "$ARGUMENTS"
|
||||
const roleMatch = args.match(/--role[=\s]+(\w+)/)
|
||||
const teamName = args.match(/--team[=\s]+([\w-]+)/)?.[1] || "tech-debt"
|
||||
|
||||
if (!roleMatch) {
|
||||
// No --role: Orchestration Mode → auto route to coordinator
|
||||
// See "Orchestration Mode" section below
|
||||
}
|
||||
|
||||
const role = roleMatch ? roleMatch[1] : "coordinator"
|
||||
const agentName = args.match(/--agent-name[=\s]+([\w-]+)/)?.[1] || role
|
||||
```
|
||||
|
||||
### Role Dispatch
|
||||
|
||||
```javascript
|
||||
const VALID_ROLES = {
|
||||
"coordinator": { file: "roles/coordinator/role.md", prefix: null },
|
||||
"scanner": { file: "roles/scanner/role.md", prefix: "TDSCAN" },
|
||||
"assessor": { file: "roles/assessor/role.md", prefix: "TDEVAL" },
|
||||
"planner": { file: "roles/planner/role.md", prefix: "TDPLAN" },
|
||||
"executor": { file: "roles/executor/role.md", prefix: "TDFIX" },
|
||||
"validator": { file: "roles/validator/role.md", prefix: "TDVAL" }
|
||||
}
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
### Orchestration Mode(无参数触发)
|
||||
|
||||
当不带 `--role` 调用时,自动进入 coordinator 编排模式。
|
||||
|
||||
**触发方式**:
|
||||
|
||||
```javascript
|
||||
// 用户调用(无 --role)— 自动路由到 coordinator
|
||||
Skill(skill="team-tech-debt", args="扫描并清理项目中的技术债务")
|
||||
|
||||
// 等价于
|
||||
Skill(skill="team-tech-debt", args="--role=coordinator 扫描并清理项目中的技术债务")
|
||||
```
|
||||
|
||||
**完整调用链**:
|
||||
|
||||
```
|
||||
用户: Skill(args="任务描述")
|
||||
│
|
||||
├─ SKILL.md: 无 --role → Orchestration Mode → 读取 coordinator role.md
|
||||
│
|
||||
├─ coordinator Phase 2: TeamCreate + spawn workers
|
||||
│ 每个 worker prompt 中包含 Skill(args="--role=xxx") 回调
|
||||
│
|
||||
├─ coordinator Phase 3: dispatch 任务链
|
||||
│
|
||||
├─ worker 收到任务 → Skill(args="--role=xxx") → SKILL.md Role Router → role.md
|
||||
│ 每个 worker 自动获取:
|
||||
│ ├─ 角色定义 (role.md: identity, boundaries, message types)
|
||||
│ ├─ 可用命令 (commands/*.md)
|
||||
│ └─ 执行逻辑 (5-phase process)
|
||||
│
|
||||
└─ coordinator Phase 4-5: 监控 → 结果汇报
|
||||
```
|
||||
|
||||
### Available Roles
|
||||
|
||||
| Role | Task Prefix | Responsibility | Role File |
|
||||
|------|-------------|----------------|-----------|
|
||||
| `coordinator` | N/A | Pipeline 编排、模式选择、质量门控 | [roles/coordinator/role.md](roles/coordinator/role.md) |
|
||||
| `scanner` | TDSCAN-* | 多维度技术债务扫描 | [roles/scanner/role.md](roles/scanner/role.md) |
|
||||
| `assessor` | TDEVAL-* | 量化评估与优先级排序 | [roles/assessor/role.md](roles/assessor/role.md) |
|
||||
| `planner` | TDPLAN-* | 分阶段治理方案规划 | [roles/planner/role.md](roles/planner/role.md) |
|
||||
| `executor` | TDFIX-* | 重构/清理/更新执行 | [roles/executor/role.md](roles/executor/role.md) |
|
||||
| `validator` | TDVAL-* | 回归测试与质量验证 | [roles/validator/role.md](roles/validator/role.md) |
|
||||
|
||||
## Shared Infrastructure
|
||||
|
||||
> 以下为编排级概览。具体实现代码(Message Bus、Task Lifecycle、工具方法)在各 role.md 中自包含。
|
||||
|
||||
### Team Configuration
|
||||
|
||||
```javascript
|
||||
const TEAM_CONFIG = {
|
||||
name: "tech-debt",
|
||||
sessionDir: ".workflow/.team/TD-{slug}-{date}/",
|
||||
sharedMemory: "shared-memory.json",
|
||||
debtDimensions: ["code", "architecture", "testing", "dependency", "documentation"],
|
||||
priorityMatrix: {
|
||||
highImpact_lowCost: "立即修复 (Quick Win)",
|
||||
highImpact_highCost: "战略规划 (Strategic)",
|
||||
lowImpact_lowCost: "待办处理 (Backlog)",
|
||||
lowImpact_highCost: "暂缓接受 (Defer)"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Role Isolation Rules
|
||||
|
||||
**核心原则**: 每个角色仅能执行自己职责范围内的工作。
|
||||
|
||||
#### Output Tagging(强制)
|
||||
|
||||
所有角色的输出必须带 `[role_name]` 标识前缀。
|
||||
|
||||
#### Coordinator 隔离
|
||||
|
||||
| 允许 | 禁止 |
|
||||
|------|------|
|
||||
| 需求澄清 (AskUserQuestion) | ❌ 直接扫描代码 |
|
||||
| 创建任务链 (TaskCreate) | ❌ 直接执行重构或清理 |
|
||||
| 模式选择 + 质量门控 | ❌ 直接评估或规划 |
|
||||
| 监控进度 (消息总线) | ❌ 绕过 worker 自行完成 |
|
||||
|
||||
#### Worker 隔离
|
||||
|
||||
| 允许 | 禁止 |
|
||||
|------|------|
|
||||
| 处理自己前缀的任务 | ❌ 处理其他角色前缀的任务 |
|
||||
| 读写 shared-memory.json (自己的字段) | ❌ 为其他角色创建任务 |
|
||||
| SendMessage 给 coordinator | ❌ 直接与其他 worker 通信 |
|
||||
|
||||
## Three-Mode Pipeline Architecture
|
||||
|
||||
```
|
||||
Scan Mode (仅扫描评估):
|
||||
TDSCAN-001(多维度扫描) → TDEVAL-001(量化评估) → 报告
|
||||
|
||||
Remediate Mode (完整闭环):
|
||||
TDSCAN-001(扫描) → TDEVAL-001(评估) → TDPLAN-001(规划) → TDFIX-001(修复) → TDVAL-001(验证)
|
||||
|
||||
Targeted Mode (定向修复):
|
||||
TDPLAN-001(规划) → TDFIX-001(修复) → TDVAL-001(验证)
|
||||
```
|
||||
|
||||
### Mode Auto-Detection
|
||||
|
||||
```javascript
|
||||
function detectMode(args, taskDescription) {
|
||||
if (/--mode[=\s]+(scan|remediate|targeted)/.test(args)) {
|
||||
return args.match(/--mode[=\s]+(\w+)/)[1]
|
||||
}
|
||||
if (/扫描|scan|审计|audit|评估|assess/.test(taskDescription)) return 'scan'
|
||||
if (/定向|targeted|指定|specific|修复.*已知/.test(taskDescription)) return 'targeted'
|
||||
return 'remediate'
|
||||
}
|
||||
```
|
||||
|
||||
### Fix-Verify Loop
|
||||
|
||||
```
|
||||
TDFIX → TDVAL → (if regression or quality drop) → TDFIX-fix → TDVAL-2
|
||||
(if all pass) → report
|
||||
```
|
||||
|
||||
## Unified Session Directory
|
||||
|
||||
```
|
||||
.workflow/.team/TD-{slug}-{YYYY-MM-DD}/
|
||||
├── team-session.json
|
||||
├── shared-memory.json # 债务清单 / 评估矩阵 / 治理方案 / 修复结果 / 验证结果
|
||||
├── scan/ # Scanner output
|
||||
│ └── debt-inventory.json
|
||||
├── assessment/ # Assessor output
|
||||
│ └── priority-matrix.json
|
||||
├── plan/ # Planner output
|
||||
│ └── remediation-plan.md
|
||||
├── fixes/ # Executor output
|
||||
│ └── fix-log.json
|
||||
└── validation/ # Validator output
|
||||
└── validation-report.json
|
||||
```
|
||||
|
||||
## Coordinator Spawn Template
|
||||
|
||||
```javascript
|
||||
TeamCreate({ team_name: teamName })
|
||||
|
||||
// Scanner
|
||||
Task({
|
||||
subagent_type: "general-purpose",
|
||||
team_name: teamName,
|
||||
name: "scanner",
|
||||
prompt: `你是 team "${teamName}" 的 SCANNER。
|
||||
|
||||
## ⚠️ 首要指令(MUST)
|
||||
你的所有工作必须通过调用 Skill 获取角色定义后执行,禁止自行发挥:
|
||||
Skill(skill="team-tech-debt", args="--role=scanner")
|
||||
此调用会加载你的角色定义(role.md)、可用命令(commands/*.md)和完整执行逻辑。
|
||||
|
||||
当前需求: ${taskDescription}
|
||||
约束: ${constraints}
|
||||
|
||||
## 角色准则(强制)
|
||||
- 你只能处理 TDSCAN-* 前缀的任务,不得执行其他角色的工作
|
||||
- 所有输出(SendMessage、team_msg)必须带 [scanner] 标识前缀
|
||||
- 仅与 coordinator 通信,不得直接联系其他 worker
|
||||
- 不得使用 TaskCreate 为其他角色创建任务
|
||||
|
||||
## 消息总线(必须)
|
||||
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
|
||||
|
||||
## 工作流程(严格按顺序)
|
||||
1. 调用 Skill(skill="team-tech-debt", args="--role=scanner") 获取角色定义和执行逻辑
|
||||
2. 按 role.md 中的 5-Phase 流程执行(TaskList → 找到 TDSCAN-* 任务 → 执行 → 汇报)
|
||||
3. team_msg log + SendMessage 结果给 coordinator(带 [scanner] 标识)
|
||||
4. TaskUpdate completed → 检查下一个任务 → 回到步骤 1`
|
||||
})
|
||||
|
||||
// Assessor
|
||||
Task({
|
||||
subagent_type: "general-purpose",
|
||||
team_name: teamName,
|
||||
name: "assessor",
|
||||
prompt: `你是 team "${teamName}" 的 ASSESSOR。
|
||||
|
||||
## ⚠️ 首要指令(MUST)
|
||||
Skill(skill="team-tech-debt", args="--role=assessor")
|
||||
|
||||
当前需求: ${taskDescription}
|
||||
约束: ${constraints}
|
||||
|
||||
## 角色准则(强制)
|
||||
- 你只能处理 TDEVAL-* 前缀的任务
|
||||
- 所有输出必须带 [assessor] 标识前缀
|
||||
- 仅与 coordinator 通信
|
||||
|
||||
## 消息总线(必须)
|
||||
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
|
||||
|
||||
## 工作流程
|
||||
1. Skill(skill="team-tech-debt", args="--role=assessor") 获取角色定义
|
||||
2. TaskList → 找到 TDEVAL-* 任务 → 执行 → 汇报
|
||||
3. team_msg log + SendMessage 结果给 coordinator
|
||||
4. TaskUpdate completed → 检查下一个任务`
|
||||
})
|
||||
|
||||
// Planner
|
||||
Task({
|
||||
subagent_type: "general-purpose",
|
||||
team_name: teamName,
|
||||
name: "planner",
|
||||
prompt: `你是 team "${teamName}" 的 PLANNER。
|
||||
|
||||
## ⚠️ 首要指令(MUST)
|
||||
Skill(skill="team-tech-debt", args="--role=planner")
|
||||
|
||||
当前需求: ${taskDescription}
|
||||
约束: ${constraints}
|
||||
|
||||
## 角色准则(强制)
|
||||
- 你只能处理 TDPLAN-* 前缀的任务
|
||||
- 所有输出必须带 [planner] 标识前缀
|
||||
- 仅与 coordinator 通信
|
||||
|
||||
## 消息总线(必须)
|
||||
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
|
||||
|
||||
## 工作流程
|
||||
1. Skill(skill="team-tech-debt", args="--role=planner") 获取角色定义
|
||||
2. TaskList → 找到 TDPLAN-* 任务 → 执行 → 汇报
|
||||
3. team_msg log + SendMessage 结果给 coordinator
|
||||
4. TaskUpdate completed → 检查下一个任务`
|
||||
})
|
||||
|
||||
// Executor
|
||||
Task({
|
||||
subagent_type: "general-purpose",
|
||||
team_name: teamName,
|
||||
name: "executor",
|
||||
prompt: `你是 team "${teamName}" 的 EXECUTOR。
|
||||
|
||||
## ⚠️ 首要指令(MUST)
|
||||
Skill(skill="team-tech-debt", args="--role=executor")
|
||||
|
||||
当前需求: ${taskDescription}
|
||||
约束: ${constraints}
|
||||
|
||||
## 角色准则(强制)
|
||||
- 你只能处理 TDFIX-* 前缀的任务
|
||||
- 所有输出必须带 [executor] 标识前缀
|
||||
- 仅与 coordinator 通信
|
||||
|
||||
## 消息总线(必须)
|
||||
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
|
||||
|
||||
## 工作流程
|
||||
1. Skill(skill="team-tech-debt", args="--role=executor") 获取角色定义
|
||||
2. TaskList → 找到 TDFIX-* 任务 → 执行 → 汇报
|
||||
3. team_msg log + SendMessage 结果给 coordinator
|
||||
4. TaskUpdate completed → 检查下一个任务`
|
||||
})
|
||||
|
||||
// Validator
|
||||
Task({
|
||||
subagent_type: "general-purpose",
|
||||
team_name: teamName,
|
||||
name: "validator",
|
||||
prompt: `你是 team "${teamName}" 的 VALIDATOR。
|
||||
|
||||
## ⚠️ 首要指令(MUST)
|
||||
Skill(skill="team-tech-debt", args="--role=validator")
|
||||
|
||||
当前需求: ${taskDescription}
|
||||
约束: ${constraints}
|
||||
|
||||
## 角色准则(强制)
|
||||
- 你只能处理 TDVAL-* 前缀的任务
|
||||
- 所有输出必须带 [validator] 标识前缀
|
||||
- 仅与 coordinator 通信
|
||||
|
||||
## 消息总线(必须)
|
||||
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
|
||||
|
||||
## 工作流程
|
||||
1. Skill(skill="team-tech-debt", args="--role=validator") 获取角色定义
|
||||
2. TaskList → 找到 TDVAL-* 任务 → 执行 → 汇报
|
||||
3. team_msg log + SendMessage 结果给 coordinator
|
||||
4. TaskUpdate completed → 检查下一个任务`
|
||||
})
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| Unknown --role value | Error with available role list |
|
||||
| Missing --role arg | Orchestration Mode → auto route to coordinator |
|
||||
| Role file not found | Error with expected path (roles/{name}/role.md) |
|
||||
| Command file not found | Fall back to inline execution in role.md |
|
||||
| Task prefix conflict | Log warning, proceed |
|
||||
| Scanner finds no debt | Report clean codebase, skip to summary |
|
||||
| Fix introduces regression | Trigger Fix-Verify loop (max 3 iterations) |
|
||||
| Validation repeatedly fails | Escalate to user with diagnosis |
|
||||
@@ -0,0 +1,164 @@
|
||||
# Command: evaluate
|
||||
|
||||
> CLI 分析评估债务项。对每项债务评估业务影响(1-5)、修复成本(1-5)、未修复风险,产出优先级象限分配。
|
||||
|
||||
## When to Use
|
||||
|
||||
- Phase 3 of Assessor
|
||||
- 需要对债务清单中的项目进行量化评估
|
||||
- 债务项数量较多需要 CLI 辅助分析
|
||||
|
||||
**Trigger conditions**:
|
||||
- TDEVAL-* 任务进入 Phase 3
|
||||
- 债务清单包含 >10 项需要评估的条目
|
||||
- 需要上下文理解来评估影响和成本
|
||||
|
||||
## Strategy
|
||||
|
||||
### Delegation Mode
|
||||
|
||||
**Mode**: CLI Batch Analysis
|
||||
**CLI Tool**: `gemini` (primary)
|
||||
**CLI Mode**: `analysis`
|
||||
|
||||
### Decision Logic
|
||||
|
||||
```javascript
|
||||
// 评估策略选择
|
||||
if (debtInventory.length <= 10) {
|
||||
// 少量项目:内联评估(基于严重性和工作量启发式)
|
||||
mode = 'heuristic'
|
||||
} else if (debtInventory.length <= 50) {
|
||||
// 中等规模:单次 CLI 批量评估
|
||||
mode = 'cli-batch'
|
||||
} else {
|
||||
// 大规模:分批 CLI 评估
|
||||
mode = 'cli-chunked'
|
||||
chunkSize = 25
|
||||
}
|
||||
```
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Context Preparation
|
||||
|
||||
```javascript
|
||||
// 准备评估上下文
|
||||
const debtSummary = debtInventory.map(item =>
|
||||
`[${item.id}] [${item.dimension}] [${item.severity}] ${item.file}:${item.line} - ${item.description}`
|
||||
).join('\n')
|
||||
|
||||
// 读取项目元信息用于上下文
|
||||
const projectContext = []
|
||||
try {
|
||||
const pkg = JSON.parse(Read('package.json'))
|
||||
projectContext.push(`Project: ${pkg.name}, Dependencies: ${Object.keys(pkg.dependencies || {}).length}`)
|
||||
} catch {}
|
||||
```
|
||||
|
||||
### Step 2: Execute Strategy
|
||||
|
||||
```javascript
|
||||
if (mode === 'heuristic') {
|
||||
// 内联启发式评估
|
||||
for (const item of debtInventory) {
|
||||
const severityImpact = { critical: 5, high: 4, medium: 3, low: 1 }
|
||||
const effortCost = { small: 1, medium: 3, large: 5 }
|
||||
item.impact_score = severityImpact[item.severity] || 3
|
||||
item.cost_score = effortCost[item.estimated_effort] || 3
|
||||
item.risk_if_unfixed = getRiskDescription(item)
|
||||
item.priority_quadrant = assignQuadrant(item.impact_score, item.cost_score)
|
||||
}
|
||||
} else {
|
||||
// CLI 批量评估
|
||||
const prompt = `PURPOSE: Evaluate technical debt items for business impact and fix cost to create a priority matrix
|
||||
TASK: • For each debt item, assess business impact (1-5 scale: 1=negligible, 5=critical) • Assess fix complexity/cost (1-5 scale: 1=trivial, 5=major refactor) • Describe risk if unfixed • Assign priority quadrant: quick-win (high impact + low cost), strategic (high impact + high cost), backlog (low impact + low cost), defer (low impact + high cost)
|
||||
MODE: analysis
|
||||
CONTEXT: ${projectContext.join(' | ')}
|
||||
EXPECTED: JSON array with: [{id, impact_score, cost_score, risk_if_unfixed, priority_quadrant}] for each item
|
||||
CONSTRAINTS: Be realistic about costs, consider dependencies between items
|
||||
|
||||
## Debt Items to Evaluate
|
||||
${debtSummary}`
|
||||
|
||||
Bash(`ccw cli -p "${prompt}" --tool gemini --mode analysis --rule analysis-analyze-code-patterns`, {
|
||||
run_in_background: true
|
||||
})
|
||||
|
||||
// 等待 CLI 完成,解析结果,合并回 debtInventory
|
||||
}
|
||||
|
||||
function assignQuadrant(impact, cost) {
|
||||
if (impact >= 4 && cost <= 2) return 'quick-win'
|
||||
if (impact >= 4 && cost >= 3) return 'strategic'
|
||||
if (impact <= 3 && cost <= 2) return 'backlog'
|
||||
return 'defer'
|
||||
}
|
||||
|
||||
function getRiskDescription(item) {
|
||||
const risks = {
|
||||
'code': 'Increased maintenance cost and bug probability',
|
||||
'architecture': 'Growing coupling makes changes harder and riskier',
|
||||
'testing': 'Reduced confidence in changes, higher regression risk',
|
||||
'dependency': 'Security vulnerabilities and compatibility issues',
|
||||
'documentation': 'Onboarding friction and knowledge loss'
|
||||
}
|
||||
return risks[item.dimension] || 'Technical quality degradation over time'
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Result Processing
|
||||
|
||||
```javascript
|
||||
// 验证评估结果完整性
|
||||
const evaluated = debtInventory.filter(i => i.priority_quadrant)
|
||||
const unevaluated = debtInventory.filter(i => !i.priority_quadrant)
|
||||
|
||||
if (unevaluated.length > 0) {
|
||||
// 未评估的项目使用启发式兜底
|
||||
for (const item of unevaluated) {
|
||||
item.impact_score = item.impact_score || 3
|
||||
item.cost_score = item.cost_score || 3
|
||||
item.priority_quadrant = assignQuadrant(item.impact_score, item.cost_score)
|
||||
item.risk_if_unfixed = item.risk_if_unfixed || getRiskDescription(item)
|
||||
}
|
||||
}
|
||||
|
||||
// 生成统计
|
||||
const stats = {
|
||||
total: debtInventory.length,
|
||||
evaluated_by_cli: evaluated.length,
|
||||
evaluated_by_heuristic: unevaluated.length,
|
||||
avg_impact: (debtInventory.reduce((s, i) => s + i.impact_score, 0) / debtInventory.length).toFixed(1),
|
||||
avg_cost: (debtInventory.reduce((s, i) => s + i.cost_score, 0) / debtInventory.length).toFixed(1)
|
||||
}
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
## Evaluation Results
|
||||
|
||||
### Method: [heuristic|cli-batch|cli-chunked]
|
||||
### Total Items: [count]
|
||||
### Average Impact: [score]/5
|
||||
### Average Cost: [score]/5
|
||||
|
||||
### Priority Distribution
|
||||
| Quadrant | Count | % |
|
||||
|----------|-------|---|
|
||||
| Quick-Win | [n] | [%] |
|
||||
| Strategic | [n] | [%] |
|
||||
| Backlog | [n] | [%] |
|
||||
| Defer | [n] | [%] |
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| CLI returns invalid JSON | Fall back to heuristic scoring |
|
||||
| CLI timeout | Evaluate processed items, heuristic for rest |
|
||||
| Debt inventory too large (>200) | Chunk into batches of 25 |
|
||||
| Missing severity/effort data | Use dimension-based defaults |
|
||||
| All items same quadrant | Re-evaluate with adjusted thresholds |
|
||||
262
.claude/skills/team-tech-debt/roles/assessor/role.md
Normal file
262
.claude/skills/team-tech-debt/roles/assessor/role.md
Normal file
@@ -0,0 +1,262 @@
|
||||
# Role: assessor
|
||||
|
||||
技术债务量化评估师。对扫描发现的每项债务进行影响评分(1-5)和修复成本评分(1-5),划分优先级象限,生成 priority-matrix.json。
|
||||
|
||||
## Role Identity
|
||||
|
||||
- **Name**: `assessor`
|
||||
- **Task Prefix**: `TDEVAL-*`
|
||||
- **Responsibility**: Read-only analysis(量化评估)
|
||||
- **Communication**: SendMessage to coordinator only
|
||||
- **Output Tag**: `[assessor]`
|
||||
|
||||
## Role Boundaries
|
||||
|
||||
### MUST
|
||||
|
||||
- 仅处理 `TDEVAL-*` 前缀的任务
|
||||
- 所有输出必须带 `[assessor]` 标识
|
||||
- 基于数据量化评估债务优先级
|
||||
- 更新 shared memory 中的 priority_matrix
|
||||
|
||||
### MUST NOT
|
||||
|
||||
- 修改源代码或测试代码
|
||||
- 执行修复操作
|
||||
- 为其他角色创建任务
|
||||
- 直接与其他 worker 通信
|
||||
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `assessment_complete` | assessor → coordinator | 评估完成 | 包含优先级矩阵摘要 |
|
||||
| `error` | assessor → coordinator | 评估失败 | 阻塞性错误 |
|
||||
|
||||
## Message Bus
|
||||
|
||||
每次 SendMessage 前,先调用 `mcp__ccw-tools__team_msg` 记录:
|
||||
|
||||
```javascript
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: teamName,
|
||||
from: "assessor",
|
||||
to: "coordinator",
|
||||
type: "assessment_complete",
|
||||
summary: "[assessor] 评估完成: 12 quick-wins, 8 strategic, 15 backlog, 7 defer"
|
||||
})
|
||||
```
|
||||
|
||||
### CLI 回退
|
||||
|
||||
若 `mcp__ccw-tools__team_msg` 不可用,使用 Bash 写入日志文件:
|
||||
|
||||
```javascript
|
||||
Bash(`echo '${JSON.stringify({ from: "assessor", to: "coordinator", type: "assessment_complete", summary: msg, ts: new Date().toISOString() })}' >> "${sessionFolder}/message-log.jsonl"`)
|
||||
```
|
||||
|
||||
## Toolbox
|
||||
|
||||
### Available Commands
|
||||
|
||||
| Command | File | Phase | Description |
|
||||
|---------|------|-------|-------------|
|
||||
| `evaluate` | [commands/evaluate.md](commands/evaluate.md) | Phase 3 | 影响/成本矩阵评估 |
|
||||
|
||||
### Subagent Capabilities
|
||||
|
||||
> Assessor 不直接使用 subagent
|
||||
|
||||
### CLI Capabilities
|
||||
|
||||
| CLI Tool | Mode | Used By | Purpose |
|
||||
|----------|------|---------|---------|
|
||||
| `gemini` | analysis | evaluate.md | 债务影响与修复成本评估 |
|
||||
|
||||
## Execution (5-Phase)
|
||||
|
||||
### Phase 1: Task Discovery
|
||||
|
||||
```javascript
|
||||
const tasks = TaskList()
|
||||
const myTasks = tasks.filter(t =>
|
||||
t.subject.startsWith('TDEVAL-') &&
|
||||
t.owner === 'assessor' &&
|
||||
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: Load Debt Inventory
|
||||
|
||||
```javascript
|
||||
const sessionFolder = task.description.match(/session:\s*(.+)/)?.[1]?.trim() || '.'
|
||||
let sharedMemory = {}
|
||||
try { sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`)) } catch {}
|
||||
|
||||
const debtInventory = sharedMemory.debt_inventory || []
|
||||
if (debtInventory.length === 0) {
|
||||
// 尝试从文件加载
|
||||
try {
|
||||
const inventoryFile = JSON.parse(Read(`${sessionFolder}/scan/debt-inventory.json`))
|
||||
debtInventory.push(...(inventoryFile.items || []))
|
||||
} catch {}
|
||||
}
|
||||
|
||||
if (debtInventory.length === 0) {
|
||||
// 无债务项,直接报告
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: teamName, from: "assessor",
|
||||
to: "coordinator", type: "assessment_complete",
|
||||
summary: `[assessor] 无债务项需要评估`
|
||||
})
|
||||
TaskUpdate({ taskId: task.id, status: 'completed' })
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 3: Evaluate Each Item
|
||||
|
||||
```javascript
|
||||
// Read commands/evaluate.md for full CLI evaluation implementation
|
||||
Read("commands/evaluate.md")
|
||||
```
|
||||
|
||||
**核心策略**: 对每项债务评估 impact(1-5) + cost(1-5) + priority quadrant
|
||||
|
||||
```javascript
|
||||
const evaluatedItems = []
|
||||
|
||||
for (const item of debtInventory) {
|
||||
// CLI 分析评估(批量处理以节约 API 调用)
|
||||
const evaluation = {
|
||||
...item,
|
||||
impact_score: 0, // 1-5, 业务影响
|
||||
cost_score: 0, // 1-5, 修复成本
|
||||
risk_if_unfixed: '', // 风险描述
|
||||
priority_quadrant: '' // quick-win / strategic / backlog / defer
|
||||
}
|
||||
|
||||
// 基于严重性预评估
|
||||
const severityImpact = { critical: 5, high: 4, medium: 3, low: 1 }
|
||||
evaluation.impact_score = severityImpact[item.severity] || 3
|
||||
|
||||
// 基于预估工作量预评估
|
||||
const effortCost = { small: 1, medium: 3, large: 5 }
|
||||
evaluation.cost_score = effortCost[item.estimated_effort] || 3
|
||||
|
||||
// 象限划分
|
||||
if (evaluation.impact_score >= 4 && evaluation.cost_score <= 2) {
|
||||
evaluation.priority_quadrant = 'quick-win'
|
||||
} else if (evaluation.impact_score >= 4 && evaluation.cost_score >= 3) {
|
||||
evaluation.priority_quadrant = 'strategic'
|
||||
} else if (evaluation.impact_score <= 3 && evaluation.cost_score <= 2) {
|
||||
evaluation.priority_quadrant = 'backlog'
|
||||
} else {
|
||||
evaluation.priority_quadrant = 'defer'
|
||||
}
|
||||
|
||||
evaluatedItems.push(evaluation)
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 4: Generate Priority Matrix
|
||||
|
||||
```javascript
|
||||
const priorityMatrix = {
|
||||
evaluation_date: new Date().toISOString(),
|
||||
total_items: evaluatedItems.length,
|
||||
by_quadrant: {
|
||||
'quick-win': evaluatedItems.filter(i => i.priority_quadrant === 'quick-win'),
|
||||
'strategic': evaluatedItems.filter(i => i.priority_quadrant === 'strategic'),
|
||||
'backlog': evaluatedItems.filter(i => i.priority_quadrant === 'backlog'),
|
||||
'defer': evaluatedItems.filter(i => i.priority_quadrant === 'defer')
|
||||
},
|
||||
summary: {
|
||||
'quick-win': evaluatedItems.filter(i => i.priority_quadrant === 'quick-win').length,
|
||||
'strategic': evaluatedItems.filter(i => i.priority_quadrant === 'strategic').length,
|
||||
'backlog': evaluatedItems.filter(i => i.priority_quadrant === 'backlog').length,
|
||||
'defer': evaluatedItems.filter(i => i.priority_quadrant === 'defer').length
|
||||
}
|
||||
}
|
||||
|
||||
// 排序:每个象限内按 impact_score 降序
|
||||
for (const quadrant of Object.keys(priorityMatrix.by_quadrant)) {
|
||||
priorityMatrix.by_quadrant[quadrant].sort((a, b) => b.impact_score - a.impact_score)
|
||||
}
|
||||
|
||||
// 保存评估结果
|
||||
Bash(`mkdir -p "${sessionFolder}/assessment"`)
|
||||
Write(`${sessionFolder}/assessment/priority-matrix.json`, JSON.stringify(priorityMatrix, null, 2))
|
||||
|
||||
// 更新 shared memory
|
||||
sharedMemory.priority_matrix = priorityMatrix.summary
|
||||
sharedMemory.debt_inventory = evaluatedItems
|
||||
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
|
||||
```
|
||||
|
||||
### Phase 5: Report to Coordinator
|
||||
|
||||
```javascript
|
||||
const summaryText = Object.entries(priorityMatrix.summary)
|
||||
.map(([q, c]) => `${q}: ${c}`)
|
||||
.join(', ')
|
||||
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: teamName,
|
||||
from: "assessor",
|
||||
to: "coordinator",
|
||||
type: "assessment_complete",
|
||||
summary: `[assessor] 评估完成: ${summaryText}`,
|
||||
ref: `${sessionFolder}/assessment/priority-matrix.json`
|
||||
})
|
||||
|
||||
SendMessage({
|
||||
type: "message",
|
||||
recipient: "coordinator",
|
||||
content: `## [assessor] Assessment Results
|
||||
|
||||
**Task**: ${task.subject}
|
||||
**Total Items**: ${evaluatedItems.length}
|
||||
|
||||
### Priority Matrix
|
||||
| Quadrant | Count | Description |
|
||||
|----------|-------|-------------|
|
||||
| Quick-Win | ${priorityMatrix.summary['quick-win']} | High impact, low cost |
|
||||
| Strategic | ${priorityMatrix.summary['strategic']} | High impact, high cost |
|
||||
| Backlog | ${priorityMatrix.summary['backlog']} | Low impact, low cost |
|
||||
| Defer | ${priorityMatrix.summary['defer']} | Low impact, high cost |
|
||||
|
||||
### Top Quick-Wins
|
||||
${priorityMatrix.by_quadrant['quick-win'].slice(0, 5).map(i => `- **[${i.dimension}]** ${i.file} - ${i.description} (impact: ${i.impact_score}, cost: ${i.cost_score})`).join('\n')}
|
||||
|
||||
### Priority Matrix
|
||||
${sessionFolder}/assessment/priority-matrix.json`,
|
||||
summary: `[assessor] TDEVAL complete: ${summaryText}`
|
||||
})
|
||||
|
||||
TaskUpdate({ taskId: task.id, status: 'completed' })
|
||||
|
||||
const nextTasks = TaskList().filter(t =>
|
||||
t.subject.startsWith('TDEVAL-') && t.owner === 'assessor' &&
|
||||
t.status === 'pending' && t.blockedBy.length === 0
|
||||
)
|
||||
if (nextTasks.length > 0) { /* back to Phase 1 */ }
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| No TDEVAL-* tasks available | Idle, wait for coordinator |
|
||||
| Debt inventory empty | Report empty assessment, notify coordinator |
|
||||
| Shared memory corrupted | Re-read from debt-inventory.json file |
|
||||
| CLI analysis fails | Fall back to severity-based heuristic scoring |
|
||||
| Too many items (>200) | Batch-evaluate top 50 critical/high first |
|
||||
@@ -0,0 +1,157 @@
|
||||
# Command: dispatch
|
||||
|
||||
> 任务链创建与依赖管理。根据 pipeline 模式创建技术债务治理任务链并分配给 worker 角色。
|
||||
|
||||
## When to Use
|
||||
|
||||
- Phase 3 of Coordinator
|
||||
- Pipeline 模式已确定,需要创建任务链
|
||||
- 团队已创建,worker 已 spawn
|
||||
|
||||
**Trigger conditions**:
|
||||
- Coordinator Phase 2 完成后
|
||||
- 模式切换需要重建任务链
|
||||
- Fix-Verify 循环需要创建修复任务
|
||||
|
||||
## Strategy
|
||||
|
||||
### Delegation Mode
|
||||
|
||||
**Mode**: Direct(coordinator 直接操作 TaskCreate/TaskUpdate)
|
||||
|
||||
### Decision Logic
|
||||
|
||||
```javascript
|
||||
// 根据 pipelineMode 选择 pipeline
|
||||
function buildPipeline(pipelineMode, sessionFolder, taskDescription) {
|
||||
const pipelines = {
|
||||
'scan': [
|
||||
{ prefix: 'TDSCAN', owner: 'scanner', desc: '多维度技术债务扫描', blockedBy: [] },
|
||||
{ prefix: 'TDEVAL', owner: 'assessor', desc: '量化评估与优先级排序', blockedBy: ['TDSCAN'] }
|
||||
],
|
||||
'remediate': [
|
||||
{ prefix: 'TDSCAN', owner: 'scanner', desc: '多维度技术债务扫描', blockedBy: [] },
|
||||
{ prefix: 'TDEVAL', owner: 'assessor', desc: '量化评估与优先级排序', blockedBy: ['TDSCAN'] },
|
||||
{ prefix: 'TDPLAN', owner: 'planner', desc: '分阶段治理方案规划', blockedBy: ['TDEVAL'] },
|
||||
{ prefix: 'TDFIX', owner: 'executor', desc: '债务清理执行', blockedBy: ['TDPLAN'] },
|
||||
{ prefix: 'TDVAL', owner: 'validator', desc: '清理结果验证', blockedBy: ['TDFIX'] }
|
||||
],
|
||||
'targeted': [
|
||||
{ prefix: 'TDPLAN', owner: 'planner', desc: '定向修复方案规划', blockedBy: [] },
|
||||
{ prefix: 'TDFIX', owner: 'executor', desc: '债务清理执行', blockedBy: ['TDPLAN'] },
|
||||
{ prefix: 'TDVAL', owner: 'validator', desc: '清理结果验证', blockedBy: ['TDFIX'] }
|
||||
]
|
||||
}
|
||||
return pipelines[pipelineMode] || pipelines['scan']
|
||||
}
|
||||
```
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Context Preparation
|
||||
|
||||
```javascript
|
||||
const pipeline = buildPipeline(pipelineMode, sessionFolder, taskDescription)
|
||||
```
|
||||
|
||||
### Step 2: Execute Strategy
|
||||
|
||||
```javascript
|
||||
const taskIds = {}
|
||||
|
||||
for (const stage of pipeline) {
|
||||
// 构建任务描述(包含 session 和上下文信息)
|
||||
const fullDesc = [
|
||||
stage.desc,
|
||||
`\nsession: ${sessionFolder}`,
|
||||
`\n\n目标: ${taskDescription}`
|
||||
].join('')
|
||||
|
||||
// 创建任务
|
||||
TaskCreate({
|
||||
subject: `${stage.prefix}-001: ${stage.desc}`,
|
||||
description: fullDesc,
|
||||
activeForm: `${stage.desc}进行中`
|
||||
})
|
||||
|
||||
// 记录任务 ID
|
||||
const allTasks = TaskList()
|
||||
const newTask = allTasks.find(t => t.subject.startsWith(`${stage.prefix}-001`))
|
||||
taskIds[stage.prefix] = newTask.id
|
||||
|
||||
// 设置 owner 和依赖
|
||||
const blockedByIds = stage.blockedBy
|
||||
.map(dep => taskIds[dep])
|
||||
.filter(Boolean)
|
||||
|
||||
TaskUpdate({
|
||||
taskId: newTask.id,
|
||||
owner: stage.owner,
|
||||
addBlockedBy: blockedByIds
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Result Processing
|
||||
|
||||
```javascript
|
||||
// 验证任务链
|
||||
const allTasks = TaskList()
|
||||
const chainTasks = pipeline.map(s => taskIds[s.prefix]).filter(Boolean)
|
||||
const chainValid = chainTasks.length === pipeline.length
|
||||
|
||||
if (!chainValid) {
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: teamName, from: "coordinator",
|
||||
to: "user", type: "error",
|
||||
summary: `[coordinator] 任务链创建不完整: ${chainTasks.length}/${pipeline.length}`
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
## Fix-Verify Loop Task Creation
|
||||
|
||||
当 validator 报告回归问题时,coordinator 调用此逻辑追加任务:
|
||||
|
||||
```javascript
|
||||
function createFixVerifyTasks(fixVerifyIteration, sessionFolder) {
|
||||
// 创建修复任务
|
||||
TaskCreate({
|
||||
subject: `TDFIX-fix-${fixVerifyIteration}: 修复回归问题 (Fix-Verify #${fixVerifyIteration})`,
|
||||
description: `修复验证发现的回归问题\nsession: ${sessionFolder}\ntype: fix-verify`,
|
||||
activeForm: `Fix-Verify #${fixVerifyIteration} 修复中`
|
||||
})
|
||||
|
||||
// 创建重新验证任务
|
||||
TaskCreate({
|
||||
subject: `TDVAL-verify-${fixVerifyIteration}: 重新验证 (Fix-Verify #${fixVerifyIteration})`,
|
||||
description: `重新验证修复结果\nsession: ${sessionFolder}`,
|
||||
activeForm: `Fix-Verify #${fixVerifyIteration} 验证中`
|
||||
})
|
||||
|
||||
// 设置依赖: TDVAL-verify 依赖 TDFIX-fix
|
||||
// ... TaskUpdate addBlockedBy
|
||||
}
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
## Task Chain Created
|
||||
|
||||
### Mode: [scan|remediate|targeted]
|
||||
### Pipeline Stages: [count]
|
||||
- [prefix]-001: [description] (owner: [role], blocked by: [deps])
|
||||
|
||||
### Verification: PASS/FAIL
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| Task creation fails | Retry once, then report to user |
|
||||
| Dependency cycle detected | Flatten dependencies, warn coordinator |
|
||||
| Invalid pipelineMode | Default to 'scan' mode |
|
||||
| Agent/CLI failure | Retry once, then fallback to inline execution |
|
||||
| Timeout (>5 min) | Report partial results, notify coordinator |
|
||||
@@ -0,0 +1,255 @@
|
||||
# Command: monitor
|
||||
|
||||
> 阶段驱动的协调循环。按 pipeline 阶段顺序等待 worker 完成,路由消息,处理 Fix-Verify 循环,检测完成。
|
||||
|
||||
## When to Use
|
||||
|
||||
- Phase 4 of Coordinator
|
||||
- 任务链已创建并分发
|
||||
- 需要持续监控直到所有任务完成
|
||||
|
||||
**Trigger conditions**:
|
||||
- dispatch 完成后立即启动
|
||||
- Fix-Verify 循环创建新任务后重新进入
|
||||
|
||||
## Strategy
|
||||
|
||||
### Delegation Mode
|
||||
|
||||
**Mode**: Stage-driven(按阶段顺序等待,非轮询)
|
||||
|
||||
### 设计原则
|
||||
|
||||
> **模型执行没有时间概念**。禁止空转 while 循环检查状态。
|
||||
> 使用固定 sleep 间隔 + 最大轮询次数,避免无意义的 API 调用浪费。
|
||||
|
||||
### Decision Logic
|
||||
|
||||
```javascript
|
||||
// 消息路由表
|
||||
const routingTable = {
|
||||
// Scanner 完成
|
||||
'scan_complete': { action: 'Mark TDSCAN complete, unblock TDEVAL' },
|
||||
'debt_items_found': { action: 'Mark TDSCAN complete with items, unblock TDEVAL' },
|
||||
// Assessor 完成
|
||||
'assessment_complete': { action: 'Mark TDEVAL complete, unblock TDPLAN' },
|
||||
// Planner 完成
|
||||
'plan_ready': { action: 'Mark TDPLAN complete, unblock TDFIX' },
|
||||
'plan_revision': { action: 'Plan revised, re-evaluate dependencies' },
|
||||
// Executor 完成
|
||||
'fix_complete': { action: 'Mark TDFIX complete, unblock TDVAL' },
|
||||
'fix_progress': { action: 'Log progress, continue waiting' },
|
||||
// Validator 完成
|
||||
'validation_complete': { action: 'Mark TDVAL complete, evaluate quality gate', special: 'quality_gate' },
|
||||
'regression_found': { action: 'Evaluate regression, decide Fix-Verify loop', special: 'fix_verify_decision' },
|
||||
// 错误
|
||||
'error': { action: 'Assess severity, retry or escalate', special: 'error_handler' }
|
||||
}
|
||||
```
|
||||
|
||||
### 等待策略常量
|
||||
|
||||
```javascript
|
||||
const POLL_INTERVAL_SEC = 300 // 每次检查间隔 5 分钟
|
||||
const MAX_POLLS_PER_STAGE = 6 // 单阶段最多等待 6 次(~30 分钟)
|
||||
const SLEEP_CMD = process.platform === 'win32'
|
||||
? `timeout /t ${POLL_INTERVAL_SEC} /nobreak >nul 2>&1`
|
||||
: `sleep ${POLL_INTERVAL_SEC}`
|
||||
|
||||
// 统一 auto mode 检测
|
||||
const autoYes = /\b(-y|--yes)\b/.test(args)
|
||||
```
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Context Preparation
|
||||
|
||||
```javascript
|
||||
// 从 shared memory 获取上下文
|
||||
const sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`))
|
||||
|
||||
let fixVerifyIteration = 0
|
||||
const MAX_FIX_VERIFY_ITERATIONS = 3
|
||||
|
||||
// 获取 pipeline 阶段列表
|
||||
const allTasks = TaskList()
|
||||
const pipelineTasks = allTasks
|
||||
.filter(t => t.owner && t.owner !== 'coordinator')
|
||||
.sort((a, b) => Number(a.id) - Number(b.id))
|
||||
```
|
||||
|
||||
### Step 2: Stage-Driven Execution
|
||||
|
||||
> **核心**: 按 pipeline 阶段顺序,逐阶段等待完成。
|
||||
> 每个阶段:sleep → 检查消息 → 确认任务状态 → 处理结果 → 下一阶段。
|
||||
|
||||
```javascript
|
||||
for (const stageTask of pipelineTasks) {
|
||||
let stageComplete = false
|
||||
let pollCount = 0
|
||||
|
||||
while (!stageComplete && pollCount < MAX_POLLS_PER_STAGE) {
|
||||
Bash(SLEEP_CMD)
|
||||
pollCount++
|
||||
|
||||
// 1. 检查消息总线
|
||||
const messages = mcp__ccw-tools__team_msg({
|
||||
operation: "list",
|
||||
team: teamName,
|
||||
last: 5
|
||||
})
|
||||
|
||||
// 2. 路由消息
|
||||
for (const msg of messages) {
|
||||
const handler = routingTable[msg.type]
|
||||
if (!handler) continue
|
||||
processMessage(msg, handler)
|
||||
}
|
||||
|
||||
// 3. 确认任务状态
|
||||
const currentTask = TaskGet({ taskId: stageTask.id })
|
||||
stageComplete = currentTask.status === 'completed' || currentTask.status === 'deleted'
|
||||
}
|
||||
|
||||
// 阶段超时处理
|
||||
if (!stageComplete) {
|
||||
const elapsedMin = Math.round(pollCount * POLL_INTERVAL_SEC / 60)
|
||||
|
||||
if (autoYes) {
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: teamName, from: "coordinator",
|
||||
to: "user", type: "error",
|
||||
summary: `[coordinator] [auto] 阶段 ${stageTask.subject} 超时 (${elapsedMin}min),自动跳过`
|
||||
})
|
||||
TaskUpdate({ taskId: stageTask.id, status: 'deleted' })
|
||||
continue
|
||||
}
|
||||
|
||||
const decision = AskUserQuestion({
|
||||
questions: [{
|
||||
question: `阶段 "${stageTask.subject}" 已等待 ${elapsedMin} 分钟仍未完成。如何处理?`,
|
||||
header: "Stage Wait",
|
||||
multiSelect: false,
|
||||
options: [
|
||||
{ label: "继续等待", description: `再等 ${MAX_POLLS_PER_STAGE} 轮` },
|
||||
{ label: "跳过此阶段", description: "标记为跳过,继续后续流水线" },
|
||||
{ label: "终止流水线", description: "停止整个流程,汇报当前结果" }
|
||||
]
|
||||
}]
|
||||
})
|
||||
|
||||
const answer = decision["Stage Wait"]
|
||||
if (answer === "跳过此阶段") {
|
||||
TaskUpdate({ taskId: stageTask.id, status: 'deleted' })
|
||||
continue
|
||||
} else if (answer === "终止流水线") {
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: teamName, from: "coordinator",
|
||||
to: "user", type: "shutdown",
|
||||
summary: `[coordinator] 用户终止流水线,当前阶段: ${stageTask.subject}`
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2.1: Message Processing (processMessage)
|
||||
|
||||
```javascript
|
||||
function processMessage(msg, handler) {
|
||||
switch (handler.special) {
|
||||
case 'quality_gate': {
|
||||
const latestMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`))
|
||||
const debtBefore = latestMemory.debt_score_before || 0
|
||||
const debtAfter = latestMemory.debt_score_after || 0
|
||||
const improved = debtAfter < debtBefore
|
||||
|
||||
let status = 'PASS'
|
||||
if (!improved && latestMemory.validation_results?.regressions > 0) status = 'FAIL'
|
||||
else if (!improved) status = 'CONDITIONAL'
|
||||
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: teamName, from: "coordinator",
|
||||
to: "user", type: "quality_gate",
|
||||
summary: `[coordinator] 质量门控: ${status} (债务分 ${debtBefore} → ${debtAfter})`
|
||||
})
|
||||
break
|
||||
}
|
||||
|
||||
case 'fix_verify_decision': {
|
||||
const regressions = msg.data?.regressions || 0
|
||||
if (regressions > 0 && fixVerifyIteration < MAX_FIX_VERIFY_ITERATIONS) {
|
||||
fixVerifyIteration++
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: teamName, from: "coordinator",
|
||||
to: "executor", type: "task_unblocked",
|
||||
summary: `[coordinator] Fix-Verify #${fixVerifyIteration}: 发现 ${regressions} 个回归,请修复`,
|
||||
data: { iteration: fixVerifyIteration, regressions }
|
||||
})
|
||||
// 创建 Fix-Verify 修复任务(参见 dispatch.md createFixVerifyTasks)
|
||||
} else {
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: teamName, from: "coordinator",
|
||||
to: "user", type: "quality_gate",
|
||||
summary: `[coordinator] Fix-Verify 循环已达上限(${MAX_FIX_VERIFY_ITERATIONS}),接受当前结果`
|
||||
})
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'error_handler': {
|
||||
const severity = msg.data?.severity || 'medium'
|
||||
if (severity === 'critical') {
|
||||
SendMessage({
|
||||
content: `## [coordinator] Critical Error from ${msg.from}\n\n${msg.summary}`,
|
||||
summary: `[coordinator] Critical error: ${msg.summary}`
|
||||
})
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Result Processing
|
||||
|
||||
```javascript
|
||||
// 汇总所有结果
|
||||
const finalSharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`))
|
||||
const allFinalTasks = TaskList()
|
||||
const workerTasks = allFinalTasks.filter(t => t.owner && t.owner !== 'coordinator')
|
||||
const summary = {
|
||||
total_tasks: workerTasks.length,
|
||||
completed_tasks: workerTasks.filter(t => t.status === 'completed').length,
|
||||
fix_verify_iterations: fixVerifyIteration,
|
||||
debt_score_before: finalSharedMemory.debt_score_before,
|
||||
debt_score_after: finalSharedMemory.debt_score_after
|
||||
}
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
## Coordination Summary
|
||||
|
||||
### Pipeline Status: COMPLETE
|
||||
### Tasks: [completed]/[total]
|
||||
### Fix-Verify Iterations: [count]
|
||||
### Debt Score: [before] → [after]
|
||||
|
||||
### Message Log (last 10)
|
||||
- [timestamp] [from] → [to]: [type] - [summary]
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| Message bus unavailable | Fall back to TaskList polling only |
|
||||
| Stage timeout (交互模式) | AskUserQuestion: 继续等待 / 跳过 / 终止 |
|
||||
| Stage timeout (自动模式 `-y`/`--yes`) | 自动跳过,记录日志 |
|
||||
| Teammate unresponsive (2x no response) | Respawn teammate with same task |
|
||||
| Deadlock detected | Identify cycle, manually unblock |
|
||||
| Quality gate FAIL | Report to user, suggest targeted re-run |
|
||||
| Fix-Verify loop stuck >3 iterations | Accept current state, continue pipeline |
|
||||
264
.claude/skills/team-tech-debt/roles/coordinator/role.md
Normal file
264
.claude/skills/team-tech-debt/roles/coordinator/role.md
Normal file
@@ -0,0 +1,264 @@
|
||||
# Role: coordinator
|
||||
|
||||
技术债务治理团队协调者。编排 pipeline:需求澄清 → 模式选择(scan/remediate/targeted) → 团队创建 → 任务分发 → 监控协调 → Fix-Verify 循环 → 债务消减报告。
|
||||
|
||||
## 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 进度并路由消息
|
||||
|
||||
### MUST NOT
|
||||
|
||||
- 直接执行任何业务任务(扫描、评估、规划、修复、验证等)
|
||||
- 直接调用 cli-explore-agent、code-developer 等实现类 subagent
|
||||
- 直接修改源代码或生成产物文件
|
||||
- 绕过 worker 角色自行完成应委派的工作
|
||||
- 在输出中省略 `[coordinator]` 标识
|
||||
|
||||
> **核心原则**: coordinator 是指挥者,不是执行者。所有实际工作必须通过 TaskCreate 委派给 worker 角色。
|
||||
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `mode_selected` | coordinator → all | 模式确定 | scan/remediate/targeted |
|
||||
| `quality_gate` | coordinator → user | 质量评估 | 通过/不通过/有条件通过 |
|
||||
| `task_unblocked` | coordinator → worker | 依赖解除 | 任务可执行 |
|
||||
| `error` | coordinator → user | 协调错误 | 阻塞性问题 |
|
||||
| `shutdown` | coordinator → all | 团队关闭 | 清理资源 |
|
||||
|
||||
## Message Bus
|
||||
|
||||
每次 SendMessage 前,先调用 `mcp__ccw-tools__team_msg` 记录:
|
||||
|
||||
```javascript
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: teamName,
|
||||
from: "coordinator",
|
||||
to: "user",
|
||||
type: "mode_selected",
|
||||
summary: "[coordinator] 模式已选择: remediate"
|
||||
})
|
||||
```
|
||||
|
||||
### CLI 回退
|
||||
|
||||
若 `mcp__ccw-tools__team_msg` 不可用,使用 Bash 写入日志文件:
|
||||
|
||||
```javascript
|
||||
Bash(`echo '${JSON.stringify({ from: "coordinator", to: "user", type: "mode_selected", summary: msg, ts: new Date().toISOString() })}' >> "${sessionFolder}/message-log.jsonl"`)
|
||||
```
|
||||
|
||||
## Toolbox
|
||||
|
||||
### Available Commands
|
||||
|
||||
| Command | File | Phase | Description |
|
||||
|---------|------|-------|-------------|
|
||||
| `dispatch` | [commands/dispatch.md](commands/dispatch.md) | Phase 3 | 任务链创建与依赖管理 |
|
||||
| `monitor` | [commands/monitor.md](commands/monitor.md) | Phase 4 | 消息总线轮询与协调循环 |
|
||||
|
||||
### Subagent Capabilities
|
||||
|
||||
> Coordinator 不直接使用 subagent(通过 worker 角色间接使用)
|
||||
|
||||
### CLI Capabilities
|
||||
|
||||
> Coordinator 不直接使用 CLI 分析工具
|
||||
|
||||
## Execution (5-Phase)
|
||||
|
||||
### Phase 1: Parse Arguments & Mode Detection
|
||||
|
||||
```javascript
|
||||
const args = "$ARGUMENTS"
|
||||
|
||||
// 提取任务描述
|
||||
const taskDescription = args.replace(/--role[=\s]+\w+/, '').replace(/--team[=\s]+[\w-]+/, '').replace(/--mode[=\s]+\w+/, '').trim()
|
||||
|
||||
// Three-Mode 检测
|
||||
function detectMode(args, desc) {
|
||||
const modeMatch = args.match(/--mode[=\s]+(scan|remediate|targeted)/)
|
||||
if (modeMatch) return modeMatch[1]
|
||||
if (/扫描|scan|审计|audit|评估|assess/.test(desc)) return 'scan'
|
||||
if (/定向|targeted|指定|specific|修复.*已知/.test(desc)) return 'targeted'
|
||||
return 'remediate'
|
||||
}
|
||||
|
||||
let pipelineMode = detectMode(args, taskDescription)
|
||||
|
||||
// 统一 auto mode 检测
|
||||
const autoYes = /\b(-y|--yes)\b/.test(args)
|
||||
|
||||
// 简单任务可跳过确认(auto 模式跳过)
|
||||
if (!autoYes && (!taskDescription || taskDescription.length < 10)) {
|
||||
const clarification = AskUserQuestion({
|
||||
questions: [{
|
||||
question: "请描述技术债务治理目标(哪些模块?关注哪些维度?)",
|
||||
header: "Tech Debt Target",
|
||||
multiSelect: false,
|
||||
options: [
|
||||
{ label: "自定义", description: "输入具体描述" },
|
||||
{ label: "全项目扫描", description: "多维度扫描并评估技术债务" },
|
||||
{ label: "完整治理", description: "扫描+评估+规划+修复+验证闭环" },
|
||||
{ label: "定向修复", description: "针对已知债务项进行修复" }
|
||||
]
|
||||
}]
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 2: Create Team + Spawn Teammates
|
||||
|
||||
```javascript
|
||||
const teamName = "tech-debt"
|
||||
const sessionSlug = taskDescription.slice(0, 30).replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '-')
|
||||
const sessionDate = new Date().toISOString().slice(0, 10)
|
||||
const sessionFolder = `.workflow/.team/TD-${sessionSlug}-${sessionDate}`
|
||||
Bash(`mkdir -p "${sessionFolder}/scan" "${sessionFolder}/assessment" "${sessionFolder}/plan" "${sessionFolder}/fixes" "${sessionFolder}/validation"`)
|
||||
|
||||
// 初始化 shared memory
|
||||
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify({
|
||||
debt_inventory: [],
|
||||
priority_matrix: {},
|
||||
remediation_plan: {},
|
||||
fix_results: {},
|
||||
validation_results: {},
|
||||
debt_score_before: null,
|
||||
debt_score_after: null
|
||||
}, null, 2))
|
||||
|
||||
TeamCreate({ team_name: teamName })
|
||||
|
||||
// Spawn teammates (see SKILL.md Coordinator Spawn Template)
|
||||
// Scanner, Assessor, Planner, Executor, Validator
|
||||
```
|
||||
|
||||
### Phase 3: Create Task Chain
|
||||
|
||||
根据 pipelineMode 创建不同的任务链:
|
||||
|
||||
```javascript
|
||||
// Read commands/dispatch.md for full implementation
|
||||
Read("commands/dispatch.md")
|
||||
```
|
||||
|
||||
**Scan Mode**:
|
||||
```
|
||||
TDSCAN-001(多维度扫描) → TDEVAL-001(量化评估)
|
||||
```
|
||||
|
||||
**Remediate Mode**:
|
||||
```
|
||||
TDSCAN-001(扫描) → TDEVAL-001(评估) → TDPLAN-001(规划) → TDFIX-001(修复) → TDVAL-001(验证)
|
||||
```
|
||||
|
||||
**Targeted Mode**:
|
||||
```
|
||||
TDPLAN-001(规划) → TDFIX-001(修复) → TDVAL-001(验证)
|
||||
```
|
||||
|
||||
### Phase 4: Coordination Loop
|
||||
|
||||
```javascript
|
||||
// Read commands/monitor.md for full implementation
|
||||
Read("commands/monitor.md")
|
||||
```
|
||||
|
||||
| Received Message | Action |
|
||||
|-----------------|--------|
|
||||
| `scan_complete` | 标记 TDSCAN complete → 解锁 TDEVAL |
|
||||
| `assessment_complete` | 标记 TDEVAL complete → 解锁 TDPLAN |
|
||||
| `plan_ready` | 标记 TDPLAN complete → 解锁 TDFIX |
|
||||
| `fix_complete` | 标记 TDFIX complete → 解锁 TDVAL |
|
||||
| `validation_complete` | 标记 TDVAL complete → 评估质量门控 |
|
||||
| `regression_found` | 评估回归 → 触发 Fix-Verify 循环(max 3) |
|
||||
| Worker: `error` | 评估严重性 → 重试或上报用户 |
|
||||
|
||||
**Fix-Verify 循环逻辑**:
|
||||
```javascript
|
||||
if (regressionFound && fixVerifyIteration < 3) {
|
||||
fixVerifyIteration++
|
||||
// 创建 TDFIX-fix 任务 → TDVAL 重新验证
|
||||
} else if (fixVerifyIteration >= 3) {
|
||||
// 接受当前状态,继续汇报
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: teamName, from: "coordinator",
|
||||
to: "user", type: "quality_gate",
|
||||
summary: `[coordinator] Fix-Verify 循环已达上限(3次),接受当前结果`
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 5: Report + Debt Reduction Metrics
|
||||
|
||||
```javascript
|
||||
// 读取 shared memory 汇总结果
|
||||
const memory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`))
|
||||
|
||||
const report = {
|
||||
mode: pipelineMode,
|
||||
debt_items_found: memory.debt_inventory?.length || 0,
|
||||
debt_score_before: memory.debt_score_before || 'N/A',
|
||||
debt_score_after: memory.debt_score_after || 'N/A',
|
||||
items_fixed: memory.fix_results?.items_fixed || 0,
|
||||
items_remaining: memory.fix_results?.items_remaining || 0,
|
||||
validation_passed: memory.validation_results?.passed || false,
|
||||
regressions: memory.validation_results?.regressions || 0
|
||||
}
|
||||
|
||||
// 计算债务消减率
|
||||
const reductionRate = report.debt_items_found > 0
|
||||
? Math.round((report.items_fixed / report.debt_items_found) * 100)
|
||||
: 0
|
||||
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: teamName, from: "coordinator",
|
||||
to: "user", type: "quality_gate",
|
||||
summary: `[coordinator] 技术债务治理完成: ${report.debt_items_found}项债务, 修复${report.items_fixed}项, 消减率${reductionRate}%`
|
||||
})
|
||||
|
||||
SendMessage({
|
||||
content: `## [coordinator] Tech Debt Report\n\n${JSON.stringify(report, null, 2)}`,
|
||||
summary: `[coordinator] Debt reduction: ${reductionRate}%`
|
||||
})
|
||||
|
||||
// 询问下一步(auto 模式跳过,默认关闭团队)
|
||||
if (!autoYes) {
|
||||
AskUserQuestion({
|
||||
questions: [{
|
||||
question: "技术债务治理流程已完成。下一步:",
|
||||
header: "Next",
|
||||
multiSelect: false,
|
||||
options: [
|
||||
{ label: "新目标", description: "对新模块/维度执行债务治理" },
|
||||
{ label: "深度修复", description: "对剩余高优先级债务继续修复" },
|
||||
{ label: "关闭团队", description: "关闭所有 teammate 并清理" }
|
||||
]
|
||||
}]
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| Teammate unresponsive | Send follow-up, 2x → respawn |
|
||||
| Scanner finds no debt | Report clean codebase, skip to summary |
|
||||
| Fix-Verify loop stuck >3 iterations | Accept current state, continue pipeline |
|
||||
| Build/test environment broken | Notify user, suggest manual fix |
|
||||
| All tasks completed but debt_score_after > debt_score_before | Report with WARNING, suggest re-run |
|
||||
@@ -0,0 +1,176 @@
|
||||
# Command: remediate
|
||||
|
||||
> 分批委派 code-developer 执行债务清理。按修复类型分组(重构、死代码移除、依赖更新、文档补充),每批委派给 code-developer。
|
||||
|
||||
## When to Use
|
||||
|
||||
- Phase 3 of Executor
|
||||
- 治理方案已加载,修复 actions 已分批
|
||||
- 需要通过 code-developer 执行代码修改
|
||||
|
||||
**Trigger conditions**:
|
||||
- TDFIX-* 任务进入 Phase 3
|
||||
- 修复 actions 列表非空
|
||||
- 目标文件可访问
|
||||
|
||||
## Strategy
|
||||
|
||||
### Delegation Mode
|
||||
|
||||
**Mode**: Sequential Batch Delegation
|
||||
**Subagent**: `code-developer`
|
||||
**Batch Strategy**: 按修复类型分组,每组一个委派
|
||||
|
||||
### Decision Logic
|
||||
|
||||
```javascript
|
||||
// 分批策略
|
||||
const batchOrder = ['refactor', 'update-deps', 'add-tests', 'add-docs', 'restructure']
|
||||
|
||||
// 按优先级排序批次
|
||||
function sortBatches(batches) {
|
||||
const sorted = {}
|
||||
for (const type of batchOrder) {
|
||||
if (batches[type]) sorted[type] = batches[type]
|
||||
}
|
||||
// 追加未知类型
|
||||
for (const [type, actions] of Object.entries(batches)) {
|
||||
if (!sorted[type]) sorted[type] = actions
|
||||
}
|
||||
return sorted
|
||||
}
|
||||
```
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Context Preparation
|
||||
|
||||
```javascript
|
||||
// 按类型分组并排序
|
||||
const sortedBatches = sortBatches(batches)
|
||||
|
||||
// 每批最大 items 数
|
||||
const MAX_ITEMS_PER_BATCH = 10
|
||||
|
||||
// 如果单批过大,进一步拆分
|
||||
function splitLargeBatches(batches) {
|
||||
const result = {}
|
||||
for (const [type, actions] of Object.entries(batches)) {
|
||||
if (actions.length <= MAX_ITEMS_PER_BATCH) {
|
||||
result[type] = actions
|
||||
} else {
|
||||
for (let i = 0; i < actions.length; i += MAX_ITEMS_PER_BATCH) {
|
||||
const chunk = actions.slice(i, i + MAX_ITEMS_PER_BATCH)
|
||||
result[`${type}-${Math.floor(i / MAX_ITEMS_PER_BATCH) + 1}`] = chunk
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const finalBatches = splitLargeBatches(sortedBatches)
|
||||
```
|
||||
|
||||
### Step 2: Execute Strategy
|
||||
|
||||
```javascript
|
||||
for (const [batchName, actions] of Object.entries(finalBatches)) {
|
||||
// 构建修复上下文
|
||||
const batchType = batchName.replace(/-\d+$/, '')
|
||||
const fileList = actions.map(a => a.file).filter(Boolean)
|
||||
|
||||
// 根据类型选择修复提示
|
||||
const typePrompts = {
|
||||
'refactor': `Refactor the following code to reduce complexity and improve readability. Preserve all existing behavior.`,
|
||||
'update-deps': `Update the specified dependencies. Check for breaking changes in changelogs.`,
|
||||
'add-tests': `Add missing test coverage for the specified modules. Follow existing test patterns.`,
|
||||
'add-docs': `Add documentation (JSDoc/docstrings) for the specified public APIs. Follow existing doc style.`,
|
||||
'restructure': `Restructure module boundaries to reduce coupling. Move code to appropriate locations.`
|
||||
}
|
||||
|
||||
const prompt = typePrompts[batchType] || 'Apply the specified fix to resolve technical debt.'
|
||||
|
||||
// 委派给 code-developer
|
||||
Task({
|
||||
subagent_type: "code-developer",
|
||||
run_in_background: false,
|
||||
description: `Tech debt cleanup: ${batchName} (${actions.length} items)`,
|
||||
prompt: `## Goal
|
||||
${prompt}
|
||||
|
||||
## Items to Fix
|
||||
${actions.map(a => `### ${a.debt_id}: ${a.action}
|
||||
- File: ${a.file || 'N/A'}
|
||||
- Type: ${a.type}
|
||||
${a.steps ? '- Steps:\n' + a.steps.map(s => ` 1. ${s}`).join('\n') : ''}`).join('\n\n')}
|
||||
|
||||
## Constraints
|
||||
- Read each file BEFORE modifying
|
||||
- Make minimal changes - fix only the specified debt item
|
||||
- Preserve backward compatibility
|
||||
- Do NOT skip tests or add @ts-ignore
|
||||
- Do NOT introduce new dependencies unless explicitly required
|
||||
- Run syntax check after modifications
|
||||
|
||||
## Files to Read First
|
||||
${fileList.map(f => `- ${f}`).join('\n')}`
|
||||
})
|
||||
|
||||
// 验证批次结果
|
||||
const batchResult = {
|
||||
batch: batchName,
|
||||
items: actions.length,
|
||||
status: 'completed'
|
||||
}
|
||||
|
||||
// 检查文件是否被修改
|
||||
for (const file of fileList) {
|
||||
const modified = Bash(`git diff --name-only -- "${file}" 2>/dev/null`).trim()
|
||||
if (modified) {
|
||||
fixResults.files_modified.push(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Result Processing
|
||||
|
||||
```javascript
|
||||
// 统计修复结果
|
||||
const totalActions = Object.values(finalBatches).flat().length
|
||||
fixResults.items_fixed = fixResults.files_modified.length
|
||||
fixResults.items_failed = totalActions - fixResults.items_fixed
|
||||
fixResults.items_remaining = fixResults.items_failed
|
||||
|
||||
// 生成修复摘要
|
||||
const batchSummaries = Object.entries(finalBatches).map(([name, actions]) =>
|
||||
`- ${name}: ${actions.length} items`
|
||||
).join('\n')
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
## Remediation Results
|
||||
|
||||
### Batches Executed: [count]
|
||||
### Items Fixed: [count]/[total]
|
||||
### Files Modified: [count]
|
||||
|
||||
### Batch Details
|
||||
- [batch-name]: [count] items - [status]
|
||||
|
||||
### Modified Files
|
||||
- [file-path]
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| code-developer fails on a batch | Retry once, mark failed items |
|
||||
| File locked or read-only | Skip file, log error |
|
||||
| Syntax error after fix | Revert with git checkout, mark as failed |
|
||||
| New import/dependency needed | Add minimally, document in fix log |
|
||||
| Batch too large (>10 items) | Auto-split into sub-batches |
|
||||
| Agent timeout | Use partial results, continue next batch |
|
||||
267
.claude/skills/team-tech-debt/roles/executor/role.md
Normal file
267
.claude/skills/team-tech-debt/roles/executor/role.md
Normal file
@@ -0,0 +1,267 @@
|
||||
# Role: executor
|
||||
|
||||
技术债务清理执行者。根据治理方案执行重构、依赖更新、代码清理、文档补充等操作。通过 code-developer subagent 分批执行修复任务,包含自验证环节。
|
||||
|
||||
## Role Identity
|
||||
|
||||
- **Name**: `executor`
|
||||
- **Task Prefix**: `TDFIX-*`
|
||||
- **Responsibility**: Code generation(债务清理执行)
|
||||
- **Communication**: SendMessage to coordinator only
|
||||
- **Output Tag**: `[executor]`
|
||||
|
||||
## Role Boundaries
|
||||
|
||||
### MUST
|
||||
|
||||
- 仅处理 `TDFIX-*` 前缀的任务
|
||||
- 所有输出必须带 `[executor]` 标识
|
||||
- 按治理方案执行修复操作
|
||||
- 执行基本自验证(语法检查、lint)
|
||||
|
||||
### MUST NOT
|
||||
|
||||
- 从零创建新功能(仅清理债务)
|
||||
- 修改不在治理方案中的代码
|
||||
- 为其他角色创建任务
|
||||
- 直接与其他 worker 通信
|
||||
- 跳过自验证步骤
|
||||
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `fix_complete` | executor → coordinator | 修复完成 | 包含修复摘要 |
|
||||
| `fix_progress` | executor → coordinator | 批次完成 | 进度更新 |
|
||||
| `error` | executor → coordinator | 执行失败 | 阻塞性错误 |
|
||||
|
||||
## Message Bus
|
||||
|
||||
每次 SendMessage 前,先调用 `mcp__ccw-tools__team_msg` 记录:
|
||||
|
||||
```javascript
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: teamName,
|
||||
from: "executor",
|
||||
to: "coordinator",
|
||||
type: "fix_complete",
|
||||
summary: "[executor] 修复完成: 15/20 items fixed"
|
||||
})
|
||||
```
|
||||
|
||||
### CLI 回退
|
||||
|
||||
若 `mcp__ccw-tools__team_msg` 不可用,使用 Bash 写入日志文件:
|
||||
|
||||
```javascript
|
||||
Bash(`echo '${JSON.stringify({ from: "executor", to: "coordinator", type: "fix_complete", summary: msg, ts: new Date().toISOString() })}' >> "${sessionFolder}/message-log.jsonl"`)
|
||||
```
|
||||
|
||||
## Toolbox
|
||||
|
||||
### Available Commands
|
||||
|
||||
| Command | File | Phase | Description |
|
||||
|---------|------|-------|-------------|
|
||||
| `remediate` | [commands/remediate.md](commands/remediate.md) | Phase 3 | 分批委派 code-developer 执行修复 |
|
||||
|
||||
### Subagent Capabilities
|
||||
|
||||
| Agent Type | Used By | Purpose |
|
||||
|------------|---------|---------|
|
||||
| `code-developer` | remediate.md | 代码修复执行 |
|
||||
|
||||
### CLI Capabilities
|
||||
|
||||
> Executor 不直接使用 CLI 分析工具(通过 code-developer 间接使用)
|
||||
|
||||
## Execution (5-Phase)
|
||||
|
||||
### Phase 1: Task Discovery
|
||||
|
||||
```javascript
|
||||
const tasks = TaskList()
|
||||
const myTasks = tasks.filter(t =>
|
||||
t.subject.startsWith('TDFIX-') &&
|
||||
t.owner === 'executor' &&
|
||||
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: Load Remediation Plan
|
||||
|
||||
```javascript
|
||||
const sessionFolder = task.description.match(/session:\s*(.+)/)?.[1]?.trim() || '.'
|
||||
let sharedMemory = {}
|
||||
try { sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`)) } catch {}
|
||||
|
||||
// 加载治理方案
|
||||
let plan = {}
|
||||
try {
|
||||
plan = JSON.parse(Read(`${sessionFolder}/plan/remediation-plan.json`))
|
||||
} catch {}
|
||||
|
||||
// 确定要执行的 actions
|
||||
const allActions = plan.phases
|
||||
? plan.phases.flatMap(p => p.actions || [])
|
||||
: []
|
||||
|
||||
// 识别目标文件
|
||||
const targetFiles = [...new Set(allActions.map(a => a.file).filter(Boolean))]
|
||||
|
||||
// 按类型分批
|
||||
const batches = groupActionsByType(allActions)
|
||||
|
||||
function groupActionsByType(actions) {
|
||||
const groups = {}
|
||||
for (const action of actions) {
|
||||
const type = action.type || 'refactor'
|
||||
if (!groups[type]) groups[type] = []
|
||||
groups[type].push(action)
|
||||
}
|
||||
return groups
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 3: Execute Fixes
|
||||
|
||||
```javascript
|
||||
// Read commands/remediate.md for full implementation
|
||||
Read("commands/remediate.md")
|
||||
```
|
||||
|
||||
**核心策略**: 分批委派 code-developer 执行修复
|
||||
|
||||
```javascript
|
||||
const fixResults = {
|
||||
items_fixed: 0,
|
||||
items_failed: 0,
|
||||
items_remaining: 0,
|
||||
batches_completed: 0,
|
||||
files_modified: [],
|
||||
errors: []
|
||||
}
|
||||
|
||||
for (const [batchType, actions] of Object.entries(batches)) {
|
||||
// 委派给 code-developer
|
||||
Task({
|
||||
subagent_type: "code-developer",
|
||||
run_in_background: false,
|
||||
description: `Fix tech debt batch: ${batchType} (${actions.length} items)`,
|
||||
prompt: `## Goal
|
||||
Execute tech debt cleanup for ${batchType} items.
|
||||
|
||||
## Actions
|
||||
${actions.map(a => `- [${a.debt_id}] ${a.action} (file: ${a.file})`).join('\n')}
|
||||
|
||||
## Instructions
|
||||
- Read each target file before modifying
|
||||
- Apply the specified fix
|
||||
- Preserve backward compatibility
|
||||
- Do NOT introduce new features
|
||||
- Do NOT modify unrelated code
|
||||
- Run basic syntax check after each change`
|
||||
})
|
||||
|
||||
// 记录进度
|
||||
fixResults.batches_completed++
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: teamName, from: "executor",
|
||||
to: "coordinator", type: "fix_progress",
|
||||
summary: `[executor] 批次 ${batchType} 完成 (${fixResults.batches_completed}/${Object.keys(batches).length})`
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 4: Self-Validation
|
||||
|
||||
```javascript
|
||||
// 基本语法检查
|
||||
const syntaxResult = Bash(`npx tsc --noEmit 2>&1 || python -m py_compile *.py 2>&1 || echo "skip"`)
|
||||
const hasSyntaxErrors = /error/i.test(syntaxResult) && !/skip/.test(syntaxResult)
|
||||
|
||||
// 基本 lint 检查
|
||||
const lintResult = Bash(`npx eslint --no-error-on-unmatched-pattern src/ 2>&1 || echo "skip"`)
|
||||
const hasLintErrors = /error/i.test(lintResult) && !/skip/.test(lintResult)
|
||||
|
||||
// 更新修复统计
|
||||
fixResults.items_fixed = allActions.length - fixResults.items_failed
|
||||
fixResults.items_remaining = fixResults.items_failed
|
||||
fixResults.self_validation = {
|
||||
syntax_check: hasSyntaxErrors ? 'FAIL' : 'PASS',
|
||||
lint_check: hasLintErrors ? 'FAIL' : 'PASS'
|
||||
}
|
||||
|
||||
// 保存修复日志
|
||||
Bash(`mkdir -p "${sessionFolder}/fixes"`)
|
||||
Write(`${sessionFolder}/fixes/fix-log.json`, JSON.stringify(fixResults, null, 2))
|
||||
|
||||
// 更新 shared memory
|
||||
sharedMemory.fix_results = fixResults
|
||||
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
|
||||
```
|
||||
|
||||
### Phase 5: Report to Coordinator
|
||||
|
||||
```javascript
|
||||
const statusMsg = `修复 ${fixResults.items_fixed}/${allActions.length} 项, 语法: ${fixResults.self_validation.syntax_check}, lint: ${fixResults.self_validation.lint_check}`
|
||||
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: teamName,
|
||||
from: "executor",
|
||||
to: "coordinator",
|
||||
type: "fix_complete",
|
||||
summary: `[executor] ${statusMsg}`,
|
||||
ref: `${sessionFolder}/fixes/fix-log.json`,
|
||||
data: { items_fixed: fixResults.items_fixed, items_failed: fixResults.items_failed }
|
||||
})
|
||||
|
||||
SendMessage({
|
||||
type: "message",
|
||||
recipient: "coordinator",
|
||||
content: `## [executor] Fix Results
|
||||
|
||||
**Task**: ${task.subject}
|
||||
**Status**: ${fixResults.items_failed === 0 ? 'ALL FIXED' : 'PARTIAL'}
|
||||
|
||||
### Summary
|
||||
- Items fixed: ${fixResults.items_fixed}
|
||||
- Items failed: ${fixResults.items_failed}
|
||||
- Batches: ${fixResults.batches_completed}/${Object.keys(batches).length}
|
||||
|
||||
### Self-Validation
|
||||
- Syntax check: ${fixResults.self_validation.syntax_check}
|
||||
- Lint check: ${fixResults.self_validation.lint_check}
|
||||
|
||||
### Fix Log
|
||||
${sessionFolder}/fixes/fix-log.json`,
|
||||
summary: `[executor] TDFIX complete: ${statusMsg}`
|
||||
})
|
||||
|
||||
TaskUpdate({ taskId: task.id, status: 'completed' })
|
||||
|
||||
const nextTasks = TaskList().filter(t =>
|
||||
t.subject.startsWith('TDFIX-') && t.owner === 'executor' &&
|
||||
t.status === 'pending' && t.blockedBy.length === 0
|
||||
)
|
||||
if (nextTasks.length > 0) { /* back to Phase 1 */ }
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| No TDFIX-* tasks available | Idle, wait for coordinator |
|
||||
| Remediation plan missing | Request plan from shared memory, report error if empty |
|
||||
| code-developer fails | Retry once, skip item on second failure |
|
||||
| Syntax check fails after fix | Revert change, mark item as failed |
|
||||
| Lint errors introduced | Attempt auto-fix with eslint --fix, report if persistent |
|
||||
| File not found | Skip item, log warning |
|
||||
@@ -0,0 +1,165 @@
|
||||
# Command: create-plan
|
||||
|
||||
> 使用 gemini CLI 创建结构化治理方案。将 quick-wins 归为立即执行,systematic 归为中期治理,识别预防机制用于长期改善。输出 remediation-plan.md。
|
||||
|
||||
## When to Use
|
||||
|
||||
- Phase 3 of Planner
|
||||
- 评估矩阵已就绪,需要创建治理方案
|
||||
- 债务项已按优先级象限分组
|
||||
|
||||
**Trigger conditions**:
|
||||
- TDPLAN-* 任务进入 Phase 3
|
||||
- 评估数据可用(priority-matrix.json)
|
||||
- 需要 CLI 辅助生成详细修复建议
|
||||
|
||||
## Strategy
|
||||
|
||||
### Delegation Mode
|
||||
|
||||
**Mode**: CLI Analysis + Template Generation
|
||||
**CLI Tool**: `gemini` (primary)
|
||||
**CLI Mode**: `analysis`
|
||||
|
||||
### Decision Logic
|
||||
|
||||
```javascript
|
||||
// 方案生成策略
|
||||
if (quickWins.length + strategic.length <= 5) {
|
||||
// 少量项目:内联生成方案
|
||||
mode = 'inline'
|
||||
} else {
|
||||
// 较多项目:CLI 辅助生成详细修复步骤
|
||||
mode = 'cli-assisted'
|
||||
}
|
||||
```
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Context Preparation
|
||||
|
||||
```javascript
|
||||
// 准备债务摘要供 CLI 分析
|
||||
const debtSummary = debtInventory
|
||||
.filter(i => i.priority_quadrant === 'quick-win' || i.priority_quadrant === 'strategic')
|
||||
.map(i => `[${i.id}] [${i.priority_quadrant}] [${i.dimension}] ${i.file}:${i.line} - ${i.description} (impact: ${i.impact_score}, cost: ${i.cost_score})`)
|
||||
.join('\n')
|
||||
|
||||
// 读取相关源文件获取上下文
|
||||
const affectedFiles = [...new Set(debtInventory.map(i => i.file).filter(Boolean))]
|
||||
const fileContext = affectedFiles.slice(0, 20).map(f => `@${f}`).join(' ')
|
||||
```
|
||||
|
||||
### Step 2: Execute Strategy
|
||||
|
||||
```javascript
|
||||
if (mode === 'inline') {
|
||||
// 内联生成方案
|
||||
for (const item of quickWins) {
|
||||
item.remediation_steps = [
|
||||
`Read ${item.file}`,
|
||||
`Apply fix: ${item.suggestion || 'Resolve ' + item.description}`,
|
||||
`Verify fix with relevant tests`
|
||||
]
|
||||
}
|
||||
for (const item of strategic) {
|
||||
item.remediation_steps = [
|
||||
`Analyze impact scope of ${item.file}`,
|
||||
`Plan refactoring: ${item.suggestion || 'Address ' + item.description}`,
|
||||
`Implement changes incrementally`,
|
||||
`Run full test suite to verify`
|
||||
]
|
||||
}
|
||||
} else {
|
||||
// CLI 辅助生成修复方案
|
||||
const prompt = `PURPOSE: Create detailed remediation steps for each technical debt item, grouped into actionable phases
|
||||
TASK: • For each quick-win item, generate specific fix steps (1-3 steps) • For each strategic item, generate a refactoring plan (3-5 steps) • Identify prevention mechanisms based on recurring patterns • Group related items that should be fixed together
|
||||
MODE: analysis
|
||||
CONTEXT: ${fileContext}
|
||||
EXPECTED: Structured remediation plan with: phase name, items, steps per item, dependencies between fixes, estimated time per phase
|
||||
CONSTRAINTS: Focus on backward-compatible changes, prefer incremental fixes over big-bang refactoring
|
||||
|
||||
## Debt Items to Plan
|
||||
${debtSummary}
|
||||
|
||||
## Recurring Patterns
|
||||
${[...new Set(debtInventory.map(i => i.dimension))].map(d => {
|
||||
const count = debtInventory.filter(i => i.dimension === d).length
|
||||
return `- ${d}: ${count} items`
|
||||
}).join('\n')}`
|
||||
|
||||
Bash(`ccw cli -p "${prompt}" --tool gemini --mode analysis --rule planning-breakdown-task-steps`, {
|
||||
run_in_background: true
|
||||
})
|
||||
|
||||
// 等待 CLI 完成,解析结果
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Result Processing
|
||||
|
||||
```javascript
|
||||
// 生成 Markdown 治理方案
|
||||
function generatePlanMarkdown(plan, validation) {
|
||||
return `# Tech Debt Remediation Plan
|
||||
|
||||
## Overview
|
||||
- **Total Actions**: ${validation.total_actions}
|
||||
- **Files Affected**: ${validation.files_affected.length}
|
||||
- **Total Estimated Effort**: ${validation.total_effort} points
|
||||
|
||||
## Phase 1: Quick Wins (Immediate)
|
||||
> High impact, low cost items for immediate action.
|
||||
|
||||
${plan.phases[0].actions.map((a, i) => `### ${i + 1}. ${a.debt_id}: ${a.action}
|
||||
- **File**: ${a.file || 'N/A'}
|
||||
- **Type**: ${a.type}
|
||||
${a.steps ? a.steps.map(s => `- [ ] ${s}`).join('\n') : ''}`).join('\n\n')}
|
||||
|
||||
## Phase 2: Systematic (Medium-term)
|
||||
> High impact items requiring structured refactoring.
|
||||
|
||||
${plan.phases[1].actions.map((a, i) => `### ${i + 1}. ${a.debt_id}: ${a.action}
|
||||
- **File**: ${a.file || 'N/A'}
|
||||
- **Type**: ${a.type}
|
||||
${a.steps ? a.steps.map(s => `- [ ] ${s}`).join('\n') : ''}`).join('\n\n')}
|
||||
|
||||
## Phase 3: Prevention (Long-term)
|
||||
> Mechanisms to prevent future debt accumulation.
|
||||
|
||||
${plan.phases[2].actions.map((a, i) => `### ${i + 1}. ${a.action}
|
||||
- **Dimension**: ${a.dimension || 'general'}
|
||||
- **Type**: ${a.type}`).join('\n\n')}
|
||||
|
||||
## Execution Notes
|
||||
- Execute Phase 1 first for maximum ROI
|
||||
- Phase 2 items may require feature branches
|
||||
- Phase 3 should be integrated into CI/CD pipeline
|
||||
`
|
||||
}
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
## Remediation Plan Created
|
||||
|
||||
### Phases: 3
|
||||
### Quick Wins: [count] actions
|
||||
### Systematic: [count] actions
|
||||
### Prevention: [count] actions
|
||||
### Files Affected: [count]
|
||||
|
||||
### Output: [sessionFolder]/plan/remediation-plan.md
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| CLI returns unstructured text | Parse manually, extract action items |
|
||||
| No quick-wins available | Focus plan on systematic and prevention |
|
||||
| File references invalid | Verify with Glob, skip non-existent files |
|
||||
| CLI timeout | Generate plan from heuristic data only |
|
||||
| Agent/CLI failure | Retry once, then inline generation |
|
||||
| Timeout (>5 min) | Report partial plan, notify planner |
|
||||
287
.claude/skills/team-tech-debt/roles/planner/role.md
Normal file
287
.claude/skills/team-tech-debt/roles/planner/role.md
Normal file
@@ -0,0 +1,287 @@
|
||||
# Role: planner
|
||||
|
||||
技术债务治理方案规划师。基于评估矩阵创建分阶段治理方案:quick-wins 立即执行、systematic 中期系统治理、prevention 长期预防机制。产出 remediation-plan.md。
|
||||
|
||||
## Role Identity
|
||||
|
||||
- **Name**: `planner`
|
||||
- **Task Prefix**: `TDPLAN-*`
|
||||
- **Responsibility**: Orchestration(治理规划)
|
||||
- **Communication**: SendMessage to coordinator only
|
||||
- **Output Tag**: `[planner]`
|
||||
|
||||
## Role Boundaries
|
||||
|
||||
### MUST
|
||||
|
||||
- 仅处理 `TDPLAN-*` 前缀的任务
|
||||
- 所有输出必须带 `[planner]` 标识
|
||||
- 基于评估数据制定可行的治理方案
|
||||
- 更新 shared memory 中的 remediation_plan
|
||||
|
||||
### MUST NOT
|
||||
|
||||
- 修改源代码或测试代码
|
||||
- 执行修复操作
|
||||
- 为其他角色创建任务
|
||||
- 直接与其他 worker 通信
|
||||
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `plan_ready` | planner → coordinator | 方案完成 | 包含分阶段治理方案 |
|
||||
| `plan_revision` | planner → coordinator | 方案修订 | 根据反馈调整方案 |
|
||||
| `error` | planner → coordinator | 规划失败 | 阻塞性错误 |
|
||||
|
||||
## Message Bus
|
||||
|
||||
每次 SendMessage 前,先调用 `mcp__ccw-tools__team_msg` 记录:
|
||||
|
||||
```javascript
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: teamName,
|
||||
from: "planner",
|
||||
to: "coordinator",
|
||||
type: "plan_ready",
|
||||
summary: "[planner] 治理方案就绪: 3 phases, 12 quick-wins, 8 systematic"
|
||||
})
|
||||
```
|
||||
|
||||
### CLI 回退
|
||||
|
||||
若 `mcp__ccw-tools__team_msg` 不可用,使用 Bash 写入日志文件:
|
||||
|
||||
```javascript
|
||||
Bash(`echo '${JSON.stringify({ from: "planner", to: "coordinator", type: "plan_ready", summary: msg, ts: new Date().toISOString() })}' >> "${sessionFolder}/message-log.jsonl"`)
|
||||
```
|
||||
|
||||
## Toolbox
|
||||
|
||||
### Available Commands
|
||||
|
||||
| Command | File | Phase | Description |
|
||||
|---------|------|-------|-------------|
|
||||
| `create-plan` | [commands/create-plan.md](commands/create-plan.md) | Phase 3 | 分阶段治理方案生成 |
|
||||
|
||||
### Subagent Capabilities
|
||||
|
||||
| Agent Type | Used By | Purpose |
|
||||
|------------|---------|---------|
|
||||
| `cli-explore-agent` | create-plan.md | 代码库探索验证方案可行性 |
|
||||
|
||||
### CLI Capabilities
|
||||
|
||||
| CLI Tool | Mode | Used By | Purpose |
|
||||
|----------|------|---------|---------|
|
||||
| `gemini` | analysis | create-plan.md | 治理方案生成 |
|
||||
|
||||
## Execution (5-Phase)
|
||||
|
||||
### Phase 1: Task Discovery
|
||||
|
||||
```javascript
|
||||
const tasks = TaskList()
|
||||
const myTasks = tasks.filter(t =>
|
||||
t.subject.startsWith('TDPLAN-') &&
|
||||
t.owner === 'planner' &&
|
||||
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: Load Assessment Data
|
||||
|
||||
```javascript
|
||||
const sessionFolder = task.description.match(/session:\s*(.+)/)?.[1]?.trim() || '.'
|
||||
let sharedMemory = {}
|
||||
try { sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`)) } catch {}
|
||||
|
||||
const debtInventory = sharedMemory.debt_inventory || []
|
||||
|
||||
// 加载优先级矩阵
|
||||
let priorityMatrix = {}
|
||||
try {
|
||||
priorityMatrix = JSON.parse(Read(`${sessionFolder}/assessment/priority-matrix.json`))
|
||||
} catch {}
|
||||
|
||||
// 分组
|
||||
const quickWins = debtInventory.filter(i => i.priority_quadrant === 'quick-win')
|
||||
const strategic = debtInventory.filter(i => i.priority_quadrant === 'strategic')
|
||||
const backlog = debtInventory.filter(i => i.priority_quadrant === 'backlog')
|
||||
const deferred = debtInventory.filter(i => i.priority_quadrant === 'defer')
|
||||
```
|
||||
|
||||
### Phase 3: Create Remediation Plan
|
||||
|
||||
```javascript
|
||||
// Read commands/create-plan.md for full implementation
|
||||
Read("commands/create-plan.md")
|
||||
```
|
||||
|
||||
**核心策略**: 3 阶段治理方案
|
||||
|
||||
```javascript
|
||||
const plan = {
|
||||
phases: [
|
||||
{
|
||||
name: 'Quick Wins',
|
||||
description: '高影响低成本项,立即执行',
|
||||
items: quickWins,
|
||||
estimated_effort: quickWins.reduce((s, i) => s + i.cost_score, 0),
|
||||
actions: quickWins.map(i => ({
|
||||
debt_id: i.id,
|
||||
action: i.suggestion || `Fix ${i.description}`,
|
||||
file: i.file,
|
||||
type: determineActionType(i)
|
||||
}))
|
||||
},
|
||||
{
|
||||
name: 'Systematic',
|
||||
description: '高影响高成本项,需系统规划',
|
||||
items: strategic,
|
||||
estimated_effort: strategic.reduce((s, i) => s + i.cost_score, 0),
|
||||
actions: strategic.map(i => ({
|
||||
debt_id: i.id,
|
||||
action: i.suggestion || `Refactor ${i.description}`,
|
||||
file: i.file,
|
||||
type: determineActionType(i)
|
||||
}))
|
||||
},
|
||||
{
|
||||
name: 'Prevention',
|
||||
description: '预防机制建设,长期生效',
|
||||
items: [],
|
||||
estimated_effort: 0,
|
||||
actions: generatePreventionActions(debtInventory)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
function determineActionType(item) {
|
||||
const typeMap = {
|
||||
'code': 'refactor',
|
||||
'architecture': 'restructure',
|
||||
'testing': 'add-tests',
|
||||
'dependency': 'update-deps',
|
||||
'documentation': 'add-docs'
|
||||
}
|
||||
return typeMap[item.dimension] || 'refactor'
|
||||
}
|
||||
|
||||
function generatePreventionActions(inventory) {
|
||||
const actions = []
|
||||
const dimensions = [...new Set(inventory.map(i => i.dimension))]
|
||||
for (const dim of dimensions) {
|
||||
const count = inventory.filter(i => i.dimension === dim).length
|
||||
if (count >= 3) {
|
||||
actions.push({
|
||||
action: getPreventionAction(dim),
|
||||
type: 'prevention',
|
||||
dimension: dim
|
||||
})
|
||||
}
|
||||
}
|
||||
return actions
|
||||
}
|
||||
|
||||
function getPreventionAction(dimension) {
|
||||
const prevention = {
|
||||
'code': 'Add linting rules for complexity thresholds and code smell detection',
|
||||
'architecture': 'Introduce module boundary checks in CI pipeline',
|
||||
'testing': 'Set minimum coverage thresholds in CI and add pre-commit test hooks',
|
||||
'dependency': 'Configure automated dependency update bot (Renovate/Dependabot)',
|
||||
'documentation': 'Add JSDoc/docstring enforcement in linting rules'
|
||||
}
|
||||
return prevention[dimension] || 'Add automated checks for this category'
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 4: Validate Plan Feasibility
|
||||
|
||||
```javascript
|
||||
// 验证方案可行性
|
||||
const validation = {
|
||||
total_actions: plan.phases.reduce((s, p) => s + p.actions.length, 0),
|
||||
total_effort: plan.phases.reduce((s, p) => s + p.estimated_effort, 0),
|
||||
files_affected: [...new Set(plan.phases.flatMap(p => p.actions.map(a => a.file)).filter(Boolean))],
|
||||
has_quick_wins: quickWins.length > 0,
|
||||
has_prevention: plan.phases[2].actions.length > 0
|
||||
}
|
||||
|
||||
// 保存治理方案
|
||||
Bash(`mkdir -p "${sessionFolder}/plan"`)
|
||||
Write(`${sessionFolder}/plan/remediation-plan.md`, generatePlanMarkdown(plan, validation))
|
||||
Write(`${sessionFolder}/plan/remediation-plan.json`, JSON.stringify(plan, null, 2))
|
||||
|
||||
// 更新 shared memory
|
||||
sharedMemory.remediation_plan = {
|
||||
phases: plan.phases.map(p => ({ name: p.name, action_count: p.actions.length, effort: p.estimated_effort })),
|
||||
total_actions: validation.total_actions,
|
||||
files_affected: validation.files_affected.length
|
||||
}
|
||||
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
|
||||
```
|
||||
|
||||
### Phase 5: Report to Coordinator
|
||||
|
||||
```javascript
|
||||
const planSummary = plan.phases.map(p => `${p.name}: ${p.actions.length} actions`).join(', ')
|
||||
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: teamName,
|
||||
from: "planner",
|
||||
to: "coordinator",
|
||||
type: "plan_ready",
|
||||
summary: `[planner] 治理方案就绪: ${planSummary}`,
|
||||
ref: `${sessionFolder}/plan/remediation-plan.md`
|
||||
})
|
||||
|
||||
SendMessage({
|
||||
type: "message",
|
||||
recipient: "coordinator",
|
||||
content: `## [planner] Remediation Plan
|
||||
|
||||
**Task**: ${task.subject}
|
||||
**Total Actions**: ${validation.total_actions}
|
||||
**Files Affected**: ${validation.files_affected.length}
|
||||
|
||||
### Phase 1: Quick Wins (${quickWins.length} items)
|
||||
${quickWins.slice(0, 5).map(i => `- ${i.file} - ${i.description}`).join('\n')}
|
||||
|
||||
### Phase 2: Systematic (${strategic.length} items)
|
||||
${strategic.slice(0, 3).map(i => `- ${i.file} - ${i.description}`).join('\n')}
|
||||
|
||||
### Phase 3: Prevention (${plan.phases[2].actions.length} items)
|
||||
${plan.phases[2].actions.slice(0, 3).map(a => `- ${a.action}`).join('\n')}
|
||||
|
||||
### Plan Document
|
||||
${sessionFolder}/plan/remediation-plan.md`,
|
||||
summary: `[planner] TDPLAN complete: ${planSummary}`
|
||||
})
|
||||
|
||||
TaskUpdate({ taskId: task.id, status: 'completed' })
|
||||
|
||||
const nextTasks = TaskList().filter(t =>
|
||||
t.subject.startsWith('TDPLAN-') && t.owner === 'planner' &&
|
||||
t.status === 'pending' && t.blockedBy.length === 0
|
||||
)
|
||||
if (nextTasks.length > 0) { /* back to Phase 1 */ }
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| No TDPLAN-* tasks available | Idle, wait for coordinator |
|
||||
| Assessment data empty | Create minimal plan based on debt inventory |
|
||||
| No quick-wins found | Skip Phase 1, focus on systematic |
|
||||
| CLI analysis fails | Fall back to heuristic plan generation |
|
||||
| Too many items for single plan | Split into multiple phases with priorities |
|
||||
@@ -0,0 +1,198 @@
|
||||
# Command: scan-debt
|
||||
|
||||
> 多维度 CLI Fan-out 技术债务扫描。从代码质量、架构、测试、依赖、文档 5 个维度并行分析代码,发现技术债务。
|
||||
|
||||
## When to Use
|
||||
|
||||
- Phase 3 of Scanner
|
||||
- 需要对代码库进行多维度技术债务扫描
|
||||
- 复杂度为 Medium 或 High 时使用 CLI Fan-out
|
||||
|
||||
**Trigger conditions**:
|
||||
- TDSCAN-* 任务进入 Phase 3
|
||||
- 复杂度评估为 Medium/High
|
||||
- 需要深度分析超出 ACE 搜索能力
|
||||
|
||||
## Strategy
|
||||
|
||||
### Delegation Mode
|
||||
|
||||
**Mode**: CLI Fan-out
|
||||
**CLI Tool**: `gemini` (primary)
|
||||
**CLI Mode**: `analysis`
|
||||
**Parallel Dimensions**: 3-5(根据复杂度)
|
||||
|
||||
### Decision Logic
|
||||
|
||||
```javascript
|
||||
// 复杂度决定扫描策略
|
||||
if (complexity === 'Low') {
|
||||
// ACE 搜索 + Grep 内联分析(不使用 CLI)
|
||||
mode = 'inline'
|
||||
} else if (complexity === 'Medium') {
|
||||
// CLI Fan-out: 3 个核心维度
|
||||
mode = 'cli-fanout'
|
||||
activeDimensions = ['code', 'testing', 'dependency']
|
||||
} else {
|
||||
// CLI Fan-out: 所有 5 个维度
|
||||
mode = 'cli-fanout'
|
||||
activeDimensions = dimensions
|
||||
}
|
||||
```
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Context Preparation
|
||||
|
||||
```javascript
|
||||
// 确定扫描范围
|
||||
const projectRoot = Bash(`git rev-parse --show-toplevel 2>/dev/null || pwd`).trim()
|
||||
const scanScope = task.description.match(/scope:\s*(.+)/)?.[1] || '**/*'
|
||||
|
||||
// 获取变更文件用于聚焦扫描
|
||||
const changedFiles = Bash(`git diff --name-only HEAD~10 2>/dev/null || echo ""`)
|
||||
.split('\n').filter(Boolean)
|
||||
|
||||
// 构建文件上下文
|
||||
const fileContext = changedFiles.length > 0
|
||||
? changedFiles.map(f => `@${f}`).join(' ')
|
||||
: `@${scanScope}`
|
||||
```
|
||||
|
||||
### Step 2: Execute Strategy
|
||||
|
||||
```javascript
|
||||
if (mode === 'inline') {
|
||||
// 快速内联扫描
|
||||
const aceResults = mcp__ace-tool__search_context({
|
||||
project_root_path: projectRoot,
|
||||
query: "code smells, TODO/FIXME, deprecated APIs, complex functions, dead code, missing tests, circular imports"
|
||||
})
|
||||
// 解析 ACE 结果并分类到维度
|
||||
} else {
|
||||
// CLI Fan-out: 每个维度一个 CLI 调用
|
||||
const dimensionPrompts = {
|
||||
'code': `PURPOSE: Identify code quality debt - complexity, duplication, code smells
|
||||
TASK: • Find functions with cyclomatic complexity > 10 • Detect code duplication (>20 lines) • Identify code smells (God class, long method, feature envy) • Find TODO/FIXME/HACK comments • Detect dead code and unused exports
|
||||
MODE: analysis
|
||||
CONTEXT: ${fileContext}
|
||||
EXPECTED: List of findings with severity (critical/high/medium/low), file:line, description, estimated fix effort (small/medium/large)
|
||||
CONSTRAINTS: Focus on actionable items, skip generated code`,
|
||||
|
||||
'architecture': `PURPOSE: Identify architecture debt - coupling, circular dependencies, layering violations
|
||||
TASK: • Detect circular dependencies between modules • Find tight coupling between components • Identify layering violations (e.g., UI importing DB) • Check for God modules with too many responsibilities • Find missing abstraction layers
|
||||
MODE: analysis
|
||||
CONTEXT: ${fileContext}
|
||||
EXPECTED: Architecture debt findings with severity, affected modules, dependency graph issues
|
||||
CONSTRAINTS: Focus on structural issues, not style`,
|
||||
|
||||
'testing': `PURPOSE: Identify testing debt - coverage gaps, test quality, missing test types
|
||||
TASK: • Find modules without any test files • Identify complex logic without test coverage • Check for test anti-patterns (flaky tests, hardcoded values) • Find missing edge case tests • Detect test files that import from test utilities incorrectly
|
||||
MODE: analysis
|
||||
CONTEXT: ${fileContext}
|
||||
EXPECTED: Testing debt findings with severity, affected files, missing test type (unit/integration/e2e)
|
||||
CONSTRAINTS: Focus on high-risk untested code paths`,
|
||||
|
||||
'dependency': `PURPOSE: Identify dependency debt - outdated packages, vulnerabilities, unnecessary deps
|
||||
TASK: • Find outdated major-version dependencies • Identify known vulnerability packages • Detect unused dependencies • Find duplicate functionality from different packages • Check for pinned vs range versions
|
||||
MODE: analysis
|
||||
CONTEXT: @package.json @package-lock.json @requirements.txt @go.mod @pom.xml
|
||||
EXPECTED: Dependency debt with severity, package name, current vs latest version, CVE references
|
||||
CONSTRAINTS: Focus on security and compatibility risks`,
|
||||
|
||||
'documentation': `PURPOSE: Identify documentation debt - missing docs, stale docs, undocumented APIs
|
||||
TASK: • Find public APIs without JSDoc/docstrings • Identify README files that are outdated • Check for missing architecture documentation • Find configuration options without documentation • Detect stale comments that don't match code
|
||||
MODE: analysis
|
||||
CONTEXT: ${fileContext}
|
||||
EXPECTED: Documentation debt with severity, file:line, type (missing/stale/incomplete)
|
||||
CONSTRAINTS: Focus on public interfaces and critical paths`
|
||||
}
|
||||
|
||||
for (const dimension of activeDimensions) {
|
||||
const prompt = dimensionPrompts[dimension]
|
||||
if (!prompt) continue
|
||||
|
||||
Bash(`ccw cli -p "${prompt}" --tool gemini --mode analysis --rule analysis-analyze-code-patterns`, {
|
||||
run_in_background: true
|
||||
})
|
||||
}
|
||||
|
||||
// 等待所有 CLI 完成(hook 回调通知)
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Result Processing
|
||||
|
||||
```javascript
|
||||
// 聚合所有维度的结果
|
||||
const allFindings = []
|
||||
|
||||
// 从 CLI 输出解析结果
|
||||
for (const dimension of activeDimensions) {
|
||||
const findings = parseCliOutput(cliResults[dimension])
|
||||
for (const finding of findings) {
|
||||
finding.dimension = dimension
|
||||
allFindings.push(finding)
|
||||
}
|
||||
}
|
||||
|
||||
// 去重:相同 file:line 的发现合并
|
||||
function deduplicateFindings(findings) {
|
||||
const seen = new Set()
|
||||
const unique = []
|
||||
for (const f of findings) {
|
||||
const key = `${f.file}:${f.line}:${f.dimension}`
|
||||
if (!seen.has(key)) {
|
||||
seen.add(key)
|
||||
unique.push(f)
|
||||
}
|
||||
}
|
||||
return unique
|
||||
}
|
||||
|
||||
const deduped = deduplicateFindings(allFindings)
|
||||
|
||||
// 按严重性排序
|
||||
deduped.sort((a, b) => {
|
||||
const order = { critical: 0, high: 1, medium: 2, low: 3 }
|
||||
return (order[a.severity] || 3) - (order[b.severity] || 3)
|
||||
})
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
## Debt Scan Results
|
||||
|
||||
### Dimensions Scanned: [list]
|
||||
### Complexity: [Low|Medium|High]
|
||||
|
||||
### Findings by Dimension
|
||||
#### Code Quality ([count])
|
||||
- [file:line] [severity] - [description]
|
||||
|
||||
#### Architecture ([count])
|
||||
- [module] [severity] - [description]
|
||||
|
||||
#### Testing ([count])
|
||||
- [file:line] [severity] - [description]
|
||||
|
||||
#### Dependency ([count])
|
||||
- [package] [severity] - [description]
|
||||
|
||||
#### Documentation ([count])
|
||||
- [file:line] [severity] - [description]
|
||||
|
||||
### Total Debt Items: [count]
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| CLI tool unavailable | Fall back to ACE search + Grep inline analysis |
|
||||
| CLI returns empty for a dimension | Note incomplete dimension, continue others |
|
||||
| Too many findings (>100) | Prioritize critical/high, summarize medium/low |
|
||||
| Timeout on CLI call | Use partial results, note incomplete dimensions |
|
||||
| Agent/CLI failure | Retry once, then fallback to inline execution |
|
||||
| Timeout (>5 min per dimension) | Report partial results, notify scanner |
|
||||
258
.claude/skills/team-tech-debt/roles/scanner/role.md
Normal file
258
.claude/skills/team-tech-debt/roles/scanner/role.md
Normal file
@@ -0,0 +1,258 @@
|
||||
# Role: scanner
|
||||
|
||||
多维度技术债务扫描器。扫描代码库的 5 个维度:代码质量、架构、测试、依赖、文档,生成结构化债务清单。通过 CLI Fan-out 并行分析,产出 debt-inventory.json。
|
||||
|
||||
## Role Identity
|
||||
|
||||
- **Name**: `scanner`
|
||||
- **Task Prefix**: `TDSCAN-*`
|
||||
- **Responsibility**: Orchestration(多维度扫描编排)
|
||||
- **Communication**: SendMessage to coordinator only
|
||||
- **Output Tag**: `[scanner]`
|
||||
|
||||
## Role Boundaries
|
||||
|
||||
### MUST
|
||||
|
||||
- 仅处理 `TDSCAN-*` 前缀的任务
|
||||
- 所有输出必须带 `[scanner]` 标识
|
||||
- 仅通过 SendMessage 与 coordinator 通信
|
||||
- 严格在债务扫描职责范围内工作
|
||||
|
||||
### MUST NOT
|
||||
|
||||
- 编写或修改代码
|
||||
- 执行修复操作
|
||||
- 为其他角色创建任务
|
||||
- 直接与其他 worker 通信
|
||||
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `scan_complete` | scanner → coordinator | 扫描完成 | 包含债务清单摘要 |
|
||||
| `debt_items_found` | scanner → coordinator | 发现高优先级债务 | 需要关注的关键发现 |
|
||||
| `error` | scanner → coordinator | 扫描失败 | 阻塞性错误 |
|
||||
|
||||
## Message Bus
|
||||
|
||||
每次 SendMessage 前,先调用 `mcp__ccw-tools__team_msg` 记录:
|
||||
|
||||
```javascript
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: teamName,
|
||||
from: "scanner",
|
||||
to: "coordinator",
|
||||
type: "scan_complete",
|
||||
summary: "[scanner] 多维度扫描完成: 42 项债务"
|
||||
})
|
||||
```
|
||||
|
||||
### CLI 回退
|
||||
|
||||
若 `mcp__ccw-tools__team_msg` 不可用,使用 Bash 写入日志文件:
|
||||
|
||||
```javascript
|
||||
Bash(`echo '${JSON.stringify({ from: "scanner", to: "coordinator", type: "scan_complete", summary: msg, ts: new Date().toISOString() })}' >> "${sessionFolder}/message-log.jsonl"`)
|
||||
```
|
||||
|
||||
## Toolbox
|
||||
|
||||
### Available Commands
|
||||
|
||||
| Command | File | Phase | Description |
|
||||
|---------|------|-------|-------------|
|
||||
| `scan-debt` | [commands/scan-debt.md](commands/scan-debt.md) | Phase 3 | 多维度 CLI Fan-out 扫描 |
|
||||
|
||||
### Subagent Capabilities
|
||||
|
||||
| Agent Type | Used By | Purpose |
|
||||
|------------|---------|---------|
|
||||
| `cli-explore-agent` | scan-debt.md | 代码库结构探索 |
|
||||
|
||||
### CLI Capabilities
|
||||
|
||||
| CLI Tool | Mode | Used By | Purpose |
|
||||
|----------|------|---------|---------|
|
||||
| `gemini` | analysis | scan-debt.md | 多维度代码分析 |
|
||||
|
||||
## Execution (5-Phase)
|
||||
|
||||
### Phase 1: Task Discovery
|
||||
|
||||
```javascript
|
||||
const tasks = TaskList()
|
||||
const myTasks = tasks.filter(t =>
|
||||
t.subject.startsWith('TDSCAN-') &&
|
||||
t.owner === 'scanner' &&
|
||||
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
|
||||
|
||||
```javascript
|
||||
// 确定扫描范围
|
||||
const scanScope = task.description.match(/scope:\s*(.+)/)?.[1] || '**/*'
|
||||
const sessionFolder = task.description.match(/session:\s*(.+)/)?.[1]?.trim() || '.'
|
||||
|
||||
// 读取 shared memory
|
||||
let sharedMemory = {}
|
||||
try { sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`)) } catch {}
|
||||
|
||||
// 检测项目类型和框架
|
||||
const projectRoot = Bash(`git rev-parse --show-toplevel 2>/dev/null || pwd`).trim()
|
||||
const hasPackageJson = Bash(`test -f package.json && echo "yes" || echo "no"`).trim() === 'yes'
|
||||
const hasPyProject = Bash(`test -f pyproject.toml -o -f requirements.txt && echo "yes" || echo "no"`).trim() === 'yes'
|
||||
const hasGoMod = Bash(`test -f go.mod && echo "yes" || echo "no"`).trim() === 'yes'
|
||||
|
||||
// 5 个扫描维度
|
||||
const dimensions = ["code", "architecture", "testing", "dependency", "documentation"]
|
||||
|
||||
// 评估复杂度
|
||||
function assessComplexity(desc) {
|
||||
let score = 0
|
||||
if (/全项目|全量|comprehensive|full/.test(desc)) score += 3
|
||||
if (/architecture|架构/.test(desc)) score += 1
|
||||
if (/multiple|across|cross|多模块/.test(desc)) score += 2
|
||||
return score >= 4 ? 'High' : score >= 2 ? 'Medium' : 'Low'
|
||||
}
|
||||
const complexity = assessComplexity(task.description)
|
||||
```
|
||||
|
||||
### Phase 3: Multi-Dimension Scan
|
||||
|
||||
```javascript
|
||||
// Read commands/scan-debt.md for full CLI Fan-out implementation
|
||||
Read("commands/scan-debt.md")
|
||||
```
|
||||
|
||||
**核心策略**: 按维度并行执行 CLI 分析
|
||||
|
||||
```javascript
|
||||
if (complexity === 'Low') {
|
||||
// 直接使用 ACE 搜索 + Grep 进行快速扫描
|
||||
const aceResults = mcp__ace-tool__search_context({
|
||||
project_root_path: projectRoot,
|
||||
query: "code smells, TODO/FIXME, deprecated APIs, complex functions, missing tests"
|
||||
})
|
||||
} else {
|
||||
// CLI Fan-out: 每个维度一个 CLI 调用
|
||||
for (const dimension of dimensions) {
|
||||
Bash(`ccw cli -p "..." --tool gemini --mode analysis`, { run_in_background: true })
|
||||
}
|
||||
// 等待所有 CLI 完成
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 4: Aggregate into Debt Inventory
|
||||
|
||||
```javascript
|
||||
// 聚合所有维度的发现
|
||||
const debtInventory = []
|
||||
|
||||
// 为每个发现项创建标准化条目
|
||||
for (const item of allFindings) {
|
||||
debtInventory.push({
|
||||
id: `TD-${String(debtInventory.length + 1).padStart(3, '0')}`,
|
||||
dimension: item.dimension,
|
||||
severity: item.severity,
|
||||
file: item.file,
|
||||
line: item.line,
|
||||
description: item.description,
|
||||
suggestion: item.suggestion,
|
||||
estimated_effort: item.effort || 'unknown'
|
||||
})
|
||||
}
|
||||
|
||||
// 更新 shared memory
|
||||
sharedMemory.debt_inventory = debtInventory
|
||||
sharedMemory.debt_score_before = debtInventory.length
|
||||
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
|
||||
|
||||
// 保存债务清单
|
||||
Write(`${sessionFolder}/scan/debt-inventory.json`, JSON.stringify({
|
||||
scan_date: new Date().toISOString(),
|
||||
dimensions: dimensions,
|
||||
total_items: debtInventory.length,
|
||||
by_dimension: dimensions.reduce((acc, d) => {
|
||||
acc[d] = debtInventory.filter(i => i.dimension === d).length
|
||||
return acc
|
||||
}, {}),
|
||||
by_severity: {
|
||||
critical: debtInventory.filter(i => i.severity === 'critical').length,
|
||||
high: debtInventory.filter(i => i.severity === 'high').length,
|
||||
medium: debtInventory.filter(i => i.severity === 'medium').length,
|
||||
low: debtInventory.filter(i => i.severity === 'low').length
|
||||
},
|
||||
items: debtInventory
|
||||
}, null, 2))
|
||||
```
|
||||
|
||||
### Phase 5: Report to Coordinator
|
||||
|
||||
```javascript
|
||||
const resultSummary = `发现 ${debtInventory.length} 项技术债务(${dimensions.map(d => `${d}: ${debtInventory.filter(i => i.dimension === d).length}`).join(', ')})`
|
||||
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: teamName,
|
||||
from: "scanner",
|
||||
to: "coordinator",
|
||||
type: debtInventory.length > 0 ? "debt_items_found" : "scan_complete",
|
||||
summary: `[scanner] ${resultSummary}`,
|
||||
ref: `${sessionFolder}/scan/debt-inventory.json`
|
||||
})
|
||||
|
||||
SendMessage({
|
||||
type: "message",
|
||||
recipient: "coordinator",
|
||||
content: `## [scanner] Debt Scan Results
|
||||
|
||||
**Task**: ${task.subject}
|
||||
**Dimensions**: ${dimensions.join(', ')}
|
||||
**Status**: ${debtInventory.length > 0 ? 'Debt Found' : 'Clean'}
|
||||
|
||||
### Summary
|
||||
${resultSummary}
|
||||
|
||||
### Top Debt Items
|
||||
${debtInventory.filter(i => i.severity === 'critical' || i.severity === 'high').slice(0, 5).map(i => `- **[${i.severity}]** [${i.dimension}] ${i.file}:${i.line} - ${i.description}`).join('\n')}
|
||||
|
||||
### Debt Inventory
|
||||
${sessionFolder}/scan/debt-inventory.json`,
|
||||
summary: `[scanner] TDSCAN complete: ${resultSummary}`
|
||||
})
|
||||
|
||||
TaskUpdate({ taskId: task.id, status: 'completed' })
|
||||
|
||||
// Check for next task
|
||||
const nextTasks = TaskList().filter(t =>
|
||||
t.subject.startsWith('TDSCAN-') &&
|
||||
t.owner === 'scanner' &&
|
||||
t.status === 'pending' &&
|
||||
t.blockedBy.length === 0
|
||||
)
|
||||
|
||||
if (nextTasks.length > 0) {
|
||||
// Continue with next task → back to Phase 1
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| No TDSCAN-* tasks available | Idle, wait for coordinator assignment |
|
||||
| CLI tool unavailable | Fall back to ACE search + Grep inline analysis |
|
||||
| Scan scope too broad | Narrow to src/ directory, report partial results |
|
||||
| All dimensions return empty | Report clean scan, notify coordinator |
|
||||
| CLI timeout | Use partial results, note incomplete dimensions |
|
||||
| Critical issue beyond scope | SendMessage debt_items_found to coordinator |
|
||||
199
.claude/skills/team-tech-debt/roles/validator/commands/verify.md
Normal file
199
.claude/skills/team-tech-debt/roles/validator/commands/verify.md
Normal file
@@ -0,0 +1,199 @@
|
||||
# Command: verify
|
||||
|
||||
> 回归测试与质量验证。运行测试套件、类型检查、lint、可选 CLI 质量分析。对比 debt_score_before vs debt_score_after 评估改善程度。
|
||||
|
||||
## When to Use
|
||||
|
||||
- Phase 3 of Validator
|
||||
- 修复操作已完成,需要验证结果
|
||||
- Fix-Verify 循环中的验证阶段
|
||||
|
||||
**Trigger conditions**:
|
||||
- TDVAL-* 任务进入 Phase 3
|
||||
- 修复日志可用(fix-log.json)
|
||||
- 需要对比 before/after 指标
|
||||
|
||||
## Strategy
|
||||
|
||||
### Delegation Mode
|
||||
|
||||
**Mode**: Sequential Checks + Optional CLI Analysis
|
||||
**CLI Tool**: `gemini` (for quality comparison)
|
||||
**CLI Mode**: `analysis`
|
||||
|
||||
### Decision Logic
|
||||
|
||||
```javascript
|
||||
// 验证策略选择
|
||||
const checks = ['test_suite', 'type_check', 'lint_check']
|
||||
|
||||
// 可选:CLI 质量分析(仅当修改文件较多时)
|
||||
if (modifiedFiles.length > 5) {
|
||||
checks.push('cli_quality_analysis')
|
||||
}
|
||||
|
||||
// Fix-Verify 循环中的验证:聚焦于回归文件
|
||||
const isFixVerify = task.description.includes('fix-verify')
|
||||
if (isFixVerify) {
|
||||
// 仅验证上次回归的文件
|
||||
targetScope = 'regression_files_only'
|
||||
}
|
||||
```
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Context Preparation
|
||||
|
||||
```javascript
|
||||
// 获取修改文件列表
|
||||
const modifiedFiles = fixLog.files_modified || []
|
||||
|
||||
// 获取原始债务分数
|
||||
const debtScoreBefore = sharedMemory.debt_score_before || 0
|
||||
|
||||
// 检测可用的验证工具
|
||||
const hasNpm = Bash(`which npm 2>/dev/null && echo "yes" || echo "no"`).trim() === 'yes'
|
||||
const hasTsc = Bash(`which npx 2>/dev/null && npx tsc --version 2>/dev/null && echo "yes" || echo "no"`).includes('yes')
|
||||
const hasEslint = Bash(`npx eslint --version 2>/dev/null && echo "yes" || echo "no"`).includes('yes')
|
||||
const hasPytest = Bash(`which pytest 2>/dev/null && echo "yes" || echo "no"`).trim() === 'yes'
|
||||
```
|
||||
|
||||
### Step 2: Execute Strategy
|
||||
|
||||
```javascript
|
||||
// === Check 1: Test Suite ===
|
||||
let testOutput = ''
|
||||
let testsPassed = true
|
||||
let testRegressions = 0
|
||||
|
||||
if (hasNpm) {
|
||||
testOutput = Bash(`npm test 2>&1 || true`)
|
||||
} else if (hasPytest) {
|
||||
testOutput = Bash(`python -m pytest 2>&1 || true`)
|
||||
} else {
|
||||
testOutput = 'no-test-runner'
|
||||
}
|
||||
|
||||
if (testOutput !== 'no-test-runner') {
|
||||
testsPassed = !/FAIL|error|failed/i.test(testOutput)
|
||||
testRegressions = testsPassed ? 0 : (testOutput.match(/(\d+) failed/)?.[1] || 1) * 1
|
||||
}
|
||||
|
||||
// === Check 2: Type Checking ===
|
||||
let typeErrors = 0
|
||||
if (hasTsc) {
|
||||
const tscOutput = Bash(`npx tsc --noEmit 2>&1 || true`)
|
||||
typeErrors = (tscOutput.match(/error TS/g) || []).length
|
||||
}
|
||||
|
||||
// === Check 3: Linting ===
|
||||
let lintErrors = 0
|
||||
if (hasEslint && modifiedFiles.length > 0) {
|
||||
const lintOutput = Bash(`npx eslint --no-error-on-unmatched-pattern ${modifiedFiles.join(' ')} 2>&1 || true`)
|
||||
lintErrors = (lintOutput.match(/(\d+) error/)?.[0]?.match(/\d+/)?.[0] || 0) * 1
|
||||
}
|
||||
|
||||
// === Check 4: Optional CLI Quality Analysis ===
|
||||
let qualityImprovement = 0
|
||||
if (checks.includes('cli_quality_analysis')) {
|
||||
const prompt = `PURPOSE: Compare code quality before and after tech debt cleanup to measure improvement
|
||||
TASK: • Analyze the modified files for quality metrics • Compare complexity, duplication, naming quality • Assess if the changes actually reduced debt • Identify any new issues introduced
|
||||
MODE: analysis
|
||||
CONTEXT: ${modifiedFiles.map(f => `@${f}`).join(' ')}
|
||||
EXPECTED: Quality comparison with: metrics_before, metrics_after, improvement_score (0-100), new_issues_found
|
||||
CONSTRAINTS: Focus on the specific changes, not overall project quality`
|
||||
|
||||
Bash(`ccw cli -p "${prompt}" --tool gemini --mode analysis --rule analysis-review-code-quality`, {
|
||||
run_in_background: true
|
||||
})
|
||||
// 等待 CLI 完成,解析质量改善分数
|
||||
}
|
||||
|
||||
// === 计算债务分数 ===
|
||||
// 已修复的项不计入 after 分数
|
||||
const fixedDebtIds = new Set(
|
||||
(sharedMemory.fix_results?.files_modified || [])
|
||||
.flatMap(f => debtInventory.filter(i => i.file === f).map(i => i.id))
|
||||
)
|
||||
const debtScoreAfter = debtInventory.filter(i => !fixedDebtIds.has(i.id)).length
|
||||
```
|
||||
|
||||
### Step 3: Result Processing
|
||||
|
||||
```javascript
|
||||
const totalRegressions = testRegressions + typeErrors + lintErrors
|
||||
const passed = totalRegressions === 0
|
||||
|
||||
// 如果有少量回归,尝试通过 code-developer 修复
|
||||
if (totalRegressions > 0 && totalRegressions <= 3) {
|
||||
const regressionDetails = []
|
||||
if (testRegressions > 0) regressionDetails.push(`${testRegressions} test failures`)
|
||||
if (typeErrors > 0) regressionDetails.push(`${typeErrors} type errors`)
|
||||
if (lintErrors > 0) regressionDetails.push(`${lintErrors} lint errors`)
|
||||
|
||||
Task({
|
||||
subagent_type: "code-developer",
|
||||
run_in_background: false,
|
||||
description: `Fix ${totalRegressions} regressions from debt cleanup`,
|
||||
prompt: `## Goal
|
||||
Fix regressions introduced by tech debt cleanup.
|
||||
|
||||
## Regressions
|
||||
${regressionDetails.join('\n')}
|
||||
|
||||
## Modified Files
|
||||
${modifiedFiles.map(f => `- ${f}`).join('\n')}
|
||||
|
||||
## Test Output (if failed)
|
||||
${testOutput.split('\n').filter(l => /FAIL|Error|error/i.test(l)).slice(0, 20).join('\n')}
|
||||
|
||||
## Constraints
|
||||
- Fix ONLY the regressions, do not undo the debt fixes
|
||||
- Preserve the debt cleanup changes
|
||||
- Do NOT skip tests or add suppressions`
|
||||
})
|
||||
|
||||
// Re-run checks after fix attempt
|
||||
// ... (simplified: re-check test suite)
|
||||
}
|
||||
|
||||
// 生成最终验证结果
|
||||
const validationReport = {
|
||||
passed,
|
||||
regressions: totalRegressions,
|
||||
debt_score_before: debtScoreBefore,
|
||||
debt_score_after: debtScoreAfter,
|
||||
improvement_percentage: debtScoreBefore > 0
|
||||
? Math.round(((debtScoreBefore - debtScoreAfter) / debtScoreBefore) * 100)
|
||||
: 0
|
||||
}
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
## Validation Results
|
||||
|
||||
### Status: [PASS|FAIL]
|
||||
### Regressions: [count]
|
||||
- Test Suite: [PASS|FAIL] ([n] regressions)
|
||||
- Type Check: [PASS|FAIL] ([n] errors)
|
||||
- Lint: [PASS|FAIL] ([n] errors)
|
||||
- Quality: [IMPROVED|NO_CHANGE]
|
||||
|
||||
### Debt Score
|
||||
- Before: [score]
|
||||
- After: [score]
|
||||
- Improvement: [%]%
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| No test runner available | Skip test check, rely on type+lint |
|
||||
| tsc not available | Skip type check, rely on test+lint |
|
||||
| eslint not available | Skip lint check, rely on test+type |
|
||||
| All checks unavailable | Report minimal validation, warn coordinator |
|
||||
| Fix attempt introduces new regressions | Revert fix, report original regressions |
|
||||
| CLI quality analysis times out | Skip quality analysis, use debt score comparison only |
|
||||
263
.claude/skills/team-tech-debt/roles/validator/role.md
Normal file
263
.claude/skills/team-tech-debt/roles/validator/role.md
Normal file
@@ -0,0 +1,263 @@
|
||||
# Role: validator
|
||||
|
||||
技术债务清理结果验证者。运行测试套件验证无回归、执行类型检查和 lint、通过 CLI 分析代码质量改善程度。对比 before/after 债务分数,生成 validation-report.json。
|
||||
|
||||
## Role Identity
|
||||
|
||||
- **Name**: `validator`
|
||||
- **Task Prefix**: `TDVAL-*`
|
||||
- **Responsibility**: Validation(清理结果验证)
|
||||
- **Communication**: SendMessage to coordinator only
|
||||
- **Output Tag**: `[validator]`
|
||||
|
||||
## Role Boundaries
|
||||
|
||||
### MUST
|
||||
|
||||
- 仅处理 `TDVAL-*` 前缀的任务
|
||||
- 所有输出必须带 `[validator]` 标识
|
||||
- 运行完整验证流程(测试、类型检查、lint、质量分析)
|
||||
- 如发现回归,报告 regression_found
|
||||
|
||||
### MUST NOT
|
||||
|
||||
- 直接修复代码(仅在小修复时通过 code-developer 尝试)
|
||||
- 为其他角色创建任务
|
||||
- 直接与其他 worker 通信
|
||||
- 跳过任何验证步骤
|
||||
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `validation_complete` | validator → coordinator | 验证通过 | 包含 before/after 指标 |
|
||||
| `regression_found` | validator → coordinator | 发现回归 | 触发 Fix-Verify 循环 |
|
||||
| `error` | validator → coordinator | 验证环境错误 | 阻塞性错误 |
|
||||
|
||||
## Message Bus
|
||||
|
||||
每次 SendMessage 前,先调用 `mcp__ccw-tools__team_msg` 记录:
|
||||
|
||||
```javascript
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: teamName,
|
||||
from: "validator",
|
||||
to: "coordinator",
|
||||
type: "validation_complete",
|
||||
summary: "[validator] 验证通过: 0 regressions, debt score 42 → 18"
|
||||
})
|
||||
```
|
||||
|
||||
### CLI 回退
|
||||
|
||||
若 `mcp__ccw-tools__team_msg` 不可用,使用 Bash 写入日志文件:
|
||||
|
||||
```javascript
|
||||
Bash(`echo '${JSON.stringify({ from: "validator", to: "coordinator", type: "validation_complete", summary: msg, ts: new Date().toISOString() })}' >> "${sessionFolder}/message-log.jsonl"`)
|
||||
```
|
||||
|
||||
## Toolbox
|
||||
|
||||
### Available Commands
|
||||
|
||||
| Command | File | Phase | Description |
|
||||
|---------|------|-------|-------------|
|
||||
| `verify` | [commands/verify.md](commands/verify.md) | Phase 3 | 回归测试与质量验证 |
|
||||
|
||||
### Subagent Capabilities
|
||||
|
||||
| Agent Type | Used By | Purpose |
|
||||
|------------|---------|---------|
|
||||
| `code-developer` | verify.md | 小修复尝试(验证失败时) |
|
||||
|
||||
### CLI Capabilities
|
||||
|
||||
| CLI Tool | Mode | Used By | Purpose |
|
||||
|----------|------|---------|---------|
|
||||
| `gemini` | analysis | verify.md | 代码质量改善分析 |
|
||||
|
||||
## Execution (5-Phase)
|
||||
|
||||
### Phase 1: Task Discovery
|
||||
|
||||
```javascript
|
||||
const tasks = TaskList()
|
||||
const myTasks = tasks.filter(t =>
|
||||
t.subject.startsWith('TDVAL-') &&
|
||||
t.owner === 'validator' &&
|
||||
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: Load Context
|
||||
|
||||
```javascript
|
||||
const sessionFolder = task.description.match(/session:\s*(.+)/)?.[1]?.trim() || '.'
|
||||
let sharedMemory = {}
|
||||
try { sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`)) } catch {}
|
||||
|
||||
const debtInventory = sharedMemory.debt_inventory || []
|
||||
const fixResults = sharedMemory.fix_results || {}
|
||||
const debtScoreBefore = sharedMemory.debt_score_before || debtInventory.length
|
||||
|
||||
// 加载修复日志
|
||||
let fixLog = {}
|
||||
try { fixLog = JSON.parse(Read(`${sessionFolder}/fixes/fix-log.json`)) } catch {}
|
||||
|
||||
const modifiedFiles = fixLog.files_modified || []
|
||||
```
|
||||
|
||||
### Phase 3: Run Validation Checks
|
||||
|
||||
```javascript
|
||||
// Read commands/verify.md for full implementation
|
||||
Read("commands/verify.md")
|
||||
```
|
||||
|
||||
**核心策略**: 4 层验证
|
||||
|
||||
```javascript
|
||||
const validationResults = {
|
||||
test_suite: { status: 'pending', regressions: 0 },
|
||||
type_check: { status: 'pending', errors: 0 },
|
||||
lint_check: { status: 'pending', errors: 0 },
|
||||
quality_analysis: { status: 'pending', improvement: 0 }
|
||||
}
|
||||
|
||||
// 1. 测试套件
|
||||
const testResult = Bash(`npm test 2>&1 || npx vitest run 2>&1 || python -m pytest 2>&1 || echo "no-tests"`)
|
||||
const testsPassed = !/FAIL|error|failed/i.test(testResult) || /no-tests/.test(testResult)
|
||||
validationResults.test_suite = {
|
||||
status: testsPassed ? 'PASS' : 'FAIL',
|
||||
regressions: testsPassed ? 0 : (testResult.match(/(\d+) failed/)?.[1] || 1) * 1
|
||||
}
|
||||
|
||||
// 2. 类型检查
|
||||
const typeResult = Bash(`npx tsc --noEmit 2>&1 || echo "skip"`)
|
||||
const typeErrors = (typeResult.match(/error TS/g) || []).length
|
||||
validationResults.type_check = {
|
||||
status: typeErrors === 0 || /skip/.test(typeResult) ? 'PASS' : 'FAIL',
|
||||
errors: typeErrors
|
||||
}
|
||||
|
||||
// 3. Lint 检查
|
||||
const lintResult = Bash(`npx eslint --no-error-on-unmatched-pattern ${modifiedFiles.join(' ')} 2>&1 || echo "skip"`)
|
||||
const lintErrors = (lintResult.match(/\d+ error/)?.[0]?.match(/\d+/)?.[0] || 0) * 1
|
||||
validationResults.lint_check = {
|
||||
status: lintErrors === 0 || /skip/.test(lintResult) ? 'PASS' : 'FAIL',
|
||||
errors: lintErrors
|
||||
}
|
||||
|
||||
// 4. 质量分析(可选 CLI)
|
||||
// 通过对比债务分数评估改善
|
||||
const debtScoreAfter = debtInventory.filter(i =>
|
||||
!fixResults.files_modified?.includes(i.file)
|
||||
).length
|
||||
validationResults.quality_analysis = {
|
||||
status: debtScoreAfter < debtScoreBefore ? 'IMPROVED' : 'NO_CHANGE',
|
||||
debt_score_before: debtScoreBefore,
|
||||
debt_score_after: debtScoreAfter,
|
||||
improvement: debtScoreBefore - debtScoreAfter
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 4: Compare Before/After & Generate Report
|
||||
|
||||
```javascript
|
||||
const totalRegressions = validationResults.test_suite.regressions +
|
||||
validationResults.type_check.errors + validationResults.lint_check.errors
|
||||
const passed = totalRegressions === 0
|
||||
|
||||
const report = {
|
||||
validation_date: new Date().toISOString(),
|
||||
passed,
|
||||
regressions: totalRegressions,
|
||||
checks: validationResults,
|
||||
debt_score_before: debtScoreBefore,
|
||||
debt_score_after: validationResults.quality_analysis.debt_score_after,
|
||||
improvement_percentage: debtScoreBefore > 0
|
||||
? Math.round(((debtScoreBefore - validationResults.quality_analysis.debt_score_after) / debtScoreBefore) * 100)
|
||||
: 0
|
||||
}
|
||||
|
||||
// 保存验证报告
|
||||
Bash(`mkdir -p "${sessionFolder}/validation"`)
|
||||
Write(`${sessionFolder}/validation/validation-report.json`, JSON.stringify(report, null, 2))
|
||||
|
||||
// 更新 shared memory
|
||||
sharedMemory.validation_results = report
|
||||
sharedMemory.debt_score_after = report.debt_score_after
|
||||
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
|
||||
```
|
||||
|
||||
### Phase 5: Report to Coordinator
|
||||
|
||||
```javascript
|
||||
const msgType = passed ? 'validation_complete' : 'regression_found'
|
||||
const statusMsg = passed
|
||||
? `验证通过: 0 regressions, debt ${debtScoreBefore} → ${report.debt_score_after} (${report.improvement_percentage}% 改善)`
|
||||
: `发现 ${totalRegressions} 个回归 (tests: ${validationResults.test_suite.regressions}, types: ${validationResults.type_check.errors}, lint: ${validationResults.lint_check.errors})`
|
||||
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log",
|
||||
team: teamName,
|
||||
from: "validator",
|
||||
to: "coordinator",
|
||||
type: msgType,
|
||||
summary: `[validator] ${statusMsg}`,
|
||||
ref: `${sessionFolder}/validation/validation-report.json`,
|
||||
data: { passed, regressions: totalRegressions }
|
||||
})
|
||||
|
||||
SendMessage({
|
||||
type: "message",
|
||||
recipient: "coordinator",
|
||||
content: `## [validator] Validation Results
|
||||
|
||||
**Task**: ${task.subject}
|
||||
**Status**: ${passed ? 'PASS' : 'FAIL - Regressions Found'}
|
||||
|
||||
### Check Results
|
||||
| Check | Status | Details |
|
||||
|-------|--------|---------|
|
||||
| Test Suite | ${validationResults.test_suite.status} | ${validationResults.test_suite.regressions} regressions |
|
||||
| Type Check | ${validationResults.type_check.status} | ${validationResults.type_check.errors} errors |
|
||||
| Lint | ${validationResults.lint_check.status} | ${validationResults.lint_check.errors} errors |
|
||||
| Quality | ${validationResults.quality_analysis.status} | ${report.improvement_percentage}% improvement |
|
||||
|
||||
### Debt Score
|
||||
- Before: ${debtScoreBefore}
|
||||
- After: ${report.debt_score_after}
|
||||
- Improvement: ${report.improvement_percentage}%
|
||||
|
||||
### Validation Report
|
||||
${sessionFolder}/validation/validation-report.json`,
|
||||
summary: `[validator] TDVAL complete: ${statusMsg}`
|
||||
})
|
||||
|
||||
TaskUpdate({ taskId: task.id, status: 'completed' })
|
||||
|
||||
const nextTasks = TaskList().filter(t =>
|
||||
t.subject.startsWith('TDVAL-') && t.owner === 'validator' &&
|
||||
t.status === 'pending' && t.blockedBy.length === 0
|
||||
)
|
||||
if (nextTasks.length > 0) { /* back to Phase 1 */ }
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| No TDVAL-* tasks available | Idle, wait for coordinator |
|
||||
| Test environment broken | Report error, suggest manual fix |
|
||||
| No test suite found | Skip test check, validate with type+lint only |
|
||||
| Fix log empty | Validate all source files, report minimal analysis |
|
||||
| Type check fails | Attempt code-developer fix for type errors |
|
||||
| Critical regression (>10) | Report immediately, do not attempt fix |
|
||||
132
.claude/skills/team-tech-debt/specs/team-config.json
Normal file
132
.claude/skills/team-tech-debt/specs/team-config.json
Normal file
@@ -0,0 +1,132 @@
|
||||
{
|
||||
"team_name": "tech-debt",
|
||||
"version": "1.0.0",
|
||||
"description": "技术债务识别与清理团队 - 融合\"债务扫描\"、\"量化评估\"、\"治理规划\"、\"清理执行\"、\"验证回归\"五大能力域,形成扫描→评估→规划→清理→验证的闭环",
|
||||
"skill_entry": "team-tech-debt",
|
||||
"invocation": "Skill(skill=\"team-tech-debt\", args=\"--role=coordinator ...\")",
|
||||
|
||||
"roles": {
|
||||
"coordinator": {
|
||||
"name": "coordinator",
|
||||
"responsibility": "Orchestration",
|
||||
"task_prefix": null,
|
||||
"description": "技术债务治理协调者。编排 pipeline:需求澄清 → 模式选择 → 团队创建 → 任务分发 → 监控协调 → 质量门控 → 结果汇报",
|
||||
"message_types_sent": ["mode_selected", "quality_gate", "task_unblocked", "error", "shutdown"],
|
||||
"message_types_received": ["scan_complete", "assessment_complete", "plan_ready", "fix_complete", "validation_complete", "regression_found", "error"],
|
||||
"commands": ["dispatch", "monitor"]
|
||||
},
|
||||
"scanner": {
|
||||
"name": "scanner",
|
||||
"responsibility": "Orchestration (多维度债务扫描)",
|
||||
"task_prefix": "TDSCAN",
|
||||
"description": "技术债务扫描员。多维度扫描代码库:代码债务、架构债务、测试债务、依赖债务、文档债务,生成债务清单",
|
||||
"message_types_sent": ["scan_complete", "debt_items_found", "error"],
|
||||
"message_types_received": [],
|
||||
"commands": ["scan-debt"],
|
||||
"cli_tools": ["gemini"],
|
||||
"subagents": ["cli-explore-agent"]
|
||||
},
|
||||
"assessor": {
|
||||
"name": "assessor",
|
||||
"responsibility": "Read-only analysis (量化评估)",
|
||||
"task_prefix": "TDEVAL",
|
||||
"description": "技术债务评估师。量化评估债务项的影响和修复成本,按优先级矩阵排序,生成评估报告",
|
||||
"message_types_sent": ["assessment_complete", "error"],
|
||||
"message_types_received": [],
|
||||
"commands": ["evaluate"],
|
||||
"cli_tools": ["gemini"]
|
||||
},
|
||||
"planner": {
|
||||
"name": "planner",
|
||||
"responsibility": "Orchestration (治理规划)",
|
||||
"task_prefix": "TDPLAN",
|
||||
"description": "技术债务治理规划师。制定分阶段治理方案:短期速赢、中期系统性治理、长期预防机制",
|
||||
"message_types_sent": ["plan_ready", "plan_revision", "error"],
|
||||
"message_types_received": [],
|
||||
"commands": ["create-plan"],
|
||||
"cli_tools": ["gemini"],
|
||||
"subagents": ["cli-explore-agent"]
|
||||
},
|
||||
"executor": {
|
||||
"name": "executor",
|
||||
"responsibility": "Code generation (债务清理执行)",
|
||||
"task_prefix": "TDFIX",
|
||||
"description": "技术债务清理执行者。按优先级执行重构、依赖更新、代码清理、测试补充等治理动作",
|
||||
"message_types_sent": ["fix_complete", "fix_progress", "error"],
|
||||
"message_types_received": [],
|
||||
"commands": ["remediate"],
|
||||
"subagents": ["code-developer"]
|
||||
},
|
||||
"validator": {
|
||||
"name": "validator",
|
||||
"responsibility": "Validation (清理验证)",
|
||||
"task_prefix": "TDVAL",
|
||||
"description": "技术债务清理验证者。验证清理后无回归、质量指标提升、债务确实消除",
|
||||
"message_types_sent": ["validation_complete", "regression_found", "error"],
|
||||
"message_types_received": [],
|
||||
"commands": ["verify"],
|
||||
"subagents": ["code-developer"],
|
||||
"cli_tools": ["gemini"]
|
||||
}
|
||||
},
|
||||
|
||||
"pipeline_modes": {
|
||||
"scan": {
|
||||
"description": "仅扫描评估,不执行修复(审计模式)",
|
||||
"stages": ["TDSCAN", "TDEVAL"],
|
||||
"entry_role": "scanner"
|
||||
},
|
||||
"remediate": {
|
||||
"description": "完整闭环:扫描 → 评估 → 规划 → 修复 → 验证",
|
||||
"stages": ["TDSCAN", "TDEVAL", "TDPLAN", "TDFIX", "TDVAL"],
|
||||
"entry_role": "scanner"
|
||||
},
|
||||
"targeted": {
|
||||
"description": "定向修复:用户已知债务项,直接规划执行",
|
||||
"stages": ["TDPLAN", "TDFIX", "TDVAL"],
|
||||
"entry_role": "planner"
|
||||
}
|
||||
},
|
||||
|
||||
"fix_verify_loop": {
|
||||
"max_iterations": 3,
|
||||
"trigger": "validation fails or regression found",
|
||||
"participants": ["executor", "validator"],
|
||||
"flow": "TDFIX-fix → TDVAL-verify → evaluate"
|
||||
},
|
||||
|
||||
"shared_memory": {
|
||||
"file": "shared-memory.json",
|
||||
"fields": {
|
||||
"debt_inventory": { "owner": "scanner", "type": "array" },
|
||||
"assessment_matrix": { "owner": "assessor", "type": "object" },
|
||||
"remediation_plan": { "owner": "planner", "type": "object" },
|
||||
"fix_results": { "owner": "executor", "type": "object" },
|
||||
"validation_results": { "owner": "validator", "type": "object" },
|
||||
"debt_score_before": { "owner": "assessor", "type": "number" },
|
||||
"debt_score_after": { "owner": "validator", "type": "number" }
|
||||
}
|
||||
},
|
||||
|
||||
"collaboration_patterns": [
|
||||
"CP-1: Linear Pipeline (scan/remediate/targeted mode)",
|
||||
"CP-2: Review-Fix Cycle (Executor ↔ Validator loop)",
|
||||
"CP-3: Fan-out (Scanner multi-dimension scan)",
|
||||
"CP-5: Escalation (Worker → Coordinator → User)",
|
||||
"CP-6: Incremental Delivery (batch remediation)",
|
||||
"CP-10: Post-Mortem (debt reduction report)"
|
||||
],
|
||||
|
||||
"debt_dimensions": {
|
||||
"code": { "name": "代码债务", "tools": ["static-analysis", "complexity-metrics"] },
|
||||
"architecture": { "name": "架构债务", "tools": ["dependency-graph", "coupling-analysis"] },
|
||||
"testing": { "name": "测试债务", "tools": ["coverage-analysis", "test-quality"] },
|
||||
"dependency": { "name": "依赖债务", "tools": ["outdated-check", "vulnerability-scan"] },
|
||||
"documentation": { "name": "文档债务", "tools": ["doc-coverage", "api-doc-check"] }
|
||||
},
|
||||
|
||||
"session_directory": {
|
||||
"pattern": ".workflow/.team/TD-{slug}-{date}",
|
||||
"subdirectories": ["scan", "assessment", "plan", "fixes", "validation"]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user