@pocketenv/cli 0.2.5 → 0.3.0
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 +425 -50
- package/package.json +1 -1
- package/src/cmd/create.ts +3 -3
- package/src/cmd/env.ts +8 -8
- package/src/cmd/expose.ts +38 -0
- package/src/cmd/file.ts +139 -0
- package/src/cmd/list.ts +7 -7
- package/src/cmd/ports.ts +63 -0
- package/src/cmd/secret.ts +34 -19
- package/src/cmd/tailscale.ts +6 -6
- package/src/cmd/unexpose.ts +31 -0
- package/src/cmd/volume.ts +123 -0
- package/src/cmd/vscode.ts +32 -0
- package/src/index.ts +99 -10
- package/src/theme.ts +12 -0
- package/src/types/port.ts +5 -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.
|
|
25
|
+
var version = "0.3.0";
|
|
26
26
|
|
|
27
27
|
async function getAccessToken() {
|
|
28
28
|
const tokenPath = path.join(os.homedir(), ".pocketenv", "token.json");
|
|
@@ -480,6 +480,17 @@ async function whoami() {
|
|
|
480
480
|
);
|
|
481
481
|
}
|
|
482
482
|
|
|
483
|
+
const c = {
|
|
484
|
+
primary: (s) => chalk.rgb(0, 232, 198)(s),
|
|
485
|
+
secondary: (s) => chalk.rgb(0, 198, 232)(s),
|
|
486
|
+
accent: (s) => chalk.rgb(130, 100, 255)(s),
|
|
487
|
+
highlight: (s) => chalk.rgb(100, 232, 130)(s),
|
|
488
|
+
muted: (s) => chalk.rgb(200, 210, 220)(s),
|
|
489
|
+
link: (s) => chalk.rgb(255, 160, 100)(s),
|
|
490
|
+
sky: (s) => chalk.rgb(0, 210, 255)(s),
|
|
491
|
+
error: (s) => chalk.rgb(255, 100, 100)(s)
|
|
492
|
+
};
|
|
493
|
+
|
|
483
494
|
dayjs.extend(relativeTime);
|
|
484
495
|
async function listSandboxes() {
|
|
485
496
|
const token = await getAccessToken();
|
|
@@ -503,10 +514,10 @@ async function listSandboxes() {
|
|
|
503
514
|
);
|
|
504
515
|
const table = new Table({
|
|
505
516
|
head: [
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
517
|
+
c.primary("NAME"),
|
|
518
|
+
c.primary("BASE"),
|
|
519
|
+
c.primary("STATUS"),
|
|
520
|
+
c.primary("CREATED AT")
|
|
510
521
|
],
|
|
511
522
|
chars: {
|
|
512
523
|
top: "",
|
|
@@ -532,9 +543,9 @@ async function listSandboxes() {
|
|
|
532
543
|
});
|
|
533
544
|
for (const sandbox of response.data.sandboxes) {
|
|
534
545
|
table.push([
|
|
535
|
-
|
|
546
|
+
c.secondary(sandbox.name),
|
|
536
547
|
sandbox.baseSandbox,
|
|
537
|
-
sandbox.status === "RUNNING" ?
|
|
548
|
+
sandbox.status === "RUNNING" ? c.highlight(sandbox.status) : sandbox.status,
|
|
538
549
|
dayjs(sandbox.createdAt).fromNow()
|
|
539
550
|
]);
|
|
540
551
|
}
|
|
@@ -566,7 +577,7 @@ async function createSandbox(name, {
|
|
|
566
577
|
const token = await getAccessToken();
|
|
567
578
|
if (["deno", "vercel", "daytona"].includes(provider || "")) {
|
|
568
579
|
consola.error(
|
|
569
|
-
`This Sandbox Runtime is temporarily disabled. ${
|
|
580
|
+
`This Sandbox Runtime is temporarily disabled. ${c.primary(provider ?? "")}`
|
|
570
581
|
);
|
|
571
582
|
process.exit(1);
|
|
572
583
|
}
|
|
@@ -586,7 +597,7 @@ async function createSandbox(name, {
|
|
|
586
597
|
);
|
|
587
598
|
if (!ssh$1) {
|
|
588
599
|
consola.success(
|
|
589
|
-
`Sandbox created successfully: ${
|
|
600
|
+
`Sandbox created successfully: ${c.primary(sandbox.data.name)}`
|
|
590
601
|
);
|
|
591
602
|
return;
|
|
592
603
|
}
|
|
@@ -662,7 +673,7 @@ async function listSecrets(sandbox) {
|
|
|
662
673
|
}
|
|
663
674
|
);
|
|
664
675
|
const table = new Table({
|
|
665
|
-
head: [
|
|
676
|
+
head: [c.primary("ID"), c.primary("NAME"), c.primary("CREATED AT")],
|
|
666
677
|
chars: {
|
|
667
678
|
top: "",
|
|
668
679
|
"top-mid": "",
|
|
@@ -687,8 +698,8 @@ async function listSecrets(sandbox) {
|
|
|
687
698
|
});
|
|
688
699
|
for (const secret of response.data.secrets) {
|
|
689
700
|
table.push([
|
|
690
|
-
|
|
691
|
-
|
|
701
|
+
c.secondary(secret.id),
|
|
702
|
+
c.highlight(secret.name),
|
|
692
703
|
dayjs(secret.createdAt).fromNow()
|
|
693
704
|
]);
|
|
694
705
|
}
|
|
@@ -696,7 +707,13 @@ async function listSecrets(sandbox) {
|
|
|
696
707
|
}
|
|
697
708
|
async function putSecret(sandbox, key) {
|
|
698
709
|
const token = await getAccessToken();
|
|
699
|
-
const
|
|
710
|
+
const isStdinPiped = !process.stdin.isTTY;
|
|
711
|
+
const value = isStdinPiped ? await new Promise((resolve) => {
|
|
712
|
+
let data2 = "";
|
|
713
|
+
process.stdin.setEncoding("utf8");
|
|
714
|
+
process.stdin.on("data", (chunk) => data2 += chunk);
|
|
715
|
+
process.stdin.on("end", () => resolve(data2.trimEnd()));
|
|
716
|
+
}) : await password({ message: "Enter secret value" });
|
|
700
717
|
const { data } = await client.get("/xrpc/io.pocketenv.sandbox.getSandbox", {
|
|
701
718
|
params: {
|
|
702
719
|
id: sandbox
|
|
@@ -709,21 +726,26 @@ async function putSecret(sandbox, key) {
|
|
|
709
726
|
consola.error(`Sandbox not found: ${chalk.greenBright(sandbox)}`);
|
|
710
727
|
process.exit(1);
|
|
711
728
|
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
729
|
+
try {
|
|
730
|
+
await client.post(
|
|
731
|
+
"/xrpc/io.pocketenv.secret.addSecret",
|
|
732
|
+
{
|
|
733
|
+
secret: {
|
|
734
|
+
sandboxId: data.sandbox.id,
|
|
735
|
+
name: key,
|
|
736
|
+
value: await encrypt(value)
|
|
737
|
+
}
|
|
738
|
+
},
|
|
739
|
+
{
|
|
740
|
+
headers: {
|
|
741
|
+
Authorization: `Bearer ${env$1.POCKETENV_TOKEN || token}`
|
|
742
|
+
}
|
|
724
743
|
}
|
|
725
|
-
|
|
726
|
-
|
|
744
|
+
);
|
|
745
|
+
consola.success("Secret added successfully");
|
|
746
|
+
} catch (error) {
|
|
747
|
+
consola.error("Failed to add secret:", error);
|
|
748
|
+
}
|
|
727
749
|
}
|
|
728
750
|
async function deleteSecret(id) {
|
|
729
751
|
const token = await getAccessToken();
|
|
@@ -737,8 +759,8 @@ async function deleteSecret(id) {
|
|
|
737
759
|
}
|
|
738
760
|
});
|
|
739
761
|
consola.success("Secret deleted successfully");
|
|
740
|
-
} catch {
|
|
741
|
-
consola.error("Failed to delete secret");
|
|
762
|
+
} catch (error) {
|
|
763
|
+
consola.error("Failed to delete secret:", error);
|
|
742
764
|
}
|
|
743
765
|
}
|
|
744
766
|
|
|
@@ -756,7 +778,7 @@ async function listEnvs(sandbox) {
|
|
|
756
778
|
}
|
|
757
779
|
);
|
|
758
780
|
if (!data.sandbox) {
|
|
759
|
-
consola.error(`Sandbox not found: ${
|
|
781
|
+
consola.error(`Sandbox not found: ${c.primary(sandbox)}`);
|
|
760
782
|
process.exit(1);
|
|
761
783
|
}
|
|
762
784
|
const response = await client.get(
|
|
@@ -774,10 +796,10 @@ async function listEnvs(sandbox) {
|
|
|
774
796
|
);
|
|
775
797
|
const table = new Table({
|
|
776
798
|
head: [
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
799
|
+
c.primary("ID"),
|
|
800
|
+
c.primary("NAME"),
|
|
801
|
+
c.primary("VALUE"),
|
|
802
|
+
c.primary("CREATED AT")
|
|
781
803
|
],
|
|
782
804
|
chars: {
|
|
783
805
|
top: "",
|
|
@@ -803,8 +825,8 @@ async function listEnvs(sandbox) {
|
|
|
803
825
|
});
|
|
804
826
|
for (const variable of response.data.variables) {
|
|
805
827
|
table.push([
|
|
806
|
-
|
|
807
|
-
|
|
828
|
+
c.secondary(variable.id),
|
|
829
|
+
c.highlight(variable.name),
|
|
808
830
|
variable.value,
|
|
809
831
|
dayjs(variable.createdAt).fromNow()
|
|
810
832
|
]);
|
|
@@ -1100,7 +1122,7 @@ async function putAuthKey(sandbox) {
|
|
|
1100
1122
|
}
|
|
1101
1123
|
);
|
|
1102
1124
|
if (!data.sandbox) {
|
|
1103
|
-
consola.error(`Sandbox not found: ${
|
|
1125
|
+
consola.error(`Sandbox not found: ${c.primary(sandbox)}`);
|
|
1104
1126
|
process.exit(1);
|
|
1105
1127
|
}
|
|
1106
1128
|
const redacted = authKey.length > 14 ? authKey.slice(0, 11) + "*".repeat(authKey.length - 14) + authKey.slice(-3) : authKey;
|
|
@@ -1119,7 +1141,7 @@ async function putAuthKey(sandbox) {
|
|
|
1119
1141
|
);
|
|
1120
1142
|
consola.success(redacted);
|
|
1121
1143
|
consola.success(
|
|
1122
|
-
`Tailscale auth key saved for sandbox: ${
|
|
1144
|
+
`Tailscale auth key saved for sandbox: ${c.primary(sandbox)}`
|
|
1123
1145
|
);
|
|
1124
1146
|
}
|
|
1125
1147
|
async function getTailscaleAuthKey(sandbox) {
|
|
@@ -1136,7 +1158,7 @@ async function getTailscaleAuthKey(sandbox) {
|
|
|
1136
1158
|
}
|
|
1137
1159
|
);
|
|
1138
1160
|
if (!data.sandbox) {
|
|
1139
|
-
consola.error(`Sandbox not found: ${
|
|
1161
|
+
consola.error(`Sandbox not found: ${c.primary(sandbox)}`);
|
|
1140
1162
|
process.exit(1);
|
|
1141
1163
|
}
|
|
1142
1164
|
try {
|
|
@@ -1151,24 +1173,349 @@ async function getTailscaleAuthKey(sandbox) {
|
|
|
1151
1173
|
}
|
|
1152
1174
|
}
|
|
1153
1175
|
);
|
|
1154
|
-
consola.info(`Tailscale auth key: ${
|
|
1176
|
+
consola.info(`Tailscale auth key: ${c.primary(tailscale.authKey)}`);
|
|
1155
1177
|
} catch {
|
|
1156
1178
|
consola.error(
|
|
1157
|
-
`No Tailscale Auth Key found for sandbox: ${
|
|
1179
|
+
`No Tailscale Auth Key found for sandbox: ${c.primary(sandbox)}`
|
|
1158
1180
|
);
|
|
1159
1181
|
process.exit(1);
|
|
1160
1182
|
}
|
|
1161
1183
|
}
|
|
1162
1184
|
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1185
|
+
async function exposePort(sandbox, port, description) {
|
|
1186
|
+
const token = await getAccessToken();
|
|
1187
|
+
try {
|
|
1188
|
+
const response = await client.post(
|
|
1189
|
+
`/xrpc/io.pocketenv.sandbox.exposePort`,
|
|
1190
|
+
{ port, description },
|
|
1191
|
+
{
|
|
1192
|
+
params: {
|
|
1193
|
+
id: sandbox
|
|
1194
|
+
},
|
|
1195
|
+
headers: {
|
|
1196
|
+
Authorization: `Bearer ${env$1.POCKETENV_TOKEN || token}`
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
);
|
|
1200
|
+
consola.success(
|
|
1201
|
+
`Port ${c.primary(port)} exposed for sandbox ${c.primary(sandbox)}`
|
|
1202
|
+
);
|
|
1203
|
+
if (response.data.previewUrl) {
|
|
1204
|
+
consola.success(`Preview URL: ${c.secondary(response.data.previewUrl)}`);
|
|
1205
|
+
}
|
|
1206
|
+
} catch (error) {
|
|
1207
|
+
consola.error("Failed to expose port:", error);
|
|
1208
|
+
process.exit(1);
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
async function unexposePort(sandbox, port) {
|
|
1213
|
+
const token = await getAccessToken();
|
|
1214
|
+
try {
|
|
1215
|
+
await client.post(
|
|
1216
|
+
`/xrpc/io.pocketenv.sandbox.unexposePort`,
|
|
1217
|
+
{ port },
|
|
1218
|
+
{
|
|
1219
|
+
params: {
|
|
1220
|
+
id: sandbox
|
|
1221
|
+
},
|
|
1222
|
+
headers: {
|
|
1223
|
+
Authorization: `Bearer ${env$1.POCKETENV_TOKEN || token}`
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
);
|
|
1227
|
+
consola.success(
|
|
1228
|
+
`Port ${c.primary(port)} unexposed for sandbox ${c.primary(sandbox)}`
|
|
1229
|
+
);
|
|
1230
|
+
} catch (error) {
|
|
1231
|
+
consola.error(`Failed to unexpose port: ${error}`);
|
|
1232
|
+
process.exit(1);
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
dayjs.extend(relativeTime);
|
|
1237
|
+
async function listVolumes(sandboxId) {
|
|
1238
|
+
const token = await getAccessToken();
|
|
1239
|
+
const response = await client.get(
|
|
1240
|
+
"/xrpc/io.pocketenv.volume.getVolumes",
|
|
1241
|
+
{
|
|
1242
|
+
params: {
|
|
1243
|
+
sandboxId
|
|
1244
|
+
},
|
|
1245
|
+
headers: {
|
|
1246
|
+
Authorization: `Bearer ${env$1.POCKETENV_TOKEN || token}`
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
);
|
|
1250
|
+
const table = new Table({
|
|
1251
|
+
head: [
|
|
1252
|
+
c.primary("ID"),
|
|
1253
|
+
c.primary("NAME"),
|
|
1254
|
+
c.primary("PATH"),
|
|
1255
|
+
c.primary("CREATED AT")
|
|
1256
|
+
],
|
|
1257
|
+
chars: {
|
|
1258
|
+
top: "",
|
|
1259
|
+
"top-mid": "",
|
|
1260
|
+
"top-left": "",
|
|
1261
|
+
"top-right": "",
|
|
1262
|
+
bottom: "",
|
|
1263
|
+
"bottom-mid": "",
|
|
1264
|
+
"bottom-left": "",
|
|
1265
|
+
"bottom-right": "",
|
|
1266
|
+
left: "",
|
|
1267
|
+
"left-mid": "",
|
|
1268
|
+
mid: "",
|
|
1269
|
+
"mid-mid": "",
|
|
1270
|
+
right: "",
|
|
1271
|
+
"right-mid": "",
|
|
1272
|
+
middle: " "
|
|
1273
|
+
},
|
|
1274
|
+
style: {
|
|
1275
|
+
border: [],
|
|
1276
|
+
head: []
|
|
1277
|
+
}
|
|
1278
|
+
});
|
|
1279
|
+
for (const volume of response.data.volumes) {
|
|
1280
|
+
table.push([
|
|
1281
|
+
c.secondary(volume.id),
|
|
1282
|
+
volume.name,
|
|
1283
|
+
volume.path,
|
|
1284
|
+
dayjs(volume.createdAt).fromNow()
|
|
1285
|
+
]);
|
|
1286
|
+
}
|
|
1287
|
+
consola.log(table.toString());
|
|
1288
|
+
}
|
|
1289
|
+
async function createVolume(sandbox, name, path) {
|
|
1290
|
+
const token = await getAccessToken();
|
|
1291
|
+
try {
|
|
1292
|
+
await client.post(
|
|
1293
|
+
"/xrpc/io.pocketenv.volume.addVolume",
|
|
1294
|
+
{
|
|
1295
|
+
volume: {
|
|
1296
|
+
sandboxId: sandbox,
|
|
1297
|
+
name,
|
|
1298
|
+
path
|
|
1299
|
+
}
|
|
1300
|
+
},
|
|
1301
|
+
{
|
|
1302
|
+
headers: {
|
|
1303
|
+
Authorization: `Bearer ${env$1.POCKETENV_TOKEN || token}`
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
);
|
|
1307
|
+
consola.success(
|
|
1308
|
+
`Volume ${chalk.rgb(0, 232, 198)(name)} successfully mounted in sandbox ${chalk.rgb(0, 232, 198)(sandbox)} at path ${chalk.rgb(0, 232, 198)(path)}`
|
|
1309
|
+
);
|
|
1310
|
+
} catch (error) {
|
|
1311
|
+
consola.error("Failed to create volume:", error);
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
async function deleteVolume(id) {
|
|
1315
|
+
const token = await getAccessToken();
|
|
1316
|
+
try {
|
|
1317
|
+
await client.post(`/xrpc/io.pocketenv.volume.deleteVolume`, void 0, {
|
|
1318
|
+
params: {
|
|
1319
|
+
id
|
|
1320
|
+
},
|
|
1321
|
+
headers: {
|
|
1322
|
+
Authorization: `Bearer ${env$1.POCKETENV_TOKEN || token}`
|
|
1323
|
+
}
|
|
1324
|
+
});
|
|
1325
|
+
} catch (error) {
|
|
1326
|
+
consola.error(`Failed to delete volume: ${error}`);
|
|
1327
|
+
return;
|
|
1328
|
+
}
|
|
1329
|
+
consola.success(
|
|
1330
|
+
`Volume ${chalk.rgb(0, 232, 198)(id)} successfully deleted from sandbox`
|
|
1331
|
+
);
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
dayjs.extend(relativeTime);
|
|
1335
|
+
async function putFile(sandbox, remotePath, localPath) {
|
|
1336
|
+
const token = await getAccessToken();
|
|
1337
|
+
let content;
|
|
1338
|
+
if (!process.stdin.isTTY) {
|
|
1339
|
+
const chunks = [];
|
|
1340
|
+
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
1341
|
+
content = Buffer.concat(chunks).toString().trim();
|
|
1342
|
+
} else if (localPath) {
|
|
1343
|
+
const resolvedPath = path.resolve(localPath);
|
|
1344
|
+
try {
|
|
1345
|
+
await fs.access(resolvedPath);
|
|
1346
|
+
} catch (err) {
|
|
1347
|
+
consola.error(`No such file: ${c.error(localPath)}`);
|
|
1348
|
+
process.exit(1);
|
|
1349
|
+
}
|
|
1350
|
+
content = await fs.readFile(resolvedPath, "utf-8");
|
|
1351
|
+
} else {
|
|
1352
|
+
content = (await editor({
|
|
1353
|
+
message: "File content (opens in $EDITOR):",
|
|
1354
|
+
waitForUserInput: false
|
|
1355
|
+
})).trim();
|
|
1356
|
+
}
|
|
1357
|
+
try {
|
|
1358
|
+
await client.post(
|
|
1359
|
+
"/xrpc/io.pocketenv.file.addFile",
|
|
1360
|
+
{
|
|
1361
|
+
file: {
|
|
1362
|
+
sandboxId: sandbox,
|
|
1363
|
+
path: remotePath,
|
|
1364
|
+
content: await encrypt(content)
|
|
1365
|
+
}
|
|
1366
|
+
},
|
|
1367
|
+
{
|
|
1368
|
+
headers: {
|
|
1369
|
+
Authorization: `Bearer ${env$1.POCKETENV_TOKEN || token}`
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
);
|
|
1373
|
+
consola.success(
|
|
1374
|
+
`File ${c.primary(remotePath)} successfully created in sandbox ${c.primary(sandbox)}`
|
|
1375
|
+
);
|
|
1376
|
+
} catch (error) {
|
|
1377
|
+
consola.error(`Failed to create file: ${error}`);
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
async function listFiles(sandboxId) {
|
|
1381
|
+
const token = await getAccessToken();
|
|
1382
|
+
const response = await client.get(
|
|
1383
|
+
"/xrpc/io.pocketenv.file.getFiles",
|
|
1384
|
+
{
|
|
1385
|
+
params: {
|
|
1386
|
+
sandboxId
|
|
1387
|
+
},
|
|
1388
|
+
headers: {
|
|
1389
|
+
Authorization: `Bearer ${env$1.POCKETENV_TOKEN || token}`
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
);
|
|
1393
|
+
const table = new Table({
|
|
1394
|
+
head: [c.primary("ID"), c.primary("PATH"), c.primary("CREATED AT")],
|
|
1395
|
+
chars: {
|
|
1396
|
+
top: "",
|
|
1397
|
+
"top-mid": "",
|
|
1398
|
+
"top-left": "",
|
|
1399
|
+
"top-right": "",
|
|
1400
|
+
bottom: "",
|
|
1401
|
+
"bottom-mid": "",
|
|
1402
|
+
"bottom-left": "",
|
|
1403
|
+
"bottom-right": "",
|
|
1404
|
+
left: "",
|
|
1405
|
+
"left-mid": "",
|
|
1406
|
+
mid: "",
|
|
1407
|
+
"mid-mid": "",
|
|
1408
|
+
right: "",
|
|
1409
|
+
"right-mid": "",
|
|
1410
|
+
middle: " "
|
|
1411
|
+
},
|
|
1412
|
+
style: {
|
|
1413
|
+
border: [],
|
|
1414
|
+
head: []
|
|
1415
|
+
}
|
|
1416
|
+
});
|
|
1417
|
+
for (const file of response.data.files) {
|
|
1418
|
+
table.push([
|
|
1419
|
+
c.secondary(file.id),
|
|
1420
|
+
file.path,
|
|
1421
|
+
dayjs(file.createdAt).fromNow()
|
|
1422
|
+
]);
|
|
1423
|
+
}
|
|
1424
|
+
consola.log(table.toString());
|
|
1425
|
+
}
|
|
1426
|
+
async function deleteFile(id) {
|
|
1427
|
+
const token = await getAccessToken();
|
|
1428
|
+
try {
|
|
1429
|
+
await client.post(`/xrpc/io.pocketenv.file.deleteFile`, void 0, {
|
|
1430
|
+
params: {
|
|
1431
|
+
id
|
|
1432
|
+
},
|
|
1433
|
+
headers: {
|
|
1434
|
+
Authorization: `Bearer ${env$1.POCKETENV_TOKEN || token}`
|
|
1435
|
+
}
|
|
1436
|
+
});
|
|
1437
|
+
consola.success(`File ${c.primary(id)} successfully deleted from sandbox`);
|
|
1438
|
+
} catch (error) {
|
|
1439
|
+
consola.error(`Failed to delete file: ${error}`);
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
async function listPorts(sandbox) {
|
|
1444
|
+
const token = await getAccessToken();
|
|
1445
|
+
const response = await client.get(
|
|
1446
|
+
"/xrpc/io.pocketenv.sandbox.getExposedPorts",
|
|
1447
|
+
{
|
|
1448
|
+
params: {
|
|
1449
|
+
id: sandbox
|
|
1450
|
+
},
|
|
1451
|
+
headers: {
|
|
1452
|
+
Authorization: `Bearer ${env$1.POCKETENV_TOKEN || token}`
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
);
|
|
1456
|
+
const table = new Table({
|
|
1457
|
+
head: [
|
|
1458
|
+
c.primary("PORT"),
|
|
1459
|
+
c.primary("DESCRIPTION"),
|
|
1460
|
+
c.primary("PREVIEW URL")
|
|
1461
|
+
],
|
|
1462
|
+
chars: {
|
|
1463
|
+
top: "",
|
|
1464
|
+
"top-mid": "",
|
|
1465
|
+
"top-left": "",
|
|
1466
|
+
"top-right": "",
|
|
1467
|
+
bottom: "",
|
|
1468
|
+
"bottom-mid": "",
|
|
1469
|
+
"bottom-left": "",
|
|
1470
|
+
"bottom-right": "",
|
|
1471
|
+
left: "",
|
|
1472
|
+
"left-mid": "",
|
|
1473
|
+
mid: "",
|
|
1474
|
+
"mid-mid": "",
|
|
1475
|
+
right: "",
|
|
1476
|
+
"right-mid": "",
|
|
1477
|
+
middle: " "
|
|
1478
|
+
},
|
|
1479
|
+
style: {
|
|
1480
|
+
border: [],
|
|
1481
|
+
head: []
|
|
1482
|
+
}
|
|
1483
|
+
});
|
|
1484
|
+
for (const port of response.data.ports) {
|
|
1485
|
+
table.push([
|
|
1486
|
+
c.secondary(port.port),
|
|
1487
|
+
port.description || "-",
|
|
1488
|
+
c.link(port.previewUrl || "-")
|
|
1489
|
+
]);
|
|
1490
|
+
}
|
|
1491
|
+
consola.log(table.toString());
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
async function exposeVscode(sandbox) {
|
|
1495
|
+
const token = await getAccessToken();
|
|
1496
|
+
try {
|
|
1497
|
+
const response = await client.post(
|
|
1498
|
+
`/xrpc/io.pocketenv.sandbox.exposeVscode`,
|
|
1499
|
+
void 0,
|
|
1500
|
+
{
|
|
1501
|
+
params: {
|
|
1502
|
+
id: sandbox
|
|
1503
|
+
},
|
|
1504
|
+
headers: {
|
|
1505
|
+
Authorization: `Bearer ${env$1.POCKETENV_TOKEN || token}`
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
);
|
|
1509
|
+
consola.success(`VS Code Server exposed for sandbox ${c.primary(sandbox)}`);
|
|
1510
|
+
if (response.data.previewUrl) {
|
|
1511
|
+
consola.success(`Preview URL: ${c.secondary(response.data.previewUrl)}`);
|
|
1512
|
+
}
|
|
1513
|
+
} catch (error) {
|
|
1514
|
+
consola.error("Failed to expose VS Code:", error);
|
|
1515
|
+
process.exit(1);
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1172
1519
|
const program = new Command();
|
|
1173
1520
|
program.name("pocketenv").description(
|
|
1174
1521
|
`${chalk.bold.rgb(0, 232, 198)(`pocketenv v${version}`)} ${c.muted("\u2500")} ${c.muted("Open, interoperable sandbox platform for agents and humans")}`
|
|
@@ -1203,6 +1550,34 @@ program.command("create").aliases(["new"]).option("--provider, -p <provider>", "
|
|
|
1203
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);
|
|
1204
1551
|
program.command("logout").description("logout (removes session token)").action(logout);
|
|
1205
1552
|
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);
|
|
1556
|
+
program.command("expose").argument("<sandbox>", "the sandbox to expose a port for").argument("<port>", "the port to expose", (val) => {
|
|
1557
|
+
const port = parseInt(val, 10);
|
|
1558
|
+
if (isNaN(port)) {
|
|
1559
|
+
consola.error(`port must be a number, got: ${val}`);
|
|
1560
|
+
process.exit(1);
|
|
1561
|
+
}
|
|
1562
|
+
return port;
|
|
1563
|
+
}).argument("[description]", "an optional description for the exposed port").description("expose a port from the given sandbox to the internet").action(exposePort);
|
|
1564
|
+
program.command("unexpose").argument("<sandbox>", "the sandbox to unexpose a port for").argument("<port>", "the port to unexpose", (val) => {
|
|
1565
|
+
const port = parseInt(val, 10);
|
|
1566
|
+
if (isNaN(port)) {
|
|
1567
|
+
consola.error(`port must be a number, got: ${val}`);
|
|
1568
|
+
process.exit(1);
|
|
1569
|
+
}
|
|
1570
|
+
return port;
|
|
1571
|
+
}).description("unexpose a port from the given sandbox").action(unexposePort);
|
|
1572
|
+
const volume = program.command("volume").description("manage volumes");
|
|
1573
|
+
volume.command("put").argument("<sandbox>", "the sandbox to put the volume in").argument("<name>", "the name of the volume").argument("<path>", "the path to mount the volume at").description("put a volume in the given sandbox").action(createVolume);
|
|
1574
|
+
volume.command("list").aliases(["ls"]).argument("<sandbox>", "the sandbox to list volumes for").description("list volumes in the given sandbox").action(listVolumes);
|
|
1575
|
+
volume.command("delete").aliases(["rm", "remove"]).argument("<id>", "the ID of the volume to delete").description("delete a volume").action(deleteVolume);
|
|
1576
|
+
const file = program.command("file").description("manage files");
|
|
1577
|
+
file.command("put").argument("<sandbox>", "the sandbox to put the file in").argument("<path>", "the remote path to upload the file to").argument("[localPath]", "the local path of the file to upload").description("upload a file to the given sandbox").action(putFile);
|
|
1578
|
+
file.command("list").aliases(["ls"]).argument("<sandbox>", "the sandbox to list files for").description("list files in the given sandbox").action(listFiles);
|
|
1579
|
+
file.command("delete").aliases(["rm", "remove"]).argument("<id>", "the ID of the file to delete").description("delete a file").action(deleteFile);
|
|
1580
|
+
program.command("ports").argument("<sandbox>", "the sandbox to list exposed ports for").description("list exposed ports for a sandbox").action(listPorts);
|
|
1206
1581
|
const secret = program.command("secret").description("manage secrets");
|
|
1207
1582
|
secret.command("put").argument("<sandbox>", "the sandbox to put the secret in").argument("<key>", "the key of the secret").description("put a secret in the given sandbox").action(putSecret);
|
|
1208
1583
|
secret.command("list").aliases(["ls"]).argument("<sandbox>", "the sandbox to list secrets for").description("list secrets in the given sandbox").action(listSecrets);
|
package/package.json
CHANGED
package/src/cmd/create.ts
CHANGED
|
@@ -2,8 +2,8 @@ import consola from "consola";
|
|
|
2
2
|
import { client } from "../client";
|
|
3
3
|
import getAccessToken from "../lib/getAccessToken";
|
|
4
4
|
import type { Sandbox } from "../types/sandbox";
|
|
5
|
-
import chalk from "chalk";
|
|
6
5
|
import connectToSandbox from "./ssh";
|
|
6
|
+
import { c } from "../theme";
|
|
7
7
|
|
|
8
8
|
async function createSandbox(
|
|
9
9
|
name: string,
|
|
@@ -21,7 +21,7 @@ async function createSandbox(
|
|
|
21
21
|
|
|
22
22
|
if (["deno", "vercel", "daytona"].includes(provider || "")) {
|
|
23
23
|
consola.error(
|
|
24
|
-
`This Sandbox Runtime is temporarily disabled. ${
|
|
24
|
+
`This Sandbox Runtime is temporarily disabled. ${c.primary(provider ?? "")}`,
|
|
25
25
|
);
|
|
26
26
|
process.exit(1);
|
|
27
27
|
}
|
|
@@ -43,7 +43,7 @@ async function createSandbox(
|
|
|
43
43
|
);
|
|
44
44
|
if (!ssh) {
|
|
45
45
|
consola.success(
|
|
46
|
-
`Sandbox created successfully: ${
|
|
46
|
+
`Sandbox created successfully: ${c.primary(sandbox.data.name)}`,
|
|
47
47
|
);
|
|
48
48
|
return;
|
|
49
49
|
}
|
package/src/cmd/env.ts
CHANGED
|
@@ -2,11 +2,11 @@ import { client } from "../client";
|
|
|
2
2
|
import getAccessToken from "../lib/getAccessToken";
|
|
3
3
|
import type { Sandbox } from "../types/sandbox";
|
|
4
4
|
import type { Variable } from "../types/variable";
|
|
5
|
-
import chalk from "chalk";
|
|
6
5
|
import dayjs from "dayjs";
|
|
7
6
|
import consola from "consola";
|
|
8
7
|
import Table from "cli-table3";
|
|
9
8
|
import { env } from "../lib/env";
|
|
9
|
+
import { c } from "../theme";
|
|
10
10
|
|
|
11
11
|
export async function listEnvs(sandbox: string) {
|
|
12
12
|
const token = await getAccessToken();
|
|
@@ -23,7 +23,7 @@ export async function listEnvs(sandbox: string) {
|
|
|
23
23
|
);
|
|
24
24
|
|
|
25
25
|
if (!data.sandbox) {
|
|
26
|
-
consola.error(`Sandbox not found: ${
|
|
26
|
+
consola.error(`Sandbox not found: ${c.primary(sandbox)}`);
|
|
27
27
|
process.exit(1);
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -43,10 +43,10 @@ export async function listEnvs(sandbox: string) {
|
|
|
43
43
|
|
|
44
44
|
const table = new Table({
|
|
45
45
|
head: [
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
c.primary("ID"),
|
|
47
|
+
c.primary("NAME"),
|
|
48
|
+
c.primary("VALUE"),
|
|
49
|
+
c.primary("CREATED AT"),
|
|
50
50
|
],
|
|
51
51
|
chars: {
|
|
52
52
|
top: "",
|
|
@@ -73,8 +73,8 @@ export async function listEnvs(sandbox: string) {
|
|
|
73
73
|
|
|
74
74
|
for (const variable of response.data.variables) {
|
|
75
75
|
table.push([
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
c.secondary(variable.id),
|
|
77
|
+
c.highlight(variable.name),
|
|
78
78
|
variable.value,
|
|
79
79
|
dayjs(variable.createdAt).fromNow(),
|
|
80
80
|
]);
|