← Files NaClARCHIVED FILE
skills/nacl-init/resources/bootstrap/rollback-project-bootstrap.mjs
2.89 KB · Oct 2, 2026 · 00:29 UTC
#!/usr/bin/env node
import { copyFileSync, existsSync, lstatSync, mkdirSync, renameSync, rmSync } from "node:fs";
import path from "node:path";
function stop(code) {
process.stderr.write(`NACL_ROLLBACK_FILES: status=FAILED code=${code}\n`);
process.exit(1);
}
const selected = {};
for (let index = 2; index < process.argv.length; index += 2) {
if (!process.argv[index]?.startsWith("--") || index + 1 >= process.argv.length) stop("ARGUMENT_INVALID");
selected[process.argv[index].slice(2)] = process.argv[index + 1];
}
for (const key of ["project-root", "graph-state", "config-state", "config-dir-state", "gitignore-state"]) if (!selected[key]) stop("ARGUMENT_MISSING");
const root = path.resolve(selected["project-root"]);
if (!path.isAbsolute(selected["project-root"]) || !existsSync(root) || lstatSync(root).isSymbolicLink() || !lstatSync(root).isDirectory()) stop("PROJECT_ROOT_UNSAFE");
for (const key of ["graph-state", "config-state", "config-dir-state", "gitignore-state"]) if (!new Set(["absent", "preexisting"]).has(selected[key])) stop("STATE_INVALID");
function safeBackup(filename) {
if (!filename || !path.isAbsolute(filename) || !existsSync(filename)) stop("BACKUP_UNAVAILABLE");
const metadata = lstatSync(filename);
if (!metadata.isFile() || metadata.isSymbolicLink()) stop("BACKUP_UNSAFE");
}
function restore(relative, state, backup) {
const target = path.join(root, relative);
if (state === "preexisting") {
safeBackup(backup);
mkdirSync(path.dirname(target), { recursive: true, mode: 0o700 });
const temporary = `${target}.nacl-rollback-${process.pid}.tmp`;
copyFileSync(backup, temporary);
renameSync(temporary, target);
} else if (existsSync(target)) {
const metadata = lstatSync(target);
if (!metadata.isFile() || metadata.isSymbolicLink()) stop("ROLLBACK_TARGET_UNSAFE");
rmSync(target);
}
}
try {
restore(path.join(".codex", "config.toml"), selected["config-state"], selected["config-backup"]);
restore(".gitignore", selected["gitignore-state"], selected["gitignore-backup"]);
const configDir = path.join(root, ".codex");
if (selected["config-dir-state"] === "absent" && existsSync(configDir)) {
const metadata = lstatSync(configDir);
if (!metadata.isDirectory() || metadata.isSymbolicLink()) stop("CODEX_DIR_ROLLBACK_UNSAFE");
try { rmSync(configDir); } catch (error) { if (error?.code !== "ENOTEMPTY") throw error; }
}
const graphDir = path.join(root, "graph-infra");
if (selected["graph-state"] === "absent" && existsSync(graphDir)) {
const metadata = lstatSync(graphDir);
if (!metadata.isDirectory() || metadata.isSymbolicLink()) stop("GRAPH_ROLLBACK_UNSAFE");
rmSync(graphDir, { recursive: true });
}
} catch {
stop("ROLLBACK_APPLY_FAILED");
}
process.stdout.write(`NACL_ROLLBACK_FILES: status=VERIFIED graph=${selected["graph-state"] === "absent" ? "removed" : "preserved-preexisting"} config=restored gitignore=restored\n`);
SHA-256: 31bdedf67199bc1c8696b28c993a391cbd57a3c71f5cf0e253bde9a6fa4a8d78