Files
clawdbot/scripts/postinstall.js

111 lines
3.0 KiB
JavaScript

import { spawnSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
function isBunInstall() {
const ua = process.env.npm_config_user_agent ?? "";
return ua.includes("bun/");
}
function getRepoRoot() {
const here = path.dirname(fileURLToPath(import.meta.url));
return path.resolve(here, "..");
}
function run(cmd, args, opts = {}) {
const res = spawnSync(cmd, args, { stdio: "inherit", ...opts });
if (typeof res.status === "number") return res.status;
return 1;
}
function applyPatchIfNeeded(opts) {
const patchPath = path.resolve(opts.patchPath);
if (!fs.existsSync(patchPath)) {
throw new Error(`missing patch: ${patchPath}`);
}
let targetDir = path.resolve(opts.targetDir);
if (!fs.existsSync(targetDir) || !fs.statSync(targetDir).isDirectory()) {
console.warn(`[postinstall] skip missing target: ${targetDir}`);
return;
}
// Resolve symlinks to avoid "beyond a symbolic link" errors from git apply
// (bun/pnpm use symlinks in node_modules)
targetDir = fs.realpathSync(targetDir);
const gitArgsBase = ["apply", "--unsafe-paths", "--whitespace=nowarn"];
const reverseCheck = [
...gitArgsBase,
"--reverse",
"--check",
"--directory",
targetDir,
patchPath,
];
const forwardCheck = [
...gitArgsBase,
"--check",
"--directory",
targetDir,
patchPath,
];
const apply = [...gitArgsBase, "--directory", targetDir, patchPath];
// Already applied?
if (run("git", reverseCheck, { stdio: "ignore" }) === 0) {
return;
}
if (run("git", forwardCheck, { stdio: "ignore" }) !== 0) {
throw new Error(`patch does not apply cleanly: ${path.basename(patchPath)}`);
}
const status = run("git", apply);
if (status !== 0) {
throw new Error(`failed applying patch: ${path.basename(patchPath)}`);
}
}
function extractPackageName(key) {
if (key.startsWith("@")) {
const idx = key.indexOf("@", 1);
if (idx === -1) return key;
return key.slice(0, idx);
}
const idx = key.lastIndexOf("@");
if (idx <= 0) return key;
return key.slice(0, idx);
}
function main() {
if (!isBunInstall()) return;
const repoRoot = getRepoRoot();
process.chdir(repoRoot);
const pkgPath = path.join(repoRoot, "package.json");
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
const patched = pkg?.pnpm?.patchedDependencies ?? {};
// Bun does not support pnpm.patchedDependencies. Apply these patch files to
// node_modules packages as a best-effort compatibility layer.
for (const [key, relPatchPath] of Object.entries(patched)) {
if (typeof relPatchPath !== "string" || !relPatchPath.trim()) continue;
const pkgName = extractPackageName(String(key));
if (!pkgName) continue;
applyPatchIfNeeded({
targetDir: path.join("node_modules", ...pkgName.split("/")),
patchPath: relPatchPath,
});
}
}
try {
main();
} catch (err) {
console.error(String(err));
process.exit(1);
}