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.

Add access token helper and list command

+148 -33
+69 -1
apps/cli/src/cmd/list.ts
··· 1 - async function listSandboxes() {} 1 + import { client } from "../client"; 2 + import chalk from "chalk"; 3 + import consola from "consola"; 4 + import { env } from "../lib/env"; 5 + import getAccessToken from "../lib/getAccessToken"; 6 + import type { Sandbox } from "../types/sandbox"; 7 + import Table from "cli-table3"; 8 + import dayjs from "dayjs"; 9 + import relativeTime from "dayjs/plugin/relativeTime"; 10 + import type { Profile } from "../types/profile"; 11 + dayjs.extend(relativeTime); 12 + 13 + async function listSandboxes() { 14 + const token = await getAccessToken(); 15 + 16 + const profile = await client.get<Profile>( 17 + "/xrpc/io.pocketenv.actor.getProfile", 18 + { 19 + headers: { 20 + Authorization: `Bearer ${env.POCKETENV_TOKEN || token}`, 21 + }, 22 + }, 23 + ); 24 + 25 + const response = await client.get<{ sandboxes: Sandbox[] }>( 26 + `/xrpc/io.pocketenv.actor.getActorSandboxes?did=${profile.data.did}&offset=0&limit=100`, 27 + ); 28 + 29 + const table = new Table({ 30 + head: [ 31 + chalk.cyan("NAME"), 32 + chalk.cyan("BASE"), 33 + chalk.cyan("STATUS"), 34 + chalk.cyan("CREATED AT"), 35 + ], 36 + chars: { 37 + top: "", 38 + "top-mid": "", 39 + "top-left": "", 40 + "top-right": "", 41 + bottom: "", 42 + "bottom-mid": "", 43 + "bottom-left": "", 44 + "bottom-right": "", 45 + left: "", 46 + "left-mid": "", 47 + mid: "", 48 + "mid-mid": "", 49 + right: "", 50 + "right-mid": "", 51 + middle: " ", 52 + }, 53 + style: { 54 + border: [], 55 + head: [], 56 + }, 57 + }); 58 + 59 + for (const sandbox of response.data.sandboxes) { 60 + table.push([ 61 + chalk.greenBright(sandbox.name), 62 + sandbox.baseSandbox, 63 + sandbox.status, 64 + dayjs(sandbox.createdAt).fromNow(), 65 + ]); 66 + } 67 + 68 + consola.log(table.toString()); 69 + } 2 70 3 71 export default listSandboxes;
+10 -32
apps/cli/src/cmd/whoami.ts
··· 1 - import os from "node:os"; 2 - import path from "node:path"; 3 - import fs from "node:fs/promises"; 4 1 import chalk from "chalk"; 5 2 import { client } from "../client"; 6 3 import { env } from "../lib/env"; 7 4 import consola from "consola"; 5 + import getAccessToken from "../lib/getAccessToken"; 6 + import type { Profile } from "../types/profile"; 8 7 9 8 async function whoami() { 10 - const tokenPath = path.join(os.homedir(), ".pocketenv", "token.json"); 11 - try { 12 - await fs.access(tokenPath); 13 - } catch (err) { 14 - if (!env.POCKETENV_TOKEN) { 15 - consola.error( 16 - `You are not logged in. Please run ${chalk.greenBright( 17 - "`pocketenv login <username>.bsky.social`", 18 - )} first.`, 19 - ); 20 - return; 21 - } 22 - } 23 - 24 - const tokenData = await fs.readFile(tokenPath, "utf-8"); 25 - const { token } = JSON.parse(tokenData); 26 - if (!token) { 27 - consola.error( 28 - `You are not logged in. Please run ${chalk.greenBright( 29 - "`rocksky login <username>.bsky.social`", 30 - )} first.`, 31 - ); 32 - return; 33 - } 34 - 35 - const profile = await client.get("/xrpc/io.pocketenv.actor.getProfile", { 36 - headers: { 37 - Authorization: `Bearer ${env.POCKETENV_TOKEN || token}`, 9 + const token = await getAccessToken(); 10 + const profile = await client.get<Profile>( 11 + "/xrpc/io.pocketenv.actor.getProfile", 12 + { 13 + headers: { 14 + Authorization: `Bearer ${env.POCKETENV_TOKEN || token}`, 15 + }, 38 16 }, 39 - }); 17 + ); 40 18 const handle = `@${profile.data.handle}`; 41 19 consola.log( 42 20 `You are logged in as ${chalk.cyan(handle)} (${profile.data.displayName}).`,
+36
apps/cli/src/lib/getAccessToken.ts
··· 1 + import consola from "consola"; 2 + import chalk from "chalk"; 3 + import fs from "fs/promises"; 4 + import path from "path"; 5 + import os from "os"; 6 + import { env } from "process"; 7 + 8 + async function getAccessToken(): Promise<string> { 9 + const tokenPath = path.join(os.homedir(), ".pocketenv", "token.json"); 10 + try { 11 + await fs.access(tokenPath); 12 + } catch (err) { 13 + if (!env.POCKETENV_TOKEN) { 14 + consola.error( 15 + `You are not logged in. Please run ${chalk.greenBright( 16 + "`pocketenv login <username>.bsky.social`", 17 + )} first.`, 18 + ); 19 + process.exit(1); 20 + } 21 + } 22 + 23 + const tokenData = await fs.readFile(tokenPath, "utf-8"); 24 + const { token } = JSON.parse(tokenData); 25 + if (!token) { 26 + consola.error( 27 + `You are not logged in. Please run ${chalk.greenBright( 28 + "`rocksky login <username>.bsky.social`", 29 + )} first.`, 30 + ); 31 + process.exit(1); 32 + } 33 + return token; 34 + } 35 + 36 + export default getAccessToken;
+9
apps/cli/src/types/profile.ts
··· 1 + export type Profile = { 2 + id: string; 3 + did: string; 4 + handle: string; 5 + displayName: string; 6 + avatar: string; 7 + createdAt: string; 8 + updatedAt: string; 9 + };
+1
apps/cli/src/types/providers.ts
··· 1 + export type Provider = "daytona" | "deno" | "cloudflare" | "vercel" | "sprites";
+23
apps/cli/src/types/sandbox.ts
··· 1 + import type { Profile } from "./profile"; 2 + import type { Provider } from "./providers"; 3 + 4 + export type Sandbox = { 5 + id: string; 6 + name: string; 7 + provider: Provider; 8 + baseSandbox: string; 9 + displayName: string; 10 + uri: string; 11 + description?: string; 12 + topics?: string[]; 13 + logo?: string; 14 + readme?: string; 15 + repo?: string; 16 + vcpus?: number; 17 + memory?: number; 18 + installs: number; 19 + status: "RUNNING" | "STOPPED"; 20 + startedAt?: string; 21 + createdAt: string; 22 + owner: Profile | null; 23 + };