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.

Use image base name for templates and add tests

Strip registry/namespace (use last path segment) when building templates
and creating sandboxes. Add Vitest config, a package.json test script,
and unit tests for parseImageRef.

+78 -3
+2 -1
apps/modal-sandbox/package.json
··· 6 6 "dev": "tsx --watch src/index.ts", 7 7 "start": "npm run build && node dist/index.js", 8 8 "start:prod": "npm run build && node --enable-source-maps dist/index.js", 9 - "build": "bun build src/index.ts --outdir ./dist --target node --minify --sourcemap=linked" 9 + "build": "bun build src/index.ts --outdir ./dist --target node --minify --sourcemap=linked", 10 + "test": "vitest run" 10 11 }, 11 12 "dependencies": { 12 13 "@daytonaio/sdk": "^0.162.0",
+60
apps/modal-sandbox/src/lib/parseImageRef.test.ts
··· 1 + import { describe, it, expect } from "vitest"; 2 + import parseImageRef from "./parseImageRef"; 3 + 4 + describe("parseImageRef", () => { 5 + it("parses a full ref with registry, namespace, name, and tag", () => { 6 + expect(parseImageRef("ghcr.io/pocketenv-io/modal-openclaw:0.1.0")).toEqual({ 7 + registry: "ghcr.io", 8 + name: "pocketenv-io/modal-openclaw", 9 + tag: "0.1.0", 10 + }); 11 + }); 12 + 13 + it("parses a ref with registry and no namespace", () => { 14 + expect(parseImageRef("docker.io/ubuntu:22.04")).toEqual({ 15 + registry: "docker.io", 16 + name: "ubuntu", 17 + tag: "22.04", 18 + }); 19 + }); 20 + 21 + it("parses a plain name with tag and no registry", () => { 22 + expect(parseImageRef("ubuntu:22.04")).toEqual({ 23 + registry: "", 24 + name: "ubuntu", 25 + tag: "22.04", 26 + }); 27 + }); 28 + 29 + it("defaults tag to latest when no tag is provided", () => { 30 + expect(parseImageRef("ubuntu")).toEqual({ 31 + registry: "", 32 + name: "ubuntu", 33 + tag: "latest", 34 + }); 35 + }); 36 + 37 + it("defaults tag to latest for a registry ref with no tag", () => { 38 + expect(parseImageRef("ghcr.io/pocketenv-io/modal-openclaw")).toEqual({ 39 + registry: "ghcr.io", 40 + name: "pocketenv-io/modal-openclaw", 41 + tag: "latest", 42 + }); 43 + }); 44 + 45 + it("handles registry with port", () => { 46 + expect(parseImageRef("localhost:5000/myimage:latest")).toEqual({ 47 + registry: "localhost:5000", 48 + name: "myimage", 49 + tag: "latest", 50 + }); 51 + }); 52 + 53 + it("parses a namespaced image with no registry", () => { 54 + expect(parseImageRef("myorg/myimage:1.0")).toEqual({ 55 + registry: "", 56 + name: "myorg/myimage", 57 + tag: "1.0", 58 + }); 59 + }); 60 + });
+3 -2
apps/modal-sandbox/src/providers/e2b/index.ts
··· 128 128 const image = options.image || "ghcr.io/pocketenv-io/modal-openclaw:0.1.0"; 129 129 const template = Template().fromImage(image); 130 130 const { name, tag } = parseImageRef(image); 131 - await Template.build(template, name, { 131 + const templateName = name.split("/").pop()!; 132 + await Template.build(template, templateName, { 132 133 tags: [tag], 133 134 cpuCount: 4, 134 135 memoryMB: 4096, 135 136 apiKey: options.e2bApiKey, 136 137 }); 137 - const sandbox = await Sandbox.create(`${name}:${tag}`, { 138 + const sandbox = await Sandbox.create(`${templateName}:${tag}`, { 138 139 apiKey: options.e2bApiKey, 139 140 }); 140 141 return new E2bSandbox(sandbox);
+13
apps/modal-sandbox/vitest.config.ts
··· 1 + import { defineConfig } from "vitest/config"; 2 + import path from "node:path"; 3 + 4 + export default defineConfig({ 5 + resolve: { 6 + alias: { 7 + lib: path.resolve(__dirname, "src/lib"), 8 + }, 9 + }, 10 + test: { 11 + environment: "node", 12 + }, 13 + });