mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-15 13:03:46 +00:00
refactor: consolidate executable check into assertExecutable helper
- Add assertExecutable() to cli-shared that checks and attempts chmod - Simplify CLI and SDK spawn code to use the shared helper - Fix cli-shared package.json exports (.js not .mjs) - Add global install instructions to SDK error message
This commit is contained in:
parent
048dcc5693
commit
7f07428621
4 changed files with 95 additions and 77 deletions
|
|
@ -15,7 +15,7 @@
|
|||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.mjs",
|
||||
"import": "./dist/index.js",
|
||||
"require": "./dist/index.cjs"
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -10,18 +10,54 @@ export type NonExecutableBinaryMessageOptions = {
|
|||
genericInstallCommands?: 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/");
|
||||
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"]);
|
||||
|
||||
export 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);
|
||||
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(
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#!/usr/bin/env node
|
||||
const { execFileSync } = require("child_process");
|
||||
const {
|
||||
assertExecutable,
|
||||
formatNonExecutableBinaryMessage,
|
||||
isPermissionError,
|
||||
} = require("@sandbox-agent/cli-shared");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
|
@ -10,29 +10,27 @@ const path = require("path");
|
|||
const TRUST_PACKAGES =
|
||||
"@sandbox-agent/cli-linux-x64 @sandbox-agent/cli-darwin-arm64 @sandbox-agent/cli-darwin-x64 @sandbox-agent/cli-win32-x64";
|
||||
|
||||
function printExecutableHint(binPath) {
|
||||
console.error(
|
||||
formatNonExecutableBinaryMessage({
|
||||
binPath,
|
||||
trustPackages: TRUST_PACKAGES,
|
||||
bunInstallBlocks: [
|
||||
{
|
||||
label: "Project install",
|
||||
commands: [
|
||||
`bun pm trust ${TRUST_PACKAGES}`,
|
||||
"bun add @sandbox-agent/cli",
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Global install",
|
||||
commands: [
|
||||
`bun pm -g trust ${TRUST_PACKAGES}`,
|
||||
"bun add -g @sandbox-agent/cli",
|
||||
],
|
||||
},
|
||||
],
|
||||
}),
|
||||
);
|
||||
function formatHint(binPath) {
|
||||
return formatNonExecutableBinaryMessage({
|
||||
binPath,
|
||||
trustPackages: TRUST_PACKAGES,
|
||||
bunInstallBlocks: [
|
||||
{
|
||||
label: "Project install",
|
||||
commands: [
|
||||
`bun pm trust ${TRUST_PACKAGES}`,
|
||||
"bun add @sandbox-agent/cli",
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Global install",
|
||||
commands: [
|
||||
`bun pm -g trust ${TRUST_PACKAGES}`,
|
||||
"bun add -g @sandbox-agent/cli",
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
const PLATFORMS = {
|
||||
|
|
@ -53,29 +51,13 @@ try {
|
|||
const pkgPath = require.resolve(`${pkg}/package.json`);
|
||||
const bin = process.platform === "win32" ? "sandbox-agent.exe" : "sandbox-agent";
|
||||
const binPath = path.join(path.dirname(pkgPath), "bin", bin);
|
||||
if (process.platform !== "win32") {
|
||||
try {
|
||||
fs.accessSync(binPath, fs.constants.X_OK);
|
||||
} catch (error) {
|
||||
try {
|
||||
fs.chmodSync(binPath, 0o755);
|
||||
} catch (chmodError) {
|
||||
if (isPermissionError(chmodError)) {
|
||||
printExecutableHint(binPath);
|
||||
}
|
||||
console.error(`Failed to make ${binPath} executable.`);
|
||||
throw chmodError;
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
execFileSync(binPath, process.argv.slice(2), { stdio: "inherit" });
|
||||
} catch (execError) {
|
||||
if (isPermissionError(execError)) {
|
||||
printExecutableHint(binPath);
|
||||
}
|
||||
throw execError;
|
||||
|
||||
if (!assertExecutable(binPath, fs)) {
|
||||
console.error(formatHint(binPath));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
execFileSync(binPath, process.argv.slice(2), { stdio: "inherit" });
|
||||
} catch (e) {
|
||||
if (e.status !== undefined) process.exit(e.status);
|
||||
throw e;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import type { ChildProcess } from "node:child_process";
|
||||
import type { AddressInfo } from "node:net";
|
||||
import {
|
||||
assertExecutable,
|
||||
formatNonExecutableBinaryMessage,
|
||||
isPermissionError,
|
||||
} from "@sandbox-agent/cli-shared";
|
||||
|
||||
export type SandboxAgentSpawnLogMode = "inherit" | "pipe" | "silent";
|
||||
|
|
@ -73,29 +73,29 @@ export async function spawnSandboxAgent(
|
|||
throw new Error("sandbox-agent binary not found. Install @sandbox-agent/cli or set SANDBOX_AGENT_BIN.");
|
||||
}
|
||||
|
||||
if (process.platform !== "win32") {
|
||||
try {
|
||||
fs.accessSync(binaryPath, fs.constants.X_OK);
|
||||
} catch (error) {
|
||||
if (isPermissionError(error)) {
|
||||
throw new Error(
|
||||
formatNonExecutableBinaryMessage({
|
||||
binPath: binaryPath,
|
||||
trustPackages: TRUST_PACKAGES,
|
||||
bunInstallBlocks: [
|
||||
{
|
||||
label: "Project install",
|
||||
commands: [
|
||||
`bun pm trust ${TRUST_PACKAGES}`,
|
||||
"bun add sandbox-agent",
|
||||
],
|
||||
},
|
||||
if (!assertExecutable(binaryPath, fs)) {
|
||||
throw new Error(
|
||||
formatNonExecutableBinaryMessage({
|
||||
binPath: binaryPath,
|
||||
trustPackages: TRUST_PACKAGES,
|
||||
bunInstallBlocks: [
|
||||
{
|
||||
label: "Project install",
|
||||
commands: [
|
||||
`bun pm trust ${TRUST_PACKAGES}`,
|
||||
"bun add sandbox-agent",
|
||||
],
|
||||
}),
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Global install",
|
||||
commands: [
|
||||
`bun pm -g trust ${TRUST_PACKAGES}`,
|
||||
"bun add -g sandbox-agent",
|
||||
],
|
||||
},
|
||||
],
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const stdio = logMode === "inherit" ? "inherit" : logMode === "silent" ? "ignore" : "pipe";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue