Files
WRNexusJS/scripts/repair-workspace.mjs
T
2026-08-01 10:04:42 +05:30

100 lines
3.2 KiB
JavaScript

import console from "node:console";
import { execFileSync } from "node:child_process";
import { existsSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import process from "node:process";
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
const dryRun = process.argv.includes("--check");
const removed = [];
const untracked = [];
const warnings = [];
function removeLocal(path) {
const absolute = join(root, path);
if (!existsSync(absolute)) return;
if (!dryRun) unlinkSync(absolute);
removed.push(path);
}
function git(args, capture = false) {
return execFileSync("git", args, {
cwd: root,
encoding: "utf8",
stdio: capture ? ["ignore", "pipe", "pipe"] : ["ignore", "ignore", "pipe"],
});
}
function isGitRepository() {
try {
return git(["rev-parse", "--is-inside-work-tree"], true).trim() === "true";
} catch {
return false;
}
}
function trackedFiles() {
try {
return git(["ls-files", "-z"], true).split("\0").filter(Boolean);
} catch {
return [];
}
}
function ensureIgnoreRules() {
const path = join(root, ".gitignore");
const current = existsSync(path) ? readFileSync(path, "utf8") : "";
const required = [
".env",
".env.*",
"!.env.example",
"!.env.*.example",
"focus-shims.d.ts",
"tsconfig.focus.json",
];
const lines = new Set(current.split(/\r?\n/).map((line) => line.trim()));
const missing = required.filter((line) => !lines.has(line));
if (missing.length === 0) return;
if (!dryRun) {
const separator = current.length > 0 && !current.endsWith("\n") ? "\n" : "";
writeFileSync(path, `${current}${separator}${missing.join("\n")}\n`);
}
warnings.push(`Added missing .gitignore rules: ${missing.join(", ")}`);
}
removeLocal("focus-shims.d.ts");
removeLocal("tsconfig.focus.json");
ensureIgnoreRules();
if (isGitRepository()) {
const secretPattern = /(?:^|\/)(?:\.env(?:\..+)?|id_rsa|id_ed25519|.*\.(?:pem|p12|pfx|key))$/i;
const safeTemplate = /(?:^|\/)\.env(?:\.[^/]+)*\.(?:example|sample|template)$/i;
const temporaryPattern = /(?:^|\/)(?:focus-shims\.d\.ts|tsconfig\.focus\.json)$/i;
const unsafeTracked = trackedFiles().filter(
(path) => temporaryPattern.test(path) || (secretPattern.test(path) && !safeTemplate.test(path)),
);
for (const path of unsafeTracked) {
if (!dryRun) git(["rm", "--cached", "--ignore-unmatch", "--", path]);
untracked.push(path);
}
} else {
warnings.push(
"Git metadata was not found, so tracked secret files could not be removed from the Git index.",
);
}
console.log(dryRun ? "Workspace repair check:" : "Workspace repaired:");
console.log(
`- ${dryRun ? "would remove" : "removed"} temporary files: ${removed.length ? removed.join(", ") : "none"}`,
);
console.log(
`- ${dryRun ? "would remove" : "removed"} from Git tracking: ${untracked.length ? untracked.join(", ") : "none"}`,
);
for (const warning of warnings) console.warn(`- warning: ${warning}`);
if (dryRun && (removed.length > 0 || untracked.length > 0)) {
console.error("Workspace repair is required. Run: bun run repair:workspace");
process.exitCode = 1;
}