@pocketenv/cli 0.3.0 → 0.3.2
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 +75 -15
- package/package.json +1 -1
- package/src/cmd/create.ts +8 -3
- package/src/cmd/exec.ts +53 -0
- package/src/cmd/start.ts +18 -7
- package/src/index.ts +20 -3
- package/src/lib/expandRepo.ts +9 -0
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.
|
|
25
|
+
var version = "0.3.2";
|
|
26
26
|
|
|
27
27
|
async function getAccessToken() {
|
|
28
28
|
const tokenPath = path.join(os.homedir(), ".pocketenv", "token.json");
|
|
@@ -410,17 +410,32 @@ async function ssh(sandboxName) {
|
|
|
410
410
|
}
|
|
411
411
|
}
|
|
412
412
|
|
|
413
|
-
|
|
413
|
+
function expandRepo(repo) {
|
|
414
|
+
const githubMatch = repo.match(/^github:([^/]+\/[^/]+)$/);
|
|
415
|
+
if (githubMatch) return `https://github.com/${githubMatch[1]}`;
|
|
416
|
+
const tangledMatch = repo.match(/^tangled:([^/]+\/[^/]+)$/);
|
|
417
|
+
if (tangledMatch) return `https://tangled.org/${tangledMatch[1]}`;
|
|
418
|
+
return repo;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
async function start(name, { ssh: ssh$1, repo }) {
|
|
414
422
|
const token = await getAccessToken();
|
|
423
|
+
if (repo) repo = expandRepo(repo);
|
|
415
424
|
try {
|
|
416
|
-
await client.post(
|
|
417
|
-
|
|
418
|
-
|
|
425
|
+
await client.post(
|
|
426
|
+
"/xrpc/io.pocketenv.sandbox.startSandbox",
|
|
427
|
+
{
|
|
428
|
+
repo
|
|
419
429
|
},
|
|
420
|
-
|
|
421
|
-
|
|
430
|
+
{
|
|
431
|
+
params: {
|
|
432
|
+
id: name
|
|
433
|
+
},
|
|
434
|
+
headers: {
|
|
435
|
+
Authorization: `Bearer ${env$1.POCKETENV_TOKEN || token}`
|
|
436
|
+
}
|
|
422
437
|
}
|
|
423
|
-
|
|
438
|
+
);
|
|
424
439
|
if (ssh$1) {
|
|
425
440
|
await ssh(name);
|
|
426
441
|
return;
|
|
@@ -572,9 +587,11 @@ async function stop(name) {
|
|
|
572
587
|
async function createSandbox(name, {
|
|
573
588
|
provider,
|
|
574
589
|
ssh: ssh$1,
|
|
575
|
-
base
|
|
590
|
+
base,
|
|
591
|
+
repo
|
|
576
592
|
}) {
|
|
577
593
|
const token = await getAccessToken();
|
|
594
|
+
if (repo) repo = expandRepo(repo);
|
|
578
595
|
if (["deno", "vercel", "daytona"].includes(provider || "")) {
|
|
579
596
|
consola.error(
|
|
580
597
|
`This Sandbox Runtime is temporarily disabled. ${c.primary(provider ?? "")}`
|
|
@@ -587,7 +604,8 @@ async function createSandbox(name, {
|
|
|
587
604
|
{
|
|
588
605
|
name,
|
|
589
606
|
base: base ?? "at://did:plc:aturpi2ls3yvsmhc6wybomun/io.pocketenv.sandbox/openclaw",
|
|
590
|
-
provider: provider ?? "cloudflare"
|
|
607
|
+
provider: provider ?? "cloudflare",
|
|
608
|
+
repo
|
|
591
609
|
},
|
|
592
610
|
{
|
|
593
611
|
headers: {
|
|
@@ -1516,6 +1534,43 @@ async function exposeVscode(sandbox) {
|
|
|
1516
1534
|
}
|
|
1517
1535
|
}
|
|
1518
1536
|
|
|
1537
|
+
async function exec(sandbox, command) {
|
|
1538
|
+
const token = await getAccessToken();
|
|
1539
|
+
try {
|
|
1540
|
+
const [cmd, ...args] = command;
|
|
1541
|
+
const response = await client.post(
|
|
1542
|
+
"/xrpc/io.pocketenv.sandbox.exec",
|
|
1543
|
+
{
|
|
1544
|
+
command: `${cmd} ${args.join(" ")}`
|
|
1545
|
+
},
|
|
1546
|
+
{
|
|
1547
|
+
params: {
|
|
1548
|
+
id: sandbox
|
|
1549
|
+
},
|
|
1550
|
+
headers: {
|
|
1551
|
+
Authorization: `Bearer ${env$1.POCKETENV_TOKEN || token}`
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
);
|
|
1555
|
+
if (response.data.stdout) {
|
|
1556
|
+
process.stdout.write(
|
|
1557
|
+
response.data.stdout.endsWith("\n") ? response.data.stdout : response.data.stdout + "\n"
|
|
1558
|
+
);
|
|
1559
|
+
}
|
|
1560
|
+
if (response.data.stderr) {
|
|
1561
|
+
process.stderr.write(
|
|
1562
|
+
response.data.stderr.endsWith("\n") ? response.data.stderr : response.data.stderr + "\n"
|
|
1563
|
+
);
|
|
1564
|
+
}
|
|
1565
|
+
if (response.data.exitCode !== 0) {
|
|
1566
|
+
consola.error(`Command exited with code ${response.data.exitCode}`);
|
|
1567
|
+
}
|
|
1568
|
+
process.exit(response.data.exitCode);
|
|
1569
|
+
} catch (error) {
|
|
1570
|
+
consola.error("Failed to execute command:", error);
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1519
1574
|
const program = new Command();
|
|
1520
1575
|
program.name("pocketenv").description(
|
|
1521
1576
|
`${chalk.bold.rgb(0, 232, 198)(`pocketenv v${version}`)} ${c.muted("\u2500")} ${c.muted("Open, interoperable sandbox platform for agents and humans")}`
|
|
@@ -1542,17 +1597,22 @@ program.command("login").argument("<handle>", "your AT Proto handle (e.g., <user
|
|
|
1542
1597
|
program.command("whoami").description("get the current logged-in user").action(whoami);
|
|
1543
1598
|
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
1599
|
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").
|
|
1600
|
+
program.command("start").argument("<sandbox>", "the sandbox to start").option("--ssh, -s", "connect to the Sandbox and automatically open a shell").option(
|
|
1601
|
+
"--repo, -r <repo>",
|
|
1602
|
+
"the repository to clone into the sandbox (e.g., github:user/repo, tangled:user/repo, or a Git URL)"
|
|
1603
|
+
).description("start the given sandbox").action(start);
|
|
1546
1604
|
program.command("stop").argument("<sandbox>", "the sandbox to stop").description("stop the given sandbox").action(stop);
|
|
1547
1605
|
program.command("create").aliases(["new"]).option("--provider, -p <provider>", "the provider to use for the sandbox").option(
|
|
1548
1606
|
"--base, -b <base>",
|
|
1549
1607
|
"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").
|
|
1608
|
+
).option("--ssh, -s", "connect to the Sandbox and automatically open a shell").option(
|
|
1609
|
+
"--repo, -r <repo>",
|
|
1610
|
+
"the repository to clone into the sandbox (e.g., github:user/repo, tangled:user/repo, or a Git URL)"
|
|
1611
|
+
).argument("[name]", "the name of the sandbox to create").description("create a new sandbox").action(createSandbox);
|
|
1551
1612
|
program.command("logout").description("logout (removes session token)").action(logout);
|
|
1552
1613
|
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
|
-
|
|
1555
|
-
).action(exposeVscode);
|
|
1614
|
+
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);
|
|
1615
|
+
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
1616
|
program.command("expose").argument("<sandbox>", "the sandbox to expose a port for").argument("<port>", "the port to expose", (val) => {
|
|
1557
1617
|
const port = parseInt(val, 10);
|
|
1558
1618
|
if (isNaN(port)) {
|
package/package.json
CHANGED
package/src/cmd/create.ts
CHANGED
|
@@ -4,6 +4,7 @@ import getAccessToken from "../lib/getAccessToken";
|
|
|
4
4
|
import type { Sandbox } from "../types/sandbox";
|
|
5
5
|
import connectToSandbox from "./ssh";
|
|
6
6
|
import { c } from "../theme";
|
|
7
|
+
import { expandRepo } from "../lib/expandRepo";
|
|
7
8
|
|
|
8
9
|
async function createSandbox(
|
|
9
10
|
name: string,
|
|
@@ -11,13 +12,16 @@ async function createSandbox(
|
|
|
11
12
|
provider,
|
|
12
13
|
ssh,
|
|
13
14
|
base,
|
|
15
|
+
repo,
|
|
14
16
|
}: {
|
|
15
|
-
provider
|
|
16
|
-
ssh
|
|
17
|
-
base
|
|
17
|
+
provider?: string;
|
|
18
|
+
ssh?: boolean;
|
|
19
|
+
base?: string;
|
|
20
|
+
repo?: string;
|
|
18
21
|
},
|
|
19
22
|
) {
|
|
20
23
|
const token = await getAccessToken();
|
|
24
|
+
if (repo) repo = expandRepo(repo);
|
|
21
25
|
|
|
22
26
|
if (["deno", "vercel", "daytona"].includes(provider || "")) {
|
|
23
27
|
consola.error(
|
|
@@ -34,6 +38,7 @@ async function createSandbox(
|
|
|
34
38
|
base ??
|
|
35
39
|
"at://did:plc:aturpi2ls3yvsmhc6wybomun/io.pocketenv.sandbox/openclaw",
|
|
36
40
|
provider: provider ?? "cloudflare",
|
|
41
|
+
repo,
|
|
37
42
|
},
|
|
38
43
|
{
|
|
39
44
|
headers: {
|
package/src/cmd/exec.ts
ADDED
|
@@ -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
|
@@ -4,19 +4,30 @@ import getAccessToken from "../lib/getAccessToken";
|
|
|
4
4
|
import { client } from "../client";
|
|
5
5
|
import { env } from "../lib/env";
|
|
6
6
|
import connectToSandbox from "./ssh";
|
|
7
|
+
import { expandRepo } from "../lib/expandRepo";
|
|
7
8
|
|
|
8
|
-
async function start(
|
|
9
|
+
async function start(
|
|
10
|
+
name: string,
|
|
11
|
+
{ ssh, repo }: { ssh?: boolean; repo?: string },
|
|
12
|
+
) {
|
|
9
13
|
const token = await getAccessToken();
|
|
14
|
+
if (repo) repo = expandRepo(repo);
|
|
10
15
|
|
|
11
16
|
try {
|
|
12
|
-
await client.post(
|
|
13
|
-
|
|
14
|
-
|
|
17
|
+
await client.post(
|
|
18
|
+
"/xrpc/io.pocketenv.sandbox.startSandbox",
|
|
19
|
+
{
|
|
20
|
+
repo,
|
|
15
21
|
},
|
|
16
|
-
|
|
17
|
-
|
|
22
|
+
{
|
|
23
|
+
params: {
|
|
24
|
+
id: name,
|
|
25
|
+
},
|
|
26
|
+
headers: {
|
|
27
|
+
Authorization: `Bearer ${env.POCKETENV_TOKEN || token}`,
|
|
28
|
+
},
|
|
18
29
|
},
|
|
19
|
-
|
|
30
|
+
);
|
|
20
31
|
|
|
21
32
|
if (ssh) {
|
|
22
33
|
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")
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function expandRepo(repo: string): string {
|
|
2
|
+
const githubMatch = repo.match(/^github:([^/]+\/[^/]+)$/);
|
|
3
|
+
if (githubMatch) return `https://github.com/${githubMatch[1]}`;
|
|
4
|
+
|
|
5
|
+
const tangledMatch = repo.match(/^tangled:([^/]+\/[^/]+)$/);
|
|
6
|
+
if (tangledMatch) return `https://tangled.org/${tangledMatch[1]}`;
|
|
7
|
+
|
|
8
|
+
return repo;
|
|
9
|
+
}
|