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.

Allow sandbox lookup by id, uri, or name

CLI expose/unexpose now call the API client instead of printing
success directly. Expose accepts an optional description; both
commands send auth via POCKETENV_TOKEN or a fetched token and
handle errors with proper logging and exit.

+64 -13
+6 -2
apps/api/src/xrpc/io/pocketenv/sandbox/exposePort.ts
··· 3 3 import { consola } from "consola"; 4 4 import { Providers } from "consts"; 5 5 import type { Context } from "context"; 6 - import { and, eq } from "drizzle-orm"; 6 + import { and, eq, or } from "drizzle-orm"; 7 7 import type { Server } from "lexicon"; 8 8 import type { 9 9 QueryParams, ··· 43 43 .leftJoin(schema.users, eq(schema.sandboxes.userId, schema.users.id)) 44 44 .where( 45 45 and( 46 - eq(schema.sandboxes.id, params.id), 46 + or( 47 + eq(schema.sandboxes.id, params.id), 48 + eq(schema.sandboxes.uri, params.id), 49 + eq(schema.sandboxes.name, params.id), 50 + ), 47 51 eq(schema.users.did, auth.credentials.did), 48 52 ), 49 53 )
+6 -2
apps/api/src/xrpc/io/pocketenv/sandbox/unexposePort.ts
··· 3 3 import { consola } from "consola"; 4 4 import { Providers } from "consts"; 5 5 import type { Context } from "context"; 6 - import { and, eq } from "drizzle-orm"; 6 + import { and, eq, or } from "drizzle-orm"; 7 7 import type { Server } from "lexicon"; 8 8 import type { 9 9 InputSchema, ··· 43 43 .leftJoin(schema.users, eq(schema.sandboxes.userId, schema.users.id)) 44 44 .where( 45 45 and( 46 - eq(schema.sandboxes.id, params.id), 46 + or( 47 + eq(schema.sandboxes.id, params.id), 48 + eq(schema.sandboxes.uri, params.id), 49 + eq(schema.sandboxes.name, params.id), 50 + ), 47 51 eq(schema.users.did, auth.credentials.did), 48 52 ), 49 53 )
+28 -5
apps/cli/src/cmd/expose.ts
··· 1 - import chalk from "chalk"; 2 1 import consola from "consola"; 3 2 import getAccessToken from "../lib/getAccessToken"; 3 + import { client } from "../client"; 4 + import { env } from "../lib/env"; 5 + import { c } from "../theme"; 4 6 5 - export async function exposePort(sandbox: string, port: number) { 7 + export async function exposePort( 8 + sandbox: string, 9 + port: number, 10 + description?: string, 11 + ) { 6 12 const token = await getAccessToken(); 13 + try { 14 + await client.post( 15 + `/xrpc/io.pocketenv.sandbox.exposePort`, 16 + { port, description }, 17 + { 18 + params: { 19 + id: sandbox, 20 + }, 21 + headers: { 22 + Authorization: `Bearer ${env.POCKETENV_TOKEN || token}`, 23 + }, 24 + }, 25 + ); 7 26 8 - consola.success( 9 - `Port ${chalk.rgb(0, 232, 198)(port)} exposed for sandbox ${chalk.rgb(0, 232, 198)(sandbox)}`, 10 - ); 27 + consola.success( 28 + `Port ${c.primary(port)} exposed for sandbox ${c.primary(sandbox)}`, 29 + ); 30 + } catch (error) { 31 + consola.error("Failed to expose port:", error); 32 + process.exit(1); 33 + } 11 34 }
+24 -4
apps/cli/src/cmd/unexpose.ts
··· 1 - import chalk from "chalk"; 2 1 import consola from "consola"; 3 2 import getAccessToken from "../lib/getAccessToken"; 3 + import { client } from "../client"; 4 + import { env } from "../lib/env"; 5 + import { c } from "../theme"; 4 6 5 7 export async function unexposePort(sandbox: string, port: number) { 6 8 const token = await getAccessToken(); 7 9 8 - consola.success( 9 - `Port ${chalk.rgb(0, 232, 198)(port)} unexposed for sandbox ${chalk.rgb(0, 232, 198)(sandbox)}`, 10 - ); 10 + try { 11 + await client.post( 12 + `/xrpc/io.pocketenv.sandbox.unexposePort`, 13 + { port }, 14 + { 15 + params: { 16 + id: sandbox, 17 + }, 18 + headers: { 19 + Authorization: `Bearer ${env.POCKETENV_TOKEN || token}`, 20 + }, 21 + }, 22 + ); 23 + 24 + consola.success( 25 + `Port ${c.primary(port)} unexposed for sandbox ${c.primary(sandbox)}`, 26 + ); 27 + } catch (error) { 28 + consola.error(`Failed to unexpose port: ${error}`); 29 + process.exit(1); 30 + } 11 31 }