chore: restore original directory structure (project under code-review-graph-main/)

This commit is contained in:
AuraK Developer
2026-08-31 13:08:20 +08:00
parent ecc55158c1
commit ecfd03a21c
404 changed files with 0 additions and 0 deletions
@@ -0,0 +1,238 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>代码审查报告</title>
<style>
:root { --border:#d0d7de; --bg:#f6f8fa; --fg:#1f2328; --muted:#57606a;
--good:#1a7f37; --warn:#9a6700; --fail:#cf222e; --na:#57606a;
--blocker:#cf222e; --major:#9a6700; --minor:#57606a;
--critical:#cf222e; --informational:#0969da; }
* { box-sizing: border-box; }
body { font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
margin:0; padding:2rem 1rem; color:var(--fg); background:#fff; line-height:1.55; }
.wrap { max-width:960px; margin:0 auto; }
h1 { font-size:1.5rem; margin:0 0 .25rem; }
h2 { font-size:1.1rem; margin:1.5rem 0 .5rem; padding-bottom:.25rem;
border-bottom:1px solid var(--border); }
.meta { color:var(--muted); font-size:.9rem; margin-bottom:1.5rem; }
.verdict { display:inline-block; padding:.25rem .75rem; border-radius:20px;
font-weight:700; font-size:.95rem; }
.verdict.pass { background:#dafbe1; color:var(--good); }
.verdict.fail { background:#ffebe9; color:var(--fail); }
table { border-collapse:collapse; width:100%; margin:.75rem 0; }
th,td { border:1px solid var(--border); padding:.45rem .6rem; text-align:left;
font-size:.9rem; vertical-align:top; }
th { background:var(--bg); }
.grade.good { color:var(--good); font-weight:600; }
.grade.warn { color:var(--warn); font-weight:600; }
.grade.fail { color:var(--fail); font-weight:600; }
.grade.na { color:var(--na); }
.issue { margin:.6rem 0; padding:.65rem .8rem; border:1px solid var(--border);
border-radius:6px; background:#fff; }
.issue .tag { display:inline-block; padding:.1rem .5rem; border-radius:10px;
font-size:.75rem; font-weight:700; color:#fff; margin-right:.5rem; }
.tag.blocker, .tag.critical { background:var(--blocker); }
.tag.major, .tag.warn { background:var(--major); }
.tag.minor, .tag.informational { background:var(--minor); }
.issue .cat { font-weight:600; }
.issue .loc { color:var(--muted); font-size:.85rem; margin-top:.2rem; }
.issue .fix { margin-top:.35rem; font-size:.88rem; background:var(--bg);
padding:.4rem .6rem; border-radius:4px; }
.muted { color:var(--muted); font-size:.85rem; }
code { background:var(--bg); padding:.1rem .3rem; border-radius:4px;
font-size:.88em; }
details.reviewed { margin:.5rem 0; border:1px solid var(--border);
border-radius:6px; padding:.4rem .8rem; }
details.reviewed summary { cursor:pointer; font-weight:600; }
details.reviewed ul { margin:.4rem 0 0; padding-left:1.2rem; }
details.reviewed li { margin:.15rem 0; }
</style>
</head>
<body>
<div class="wrap" id="app"></div>
<script>
const data = {{REPORT_DATA}};
function esc(s) {
return String(s ?? "").replace(/[&<>"']/g, c => ({
"&":"&amp;", "<":"&lt;", ">":"&gt;", '"':"&quot;", "'":"&#39;"
})[c]);
}
function verdictClass(v) {
v = String(v || "").toUpperCase();
return v.includes("PASS") ? "pass" : "fail";
}
// Collapsible list of the reviewed files (native <details>/<summary>, no JS).
// Accepts an array OR a comma-separated string (agents pass both). Falls
// back to the flat ``files`` string when nothing structured is given.
function renderReviewedFiles(data) {
let arr = data.reviewed_files;
if (typeof arr === "string") {
arr = arr.split(",").map(s => s.trim()).filter(Boolean);
}
if (!Array.isArray(arr) || !arr.length) {
return data.files ? `<p><b>文件:</b> ${esc(data.files)}</p>` : "";
}
return `<details class="reviewed">
<summary>审查文件 (${arr.length}) <span class="muted">点击展开/收起</span></summary>
<ul>${arr.map(f => `<li><code>${esc(f)}</code></li>`).join("")}</ul>
</details>`;
}
const metricLabels = {
sql_risk: "SQL 注入风险",
exception_coverage: "异常分支覆盖",
redundancy_rate: "代码冗余率",
high_risk_density: "高风险场景密度",
vulnerability_risk: "漏洞风险",
};
const gradeLabels = { good: "良好", warn: "警告", fail: "不合格", na: "不适用" };
const sevLabels = {
blocker: "🔴 阻塞", critical: "🔴 严重",
major: "🟡 主要", warn: "🟡 主要",
minor: "🔵 次要", informational: "🔵 次要",
};
let html = `<h1>代码审查报告</h1>
<div class="meta">
<span class="verdict ${verdictClass(data.verdict)}">${esc(data.verdict || "无结论")}</span>
&nbsp; 档位: <code>${esc(data.tier || "standard")}</code>
&nbsp; 范围: <code>${esc(data.scope || "change-level")}</code>
${data.baseline ? `&nbsp; 基线: <code>${esc(data.baseline)}</code>` : ""}
</div>`;
if (data.quality_score != null) html += `<p><b>PR 质量分:</b> ${esc(data.quality_score)}/10</p>`;
if (data.timestamp) html += `<p class="muted">生成时间: ${esc(data.timestamp)}</p>`;
html += renderReviewedFiles(data);
if (data.summary) html += `<p>${esc(data.summary)}</p>`;
const cov = data.coverage || {};
// The coverage section renders whenever file-count coverage OR line/unit
// coverage was computed. gate="line+unit" (feature reviews) returns
// coverage_pct=null, so the 全库/高风险 rows are skipped and only the
// line/unit rows + spot-check render.
if (cov && (cov.coverage_pct != null || cov.line_coverage_pct != null)) {
const isLineOnly = cov.coverage_pct == null;
const covOk = cov.target_reached;
const covCls = covOk ? "good" : "fail";
const covStatus = covOk ? "✅ 达标" : "🔴 覆盖不足";
const oTarget = cov.overall_target ?? cov.target ?? "N/A";
const hTarget = cov.high_risk_target ?? cov.target ?? "N/A";
html += `<h2>覆盖度</h2>
<p><span class="verdict ${covCls}">${covStatus}</span></p>`;
if (!isLineOnly) {
html += `<p><b>全库覆盖:</b> ${esc(cov.coverage_pct ?? "N/A")}% — 已深读 ${esc(cov.deep_read_count ?? "N/A")}/${esc(cov.total_files ?? "N/A")}(目标 ${esc(oTarget)}%</p>
<p><b>高风险覆盖:</b> ${esc(cov.high_risk_coverage_pct ?? "N/A")}% — 已深读 ${esc(cov.high_risk_deep_count ?? "N/A")}/${esc(cov.high_risk_total_files ?? "N/A")}(目标 ${esc(hTarget)}%</p>`;
}
html += renderLineUnit(cov);
html += renderSpotCheck(data.spot_check);
if (!isLineOnly && (cov.uncovered_files || []).length) {
html += `<p class="muted"><b>未深读文件:</b> ${esc(cov.uncovered_files.length)} 个(静默文件 ${esc((cov.silent_files || []).length)} 个)</p>`;
}
}
// Line / unit coverage (three-piece suite items 1-2). Fail-closed: a
// missing line/unit coverage renders "未执行 🔴" so reviews that skipped
// gate="both+line" or the three-piece data are visible, never silent green.
function renderLineUnit(cov) {
const linePct = cov.line_coverage_pct;
const unitPct = cov.unit_coverage_pct;
const lineTarget = cov.line_target ?? 95.0;
const unitTarget = cov.unit_target ?? 100.0;
const lineGap = (cov.line_gap_files || []).length;
const unitGap = (cov.unit_gap_files || []).length;
const missing = (cov.missing_data_files || []).length;
let s = "";
if (linePct == null || unitPct == null) {
s += `<p><b>行覆盖:</b> 未执行 🔴 <span class="muted">(coverage_tool 未用 gate="both+line" 或未传三件套数据)</span></p>`;
} else {
const lineOk = linePct >= lineTarget && lineGap === 0;
const unitOk = unitPct >= unitTarget && unitGap === 0;
s += `<p><b>行覆盖:</b> ${esc(linePct)}% — 目标 ${esc(lineTarget)}%(缺口 ${esc(lineGap)} 文件)${lineOk ? "✅" : "🔴"}</p>`;
s += `<p><b>单元覆盖:</b> ${esc(unitPct)}% — 目标 ${esc(unitTarget)}%(缺口 ${esc(unitGap)} 文件)${unitOk ? "✅" : "🔴"}</p>`;
}
if (missing) {
s += `<p class="muted"><b>三件套数据缺失:</b> ${esc(missing)} 个文件(缺 read_ranges/语义单元,已按 fail-closed 计为缺口)</p>`;
}
return s;
}
// Anti-fake spot check (three-piece suite item 3). Fail-closed: a
// missing/incomplete spot_check renders "未执行 🔴" so reviews that
// skipped the sampled re-read are visible instead of silently green.
function renderSpotCheck(spot) {
if (!spot) {
return `<p><b>防伪抽验:</b> 未执行 🔴 <span class="muted">(主代理未回读任何语义单元;Step 5.5 应执行每组抽 2 文件 × 2-3 单元并落盘 spot_check)</span></p>`;
}
const groups = spot.groups_sampled;
const files = spot.files_sampled;
const units = spot.units_sampled;
const fake = spot.fake_read_found || 0;
const rereread = spot.groups_rereread || [];
if (!units) {
return `<p><b>防伪抽验:</b> 未执行 🔴 <span class="muted">(spot_check 已上报但单元数为 0)</span></p>`;
}
const mark = (fake || rereread.length) ? "🔴 发现假读" : "✅";
let s = `<p><b>防伪抽验:</b> 抽样 ${esc(files)} 文件 / ${esc(units)} 单元 / ${esc(groups)} 组,假读 ${esc(fake)} ${mark}</p>`;
if (rereread.length) {
s += `<p class="muted">因假读重读组:${esc(rereread.join(", "))}</p>`;
}
return s;
}
const metrics = data.metrics || {};
const mkeys = Object.keys(metrics);
if (mkeys.length) {
html += `<h2>客观指标</h2><table><tr><th>指标</th><th>数值</th><th>评级</th><th>说明</th></tr>`;
for (const k of mkeys) {
const m = metrics[k] || {};
const g = m.grade || "na";
const label = metricLabels[k] || k;
const gradeText = gradeLabels[g] || g;
html += `<tr>
<td>${esc(label)}</td>
<td>${esc(m.value ?? "N/A")}</td>
<td class="grade ${esc(g)}">${esc(gradeText)}</td>
<td class="muted">${esc(m.note || "")}</td>
</tr>`;
}
html += `</table>`;
}
const issues = data.issues || [];
html += `<h2>问题清单 (${issues.length})</h2>`;
if (!issues.length) {
html += `<p class="muted">未发现问题。</p>`;
}
for (const i of issues) {
const sev = (i.severity || "minor").toLowerCase();
const sevLabel = sevLabels[sev] || i.severity;
html += `<div class="issue">
<span class="tag ${esc(sev)}">${esc(sevLabel)}</span>
<span class="cat">${esc(i.category)}</span>
${esc(i.message || "")}
${i.confidence != null ? `<span class="muted">(置信度 ${esc(i.confidence)}/10)</span>` : ""}
${i.location ? `<div class="loc">→ ${esc(i.location)}</div>` : ""}
${i.fix ? `<div class="fix"><b>修复建议:</b> ${esc(i.fix)}</div>` : ""}
</div>`;
}
const manual = data.manual_review || [];
if (manual.length) {
html += `<h2>需要人工审查</h2><ul>`;
for (const m of manual) html += `<li>${esc(m)}</li>`;
html += `</ul>`;
}
const judged = data.llm_judged || [];
if (judged.length) {
html += `<p class="muted"><b>需 LLM 判断的指标:</b> ${judged.map(esc).join(", ")}</p>`;
}
document.getElementById("app").innerHTML = html;
</script>
</body>
</html>