fix: fix bun install bug (#62)

* fix: fix bun install bug

* 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

* chore(release): update version to 0.1.6-rc.1

* fix: add cli-shared package to Dockerfiles

* chore(release): update version to 0.1.6-rc.1

* fix: add cli-shared publishing to release workflow

* chore(release): update version to 0.1.6-rc.1

* fix: handle already-exists error during crate publish

* chore(release): update version to 0.1.6-rc.1
This commit is contained in:
Nathan Flurry 2026-02-02 21:12:41 -08:00 committed by GitHub
parent 24de9e686c
commit 02bb992b11
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 467 additions and 44 deletions

View file

@ -3,7 +3,7 @@ resolver = "2"
members = ["server/packages/*"] members = ["server/packages/*"]
[workspace.package] [workspace.package]
version = "0.1.4-rc.7" version = "0.1.6-rc.1"
edition = "2021" edition = "2021"
authors = [ "Rivet Gaming, LLC <developer@rivet.gg>" ] authors = [ "Rivet Gaming, LLC <developer@rivet.gg>" ]
license = "Apache-2.0" license = "Apache-2.0"
@ -12,12 +12,12 @@ description = "Universal API for automatic coding agents in sandboxes. Supprots
[workspace.dependencies] [workspace.dependencies]
# Internal crates # Internal crates
sandbox-agent = { version = "0.1.4-rc.7", path = "server/packages/sandbox-agent" } sandbox-agent = { version = "0.1.6-rc.1", path = "server/packages/sandbox-agent" }
sandbox-agent-error = { version = "0.1.4-rc.7", path = "server/packages/error" } sandbox-agent-error = { version = "0.1.6-rc.1", path = "server/packages/error" }
sandbox-agent-agent-management = { version = "0.1.4-rc.7", path = "server/packages/agent-management" } sandbox-agent-agent-management = { version = "0.1.6-rc.1", path = "server/packages/agent-management" }
sandbox-agent-agent-credentials = { version = "0.1.4-rc.7", path = "server/packages/agent-credentials" } sandbox-agent-agent-credentials = { version = "0.1.6-rc.1", path = "server/packages/agent-credentials" }
sandbox-agent-universal-agent-schema = { version = "0.1.4-rc.7", path = "server/packages/universal-agent-schema" } sandbox-agent-universal-agent-schema = { version = "0.1.6-rc.1", path = "server/packages/universal-agent-schema" }
sandbox-agent-extracted-agent-schemas = { version = "0.1.4-rc.7", path = "server/packages/extracted-agent-schemas" } sandbox-agent-extracted-agent-schemas = { version = "0.1.6-rc.1", path = "server/packages/extracted-agent-schemas" }
# Serialization # Serialization
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }

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

@ -8,6 +8,7 @@ RUN npm install -g pnpm
# Copy package files for workspaces # Copy package files for workspaces
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY frontend/packages/inspector/package.json ./frontend/packages/inspector/ COPY frontend/packages/inspector/package.json ./frontend/packages/inspector/
COPY sdks/cli-shared/package.json ./sdks/cli-shared/
COPY sdks/typescript/package.json ./sdks/typescript/ COPY sdks/typescript/package.json ./sdks/typescript/
# Install dependencies # Install dependencies
@ -15,9 +16,11 @@ RUN pnpm install --filter @sandbox-agent/inspector...
# Copy SDK source (with pre-generated types from docs/openapi.json) # Copy SDK source (with pre-generated types from docs/openapi.json)
COPY docs/openapi.json ./docs/ COPY docs/openapi.json ./docs/
COPY sdks/cli-shared ./sdks/cli-shared
COPY sdks/typescript ./sdks/typescript COPY sdks/typescript ./sdks/typescript
# Build SDK (just tsup, skip generate since types are pre-generated) # Build cli-shared and SDK (just tsup, skip generate since types are pre-generated)
RUN cd sdks/cli-shared && pnpm exec tsup
RUN cd sdks/typescript && SKIP_OPENAPI_GEN=1 pnpm exec tsup RUN cd sdks/typescript && SKIP_OPENAPI_GEN=1 pnpm exec tsup
# Copy inspector source and build # Copy inspector source and build

View file

@ -8,6 +8,7 @@ RUN npm install -g pnpm
# Copy package files for workspaces # Copy package files for workspaces
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY frontend/packages/inspector/package.json ./frontend/packages/inspector/ COPY frontend/packages/inspector/package.json ./frontend/packages/inspector/
COPY sdks/cli-shared/package.json ./sdks/cli-shared/
COPY sdks/typescript/package.json ./sdks/typescript/ COPY sdks/typescript/package.json ./sdks/typescript/
# Install dependencies # Install dependencies
@ -15,9 +16,11 @@ RUN pnpm install --filter @sandbox-agent/inspector...
# Copy SDK source (with pre-generated types from docs/openapi.json) # Copy SDK source (with pre-generated types from docs/openapi.json)
COPY docs/openapi.json ./docs/ COPY docs/openapi.json ./docs/
COPY sdks/cli-shared ./sdks/cli-shared
COPY sdks/typescript ./sdks/typescript COPY sdks/typescript ./sdks/typescript
# Build SDK (just tsup, skip generate since types are pre-generated) # Build cli-shared and SDK (just tsup, skip generate since types are pre-generated)
RUN cd sdks/cli-shared && pnpm exec tsup
RUN cd sdks/typescript && SKIP_OPENAPI_GEN=1 pnpm exec tsup RUN cd sdks/typescript && SKIP_OPENAPI_GEN=1 pnpm exec tsup
# Copy inspector source and build # Copy inspector source and build

View file

@ -8,6 +8,7 @@ RUN npm install -g pnpm
# Copy package files for workspaces # Copy package files for workspaces
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY frontend/packages/inspector/package.json ./frontend/packages/inspector/ COPY frontend/packages/inspector/package.json ./frontend/packages/inspector/
COPY sdks/cli-shared/package.json ./sdks/cli-shared/
COPY sdks/typescript/package.json ./sdks/typescript/ COPY sdks/typescript/package.json ./sdks/typescript/
# Install dependencies # Install dependencies
@ -15,9 +16,11 @@ RUN pnpm install --filter @sandbox-agent/inspector...
# Copy SDK source (with pre-generated types from docs/openapi.json) # Copy SDK source (with pre-generated types from docs/openapi.json)
COPY docs/openapi.json ./docs/ COPY docs/openapi.json ./docs/
COPY sdks/cli-shared ./sdks/cli-shared
COPY sdks/typescript ./sdks/typescript COPY sdks/typescript ./sdks/typescript
# Build SDK (just tsup, skip generate since types are pre-generated) # Build cli-shared and SDK (just tsup, skip generate since types are pre-generated)
RUN cd sdks/cli-shared && pnpm exec tsup
RUN cd sdks/typescript && SKIP_OPENAPI_GEN=1 pnpm exec tsup RUN cd sdks/typescript && SKIP_OPENAPI_GEN=1 pnpm exec tsup
# Copy inspector source and build # Copy inspector source and build

View file

@ -8,6 +8,7 @@ RUN npm install -g pnpm
# Copy package files for workspaces # Copy package files for workspaces
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY frontend/packages/inspector/package.json ./frontend/packages/inspector/ COPY frontend/packages/inspector/package.json ./frontend/packages/inspector/
COPY sdks/cli-shared/package.json ./sdks/cli-shared/
COPY sdks/typescript/package.json ./sdks/typescript/ COPY sdks/typescript/package.json ./sdks/typescript/
# Install dependencies # Install dependencies
@ -15,9 +16,11 @@ RUN pnpm install --filter @sandbox-agent/inspector...
# Copy SDK source (with pre-generated types from docs/openapi.json) # Copy SDK source (with pre-generated types from docs/openapi.json)
COPY docs/openapi.json ./docs/ COPY docs/openapi.json ./docs/
COPY sdks/cli-shared ./sdks/cli-shared
COPY sdks/typescript ./sdks/typescript COPY sdks/typescript ./sdks/typescript
# Build SDK (just tsup, skip generate since types are pre-generated) # Build cli-shared and SDK (just tsup, skip generate since types are pre-generated)
RUN cd sdks/cli-shared && pnpm exec tsup
RUN cd sdks/typescript && SKIP_OPENAPI_GEN=1 pnpm exec tsup RUN cd sdks/typescript && SKIP_OPENAPI_GEN=1 pnpm exec tsup
# Copy inspector source and build # Copy inspector source and build

View file

@ -10,6 +10,7 @@ RUN npm install -g pnpm
# Copy package files for workspaces # Copy package files for workspaces
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY frontend/packages/inspector/package.json ./frontend/packages/inspector/ COPY frontend/packages/inspector/package.json ./frontend/packages/inspector/
COPY sdks/cli-shared/package.json ./sdks/cli-shared/
COPY sdks/typescript/package.json ./sdks/typescript/ COPY sdks/typescript/package.json ./sdks/typescript/
# Install dependencies # Install dependencies
@ -17,9 +18,11 @@ RUN pnpm install --filter @sandbox-agent/inspector...
# Copy SDK source (with pre-generated types from docs/openapi.json) # Copy SDK source (with pre-generated types from docs/openapi.json)
COPY docs/openapi.json ./docs/ COPY docs/openapi.json ./docs/
COPY sdks/cli-shared ./sdks/cli-shared
COPY sdks/typescript ./sdks/typescript COPY sdks/typescript ./sdks/typescript
# Build SDK (just tsup, skip generate since types are pre-generated) # Build cli-shared and SDK (just tsup, skip generate since types are pre-generated)
RUN cd sdks/cli-shared && pnpm exec tsup
RUN cd sdks/typescript && SKIP_OPENAPI_GEN=1 pnpm exec tsup RUN cd sdks/typescript && SKIP_OPENAPI_GEN=1 pnpm exec tsup
# Copy inspector source and build # Copy inspector source and build

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>
npx skills add rivet-dev/skills -s sandbox-agent <Tab title="npx">
``` ```bash
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:
```bash <Tabs>
npx sandbox-agent server --no-token --host 127.0.0.1 --port 2468 <Tab title="npx">
``` ```bash
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

@ -10,7 +10,7 @@
"license": { "license": {
"name": "Apache-2.0" "name": "Apache-2.0"
}, },
"version": "0.1.4-rc.7" "version": "0.1.6-rc.1"
}, },
"servers": [ "servers": [
{ {

View file

@ -6,9 +6,18 @@ icon: "rocket"
<Steps> <Steps>
<Step title="Install skill (optional)"> <Step title="Install skill (optional)">
```bash <Tabs>
npx skills add rivet-dev/skills -s sandbox-agent <Tab title="npx">
``` ```bash
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
```bash <Tabs>
npm install sandbox-agent <Tab title="npm">
``` ```bash
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

@ -13,7 +13,7 @@ import {
createGitHubRelease, createGitHubRelease,
validateGit, validateGit,
} from "./git"; } from "./git";
import { publishCrates, publishNpmCli, publishNpmSdk } from "./sdk"; import { publishCrates, publishNpmCli, publishNpmCliShared, publishNpmSdk } from "./sdk";
import { updateVersion } from "./update_version"; import { updateVersion } from "./update_version";
import { assert, assertEquals, fetchGitRef, versionOrCommitToRef } from "./utils"; import { assert, assertEquals, fetchGitRef, versionOrCommitToRef } from "./utils";
@ -281,6 +281,7 @@ const STEPS = [
"run-ci-checks", "run-ci-checks",
"build-js-artifacts", "build-js-artifacts",
"publish-crates", "publish-crates",
"publish-npm-cli-shared",
"publish-npm-sdk", "publish-npm-sdk",
"publish-npm-cli", "publish-npm-cli",
"tag-docker", "tag-docker",
@ -322,6 +323,7 @@ const PHASE_MAP: Record<Phase, Step[]> = {
"complete-ci": [ "complete-ci": [
"update-version", "update-version",
"publish-crates", "publish-crates",
"publish-npm-cli-shared",
"publish-npm-sdk", "publish-npm-sdk",
"publish-npm-cli", "publish-npm-cli",
"tag-docker", "tag-docker",
@ -595,6 +597,11 @@ async function main() {
await publishCrates(releaseOpts); await publishCrates(releaseOpts);
} }
if (shouldRunStep("publish-npm-cli-shared")) {
console.log("==> Publishing NPM CLI Shared");
await publishNpmCliShared(releaseOpts);
}
if (shouldRunStep("publish-npm-sdk")) { if (shouldRunStep("publish-npm-sdk")) {
console.log("==> Publishing NPM SDK"); console.log("==> Publishing NPM SDK");
await publishNpmSdk(releaseOpts); await publishNpmSdk(releaseOpts);

View file

@ -116,12 +116,21 @@ export async function publishCrates(opts: ReleaseOpts) {
try { try {
await $({ await $({
stdio: "inherit", stdout: "pipe",
stderr: "pipe",
cwd: cratePath, cwd: cratePath,
})`cargo publish --allow-dirty --no-verify`; })`cargo publish --allow-dirty --no-verify`;
console.log(`✅ Published ${crateName}@${opts.version}`); console.log(`✅ Published ${crateName}@${opts.version}`);
} catch (err) { } catch (err: any) {
// Check if error is because crate already exists (from a previous partial run)
if (err.stderr?.includes("already exists")) {
console.log(
`Version ${opts.version} of ${crateName} already exists on crates.io. Skipping...`,
);
continue;
}
console.error(`❌ Failed to publish ${crateName}`); console.error(`❌ Failed to publish ${crateName}`);
console.error(err.stderr || err.message);
throw err; throw err;
} }
@ -133,6 +142,43 @@ export async function publishCrates(opts: ReleaseOpts) {
console.log("✅ All crates published"); console.log("✅ All crates published");
} }
export async function publishNpmCliShared(opts: ReleaseOpts) {
const cliSharedPath = join(opts.root, "sdks/cli-shared");
const packageJsonPath = join(cliSharedPath, "package.json");
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf-8"));
const name = packageJson.name;
// Check if version already exists
const versionExists = await npmVersionExists(name, opts.version);
if (versionExists) {
console.log(
`Version ${opts.version} of ${name} already exists. Skipping...`,
);
return;
}
// Build cli-shared
console.log(`==> Building @sandbox-agent/cli-shared`);
await $({
stdio: "inherit",
cwd: opts.root,
})`pnpm --filter @sandbox-agent/cli-shared build`;
// Publish
console.log(`==> Publishing to NPM: ${name}@${opts.version}`);
// Add --tag flag for release candidates
const isReleaseCandidate = opts.version.includes("-rc.");
const tag = isReleaseCandidate ? "rc" : "latest";
await $({
stdio: "inherit",
cwd: cliSharedPath,
})`pnpm publish --access public --tag ${tag} --no-git-checks`;
console.log(`✅ Published ${name}@${opts.version}`);
}
export async function publishNpmSdk(opts: ReleaseOpts) { export async function publishNpmSdk(opts: ReleaseOpts) {
const sdkPath = join(opts.root, "sdks/typescript"); const sdkPath = join(opts.root, "sdks/typescript");
const packageJsonPath = join(sdkPath, "package.json"); const packageJsonPath = join(sdkPath, "package.json");
@ -148,7 +194,7 @@ export async function publishNpmSdk(opts: ReleaseOpts) {
return; return;
} }
// Build the SDK // Build the SDK (cli-shared should already be built by publishNpmCliShared)
console.log(`==> Building TypeScript SDK`); console.log(`==> Building TypeScript SDK`);
await $({ await $({
stdio: "inherit", stdio: "inherit",

View file

@ -17,6 +17,11 @@ export async function updateVersion(opts: ReleaseOpts) {
find: /\[workspace\.package\]\nversion = ".*"/, find: /\[workspace\.package\]\nversion = ".*"/,
replace: `[workspace.package]\nversion = "${opts.version}"`, replace: `[workspace.package]\nversion = "${opts.version}"`,
}, },
{
path: "sdks/cli-shared/package.json",
find: /"version": ".*"/,
replace: `"version": "${opts.version}"`,
},
{ {
path: "sdks/typescript/package.json", path: "sdks/typescript/package.json",
find: /"version": ".*"/, find: /"version": ".*"/,

View file

@ -0,0 +1,30 @@
{
"name": "@sandbox-agent/cli-shared",
"version": "0.1.6-rc.1",
"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.js",
"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,99 @@
export type InstallCommandBlock = {
label: string;
commands: string[];
};
export type NonExecutableBinaryMessageOptions = {
binPath: string;
trustPackages: string;
bunInstallBlocks: InstallCommandBlock[];
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/");
}
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 } =
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,38 @@
#!/usr/bin/env node #!/usr/bin/env node
const { execFileSync } = require("child_process"); const { execFileSync } = require("child_process");
const {
assertExecutable,
formatNonExecutableBinaryMessage,
} = 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 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 = { 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 +50,14 @@ 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 (!assertExecutable(binPath, fs)) {
console.error(formatHint(binPath));
process.exit(1);
}
execFileSync(binPath, process.argv.slice(2), { stdio: "inherit" });
} 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

@ -1,6 +1,6 @@
{ {
"name": "@sandbox-agent/cli", "name": "@sandbox-agent/cli",
"version": "0.1.4-rc.7", "version": "0.1.6-rc.1",
"description": "CLI for sandbox-agent - run AI coding agents in sandboxes", "description": "CLI for sandbox-agent - run AI coding agents in sandboxes",
"license": "Apache-2.0", "license": "Apache-2.0",
"repository": { "repository": {
@ -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

@ -1,6 +1,6 @@
{ {
"name": "@sandbox-agent/cli-darwin-arm64", "name": "@sandbox-agent/cli-darwin-arm64",
"version": "0.1.4-rc.7", "version": "0.1.6-rc.1",
"description": "sandbox-agent CLI binary for macOS ARM64", "description": "sandbox-agent CLI binary for macOS ARM64",
"license": "Apache-2.0", "license": "Apache-2.0",
"repository": { "repository": {

View file

@ -1,6 +1,6 @@
{ {
"name": "@sandbox-agent/cli-darwin-x64", "name": "@sandbox-agent/cli-darwin-x64",
"version": "0.1.4-rc.7", "version": "0.1.6-rc.1",
"description": "sandbox-agent CLI binary for macOS x64", "description": "sandbox-agent CLI binary for macOS x64",
"license": "Apache-2.0", "license": "Apache-2.0",
"repository": { "repository": {

View file

@ -1,6 +1,6 @@
{ {
"name": "@sandbox-agent/cli-linux-x64", "name": "@sandbox-agent/cli-linux-x64",
"version": "0.1.4-rc.7", "version": "0.1.6-rc.1",
"description": "sandbox-agent CLI binary for Linux x64", "description": "sandbox-agent CLI binary for Linux x64",
"license": "Apache-2.0", "license": "Apache-2.0",
"repository": { "repository": {

View file

@ -1,6 +1,6 @@
{ {
"name": "@sandbox-agent/cli-win32-x64", "name": "@sandbox-agent/cli-win32-x64",
"version": "0.1.4-rc.7", "version": "0.1.6-rc.1",
"description": "sandbox-agent CLI binary for Windows x64", "description": "sandbox-agent CLI binary for Windows x64",
"license": "Apache-2.0", "license": "Apache-2.0",
"repository": { "repository": {

View file

@ -1,6 +1,6 @@
{ {
"name": "sandbox-agent", "name": "sandbox-agent",
"version": "0.1.4-rc.7", "version": "0.1.6-rc.1",
"description": "Universal API for automatic coding agents in sandboxes. Supprots Claude Code, Codex, OpenCode, and Amp.", "description": "Universal API for automatic coding agents in sandboxes. Supprots Claude Code, Codex, OpenCode, and Amp.",
"license": "Apache-2.0", "license": "Apache-2.0",
"repository": { "repository": {
@ -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 {
assertExecutable,
formatNonExecutableBinaryMessage,
} 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 (!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",
],
},
{
label: "Global install",
commands: [
`bun pm -g trust ${TRUST_PACKAGES}`,
"bun add -g sandbox-agent",
],
},
],
}),
);
}
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, {