@pocketenv/cli 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -22,7 +22,7 @@ import relativeTime from 'dayjs/plugin/relativeTime.js';
22
22
  import { password, editor, input } from '@inquirer/prompts';
23
23
  import sodium from 'libsodium-wrappers';
24
24
 
25
- var version = "0.3.0";
25
+ var version = "0.3.1";
26
26
 
27
27
  async function getAccessToken() {
28
28
  const tokenPath = path.join(os.homedir(), ".pocketenv", "token.json");
@@ -410,17 +410,23 @@ async function ssh(sandboxName) {
410
410
  }
411
411
  }
412
412
 
413
- async function start(name, { ssh: ssh$1 }) {
413
+ async function start(name, { ssh: ssh$1, repo }) {
414
414
  const token = await getAccessToken();
415
415
  try {
416
- await client.post("/xrpc/io.pocketenv.sandbox.startSandbox", void 0, {
417
- params: {
418
- id: name
416
+ await client.post(
417
+ "/xrpc/io.pocketenv.sandbox.startSandbox",
418
+ {
419
+ repo
419
420
  },
420
- headers: {
421
- Authorization: `Bearer ${env$1.POCKETENV_TOKEN || token}`
421
+ {
422
+ params: {
423
+ id: name
424
+ },
425
+ headers: {
426
+ Authorization: `Bearer ${env$1.POCKETENV_TOKEN || token}`
427
+ }
422
428
  }
423
- });
429
+ );
424
430
  if (ssh$1) {
425
431
  await ssh(name);
426
432
  return;
@@ -572,7 +578,8 @@ async function stop(name) {
572
578
  async function createSandbox(name, {
573
579
  provider,
574
580
  ssh: ssh$1,
575
- base
581
+ base,
582
+ repo
576
583
  }) {
577
584
  const token = await getAccessToken();
578
585
  if (["deno", "vercel", "daytona"].includes(provider || "")) {
@@ -587,7 +594,8 @@ async function createSandbox(name, {
587
594
  {
588
595
  name,
589
596
  base: base ?? "at://did:plc:aturpi2ls3yvsmhc6wybomun/io.pocketenv.sandbox/openclaw",
590
- provider: provider ?? "cloudflare"
597
+ provider: provider ?? "cloudflare",
598
+ repo
591
599
  },
592
600
  {
593
601
  headers: {
@@ -1516,6 +1524,43 @@ async function exposeVscode(sandbox) {
1516
1524
  }
1517
1525
  }
1518
1526
 
1527
+ async function exec(sandbox, command) {
1528
+ const token = await getAccessToken();
1529
+ try {
1530
+ const [cmd, ...args] = command;
1531
+ const response = await client.post(
1532
+ "/xrpc/io.pocketenv.sandbox.exec",
1533
+ {
1534
+ command: `${cmd} ${args.join(" ")}`
1535
+ },
1536
+ {
1537
+ params: {
1538
+ id: sandbox
1539
+ },
1540
+ headers: {
1541
+ Authorization: `Bearer ${env$1.POCKETENV_TOKEN || token}`
1542
+ }
1543
+ }
1544
+ );
1545
+ if (response.data.stdout) {
1546
+ process.stdout.write(
1547
+ response.data.stdout.endsWith("\n") ? response.data.stdout : response.data.stdout + "\n"
1548
+ );
1549
+ }
1550
+ if (response.data.stderr) {
1551
+ process.stderr.write(
1552
+ response.data.stderr.endsWith("\n") ? response.data.stderr : response.data.stderr + "\n"
1553
+ );
1554
+ }
1555
+ if (response.data.exitCode !== 0) {
1556
+ consola.error(`Command exited with code ${response.data.exitCode}`);
1557
+ }
1558
+ process.exit(response.data.exitCode);
1559
+ } catch (error) {
1560
+ consola.error("Failed to execute command:", error);
1561
+ }
1562
+ }
1563
+
1519
1564
  const program = new Command();
1520
1565
  program.name("pocketenv").description(
1521
1566
  `${chalk.bold.rgb(0, 232, 198)(`pocketenv v${version}`)} ${c.muted("\u2500")} ${c.muted("Open, interoperable sandbox platform for agents and humans")}`
@@ -1542,17 +1587,22 @@ program.command("login").argument("<handle>", "your AT Proto handle (e.g., <user
1542
1587
  program.command("whoami").description("get the current logged-in user").action(whoami);
1543
1588
  program.command("console").aliases(["shell", "ssh", "s"]).argument("[sandbox]", "the sandbox to connect to").description("open an interactive shell for the given sandbox").action(ssh);
1544
1589
  program.command("ls").description("list sandboxes").action(listSandboxes);
1545
- program.command("start").argument("<sandbox>", "the sandbox to start").option("--ssh, -s", "connect to the Sandbox and automatically open a shell").description("start the given sandbox").action(start);
1590
+ program.command("start").argument("<sandbox>", "the sandbox to start").option("--ssh, -s", "connect to the Sandbox and automatically open a shell").option(
1591
+ "--repo, -r <repo>",
1592
+ "the repository to clone into the sandbox (e.g., github:user/repo, tangled:user/repo, or a Git URL)"
1593
+ ).description("start the given sandbox").action(start);
1546
1594
  program.command("stop").argument("<sandbox>", "the sandbox to stop").description("stop the given sandbox").action(stop);
1547
1595
  program.command("create").aliases(["new"]).option("--provider, -p <provider>", "the provider to use for the sandbox").option(
1548
1596
  "--base, -b <base>",
1549
1597
  "the base sandbox to use for the sandbox, e.g. openclaw, claude-code, codex, copilot ..."
1550
- ).option("--ssh, -s", "connect to the Sandbox and automatically open a shell").argument("[name]", "the name of the sandbox to create").description("create a new sandbox").action(createSandbox);
1598
+ ).option("--ssh, -s", "connect to the Sandbox and automatically open a shell").option(
1599
+ "--repo, -r <repo>",
1600
+ "the repository to clone into the sandbox (e.g., github:user/repo, tangled:user/repo, or a Git URL)"
1601
+ ).argument("[name]", "the name of the sandbox to create").description("create a new sandbox").action(createSandbox);
1551
1602
  program.command("logout").description("logout (removes session token)").action(logout);
1552
1603
  program.command("rm").aliases(["delete", "remove"]).argument("<sandbox>", "the sandbox to delete").description("delete the given sandbox").action(deleteSandbox);
1553
- program.command("vscode").argument("<sandbox>", "the sandbox to expose VS Code for").description(
1554
- "expose a VS Code Server instance running in the given sandbox to the internet"
1555
- ).action(exposeVscode);
1604
+ program.command("vscode").aliases(["code", "code-server"]).argument("<sandbox>", "the sandbox to expose VS Code for").description("expose a visual code server to the internet").action(exposeVscode);
1605
+ program.enablePositionalOptions().command("exec").argument("<sandbox>", "the sandbox to execute the command in").argument("<command...>", "the command to execute").description("execute a command in the given sandbox").passThroughOptions().action(exec);
1556
1606
  program.command("expose").argument("<sandbox>", "the sandbox to expose a port for").argument("<port>", "the port to expose", (val) => {
1557
1607
  const port = parseInt(val, 10);
1558
1608
  if (isNaN(port)) {
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "bin": {
5
5
  "pocketenv": "dist/index.js"
6
6
  },
7
- "version": "0.3.0",
7
+ "version": "0.3.1",
8
8
  "type": "module",
9
9
  "keywords": [
10
10
  "sandbox",
package/src/cmd/create.ts CHANGED
@@ -11,10 +11,12 @@ async function createSandbox(
11
11
  provider,
12
12
  ssh,
13
13
  base,
14
+ repo,
14
15
  }: {
15
- provider: string | undefined;
16
- ssh: boolean | undefined;
17
- base: string | undefined;
16
+ provider?: string;
17
+ ssh?: boolean;
18
+ base?: string;
19
+ repo?: string;
18
20
  },
19
21
  ) {
20
22
  const token = await getAccessToken();
@@ -34,6 +36,7 @@ async function createSandbox(
34
36
  base ??
35
37
  "at://did:plc:aturpi2ls3yvsmhc6wybomun/io.pocketenv.sandbox/openclaw",
36
38
  provider: provider ?? "cloudflare",
39
+ repo,
37
40
  },
38
41
  {
39
42
  headers: {
@@ -0,0 +1,53 @@
1
+ import consola from "consola";
2
+ import getAccessToken from "../lib/getAccessToken";
3
+ import { client } from "../client";
4
+ import { env } from "../lib/env";
5
+
6
+ export async function exec(sandbox: string, command: string[]) {
7
+ const token = await getAccessToken();
8
+
9
+ try {
10
+ const [cmd, ...args] = command;
11
+ const response = await client.post<{
12
+ stderr: string;
13
+ stdout: string;
14
+ exitCode: number;
15
+ }>(
16
+ "/xrpc/io.pocketenv.sandbox.exec",
17
+ {
18
+ command: `${cmd} ${args.join(" ")}`,
19
+ },
20
+ {
21
+ params: {
22
+ id: sandbox,
23
+ },
24
+ headers: {
25
+ Authorization: `Bearer ${env.POCKETENV_TOKEN || token}`,
26
+ },
27
+ },
28
+ );
29
+
30
+ if (response.data.stdout) {
31
+ process.stdout.write(
32
+ response.data.stdout.endsWith("\n")
33
+ ? response.data.stdout
34
+ : response.data.stdout + "\n",
35
+ );
36
+ }
37
+ if (response.data.stderr) {
38
+ process.stderr.write(
39
+ response.data.stderr.endsWith("\n")
40
+ ? response.data.stderr
41
+ : response.data.stderr + "\n",
42
+ );
43
+ }
44
+
45
+ if (response.data.exitCode !== 0) {
46
+ consola.error(`Command exited with code ${response.data.exitCode}`);
47
+ }
48
+
49
+ process.exit(response.data.exitCode);
50
+ } catch (error) {
51
+ consola.error("Failed to execute command:", error);
52
+ }
53
+ }
package/src/cmd/start.ts CHANGED
@@ -5,18 +5,27 @@ import { client } from "../client";
5
5
  import { env } from "../lib/env";
6
6
  import connectToSandbox from "./ssh";
7
7
 
8
- async function start(name: string, { ssh }: { ssh?: boolean }) {
8
+ async function start(
9
+ name: string,
10
+ { ssh, repo }: { ssh?: boolean; repo?: string },
11
+ ) {
9
12
  const token = await getAccessToken();
10
13
 
11
14
  try {
12
- await client.post("/xrpc/io.pocketenv.sandbox.startSandbox", undefined, {
13
- params: {
14
- id: name,
15
+ await client.post(
16
+ "/xrpc/io.pocketenv.sandbox.startSandbox",
17
+ {
18
+ repo,
15
19
  },
16
- headers: {
17
- Authorization: `Bearer ${env.POCKETENV_TOKEN || token}`,
20
+ {
21
+ params: {
22
+ id: name,
23
+ },
24
+ headers: {
25
+ Authorization: `Bearer ${env.POCKETENV_TOKEN || token}`,
26
+ },
18
27
  },
19
- });
28
+ );
20
29
 
21
30
  if (ssh) {
22
31
  await connectToSandbox(name);
package/src/index.ts CHANGED
@@ -22,6 +22,7 @@ import consola from "consola";
22
22
  import { listPorts } from "./cmd/ports";
23
23
  import { c } from "./theme";
24
24
  import { exposeVscode } from "./cmd/vscode";
25
+ import { exec } from "./cmd/exec";
25
26
 
26
27
  const program = new Command();
27
28
 
@@ -76,6 +77,10 @@ program
76
77
  .command("start")
77
78
  .argument("<sandbox>", "the sandbox to start")
78
79
  .option("--ssh, -s", "connect to the Sandbox and automatically open a shell")
80
+ .option(
81
+ "--repo, -r <repo>",
82
+ "the repository to clone into the sandbox (e.g., github:user/repo, tangled:user/repo, or a Git URL)",
83
+ )
79
84
  .description("start the given sandbox")
80
85
  .action(start);
81
86
 
@@ -94,6 +99,10 @@ program
94
99
  "the base sandbox to use for the sandbox, e.g. openclaw, claude-code, codex, copilot ...",
95
100
  )
96
101
  .option("--ssh, -s", "connect to the Sandbox and automatically open a shell")
102
+ .option(
103
+ "--repo, -r <repo>",
104
+ "the repository to clone into the sandbox (e.g., github:user/repo, tangled:user/repo, or a Git URL)",
105
+ )
97
106
  .argument("[name]", "the name of the sandbox to create")
98
107
  .description("create a new sandbox")
99
108
  .action(createSandbox);
@@ -112,12 +121,20 @@ program
112
121
 
113
122
  program
114
123
  .command("vscode")
124
+ .aliases(["code", "code-server"])
115
125
  .argument("<sandbox>", "the sandbox to expose VS Code for")
116
- .description(
117
- "expose a VS Code Server instance running in the given sandbox to the internet",
118
- )
126
+ .description("expose a visual code server to the internet")
119
127
  .action(exposeVscode);
120
128
 
129
+ program
130
+ .enablePositionalOptions()
131
+ .command("exec")
132
+ .argument("<sandbox>", "the sandbox to execute the command in")
133
+ .argument("<command...>", "the command to execute")
134
+ .description("execute a command in the given sandbox")
135
+ .passThroughOptions()
136
+ .action(exec);
137
+
121
138
  program
122
139
  .command("expose")
123
140
  .argument("<sandbox>", "the sandbox to expose a port for")