sandbox-cli-detector
Advanced tools
+10
-5
| { | ||
| "name": "sandbox-cli-detector", | ||
| "version": "0.1.0", | ||
| "version": "0.1.1", | ||
| "description": "Detect whether a CLI is running inside a sandboxed environment (E2B, Vercel Sandbox, Replit, Daytona, Modal, and more)", | ||
@@ -28,5 +28,10 @@ "keywords": [ | ||
| ".": { | ||
| "types": "./dist/index.d.ts", | ||
| "import": "./dist/index.js", | ||
| "require": "./dist/index.cjs" | ||
| "import": { | ||
| "types": "./dist/index.d.ts", | ||
| "default": "./dist/index.js" | ||
| }, | ||
| "require": { | ||
| "types": "./dist/index.d.cts", | ||
| "default": "./dist/index.cjs" | ||
| } | ||
| } | ||
@@ -38,3 +43,3 @@ }, | ||
| "bin": { | ||
| "sandbox-cli-detector": "./dist/cli.js" | ||
| "sandbox-cli-detector": "dist/cli.js" | ||
| }, | ||
@@ -41,0 +46,0 @@ "files": [ |
+188
-53
| # sandbox-cli-detector | ||
| Detect whether your CLI is running inside a sandboxed environment — an AI code-execution sandbox (E2B, Vercel Sandbox, Daytona, Modal, ...), an AI app builder (Replit, bolt.new, Rork, ...), or a cloud development environment (Codespaces, CodeSandbox, ...). | ||
| Detect whether the current process is running inside a sandboxed developer | ||
| environment. | ||
| Inspired by [ci-info](https://github.com/watson/ci-info) and a companion to [agent-cli-detector](https://github.com/davidmokos/detect-agent): `agent-cli-detector` tells you *which agent* is driving your CLI, this package tells you *where* it is running. | ||
| This is useful for CLIs, SDKs, test runners, and install scripts that need to | ||
| adjust behavior inside AI sandboxes, AI app builders, and cloud IDEs. | ||
| Inspired by [ci-info](https://github.com/watson/ci-info) and built as a | ||
| companion to [agent-cli-detector](https://github.com/davidmokos/detect-agent): | ||
| `agent-cli-detector` tells you which agent is driving your CLI; | ||
| `sandbox-cli-detector` tells you where that CLI is running. | ||
| Please open an issue if a sandbox is missing or incorrectly detected. | ||
| ## Installation | ||
@@ -19,62 +28,96 @@ | ||
| if (isRunningInSandbox()) { | ||
| // e.g. skip interactive prompts, adjust telemetry, relax auth flows | ||
| // Skip interactive prompts, tune telemetry, relax auth flows, etc. | ||
| } | ||
| const result = detectSandbox(); | ||
| // { | ||
| // detected: true, | ||
| // sandbox: { | ||
| // id: "e2b", | ||
| // name: "E2B", | ||
| // category: "ai-sandbox", | ||
| // instanceId: "sbx_abc123", | ||
| // evidence: [{ envVar: "E2B_SANDBOX", value: "true" }] | ||
| // }, | ||
| // matches: [ ... ] // all matched sandboxes, most specific first | ||
| // } | ||
| if (result.detected) { | ||
| console.log("sandbox:", result.sandbox?.name); | ||
| } else { | ||
| console.log("not running in a known sandbox"); | ||
| } | ||
| ``` | ||
| Or from the command line (exit code 0 when a sandbox is detected, 1 otherwise): | ||
| Example result: | ||
| ```sh | ||
| npx sandbox-cli-detector # "detected: E2B (sbx_abc123)" / "no sandbox detected" | ||
| npx sandbox-cli-detector --json # full detection result as JSON | ||
| npx sandbox-cli-detector --quiet # exit code only | ||
| ```json | ||
| { | ||
| "detected": true, | ||
| "sandbox": { | ||
| "id": "e2b", | ||
| "name": "E2B", | ||
| "category": "ai-sandbox", | ||
| "instanceId": "sbx_abc123", | ||
| "evidence": [{ "envVar": "E2B_SANDBOX", "value": "true" }] | ||
| }, | ||
| "matches": [ | ||
| { | ||
| "id": "e2b", | ||
| "name": "E2B", | ||
| "category": "ai-sandbox", | ||
| "instanceId": "sbx_abc123", | ||
| "evidence": [{ "envVar": "E2B_SANDBOX", "value": "true" }] | ||
| } | ||
| ] | ||
| } | ||
| ``` | ||
| Layered environments are common — an app builder may run its builds inside a generic AI sandbox. `result.sandbox` is the most specific match (app builder → AI sandbox → cloud IDE) and `result.matches` lists everything that matched. | ||
| Layered environments are common. For example, an app builder may run user code | ||
| inside a generic AI sandbox. `result.sandbox` is the primary match and | ||
| `result.matches` contains every matched environment in definition order. The | ||
| built-in definitions are ordered from most specific to least specific: | ||
| app builders, then AI code-execution sandboxes, then cloud IDEs. | ||
| ## Supported environments | ||
| Use `result.sandbox.id` for stable checks. `result.sandbox.name` is display text | ||
| and may change. | ||
| Detection currently relies on environment variables only. Every marker below was confirmed by probing the real platform — no guessed or documentation-only markers. | ||
| ## CLI | ||
| ### AI code-execution sandboxes | ||
| ```sh | ||
| npx sandbox-cli-detector | ||
| # detected: E2B (sbx_abc123) | ||
| # no sandbox detected | ||
| | Sandbox | id | Detection env vars | | ||
| | --- | --- | --- | | ||
| | [E2B](https://e2b.dev) | `e2b` | `E2B_SANDBOX=true` (id: `E2B_SANDBOX_ID`) | | ||
| | [Vercel Sandbox](https://vercel.com/docs/sandbox) | `vercel-sandbox` | `HOME=/home/vercel-sandbox` | | ||
| | [Daytona](https://daytona.io) | `daytona` | `DAYTONA_SANDBOX_ID` | | ||
| | [Modal](https://modal.com) | `modal` | `MODAL_SANDBOX_ID` or `MODAL_TASK_ID` | | ||
| | [Cloudflare Sandbox](https://developers.cloudflare.com/sandbox/) | `cloudflare-sandbox` | `CLOUDFLARE_DURABLE_OBJECT_ID` | | ||
| npx sandbox-cli-detector --json | ||
| # prints the full DetectionResult as JSON | ||
| ### AI app builders | ||
| npx sandbox-cli-detector --quiet | ||
| # no output, exit code only | ||
| ``` | ||
| | Sandbox | id | Detection env vars | | ||
| | --- | --- | --- | | ||
| | [Replit](https://replit.com) | `replit` | `REPLIT_SESSION`, `REPLIT_CONTAINER`, or `REPLIT_USER` | | ||
| | [bolt.new](https://bolt.new) | `bolt` | `BOLT_ENV`, `BOLT_ORIGIN`, or `BOLT_SERVER_URL` | | ||
| | [Rork](https://rork.com) | `rork` | `RORK_API_URL` (runs on E2B, so `e2b` also matches) | | ||
| Exit codes: | ||
| Lovable, v0, and Base44 are intentionally not on the list: they expose no shell, so a CLI can never run inside them. | ||
| | Code | Meaning | | ||
| | --- | --- | | ||
| | `0` | a known sandbox was detected | | ||
| | `1` | no known sandbox was detected | | ||
| ### Cloud development environments | ||
| ## Supported environments | ||
| | Sandbox | id | Detection env vars | | ||
| | --- | --- | --- | | ||
| | [GitHub Codespaces](https://github.com/features/codespaces) | `codespaces` | `CODESPACES=true` (id: `CODESPACE_NAME`) | | ||
| | [CodeSandbox](https://codesandbox.io) | `codesandbox` | `CSB=true` or `CSB_SANDBOX_ID` (id: `CSB_SANDBOX_ID`) | | ||
| Detection currently uses environment variables only. Every built-in marker was | ||
| confirmed by probing the real platform; guessed or documentation-only markers | ||
| are intentionally not included. | ||
| Missing a platform (Morph, Runloop, Gitpod, Cloud Shell, Coder, ...)? Please open an issue or PR with the env vars it sets — the fastest way to check is running `env | sort` (or `npx sandbox-cli-detector --json`) inside it. | ||
| | Name | Category | Stable id | Detection env vars | Instance id | | ||
| | --- | --- | --- | --- | --- | | ||
| | [Replit](https://replit.com) | app builder | `replit` | `REPLIT_SESSION`, `REPLIT_CONTAINER`, or `REPLIT_USER` | - | | ||
| | [bolt.new](https://bolt.new) | app builder | `bolt` | `BOLT_ENV`, `BOLT_ORIGIN`, or `BOLT_SERVER_URL` | - | | ||
| | [Rork](https://rork.com) | app builder | `rork` | `RORK_API_URL` | - | | ||
| | [E2B](https://e2b.dev) | AI sandbox | `e2b` | `E2B_SANDBOX=true` | `E2B_SANDBOX_ID` | | ||
| | [Vercel Sandbox](https://vercel.com/docs/sandbox) | AI sandbox | `vercel-sandbox` | `HOME=/home/vercel-sandbox` | - | | ||
| | [Daytona](https://daytona.io) | AI sandbox | `daytona` | `DAYTONA_SANDBOX_ID` | `DAYTONA_SANDBOX_ID` | | ||
| | [Modal](https://modal.com) | AI sandbox | `modal` | `MODAL_SANDBOX_ID` or `MODAL_TASK_ID` | `MODAL_SANDBOX_ID`, `MODAL_TASK_ID` | | ||
| | [Cloudflare Sandbox](https://developers.cloudflare.com/sandbox/) | AI sandbox | `cloudflare-sandbox` | `CLOUDFLARE_DURABLE_OBJECT_ID` | `CLOUDFLARE_DURABLE_OBJECT_ID` | | ||
| | [GitHub Codespaces](https://github.com/features/codespaces) | cloud IDE | `codespaces` | `CODESPACES=true` | `CODESPACE_NAME` | | ||
| | [CodeSandbox](https://codesandbox.io) | cloud IDE | `codesandbox` | `CSB=true` or `CSB_SANDBOX_ID` | `CSB_SANDBOX_ID` | | ||
| Notes: | ||
| - Rork currently runs on E2B, so `detectSandbox()` can report both `rork` and | ||
| `e2b` in `matches`. | ||
| - Lovable, v0, and Base44 are intentionally absent because they do not expose a | ||
| shell where a CLI can run. | ||
| - Some platforms do not provide a dedicated marker. Vercel Sandbox is detected | ||
| by its sandbox user home directory. | ||
| ## API | ||
@@ -84,26 +127,118 @@ | ||
| Returns a `DetectionResult`: | ||
| Returns a `DetectionResult`. | ||
| - `detected: boolean` | ||
| - `sandbox: DetectedSandbox | null` — the most specific match | ||
| - `matches: DetectedSandbox[]` — all matches, in definition order | ||
| ```ts | ||
| interface DetectionResult { | ||
| detected: boolean; | ||
| sandbox: DetectedSandbox | null; | ||
| matches: DetectedSandbox[]; | ||
| } | ||
| ``` | ||
| Each `DetectedSandbox` has `id`, `name`, `category` (`"ai-sandbox" | "app-builder" | "cloud-ide"`), optional `instanceId`, and the `evidence` (which env vars matched). | ||
| `sandbox` is the primary match. `matches` includes all matches, in definition | ||
| order. | ||
| ```ts | ||
| interface DetectedSandbox { | ||
| id: string; | ||
| name: string; | ||
| category: "ai-sandbox" | "app-builder" | "cloud-ide"; | ||
| instanceId?: string; | ||
| evidence: DetectionEvidence[]; | ||
| } | ||
| interface DetectionEvidence { | ||
| envVar: string; | ||
| value: string; | ||
| } | ||
| ``` | ||
| `evidence` contains the environment variables that caused a match. Treat the | ||
| values as runtime metadata and avoid logging them unless you are comfortable | ||
| with exposing your environment. | ||
| Options: | ||
| - `env` — environment to inspect (defaults to `process.env`) | ||
| - `sandboxes` — custom `SandboxDefinition[]` (defaults to the built-in list) | ||
| - `strategies` — custom `DetectionStrategy[]` (defaults to env-variable detection; more strategies, e.g. filesystem markers, may come later) | ||
| ```ts | ||
| interface DetectSandboxOptions { | ||
| env?: Record<string, string | undefined>; | ||
| sandboxes?: readonly SandboxDefinition[]; | ||
| strategies?: readonly DetectionStrategy[]; | ||
| } | ||
| ``` | ||
| - `env` defaults to `process.env`. | ||
| - `sandboxes` defaults to the built-in `defaultSandboxes` list. | ||
| - `strategies` defaults to environment-variable detection. | ||
| ### `isRunningInSandbox(options?)` | ||
| Convenience wrapper returning just the boolean. | ||
| Returns `true` when `detectSandbox(options).detected` is `true`. | ||
| ```ts | ||
| if (isRunningInSandbox()) { | ||
| // running in a known sandbox | ||
| } | ||
| ``` | ||
| ### `defaultSandboxes` | ||
| The built-in `SandboxDefinition[]`, exported so you can extend or filter it. | ||
| The built-in `SandboxDefinition[]`, exported so you can extend, filter, or | ||
| replace the supported environment list. | ||
| ```ts | ||
| import { defaultSandboxes, detectSandbox } from "sandbox-cli-detector"; | ||
| const result = detectSandbox({ | ||
| sandboxes: defaultSandboxes.filter((sandbox) => sandbox.category !== "cloud-ide"), | ||
| }); | ||
| ``` | ||
| ### Custom sandbox definitions | ||
| Use custom definitions when you know about an internal sandbox or want to test | ||
| against a controlled environment object. | ||
| ```ts | ||
| import { detectSandbox, defaultSandboxes } from "sandbox-cli-detector"; | ||
| const result = detectSandbox({ | ||
| env: { | ||
| INTERNAL_SANDBOX: "true", | ||
| INTERNAL_SANDBOX_ID: "dev-123", | ||
| }, | ||
| sandboxes: [ | ||
| { | ||
| id: "internal", | ||
| name: "Internal Sandbox", | ||
| category: "ai-sandbox", | ||
| env: [{ name: "INTERNAL_SANDBOX", value: "true" }], | ||
| idEnv: ["INTERNAL_SANDBOX_ID"], | ||
| verified: true, | ||
| }, | ||
| ...defaultSandboxes, | ||
| ], | ||
| }); | ||
| ``` | ||
| ## Contributing platform detections | ||
| The best detection signals are stable environment variables that are present in | ||
| every shell for that platform and absent elsewhere. | ||
| To propose a new platform, open an issue or PR with: | ||
| - The platform name and URL. | ||
| - The output of `env | sort` from inside the platform, with secrets removed. | ||
| - Which variables identify the platform. | ||
| - Which variable, if any, contains the sandbox or instance id. | ||
| You can also run: | ||
| ```sh | ||
| npx sandbox-cli-detector --json | ||
| ``` | ||
| ## License | ||
| MIT |
71837
3.74%243
125%