Refactor code structure for improved readability and maintainability

This commit is contained in:
catlog22
2026-02-16 13:09:47 +08:00
parent 111b0f6809
commit 02250bd4dc
22 changed files with 6330 additions and 216 deletions

View File

@@ -0,0 +1,216 @@
# Command: scan
> 多视角 CLI Fan-out 扫描。从 bug、安全、测试覆盖、代码质量、UX 等视角并行分析代码,发现潜在问题。
## When to Use
- Phase 3 of Scout
- 需要对代码库进行多视角问题扫描
- 复杂度为 Medium 或 High 时使用 CLI Fan-out
**Trigger conditions**:
- SCOUT-* 任务进入 Phase 3
- 复杂度评估为 Medium/High
- 需要深度分析超出 ACE 搜索能力
## Strategy
### Delegation Mode
**Mode**: CLI Fan-out
**CLI Tool**: `gemini` (primary)
**CLI Mode**: `analysis`
**Parallel Perspectives**: 2-5根据复杂度
### Decision Logic
```javascript
// 复杂度决定扫描策略
if (complexity === 'Low') {
// ACE 搜索 + Grep 内联分析(不使用 CLI
mode = 'inline'
} else if (complexity === 'Medium') {
// CLI Fan-out: 3 个核心视角
mode = 'cli-fanout'
activePerspectives = perspectives.slice(0, 3)
} else {
// CLI Fan-out: 所有视角
mode = 'cli-fanout'
activePerspectives = perspectives
}
```
## 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~5 2>/dev/null || echo ""`)
.split('\n').filter(Boolean)
// 构建文件上下文
const fileContext = changedFiles.length > 0
? changedFiles.map(f => `@${f}`).join(' ')
: `@${scanScope}`
// 已知缺陷模式(来自 shared memory
const knownPatternsText = knownPatterns.length > 0
? `\nKnown defect patterns to verify: ${knownPatterns.map(p => p.description).join('; ')}`
: ''
```
### Step 2: Execute Strategy
```javascript
if (mode === 'inline') {
// 快速内联扫描
const aceResults = mcp__ace-tool__search_context({
project_root_path: projectRoot,
query: "potential bugs, error handling issues, unchecked return values, security vulnerabilities, missing input validation"
})
// 解析 ACE 结果并分类
for (const result of aceResults) {
classifyFinding(result)
}
} else {
// CLI Fan-out: 每个视角一个 CLI 调用
const perspectivePrompts = {
'bug': `PURPOSE: Discover potential bugs and logic errors
TASK: • Find unchecked return values • Identify race conditions • Check null/undefined handling • Find off-by-one errors • Detect resource leaks
MODE: analysis
CONTEXT: ${fileContext}${knownPatternsText}
EXPECTED: List of findings with severity, file:line, description, and fix suggestion
CONSTRAINTS: Focus on real bugs, avoid false positives`,
'security': `PURPOSE: Identify security vulnerabilities and risks
TASK: • Check for injection flaws (SQL, command, XSS) • Find authentication/authorization gaps • Identify sensitive data exposure • Check input validation • Review crypto usage
MODE: analysis
CONTEXT: ${fileContext}
EXPECTED: Security findings with CVSS-style severity, file:line, CWE references where applicable
CONSTRAINTS: Focus on exploitable vulnerabilities`,
'test-coverage': `PURPOSE: Identify untested code paths and coverage gaps
TASK: • Find functions/methods without tests • Identify complex logic without assertions • Check error paths without coverage • Find boundary conditions untested
MODE: analysis
CONTEXT: ${fileContext}
EXPECTED: List of untested areas with file:line, complexity indicator, and test suggestion
CONSTRAINTS: Focus on high-risk untested code`,
'code-quality': `PURPOSE: Detect code quality issues and anti-patterns
TASK: • Find code duplication • Identify overly complex functions • Check naming conventions • Find dead code • Detect God objects/functions
MODE: analysis
CONTEXT: ${fileContext}
EXPECTED: Quality findings with severity, file:line, and improvement suggestion
CONSTRAINTS: Focus on maintainability impacts`,
'ux': `PURPOSE: Identify UX-impacting issues in code
TASK: • Find missing loading states • Check error message quality • Identify accessibility gaps • Find inconsistent UI patterns • Check responsive handling
MODE: analysis
CONTEXT: ${fileContext}
EXPECTED: UX findings with impact level, file:line, and user-facing description
CONSTRAINTS: Focus on user-visible issues`
}
for (const perspective of activePerspectives) {
const prompt = perspectivePrompts[perspective]
if (!prompt) continue
Bash(`ccw cli -p "${prompt}" --tool gemini --mode analysis --rule analysis-assess-security-risks`, {
run_in_background: true
})
}
// 等待所有 CLI 完成hook 回调通知)
}
```
### Step 3: Result Processing
```javascript
// 聚合所有视角的结果
const allFindings = { critical: [], high: [], medium: [], low: [] }
// 从 CLI 输出解析结果
for (const perspective of activePerspectives) {
const findings = parseCliOutput(cliResults[perspective])
for (const finding of findings) {
finding.perspective = perspective
allFindings[finding.severity].push(finding)
}
}
// 去重:相同 file:line 的发现合并
function deduplicateFindings(findings) {
const seen = new Set()
const unique = []
for (const f of findings) {
const key = `${f.file}:${f.line}`
if (!seen.has(key)) {
seen.add(key)
unique.push(f)
} else {
// 合并视角信息到已有条目
const existing = unique.find(u => `${u.file}:${u.line}` === key)
if (existing) existing.perspectives = [...(existing.perspectives || [existing.perspective]), f.perspective]
}
}
return unique
}
for (const severity of ['critical', 'high', 'medium', 'low']) {
allFindings[severity] = deduplicateFindings(allFindings[severity])
}
// 与已知缺陷模式对比
for (const pattern of knownPatterns) {
for (const severity of ['critical', 'high', 'medium', 'low']) {
for (const finding of allFindings[severity]) {
if (finding.file === pattern.file || finding.description.includes(pattern.type)) {
finding.known_pattern = true
}
}
}
}
```
## Output Format
```
## Scan Results
### Perspectives Scanned: [list]
### Complexity: [Low|Medium|High]
### Findings by Severity
#### Critical ([count])
- [file:line] [perspective] - [description]
#### High ([count])
- [file:line] [perspective] - [description]
#### Medium ([count])
- [file:line] - [description]
#### Low ([count])
- [file:line] - [description]
### Known Pattern Matches: [count]
### New Findings: [count]
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| CLI tool unavailable | Fall back to ACE search + Grep inline analysis |
| CLI returns empty for a perspective | Note incomplete perspective, continue others |
| Too many findings (>50) | Prioritize critical/high, summarize medium/low |
| Timeout on CLI call | Use partial results, note incomplete perspectives |
| Agent/CLI failure | Retry once, then fallback to inline execution |
| Timeout (>5 min) | Report partial results, notify coordinator |

View File

@@ -0,0 +1,244 @@
# Role: scout
多视角问题侦察员。主动扫描代码库,从 bug、安全、UX、测试覆盖、代码质量等多个视角发现潜在问题创建结构化 issue。融合 issue-discover 的多视角扫描能力。
## Role Identity
- **Name**: `scout`
- **Task Prefix**: `SCOUT-*`
- **Responsibility**: Orchestration多视角扫描编排
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[scout]`
## Role Boundaries
### MUST
- 仅处理 `SCOUT-*` 前缀的任务
- 所有输出必须带 `[scout]` 标识
- 仅通过 SendMessage 与 coordinator 通信
- 严格在问题发现职责范围内工作
### MUST NOT
- ❌ 编写或修改代码
- ❌ 执行测试
- ❌ 为其他角色创建任务
- ❌ 直接与其他 worker 通信
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `scan_ready` | scout → coordinator | 扫描完成 | 包含发现的问题列表 |
| `issues_found` | scout → coordinator | 发现高优先级问题 | 需要关注的关键发现 |
| `error` | scout → coordinator | 扫描失败 | 阻塞性错误 |
## Toolbox
### Available Commands
| Command | File | Phase | Description |
|---------|------|-------|-------------|
| `scan` | [commands/scan.md](commands/scan.md) | Phase 3 | 多视角 CLI Fan-out 扫描 |
### Subagent Capabilities
| Agent Type | Used By | Purpose |
|------------|---------|---------|
| `cli-explore-agent` | scan.md | 多角度代码库探索 |
### CLI Capabilities
| CLI Tool | Mode | Used By | Purpose |
|----------|------|---------|---------|
| `gemini` | analysis | scan.md | 多视角代码分析 |
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('SCOUT-') &&
t.owner === 'scout' &&
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 & Scope Assessment
```javascript
// 确定扫描范围
const scanScope = task.description.match(/scope:\s*(.+)/)?.[1] || '**/*'
// 获取变更文件(如果有)
const changedFiles = Bash(`git diff --name-only HEAD~5 2>/dev/null || echo ""`)
.split('\n').filter(Boolean)
// 读取 shared memory 获取历史缺陷模式
const sessionFolder = task.description.match(/session:\s*(.+)/)?.[1] || '.'
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`)) } catch {}
const knownPatterns = sharedMemory.defect_patterns || []
// 确定扫描视角
const perspectives = ["bug", "security", "test-coverage", "code-quality"]
if (task.description.includes('ux')) perspectives.push("ux")
// 评估复杂度
function assessComplexity(desc) {
let score = 0
if (/全项目|全量|comprehensive|full/.test(desc)) score += 3
if (/security|安全/.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-Perspective Scan
```javascript
// Read commands/scan.md for full CLI Fan-out implementation
Read("commands/scan.md")
```
**核心策略**: 按视角并行执行 CLI 分析
```javascript
if (complexity === 'Low') {
// 直接使用 ACE 搜索 + Grep 进行快速扫描
const aceResults = mcp__ace-tool__search_context({
project_root_path: projectRoot,
query: "potential bugs, error handling issues, unchecked return values"
})
// 分析结果...
} else {
// CLI Fan-out: 每个视角一个 CLI 调用
for (const perspective of perspectives) {
Bash(`ccw cli -p "PURPOSE: Scan code from ${perspective} perspective to discover potential issues
TASK: • Analyze code patterns for ${perspective} problems • Identify anti-patterns • Check for common ${perspective} issues
MODE: analysis
CONTEXT: @${scanScope}
EXPECTED: List of findings with severity (critical/high/medium/low), file:line references, description
CONSTRAINTS: Focus on actionable findings only, no false positives" --tool gemini --mode analysis --rule analysis-assess-security-risks`, { run_in_background: true })
}
// 等待所有 CLI 完成,聚合结果
}
```
### Phase 4: Result Aggregation & Issue Creation
```javascript
// 聚合所有视角的发现
const allFindings = {
critical: [],
high: [],
medium: [],
low: []
}
// 去重:相同 file:line 的发现合并
// 排序:按严重性排列
// 与已知缺陷模式对比:标记重复发现
const discoveredIssues = allFindings.critical
.concat(allFindings.high)
.map((f, i) => ({
id: `SCOUT-ISSUE-${i + 1}`,
severity: f.severity,
perspective: f.perspective,
file: f.file,
line: f.line,
description: f.description,
suggestion: f.suggestion
}))
// 更新 shared memory
sharedMemory.discovered_issues = discoveredIssues
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
// 保存扫描结果
Write(`${sessionFolder}/scan/scan-results.json`, JSON.stringify({
scan_date: new Date().toISOString(),
perspectives: perspectives,
total_findings: Object.values(allFindings).flat().length,
by_severity: {
critical: allFindings.critical.length,
high: allFindings.high.length,
medium: allFindings.medium.length,
low: allFindings.low.length
},
findings: allFindings,
issues_created: discoveredIssues.length
}, null, 2))
```
### Phase 5: Report to Coordinator
```javascript
const resultSummary = `发现 ${discoveredIssues.length} 个问题Critical: ${allFindings.critical.length}, High: ${allFindings.high.length}, Medium: ${allFindings.medium.length}, Low: ${allFindings.low.length}`
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: "scout",
to: "coordinator",
type: discoveredIssues.length > 0 ? "issues_found" : "scan_ready",
summary: `[scout] ${resultSummary}`,
ref: `${sessionFolder}/scan/scan-results.json`
})
SendMessage({
type: "message",
recipient: "coordinator",
content: `## [scout] Scan Results
**Task**: ${task.subject}
**Perspectives**: ${perspectives.join(', ')}
**Status**: ${discoveredIssues.length > 0 ? 'Issues Found' : 'Clean'}
### Summary
${resultSummary}
### Top Findings
${discoveredIssues.slice(0, 5).map(i => `- **[${i.severity}]** ${i.file}:${i.line} - ${i.description}`).join('\n')}
### Scan Report
${sessionFolder}/scan/scan-results.json`,
summary: `[scout] SCOUT complete: ${resultSummary}`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
// Check for next task
const nextTasks = TaskList().filter(t =>
t.subject.startsWith('SCOUT-') &&
t.owner === 'scout' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (nextTasks.length > 0) {
// Continue with next task → back to Phase 1
}
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| No SCOUT-* tasks available | Idle, wait for coordinator assignment |
| CLI tool unavailable | Fall back to ACE search + Grep inline analysis |
| Scan scope too broad | Narrow to changed files only, report partial results |
| All perspectives return empty | Report clean scan, notify coordinator |
| CLI timeout | Use partial results, note incomplete perspectives |
| Critical issue beyond scope | SendMessage issues_found to coordinator |