Compare commits

...

9 commits

Author SHA1 Message Date
Nathan Flurry
77a213befd chore(release): update version to 0.1.6-rc.1 2026-02-02 19:06:59 -08:00
Nathan Flurry
f0810b0541 fix: handle already-exists error during crate publish 2026-02-02 19:06:47 -08:00
Nathan Flurry
2b419f9e40 chore(release): update version to 0.1.6-rc.1 2026-02-02 18:58:27 -08:00
Nathan Flurry
e0573ebaf5 fix: add cli-shared publishing to release workflow 2026-02-02 18:58:09 -08:00
Nathan Flurry
7404e86975 chore(release): update version to 0.1.6-rc.1 2026-02-02 18:43:22 -08:00
Nathan Flurry
90589cded5 fix: add cli-shared package to Dockerfiles 2026-02-02 18:43:12 -08:00
Nathan Flurry
5a4faddfc4 chore(release): update version to 0.1.6-rc.1 2026-02-02 18:39:32 -08:00
Nathan Flurry
7f07428621 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
2026-02-02 18:38:06 -08:00
Nathan Flurry
048dcc5693 fix: fix bun install bug 2026-02-02 18:25:51 -08:00
31 changed files with 468 additions and 45 deletions

View file

@ -3,7 +3,7 @@ resolver = "2"
members = ["server/packages/*"]
[workspace.package]
version = "0.1.4-rc.7"
version = "0.1.6-rc.1"
edition = "2021"
authors = [ "Rivet Gaming, LLC <developer@rivet.gg>" ]
license = "Apache-2.0"
@ -12,12 +12,12 @@ description = "Universal API for automatic coding agents in sandboxes. Supprots
[workspace.dependencies]
# Internal crates
sandbox-agent = { version = "0.1.4-rc.7", path = "server/packages/sandbox-agent" }
sandbox-agent-error = { version = "0.1.4-rc.7", path = "server/packages/error" }
sandbox-agent-agent-management = { version = "0.1.4-rc.7", path = "server/packages/agent-management" }
sandbox-agent-agent-credentials = { version = "0.1.4-rc.7", path = "server/packages/agent-credentials" }
sandbox-agent-universal-agent-schema = { version = "0.1.4-rc.7", 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 = { version = "0.1.6-rc.1", path = "server/packages/sandbox-agent" }
sandbox-agent-error = { version = "0.1.6-rc.1", path = "server/packages/error" }
sandbox-agent-agent-management = { version = "0.1.6-rc.1", path = "server/packages/agent-management" }
sandbox-agent-agent-credentials = { version = "0.1.6-rc.1", path = "server/packages/agent-credentials" }
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.6-rc.1", path = "server/packages/extracted-agent-schemas" }
# Serialization
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:
```
```bash
npx skills add rivet-dev/skills -s sandbox-agent
```
```bash
bunx skills add rivet-dev/skills -s sandbox-agent
```
### TypeScript SDK
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
```
```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**
Local (embedded mode):
@ -154,6 +164,12 @@ Install the CLI wrapper (optional but convenient):
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:
```bash
@ -168,6 +184,10 @@ You can also use npx like:
npx sandbox-agent --help
```
```bash
bunx sandbox-agent --help
```
[CLI documentation](https://sandboxagent.dev/docs/cli)
### Inspector

View file

@ -8,6 +8,7 @@ RUN npm install -g pnpm
# Copy package files for workspaces
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
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/
# 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 docs/openapi.json ./docs/
COPY sdks/cli-shared ./sdks/cli-shared
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
# Copy inspector source and build

View file

@ -8,6 +8,7 @@ RUN npm install -g pnpm
# Copy package files for workspaces
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
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/
# 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 docs/openapi.json ./docs/
COPY sdks/cli-shared ./sdks/cli-shared
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
# Copy inspector source and build

View file

@ -8,6 +8,7 @@ RUN npm install -g pnpm
# Copy package files for workspaces
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
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/
# 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 docs/openapi.json ./docs/
COPY sdks/cli-shared ./sdks/cli-shared
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
# Copy inspector source and build

View file

@ -8,6 +8,7 @@ RUN npm install -g pnpm
# Copy package files for workspaces
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
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/
# 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 docs/openapi.json ./docs/
COPY sdks/cli-shared ./sdks/cli-shared
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
# Copy inspector source and build

View file

@ -10,6 +10,7 @@ RUN npm install -g pnpm
# Copy package files for workspaces
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
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/
# 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 docs/openapi.json ./docs/
COPY sdks/cli-shared ./sdks/cli-shared
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
# 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:
```
npx skills add rivet-dev/skills -s sandbox-agent
```
<Tabs>
<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/*`
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
```
Or with npm:
Or with npm or Bun:
```bash
npx sandbox-agent server --no-token --host 127.0.0.1 --port 2468
```
<Tabs>
<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

View file

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

View file

@ -6,9 +6,18 @@ icon: "rocket"
<Steps>
<Step title="Install skill (optional)">
```bash
npx skills add rivet-dev/skills -s sandbox-agent
```
<Tabs>
<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 title="Set environment variables">
@ -88,6 +97,14 @@ icon: "rocket"
```
</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">
Install globally, then run.
@ -97,17 +114,41 @@ icon: "rocket"
```
</Tab>
<Tab title="Build from source">
If you're running from source instead of the installed CLI.
<Tab title="bun add -g">
Install globally, then run.
```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 title="TypeScript (local)">
<Tab title="Bun (local)">
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
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.
</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>
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
```bash
npm install sandbox-agent
```
<Tabs>
<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

View file

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

View file

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

20
pnpm-lock.yaml generated
View file

@ -288,6 +288,10 @@ importers:
version: 5.9.3
sdks/cli:
dependencies:
'@sandbox-agent/cli-shared':
specifier: workspace:*
version: link:../cli-shared
optionalDependencies:
'@sandbox-agent/cli-darwin-arm64':
specifier: workspace:*
@ -306,6 +310,18 @@ importers:
specifier: ^3.0.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-x64: {}
@ -315,6 +331,10 @@ importers:
sdks/cli/platforms/win32-x64: {}
sdks/typescript:
dependencies:
'@sandbox-agent/cli-shared':
specifier: workspace:*
version: link:../cli-shared
devDependencies:
'@types/node':
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:
- **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
- **OpenTelemetry Resource Detectors**: Production-grade detectors across Node.js, Python, Go — use `@opentelemetry/resource-detector-aws`, `@opentelemetry/resource-detector-gcp`, etc.

View file

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

View file

@ -116,12 +116,21 @@ export async function publishCrates(opts: ReleaseOpts) {
try {
await $({
stdio: "inherit",
stdout: "pipe",
stderr: "pipe",
cwd: cratePath,
})`cargo publish --allow-dirty --no-verify`;
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(err.stderr || err.message);
throw err;
}
@ -133,6 +142,43 @@ export async function publishCrates(opts: ReleaseOpts) {
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) {
const sdkPath = join(opts.root, "sdks/typescript");
const packageJsonPath = join(sdkPath, "package.json");
@ -148,7 +194,7 @@ export async function publishNpmSdk(opts: ReleaseOpts) {
return;
}
// Build the SDK
// Build the SDK (cli-shared should already be built by publishNpmCliShared)
console.log(`==> Building TypeScript SDK`);
await $({
stdio: "inherit",

View file

@ -17,6 +17,11 @@ export async function updateVersion(opts: ReleaseOpts) {
find: /\[workspace\.package\]\nversion = ".*"/,
replace: `[workspace.package]\nversion = "${opts.version}"`,
},
{
path: "sdks/cli-shared/package.json",
find: /"version": ".*"/,
replace: `"version": "${opts.version}"`,
},
{
path: "sdks/typescript/package.json",
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
const { execFileSync } = require("child_process");
const {
assertExecutable,
formatNonExecutableBinaryMessage,
} = require("@sandbox-agent/cli-shared");
const fs = require("fs");
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 = {
"darwin-arm64": "@sandbox-agent/cli-darwin-arm64",
"darwin-x64": "@sandbox-agent/cli-darwin-x64",
@ -19,7 +50,14 @@ if (!pkg) {
try {
const pkgPath = require.resolve(`${pkg}/package.json`);
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) {
if (e.status !== undefined) process.exit(e.status);
throw e;

View file

@ -1,6 +1,6 @@
{
"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",
"license": "Apache-2.0",
"repository": {
@ -13,6 +13,9 @@
"scripts": {
"test": "vitest run"
},
"dependencies": {
"@sandbox-agent/cli-shared": "workspace:*"
},
"devDependencies": {
"vitest": "^3.0.0"
},

View file

@ -1,6 +1,6 @@
{
"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",
"license": "Apache-2.0",
"repository": {

View file

@ -1,6 +1,6 @@
{
"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",
"license": "Apache-2.0",
"repository": {

View file

@ -1,6 +1,6 @@
{
"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",
"license": "Apache-2.0",
"repository": {

View file

@ -1,6 +1,6 @@
{
"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",
"license": "Apache-2.0",
"repository": {

View file

@ -1,6 +1,6 @@
{
"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.",
"license": "Apache-2.0",
"repository": {
@ -16,6 +16,9 @@
"import": "./dist/index.js"
}
},
"dependencies": {
"@sandbox-agent/cli-shared": "workspace:*"
},
"files": [
"dist"
],

View file

@ -1,5 +1,9 @@
import type { ChildProcess } from "node:child_process";
import type { AddressInfo } from "node:net";
import {
assertExecutable,
formatNonExecutableBinaryMessage,
} from "@sandbox-agent/cli-shared";
export type SandboxAgentSpawnLogMode = "inherit" | "pipe" | "silent";
@ -28,6 +32,9 @@ const PLATFORM_PACKAGES: Record<string, string> = {
"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 {
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.");
}
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 args = ["server", "--host", bindHost, "--port", String(port), "--token", token];
const child = spawn(binaryPath, args, {