100 lines
3.2 KiB
JavaScript
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;
|
|
}
|