Files
Claude-Code-Workflow/.claude/skills/team-tech-debt/roles/scanner/role.md
catlog22 f60dd44d5b 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.
2026-02-23 22:46:27 +08:00

7.8 KiB
Raw Blame History

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 记录:

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 写入日志文件:

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 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

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

// 确定扫描范围
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

// Read commands/scan-debt.md for full CLI Fan-out implementation
Read("commands/scan-debt.md")

核心策略: 按维度并行执行 CLI 分析

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

// 聚合所有维度的发现
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

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