Sign In

sandbox-cli-detector

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sandbox-cli-detector - npm Package Compare versions

Comparing version
0.1.1
to
0.2.0
+76
dist/chunk-HZH3SATY.js
// src/sandboxes.ts
var defaultSandboxes = [
{
id: "replit",
name: "Replit",
env: [{ name: "REPLIT_SESSION" }, { name: "REPLIT_CONTAINER" }, { name: "REPLIT_USER" }]
},
{
id: "bolt",
name: "bolt.new",
env: [{ name: "BOLT_ENV" }, { name: "BOLT_ORIGIN" }, { name: "BOLT_SERVER_URL" }]
},
{
id: "e2b",
name: "E2B",
env: [{ name: "E2B_SANDBOX", value: "true" }]
},
{
id: "vercel-sandbox",
name: "Vercel Sandbox",
env: [{ name: "HOME", value: "/home/vercel-sandbox" }]
},
{
id: "daytona",
name: "Daytona",
env: [{ name: "DAYTONA_SANDBOX_ID" }]
},
{
id: "modal",
name: "Modal",
env: [{ name: "MODAL_SANDBOX_ID" }, { name: "MODAL_TASK_ID" }]
},
{
id: "cloudflare-sandbox",
name: "Cloudflare Sandbox",
env: [{ name: "CLOUDFLARE_DURABLE_OBJECT_ID" }]
},
{
id: "codespaces",
name: "GitHub Codespaces",
env: [{ name: "CODESPACES", value: "true" }]
},
{
id: "codesandbox",
name: "CodeSandbox",
env: [{ name: "CSB", value: "true" }, { name: "CSB_SANDBOX_ID" }]
}
];
// src/index.ts
function detectSandbox(options = {}) {
const env = options.env ?? process.env;
const sandboxes = options.sandboxes ?? defaultSandboxes;
const sandbox = sandboxes.find(
(candidate) => candidate.env.some((signal) => matchesEnvSignal(signal, env))
);
if (sandbox === void 0) return { detected: false };
return {
detected: true,
sandbox: { id: sandbox.id, name: sandbox.name }
};
}
function isRunningInSandbox(options = {}) {
return detectSandbox(options).detected;
}
function matchesEnvSignal(signal, env) {
const value = env[signal.name];
return value !== void 0 && value !== "" && (signal.value === void 0 || value === signal.value);
}
export {
defaultSandboxes,
detectSandbox,
isRunningInSandbox
};
//# sourceMappingURL=chunk-HZH3SATY.js.map
{"version":3,"sources":["../src/sandboxes.ts","../src/index.ts"],"sourcesContent":["import type { SandboxDefinition } from \"./types.js\";\n\nexport const defaultSandboxes = [\n {\n id: \"replit\",\n name: \"Replit\",\n env: [{ name: \"REPLIT_SESSION\" }, { name: \"REPLIT_CONTAINER\" }, { name: \"REPLIT_USER\" }],\n },\n {\n id: \"bolt\",\n name: \"bolt.new\",\n env: [{ name: \"BOLT_ENV\" }, { name: \"BOLT_ORIGIN\" }, { name: \"BOLT_SERVER_URL\" }],\n },\n {\n id: \"e2b\",\n name: \"E2B\",\n env: [{ name: \"E2B_SANDBOX\", value: \"true\" }],\n },\n {\n id: \"vercel-sandbox\",\n name: \"Vercel Sandbox\",\n env: [{ name: \"HOME\", value: \"/home/vercel-sandbox\" }],\n },\n {\n id: \"daytona\",\n name: \"Daytona\",\n env: [{ name: \"DAYTONA_SANDBOX_ID\" }],\n },\n {\n id: \"modal\",\n name: \"Modal\",\n env: [{ name: \"MODAL_SANDBOX_ID\" }, { name: \"MODAL_TASK_ID\" }],\n },\n {\n id: \"cloudflare-sandbox\",\n name: \"Cloudflare Sandbox\",\n env: [{ name: \"CLOUDFLARE_DURABLE_OBJECT_ID\" }],\n },\n {\n id: \"codespaces\",\n name: \"GitHub Codespaces\",\n env: [{ name: \"CODESPACES\", value: \"true\" }],\n },\n {\n id: \"codesandbox\",\n name: \"CodeSandbox\",\n env: [{ name: \"CSB\", value: \"true\" }, { name: \"CSB_SANDBOX_ID\" }],\n },\n] satisfies readonly SandboxDefinition[];\n","import { defaultSandboxes } from \"./sandboxes.js\";\nimport type { DetectSandboxOptions, DetectionResult, EnvSignal } from \"./types.js\";\n\nexport { defaultSandboxes } from \"./sandboxes.js\";\nexport type {\n DetectedSandbox,\n DetectionResult,\n DetectSandboxOptions,\n EnvSignal,\n SandboxDefinition,\n} from \"./types.js\";\n\nexport function detectSandbox(options: DetectSandboxOptions = {}): DetectionResult {\n const env = options.env ?? process.env;\n const sandboxes = options.sandboxes ?? defaultSandboxes;\n const sandbox = sandboxes.find((candidate) =>\n candidate.env.some((signal) => matchesEnvSignal(signal, env)),\n );\n\n if (sandbox === undefined) return { detected: false };\n\n return {\n detected: true,\n sandbox: { id: sandbox.id, name: sandbox.name },\n };\n}\n\nexport function isRunningInSandbox(options: DetectSandboxOptions = {}): boolean {\n return detectSandbox(options).detected;\n}\n\nfunction matchesEnvSignal(signal: EnvSignal, env: NodeJS.ProcessEnv): boolean {\n const value = env[signal.name];\n return (\n value !== undefined &&\n value !== \"\" &&\n (signal.value === undefined || value === signal.value)\n );\n}\n"],"mappings":";AAEO,IAAM,mBAAmB;AAAA,EAC9B;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,iBAAiB,GAAG,EAAE,MAAM,mBAAmB,GAAG,EAAE,MAAM,cAAc,CAAC;AAAA,EACzF;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,WAAW,GAAG,EAAE,MAAM,cAAc,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAAA,EAClF;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,eAAe,OAAO,OAAO,CAAC;AAAA,EAC9C;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,QAAQ,OAAO,uBAAuB,CAAC;AAAA,EACvD;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,qBAAqB,CAAC;AAAA,EACtC;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,mBAAmB,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAAA,EAC/D;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,+BAA+B,CAAC;AAAA,EAChD;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,cAAc,OAAO,OAAO,CAAC;AAAA,EAC7C;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,OAAO,OAAO,OAAO,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAAA,EAClE;AACF;;;ACpCO,SAAS,cAAc,UAAgC,CAAC,GAAoB;AACjF,QAAM,MAAM,QAAQ,OAAO,QAAQ;AACnC,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,UAAU,UAAU;AAAA,IAAK,CAAC,cAC9B,UAAU,IAAI,KAAK,CAAC,WAAW,iBAAiB,QAAQ,GAAG,CAAC;AAAA,EAC9D;AAEA,MAAI,YAAY,OAAW,QAAO,EAAE,UAAU,MAAM;AAEpD,SAAO;AAAA,IACL,UAAU;AAAA,IACV,SAAS,EAAE,IAAI,QAAQ,IAAI,MAAM,QAAQ,KAAK;AAAA,EAChD;AACF;AAEO,SAAS,mBAAmB,UAAgC,CAAC,GAAY;AAC9E,SAAO,cAAc,OAAO,EAAE;AAChC;AAEA,SAAS,iBAAiB,QAAmB,KAAiC;AAC5E,QAAM,QAAQ,IAAI,OAAO,IAAI;AAC7B,SACE,UAAU,UACV,UAAU,OACT,OAAO,UAAU,UAAa,UAAU,OAAO;AAEpD;","names":[]}
+20
-115

@@ -6,13 +6,6 @@ #!/usr/bin/env node

var defaultSandboxes = [
// ── AI app builders ────────────────────────────────────────────────────
// Lovable, v0, and Base44 are intentionally absent: they expose no shell,
// so a CLI can never run inside them.
{
id: "replit",
name: "Replit",
category: "app-builder",
// Observed inside Replit. The often-cited REPL_ID and REPLIT_ENVIRONMENT
// are NOT present in current Replit environments.
env: [{ name: "REPLIT_SESSION" }, { name: "REPLIT_CONTAINER" }, { name: "REPLIT_USER" }],
verified: true
env: [{ name: "REPLIT_SESSION" }, { name: "REPLIT_CONTAINER" }, { name: "REPLIT_USER" }]
},

@@ -22,23 +15,8 @@ {

name: "bolt.new",
category: "app-builder",
env: [{ name: "BOLT_ENV" }, { name: "BOLT_ORIGIN" }, { name: "BOLT_SERVER_URL" }],
verified: true
env: [{ name: "BOLT_ENV" }, { name: "BOLT_ORIGIN" }, { name: "BOLT_SERVER_URL" }]
},
{
id: "rork",
name: "Rork",
category: "app-builder",
// Rork runs on E2B, so e2b also appears in matches.
env: [{ name: "RORK_API_URL" }],
verified: true
},
// ── AI code-execution sandboxes ────────────────────────────────────────
{
id: "e2b",
name: "E2B",
category: "ai-sandbox",
// Documented: https://e2b.dev/docs/sandbox/environment-variables
env: [{ name: "E2B_SANDBOX", value: "true" }],
idEnv: ["E2B_SANDBOX_ID"],
verified: true
env: [{ name: "E2B_SANDBOX", value: "true" }]
},

@@ -48,7 +26,3 @@ {

name: "Vercel Sandbox",
category: "ai-sandbox",
// No dedicated marker; the microVMs run as the vercel-sandbox user.
// (PS1="▲ $PWD/" is also set, but only in interactive shells.)
env: [{ name: "HOME", value: "/home/vercel-sandbox" }],
verified: true
env: [{ name: "HOME", value: "/home/vercel-sandbox" }]
},

@@ -58,6 +32,3 @@ {

name: "Daytona",
category: "ai-sandbox",
env: [{ name: "DAYTONA_SANDBOX_ID" }],
idEnv: ["DAYTONA_SANDBOX_ID"],
verified: true
env: [{ name: "DAYTONA_SANDBOX_ID" }]
},

@@ -67,8 +38,3 @@ {

name: "Modal",
category: "ai-sandbox",
// MODAL_SANDBOX_ID observed in Modal Sandboxes; MODAL_TASK_ID is the
// documented container id (https://modal.com/docs/guide/environment_variables).
env: [{ name: "MODAL_SANDBOX_ID" }, { name: "MODAL_TASK_ID" }],
idEnv: ["MODAL_SANDBOX_ID", "MODAL_TASK_ID"],
verified: true
env: [{ name: "MODAL_SANDBOX_ID" }, { name: "MODAL_TASK_ID" }]
},

@@ -78,15 +44,8 @@ {

name: "Cloudflare Sandbox",
category: "ai-sandbox",
env: [{ name: "CLOUDFLARE_DURABLE_OBJECT_ID" }],
idEnv: ["CLOUDFLARE_DURABLE_OBJECT_ID"],
verified: true
env: [{ name: "CLOUDFLARE_DURABLE_OBJECT_ID" }]
},
// ── Cloud development environments ─────────────────────────────────────
{
id: "codespaces",
name: "GitHub Codespaces",
category: "cloud-ide",
env: [{ name: "CODESPACES", value: "true" }],
idEnv: ["CODESPACE_NAME"],
verified: true
env: [{ name: "CODESPACES", value: "true" }]
},

@@ -96,51 +55,6 @@ {

name: "CodeSandbox",
category: "cloud-ide",
env: [{ name: "CSB", value: "true" }, { name: "CSB_SANDBOX_ID" }],
idEnv: ["CSB_SANDBOX_ID"],
verified: true
env: [{ name: "CSB", value: "true" }, { name: "CSB_SANDBOX_ID" }]
}
];
// src/strategies.ts
function matchCondition(condition, env) {
const value = env[condition.name];
if (value === void 0 || value === "") return null;
if (condition.value !== void 0 && value !== condition.value) return null;
return { envVar: condition.name, value };
}
var EnvironmentDetectionStrategy = class {
id = "env";
detect(sandbox, context) {
for (const matcher of sandbox.env) {
const conditions = Array.isArray(matcher) ? matcher : [matcher];
if (conditions.length === 0) continue;
const evidence = [];
for (const condition of conditions) {
const matched = matchCondition(condition, context.env);
if (!matched) break;
evidence.push(matched);
}
if (evidence.length !== conditions.length) continue;
return {
id: sandbox.id,
name: sandbox.name,
category: sandbox.category,
instanceId: this.findInstanceId(sandbox, context),
evidence
};
}
return null;
}
findInstanceId(sandbox, context) {
for (const name of sandbox.idEnv ?? []) {
const value = context.env[name];
if (value) return value;
}
return void 0;
}
};
function createDefaultStrategies() {
return [new EnvironmentDetectionStrategy()];
}
// src/index.ts

@@ -150,20 +64,15 @@ function detectSandbox(options = {}) {

const sandboxes = options.sandboxes ?? defaultSandboxes;
const strategies = options.strategies ?? createDefaultStrategies();
const context = { env };
const matches = [];
for (const sandbox of sandboxes) {
for (const strategy of strategies) {
const detected = strategy.detect(sandbox, context);
if (detected) {
matches.push(detected);
break;
}
}
}
const sandbox = sandboxes.find(
(candidate) => candidate.env.some((signal) => matchesEnvSignal(signal, env))
);
if (sandbox === void 0) return { detected: false };
return {
detected: matches.length > 0,
sandbox: matches[0] ?? null,
matches
detected: true,
sandbox: { id: sandbox.id, name: sandbox.name }
};
}
function matchesEnvSignal(signal, env) {
const value = env[signal.name];
return value !== void 0 && value !== "" && (signal.value === void 0 || value === signal.value);
}

@@ -192,7 +101,3 @@ // src/cli.ts

} else if (result.sandbox) {
const id = result.sandbox.instanceId ? ` (${result.sandbox.instanceId})` : "";
console.log(`detected: ${result.sandbox.name}${id}`);
for (const match of result.matches.slice(1)) {
console.log(`also matched: ${match.name}`);
}
console.log(`detected: ${result.sandbox.name}`);
} else {

@@ -199,0 +104,0 @@ console.log("no sandbox detected");

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/sandboxes.ts","../src/strategies.ts","../src/index.ts","../src/cli.ts"],"sourcesContent":["import type { SandboxDefinition } from \"./types.js\";\n\n/**\n * Built-in sandbox definitions.\n *\n * Ordered by specificity: app builders first (they often run on top of the\n * generic AI sandboxes below), then AI code-execution sandboxes, then cloud\n * development environments. Detection returns the first match as the primary\n * result but reports all matches.\n *\n * Only environments whose markers were confirmed by probing the real\n * platform are listed — no guessed or documentation-only markers.\n */\nexport const defaultSandboxes: readonly SandboxDefinition[] = [\n // ── AI app builders ────────────────────────────────────────────────────\n // Lovable, v0, and Base44 are intentionally absent: they expose no shell,\n // so a CLI can never run inside them.\n {\n id: \"replit\",\n name: \"Replit\",\n category: \"app-builder\",\n // Observed inside Replit. The often-cited REPL_ID and REPLIT_ENVIRONMENT\n // are NOT present in current Replit environments.\n env: [{ name: \"REPLIT_SESSION\" }, { name: \"REPLIT_CONTAINER\" }, { name: \"REPLIT_USER\" }],\n verified: true,\n },\n {\n id: \"bolt\",\n name: \"bolt.new\",\n category: \"app-builder\",\n env: [{ name: \"BOLT_ENV\" }, { name: \"BOLT_ORIGIN\" }, { name: \"BOLT_SERVER_URL\" }],\n verified: true,\n },\n {\n id: \"rork\",\n name: \"Rork\",\n category: \"app-builder\",\n // Rork runs on E2B, so e2b also appears in matches.\n env: [{ name: \"RORK_API_URL\" }],\n verified: true,\n },\n\n // ── AI code-execution sandboxes ────────────────────────────────────────\n {\n id: \"e2b\",\n name: \"E2B\",\n category: \"ai-sandbox\",\n // Documented: https://e2b.dev/docs/sandbox/environment-variables\n env: [{ name: \"E2B_SANDBOX\", value: \"true\" }],\n idEnv: [\"E2B_SANDBOX_ID\"],\n verified: true,\n },\n {\n id: \"vercel-sandbox\",\n name: \"Vercel Sandbox\",\n category: \"ai-sandbox\",\n // No dedicated marker; the microVMs run as the vercel-sandbox user.\n // (PS1=\"▲ $PWD/\" is also set, but only in interactive shells.)\n env: [{ name: \"HOME\", value: \"/home/vercel-sandbox\" }],\n verified: true,\n },\n {\n id: \"daytona\",\n name: \"Daytona\",\n category: \"ai-sandbox\",\n env: [{ name: \"DAYTONA_SANDBOX_ID\" }],\n idEnv: [\"DAYTONA_SANDBOX_ID\"],\n verified: true,\n },\n {\n id: \"modal\",\n name: \"Modal\",\n category: \"ai-sandbox\",\n // MODAL_SANDBOX_ID observed in Modal Sandboxes; MODAL_TASK_ID is the\n // documented container id (https://modal.com/docs/guide/environment_variables).\n env: [{ name: \"MODAL_SANDBOX_ID\" }, { name: \"MODAL_TASK_ID\" }],\n idEnv: [\"MODAL_SANDBOX_ID\", \"MODAL_TASK_ID\"],\n verified: true,\n },\n {\n id: \"cloudflare-sandbox\",\n name: \"Cloudflare Sandbox\",\n category: \"ai-sandbox\",\n env: [{ name: \"CLOUDFLARE_DURABLE_OBJECT_ID\" }],\n idEnv: [\"CLOUDFLARE_DURABLE_OBJECT_ID\"],\n verified: true,\n },\n\n // ── Cloud development environments ─────────────────────────────────────\n {\n id: \"codespaces\",\n name: \"GitHub Codespaces\",\n category: \"cloud-ide\",\n env: [{ name: \"CODESPACES\", value: \"true\" }],\n idEnv: [\"CODESPACE_NAME\"],\n verified: true,\n },\n {\n id: \"codesandbox\",\n name: \"CodeSandbox\",\n category: \"cloud-ide\",\n env: [{ name: \"CSB\", value: \"true\" }, { name: \"CSB_SANDBOX_ID\" }],\n idEnv: [\"CSB_SANDBOX_ID\"],\n verified: true,\n },\n];\n","import type {\n DetectedSandbox,\n DetectionContext,\n DetectionEvidence,\n DetectionStrategy,\n EnvCondition,\n SandboxDefinition,\n} from \"./types.js\";\n\nfunction matchCondition(\n condition: EnvCondition,\n env: Record<string, string | undefined>,\n): DetectionEvidence | null {\n const value = env[condition.name];\n if (value === undefined || value === \"\") return null;\n if (condition.value !== undefined && value !== condition.value) return null;\n return { envVar: condition.name, value };\n}\n\n/** Detects a sandbox purely from environment variables. */\nexport class EnvironmentDetectionStrategy implements DetectionStrategy {\n readonly id = \"env\";\n\n detect(sandbox: SandboxDefinition, context: DetectionContext): DetectedSandbox | null {\n for (const matcher of sandbox.env) {\n const conditions = Array.isArray(matcher) ? matcher : [matcher];\n if (conditions.length === 0) continue;\n\n const evidence: DetectionEvidence[] = [];\n for (const condition of conditions) {\n const matched = matchCondition(condition, context.env);\n if (!matched) break;\n evidence.push(matched);\n }\n if (evidence.length !== conditions.length) continue;\n\n return {\n id: sandbox.id,\n name: sandbox.name,\n category: sandbox.category,\n instanceId: this.findInstanceId(sandbox, context),\n evidence,\n };\n }\n return null;\n }\n\n private findInstanceId(\n sandbox: SandboxDefinition,\n context: DetectionContext,\n ): string | undefined {\n for (const name of sandbox.idEnv ?? []) {\n const value = context.env[name];\n if (value) return value;\n }\n return undefined;\n }\n}\n\nexport function createDefaultStrategies(): DetectionStrategy[] {\n return [new EnvironmentDetectionStrategy()];\n}\n","import { defaultSandboxes } from \"./sandboxes.js\";\nimport { createDefaultStrategies } from \"./strategies.js\";\nimport type { DetectedSandbox, DetectionResult, DetectSandboxOptions } from \"./types.js\";\n\nexport { defaultSandboxes } from \"./sandboxes.js\";\nexport { createDefaultStrategies, EnvironmentDetectionStrategy } from \"./strategies.js\";\nexport type {\n DetectedSandbox,\n DetectionContext,\n DetectionEvidence,\n DetectionResult,\n DetectionStrategy,\n DetectSandboxOptions,\n EnvCondition,\n EnvMatcher,\n SandboxCategory,\n SandboxDefinition,\n} from \"./types.js\";\n\n/**\n * Detect whether the current process runs inside a known sandboxed\n * environment (AI code-execution sandbox, AI app builder, or cloud IDE).\n */\nexport function detectSandbox(options: DetectSandboxOptions = {}): DetectionResult {\n const env = options.env ?? process.env;\n const sandboxes = options.sandboxes ?? defaultSandboxes;\n const strategies = options.strategies ?? createDefaultStrategies();\n const context = { env };\n\n const matches: DetectedSandbox[] = [];\n for (const sandbox of sandboxes) {\n for (const strategy of strategies) {\n const detected = strategy.detect(sandbox, context);\n if (detected) {\n matches.push(detected);\n break;\n }\n }\n }\n\n return {\n detected: matches.length > 0,\n sandbox: matches[0] ?? null,\n matches,\n };\n}\n\n/** Convenience wrapper returning just the boolean. */\nexport function isRunningInSandbox(options: DetectSandboxOptions = {}): boolean {\n return detectSandbox(options).detected;\n}\n","#!/usr/bin/env node\nimport { detectSandbox } from \"./index.js\";\n\nconst args = new Set(process.argv.slice(2));\n\nif (args.has(\"-h\") || args.has(\"--help\")) {\n console.log(`Usage: sandbox-cli-detector [options]\n\nDetect whether this process runs inside a sandboxed environment.\n\nOptions:\n --json Print the full detection result as JSON\n --quiet No output, exit code only\n -h, --help Show this help\n\nExit codes:\n 0 sandbox detected\n 1 no sandbox detected`);\n process.exit(0);\n}\n\nconst result = detectSandbox();\n\nif (!args.has(\"--quiet\")) {\n if (args.has(\"--json\")) {\n console.log(JSON.stringify(result, null, 2));\n } else if (result.sandbox) {\n const id = result.sandbox.instanceId ? ` (${result.sandbox.instanceId})` : \"\";\n console.log(`detected: ${result.sandbox.name}${id}`);\n for (const match of result.matches.slice(1)) {\n console.log(`also matched: ${match.name}`);\n }\n } else {\n console.log(\"no sandbox detected\");\n }\n}\n\nprocess.exitCode = result.detected ? 0 : 1;\n"],"mappings":"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","names":[]}
{"version":3,"sources":["../src/sandboxes.ts","../src/index.ts","../src/cli.ts"],"sourcesContent":["import type { SandboxDefinition } from \"./types.js\";\n\nexport const defaultSandboxes = [\n {\n id: \"replit\",\n name: \"Replit\",\n env: [{ name: \"REPLIT_SESSION\" }, { name: \"REPLIT_CONTAINER\" }, { name: \"REPLIT_USER\" }],\n },\n {\n id: \"bolt\",\n name: \"bolt.new\",\n env: [{ name: \"BOLT_ENV\" }, { name: \"BOLT_ORIGIN\" }, { name: \"BOLT_SERVER_URL\" }],\n },\n {\n id: \"e2b\",\n name: \"E2B\",\n env: [{ name: \"E2B_SANDBOX\", value: \"true\" }],\n },\n {\n id: \"vercel-sandbox\",\n name: \"Vercel Sandbox\",\n env: [{ name: \"HOME\", value: \"/home/vercel-sandbox\" }],\n },\n {\n id: \"daytona\",\n name: \"Daytona\",\n env: [{ name: \"DAYTONA_SANDBOX_ID\" }],\n },\n {\n id: \"modal\",\n name: \"Modal\",\n env: [{ name: \"MODAL_SANDBOX_ID\" }, { name: \"MODAL_TASK_ID\" }],\n },\n {\n id: \"cloudflare-sandbox\",\n name: \"Cloudflare Sandbox\",\n env: [{ name: \"CLOUDFLARE_DURABLE_OBJECT_ID\" }],\n },\n {\n id: \"codespaces\",\n name: \"GitHub Codespaces\",\n env: [{ name: \"CODESPACES\", value: \"true\" }],\n },\n {\n id: \"codesandbox\",\n name: \"CodeSandbox\",\n env: [{ name: \"CSB\", value: \"true\" }, { name: \"CSB_SANDBOX_ID\" }],\n },\n] satisfies readonly SandboxDefinition[];\n","import { defaultSandboxes } from \"./sandboxes.js\";\nimport type { DetectSandboxOptions, DetectionResult, EnvSignal } from \"./types.js\";\n\nexport { defaultSandboxes } from \"./sandboxes.js\";\nexport type {\n DetectedSandbox,\n DetectionResult,\n DetectSandboxOptions,\n EnvSignal,\n SandboxDefinition,\n} from \"./types.js\";\n\nexport function detectSandbox(options: DetectSandboxOptions = {}): DetectionResult {\n const env = options.env ?? process.env;\n const sandboxes = options.sandboxes ?? defaultSandboxes;\n const sandbox = sandboxes.find((candidate) =>\n candidate.env.some((signal) => matchesEnvSignal(signal, env)),\n );\n\n if (sandbox === undefined) return { detected: false };\n\n return {\n detected: true,\n sandbox: { id: sandbox.id, name: sandbox.name },\n };\n}\n\nexport function isRunningInSandbox(options: DetectSandboxOptions = {}): boolean {\n return detectSandbox(options).detected;\n}\n\nfunction matchesEnvSignal(signal: EnvSignal, env: NodeJS.ProcessEnv): boolean {\n const value = env[signal.name];\n return (\n value !== undefined &&\n value !== \"\" &&\n (signal.value === undefined || value === signal.value)\n );\n}\n","#!/usr/bin/env node\nimport { detectSandbox } from \"./index.js\";\n\nconst args = new Set(process.argv.slice(2));\n\nif (args.has(\"-h\") || args.has(\"--help\")) {\n console.log(`Usage: sandbox-cli-detector [options]\n\nDetect whether this process runs inside a sandboxed environment.\n\nOptions:\n --json Print the full detection result as JSON\n --quiet No output, exit code only\n -h, --help Show this help\n\nExit codes:\n 0 sandbox detected\n 1 no sandbox detected`);\n process.exit(0);\n}\n\nconst result = detectSandbox();\n\nif (!args.has(\"--quiet\")) {\n if (args.has(\"--json\")) {\n console.log(JSON.stringify(result, null, 2));\n } else if (result.sandbox) {\n console.log(`detected: ${result.sandbox.name}`);\n } else {\n console.log(\"no sandbox detected\");\n }\n}\n\nprocess.exitCode = result.detected ? 0 : 1;\n"],"mappings":";;;;AAEO,IAAM,mBAAmB;AAAA,EAC9B;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,iBAAiB,GAAG,EAAE,MAAM,mBAAmB,GAAG,EAAE,MAAM,cAAc,CAAC;AAAA,EACzF;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,WAAW,GAAG,EAAE,MAAM,cAAc,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAAA,EAClF;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,eAAe,OAAO,OAAO,CAAC;AAAA,EAC9C;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,QAAQ,OAAO,uBAAuB,CAAC;AAAA,EACvD;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,qBAAqB,CAAC;AAAA,EACtC;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,mBAAmB,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAAA,EAC/D;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,+BAA+B,CAAC;AAAA,EAChD;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,cAAc,OAAO,OAAO,CAAC;AAAA,EAC7C;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,OAAO,OAAO,OAAO,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAAA,EAClE;AACF;;;ACpCO,SAAS,cAAc,UAAgC,CAAC,GAAoB;AACjF,QAAM,MAAM,QAAQ,OAAO,QAAQ;AACnC,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,UAAU,UAAU;AAAA,IAAK,CAAC,cAC9B,UAAU,IAAI,KAAK,CAAC,WAAW,iBAAiB,QAAQ,GAAG,CAAC;AAAA,EAC9D;AAEA,MAAI,YAAY,OAAW,QAAO,EAAE,UAAU,MAAM;AAEpD,SAAO;AAAA,IACL,UAAU;AAAA,IACV,SAAS,EAAE,IAAI,QAAQ,IAAI,MAAM,QAAQ,KAAK;AAAA,EAChD;AACF;AAMA,SAAS,iBAAiB,QAAmB,KAAiC;AAC5E,QAAM,QAAQ,IAAI,OAAO,IAAI;AAC7B,SACE,UAAU,UACV,UAAU,OACT,OAAO,UAAU,UAAa,UAAU,OAAO;AAEpD;;;ACnCA,IAAM,OAAO,IAAI,IAAI,QAAQ,KAAK,MAAM,CAAC,CAAC;AAE1C,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,QAAQ,GAAG;AACxC,UAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAWW;AACvB,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAM,SAAS,cAAc;AAE7B,IAAI,CAAC,KAAK,IAAI,SAAS,GAAG;AACxB,MAAI,KAAK,IAAI,QAAQ,GAAG;AACtB,YAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,EAC7C,WAAW,OAAO,SAAS;AACzB,YAAQ,IAAI,aAAa,OAAO,QAAQ,IAAI,EAAE;AAAA,EAChD,OAAO;AACL,YAAQ,IAAI,qBAAqB;AAAA,EACnC;AACF;AAEA,QAAQ,WAAW,OAAO,WAAW,IAAI;","names":[]}
#!/usr/bin/env node
import {
detectSandbox
} from "./chunk-2S3637PR.js";
} from "./chunk-HZH3SATY.js";

@@ -28,7 +28,3 @@ // src/cli.ts

} else if (result.sandbox) {
const id = result.sandbox.instanceId ? ` (${result.sandbox.instanceId})` : "";
console.log(`detected: ${result.sandbox.name}${id}`);
for (const match of result.matches.slice(1)) {
console.log(`also matched: ${match.name}`);
}
console.log(`detected: ${result.sandbox.name}`);
} else {

@@ -35,0 +31,0 @@ console.log("no sandbox detected");

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { detectSandbox } from \"./index.js\";\n\nconst args = new Set(process.argv.slice(2));\n\nif (args.has(\"-h\") || args.has(\"--help\")) {\n console.log(`Usage: sandbox-cli-detector [options]\n\nDetect whether this process runs inside a sandboxed environment.\n\nOptions:\n --json Print the full detection result as JSON\n --quiet No output, exit code only\n -h, --help Show this help\n\nExit codes:\n 0 sandbox detected\n 1 no sandbox detected`);\n process.exit(0);\n}\n\nconst result = detectSandbox();\n\nif (!args.has(\"--quiet\")) {\n if (args.has(\"--json\")) {\n console.log(JSON.stringify(result, null, 2));\n } else if (result.sandbox) {\n const id = result.sandbox.instanceId ? ` (${result.sandbox.instanceId})` : \"\";\n console.log(`detected: ${result.sandbox.name}${id}`);\n for (const match of result.matches.slice(1)) {\n console.log(`also matched: ${match.name}`);\n }\n } else {\n console.log(\"no sandbox detected\");\n }\n}\n\nprocess.exitCode = result.detected ? 0 : 1;\n"],"mappings":";;;;;;AAGA,IAAM,OAAO,IAAI,IAAI,QAAQ,KAAK,MAAM,CAAC,CAAC;AAE1C,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,QAAQ,GAAG;AACxC,UAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAWW;AACvB,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAM,SAAS,cAAc;AAE7B,IAAI,CAAC,KAAK,IAAI,SAAS,GAAG;AACxB,MAAI,KAAK,IAAI,QAAQ,GAAG;AACtB,YAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,EAC7C,WAAW,OAAO,SAAS;AACzB,UAAM,KAAK,OAAO,QAAQ,aAAa,KAAK,OAAO,QAAQ,UAAU,MAAM;AAC3E,YAAQ,IAAI,aAAa,OAAO,QAAQ,IAAI,GAAG,EAAE,EAAE;AACnD,eAAW,SAAS,OAAO,QAAQ,MAAM,CAAC,GAAG;AAC3C,cAAQ,IAAI,iBAAiB,MAAM,IAAI,EAAE;AAAA,IAC3C;AAAA,EACF,OAAO;AACL,YAAQ,IAAI,qBAAqB;AAAA,EACnC;AACF;AAEA,QAAQ,WAAW,OAAO,WAAW,IAAI;","names":[]}
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { detectSandbox } from \"./index.js\";\n\nconst args = new Set(process.argv.slice(2));\n\nif (args.has(\"-h\") || args.has(\"--help\")) {\n console.log(`Usage: sandbox-cli-detector [options]\n\nDetect whether this process runs inside a sandboxed environment.\n\nOptions:\n --json Print the full detection result as JSON\n --quiet No output, exit code only\n -h, --help Show this help\n\nExit codes:\n 0 sandbox detected\n 1 no sandbox detected`);\n process.exit(0);\n}\n\nconst result = detectSandbox();\n\nif (!args.has(\"--quiet\")) {\n if (args.has(\"--json\")) {\n console.log(JSON.stringify(result, null, 2));\n } else if (result.sandbox) {\n console.log(`detected: ${result.sandbox.name}`);\n } else {\n console.log(\"no sandbox detected\");\n }\n}\n\nprocess.exitCode = result.detected ? 0 : 1;\n"],"mappings":";;;;;;AAGA,IAAM,OAAO,IAAI,IAAI,QAAQ,KAAK,MAAM,CAAC,CAAC;AAE1C,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,QAAQ,GAAG;AACxC,UAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAWW;AACvB,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAM,SAAS,cAAc;AAE7B,IAAI,CAAC,KAAK,IAAI,SAAS,GAAG;AACxB,MAAI,KAAK,IAAI,QAAQ,GAAG;AACtB,YAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,EAC7C,WAAW,OAAO,SAAS;AACzB,YAAQ,IAAI,aAAa,OAAO,QAAQ,IAAI,EAAE;AAAA,EAChD,OAAO;AACL,YAAQ,IAAI,qBAAqB;AAAA,EACnC;AACF;AAEA,QAAQ,WAAW,OAAO,WAAW,IAAI;","names":[]}

@@ -23,4 +23,2 @@ "use strict";

__export(index_exports, {
EnvironmentDetectionStrategy: () => EnvironmentDetectionStrategy,
createDefaultStrategies: () => createDefaultStrategies,
defaultSandboxes: () => defaultSandboxes,

@@ -34,13 +32,6 @@ detectSandbox: () => detectSandbox,

var defaultSandboxes = [
// ── AI app builders ────────────────────────────────────────────────────
// Lovable, v0, and Base44 are intentionally absent: they expose no shell,
// so a CLI can never run inside them.
{
id: "replit",
name: "Replit",
category: "app-builder",
// Observed inside Replit. The often-cited REPL_ID and REPLIT_ENVIRONMENT
// are NOT present in current Replit environments.
env: [{ name: "REPLIT_SESSION" }, { name: "REPLIT_CONTAINER" }, { name: "REPLIT_USER" }],
verified: true
env: [{ name: "REPLIT_SESSION" }, { name: "REPLIT_CONTAINER" }, { name: "REPLIT_USER" }]
},

@@ -50,23 +41,8 @@ {

name: "bolt.new",
category: "app-builder",
env: [{ name: "BOLT_ENV" }, { name: "BOLT_ORIGIN" }, { name: "BOLT_SERVER_URL" }],
verified: true
env: [{ name: "BOLT_ENV" }, { name: "BOLT_ORIGIN" }, { name: "BOLT_SERVER_URL" }]
},
{
id: "rork",
name: "Rork",
category: "app-builder",
// Rork runs on E2B, so e2b also appears in matches.
env: [{ name: "RORK_API_URL" }],
verified: true
},
// ── AI code-execution sandboxes ────────────────────────────────────────
{
id: "e2b",
name: "E2B",
category: "ai-sandbox",
// Documented: https://e2b.dev/docs/sandbox/environment-variables
env: [{ name: "E2B_SANDBOX", value: "true" }],
idEnv: ["E2B_SANDBOX_ID"],
verified: true
env: [{ name: "E2B_SANDBOX", value: "true" }]
},

@@ -76,7 +52,3 @@ {

name: "Vercel Sandbox",
category: "ai-sandbox",
// No dedicated marker; the microVMs run as the vercel-sandbox user.
// (PS1="▲ $PWD/" is also set, but only in interactive shells.)
env: [{ name: "HOME", value: "/home/vercel-sandbox" }],
verified: true
env: [{ name: "HOME", value: "/home/vercel-sandbox" }]
},

@@ -86,6 +58,3 @@ {

name: "Daytona",
category: "ai-sandbox",
env: [{ name: "DAYTONA_SANDBOX_ID" }],
idEnv: ["DAYTONA_SANDBOX_ID"],
verified: true
env: [{ name: "DAYTONA_SANDBOX_ID" }]
},

@@ -95,8 +64,3 @@ {

name: "Modal",
category: "ai-sandbox",
// MODAL_SANDBOX_ID observed in Modal Sandboxes; MODAL_TASK_ID is the
// documented container id (https://modal.com/docs/guide/environment_variables).
env: [{ name: "MODAL_SANDBOX_ID" }, { name: "MODAL_TASK_ID" }],
idEnv: ["MODAL_SANDBOX_ID", "MODAL_TASK_ID"],
verified: true
env: [{ name: "MODAL_SANDBOX_ID" }, { name: "MODAL_TASK_ID" }]
},

@@ -106,15 +70,8 @@ {

name: "Cloudflare Sandbox",
category: "ai-sandbox",
env: [{ name: "CLOUDFLARE_DURABLE_OBJECT_ID" }],
idEnv: ["CLOUDFLARE_DURABLE_OBJECT_ID"],
verified: true
env: [{ name: "CLOUDFLARE_DURABLE_OBJECT_ID" }]
},
// ── Cloud development environments ─────────────────────────────────────
{
id: "codespaces",
name: "GitHub Codespaces",
category: "cloud-ide",
env: [{ name: "CODESPACES", value: "true" }],
idEnv: ["CODESPACE_NAME"],
verified: true
env: [{ name: "CODESPACES", value: "true" }]
},

@@ -124,51 +81,6 @@ {

name: "CodeSandbox",
category: "cloud-ide",
env: [{ name: "CSB", value: "true" }, { name: "CSB_SANDBOX_ID" }],
idEnv: ["CSB_SANDBOX_ID"],
verified: true
env: [{ name: "CSB", value: "true" }, { name: "CSB_SANDBOX_ID" }]
}
];
// src/strategies.ts
function matchCondition(condition, env) {
const value = env[condition.name];
if (value === void 0 || value === "") return null;
if (condition.value !== void 0 && value !== condition.value) return null;
return { envVar: condition.name, value };
}
var EnvironmentDetectionStrategy = class {
id = "env";
detect(sandbox, context) {
for (const matcher of sandbox.env) {
const conditions = Array.isArray(matcher) ? matcher : [matcher];
if (conditions.length === 0) continue;
const evidence = [];
for (const condition of conditions) {
const matched = matchCondition(condition, context.env);
if (!matched) break;
evidence.push(matched);
}
if (evidence.length !== conditions.length) continue;
return {
id: sandbox.id,
name: sandbox.name,
category: sandbox.category,
instanceId: this.findInstanceId(sandbox, context),
evidence
};
}
return null;
}
findInstanceId(sandbox, context) {
for (const name of sandbox.idEnv ?? []) {
const value = context.env[name];
if (value) return value;
}
return void 0;
}
};
function createDefaultStrategies() {
return [new EnvironmentDetectionStrategy()];
}
// src/index.ts

@@ -178,18 +90,9 @@ function detectSandbox(options = {}) {

const sandboxes = options.sandboxes ?? defaultSandboxes;
const strategies = options.strategies ?? createDefaultStrategies();
const context = { env };
const matches = [];
for (const sandbox of sandboxes) {
for (const strategy of strategies) {
const detected = strategy.detect(sandbox, context);
if (detected) {
matches.push(detected);
break;
}
}
}
const sandbox = sandboxes.find(
(candidate) => candidate.env.some((signal) => matchesEnvSignal(signal, env))
);
if (sandbox === void 0) return { detected: false };
return {
detected: matches.length > 0,
sandbox: matches[0] ?? null,
matches
detected: true,
sandbox: { id: sandbox.id, name: sandbox.name }
};

@@ -200,6 +103,8 @@ }

}
function matchesEnvSignal(signal, env) {
const value = env[signal.name];
return value !== void 0 && value !== "" && (signal.value === void 0 || value === signal.value);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
EnvironmentDetectionStrategy,
createDefaultStrategies,
defaultSandboxes,

@@ -206,0 +111,0 @@ detectSandbox,

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/index.ts","../src/sandboxes.ts","../src/strategies.ts"],"sourcesContent":["import { defaultSandboxes } from \"./sandboxes.js\";\nimport { createDefaultStrategies } from \"./strategies.js\";\nimport type { DetectedSandbox, DetectionResult, DetectSandboxOptions } from \"./types.js\";\n\nexport { defaultSandboxes } from \"./sandboxes.js\";\nexport { createDefaultStrategies, EnvironmentDetectionStrategy } from \"./strategies.js\";\nexport type {\n DetectedSandbox,\n DetectionContext,\n DetectionEvidence,\n DetectionResult,\n DetectionStrategy,\n DetectSandboxOptions,\n EnvCondition,\n EnvMatcher,\n SandboxCategory,\n SandboxDefinition,\n} from \"./types.js\";\n\n/**\n * Detect whether the current process runs inside a known sandboxed\n * environment (AI code-execution sandbox, AI app builder, or cloud IDE).\n */\nexport function detectSandbox(options: DetectSandboxOptions = {}): DetectionResult {\n const env = options.env ?? process.env;\n const sandboxes = options.sandboxes ?? defaultSandboxes;\n const strategies = options.strategies ?? createDefaultStrategies();\n const context = { env };\n\n const matches: DetectedSandbox[] = [];\n for (const sandbox of sandboxes) {\n for (const strategy of strategies) {\n const detected = strategy.detect(sandbox, context);\n if (detected) {\n matches.push(detected);\n break;\n }\n }\n }\n\n return {\n detected: matches.length > 0,\n sandbox: matches[0] ?? null,\n matches,\n };\n}\n\n/** Convenience wrapper returning just the boolean. */\nexport function isRunningInSandbox(options: DetectSandboxOptions = {}): boolean {\n return detectSandbox(options).detected;\n}\n","import type { SandboxDefinition } from \"./types.js\";\n\n/**\n * Built-in sandbox definitions.\n *\n * Ordered by specificity: app builders first (they often run on top of the\n * generic AI sandboxes below), then AI code-execution sandboxes, then cloud\n * development environments. Detection returns the first match as the primary\n * result but reports all matches.\n *\n * Only environments whose markers were confirmed by probing the real\n * platform are listed — no guessed or documentation-only markers.\n */\nexport const defaultSandboxes: readonly SandboxDefinition[] = [\n // ── AI app builders ────────────────────────────────────────────────────\n // Lovable, v0, and Base44 are intentionally absent: they expose no shell,\n // so a CLI can never run inside them.\n {\n id: \"replit\",\n name: \"Replit\",\n category: \"app-builder\",\n // Observed inside Replit. The often-cited REPL_ID and REPLIT_ENVIRONMENT\n // are NOT present in current Replit environments.\n env: [{ name: \"REPLIT_SESSION\" }, { name: \"REPLIT_CONTAINER\" }, { name: \"REPLIT_USER\" }],\n verified: true,\n },\n {\n id: \"bolt\",\n name: \"bolt.new\",\n category: \"app-builder\",\n env: [{ name: \"BOLT_ENV\" }, { name: \"BOLT_ORIGIN\" }, { name: \"BOLT_SERVER_URL\" }],\n verified: true,\n },\n {\n id: \"rork\",\n name: \"Rork\",\n category: \"app-builder\",\n // Rork runs on E2B, so e2b also appears in matches.\n env: [{ name: \"RORK_API_URL\" }],\n verified: true,\n },\n\n // ── AI code-execution sandboxes ────────────────────────────────────────\n {\n id: \"e2b\",\n name: \"E2B\",\n category: \"ai-sandbox\",\n // Documented: https://e2b.dev/docs/sandbox/environment-variables\n env: [{ name: \"E2B_SANDBOX\", value: \"true\" }],\n idEnv: [\"E2B_SANDBOX_ID\"],\n verified: true,\n },\n {\n id: \"vercel-sandbox\",\n name: \"Vercel Sandbox\",\n category: \"ai-sandbox\",\n // No dedicated marker; the microVMs run as the vercel-sandbox user.\n // (PS1=\"▲ $PWD/\" is also set, but only in interactive shells.)\n env: [{ name: \"HOME\", value: \"/home/vercel-sandbox\" }],\n verified: true,\n },\n {\n id: \"daytona\",\n name: \"Daytona\",\n category: \"ai-sandbox\",\n env: [{ name: \"DAYTONA_SANDBOX_ID\" }],\n idEnv: [\"DAYTONA_SANDBOX_ID\"],\n verified: true,\n },\n {\n id: \"modal\",\n name: \"Modal\",\n category: \"ai-sandbox\",\n // MODAL_SANDBOX_ID observed in Modal Sandboxes; MODAL_TASK_ID is the\n // documented container id (https://modal.com/docs/guide/environment_variables).\n env: [{ name: \"MODAL_SANDBOX_ID\" }, { name: \"MODAL_TASK_ID\" }],\n idEnv: [\"MODAL_SANDBOX_ID\", \"MODAL_TASK_ID\"],\n verified: true,\n },\n {\n id: \"cloudflare-sandbox\",\n name: \"Cloudflare Sandbox\",\n category: \"ai-sandbox\",\n env: [{ name: \"CLOUDFLARE_DURABLE_OBJECT_ID\" }],\n idEnv: [\"CLOUDFLARE_DURABLE_OBJECT_ID\"],\n verified: true,\n },\n\n // ── Cloud development environments ─────────────────────────────────────\n {\n id: \"codespaces\",\n name: \"GitHub Codespaces\",\n category: \"cloud-ide\",\n env: [{ name: \"CODESPACES\", value: \"true\" }],\n idEnv: [\"CODESPACE_NAME\"],\n verified: true,\n },\n {\n id: \"codesandbox\",\n name: \"CodeSandbox\",\n category: \"cloud-ide\",\n env: [{ name: \"CSB\", value: \"true\" }, { name: \"CSB_SANDBOX_ID\" }],\n idEnv: [\"CSB_SANDBOX_ID\"],\n verified: true,\n },\n];\n","import type {\n DetectedSandbox,\n DetectionContext,\n DetectionEvidence,\n DetectionStrategy,\n EnvCondition,\n SandboxDefinition,\n} from \"./types.js\";\n\nfunction matchCondition(\n condition: EnvCondition,\n env: Record<string, string | undefined>,\n): DetectionEvidence | null {\n const value = env[condition.name];\n if (value === undefined || value === \"\") return null;\n if (condition.value !== undefined && value !== condition.value) return null;\n return { envVar: condition.name, value };\n}\n\n/** Detects a sandbox purely from environment variables. */\nexport class EnvironmentDetectionStrategy implements DetectionStrategy {\n readonly id = \"env\";\n\n detect(sandbox: SandboxDefinition, context: DetectionContext): DetectedSandbox | null {\n for (const matcher of sandbox.env) {\n const conditions = Array.isArray(matcher) ? matcher : [matcher];\n if (conditions.length === 0) continue;\n\n const evidence: DetectionEvidence[] = [];\n for (const condition of conditions) {\n const matched = matchCondition(condition, context.env);\n if (!matched) break;\n evidence.push(matched);\n }\n if (evidence.length !== conditions.length) continue;\n\n return {\n id: sandbox.id,\n name: sandbox.name,\n category: sandbox.category,\n instanceId: this.findInstanceId(sandbox, context),\n evidence,\n };\n }\n return null;\n }\n\n private findInstanceId(\n sandbox: SandboxDefinition,\n context: DetectionContext,\n ): string | undefined {\n for (const name of sandbox.idEnv ?? []) {\n const value = context.env[name];\n if (value) return value;\n }\n return undefined;\n }\n}\n\nexport function createDefaultStrategies(): DetectionStrategy[] {\n return [new EnvironmentDetectionStrategy()];\n}\n"],"mappings":"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","names":[]}
{"version":3,"sources":["../src/index.ts","../src/sandboxes.ts"],"sourcesContent":["import { defaultSandboxes } from \"./sandboxes.js\";\nimport type { DetectSandboxOptions, DetectionResult, EnvSignal } from \"./types.js\";\n\nexport { defaultSandboxes } from \"./sandboxes.js\";\nexport type {\n DetectedSandbox,\n DetectionResult,\n DetectSandboxOptions,\n EnvSignal,\n SandboxDefinition,\n} from \"./types.js\";\n\nexport function detectSandbox(options: DetectSandboxOptions = {}): DetectionResult {\n const env = options.env ?? process.env;\n const sandboxes = options.sandboxes ?? defaultSandboxes;\n const sandbox = sandboxes.find((candidate) =>\n candidate.env.some((signal) => matchesEnvSignal(signal, env)),\n );\n\n if (sandbox === undefined) return { detected: false };\n\n return {\n detected: true,\n sandbox: { id: sandbox.id, name: sandbox.name },\n };\n}\n\nexport function isRunningInSandbox(options: DetectSandboxOptions = {}): boolean {\n return detectSandbox(options).detected;\n}\n\nfunction matchesEnvSignal(signal: EnvSignal, env: NodeJS.ProcessEnv): boolean {\n const value = env[signal.name];\n return (\n value !== undefined &&\n value !== \"\" &&\n (signal.value === undefined || value === signal.value)\n );\n}\n","import type { SandboxDefinition } from \"./types.js\";\n\nexport const defaultSandboxes = [\n {\n id: \"replit\",\n name: \"Replit\",\n env: [{ name: \"REPLIT_SESSION\" }, { name: \"REPLIT_CONTAINER\" }, { name: \"REPLIT_USER\" }],\n },\n {\n id: \"bolt\",\n name: \"bolt.new\",\n env: [{ name: \"BOLT_ENV\" }, { name: \"BOLT_ORIGIN\" }, { name: \"BOLT_SERVER_URL\" }],\n },\n {\n id: \"e2b\",\n name: \"E2B\",\n env: [{ name: \"E2B_SANDBOX\", value: \"true\" }],\n },\n {\n id: \"vercel-sandbox\",\n name: \"Vercel Sandbox\",\n env: [{ name: \"HOME\", value: \"/home/vercel-sandbox\" }],\n },\n {\n id: \"daytona\",\n name: \"Daytona\",\n env: [{ name: \"DAYTONA_SANDBOX_ID\" }],\n },\n {\n id: \"modal\",\n name: \"Modal\",\n env: [{ name: \"MODAL_SANDBOX_ID\" }, { name: \"MODAL_TASK_ID\" }],\n },\n {\n id: \"cloudflare-sandbox\",\n name: \"Cloudflare Sandbox\",\n env: [{ name: \"CLOUDFLARE_DURABLE_OBJECT_ID\" }],\n },\n {\n id: \"codespaces\",\n name: \"GitHub Codespaces\",\n env: [{ name: \"CODESPACES\", value: \"true\" }],\n },\n {\n id: \"codesandbox\",\n name: \"CodeSandbox\",\n env: [{ name: \"CSB\", value: \"true\" }, { name: \"CSB_SANDBOX_ID\" }],\n },\n] satisfies readonly SandboxDefinition[];\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEO,IAAM,mBAAmB;AAAA,EAC9B;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,iBAAiB,GAAG,EAAE,MAAM,mBAAmB,GAAG,EAAE,MAAM,cAAc,CAAC;AAAA,EACzF;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,WAAW,GAAG,EAAE,MAAM,cAAc,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAAA,EAClF;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,eAAe,OAAO,OAAO,CAAC;AAAA,EAC9C;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,QAAQ,OAAO,uBAAuB,CAAC;AAAA,EACvD;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,qBAAqB,CAAC;AAAA,EACtC;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,mBAAmB,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAAA,EAC/D;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,+BAA+B,CAAC;AAAA,EAChD;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,cAAc,OAAO,OAAO,CAAC;AAAA,EAC7C;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK,CAAC,EAAE,MAAM,OAAO,OAAO,OAAO,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAAA,EAClE;AACF;;;ADpCO,SAAS,cAAc,UAAgC,CAAC,GAAoB;AACjF,QAAM,MAAM,QAAQ,OAAO,QAAQ;AACnC,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,UAAU,UAAU;AAAA,IAAK,CAAC,cAC9B,UAAU,IAAI,KAAK,CAAC,WAAW,iBAAiB,QAAQ,GAAG,CAAC;AAAA,EAC9D;AAEA,MAAI,YAAY,OAAW,QAAO,EAAE,UAAU,MAAM;AAEpD,SAAO;AAAA,IACL,UAAU;AAAA,IACV,SAAS,EAAE,IAAI,QAAQ,IAAI,MAAM,QAAQ,KAAK;AAAA,EAChD;AACF;AAEO,SAAS,mBAAmB,UAAgC,CAAC,GAAY;AAC9E,SAAO,cAAc,OAAO,EAAE;AAChC;AAEA,SAAS,iBAAiB,QAAmB,KAAiC;AAC5E,QAAM,QAAQ,IAAI,OAAO,IAAI;AAC7B,SACE,UAAU,UACV,UAAU,OACT,OAAO,UAAU,UAAa,UAAU,OAAO;AAEpD;","names":[]}

@@ -1,103 +0,36 @@

/** A single environment variable condition. */
interface EnvCondition {
/** Environment variable name. */
name: string;
/** Exact expected value. If omitted, any non-empty value matches. */
value?: string;
interface EnvSignal {
readonly name: string;
readonly value?: string;
}
/**
* One way a sandbox can be recognized from the environment.
* A single condition, or a group of conditions that must ALL hold.
* A sandbox's `env` list is OR-ed: any one matcher is enough.
*/
type EnvMatcher = EnvCondition | EnvCondition[];
type SandboxCategory =
/** Ephemeral code-execution sandboxes used by AI agents (E2B, Daytona, Modal, ...). */
"ai-sandbox"
/** AI app builders that run user code in their own sandboxes (Lovable, Replit, bolt.new, ...). */
| "app-builder"
/** Cloud development environments (Codespaces, Gitpod, Cloud Shell, ...). */
| "cloud-ide";
interface SandboxDefinition {
/** Stable identifier, e.g. "e2b". */
id: string;
/** Display name, e.g. "E2B". */
name: string;
category: SandboxCategory;
/** Env matchers; matching ANY entry means this sandbox is detected. */
env: EnvMatcher[];
/** Env vars that carry the sandbox/instance id; first one present wins. */
idEnv?: string[];
/** True once the markers have been confirmed on the real platform. */
verified: boolean;
}
/** A matched env var, kept as evidence for debugging. */
interface DetectionEvidence {
envVar: string;
value: string;
}
interface DetectedSandbox {
id: string;
name: string;
category: SandboxCategory;
/** Sandbox/instance id when the platform exposes one (e.g. E2B_SANDBOX_ID). */
instanceId?: string;
evidence: DetectionEvidence[];
readonly id: string;
readonly name: string;
}
interface DetectionContext {
env: Record<string, string | undefined>;
interface SandboxDefinition extends DetectedSandbox {
readonly env: readonly EnvSignal[];
}
interface DetectionStrategy {
/** Strategy identifier, e.g. "env". */
readonly id: string;
detect(sandbox: SandboxDefinition, context: DetectionContext): DetectedSandbox | null;
}
interface DetectSandboxOptions {
/** Environment to inspect. Defaults to process.env. */
env?: Record<string, string | undefined>;
/** Sandbox definitions to check. Defaults to the built-in list. */
sandboxes?: readonly SandboxDefinition[];
/** Detection strategies to run. Defaults to env-variable detection. */
strategies?: readonly DetectionStrategy[];
readonly env?: NodeJS.ProcessEnv;
readonly sandboxes?: readonly SandboxDefinition[];
}
interface DetectionResult {
detected: boolean;
/**
* The most specific match (definitions are ordered app-builder →
* ai-sandbox → cloud-ide, so a Lovable build running on E2B reports Lovable).
*/
sandbox: DetectedSandbox | null;
/** All sandboxes that matched, in definition order. */
matches: DetectedSandbox[];
readonly detected: boolean;
readonly sandbox?: DetectedSandbox;
}
/**
* Built-in sandbox definitions.
*
* Ordered by specificity: app builders first (they often run on top of the
* generic AI sandboxes below), then AI code-execution sandboxes, then cloud
* development environments. Detection returns the first match as the primary
* result but reports all matches.
*
* Only environments whose markers were confirmed by probing the real
* platform are listed — no guessed or documentation-only markers.
*/
declare const defaultSandboxes: readonly SandboxDefinition[];
declare const defaultSandboxes: {
id: string;
name: string;
env: ({
name: string;
value: string;
} | {
name: string;
value?: undefined;
})[];
}[];
/** Detects a sandbox purely from environment variables. */
declare class EnvironmentDetectionStrategy implements DetectionStrategy {
readonly id = "env";
detect(sandbox: SandboxDefinition, context: DetectionContext): DetectedSandbox | null;
private findInstanceId;
}
declare function createDefaultStrategies(): DetectionStrategy[];
/**
* Detect whether the current process runs inside a known sandboxed
* environment (AI code-execution sandbox, AI app builder, or cloud IDE).
*/
declare function detectSandbox(options?: DetectSandboxOptions): DetectionResult;
/** Convenience wrapper returning just the boolean. */
declare function isRunningInSandbox(options?: DetectSandboxOptions): boolean;
export { type DetectSandboxOptions, type DetectedSandbox, type DetectionContext, type DetectionEvidence, type DetectionResult, type DetectionStrategy, type EnvCondition, type EnvMatcher, EnvironmentDetectionStrategy, type SandboxCategory, type SandboxDefinition, createDefaultStrategies, defaultSandboxes, detectSandbox, isRunningInSandbox };
export { type DetectSandboxOptions, type DetectedSandbox, type DetectionResult, type EnvSignal, type SandboxDefinition, defaultSandboxes, detectSandbox, isRunningInSandbox };

@@ -1,103 +0,36 @@

/** A single environment variable condition. */
interface EnvCondition {
/** Environment variable name. */
name: string;
/** Exact expected value. If omitted, any non-empty value matches. */
value?: string;
interface EnvSignal {
readonly name: string;
readonly value?: string;
}
/**
* One way a sandbox can be recognized from the environment.
* A single condition, or a group of conditions that must ALL hold.
* A sandbox's `env` list is OR-ed: any one matcher is enough.
*/
type EnvMatcher = EnvCondition | EnvCondition[];
type SandboxCategory =
/** Ephemeral code-execution sandboxes used by AI agents (E2B, Daytona, Modal, ...). */
"ai-sandbox"
/** AI app builders that run user code in their own sandboxes (Lovable, Replit, bolt.new, ...). */
| "app-builder"
/** Cloud development environments (Codespaces, Gitpod, Cloud Shell, ...). */
| "cloud-ide";
interface SandboxDefinition {
/** Stable identifier, e.g. "e2b". */
id: string;
/** Display name, e.g. "E2B". */
name: string;
category: SandboxCategory;
/** Env matchers; matching ANY entry means this sandbox is detected. */
env: EnvMatcher[];
/** Env vars that carry the sandbox/instance id; first one present wins. */
idEnv?: string[];
/** True once the markers have been confirmed on the real platform. */
verified: boolean;
}
/** A matched env var, kept as evidence for debugging. */
interface DetectionEvidence {
envVar: string;
value: string;
}
interface DetectedSandbox {
id: string;
name: string;
category: SandboxCategory;
/** Sandbox/instance id when the platform exposes one (e.g. E2B_SANDBOX_ID). */
instanceId?: string;
evidence: DetectionEvidence[];
readonly id: string;
readonly name: string;
}
interface DetectionContext {
env: Record<string, string | undefined>;
interface SandboxDefinition extends DetectedSandbox {
readonly env: readonly EnvSignal[];
}
interface DetectionStrategy {
/** Strategy identifier, e.g. "env". */
readonly id: string;
detect(sandbox: SandboxDefinition, context: DetectionContext): DetectedSandbox | null;
}
interface DetectSandboxOptions {
/** Environment to inspect. Defaults to process.env. */
env?: Record<string, string | undefined>;
/** Sandbox definitions to check. Defaults to the built-in list. */
sandboxes?: readonly SandboxDefinition[];
/** Detection strategies to run. Defaults to env-variable detection. */
strategies?: readonly DetectionStrategy[];
readonly env?: NodeJS.ProcessEnv;
readonly sandboxes?: readonly SandboxDefinition[];
}
interface DetectionResult {
detected: boolean;
/**
* The most specific match (definitions are ordered app-builder →
* ai-sandbox → cloud-ide, so a Lovable build running on E2B reports Lovable).
*/
sandbox: DetectedSandbox | null;
/** All sandboxes that matched, in definition order. */
matches: DetectedSandbox[];
readonly detected: boolean;
readonly sandbox?: DetectedSandbox;
}
/**
* Built-in sandbox definitions.
*
* Ordered by specificity: app builders first (they often run on top of the
* generic AI sandboxes below), then AI code-execution sandboxes, then cloud
* development environments. Detection returns the first match as the primary
* result but reports all matches.
*
* Only environments whose markers were confirmed by probing the real
* platform are listed — no guessed or documentation-only markers.
*/
declare const defaultSandboxes: readonly SandboxDefinition[];
declare const defaultSandboxes: {
id: string;
name: string;
env: ({
name: string;
value: string;
} | {
name: string;
value?: undefined;
})[];
}[];
/** Detects a sandbox purely from environment variables. */
declare class EnvironmentDetectionStrategy implements DetectionStrategy {
readonly id = "env";
detect(sandbox: SandboxDefinition, context: DetectionContext): DetectedSandbox | null;
private findInstanceId;
}
declare function createDefaultStrategies(): DetectionStrategy[];
/**
* Detect whether the current process runs inside a known sandboxed
* environment (AI code-execution sandbox, AI app builder, or cloud IDE).
*/
declare function detectSandbox(options?: DetectSandboxOptions): DetectionResult;
/** Convenience wrapper returning just the boolean. */
declare function isRunningInSandbox(options?: DetectSandboxOptions): boolean;
export { type DetectSandboxOptions, type DetectedSandbox, type DetectionContext, type DetectionEvidence, type DetectionResult, type DetectionStrategy, type EnvCondition, type EnvMatcher, EnvironmentDetectionStrategy, type SandboxCategory, type SandboxDefinition, createDefaultStrategies, defaultSandboxes, detectSandbox, isRunningInSandbox };
export { type DetectSandboxOptions, type DetectedSandbox, type DetectionResult, type EnvSignal, type SandboxDefinition, defaultSandboxes, detectSandbox, isRunningInSandbox };
import {
EnvironmentDetectionStrategy,
createDefaultStrategies,
defaultSandboxes,
detectSandbox,
isRunningInSandbox
} from "./chunk-2S3637PR.js";
} from "./chunk-HZH3SATY.js";
export {
EnvironmentDetectionStrategy,
createDefaultStrategies,
defaultSandboxes,

@@ -12,0 +8,0 @@ detectSandbox,

{
"name": "sandbox-cli-detector",
"version": "0.1.1",
"description": "Detect whether a CLI is running inside a sandboxed environment (E2B, Vercel Sandbox, Replit, Daytona, Modal, and more)",
"version": "0.2.0",
"description": "Detect whether a CLI is running inside a sandboxed environment",
"keywords": [

@@ -6,0 +6,0 @@ "sandbox",

+61
-164

@@ -6,12 +6,9 @@ # sandbox-cli-detector

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.
Please [open an issue](https://github.com/davidmokos/sandbox-cli-detector/issues/new)
if your sandbox is not properly detected.
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.
[![npm](https://img.shields.io/npm/v/sandbox-cli-detector.svg)](https://www.npmjs.com/package/sandbox-cli-detector)
[![Tests](https://github.com/davidmokos/sandbox-cli-detector/actions/workflows/test.yml/badge.svg)](https://github.com/davidmokos/sandbox-cli-detector/actions/workflows/test.yml)
[![License](https://img.shields.io/npm/l/sandbox-cli-detector.svg)](LICENSE)
Please open an issue if a sandbox is missing or incorrectly detected.
## Installation

@@ -26,99 +23,32 @@

```ts
import { detectSandbox, isRunningInSandbox } from "sandbox-cli-detector";
import { detectSandbox } from "sandbox-cli-detector";
if (isRunningInSandbox()) {
// Skip interactive prompts, tune telemetry, relax auth flows, etc.
}
const result = detectSandbox();
if (result.detected) {
console.log("sandbox:", result.sandbox?.name);
if (result.detected && result.sandbox) {
console.log("The name of the sandbox is:", result.sandbox.name);
} else {
console.log("not running in a known sandbox");
console.log("This program is not running inside a known sandbox");
}
```
Example result:
## Supported sandboxes
```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" }]
}
]
}
```
Officially supported sandbox environments:
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.
Use `result.sandbox.id` for stable checks. `result.sandbox.name` is display text
and may change.
## CLI
```sh
npx sandbox-cli-detector
# detected: E2B (sbx_abc123)
# no sandbox detected
npx sandbox-cli-detector --json
# prints the full DetectionResult as JSON
npx sandbox-cli-detector --quiet
# no output, exit code only
```
Exit codes:
| Code | Meaning |
| Name | ID |
| --- | --- |
| `0` | a known sandbox was detected |
| `1` | no known sandbox was detected |
| [Replit](https://replit.com) | `replit` |
| [bolt.new](https://bolt.new) | `bolt` |
| [E2B](https://e2b.dev) | `e2b` |
| [Vercel Sandbox](https://vercel.com/docs/sandbox) | `vercel-sandbox` |
| [Daytona](https://daytona.io) | `daytona` |
| [Modal](https://modal.com) | `modal` |
| [Cloudflare Sandbox](https://developers.cloudflare.com/sandbox/) | `cloudflare-sandbox` |
| [GitHub Codespaces](https://github.com/features/codespaces) | `codespaces` |
| [CodeSandbox](https://codesandbox.io) | `codesandbox` |
## Supported environments
Detection is data-driven. The exact environment variables for each sandbox
live in [`src/sandboxes.ts`](src/sandboxes.ts).
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.
| 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

@@ -128,62 +58,46 @@

Returns a `DetectionResult`.
Returns a detection result:
```ts
interface DetectionResult {
detected: boolean;
sandbox: DetectedSandbox | null;
matches: DetectedSandbox[];
{
detected: true,
sandbox: {
id: "e2b",
name: "E2B"
}
}
```
`sandbox` is the primary match. `matches` includes all matches, in definition
order.
When no sandbox is detected, it returns `{ detected: false }`.
```ts
interface DetectedSandbox {
id: string;
name: string;
category: "ai-sandbox" | "app-builder" | "cloud-ide";
instanceId?: string;
evidence: DetectionEvidence[];
}
### `result.detected`
interface DetectionEvidence {
envVar: string;
value: string;
}
```
A boolean that is `true` when the process is running inside a known sandbox and
`false` otherwise.
`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.
### `result.sandbox.id`
Options:
A stable identifier for the detected sandbox. Prefer comparing this value over
`result.sandbox.name`.
```ts
interface DetectSandboxOptions {
env?: Record<string, string | undefined>;
sandboxes?: readonly SandboxDefinition[];
strategies?: readonly DetectionStrategy[];
}
```
### `result.sandbox.name`
- `env` defaults to `process.env`.
- `sandboxes` defaults to the built-in `defaultSandboxes` list.
- `strategies` defaults to environment-variable detection.
The display name of the detected sandbox. This may change without it being a
breaking change.
### `isRunningInSandbox(options?)`
Returns `true` when `detectSandbox(options).detected` is `true`.
A convenience function that returns `result.detected` as a boolean:
```ts
import { isRunningInSandbox } from "sandbox-cli-detector";
if (isRunningInSandbox()) {
// running in a known sandbox
// Adjust CLI behavior for sandboxed execution.
}
```
### `defaultSandboxes`
### Custom sandboxes
The built-in `SandboxDefinition[]`, exported so you can extend, filter, or
replace the supported environment list.
Pass custom definitions when you need to detect an internal environment:

@@ -194,19 +108,2 @@ ```ts

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: [

@@ -216,6 +113,3 @@ {

name: "Internal Sandbox",
category: "ai-sandbox",
env: [{ name: "INTERNAL_SANDBOX", value: "true" }],
idEnv: ["INTERNAL_SANDBOX_ID"],
verified: true,
},

@@ -227,22 +121,25 @@ ...defaultSandboxes,

## Contributing platform detections
Each environment signal matches either an exact `value` or any non-empty value
when `value` is omitted. If multiple sandboxes match, the first definition is
returned.
The best detection signals are stable environment variables that are present in
every shell for that platform and absent elsewhere.
## CLI
To propose a new platform, open an issue or PR with:
The package also ships a CLI:
- 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
npx sandbox-cli-detector --json
npx sandbox-cli-detector --quiet
```
It exits with `0` when a sandbox is detected and `1` otherwise.
## Contributing detections
Please include the platform name, a redacted `env | sort` captured inside the
platform, and the variables that identify it.
## License
MIT
[MIT](LICENSE)
// src/sandboxes.ts
var defaultSandboxes = [
// ── AI app builders ────────────────────────────────────────────────────
// Lovable, v0, and Base44 are intentionally absent: they expose no shell,
// so a CLI can never run inside them.
{
id: "replit",
name: "Replit",
category: "app-builder",
// Observed inside Replit. The often-cited REPL_ID and REPLIT_ENVIRONMENT
// are NOT present in current Replit environments.
env: [{ name: "REPLIT_SESSION" }, { name: "REPLIT_CONTAINER" }, { name: "REPLIT_USER" }],
verified: true
},
{
id: "bolt",
name: "bolt.new",
category: "app-builder",
env: [{ name: "BOLT_ENV" }, { name: "BOLT_ORIGIN" }, { name: "BOLT_SERVER_URL" }],
verified: true
},
{
id: "rork",
name: "Rork",
category: "app-builder",
// Rork runs on E2B, so e2b also appears in matches.
env: [{ name: "RORK_API_URL" }],
verified: true
},
// ── AI code-execution sandboxes ────────────────────────────────────────
{
id: "e2b",
name: "E2B",
category: "ai-sandbox",
// Documented: https://e2b.dev/docs/sandbox/environment-variables
env: [{ name: "E2B_SANDBOX", value: "true" }],
idEnv: ["E2B_SANDBOX_ID"],
verified: true
},
{
id: "vercel-sandbox",
name: "Vercel Sandbox",
category: "ai-sandbox",
// No dedicated marker; the microVMs run as the vercel-sandbox user.
// (PS1="▲ $PWD/" is also set, but only in interactive shells.)
env: [{ name: "HOME", value: "/home/vercel-sandbox" }],
verified: true
},
{
id: "daytona",
name: "Daytona",
category: "ai-sandbox",
env: [{ name: "DAYTONA_SANDBOX_ID" }],
idEnv: ["DAYTONA_SANDBOX_ID"],
verified: true
},
{
id: "modal",
name: "Modal",
category: "ai-sandbox",
// MODAL_SANDBOX_ID observed in Modal Sandboxes; MODAL_TASK_ID is the
// documented container id (https://modal.com/docs/guide/environment_variables).
env: [{ name: "MODAL_SANDBOX_ID" }, { name: "MODAL_TASK_ID" }],
idEnv: ["MODAL_SANDBOX_ID", "MODAL_TASK_ID"],
verified: true
},
{
id: "cloudflare-sandbox",
name: "Cloudflare Sandbox",
category: "ai-sandbox",
env: [{ name: "CLOUDFLARE_DURABLE_OBJECT_ID" }],
idEnv: ["CLOUDFLARE_DURABLE_OBJECT_ID"],
verified: true
},
// ── Cloud development environments ─────────────────────────────────────
{
id: "codespaces",
name: "GitHub Codespaces",
category: "cloud-ide",
env: [{ name: "CODESPACES", value: "true" }],
idEnv: ["CODESPACE_NAME"],
verified: true
},
{
id: "codesandbox",
name: "CodeSandbox",
category: "cloud-ide",
env: [{ name: "CSB", value: "true" }, { name: "CSB_SANDBOX_ID" }],
idEnv: ["CSB_SANDBOX_ID"],
verified: true
}
];
// src/strategies.ts
function matchCondition(condition, env) {
const value = env[condition.name];
if (value === void 0 || value === "") return null;
if (condition.value !== void 0 && value !== condition.value) return null;
return { envVar: condition.name, value };
}
var EnvironmentDetectionStrategy = class {
id = "env";
detect(sandbox, context) {
for (const matcher of sandbox.env) {
const conditions = Array.isArray(matcher) ? matcher : [matcher];
if (conditions.length === 0) continue;
const evidence = [];
for (const condition of conditions) {
const matched = matchCondition(condition, context.env);
if (!matched) break;
evidence.push(matched);
}
if (evidence.length !== conditions.length) continue;
return {
id: sandbox.id,
name: sandbox.name,
category: sandbox.category,
instanceId: this.findInstanceId(sandbox, context),
evidence
};
}
return null;
}
findInstanceId(sandbox, context) {
for (const name of sandbox.idEnv ?? []) {
const value = context.env[name];
if (value) return value;
}
return void 0;
}
};
function createDefaultStrategies() {
return [new EnvironmentDetectionStrategy()];
}
// src/index.ts
function detectSandbox(options = {}) {
const env = options.env ?? process.env;
const sandboxes = options.sandboxes ?? defaultSandboxes;
const strategies = options.strategies ?? createDefaultStrategies();
const context = { env };
const matches = [];
for (const sandbox of sandboxes) {
for (const strategy of strategies) {
const detected = strategy.detect(sandbox, context);
if (detected) {
matches.push(detected);
break;
}
}
}
return {
detected: matches.length > 0,
sandbox: matches[0] ?? null,
matches
};
}
function isRunningInSandbox(options = {}) {
return detectSandbox(options).detected;
}
export {
defaultSandboxes,
EnvironmentDetectionStrategy,
createDefaultStrategies,
detectSandbox,
isRunningInSandbox
};
//# sourceMappingURL=chunk-2S3637PR.js.map
{"version":3,"sources":["../src/sandboxes.ts","../src/strategies.ts","../src/index.ts"],"sourcesContent":["import type { SandboxDefinition } from \"./types.js\";\n\n/**\n * Built-in sandbox definitions.\n *\n * Ordered by specificity: app builders first (they often run on top of the\n * generic AI sandboxes below), then AI code-execution sandboxes, then cloud\n * development environments. Detection returns the first match as the primary\n * result but reports all matches.\n *\n * Only environments whose markers were confirmed by probing the real\n * platform are listed — no guessed or documentation-only markers.\n */\nexport const defaultSandboxes: readonly SandboxDefinition[] = [\n // ── AI app builders ────────────────────────────────────────────────────\n // Lovable, v0, and Base44 are intentionally absent: they expose no shell,\n // so a CLI can never run inside them.\n {\n id: \"replit\",\n name: \"Replit\",\n category: \"app-builder\",\n // Observed inside Replit. The often-cited REPL_ID and REPLIT_ENVIRONMENT\n // are NOT present in current Replit environments.\n env: [{ name: \"REPLIT_SESSION\" }, { name: \"REPLIT_CONTAINER\" }, { name: \"REPLIT_USER\" }],\n verified: true,\n },\n {\n id: \"bolt\",\n name: \"bolt.new\",\n category: \"app-builder\",\n env: [{ name: \"BOLT_ENV\" }, { name: \"BOLT_ORIGIN\" }, { name: \"BOLT_SERVER_URL\" }],\n verified: true,\n },\n {\n id: \"rork\",\n name: \"Rork\",\n category: \"app-builder\",\n // Rork runs on E2B, so e2b also appears in matches.\n env: [{ name: \"RORK_API_URL\" }],\n verified: true,\n },\n\n // ── AI code-execution sandboxes ────────────────────────────────────────\n {\n id: \"e2b\",\n name: \"E2B\",\n category: \"ai-sandbox\",\n // Documented: https://e2b.dev/docs/sandbox/environment-variables\n env: [{ name: \"E2B_SANDBOX\", value: \"true\" }],\n idEnv: [\"E2B_SANDBOX_ID\"],\n verified: true,\n },\n {\n id: \"vercel-sandbox\",\n name: \"Vercel Sandbox\",\n category: \"ai-sandbox\",\n // No dedicated marker; the microVMs run as the vercel-sandbox user.\n // (PS1=\"▲ $PWD/\" is also set, but only in interactive shells.)\n env: [{ name: \"HOME\", value: \"/home/vercel-sandbox\" }],\n verified: true,\n },\n {\n id: \"daytona\",\n name: \"Daytona\",\n category: \"ai-sandbox\",\n env: [{ name: \"DAYTONA_SANDBOX_ID\" }],\n idEnv: [\"DAYTONA_SANDBOX_ID\"],\n verified: true,\n },\n {\n id: \"modal\",\n name: \"Modal\",\n category: \"ai-sandbox\",\n // MODAL_SANDBOX_ID observed in Modal Sandboxes; MODAL_TASK_ID is the\n // documented container id (https://modal.com/docs/guide/environment_variables).\n env: [{ name: \"MODAL_SANDBOX_ID\" }, { name: \"MODAL_TASK_ID\" }],\n idEnv: [\"MODAL_SANDBOX_ID\", \"MODAL_TASK_ID\"],\n verified: true,\n },\n {\n id: \"cloudflare-sandbox\",\n name: \"Cloudflare Sandbox\",\n category: \"ai-sandbox\",\n env: [{ name: \"CLOUDFLARE_DURABLE_OBJECT_ID\" }],\n idEnv: [\"CLOUDFLARE_DURABLE_OBJECT_ID\"],\n verified: true,\n },\n\n // ── Cloud development environments ─────────────────────────────────────\n {\n id: \"codespaces\",\n name: \"GitHub Codespaces\",\n category: \"cloud-ide\",\n env: [{ name: \"CODESPACES\", value: \"true\" }],\n idEnv: [\"CODESPACE_NAME\"],\n verified: true,\n },\n {\n id: \"codesandbox\",\n name: \"CodeSandbox\",\n category: \"cloud-ide\",\n env: [{ name: \"CSB\", value: \"true\" }, { name: \"CSB_SANDBOX_ID\" }],\n idEnv: [\"CSB_SANDBOX_ID\"],\n verified: true,\n },\n];\n","import type {\n DetectedSandbox,\n DetectionContext,\n DetectionEvidence,\n DetectionStrategy,\n EnvCondition,\n SandboxDefinition,\n} from \"./types.js\";\n\nfunction matchCondition(\n condition: EnvCondition,\n env: Record<string, string | undefined>,\n): DetectionEvidence | null {\n const value = env[condition.name];\n if (value === undefined || value === \"\") return null;\n if (condition.value !== undefined && value !== condition.value) return null;\n return { envVar: condition.name, value };\n}\n\n/** Detects a sandbox purely from environment variables. */\nexport class EnvironmentDetectionStrategy implements DetectionStrategy {\n readonly id = \"env\";\n\n detect(sandbox: SandboxDefinition, context: DetectionContext): DetectedSandbox | null {\n for (const matcher of sandbox.env) {\n const conditions = Array.isArray(matcher) ? matcher : [matcher];\n if (conditions.length === 0) continue;\n\n const evidence: DetectionEvidence[] = [];\n for (const condition of conditions) {\n const matched = matchCondition(condition, context.env);\n if (!matched) break;\n evidence.push(matched);\n }\n if (evidence.length !== conditions.length) continue;\n\n return {\n id: sandbox.id,\n name: sandbox.name,\n category: sandbox.category,\n instanceId: this.findInstanceId(sandbox, context),\n evidence,\n };\n }\n return null;\n }\n\n private findInstanceId(\n sandbox: SandboxDefinition,\n context: DetectionContext,\n ): string | undefined {\n for (const name of sandbox.idEnv ?? []) {\n const value = context.env[name];\n if (value) return value;\n }\n return undefined;\n }\n}\n\nexport function createDefaultStrategies(): DetectionStrategy[] {\n return [new EnvironmentDetectionStrategy()];\n}\n","import { defaultSandboxes } from \"./sandboxes.js\";\nimport { createDefaultStrategies } from \"./strategies.js\";\nimport type { DetectedSandbox, DetectionResult, DetectSandboxOptions } from \"./types.js\";\n\nexport { defaultSandboxes } from \"./sandboxes.js\";\nexport { createDefaultStrategies, EnvironmentDetectionStrategy } from \"./strategies.js\";\nexport type {\n DetectedSandbox,\n DetectionContext,\n DetectionEvidence,\n DetectionResult,\n DetectionStrategy,\n DetectSandboxOptions,\n EnvCondition,\n EnvMatcher,\n SandboxCategory,\n SandboxDefinition,\n} from \"./types.js\";\n\n/**\n * Detect whether the current process runs inside a known sandboxed\n * environment (AI code-execution sandbox, AI app builder, or cloud IDE).\n */\nexport function detectSandbox(options: DetectSandboxOptions = {}): DetectionResult {\n const env = options.env ?? process.env;\n const sandboxes = options.sandboxes ?? defaultSandboxes;\n const strategies = options.strategies ?? createDefaultStrategies();\n const context = { env };\n\n const matches: DetectedSandbox[] = [];\n for (const sandbox of sandboxes) {\n for (const strategy of strategies) {\n const detected = strategy.detect(sandbox, context);\n if (detected) {\n matches.push(detected);\n break;\n }\n }\n }\n\n return {\n detected: matches.length > 0,\n sandbox: matches[0] ?? null,\n matches,\n };\n}\n\n/** Convenience wrapper returning just the boolean. */\nexport function isRunningInSandbox(options: DetectSandboxOptions = {}): boolean {\n return detectSandbox(options).detected;\n}\n"],"mappings":"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","names":[]}