the universal sandbox runtime for agents and humans. pocketenv.io
sandbox openclaw agent claude-code vercel-sandbox deno-sandbox cloudflare-sandbox atproto sprites daytona
7
fork

Configure Feed

Select the types of activity you want to include in your feed.

Do not throw on command failure in prepareSandbox

Log a warning instead of throwing when a command exits non-zero.
Update tests to assert specific commands ran or not, change the mock
to only fail condition checks, and rename the mock class accordingly.

+26 -17
+22 -15
apps/sandbox/src/lib/prepare-sandbox.test.ts
··· 33 33 }); 34 34 35 35 Deno.test("prepareSandbox - runs commands for known preset", async () => { 36 + // exitCode 0 → conditions "already met" → conditional steps skipped 37 + // Only unconditional steps (e.g. Install Dependencies) run their commands 36 38 const sandbox = new MockSandbox(); 37 39 await prepareSandbox(sandbox, "nix"); 38 - // At least one command was executed 39 - assertEquals(sandbox.calls.length > 0, true); 40 + const ranAptGet = sandbox.calls.some((cmd) => cmd.includes("apt-get update")); 41 + assertEquals(ranAptGet, true); 40 42 }); 41 43 42 44 Deno.test("prepareSandbox - skips step when condition is already met", async () => { 43 - // Sandbox that always returns exitCode 0 (condition "already met") 45 + // exitCode 0 → condition IS met → conditional run blocks are skipped 44 46 const sandbox = new MockSandbox(); 45 - const callsBefore = [...sandbox.calls]; 46 47 await prepareSandbox(sandbox, "nix"); 47 - // All condition checks returned 0 so no run commands should have fired 48 - // (every step is skipped because its `if` condition is satisfied) 49 - // We just verify the sandbox was called (for the `if` checks themselves) 50 - assertEquals(Array.isArray(sandbox.calls), true); 51 - void callsBefore; // used to satisfy linter 48 + // The nix install command is inside a conditional step and must NOT have run 49 + const ranNixInstall = sandbox.calls.some((cmd) => 50 + cmd.includes("install.determinate.systems/nix") 51 + ); 52 + assertEquals(ranNixInstall, false); 52 53 }); 53 54 54 55 Deno.test("prepareSandbox - executes run commands when condition not met", async () => { 55 - class AlwaysFailCondition extends MockSandbox { 56 + class ConditionFailMock extends MockSandbox { 56 57 override sh(strings: TemplateStringsArray, ...values: any[]) { 57 58 const cmd = String.raw({ raw: strings }, ...values); 58 59 this.calls.push(cmd); 59 - // Non-zero exit means condition is NOT met → run block executes 60 - return Promise.resolve({ exitCode: 1, stdout: "", stderr: "" }); 60 + // Only if-condition checks (starting with "[") return non-zero exit code, 61 + // meaning the condition is NOT met → run block executes. 62 + // All subsequent run commands return 0 (success). 63 + const exitCode = cmd.trimStart().startsWith("[") ? 1 : 0; 64 + return Promise.resolve({ exitCode, stdout: "", stderr: "" }); 61 65 } 62 66 } 63 67 64 - const sandbox = new AlwaysFailCondition(); 68 + const sandbox = new ConditionFailMock(); 65 69 await prepareSandbox(sandbox, "nix"); 66 - // With conditions never met, all run lines should have executed 67 - assertEquals(sandbox.calls.length > 0, true); 70 + // With conditions never met, conditional run commands should have executed 71 + const ranNixInstall = sandbox.calls.some((cmd) => 72 + cmd.includes("install.determinate.systems/nix") 73 + ); 74 + assertEquals(ranNixInstall, true); 68 75 });
+4 -2
apps/sandbox/src/lib/prepare-sandbox.ts
··· 81 81 console.log(`${chalk.rgb(100, 232, 130)("exec")} ${line}`); 82 82 const result = await sandbox.sh`${line}`; 83 83 if (result.exitCode !== 0) { 84 - consola.warn(`Command "${chalk.rgb(100, 232, 130)(line)}" failed with exit code ${result.exitCode} ${result.stderr} ${result.stdout}.`); 85 - throw new Error(`Command "${line}" failed with exit code ${result.exitCode}`); 84 + consola.warn( 85 + `Command "${chalk.rgb(100, 232, 130)(line)}" failed with exit code ${result.exitCode} ${result.stderr} ${result.stdout}.`, 86 + ); 87 + } 86 88 } 87 89 } 88 90 }