fix: fix bun install bug

This commit is contained in:
Nathan Flurry 2026-02-02 16:25:53 -08:00
parent 553f249836
commit 048dcc5693
17 changed files with 354 additions and 22 deletions

View file

@ -63,10 +63,14 @@ Choose the installation method that works best for your use case.
Install skill with: Install skill with:
``` ```bash
npx skills add rivet-dev/skills -s sandbox-agent npx skills add rivet-dev/skills -s sandbox-agent
``` ```
```bash
bunx skills add rivet-dev/skills -s sandbox-agent
```
### TypeScript SDK ### TypeScript SDK
Import the SDK directly into your Node or browser application. Full type safety and streaming support. Import the SDK directly into your Node or browser application. Full type safety and streaming support.
@ -77,6 +81,12 @@ Import the SDK directly into your Node or browser application. Full type safety
npm install sandbox-agent npm install sandbox-agent
``` ```
```bash
bun add sandbox-agent
# Optional: allow Bun to run postinstall scripts for native binaries (required for SandboxAgent.start()).
bun pm trust @sandbox-agent/cli-linux-x64 @sandbox-agent/cli-darwin-arm64 @sandbox-agent/cli-darwin-x64 @sandbox-agent/cli-win32-x64
```
**Setup** **Setup**
Local (embedded mode): Local (embedded mode):
@ -154,6 +164,12 @@ Install the CLI wrapper (optional but convenient):
npm install -g @sandbox-agent/cli npm install -g @sandbox-agent/cli
``` ```
```bash
# Allow Bun to run postinstall scripts for native binaries.
bun add -g @sandbox-agent/cli
bun pm -g trust @sandbox-agent/cli-linux-x64 @sandbox-agent/cli-darwin-arm64 @sandbox-agent/cli-darwin-x64 @sandbox-agent/cli-win32-x64
```
Create a session and send a message: Create a session and send a message:
```bash ```bash
@ -168,6 +184,10 @@ You can also use npx like:
npx sandbox-agent --help npx sandbox-agent --help
``` ```
```bash
bunx sandbox-agent --help
```
[CLI documentation](https://sandboxagent.dev/docs/cli) [CLI documentation](https://sandboxagent.dev/docs/cli)
### Inspector ### Inspector

View file

@ -13,9 +13,18 @@ https://rivet.dev/docs/skill.md
To add it to an agent using the Skills CLI: To add it to an agent using the Skills CLI:
``` <Tabs>
<Tab title="npx">
```bash
npx skills add rivet-dev/skills -s sandbox-agent npx skills add rivet-dev/skills -s sandbox-agent
``` ```
</Tab>
<Tab title="bunx">
```bash
bunx skills add rivet-dev/skills -s sandbox-agent
```
</Tab>
</Tabs>
If you run a reverse proxy in front of the docs, make sure `/skill.md` and `/.well-known/skills/*` If you run a reverse proxy in front of the docs, make sure `/skill.md` and `/.well-known/skills/*`
are forwarded to Mintlify. are forwarded to Mintlify.

View file

@ -15,11 +15,20 @@ curl -fsSL https://releases.rivet.dev/sandbox-agent/latest/install.sh | sh
sandbox-agent server --no-token --host 127.0.0.1 --port 2468 sandbox-agent server --no-token --host 127.0.0.1 --port 2468
``` ```
Or with npm: Or with npm or Bun:
<Tabs>
<Tab title="npx">
```bash ```bash
npx sandbox-agent server --no-token --host 127.0.0.1 --port 2468 npx sandbox-agent server --no-token --host 127.0.0.1 --port 2468
``` ```
</Tab>
<Tab title="bunx">
```bash
bunx sandbox-agent server --no-token --host 127.0.0.1 --port 2468
```
</Tab>
</Tabs>
## With the TypeScript SDK ## With the TypeScript SDK

View file

@ -6,9 +6,18 @@ icon: "rocket"
<Steps> <Steps>
<Step title="Install skill (optional)"> <Step title="Install skill (optional)">
<Tabs>
<Tab title="npx">
```bash ```bash
npx skills add rivet-dev/skills -s sandbox-agent npx skills add rivet-dev/skills -s sandbox-agent
``` ```
</Tab>
<Tab title="bunx">
```bash
bunx skills add rivet-dev/skills -s sandbox-agent
```
</Tab>
</Tabs>
</Step> </Step>
<Step title="Set environment variables"> <Step title="Set environment variables">
@ -88,6 +97,14 @@ icon: "rocket"
``` ```
</Tab> </Tab>
<Tab title="bunx">
Run without installing globally.
```bash
bunx @sandbox-agent/cli server --no-token --host 0.0.0.0 --port 2468
```
</Tab>
<Tab title="npm i -g"> <Tab title="npm i -g">
Install globally, then run. Install globally, then run.
@ -97,17 +114,41 @@ icon: "rocket"
``` ```
</Tab> </Tab>
<Tab title="Build from source"> <Tab title="bun add -g">
If you're running from source instead of the installed CLI. Install globally, then run.
```bash ```bash
cargo run -p sandbox-agent -- server --no-token --host 0.0.0.0 --port 2468 bun add -g @sandbox-agent/cli
# Allow Bun to run postinstall scripts for native binaries (required for SandboxAgent.start()).
bun pm -g trust @sandbox-agent/cli-linux-x64 @sandbox-agent/cli-darwin-arm64 @sandbox-agent/cli-darwin-x64 @sandbox-agent/cli-win32-x64
sandbox-agent server --no-token --host 0.0.0.0 --port 2468
```
</Tab>
<Tab title="Node.js (local)">
For local development, use `SandboxAgent.start()` to automatically spawn and manage the server as a subprocess.
```bash
npm install sandbox-agent
```
```typescript
import { SandboxAgent } from "sandbox-agent";
const client = await SandboxAgent.start();
``` ```
</Tab> </Tab>
<Tab title="TypeScript (local)"> <Tab title="Bun (local)">
For local development, use `SandboxAgent.start()` to automatically spawn and manage the server as a subprocess. For local development, use `SandboxAgent.start()` to automatically spawn and manage the server as a subprocess.
```bash
bun add sandbox-agent
# Allow Bun to run postinstall scripts for native binaries (required for SandboxAgent.start()).
bun pm trust @sandbox-agent/cli-linux-x64 @sandbox-agent/cli-darwin-arm64 @sandbox-agent/cli-darwin-x64 @sandbox-agent/cli-win32-x64
```
```typescript ```typescript
import { SandboxAgent } from "sandbox-agent"; import { SandboxAgent } from "sandbox-agent";
@ -116,6 +157,14 @@ icon: "rocket"
This installs the binary and starts the server for you. No manual setup required. This installs the binary and starts the server for you. No manual setup required.
</Tab> </Tab>
<Tab title="Build from source">
If you're running from source instead of the installed CLI.
```bash
cargo run -p sandbox-agent -- server --no-token --host 0.0.0.0 --port 2468
```
</Tab>
</Tabs> </Tabs>
Binding to `0.0.0.0` allows the server to accept connections from any network interface, which is required when running inside a sandbox where clients connect remotely. Binding to `0.0.0.0` allows the server to accept connections from any network interface, which is required when running inside a sandbox where clients connect remotely.

View file

@ -9,9 +9,20 @@ client for sessions, events, and agent operations.
## Install ## Install
<Tabs>
<Tab title="npm">
```bash ```bash
npm install sandbox-agent npm install sandbox-agent
``` ```
</Tab>
<Tab title="bun">
```bash
bun add sandbox-agent
# Allow Bun to run postinstall scripts for native binaries (required for SandboxAgent.start()).
bun pm trust @sandbox-agent/cli-linux-x64 @sandbox-agent/cli-darwin-arm64 @sandbox-agent/cli-darwin-x64 @sandbox-agent/cli-win32-x64
```
</Tab>
</Tabs>
## Create a client ## Create a client

View file

@ -46,3 +46,7 @@ check:
[group('dev')] [group('dev')]
fmt: fmt:
cargo fmt --all cargo fmt --all
[group('dev')]
dev-docs:
cd docs && pnpm dlx mintlify dev

View file

@ -7,8 +7,7 @@
"build": "turbo run build", "build": "turbo run build",
"dev": "turbo run dev --parallel", "dev": "turbo run dev --parallel",
"generate": "turbo run generate", "generate": "turbo run generate",
"typecheck": "turbo run typecheck", "typecheck": "turbo run typecheck"
"dev:docs": "cd docs/ && pnpm dlx mintlify dev"
}, },
"devDependencies": { "devDependencies": {
"turbo": "^2.4.0", "turbo": "^2.4.0",

20
pnpm-lock.yaml generated
View file

@ -288,6 +288,10 @@ importers:
version: 5.9.3 version: 5.9.3
sdks/cli: sdks/cli:
dependencies:
'@sandbox-agent/cli-shared':
specifier: workspace:*
version: link:../cli-shared
optionalDependencies: optionalDependencies:
'@sandbox-agent/cli-darwin-arm64': '@sandbox-agent/cli-darwin-arm64':
specifier: workspace:* specifier: workspace:*
@ -306,6 +310,18 @@ importers:
specifier: ^3.0.0 specifier: ^3.0.0
version: 3.2.4(@types/debug@4.1.12)(@types/node@25.1.0) version: 3.2.4(@types/debug@4.1.12)(@types/node@25.1.0)
sdks/cli-shared:
devDependencies:
'@types/node':
specifier: ^22.0.0
version: 22.19.7
tsup:
specifier: ^8.0.0
version: 8.5.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)
typescript:
specifier: ^5.7.0
version: 5.9.3
sdks/cli/platforms/darwin-arm64: {} sdks/cli/platforms/darwin-arm64: {}
sdks/cli/platforms/darwin-x64: {} sdks/cli/platforms/darwin-x64: {}
@ -315,6 +331,10 @@ importers:
sdks/cli/platforms/win32-x64: {} sdks/cli/platforms/win32-x64: {}
sdks/typescript: sdks/typescript:
dependencies:
'@sandbox-agent/cli-shared':
specifier: workspace:*
version: link:../cli-shared
devDependencies: devDependencies:
'@types/node': '@types/node':
specifier: ^22.0.0 specifier: ^22.0.0

View file

@ -567,7 +567,7 @@ console.log(`Running on: ${provider.provider} (${provider.confidence} confidence
Several open-source projects implement cloud detection patterns: Several open-source projects implement cloud detection patterns:
- **cloud-detect** (Python, `pip install cloud-detect`): Detects AWS, GCP, Azure, Alibaba, DigitalOcean, Oracle via filesystem + metadata - **cloud-detect** (Python, `pip install cloud-detect`): Detects AWS, GCP, Azure, Alibaba, DigitalOcean, Oracle via filesystem + metadata
- **cloud-detect-js** (Node, `npm install cloud-detect-js`): JavaScript port with similar capabilities - **cloud-detect-js** (Node, `npm install cloud-detect-js` or `bun add cloud-detect-js`): JavaScript port with similar capabilities
- **banzaicloud/satellite** (Go): Uses two-tier detection with sysfs first, then metadata fallback - **banzaicloud/satellite** (Go): Uses two-tier detection with sysfs first, then metadata fallback
- **OpenTelemetry Resource Detectors**: Production-grade detectors across Node.js, Python, Go — use `@opentelemetry/resource-detector-aws`, `@opentelemetry/resource-detector-gcp`, etc. - **OpenTelemetry Resource Detectors**: Production-grade detectors across Node.js, Python, Go — use `@opentelemetry/resource-detector-aws`, `@opentelemetry/resource-detector-gcp`, etc.

View file

@ -0,0 +1,30 @@
{
"name": "@sandbox-agent/cli-shared",
"version": "0.1.4-rc.7",
"description": "Shared helpers for sandbox-agent CLI and SDK",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/rivet-dev/sandbox-agent"
},
"type": "module",
"scripts": {
"build": "tsup",
"typecheck": "tsc --noEmit"
},
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
},
"files": [
"dist"
],
"devDependencies": {
"@types/node": "^22.0.0",
"tsup": "^8.0.0",
"typescript": "^5.7.0"
}
}

View file

@ -0,0 +1,63 @@
export type InstallCommandBlock = {
label: string;
commands: string[];
};
export type NonExecutableBinaryMessageOptions = {
binPath: string;
trustPackages: string;
bunInstallBlocks: InstallCommandBlock[];
genericInstallCommands?: string[];
};
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"]);
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);
}
export function formatNonExecutableBinaryMessage(
options: NonExecutableBinaryMessageOptions,
): string {
const { binPath, trustPackages, bunInstallBlocks, genericInstallCommands } =
options;
const lines = [`sandbox-agent 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");
}

View file

@ -0,0 +1,15 @@
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022"],
"module": "ESNext",
"moduleResolution": "Bundler",
"noEmit": true,
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"types": ["node"]
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

View file

@ -0,0 +1,9 @@
import { defineConfig } from "tsup";
export default defineConfig({
entry: ["src/index.ts"],
format: ["esm", "cjs"],
dts: true,
clean: true,
sourcemap: true,
});

View file

@ -1,7 +1,40 @@
#!/usr/bin/env node #!/usr/bin/env node
const { execFileSync } = require("child_process"); const { execFileSync } = require("child_process");
const {
formatNonExecutableBinaryMessage,
isPermissionError,
} = require("@sandbox-agent/cli-shared");
const fs = require("fs");
const path = require("path"); 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",
],
},
],
}),
);
}
const PLATFORMS = { const PLATFORMS = {
"darwin-arm64": "@sandbox-agent/cli-darwin-arm64", "darwin-arm64": "@sandbox-agent/cli-darwin-arm64",
"darwin-x64": "@sandbox-agent/cli-darwin-x64", "darwin-x64": "@sandbox-agent/cli-darwin-x64",
@ -19,7 +52,30 @@ if (!pkg) {
try { try {
const pkgPath = require.resolve(`${pkg}/package.json`); const pkgPath = require.resolve(`${pkg}/package.json`);
const bin = process.platform === "win32" ? "sandbox-agent.exe" : "sandbox-agent"; const bin = process.platform === "win32" ? "sandbox-agent.exe" : "sandbox-agent";
execFileSync(path.join(path.dirname(pkgPath), "bin", bin), process.argv.slice(2), { stdio: "inherit" }); 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;
}
} catch (e) { } catch (e) {
if (e.status !== undefined) process.exit(e.status); if (e.status !== undefined) process.exit(e.status);
throw e; throw e;

View file

@ -13,6 +13,9 @@
"scripts": { "scripts": {
"test": "vitest run" "test": "vitest run"
}, },
"dependencies": {
"@sandbox-agent/cli-shared": "workspace:*"
},
"devDependencies": { "devDependencies": {
"vitest": "^3.0.0" "vitest": "^3.0.0"
}, },

View file

@ -16,6 +16,9 @@
"import": "./dist/index.js" "import": "./dist/index.js"
} }
}, },
"dependencies": {
"@sandbox-agent/cli-shared": "workspace:*"
},
"files": [ "files": [
"dist" "dist"
], ],

View file

@ -1,5 +1,9 @@
import type { ChildProcess } from "node:child_process"; import type { ChildProcess } from "node:child_process";
import type { AddressInfo } from "node:net"; import type { AddressInfo } from "node:net";
import {
formatNonExecutableBinaryMessage,
isPermissionError,
} from "@sandbox-agent/cli-shared";
export type SandboxAgentSpawnLogMode = "inherit" | "pipe" | "silent"; export type SandboxAgentSpawnLogMode = "inherit" | "pipe" | "silent";
@ -28,6 +32,9 @@ const PLATFORM_PACKAGES: Record<string, string> = {
"win32-x64": "@sandbox-agent/cli-win32-x64", "win32-x64": "@sandbox-agent/cli-win32-x64",
}; };
const TRUST_PACKAGES =
"@sandbox-agent/cli-linux-x64 @sandbox-agent/cli-darwin-arm64 @sandbox-agent/cli-darwin-x64 @sandbox-agent/cli-win32-x64";
export function isNodeRuntime(): boolean { export function isNodeRuntime(): boolean {
return typeof process !== "undefined" && !!process.versions?.node; return typeof process !== "undefined" && !!process.versions?.node;
} }
@ -66,6 +73,31 @@ export async function spawnSandboxAgent(
throw new Error("sandbox-agent binary not found. Install @sandbox-agent/cli or set SANDBOX_AGENT_BIN."); 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",
],
},
],
}),
);
}
throw error;
}
}
const stdio = logMode === "inherit" ? "inherit" : logMode === "silent" ? "ignore" : "pipe"; const stdio = logMode === "inherit" ? "inherit" : logMode === "silent" ? "ignore" : "pipe";
const args = ["server", "--host", bindHost, "--port", String(port), "--token", token]; const args = ["server", "--host", bindHost, "--port", String(port), "--token", token];
const child = spawn(binaryPath, args, { const child = spawn(binaryPath, args, {