mirror of
https://github.com/aiclientproxy/proxycast.git
synced 2026-09-24 23:10:56 +08:00
315 lines
8.4 KiB
JavaScript
315 lines
8.4 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { execFileSync } from "node:child_process";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import process from "node:process";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
import {
|
|
buildGeneratedSlopReport,
|
|
renderGeneratedSlopMarkdown,
|
|
renderGeneratedSlopText,
|
|
} from "./lib/generated-slop-report-core.mjs";
|
|
import { buildLiveDocFreshnessReport } from "./check-doc-freshness.mjs";
|
|
import {
|
|
buildLegacySurfaceReport,
|
|
toSerializableLegacySurfaceReport,
|
|
} from "./report-legacy-surfaces.mjs";
|
|
|
|
const TREND_REPORT_PATH = "scripts/harness-eval-trend-report.mjs";
|
|
|
|
export {
|
|
buildGeneratedSlopReport,
|
|
renderGeneratedSlopMarkdown,
|
|
renderGeneratedSlopText,
|
|
} from "./lib/generated-slop-report-core.mjs";
|
|
|
|
function parseArgs(argv) {
|
|
const result = {
|
|
format: "text",
|
|
help: false,
|
|
docFreshnessInput: "",
|
|
legacyInput: "",
|
|
manifest: "",
|
|
outputJson: "",
|
|
outputMarkdown: "",
|
|
trendHistoryDir: "",
|
|
trendInput: "",
|
|
workspaceRoot: process.cwd(),
|
|
};
|
|
|
|
for (let index = 0; index < argv.length; index += 1) {
|
|
const arg = argv[index];
|
|
|
|
if (arg === "--trend-input" && argv[index + 1]) {
|
|
result.trendInput = String(argv[index + 1]).trim();
|
|
index += 1;
|
|
continue;
|
|
}
|
|
|
|
if (arg === "--manifest" && argv[index + 1]) {
|
|
result.manifest = String(argv[index + 1]).trim();
|
|
index += 1;
|
|
continue;
|
|
}
|
|
|
|
if (arg === "--doc-freshness-input" && argv[index + 1]) {
|
|
result.docFreshnessInput = String(argv[index + 1]).trim();
|
|
index += 1;
|
|
continue;
|
|
}
|
|
|
|
if (arg === "--legacy-input" && argv[index + 1]) {
|
|
result.legacyInput = String(argv[index + 1]).trim();
|
|
index += 1;
|
|
continue;
|
|
}
|
|
|
|
if (arg === "--trend-history-dir" && argv[index + 1]) {
|
|
result.trendHistoryDir = String(argv[index + 1]).trim();
|
|
index += 1;
|
|
continue;
|
|
}
|
|
|
|
if (arg === "--workspace-root" && argv[index + 1]) {
|
|
result.workspaceRoot = String(argv[index + 1]).trim();
|
|
index += 1;
|
|
continue;
|
|
}
|
|
|
|
if (arg === "--format" && argv[index + 1]) {
|
|
result.format = String(argv[index + 1]).trim();
|
|
index += 1;
|
|
continue;
|
|
}
|
|
|
|
if (arg === "--output-json" && argv[index + 1]) {
|
|
result.outputJson = String(argv[index + 1]).trim();
|
|
index += 1;
|
|
continue;
|
|
}
|
|
|
|
if (arg === "--output-markdown" && argv[index + 1]) {
|
|
result.outputMarkdown = String(argv[index + 1]).trim();
|
|
index += 1;
|
|
continue;
|
|
}
|
|
|
|
if (arg === "--help" || arg === "-h") {
|
|
result.help = true;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
function printHelp() {
|
|
console.log(`
|
|
Lime Harness Cleanup / Slop Report
|
|
|
|
用法:
|
|
node scripts/report-generated-slop.mjs
|
|
node scripts/report-generated-slop.mjs --manifest "./tmp/harness-evals.manifest.json"
|
|
node scripts/report-generated-slop.mjs --trend-input "./tmp/harness-eval-trend.json"
|
|
node scripts/report-generated-slop.mjs --doc-freshness-input "./tmp/doc-freshness.json"
|
|
node scripts/report-generated-slop.mjs --legacy-input "./tmp/legacy-surface-report.json"
|
|
node scripts/report-generated-slop.mjs --trend-history-dir "./artifacts/history"
|
|
node scripts/report-generated-slop.mjs --output-json "./tmp/harness-cleanup-report.json" --output-markdown "./tmp/harness-cleanup-report.md"
|
|
|
|
选项:
|
|
--manifest PATH 透传给 harness eval trend/runner,覆盖默认 manifest
|
|
--trend-input PATH 显式指定 harness eval trend JSON
|
|
--doc-freshness-input PATH 显式指定 doc freshness JSON
|
|
--legacy-input PATH 显式指定 governance / legacy surface report JSON
|
|
--trend-history-dir PATH 透传给 trend report,用历史 summary 生成趋势
|
|
--workspace-root PATH 未提供 trend-input 时,用该工作区生成当前 trend 报告
|
|
--format FMT 标准输出格式:text | json | markdown
|
|
--output-json PATH 将 cleanup/slop 报告 JSON 写入指定路径
|
|
--output-markdown PATH 将 cleanup/slop 报告 Markdown 写入指定路径
|
|
-h, --help 显示帮助
|
|
`);
|
|
}
|
|
|
|
function resolvePath(baseDir, targetPath) {
|
|
return path.resolve(baseDir, targetPath);
|
|
}
|
|
|
|
function ensureParentDirectory(filePath) {
|
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
}
|
|
|
|
function readJsonFile(filePath) {
|
|
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
}
|
|
|
|
function detectDefaultTrendHistoryDir(repoRoot) {
|
|
const candidates = [
|
|
resolvePath(repoRoot, "./.lime/harness/history"),
|
|
resolvePath(repoRoot, "./artifacts/history"),
|
|
];
|
|
|
|
for (const candidate of candidates) {
|
|
if (!fs.existsSync(candidate)) {
|
|
continue;
|
|
}
|
|
|
|
const hasJson = fs
|
|
.readdirSync(candidate, { withFileTypes: true })
|
|
.some((entry) => entry.isFile() && entry.name.endsWith(".json"));
|
|
|
|
if (hasJson) {
|
|
return candidate;
|
|
}
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
function buildTrendReport(repoRoot, options) {
|
|
if (options.trendInput) {
|
|
const resolvedPath = resolvePath(repoRoot, options.trendInput);
|
|
return {
|
|
report: readJsonFile(resolvedPath),
|
|
source: {
|
|
kind: "input-json",
|
|
path: resolvedPath,
|
|
},
|
|
};
|
|
}
|
|
|
|
const nodeCommand = process.execPath;
|
|
const trendScriptPath = resolvePath(repoRoot, TREND_REPORT_PATH);
|
|
const args = [trendScriptPath, "--format", "json"];
|
|
const effectiveHistoryDir =
|
|
options.trendHistoryDir || detectDefaultTrendHistoryDir(repoRoot);
|
|
|
|
if (options.manifest) {
|
|
args.push("--manifest", options.manifest);
|
|
}
|
|
|
|
if (effectiveHistoryDir) {
|
|
args.push("--history-dir", effectiveHistoryDir);
|
|
}
|
|
|
|
if (options.workspaceRoot) {
|
|
args.push("--workspace-root", options.workspaceRoot);
|
|
}
|
|
|
|
const output = execFileSync(nodeCommand, args, {
|
|
cwd: repoRoot,
|
|
encoding: "utf8",
|
|
stdio: ["ignore", "pipe", "inherit"],
|
|
});
|
|
|
|
return {
|
|
report: JSON.parse(output),
|
|
source: {
|
|
kind: effectiveHistoryDir ? "generated-history" : "generated-current",
|
|
path: effectiveHistoryDir
|
|
? resolvePath(repoRoot, effectiveHistoryDir)
|
|
: "",
|
|
},
|
|
};
|
|
}
|
|
|
|
function buildGovernanceReport(repoRoot, options) {
|
|
if (options.legacyInput) {
|
|
const resolvedPath = resolvePath(repoRoot, options.legacyInput);
|
|
return {
|
|
report: readJsonFile(resolvedPath),
|
|
source: {
|
|
kind: "input-json",
|
|
path: resolvedPath,
|
|
},
|
|
};
|
|
}
|
|
|
|
return {
|
|
report: toSerializableLegacySurfaceReport(buildLegacySurfaceReport()),
|
|
source: {
|
|
kind: "live-scan",
|
|
path: "",
|
|
},
|
|
};
|
|
}
|
|
|
|
function buildDocFreshnessReport(repoRoot, options) {
|
|
if (options.docFreshnessInput) {
|
|
const resolvedPath = resolvePath(repoRoot, options.docFreshnessInput);
|
|
return {
|
|
report: readJsonFile(resolvedPath),
|
|
source: {
|
|
kind: "input-json",
|
|
path: resolvedPath,
|
|
},
|
|
};
|
|
}
|
|
|
|
return {
|
|
report: buildLiveDocFreshnessReport(repoRoot),
|
|
source: {
|
|
kind: "live-scan",
|
|
path: "",
|
|
},
|
|
};
|
|
}
|
|
|
|
function renderOutput(report, format) {
|
|
if (format === "json") {
|
|
return `${JSON.stringify(report, null, 2)}\n`;
|
|
}
|
|
|
|
if (format === "markdown") {
|
|
return renderGeneratedSlopMarkdown(report);
|
|
}
|
|
|
|
return renderGeneratedSlopText(report);
|
|
}
|
|
|
|
function runGeneratedSlopReportCli() {
|
|
const options = parseArgs(process.argv.slice(2));
|
|
if (options.help) {
|
|
printHelp();
|
|
return;
|
|
}
|
|
|
|
const repoRoot = process.cwd();
|
|
const trendResult = buildTrendReport(repoRoot, options);
|
|
const docFreshnessResult = buildDocFreshnessReport(repoRoot, options);
|
|
const governanceResult = buildGovernanceReport(repoRoot, options);
|
|
const report = buildGeneratedSlopReport({
|
|
repoRoot,
|
|
trendReport: trendResult.report,
|
|
docFreshnessReport: docFreshnessResult.report,
|
|
governanceReport: governanceResult.report,
|
|
sources: {
|
|
trend: trendResult.source,
|
|
docFreshness: docFreshnessResult.source,
|
|
governance: governanceResult.source,
|
|
},
|
|
});
|
|
|
|
if (options.outputJson) {
|
|
const targetPath = resolvePath(repoRoot, options.outputJson);
|
|
ensureParentDirectory(targetPath);
|
|
fs.writeFileSync(targetPath, `${JSON.stringify(report, null, 2)}\n`, "utf8");
|
|
}
|
|
|
|
if (options.outputMarkdown) {
|
|
const targetPath = resolvePath(repoRoot, options.outputMarkdown);
|
|
ensureParentDirectory(targetPath);
|
|
fs.writeFileSync(targetPath, renderGeneratedSlopMarkdown(report), "utf8");
|
|
}
|
|
|
|
process.stdout.write(renderOutput(report, options.format));
|
|
}
|
|
|
|
const isMainModule =
|
|
process.argv[1] &&
|
|
path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
|
|
|
|
if (isMainModule) {
|
|
runGeneratedSlopReportCli();
|
|
}
|