mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-03-01 15:03:57 +08:00
chore: move 3 skills to ccw-skill-hub repository
Migrated to D:/ccw-skill-hub/skills/: - project-analyze - copyright-docs - software-manual
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
# Command: generate-report
|
||||
|
||||
> Cross-correlate enriched + pass-through findings, compute metrics, write review-report.json (for fixer) and review-report.md (for humans).
|
||||
|
||||
## When to Use
|
||||
|
||||
- Phase 4 of Reviewer, after deep analysis (or directly if deep_analysis was empty)
|
||||
- Requires: `enrichedFindings[]` (from Phase 3 or empty), `pass_through[]` (from Phase 2), `sessionFolder`
|
||||
|
||||
## Strategy
|
||||
|
||||
**Mode**: Direct (inline execution, no CLI needed)
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Load & Combine Findings
|
||||
|
||||
```javascript
|
||||
let enrichedFindings = []
|
||||
try { enrichedFindings = JSON.parse(Read(`${sessionFolder}/review/enriched-findings.json`)) } catch {}
|
||||
const allFindings = [...enrichedFindings, ...pass_through]
|
||||
```
|
||||
|
||||
### Step 2: Cross-Correlate
|
||||
|
||||
```javascript
|
||||
// 2a: Critical files (file appears in >=2 dimensions)
|
||||
const fileDimMap = {}
|
||||
for (const f of allFindings) {
|
||||
const file = f.location?.file; if (!file) continue
|
||||
if (!fileDimMap[file]) fileDimMap[file] = new Set()
|
||||
fileDimMap[file].add(f.dimension)
|
||||
}
|
||||
const critical_files = Object.entries(fileDimMap)
|
||||
.filter(([, dims]) => dims.size >= 2)
|
||||
.map(([file, dims]) => ({
|
||||
file, dimensions: [...dims],
|
||||
finding_count: allFindings.filter(f => f.location?.file === file).length,
|
||||
severities: [...new Set(allFindings.filter(f => f.location?.file === file).map(f => f.severity))]
|
||||
})).sort((a, b) => b.finding_count - a.finding_count)
|
||||
|
||||
// 2b: Group by shared root cause
|
||||
const rootCauseGroups = [], grouped = new Set()
|
||||
for (const f of allFindings) {
|
||||
if (grouped.has(f.id)) continue
|
||||
const related = (f.root_cause?.related_findings || []).filter(rid => !grouped.has(rid))
|
||||
if (related.length > 0) {
|
||||
const ids = [f.id, ...related]; ids.forEach(id => grouped.add(id))
|
||||
rootCauseGroups.push({ root_cause: f.root_cause?.description || f.title,
|
||||
finding_ids: ids, primary_id: f.id, dimension: f.dimension, severity: f.severity })
|
||||
}
|
||||
}
|
||||
|
||||
// 2c: Optimization suggestions from root cause groups + standalone enriched
|
||||
const optimization_suggestions = []
|
||||
for (const group of rootCauseGroups) {
|
||||
const p = allFindings.find(f => f.id === group.primary_id)
|
||||
if (p?.optimization?.approach) {
|
||||
optimization_suggestions.push({ title: `Fix root cause: ${group.root_cause}`,
|
||||
approach: p.optimization.approach, alternative: p.optimization.alternative || '',
|
||||
tradeoff: p.optimization.tradeoff || '', affected_findings: group.finding_ids,
|
||||
fix_strategy: p.fix_strategy || 'minimal', fix_complexity: p.fix_complexity || 'medium',
|
||||
estimated_impact: `Resolves ${group.finding_ids.length} findings` })
|
||||
}
|
||||
}
|
||||
for (const f of enrichedFindings) {
|
||||
if (grouped.has(f.id) || !f.optimization?.approach || f.severity === 'low' || f.severity === 'info') continue
|
||||
optimization_suggestions.push({ title: `${f.id}: ${f.title}`,
|
||||
approach: f.optimization.approach, alternative: f.optimization.alternative || '',
|
||||
tradeoff: f.optimization.tradeoff || '', affected_findings: [f.id],
|
||||
fix_strategy: f.fix_strategy || 'minimal', fix_complexity: f.fix_complexity || 'medium',
|
||||
estimated_impact: 'Resolves 1 finding' })
|
||||
}
|
||||
|
||||
// 2d: Metrics
|
||||
const by_dimension = {}, by_severity = {}, dimension_severity_matrix = {}
|
||||
for (const f of allFindings) {
|
||||
by_dimension[f.dimension] = (by_dimension[f.dimension] || 0) + 1
|
||||
by_severity[f.severity] = (by_severity[f.severity] || 0) + 1
|
||||
if (!dimension_severity_matrix[f.dimension]) dimension_severity_matrix[f.dimension] = {}
|
||||
dimension_severity_matrix[f.dimension][f.severity] = (dimension_severity_matrix[f.dimension][f.severity] || 0) + 1
|
||||
}
|
||||
const fixable = allFindings.filter(f => f.fix_strategy !== 'skip')
|
||||
const autoFixable = fixable.filter(f => f.fix_complexity === 'low' && f.fix_strategy === 'minimal')
|
||||
```
|
||||
|
||||
### Step 3: Write review-report.json
|
||||
|
||||
```javascript
|
||||
const reviewReport = {
|
||||
review_id: `rev-${Date.now()}`, review_date: new Date().toISOString(),
|
||||
findings: allFindings, critical_files, optimization_suggestions, root_cause_groups: rootCauseGroups,
|
||||
summary: { total: allFindings.length, deep_analyzed: enrichedFindings.length,
|
||||
pass_through: pass_through.length, by_dimension, by_severity, dimension_severity_matrix,
|
||||
fixable_count: fixable.length, auto_fixable_count: autoFixable.length,
|
||||
critical_file_count: critical_files.length, optimization_count: optimization_suggestions.length }
|
||||
}
|
||||
Bash(`mkdir -p "${sessionFolder}/review"`)
|
||||
Write(`${sessionFolder}/review/review-report.json`, JSON.stringify(reviewReport, null, 2))
|
||||
```
|
||||
|
||||
### Step 4: Write review-report.md
|
||||
|
||||
```javascript
|
||||
const dims = ['security','correctness','performance','maintainability']
|
||||
const sevs = ['critical','high','medium','low','info']
|
||||
const S = reviewReport.summary
|
||||
|
||||
// Dimension x Severity matrix
|
||||
let mx = '| Dimension | Critical | High | Medium | Low | Info | Total |\n|---|---|---|---|---|---|---|\n'
|
||||
for (const d of dims) {
|
||||
mx += `| ${d} | ${sevs.map(s => dimension_severity_matrix[d]?.[s]||0).join(' | ')} | ${by_dimension[d]||0} |\n`
|
||||
}
|
||||
mx += `| **Total** | ${sevs.map(s => by_severity[s]||0).join(' | ')} | **${S.total}** |\n`
|
||||
|
||||
// Critical+High findings table
|
||||
const ch = allFindings.filter(f => f.severity==='critical'||f.severity==='high')
|
||||
.sort((a,b) => (a.severity==='critical'?0:1)-(b.severity==='critical'?0:1))
|
||||
let ft = '| ID | Sev | Dim | File:Line | Title | Fix |\n|---|---|---|---|---|---|\n'
|
||||
if (ch.length) ch.forEach(f => { ft += `| ${f.id} | ${f.severity} | ${f.dimension} | ${f.location?.file}:${f.location?.line} | ${f.title} | ${f.fix_strategy||'-'} |\n` })
|
||||
else ft += '| - | - | - | - | No critical/high findings | - |\n'
|
||||
|
||||
// Optimization suggestions
|
||||
let os = optimization_suggestions.map((o,i) =>
|
||||
`### ${i+1}. ${o.title}\n- **Approach**: ${o.approach}\n${o.tradeoff?`- **Tradeoff**: ${o.tradeoff}\n`:''}- **Strategy**: ${o.fix_strategy} | **Complexity**: ${o.fix_complexity} | ${o.estimated_impact}`
|
||||
).join('\n\n') || '_No optimization suggestions._'
|
||||
|
||||
// Critical files
|
||||
const cf = critical_files.slice(0,10).map(c =>
|
||||
`- **${c.file}** (${c.finding_count} findings, dims: ${c.dimensions.join(', ')})`
|
||||
).join('\n') || '_No critical files._'
|
||||
|
||||
// Fix scope
|
||||
const fs = [
|
||||
by_severity.critical ? `${by_severity.critical} critical (must fix)` : '',
|
||||
by_severity.high ? `${by_severity.high} high (should fix)` : '',
|
||||
autoFixable.length ? `${autoFixable.length} auto-fixable (low effort)` : ''
|
||||
].filter(Boolean).map(s => `- ${s}`).join('\n') || '- No actionable findings.'
|
||||
|
||||
Write(`${sessionFolder}/review/review-report.md`,
|
||||
`# Review Report
|
||||
|
||||
**ID**: ${reviewReport.review_id} | **Date**: ${reviewReport.review_date}
|
||||
**Findings**: ${S.total} | **Fixable**: ${S.fixable_count} | **Auto-fixable**: ${S.auto_fixable_count}
|
||||
|
||||
## Executive Summary
|
||||
- Deep analyzed: ${S.deep_analyzed} | Pass-through: ${S.pass_through}
|
||||
- Critical files: ${S.critical_file_count} | Optimizations: ${S.optimization_count}
|
||||
|
||||
## Metrics Matrix
|
||||
${mx}
|
||||
## Critical & High Findings
|
||||
${ft}
|
||||
## Critical Files
|
||||
${cf}
|
||||
|
||||
## Optimization Suggestions
|
||||
${os}
|
||||
|
||||
## Recommended Fix Scope
|
||||
${fs}
|
||||
|
||||
**Total fixable**: ${S.fixable_count} / ${S.total}
|
||||
`)
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| Enriched findings missing | Use empty array, report pass_through only |
|
||||
| JSON parse failure | Log warning, use raw findings |
|
||||
| Session folder missing | Create review subdir via mkdir |
|
||||
| Empty allFindings | Write minimal "clean" report |
|
||||
Reference in New Issue
Block a user