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.

Persist sandbox record and navigate by URI

+57 -2
+52 -1
apps/api/src/xrpc/io/pocketenv/sandbox/createSandbox.ts
··· 1 1 import type { HandlerAuth } from "@atproto/xrpc-server"; 2 + import { consola } from "consola"; 2 3 import type { Context } from "context"; 3 4 import type { Server } from "lexicon"; 4 5 import type { HandlerInput } from "lexicon/types/io/pocketenv/sandbox/createSandbox"; 5 6 import generateJwt from "lib/generateJwt"; 7 + import type * as Sandbox from "lexicon/types/io/pocketenv/sandbox"; 8 + import chalk from "chalk"; 9 + import { createAgent } from "lib/agent"; 10 + import { TID } from "@atproto/common"; 11 + import schema from "schema"; 12 + import { eq } from "drizzle-orm"; 6 13 7 14 export default function (server: Server, ctx: Context) { 8 15 const createSandbox = async (input: HandlerInput, auth: HandlerAuth) => { ··· 19 26 }), 20 27 }, 21 28 ); 29 + 30 + let uri: string | null = null; 31 + 32 + if (auth?.credentials) { 33 + const agent = await createAgent(ctx.oauthClient, auth.credentials.did); 34 + 35 + consola.info( 36 + `Writing ${chalk.greenBright("io.pocketenv.sandbox")} record...`, 37 + ); 38 + 39 + const record: Sandbox.Record = { 40 + $type: "io.pocketenv.sandbox", 41 + name: res.data.name, 42 + description: res.data.description, 43 + vcpus: res.data.vcpus, 44 + memory: res.data.memory, 45 + disk: res.data.disk, 46 + createdAt: new Date().toISOString(), 47 + }; 48 + 49 + if (!agent) { 50 + consola.error("failed to create agent"); 51 + process.exit(1); 52 + } 53 + 54 + const rkey = TID.nextStr(); 55 + const { data } = await agent.com.atproto.repo.createRecord({ 56 + repo: agent.assertDid, 57 + collection: "io.pocketenv.sandbox", 58 + record, 59 + rkey: rkey, 60 + }); 61 + 62 + consola.info(chalk.greenBright("Sandbox created successfully!")); 63 + consola.info(`Record created at: ${chalk.cyan(data.uri)}`); 64 + 65 + await ctx.db 66 + .update(schema.sandboxes) 67 + .set({ uri: data.uri }) 68 + .where(eq(schema.sandboxes.id, res.data.id)) 69 + .execute(); 70 + 71 + uri = data.uri; 72 + } 22 73 return { 23 74 id: res.data.id, 24 75 name: input.body.name || "Unnamed Sandbox", ··· 31 82 disk: input.body.disk, 32 83 readme: input.body.readme, 33 84 createdAt: new Date().toISOString(), 34 - // Add other required fields 85 + uri, 35 86 }; 36 87 }; 37 88 server.io.pocketenv.sandbox.createSandbox({
+5 -1
apps/web/src/components/newproject/NewProject.tsx
··· 58 58 const onSelect = async (id: string) => { 59 59 setSelected(id); 60 60 const res = await mutateAsync(id); 61 - await navigate({ to: `/sandbox/${res.data.id}` }); 61 + await navigate({ 62 + to: res.data.uri 63 + ? `/${res.data.uri.split("at://")[1].replace("io.pocketenv.", "")}` 64 + : `/sandbox/${res.data.id}`, 65 + }); 62 66 setSelected(null); 63 67 onClose(); 64 68 setFilter("");