the universal sandbox runtime for agents and humans.
pocketenv.io
sandbox
openclaw
agent
claude-code
vercel-sandbox
deno-sandbox
cloudflare-sandbox
atproto
sprites
daytona
1import consola from "consola";
2import { Sandbox } from "@pocketenv/sdk";
3import Table from "cli-table3";
4import dayjs from "dayjs";
5import relativeTime from "dayjs/plugin/relativeTime";
6import { c } from "../theme";
7import process from "node:process";
8import { configureSdk } from "../lib/sdk";
9import { client } from "../client";
10import getAccessToken from "../lib/getAccessToken";
11import { env } from "../lib/env";
12
13dayjs.extend(relativeTime);
14
15type CreateServiceOptions = {
16 ports?: string[];
17 description?: string;
18};
19
20export async function createService(
21 sandboxId: string,
22 name: string,
23 command: string[],
24 { ports, description }: CreateServiceOptions,
25) {
26 await configureSdk();
27
28 try {
29 const sandbox = await Sandbox.get(sandboxId);
30 await sandbox.service.add(name, command.join(" "), {
31 description,
32 ports: ports?.map((port) => parseInt(port)),
33 });
34
35 consola.success(`Service ${c.highlight(name)} created successfully`);
36 } catch (error) {
37 consola.error("Failed to create service", error);
38 process.exit(1);
39 }
40}
41
42export async function listServices(sandboxId: string) {
43 await configureSdk();
44
45 try {
46 const sandbox = await Sandbox.get(sandboxId);
47 const { services } = await sandbox.service.list();
48
49 const table = new Table({
50 head: [
51 c.primary("ID"),
52 c.primary("NAME"),
53 c.primary("COMMAND"),
54 c.primary("STATUS"),
55 c.primary("CREATED AT"),
56 ],
57 chars: {
58 top: "",
59 "top-mid": "",
60 "top-left": "",
61 "top-right": "",
62 bottom: "",
63 "bottom-mid": "",
64 "bottom-left": "",
65 "bottom-right": "",
66 left: "",
67 "left-mid": "",
68 mid: "",
69 "mid-mid": "",
70 right: "",
71 "right-mid": "",
72 middle: " ",
73 },
74 style: {
75 border: [],
76 head: [],
77 },
78 });
79
80 for (const service of services) {
81 table.push([
82 c.secondary(service.id),
83 service.name,
84 service.command,
85 service.status === "RUNNING"
86 ? c.highlight(service.status)
87 : service.status ?? "",
88 dayjs(service.createdAt).fromNow(),
89 ]);
90 }
91
92 consola.log(table.toString());
93 } catch (error) {
94 consola.error("Failed to list services", error);
95 process.exit(1);
96 }
97}
98
99export async function restartService(serviceId: string) {
100 const token = await getAccessToken();
101 try {
102 await client.post("/xrpc/io.pocketenv.service.restartService", undefined, {
103 params: { serviceId },
104 headers: {
105 Authorization: `Bearer ${env.POCKETENV_TOKEN || token}`,
106 },
107 });
108 } catch (error) {
109 consola.error(`Failed to restart service ${serviceId}`, error);
110 process.exit(1);
111 }
112}
113
114export async function startService(serviceId: string) {
115 const token = await getAccessToken();
116
117 try {
118 await client.post("/xrpc/io.pocketenv.service.startService", undefined, {
119 params: { serviceId },
120 headers: {
121 Authorization: `Bearer ${env.POCKETENV_TOKEN || token}`,
122 },
123 });
124 } catch (error) {
125 consola.error(`Failed to start service ${serviceId}`, error);
126 process.exit(1);
127 }
128}
129
130export async function stopService(serviceId: string) {
131 const token = await getAccessToken();
132
133 try {
134 await client.post("/xrpc/io.pocketenv.service.stopService", undefined, {
135 params: { serviceId },
136 headers: {
137 Authorization: `Bearer ${env.POCKETENV_TOKEN || token}`,
138 },
139 });
140 } catch (error) {
141 consola.error(`Failed to stop service ${serviceId}`, error);
142 process.exit(1);
143 }
144}
145
146export async function deleteService(serviceId: string) {
147 const token = await getAccessToken();
148
149 try {
150 await client.post("/xrpc/io.pocketenv.service.deleteService", undefined, {
151 params: { serviceId },
152 headers: {
153 Authorization: `Bearer ${env.POCKETENV_TOKEN || token}`,
154 },
155 });
156 consola.success(`Service ${c.highlight(serviceId)} deleted successfully`);
157 } catch (error) {
158 consola.error(`Failed to delete service ${serviceId}`, error);
159 process.exit(1);
160 }
161}