mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-15 06:04:43 +00:00
106 lines
2.8 KiB
TypeScript
106 lines
2.8 KiB
TypeScript
export type InstallCommandBlock = {
|
|
label: string;
|
|
commands: string[];
|
|
};
|
|
|
|
export type NonExecutableBinaryMessageOptions = {
|
|
binPath: string;
|
|
trustPackages: string;
|
|
bunInstallBlocks: InstallCommandBlock[];
|
|
genericInstallCommands?: string[];
|
|
binaryName?: string;
|
|
};
|
|
|
|
export type FsSubset = {
|
|
accessSync: (path: string, mode?: number) => void;
|
|
chmodSync: (path: string, mode: number) => void;
|
|
constants: { X_OK: number };
|
|
};
|
|
|
|
export function isBunRuntime(): boolean {
|
|
if (typeof process?.versions?.bun === "string") return true;
|
|
const userAgent = process?.env?.npm_config_user_agent || "";
|
|
return userAgent.includes("bun/");
|
|
}
|
|
|
|
const PERMISSION_ERRORS = new Set(["EACCES", "EPERM", "ENOEXEC"]);
|
|
|
|
function isPermissionError(error: unknown): boolean {
|
|
if (!error || typeof error !== "object") return false;
|
|
const code = (error as { code?: unknown }).code;
|
|
return typeof code === "string" && PERMISSION_ERRORS.has(code);
|
|
}
|
|
|
|
/**
|
|
* Checks if a binary is executable and attempts to make it executable if not.
|
|
* Returns true if the binary is (or was made) executable, false if it couldn't
|
|
* be made executable due to permission errors. Throws for other errors.
|
|
*
|
|
* Requires fs to be passed in to avoid static imports that break browser builds.
|
|
*/
|
|
export function assertExecutable(binPath: string, fs: FsSubset): boolean {
|
|
if (process.platform === "win32") {
|
|
return true;
|
|
}
|
|
|
|
try {
|
|
fs.accessSync(binPath, fs.constants.X_OK);
|
|
return true;
|
|
} catch {
|
|
// Not executable, try to fix
|
|
}
|
|
|
|
try {
|
|
fs.chmodSync(binPath, 0o755);
|
|
return true;
|
|
} catch (error) {
|
|
if (isPermissionError(error)) {
|
|
return false;
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
export function formatNonExecutableBinaryMessage(
|
|
options: NonExecutableBinaryMessageOptions,
|
|
): string {
|
|
const {
|
|
binPath,
|
|
trustPackages,
|
|
bunInstallBlocks,
|
|
genericInstallCommands,
|
|
binaryName,
|
|
} = options;
|
|
|
|
const label = binaryName ?? "sandbox-agent";
|
|
const lines = [`${label} binary is not executable: ${binPath}`];
|
|
|
|
if (isBunRuntime()) {
|
|
lines.push(
|
|
"Allow Bun to run postinstall scripts for native binaries and reinstall:",
|
|
);
|
|
for (const block of bunInstallBlocks) {
|
|
lines.push(`${block.label}:`);
|
|
for (const command of block.commands) {
|
|
lines.push(` ${command}`);
|
|
}
|
|
}
|
|
lines.push(`Or run: chmod +x "${binPath}"`);
|
|
return lines.join("\n");
|
|
}
|
|
|
|
lines.push(
|
|
"Postinstall scripts for native packages did not run, so the binary was left non-executable.",
|
|
);
|
|
if (genericInstallCommands && genericInstallCommands.length > 0) {
|
|
lines.push("Reinstall with scripts enabled:");
|
|
for (const command of genericInstallCommands) {
|
|
lines.push(` ${command}`);
|
|
}
|
|
} else {
|
|
lines.push("Reinstall with scripts enabled for:");
|
|
lines.push(` ${trustPackages}`);
|
|
}
|
|
lines.push(`Or run: chmod +x "${binPath}"`);
|
|
return lines.join("\n");
|
|
}
|