feat: Add orchestrator and state management for code review process

- Implemented orchestrator logic to manage code review phases, including state reading, action selection, and execution loop.
- Defined state schema for review process, including metadata, context, findings, and execution tracking.
- Created action catalog detailing actions for context collection, quick scan, deep review, report generation, and completion.
- Established error recovery strategies and termination conditions for robust review handling.
- Developed issue classification and quality standards documentation to guide review severity and categorization.
- Introduced review dimensions with detailed checklists for correctness, security, performance, readability, testing, and architecture.
- Added templates for issue reporting and review reports to standardize output and improve clarity.
This commit is contained in:
catlog22
2026-01-13 14:39:16 +08:00
parent 76f5311e78
commit 29c8bb7a66
13 changed files with 2611 additions and 0 deletions

View File

@@ -0,0 +1,170 @@
---
name: review-code
description: Multi-dimensional code review with structured reports. Analyzes correctness, readability, performance, security, testing, and architecture. Triggers on "review code", "code review", "审查代码", "代码审查".
allowed-tools: Task, AskUserQuestion, Read, Write, Glob, Grep, Bash, mcp__ace-tool__search_context, mcp__ide__getDiagnostics
---
# Review Code
Multi-dimensional code review skill that analyzes code across 6 key dimensions and generates structured review reports with actionable recommendations.
## Architecture Overview
```
┌─────────────────────────────────────────────────────────────────┐
│ ⚠️ Phase 0: Specification Study (强制前置) │
│ → 阅读 specs/review-dimensions.md │
│ → 理解审查维度和问题分类标准 │
└───────────────┬─────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Orchestrator (状态驱动决策) │
│ → 读取状态 → 选择审查动作 → 执行 → 更新状态 │
└───────────────┬─────────────────────────────────────────────────┘
┌───────────┼───────────┬───────────┬───────────┐
↓ ↓ ↓ ↓ ↓
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ Collect │ │ Quick │ │ Deep │ │ Report │ │Complete │
│ Context │ │ Scan │ │ Review │ │ Generate│ │ │
└─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘
↓ ↓ ↓ ↓
┌─────────────────────────────────────────────────────────────────┐
│ Review Dimensions │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │Correctness│ │Readability│ │Performance│ │ Security │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ │
│ │ Testing │ │Architecture│ │
│ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────────┘
```
## Key Design Principles
1. **多维度审查**: 覆盖正确性、可读性、性能、安全性、测试覆盖、架构一致性六大维度
2. **分层执行**: 快速扫描识别高风险区域,深入审查聚焦关键问题
3. **结构化报告**: 按严重程度分类,提供文件位置和修复建议
4. **状态驱动**: 自主模式,根据审查进度动态选择下一步动作
---
## ⚠️ Mandatory Prerequisites (强制前置条件)
> **⛔ 禁止跳过**: 在执行任何审查操作之前,**必须**完整阅读以下文档。
### 规范文档 (必读)
| Document | Purpose | Priority |
|----------|---------|----------|
| [specs/review-dimensions.md](specs/review-dimensions.md) | 审查维度定义和检查点 | **P0 - 最高** |
| [specs/issue-classification.md](specs/issue-classification.md) | 问题分类和严重程度标准 | **P0 - 最高** |
| [specs/quality-standards.md](specs/quality-standards.md) | 审查质量标准 | P1 |
### 模板文件 (生成前必读)
| Document | Purpose |
|----------|---------|
| [templates/review-report.md](templates/review-report.md) | 审查报告模板 |
| [templates/issue-template.md](templates/issue-template.md) | 问题记录模板 |
---
## Execution Flow
```
┌─────────────────────────────────────────────────────────────────┐
│ Phase 0: Specification Study (强制前置 - 禁止跳过) │
│ → Read: specs/review-dimensions.md │
│ → Read: specs/issue-classification.md │
│ → 理解审查标准和问题分类 │
├─────────────────────────────────────────────────────────────────┤
│ Action: collect-context │
│ → 收集目标文件/目录 │
│ → 识别技术栈和语言 │
│ → Output: state.context (files, language, framework) │
├─────────────────────────────────────────────────────────────────┤
│ Action: quick-scan │
│ → 快速扫描整体结构 │
│ → 识别高风险区域 │
│ → Output: state.risk_areas, state.scan_summary │
├─────────────────────────────────────────────────────────────────┤
│ Action: deep-review (per dimension) │
│ → 逐维度深入审查 │
│ → 记录发现的问题 │
│ → Output: state.findings[] │
├─────────────────────────────────────────────────────────────────┤
│ Action: generate-report │
│ → 汇总所有发现 │
│ → 生成结构化报告 │
│ → Output: review-report.md │
├─────────────────────────────────────────────────────────────────┤
│ Action: complete │
│ → 保存最终状态 │
│ → 输出审查摘要 │
└─────────────────────────────────────────────────────────────────┘
```
## Directory Setup
```javascript
const timestamp = new Date().toISOString().slice(0,19).replace(/[-:T]/g, '');
const workDir = `.workflow/.scratchpad/review-code-${timestamp}`;
Bash(`mkdir -p "${workDir}"`);
Bash(`mkdir -p "${workDir}/findings"`);
```
## Output Structure
```
.workflow/.scratchpad/review-code-{timestamp}/
├── state.json # 审查状态
├── context.json # 目标上下文
├── findings/ # 问题发现
│ ├── correctness.json
│ ├── readability.json
│ ├── performance.json
│ ├── security.json
│ ├── testing.json
│ └── architecture.json
└── review-report.md # 最终审查报告
```
## Review Dimensions
| Dimension | Focus Areas | Key Checks |
|-----------|-------------|------------|
| **Correctness** | 逻辑正确性 | 边界条件、错误处理、null 检查 |
| **Readability** | 代码可读性 | 命名规范、函数长度、注释质量 |
| **Performance** | 性能效率 | 算法复杂度、I/O 优化、资源使用 |
| **Security** | 安全性 | 注入风险、敏感信息、权限控制 |
| **Testing** | 测试覆盖 | 测试充分性、边界覆盖、可维护性 |
| **Architecture** | 架构一致性 | 设计模式、分层结构、依赖管理 |
## Issue Severity Levels
| Level | Prefix | Description | Action Required |
|-------|--------|-------------|-----------------|
| **Critical** | [C] | 阻塞性问题,必须立即修复 | Must fix before merge |
| **High** | [H] | 重要问题,需要修复 | Should fix |
| **Medium** | [M] | 建议改进 | Consider fixing |
| **Low** | [L] | 可选优化 | Nice to have |
| **Info** | [I] | 信息性建议 | For reference |
## Reference Documents
| Document | Purpose |
|----------|---------|
| [phases/orchestrator.md](phases/orchestrator.md) | 审查编排器 |
| [phases/state-schema.md](phases/state-schema.md) | 状态结构定义 |
| [phases/actions/action-collect-context.md](phases/actions/action-collect-context.md) | 收集上下文 |
| [phases/actions/action-quick-scan.md](phases/actions/action-quick-scan.md) | 快速扫描 |
| [phases/actions/action-deep-review.md](phases/actions/action-deep-review.md) | 深入审查 |
| [phases/actions/action-generate-report.md](phases/actions/action-generate-report.md) | 生成报告 |
| [phases/actions/action-complete.md](phases/actions/action-complete.md) | 完成审查 |
| [specs/review-dimensions.md](specs/review-dimensions.md) | 审查维度规范 |
| [specs/issue-classification.md](specs/issue-classification.md) | 问题分类标准 |
| [specs/quality-standards.md](specs/quality-standards.md) | 质量标准 |
| [templates/review-report.md](templates/review-report.md) | 报告模板 |
| [templates/issue-template.md](templates/issue-template.md) | 问题模板 |

View File

@@ -0,0 +1,139 @@
# Action: Collect Context
收集审查目标的上下文信息。
## Purpose
在开始审查前,收集目标代码的基本信息:
- 确定审查范围(文件/目录)
- 识别编程语言和框架
- 统计代码规模
## Preconditions
- [ ] state.status === 'pending' || state.context === null
## Execution
```javascript
async function execute(state, workDir) {
// 1. 询问用户审查目标
const input = await AskUserQuestion({
questions: [{
question: "请指定要审查的代码路径:",
header: "审查目标",
multiSelect: false,
options: [
{ label: "当前目录", description: "审查当前工作目录下的所有代码" },
{ label: "src/", description: "审查 src/ 目录" },
{ label: "手动指定", description: "输入自定义路径" }
]
}]
});
const targetPath = input["审查目标"] === "手动指定"
? input["其他"]
: input["审查目标"] === "当前目录" ? "." : "src/";
// 2. 收集文件列表
const files = Glob(`${targetPath}/**/*.{ts,tsx,js,jsx,py,java,go,rs,cpp,c,cs}`);
// 3. 检测主要语言
const languageCounts = {};
files.forEach(file => {
const ext = file.split('.').pop();
const langMap = {
'ts': 'TypeScript', 'tsx': 'TypeScript',
'js': 'JavaScript', 'jsx': 'JavaScript',
'py': 'Python',
'java': 'Java',
'go': 'Go',
'rs': 'Rust',
'cpp': 'C++', 'c': 'C',
'cs': 'C#'
};
const lang = langMap[ext] || 'Unknown';
languageCounts[lang] = (languageCounts[lang] || 0) + 1;
});
const primaryLanguage = Object.entries(languageCounts)
.sort((a, b) => b[1] - a[1])[0]?.[0] || 'Unknown';
// 4. 统计代码行数
let totalLines = 0;
for (const file of files.slice(0, 100)) { // 限制前100个文件
try {
const content = Read(file);
totalLines += content.split('\n').length;
} catch (e) {}
}
// 5. 检测框架
let framework = null;
if (files.some(f => f.includes('package.json'))) {
const pkg = JSON.parse(Read('package.json'));
if (pkg.dependencies?.react) framework = 'React';
else if (pkg.dependencies?.vue) framework = 'Vue';
else if (pkg.dependencies?.angular) framework = 'Angular';
else if (pkg.dependencies?.express) framework = 'Express';
else if (pkg.dependencies?.next) framework = 'Next.js';
}
// 6. 构建上下文
const context = {
target_path: targetPath,
files: files.slice(0, 200), // 限制最多200个文件
language: primaryLanguage,
framework: framework,
total_lines: totalLines,
file_count: files.length
};
// 7. 保存上下文
Write(`${workDir}/context.json`, JSON.stringify(context, null, 2));
return {
stateUpdates: {
status: 'running',
context: context
}
};
}
```
## State Updates
```javascript
return {
stateUpdates: {
status: 'running',
context: {
target_path: targetPath,
files: fileList,
language: primaryLanguage,
framework: detectedFramework,
total_lines: totalLines,
file_count: fileCount
}
}
};
```
## Output
- **File**: `context.json`
- **Location**: `${workDir}/context.json`
- **Format**: JSON
## Error Handling
| Error Type | Recovery |
|------------|----------|
| 路径不存在 | 提示用户重新输入 |
| 无代码文件 | 返回错误,终止审查 |
| 读取权限问题 | 跳过该文件,记录警告 |
## Next Actions
- 成功: action-quick-scan
- 失败: action-abort

View File

@@ -0,0 +1,115 @@
# Action: Complete
完成审查,保存最终状态。
## Purpose
结束代码审查流程:
- 保存最终状态
- 输出审查摘要
- 提供报告路径
## Preconditions
- [ ] state.status === 'running'
- [ ] state.report_generated === true
## Execution
```javascript
async function execute(state, workDir) {
// 1. 计算审查时长
const duration = Date.now() - new Date(state.started_at).getTime();
const durationMinutes = Math.round(duration / 60000);
// 2. 生成最终摘要
const summary = {
...state.summary,
review_duration_ms: duration,
completed_at: new Date().toISOString()
};
// 3. 保存最终状态
const finalState = {
...state,
status: 'completed',
completed_at: summary.completed_at,
summary: summary
};
Write(`${workDir}/state.json`, JSON.stringify(finalState, null, 2));
// 4. 输出摘要信息
console.log('========================================');
console.log(' CODE REVIEW COMPLETED');
console.log('========================================');
console.log('');
console.log(`📁 审查目标: ${state.context.target_path}`);
console.log(`📄 文件数量: ${state.context.file_count}`);
console.log(`📝 代码行数: ${state.context.total_lines}`);
console.log('');
console.log('--- 问题统计 ---');
console.log(`🔴 Critical: ${summary.critical}`);
console.log(`🟠 High: ${summary.high}`);
console.log(`🟡 Medium: ${summary.medium}`);
console.log(`🔵 Low: ${summary.low}`);
console.log(`⚪ Info: ${summary.info}`);
console.log(`📊 Total: ${summary.total_issues}`);
console.log('');
console.log(`⏱️ 审查用时: ${durationMinutes} 分钟`);
console.log('');
console.log(`📋 报告位置: ${state.report_path}`);
console.log('========================================');
// 5. 返回状态更新
return {
stateUpdates: {
status: 'completed',
completed_at: summary.completed_at,
summary: summary
}
};
}
```
## State Updates
```javascript
return {
stateUpdates: {
status: 'completed',
completed_at: new Date().toISOString(),
summary: {
total_issues: state.summary.total_issues,
critical: state.summary.critical,
high: state.summary.high,
medium: state.summary.medium,
low: state.summary.low,
info: state.summary.info,
review_duration_ms: duration
}
}
};
```
## Output
- **Console**: 审查完成摘要
- **State**: 最终状态保存到 `state.json`
## Error Handling
| Error Type | Recovery |
|------------|----------|
| 状态保存失败 | 输出到控制台 |
## Next Actions
- 无(终止状态)
## Post-Completion
用户可以:
1. 查看完整报告: `cat ${workDir}/review-report.md`
2. 查看问题详情: `cat ${workDir}/findings/*.json`
3. 导出报告到其他位置

View File

@@ -0,0 +1,256 @@
# Action: Deep Review
深入审查指定维度的代码质量。
## Purpose
针对单个维度进行深入审查:
- 逐文件检查
- 记录发现的问题
- 提供具体的修复建议
## Preconditions
- [ ] state.status === 'running'
- [ ] state.scan_completed === true
- [ ] 存在未审查的维度
## Dimension Focus Areas
### Correctness (正确性)
- 逻辑错误和边界条件
- Null/undefined 处理
- 错误处理完整性
- 类型安全
- 资源泄漏
### Readability (可读性)
- 命名规范
- 函数长度和复杂度
- 代码重复
- 注释质量
- 代码组织
### Performance (性能)
- 算法复杂度
- 不必要的计算
- 内存使用
- I/O 效率
- 缓存策略
### Security (安全性)
- 注入风险 (SQL, XSS, Command)
- 认证和授权
- 敏感数据处理
- 加密使用
- 依赖安全
### Testing (测试)
- 测试覆盖率
- 边界条件测试
- 错误路径测试
- 测试可维护性
- Mock 使用
### Architecture (架构)
- 分层结构
- 依赖方向
- 单一职责
- 接口设计
- 扩展性
## Execution
```javascript
async function execute(state, workDir, currentDimension) {
const context = state.context;
const dimension = currentDimension;
const findings = [];
// 获取维度特定的检查规则
const rules = getDimensionRules(dimension);
// 优先审查高风险区域
const filesToReview = state.scan_summary?.risk_areas
?.map(r => r.file)
?.filter(f => context.files.includes(f)) || context.files;
const filesToCheck = [...new Set([
...filesToReview.slice(0, 20),
...context.files.slice(0, 30)
])].slice(0, 50); // 最多50个文件
let findingCounter = 1;
for (const file of filesToCheck) {
try {
const content = Read(file);
const lines = content.split('\n');
// 应用维度特定规则
for (const rule of rules) {
const matches = rule.detect(content, lines, file);
for (const match of matches) {
findings.push({
id: `${getDimensionPrefix(dimension)}-${String(findingCounter++).padStart(3, '0')}`,
severity: match.severity,
dimension: dimension,
category: rule.category,
file: file,
line: match.line,
code_snippet: match.snippet,
description: match.description,
recommendation: rule.recommendation,
fix_example: rule.fixExample
});
}
}
} catch (e) {
// 跳过无法读取的文件
}
}
// 保存维度发现
Write(`${workDir}/findings/${dimension}.json`, JSON.stringify(findings, null, 2));
return {
stateUpdates: {
reviewed_dimensions: [...(state.reviewed_dimensions || []), dimension],
current_dimension: null,
[`findings.${dimension}`]: findings
}
};
}
function getDimensionPrefix(dimension) {
const prefixes = {
correctness: 'CORR',
readability: 'READ',
performance: 'PERF',
security: 'SEC',
testing: 'TEST',
architecture: 'ARCH'
};
return prefixes[dimension] || 'MISC';
}
function getDimensionRules(dimension) {
// 参见 specs/review-dimensions.md 获取完整规则
const allRules = {
correctness: [
{
category: 'null-check',
detect: (content, lines) => {
const issues = [];
lines.forEach((line, i) => {
if (line.match(/\w+\.\w+/) && !line.includes('?.') && !line.includes('if') && !line.includes('null')) {
// 简化检测:可能缺少 null 检查
}
});
return issues;
},
recommendation: 'Add null/undefined check before accessing properties',
fixExample: 'obj?.property or if (obj) { obj.property }'
},
{
category: 'empty-catch',
detect: (content, lines) => {
const issues = [];
const regex = /catch\s*\([^)]*\)\s*{\s*}/g;
let match;
while ((match = regex.exec(content)) !== null) {
const lineNum = content.substring(0, match.index).split('\n').length;
issues.push({
severity: 'high',
line: lineNum,
snippet: match[0],
description: 'Empty catch block silently swallows errors'
});
}
return issues;
},
recommendation: 'Log the error or rethrow it',
fixExample: 'catch (e) { console.error(e); throw e; }'
}
],
security: [
{
category: 'xss-risk',
detect: (content, lines) => {
const issues = [];
lines.forEach((line, i) => {
if (line.includes('innerHTML') || line.includes('dangerouslySetInnerHTML')) {
issues.push({
severity: 'critical',
line: i + 1,
snippet: line.trim().substring(0, 100),
description: 'Direct HTML injection can lead to XSS vulnerabilities'
});
}
});
return issues;
},
recommendation: 'Use textContent or sanitize HTML before injection',
fixExample: 'element.textContent = userInput; // or sanitize(userInput)'
},
{
category: 'hardcoded-secret',
detect: (content, lines) => {
const issues = [];
const regex = /(?:password|secret|api[_-]?key|token)\s*[=:]\s*['"]([^'"]{8,})['"]/gi;
lines.forEach((line, i) => {
if (regex.test(line)) {
issues.push({
severity: 'critical',
line: i + 1,
snippet: line.trim().substring(0, 100),
description: 'Hardcoded credentials detected'
});
}
regex.lastIndex = 0; // Reset regex
});
return issues;
},
recommendation: 'Use environment variables or secret management',
fixExample: 'const apiKey = process.env.API_KEY;'
}
],
// ... 其他维度规则参见 specs/review-dimensions.md
};
return allRules[dimension] || [];
}
```
## State Updates
```javascript
return {
stateUpdates: {
reviewed_dimensions: [...state.reviewed_dimensions, currentDimension],
current_dimension: null,
findings: {
...state.findings,
[currentDimension]: newFindings
}
}
};
```
## Output
- **File**: `findings/{dimension}.json`
- **Location**: `${workDir}/findings/`
- **Format**: JSON array of Finding objects
## Error Handling
| Error Type | Recovery |
|------------|----------|
| 文件读取失败 | 跳过该文件,记录警告 |
| 规则执行错误 | 跳过该规则,继续其他规则 |
## Next Actions
- 还有未审查维度: 继续 action-deep-review
- 所有维度完成: action-generate-report

View File

@@ -0,0 +1,263 @@
# Action: Generate Report
汇总所有发现,生成结构化审查报告。
## Purpose
生成最终的代码审查报告:
- 汇总所有维度的发现
- 按严重程度排序
- 提供统计摘要
- 输出 Markdown 格式报告
## Preconditions
- [ ] state.status === 'running'
- [ ] 所有维度已审查完成 (reviewed_dimensions.length === 6)
## Execution
```javascript
async function execute(state, workDir) {
const context = state.context;
const findings = state.findings;
// 1. 汇总所有发现
const allFindings = [
...findings.correctness,
...findings.readability,
...findings.performance,
...findings.security,
...findings.testing,
...findings.architecture
];
// 2. 按严重程度排序
const severityOrder = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };
allFindings.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]);
// 3. 统计
const stats = {
total_issues: allFindings.length,
critical: allFindings.filter(f => f.severity === 'critical').length,
high: allFindings.filter(f => f.severity === 'high').length,
medium: allFindings.filter(f => f.severity === 'medium').length,
low: allFindings.filter(f => f.severity === 'low').length,
info: allFindings.filter(f => f.severity === 'info').length,
by_dimension: {
correctness: findings.correctness.length,
readability: findings.readability.length,
performance: findings.performance.length,
security: findings.security.length,
testing: findings.testing.length,
architecture: findings.architecture.length
}
};
// 4. 生成报告
const report = generateMarkdownReport(context, stats, allFindings, state.scan_summary);
// 5. 保存报告
const reportPath = `${workDir}/review-report.md`;
Write(reportPath, report);
return {
stateUpdates: {
report_generated: true,
report_path: reportPath,
summary: {
...stats,
review_duration_ms: Date.now() - new Date(state.started_at).getTime()
}
}
};
}
function generateMarkdownReport(context, stats, findings, scanSummary) {
const severityEmoji = {
critical: '🔴',
high: '🟠',
medium: '🟡',
low: '🔵',
info: '⚪'
};
let report = `# Code Review Report
## 审查概览
| 项目 | 值 |
|------|------|
| 目标路径 | \`${context.target_path}\` |
| 文件数量 | ${context.file_count} |
| 代码行数 | ${context.total_lines} |
| 主要语言 | ${context.language} |
| 框架 | ${context.framework || 'N/A'} |
## 问题统计
| 严重程度 | 数量 |
|----------|------|
| 🔴 Critical | ${stats.critical} |
| 🟠 High | ${stats.high} |
| 🟡 Medium | ${stats.medium} |
| 🔵 Low | ${stats.low} |
| ⚪ Info | ${stats.info} |
| **总计** | **${stats.total_issues}** |
### 按维度统计
| 维度 | 问题数 |
|------|--------|
| Correctness (正确性) | ${stats.by_dimension.correctness} |
| Security (安全性) | ${stats.by_dimension.security} |
| Performance (性能) | ${stats.by_dimension.performance} |
| Readability (可读性) | ${stats.by_dimension.readability} |
| Testing (测试) | ${stats.by_dimension.testing} |
| Architecture (架构) | ${stats.by_dimension.architecture} |
---
## 高风险区域
`;
if (scanSummary?.risk_areas?.length > 0) {
report += `| 文件 | 原因 | 优先级 |
|------|------|--------|
`;
for (const area of scanSummary.risk_areas.slice(0, 10)) {
report += `| \`${area.file}\` | ${area.reason} | ${area.priority} |\n`;
}
} else {
report += `未发现明显的高风险区域。\n`;
}
report += `
---
## 问题详情
`;
// 按维度分组输出
const dimensions = ['correctness', 'security', 'performance', 'readability', 'testing', 'architecture'];
const dimensionNames = {
correctness: '正确性 (Correctness)',
security: '安全性 (Security)',
performance: '性能 (Performance)',
readability: '可读性 (Readability)',
testing: '测试 (Testing)',
architecture: '架构 (Architecture)'
};
for (const dim of dimensions) {
const dimFindings = findings.filter(f => f.dimension === dim);
if (dimFindings.length === 0) continue;
report += `### ${dimensionNames[dim]}
`;
for (const finding of dimFindings) {
report += `#### ${severityEmoji[finding.severity]} [${finding.id}] ${finding.category}
- **严重程度**: ${finding.severity.toUpperCase()}
- **文件**: \`${finding.file}\`${finding.line ? `:${finding.line}` : ''}
- **描述**: ${finding.description}
`;
if (finding.code_snippet) {
report += `
\`\`\`
${finding.code_snippet}
\`\`\`
`;
}
report += `
**建议**: ${finding.recommendation}
`;
if (finding.fix_example) {
report += `
**修复示例**:
\`\`\`
${finding.fix_example}
\`\`\`
`;
}
report += `
---
`;
}
}
report += `
## 审查建议
### 必须修复 (Must Fix)
${stats.critical + stats.high > 0
? `发现 ${stats.critical} 个严重问题和 ${stats.high} 个高优先级问题,建议在合并前修复。`
: '未发现必须立即修复的问题。'}
### 建议改进 (Should Fix)
${stats.medium > 0
? `发现 ${stats.medium} 个中等优先级问题,建议在后续迭代中改进。`
: '代码质量良好,无明显需要改进的地方。'}
### 可选优化 (Nice to Have)
${stats.low + stats.info > 0
? `发现 ${stats.low + stats.info} 个低优先级建议,可根据团队规范酌情处理。`
: '无额外建议。'}
---
*报告生成时间: ${new Date().toISOString()}*
`;
return report;
}
```
## State Updates
```javascript
return {
stateUpdates: {
report_generated: true,
report_path: reportPath,
summary: {
total_issues: totalCount,
critical: criticalCount,
high: highCount,
medium: mediumCount,
low: lowCount,
info: infoCount,
review_duration_ms: duration
}
}
};
```
## Output
- **File**: `review-report.md`
- **Location**: `${workDir}/review-report.md`
- **Format**: Markdown
## Error Handling
| Error Type | Recovery |
|------------|----------|
| 写入失败 | 尝试备用位置 |
| 模板错误 | 使用简化格式 |
## Next Actions
- 成功: action-complete

View File

@@ -0,0 +1,164 @@
# Action: Quick Scan
快速扫描代码,识别高风险区域。
## Purpose
进行第一遍快速扫描:
- 识别复杂度高的文件
- 标记潜在的高风险区域
- 发现明显的问题模式
## Preconditions
- [ ] state.status === 'running'
- [ ] state.context !== null
## Execution
```javascript
async function execute(state, workDir) {
const context = state.context;
const riskAreas = [];
const quickIssues = [];
// 1. 扫描每个文件
for (const file of context.files) {
try {
const content = Read(file);
const lines = content.split('\n');
// --- 复杂度检查 ---
const functionMatches = content.match(/function\s+\w+|=>\s*{|async\s+\w+/g) || [];
const nestingDepth = Math.max(...lines.map(l => (l.match(/^\s*/)?.[0].length || 0) / 2));
if (lines.length > 500 || functionMatches.length > 20 || nestingDepth > 8) {
riskAreas.push({
file: file,
reason: `High complexity: ${lines.length} lines, ${functionMatches.length} functions, depth ${nestingDepth}`,
priority: 'high'
});
}
// --- 快速问题检测 ---
// 安全问题快速检测
if (content.includes('eval(') || content.includes('innerHTML')) {
quickIssues.push({
type: 'security',
file: file,
message: 'Potential XSS/injection risk: eval() or innerHTML usage'
});
}
// 硬编码密钥检测
if (/(?:password|secret|api_key|token)\s*[=:]\s*['"][^'"]{8,}/i.test(content)) {
quickIssues.push({
type: 'security',
file: file,
message: 'Potential hardcoded credential detected'
});
}
// TODO/FIXME 检测
const todoCount = (content.match(/TODO|FIXME|HACK|XXX/gi) || []).length;
if (todoCount > 5) {
quickIssues.push({
type: 'maintenance',
file: file,
message: `${todoCount} TODO/FIXME comments found`
});
}
// console.log 检测(生产代码)
if (!file.includes('test') && !file.includes('spec')) {
const consoleCount = (content.match(/console\.(log|debug|info)/g) || []).length;
if (consoleCount > 3) {
quickIssues.push({
type: 'readability',
file: file,
message: `${consoleCount} console statements (should be removed in production)`
});
}
}
// 长函数检测
const longFunctions = content.match(/function[^{]+\{[^}]{2000,}\}/g) || [];
if (longFunctions.length > 0) {
quickIssues.push({
type: 'readability',
file: file,
message: `${longFunctions.length} long function(s) detected (>50 lines)`
});
}
// 错误处理检测
if (content.includes('catch') && content.includes('catch (') && content.match(/catch\s*\([^)]*\)\s*{\s*}/)) {
quickIssues.push({
type: 'correctness',
file: file,
message: 'Empty catch block detected'
});
}
} catch (e) {
// 跳过无法读取的文件
}
}
// 2. 计算复杂度评分
const complexityScore = Math.min(100, Math.round(
(riskAreas.length * 10 + quickIssues.length * 5) / context.file_count * 100
));
// 3. 构建扫描摘要
const scanSummary = {
risk_areas: riskAreas,
complexity_score: complexityScore,
quick_issues: quickIssues
};
// 4. 保存扫描结果
Write(`${workDir}/scan-summary.json`, JSON.stringify(scanSummary, null, 2));
return {
stateUpdates: {
scan_completed: true,
scan_summary: scanSummary
}
};
}
```
## State Updates
```javascript
return {
stateUpdates: {
scan_completed: true,
scan_summary: {
risk_areas: riskAreas,
complexity_score: score,
quick_issues: quickIssues
}
}
};
```
## Output
- **File**: `scan-summary.json`
- **Location**: `${workDir}/scan-summary.json`
- **Format**: JSON
## Error Handling
| Error Type | Recovery |
|------------|----------|
| 文件读取失败 | 跳过该文件,继续扫描 |
| 编码问题 | 以二进制跳过 |
## Next Actions
- 成功: action-deep-review (开始逐维度审查)
- 风险区域过多 (>20): 可询问用户是否缩小范围

View File

@@ -0,0 +1,192 @@
# Orchestrator
根据当前状态选择并执行下一个审查动作。
## Role
Code Review 编排器,负责:
1. 读取当前审查状态
2. 根据状态选择下一个动作
3. 执行动作并更新状态
4. 循环直到审查完成
## State Management
### 读取状态
```javascript
const state = JSON.parse(Read(`${workDir}/state.json`));
```
### 更新状态
```javascript
function updateState(updates) {
const state = JSON.parse(Read(`${workDir}/state.json`));
const newState = {
...state,
...updates,
updated_at: new Date().toISOString()
};
Write(`${workDir}/state.json`, JSON.stringify(newState, null, 2));
return newState;
}
```
## Decision Logic
```javascript
function selectNextAction(state) {
// 1. 终止条件检查
if (state.status === 'completed') return null;
if (state.status === 'user_exit') return null;
if (state.error_count >= 3) return 'action-abort';
// 2. 初始化阶段
if (state.status === 'pending' || !state.context) {
return 'action-collect-context';
}
// 3. 快速扫描阶段
if (!state.scan_completed) {
return 'action-quick-scan';
}
// 4. 深入审查阶段 - 逐维度审查
const dimensions = ['correctness', 'readability', 'performance', 'security', 'testing', 'architecture'];
const reviewedDimensions = state.reviewed_dimensions || [];
for (const dim of dimensions) {
if (!reviewedDimensions.includes(dim)) {
return 'action-deep-review'; // 传递 dimension 参数
}
}
// 5. 报告生成阶段
if (!state.report_generated) {
return 'action-generate-report';
}
// 6. 完成
return 'action-complete';
}
```
## Execution Loop
```javascript
async function runOrchestrator() {
console.log('=== Code Review Orchestrator Started ===');
let iteration = 0;
const MAX_ITERATIONS = 20; // 6 dimensions + overhead
while (iteration < MAX_ITERATIONS) {
iteration++;
// 1. 读取当前状态
const state = JSON.parse(Read(`${workDir}/state.json`));
console.log(`[Iteration ${iteration}] Status: ${state.status}`);
// 2. 选择下一个动作
const actionId = selectNextAction(state);
if (!actionId) {
console.log('Review completed, terminating.');
break;
}
console.log(`[Iteration ${iteration}] Executing: ${actionId}`);
// 3. 更新状态:当前动作
updateState({ current_action: actionId });
// 4. 执行动作
try {
const actionPrompt = Read(`phases/actions/${actionId}.md`);
// 确定当前需要审查的维度
let currentDimension = null;
if (actionId === 'action-deep-review') {
const dimensions = ['correctness', 'readability', 'performance', 'security', 'testing', 'architecture'];
const reviewed = state.reviewed_dimensions || [];
currentDimension = dimensions.find(d => !reviewed.includes(d));
}
const result = await Task({
subagent_type: 'universal-executor',
run_in_background: false,
prompt: `
[WORK_DIR]
${workDir}
[STATE]
${JSON.stringify(state, null, 2)}
[CURRENT_DIMENSION]
${currentDimension || 'N/A'}
[ACTION]
${actionPrompt}
[SPECS]
Review Dimensions: specs/review-dimensions.md
Issue Classification: specs/issue-classification.md
[RETURN]
Return JSON with stateUpdates field containing updates to apply to state.
`
});
const actionResult = JSON.parse(result);
// 5. 更新状态:动作完成
updateState({
current_action: null,
completed_actions: [...(state.completed_actions || []), actionId],
...actionResult.stateUpdates
});
} catch (error) {
// 错误处理
updateState({
current_action: null,
errors: [...(state.errors || []), {
action: actionId,
message: error.message,
timestamp: new Date().toISOString()
}],
error_count: (state.error_count || 0) + 1
});
}
}
console.log('=== Code Review Orchestrator Finished ===');
}
```
## Action Catalog
| Action | Purpose | Preconditions |
|--------|---------|---------------|
| [action-collect-context](actions/action-collect-context.md) | 收集审查目标上下文 | status === 'pending' |
| [action-quick-scan](actions/action-quick-scan.md) | 快速扫描识别风险区域 | context !== null |
| [action-deep-review](actions/action-deep-review.md) | 深入审查指定维度 | scan_completed === true |
| [action-generate-report](actions/action-generate-report.md) | 生成结构化审查报告 | all dimensions reviewed |
| [action-complete](actions/action-complete.md) | 完成审查,保存结果 | report_generated === true |
## Termination Conditions
- `state.status === 'completed'` - 审查正常完成
- `state.status === 'user_exit'` - 用户主动退出
- `state.error_count >= 3` - 错误次数超限
- `iteration >= MAX_ITERATIONS` - 迭代次数超限
## Error Recovery
| Error Type | Recovery Strategy |
|------------|-------------------|
| 文件读取失败 | 跳过该文件,记录警告 |
| 动作执行失败 | 重试最多 3 次 |
| 状态不一致 | 重新初始化状态 |
| 用户中止 | 保存当前进度,允许恢复 |

View File

@@ -0,0 +1,174 @@
# State Schema
Code Review 状态结构定义。
## Schema Definition
```typescript
interface ReviewState {
// === 元数据 ===
status: 'pending' | 'running' | 'completed' | 'failed' | 'user_exit';
started_at: string; // ISO timestamp
updated_at: string; // ISO timestamp
completed_at?: string; // ISO timestamp
// === 审查目标 ===
context: {
target_path: string; // 目标路径(文件或目录)
files: string[]; // 待审查文件列表
language: string; // 主要编程语言
framework?: string; // 框架(如有)
total_lines: number; // 总代码行数
file_count: number; // 文件数量
};
// === 扫描结果 ===
scan_completed: boolean;
scan_summary: {
risk_areas: RiskArea[]; // 高风险区域
complexity_score: number; // 复杂度评分
quick_issues: QuickIssue[]; // 快速发现的问题
};
// === 审查进度 ===
reviewed_dimensions: string[]; // 已完成的审查维度
current_dimension?: string; // 当前审查维度
// === 发现的问题 ===
findings: {
correctness: Finding[];
readability: Finding[];
performance: Finding[];
security: Finding[];
testing: Finding[];
architecture: Finding[];
};
// === 报告状态 ===
report_generated: boolean;
report_path?: string;
// === 执行跟踪 ===
current_action?: string;
completed_actions: string[];
errors: ExecutionError[];
error_count: number;
// === 统计信息 ===
summary?: {
total_issues: number;
critical: number;
high: number;
medium: number;
low: number;
info: number;
review_duration_ms: number;
};
}
interface RiskArea {
file: string;
reason: string;
priority: 'high' | 'medium' | 'low';
}
interface QuickIssue {
type: string;
file: string;
line?: number;
message: string;
}
interface Finding {
id: string; // 唯一标识 e.g., "CORR-001"
severity: 'critical' | 'high' | 'medium' | 'low' | 'info';
dimension: string; // 所属维度
category: string; // 问题类别
file: string; // 文件路径
line?: number; // 行号
column?: number; // 列号
code_snippet?: string; // 问题代码片段
description: string; // 问题描述
recommendation: string; // 修复建议
fix_example?: string; // 修复示例代码
references?: string[]; // 参考资料链接
}
interface ExecutionError {
action: string;
message: string;
timestamp: string;
}
```
## Initial State
```json
{
"status": "pending",
"started_at": "2024-01-01T00:00:00.000Z",
"updated_at": "2024-01-01T00:00:00.000Z",
"context": null,
"scan_completed": false,
"scan_summary": null,
"reviewed_dimensions": [],
"current_dimension": null,
"findings": {
"correctness": [],
"readability": [],
"performance": [],
"security": [],
"testing": [],
"architecture": []
},
"report_generated": false,
"report_path": null,
"current_action": null,
"completed_actions": [],
"errors": [],
"error_count": 0,
"summary": null
}
```
## State Transitions
```mermaid
stateDiagram-v2
[*] --> pending: Initialize
pending --> running: collect-context
running --> running: quick-scan
running --> running: deep-review (6x)
running --> running: generate-report
running --> completed: complete
running --> failed: error_count >= 3
running --> user_exit: User abort
completed --> [*]
failed --> [*]
user_exit --> [*]
```
## Dimension Review Order
1. **correctness** - 正确性(最高优先级)
2. **security** - 安全性(关键)
3. **performance** - 性能
4. **readability** - 可读性
5. **testing** - 测试覆盖
6. **architecture** - 架构一致性
## Finding ID Format
```
{DIMENSION_PREFIX}-{SEQUENCE}
Prefixes:
- CORR: Correctness
- READ: Readability
- PERF: Performance
- SEC: Security
- TEST: Testing
- ARCH: Architecture
Example: SEC-003 = Security issue #3
```

View File

@@ -0,0 +1,228 @@
# Issue Classification
问题分类和严重程度标准。
## When to Use
| Phase | Usage | Section |
|-------|-------|---------|
| action-deep-review | 确定问题严重程度 | Severity Levels |
| action-generate-report | 问题分类展示 | Category Mapping |
---
## Severity Levels
### Critical (严重) 🔴
**定义**: 必须在合并前修复的阻塞性问题
**标准**:
- 安全漏洞 (可被利用)
- 数据损坏或丢失风险
- 系统崩溃风险
- 生产环境重大故障
**示例**:
- SQL/XSS/命令注入
- 硬编码密钥泄露
- 未捕获的异常导致崩溃
- 数据库事务未正确处理
**响应**: 必须立即修复,阻塞合并
---
### High (高) 🟠
**定义**: 应在合并前修复的重要问题
**标准**:
- 功能缺陷
- 重要边界条件未处理
- 性能严重退化
- 资源泄漏
**示例**:
- 核心业务逻辑错误
- 内存泄漏
- N+1 查询问题
- 缺少必要的错误处理
**响应**: 强烈建议修复
---
### Medium (中) 🟡
**定义**: 建议修复的代码质量问题
**标准**:
- 代码可维护性问题
- 轻微性能问题
- 测试覆盖不足
- 不符合团队规范
**示例**:
- 函数过长
- 命名不清晰
- 缺少注释
- 代码重复
**响应**: 建议在后续迭代修复
---
### Low (低) 🔵
**定义**: 可选优化的问题
**标准**:
- 风格问题
- 微小优化
- 可读性改进
**示例**:
- 变量声明顺序
- 额外的空行
- 可以更简洁的写法
**响应**: 可根据团队偏好处理
---
### Info (信息) ⚪
**定义**: 信息性建议,非问题
**标准**:
- 学习机会
- 替代方案建议
- 文档完善建议
**示例**:
- "这里可以考虑使用新的 API"
- "建议添加 JSDoc 注释"
- "可以参考 xxx 模式"
**响应**: 仅供参考
---
## Category Mapping
### By Dimension
| Dimension | Common Categories |
|-----------|-------------------|
| Correctness | `null-check`, `boundary`, `error-handling`, `type-safety`, `logic-error` |
| Security | `injection`, `xss`, `hardcoded-secret`, `auth`, `sensitive-data` |
| Performance | `complexity`, `n+1-query`, `memory-leak`, `blocking-io`, `inefficient-algorithm` |
| Readability | `naming`, `function-length`, `complexity`, `comments`, `duplication` |
| Testing | `coverage`, `boundary-test`, `mock-abuse`, `test-isolation` |
| Architecture | `layer-violation`, `circular-dependency`, `coupling`, `srp-violation` |
### Category Details
#### Correctness Categories
| Category | Description | Default Severity |
|----------|-------------|------------------|
| `null-check` | 缺少空值检查 | High |
| `boundary` | 边界条件未处理 | High |
| `error-handling` | 错误处理不当 | High |
| `type-safety` | 类型安全问题 | Medium |
| `logic-error` | 逻辑错误 | Critical/High |
| `resource-leak` | 资源泄漏 | High |
#### Security Categories
| Category | Description | Default Severity |
|----------|-------------|------------------|
| `injection` | 注入风险 (SQL/Command) | Critical |
| `xss` | 跨站脚本风险 | Critical |
| `hardcoded-secret` | 硬编码密钥 | Critical |
| `auth` | 认证授权问题 | High |
| `sensitive-data` | 敏感数据暴露 | High |
| `insecure-dependency` | 不安全依赖 | Medium |
#### Performance Categories
| Category | Description | Default Severity |
|----------|-------------|------------------|
| `complexity` | 高算法复杂度 | Medium |
| `n+1-query` | N+1 查询问题 | High |
| `memory-leak` | 内存泄漏 | High |
| `blocking-io` | 阻塞 I/O | Medium |
| `inefficient-algorithm` | 低效算法 | Medium |
| `missing-cache` | 缺少缓存 | Low |
#### Readability Categories
| Category | Description | Default Severity |
|----------|-------------|------------------|
| `naming` | 命名问题 | Medium |
| `function-length` | 函数过长 | Medium |
| `nesting-depth` | 嵌套过深 | Medium |
| `comments` | 注释问题 | Low |
| `duplication` | 代码重复 | Medium |
| `magic-number` | 魔法数字 | Low |
#### Testing Categories
| Category | Description | Default Severity |
|----------|-------------|------------------|
| `coverage` | 测试覆盖不足 | Medium |
| `boundary-test` | 缺少边界测试 | Medium |
| `mock-abuse` | Mock 过度使用 | Low |
| `test-isolation` | 测试不独立 | Medium |
| `flaky-test` | 不稳定测试 | High |
#### Architecture Categories
| Category | Description | Default Severity |
|----------|-------------|------------------|
| `layer-violation` | 层次违规 | Medium |
| `circular-dependency` | 循环依赖 | High |
| `coupling` | 耦合过紧 | Medium |
| `srp-violation` | 单一职责违规 | Medium |
| `god-class` | 上帝类 | High |
---
## Finding ID Format
```
{PREFIX}-{NNN}
Prefixes by Dimension:
- CORR: Correctness
- SEC: Security
- PERF: Performance
- READ: Readability
- TEST: Testing
- ARCH: Architecture
Examples:
- SEC-001: First security finding
- CORR-015: 15th correctness finding
```
---
## Quality Gates
| Gate | Condition | Action |
|------|-----------|--------|
| **Block** | Critical > 0 | 禁止合并 |
| **Warn** | High > 0 | 需要审批 |
| **Pass** | Critical = 0, High = 0 | 允许合并 |
### Recommended Thresholds
| Metric | Ideal | Acceptable | Needs Work |
|--------|-------|------------|------------|
| Critical | 0 | 0 | Any > 0 |
| High | 0 | ≤ 2 | > 2 |
| Medium | ≤ 5 | ≤ 10 | > 10 |
| Total | ≤ 10 | ≤ 20 | > 20 |

View File

@@ -0,0 +1,214 @@
# Quality Standards
代码审查质量标准。
## When to Use
| Phase | Usage | Section |
|-------|-------|---------|
| action-generate-report | 质量评估 | Quality Dimensions |
| action-complete | 最终评分 | Quality Gates |
---
## Quality Dimensions
### 1. Completeness (完整性) - 25%
**评估审查覆盖的完整程度**
| Score | Criteria |
|-------|----------|
| 100% | 所有维度审查完成,所有高风险文件检查 |
| 80% | 核心维度完成,主要文件检查 |
| 60% | 部分维度完成 |
| < 60% | 审查不完整 |
**检查点**:
- [ ] 6 个维度全部审查
- [ ] 高风险区域重点检查
- [ ] 关键文件覆盖
---
### 2. Accuracy (准确性) - 25%
**评估发现问题的准确程度**
| Score | Criteria |
|-------|----------|
| 100% | 问题定位准确,分类正确,无误报 |
| 80% | 偶有分类偏差,定位准确 |
| 60% | 存在误报或漏报 |
| < 60% | 准确性差 |
**检查点**:
- [ ] 问题行号准确
- [ ] 严重程度合理
- [ ] 分类正确
---
### 3. Actionability (可操作性) - 25%
**评估建议的实用程度**
| Score | Criteria |
|-------|----------|
| 100% | 每个问题都有具体可执行的修复建议 |
| 80% | 大部分问题有清晰建议 |
| 60% | 建议较笼统 |
| < 60% | 缺乏可操作建议 |
**检查点**:
- [ ] 提供具体修复建议
- [ ] 包含代码示例
- [ ] 说明修复优先级
---
### 4. Consistency (一致性) - 25%
**评估审查标准的一致程度**
| Score | Criteria |
|-------|----------|
| 100% | 相同问题相同处理,标准统一 |
| 80% | 基本一致,偶有差异 |
| 60% | 标准不太统一 |
| < 60% | 标准混乱 |
**检查点**:
- [ ] ID 格式统一
- [ ] 严重程度标准一致
- [ ] 描述风格统一
---
## Quality Gates
### Review Quality Gate
| Gate | Overall Score | Action |
|------|---------------|--------|
| **Excellent** | ≥ 90% | 高质量审查 |
| **Good** | ≥ 80% | 合格审查 |
| **Acceptable** | ≥ 70% | 基本可接受 |
| **Needs Improvement** | < 70% | 需要改进 |
### Code Quality Gate (Based on Findings)
| Gate | Condition | Recommendation |
|------|-----------|----------------|
| **Block** | Critical > 0 | 禁止合并,必须修复 |
| **Warn** | High > 3 | 需要团队讨论 |
| **Caution** | Medium > 10 | 建议改进 |
| **Pass** | 其他 | 可以合并 |
---
## Report Quality Checklist
### Structure
- [ ] 包含审查概览
- [ ] 包含问题统计
- [ ] 包含高风险区域
- [ ] 包含问题详情
- [ ] 包含修复建议
### Content
- [ ] 问题描述清晰
- [ ] 文件位置准确
- [ ] 代码片段有效
- [ ] 修复建议具体
- [ ] 优先级明确
### Format
- [ ] Markdown 格式正确
- [ ] 表格对齐
- [ ] 代码块语法正确
- [ ] 链接有效
- [ ] 无拼写错误
---
## Validation Function
```javascript
function validateReviewQuality(state) {
const scores = {
completeness: 0,
accuracy: 0,
actionability: 0,
consistency: 0
};
// 1. Completeness
const dimensionsReviewed = state.reviewed_dimensions?.length || 0;
scores.completeness = (dimensionsReviewed / 6) * 100;
// 2. Accuracy (需要人工验证或后续反馈)
// 暂时基于有无错误来估算
scores.accuracy = state.error_count === 0 ? 100 : Math.max(0, 100 - state.error_count * 20);
// 3. Actionability
const findings = Object.values(state.findings).flat();
const withRecommendations = findings.filter(f => f.recommendation).length;
scores.actionability = findings.length > 0
? (withRecommendations / findings.length) * 100
: 100;
// 4. Consistency (检查 ID 格式等)
const validIds = findings.filter(f => /^(CORR|SEC|PERF|READ|TEST|ARCH)-\d{3}$/.test(f.id)).length;
scores.consistency = findings.length > 0
? (validIds / findings.length) * 100
: 100;
// Overall
const overall = (
scores.completeness * 0.25 +
scores.accuracy * 0.25 +
scores.actionability * 0.25 +
scores.consistency * 0.25
);
return {
scores,
overall,
gate: overall >= 90 ? 'excellent' :
overall >= 80 ? 'good' :
overall >= 70 ? 'acceptable' : 'needs_improvement'
};
}
```
---
## Improvement Recommendations
### If Completeness is Low
- 增加扫描的文件范围
- 确保所有维度都被审查
- 重点关注高风险区域
### If Accuracy is Low
- 提高规则精度
- 减少误报
- 验证行号准确性
### If Actionability is Low
- 为每个问题添加修复建议
- 提供代码示例
- 说明修复步骤
### If Consistency is Low
- 统一 ID 格式
- 标准化严重程度判定
- 使用模板化描述

View File

@@ -0,0 +1,337 @@
# Review Dimensions
代码审查维度定义和检查点规范。
## When to Use
| Phase | Usage | Section |
|-------|-------|---------|
| action-deep-review | 获取维度检查规则 | All |
| action-generate-report | 维度名称映射 | Dimension Names |
---
## Dimension Overview
| Dimension | Weight | Focus | Key Indicators |
|-----------|--------|-------|----------------|
| **Correctness** | 25% | 功能正确性 | 边界条件、错误处理、类型安全 |
| **Security** | 25% | 安全风险 | 注入攻击、敏感数据、权限 |
| **Performance** | 15% | 执行效率 | 算法复杂度、资源使用 |
| **Readability** | 15% | 可维护性 | 命名、结构、注释 |
| **Testing** | 10% | 测试质量 | 覆盖率、边界测试 |
| **Architecture** | 10% | 架构一致性 | 分层、依赖、模式 |
---
## 1. Correctness (正确性)
### 检查清单
- [ ] **边界条件处理**
- 空数组/空字符串
- Null/Undefined
- 数值边界 (0, 负数, MAX_INT)
- 集合边界 (首元素, 末元素)
- [ ] **错误处理**
- Try-catch 覆盖
- 错误不被静默吞掉
- 错误信息有意义
- 资源正确释放
- [ ] **类型安全**
- 类型转换正确
- 避免隐式转换
- TypeScript strict mode
- [ ] **逻辑完整性**
- If-else 分支完整
- Switch 有 default
- 循环终止条件正确
### 常见问题模式
```javascript
// ❌ 问题: 未检查 null
function getName(user) {
return user.name.toUpperCase(); // user 可能为 null
}
// ✅ 修复
function getName(user) {
return user?.name?.toUpperCase() ?? 'Unknown';
}
// ❌ 问题: 空 catch 块
try {
await fetchData();
} catch (e) {} // 错误被静默吞掉
// ✅ 修复
try {
await fetchData();
} catch (e) {
console.error('Failed to fetch data:', e);
throw e;
}
```
---
## 2. Security (安全性)
### 检查清单
- [ ] **注入防护**
- SQL 注入 (使用参数化查询)
- XSS (避免 innerHTML)
- 命令注入 (避免 exec)
- 路径遍历
- [ ] **认证授权**
- 权限检查完整
- Token 验证
- Session 管理
- [ ] **敏感数据**
- 无硬编码密钥
- 日志不含敏感信息
- 传输加密
- [ ] **依赖安全**
- 无已知漏洞依赖
- 版本锁定
### 常见问题模式
```javascript
// ❌ 问题: SQL 注入风险
const query = `SELECT * FROM users WHERE id = ${userId}`;
// ✅ 修复: 参数化查询
const query = `SELECT * FROM users WHERE id = ?`;
db.query(query, [userId]);
// ❌ 问题: XSS 风险
element.innerHTML = userInput;
// ✅ 修复
element.textContent = userInput;
// ❌ 问题: 硬编码密钥
const apiKey = 'sk-xxxxxxxxxxxx';
// ✅ 修复
const apiKey = process.env.API_KEY;
```
---
## 3. Performance (性能)
### 检查清单
- [ ] **算法复杂度**
- 避免 O(n²) 在大数据集
- 使用合适的数据结构
- 避免不必要的循环
- [ ] **I/O 效率**
- 批量操作 vs 循环单条
- 避免 N+1 查询
- 适当使用缓存
- [ ] **资源使用**
- 内存泄漏
- 连接池使用
- 大文件流式处理
- [ ] **异步处理**
- 并行 vs 串行
- Promise.all 使用
- 避免阻塞
### 常见问题模式
```javascript
// ❌ 问题: N+1 查询
for (const user of users) {
const posts = await db.query('SELECT * FROM posts WHERE user_id = ?', [user.id]);
}
// ✅ 修复: 批量查询
const userIds = users.map(u => u.id);
const posts = await db.query('SELECT * FROM posts WHERE user_id IN (?)', [userIds]);
// ❌ 问题: 串行执行可并行操作
const a = await fetchA();
const b = await fetchB();
const c = await fetchC();
// ✅ 修复: 并行执行
const [a, b, c] = await Promise.all([fetchA(), fetchB(), fetchC()]);
```
---
## 4. Readability (可读性)
### 检查清单
- [ ] **命名规范**
- 变量名见名知意
- 函数名表达动作
- 常量使用 UPPER_CASE
- 避免缩写和单字母
- [ ] **函数设计**
- 单一职责
- 长度 < 50 行
- 参数 < 5 个
- 嵌套 < 4 层
- [ ] **代码组织**
- 逻辑分组
- 空行分隔
- Import 顺序
- [ ] **注释质量**
- 解释 WHY 而非 WHAT
- 及时更新
- 无冗余注释
### 常见问题模式
```javascript
// ❌ 问题: 命名不清晰
const d = new Date();
const a = users.filter(x => x.s === 'active');
// ✅ 修复
const currentDate = new Date();
const activeUsers = users.filter(user => user.status === 'active');
// ❌ 问题: 函数过长、职责过多
function processOrder(order) {
// ... 200 行代码,包含验证、计算、保存、通知
}
// ✅ 修复: 拆分职责
function validateOrder(order) { /* ... */ }
function calculateTotal(order) { /* ... */ }
function saveOrder(order) { /* ... */ }
function notifyCustomer(order) { /* ... */ }
```
---
## 5. Testing (测试)
### 检查清单
- [ ] **测试覆盖**
- 核心逻辑有测试
- 边界条件有测试
- 错误路径有测试
- [ ] **测试质量**
- 测试独立
- 断言明确
- Mock 适度
- [ ] **测试可维护性**
- 命名清晰
- 结构统一
- 避免重复
### 常见问题模式
```javascript
// ❌ 问题: 测试不独立
let counter = 0;
test('increment', () => {
counter++; // 依赖外部状态
expect(counter).toBe(1);
});
// ✅ 修复: 每个测试独立
test('increment', () => {
const counter = new Counter();
counter.increment();
expect(counter.value).toBe(1);
});
// ❌ 问题: 缺少边界测试
test('divide', () => {
expect(divide(10, 2)).toBe(5);
});
// ✅ 修复: 包含边界情况
test('divide by zero throws', () => {
expect(() => divide(10, 0)).toThrow();
});
```
---
## 6. Architecture (架构)
### 检查清单
- [ ] **分层结构**
- 层次清晰
- 依赖方向正确
- 无循环依赖
- [ ] **模块化**
- 高内聚低耦合
- 接口定义清晰
- 职责单一
- [ ] **设计模式**
- 使用合适的模式
- 避免过度设计
- 遵循项目既有模式
### 常见问题模式
```javascript
// ❌ 问题: 层次混乱 (Controller 直接操作数据库)
class UserController {
async getUser(req, res) {
const user = await db.query('SELECT * FROM users WHERE id = ?', [req.params.id]);
res.json(user);
}
}
// ✅ 修复: 分层清晰
class UserController {
constructor(private userService: UserService) {}
async getUser(req, res) {
const user = await this.userService.findById(req.params.id);
res.json(user);
}
}
// ❌ 问题: 循环依赖
// moduleA.ts
import { funcB } from './moduleB';
// moduleB.ts
import { funcA } from './moduleA';
// ✅ 修复: 提取共享模块或使用依赖注入
```
---
## Severity Mapping
| Severity | Criteria |
|----------|----------|
| **Critical** | 安全漏洞、数据损坏风险、崩溃风险 |
| **High** | 功能缺陷、性能严重问题、重要边界未处理 |
| **Medium** | 代码质量问题、可维护性问题 |
| **Low** | 风格问题、优化建议 |
| **Info** | 信息性建议、学习机会 |

View File

@@ -0,0 +1,186 @@
# Issue Template
问题记录模板。
## Single Issue Template
```markdown
#### {{severity_emoji}} [{{id}}] {{category}}
- **严重程度**: {{severity}}
- **维度**: {{dimension}}
- **文件**: `{{file}}`{{#if line}}:{{line}}{{/if}}
- **描述**: {{description}}
{{#if code_snippet}}
**问题代码**:
```{{language}}
{{code_snippet}}
```
{{/if}}
**建议**: {{recommendation}}
{{#if fix_example}}
**修复示例**:
```{{language}}
{{fix_example}}
```
{{/if}}
{{#if references}}
**参考资料**:
{{#each references}}
- {{this}}
{{/each}}
{{/if}}
```
## Issue Object Schema
```typescript
interface Issue {
id: string; // e.g., "SEC-001"
severity: 'critical' | 'high' | 'medium' | 'low' | 'info';
dimension: string; // e.g., "security"
category: string; // e.g., "xss-risk"
file: string; // e.g., "src/utils/render.ts"
line?: number; // e.g., 42
column?: number; // e.g., 15
code_snippet?: string;
description: string;
recommendation: string;
fix_example?: string;
references?: string[];
}
```
## ID Generation
```javascript
function generateIssueId(dimension, counter) {
const prefixes = {
correctness: 'CORR',
readability: 'READ',
performance: 'PERF',
security: 'SEC',
testing: 'TEST',
architecture: 'ARCH'
};
const prefix = prefixes[dimension] || 'MISC';
const number = String(counter).padStart(3, '0');
return `${prefix}-${number}`;
}
```
## Severity Emojis
```javascript
const SEVERITY_EMOJI = {
critical: '🔴',
high: '🟠',
medium: '🟡',
low: '🔵',
info: '⚪'
};
```
## Issue Categories by Dimension
### Correctness
- `null-check` - 缺少空值检查
- `boundary` - 边界条件未处理
- `error-handling` - 错误处理不当
- `type-safety` - 类型安全问题
- `logic-error` - 逻辑错误
- `resource-leak` - 资源泄漏
### Security
- `injection` - 注入风险
- `xss` - 跨站脚本
- `hardcoded-secret` - 硬编码密钥
- `auth` - 认证授权
- `sensitive-data` - 敏感数据
### Performance
- `complexity` - 复杂度问题
- `n+1-query` - N+1 查询
- `memory-leak` - 内存泄漏
- `blocking-io` - 阻塞 I/O
- `inefficient-algorithm` - 低效算法
### Readability
- `naming` - 命名问题
- `function-length` - 函数过长
- `nesting-depth` - 嵌套过深
- `comments` - 注释问题
- `duplication` - 代码重复
### Testing
- `coverage` - 覆盖不足
- `boundary-test` - 缺少边界测试
- `test-isolation` - 测试不独立
- `flaky-test` - 不稳定测试
### Architecture
- `layer-violation` - 层次违规
- `circular-dependency` - 循环依赖
- `coupling` - 耦合过紧
- `srp-violation` - 单一职责违规
## Example Issues
### Critical Security Issue
```json
{
"id": "SEC-001",
"severity": "critical",
"dimension": "security",
"category": "xss",
"file": "src/components/Comment.tsx",
"line": 25,
"code_snippet": "element.innerHTML = userComment;",
"description": "直接使用 innerHTML 插入用户输入,存在 XSS 攻击风险",
"recommendation": "使用 textContent 或对用户输入进行 HTML 转义",
"fix_example": "element.textContent = userComment;\n// 或\nelement.innerHTML = DOMPurify.sanitize(userComment);",
"references": [
"https://owasp.org/www-community/xss-filter-evasion-cheatsheet"
]
}
```
### High Correctness Issue
```json
{
"id": "CORR-003",
"severity": "high",
"dimension": "correctness",
"category": "error-handling",
"file": "src/services/api.ts",
"line": 42,
"code_snippet": "try {\n await fetchData();\n} catch (e) {}",
"description": "空的 catch 块会静默吞掉错误,导致问题难以发现和调试",
"recommendation": "记录错误日志或重新抛出异常",
"fix_example": "try {\n await fetchData();\n} catch (e) {\n console.error('Failed to fetch data:', e);\n throw e;\n}"
}
```
### Medium Readability Issue
```json
{
"id": "READ-007",
"severity": "medium",
"dimension": "readability",
"category": "function-length",
"file": "src/utils/processor.ts",
"line": 15,
"description": "函数 processData 有 150 行,超过推荐的 50 行限制,难以理解和维护",
"recommendation": "将函数拆分为多个小函数,每个函数负责单一职责",
"fix_example": "// 拆分为:\nfunction validateInput(data) { ... }\nfunction transformData(data) { ... }\nfunction saveData(data) { ... }"
}
```

View File

@@ -0,0 +1,173 @@
# Review Report Template
审查报告模板。
## Template Structure
```markdown
# Code Review Report
## 审查概览
| 项目 | 值 |
|------|------|
| 目标路径 | `{{target_path}}` |
| 文件数量 | {{file_count}} |
| 代码行数 | {{total_lines}} |
| 主要语言 | {{language}} |
| 框架 | {{framework}} |
| 审查时间 | {{review_duration}} |
## 问题统计
| 严重程度 | 数量 |
|----------|------|
| 🔴 Critical | {{critical_count}} |
| 🟠 High | {{high_count}} |
| 🟡 Medium | {{medium_count}} |
| 🔵 Low | {{low_count}} |
| ⚪ Info | {{info_count}} |
| **总计** | **{{total_issues}}** |
### 按维度统计
| 维度 | 问题数 |
|------|--------|
| Correctness (正确性) | {{correctness_count}} |
| Security (安全性) | {{security_count}} |
| Performance (性能) | {{performance_count}} |
| Readability (可读性) | {{readability_count}} |
| Testing (测试) | {{testing_count}} |
| Architecture (架构) | {{architecture_count}} |
---
## 高风险区域
{{#if risk_areas}}
| 文件 | 原因 | 优先级 |
|------|------|--------|
{{#each risk_areas}}
| `{{this.file}}` | {{this.reason}} | {{this.priority}} |
{{/each}}
{{else}}
未发现明显的高风险区域。
{{/if}}
---
## 问题详情
{{#each dimensions}}
### {{this.name}}
{{#each this.findings}}
#### {{severity_emoji this.severity}} [{{this.id}}] {{this.category}}
- **严重程度**: {{this.severity}}
- **文件**: `{{this.file}}`{{#if this.line}}:{{this.line}}{{/if}}
- **描述**: {{this.description}}
{{#if this.code_snippet}}
```
{{this.code_snippet}}
```
{{/if}}
**建议**: {{this.recommendation}}
{{#if this.fix_example}}
**修复示例**:
```
{{this.fix_example}}
```
{{/if}}
---
{{/each}}
{{/each}}
## 审查建议
### 必须修复 (Must Fix)
{{must_fix_summary}}
### 建议改进 (Should Fix)
{{should_fix_summary}}
### 可选优化 (Nice to Have)
{{nice_to_have_summary}}
---
*报告生成时间: {{generated_at}}*
```
## Variable Definitions
| Variable | Type | Source |
|----------|------|--------|
| `{{target_path}}` | string | state.context.target_path |
| `{{file_count}}` | number | state.context.file_count |
| `{{total_lines}}` | number | state.context.total_lines |
| `{{language}}` | string | state.context.language |
| `{{framework}}` | string | state.context.framework |
| `{{review_duration}}` | string | Formatted duration |
| `{{critical_count}}` | number | Count of critical findings |
| `{{high_count}}` | number | Count of high findings |
| `{{medium_count}}` | number | Count of medium findings |
| `{{low_count}}` | number | Count of low findings |
| `{{info_count}}` | number | Count of info findings |
| `{{total_issues}}` | number | Total findings |
| `{{risk_areas}}` | array | state.scan_summary.risk_areas |
| `{{dimensions}}` | array | Grouped findings by dimension |
| `{{generated_at}}` | string | ISO timestamp |
## Helper Functions
```javascript
function severity_emoji(severity) {
const emojis = {
critical: '🔴',
high: '🟠',
medium: '🟡',
low: '🔵',
info: '⚪'
};
return emojis[severity] || '⚪';
}
function formatDuration(ms) {
const minutes = Math.floor(ms / 60000);
const seconds = Math.floor((ms % 60000) / 1000);
return `${minutes}${seconds}`;
}
function generateMustFixSummary(findings) {
const critical = findings.filter(f => f.severity === 'critical');
const high = findings.filter(f => f.severity === 'high');
if (critical.length + high.length === 0) {
return '未发现必须立即修复的问题。';
}
return `发现 ${critical.length} 个严重问题和 ${high.length} 个高优先级问题,建议在合并前修复。`;
}
```
## Usage Example
```javascript
const report = generateReport({
context: state.context,
summary: state.summary,
findings: state.findings,
scanSummary: state.scan_summary
});
Write(`${workDir}/review-report.md`, report);
```