openclaw/scripts/check-duplicates.mts
Peter Steinberger 567d7d393c
refactor(scripts): deslop root scripts a–k (#159199)
Consolidate repeated CLI parsing, scanning, benchmark and release projections through their existing owners. Preserve script and CI contracts.

Fix malformed installer version diagnostics, flat ClawHub artifact sealing, completed polling sleep listener retention, and metadata output symlink confinement.
2026-09-27 01:08:19 -07:00

182 lines
4.5 KiB
TypeScript

import { spawnSync } from "node:child_process";
import path from "node:path";
import { resolveRepoToolBinPath } from "./lib/local-check-runtime.mts";
import { runManagedCommand } from "./lib/managed-child-process.mts";
import { resolveRepoRoot } from "./lib/repo-root.mjs";
const repoRoot = resolveRepoRoot(import.meta.url);
const jscpdBin = resolveRepoToolBinPath("jscpd", { cwd: repoRoot });
const targets = [
".github/actions",
".github/codeql/openclaw-boundary/tests",
"src",
"extensions",
"examples",
"scripts",
"packages",
"ui",
"apps",
"docs",
"qa",
"security",
"test",
"skills",
"config",
"cli-root-options.mjs",
"docker-entrypoint.mjs",
"gateway-run-argv.mjs",
"gateway-shutdown-budget.mjs",
"node-compile-cache.mjs",
"node-host-launcher.mjs",
"node-runtime-update.mjs",
"node-runtime-recovery.mjs",
"node-sqlite.mjs",
"node-version.mjs",
"openclaw.mjs",
"tsdown.ai.config.ts",
"tsdown.config.ts",
"vitest.config.ts",
];
const sourceExtensions = new Set([".ts", ".tsx", ".js", ".mjs", ".cjs"]);
const sourcePattern = "**/*.{ts,tsx,js,mjs,cjs}";
const testPattern = "**/*.{test,e2e.test,live.test}.{ts,tsx,js,mjs,cjs}";
// Keep local agent support trees and vendored snapshots classified but outside jscpd.
const intentionallyUnscannedPrefixes = [".agents/", "vendor/"];
const generatedIgnores = [
"**/node_modules/**",
"**/dist/**",
"**/.git/**",
"**/coverage/**",
"**/build/**",
"**/.build/**",
"**/.artifacts/**",
"vendor/**",
];
const testIgnores = ["test", "e2e.test", "live.test"].flatMap((suffix) =>
[...sourceExtensions].map((extension) => `**/*.${suffix}${extension}`),
);
const commonArgs = [
"--format",
"typescript,javascript",
"--min-lines",
"50",
"--min-tokens",
"300",
];
const json = process.argv.includes("--json");
const coverageOnly = process.argv.includes("--coverage");
function normalizeRepoPath(value: string) {
return value.split(path.sep).join("/");
}
function isUnderPrefix(value: string, prefix: string) {
return value === prefix.slice(0, -1) || value.startsWith(prefix);
}
function isCoveredByTargets(file: string) {
return targets.some((target) => {
const normalizedTarget = normalizeRepoPath(target);
if (file === normalizedTarget) {
return true;
}
return file.startsWith(`${normalizedTarget}/`);
});
}
function listTrackedSourceFiles() {
const result = spawnSync("git", ["ls-files", "-z"], {
cwd: repoRoot,
encoding: "utf8",
maxBuffer: 64 * 1024 * 1024,
});
if (result.status !== 0) {
throw new Error(result.stderr || "git ls-files failed");
}
return result.stdout
.split("\0")
.filter(Boolean)
.map(normalizeRepoPath)
.filter((file) => sourceExtensions.has(path.extname(file)))
.filter((file) => !intentionallyUnscannedPrefixes.some((prefix) => isUnderPrefix(file, prefix)))
.toSorted((left, right) => left.localeCompare(right));
}
function assertTargetCoverage() {
const uncovered = listTrackedSourceFiles().filter((file) => !isCoveredByTargets(file));
if (uncovered.length === 0) {
console.log(`[dup:check] target coverage ok`);
return true;
}
console.error(
"[dup:check] tracked duplicate-scan source files are outside scan targets or intentional excludes:",
);
for (const file of uncovered) {
console.error(` - ${file}`);
}
return false;
}
function reportArgs(name: string) {
if (!json) {
return ["--reporters", "console"];
}
return ["--reporters", "json", "--output", path.join(".artifacts", "jscpd", name)];
}
const scans = [
{
name: "production",
targets,
pattern: sourcePattern,
ignore: [...testIgnores, ...generatedIgnores],
},
{
name: "tests",
targets,
pattern: testPattern,
ignore: generatedIgnores,
},
...["src", "extensions", "test"].map((target) => ({
name: `${target}-mixed`,
targets: [target],
pattern: sourcePattern,
ignore: generatedIgnores,
})),
];
let failed = !assertTargetCoverage();
if (coverageOnly) {
process.exit(failed ? 1 : 0);
}
for (const scan of scans) {
console.log(`\n[dup:check] ${scan.name}`);
const status = await runManagedCommand({
bin: jscpdBin,
args: [
...scan.targets,
...commonArgs,
"--pattern",
scan.pattern,
"--ignore",
scan.ignore.join(","),
...reportArgs(scan.name),
],
cwd: repoRoot,
}).catch((error: unknown) => {
console.error(error);
return 1;
});
if (status !== 0) {
failed = true;
}
}
if (failed) {
process.exit(1);
}