@madarco/agentbox 0.9.0 → 0.10.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/CHANGELOG.md +89 -0
- package/README.md +161 -0
- package/dist/{_cloud-attach-ZXBCNWJX.js → _cloud-attach-O6NYTLES.js} +3 -3
- package/dist/{chunk-BXQMIEHC.js → chunk-2GPORKYF.js} +254 -162
- package/dist/chunk-2GPORKYF.js.map +1 -0
- package/dist/{chunk-NCJP5MTN.js → chunk-7UIAO7PC.js} +213 -51
- package/dist/chunk-7UIAO7PC.js.map +1 -0
- package/dist/{chunk-GU5LW4B5.js → chunk-R4O5WPHW.js} +374 -62
- package/dist/chunk-R4O5WPHW.js.map +1 -0
- package/dist/{dist-GDHP34ZK.js → dist-5FQGYRW5.js} +15 -3
- package/dist/dist-5FQGYRW5.js.map +1 -0
- package/dist/{dist-32EZBYG4.js → dist-BQNX7RQE.js} +12 -2
- package/dist/{dist-XML54CNB.js → dist-PZW3GWWU.js} +30 -5
- package/dist/dist-PZW3GWWU.js.map +1 -0
- package/dist/{dist-CX5CGVEB.js → dist-TMHSUVTP.js} +3 -3
- package/dist/index.js +1773 -526
- package/dist/index.js.map +1 -1
- package/package.json +9 -7
- package/runtime/docker/apps/cli/share/agentbox-setup/SKILL.md +9 -8
- package/runtime/docker/packages/ctl/dist/bin.cjs +32 -3
- package/runtime/hetzner/agentbox-setup-skill.md +9 -8
- package/runtime/hetzner/ctl.cjs +32 -3
- package/runtime/relay/bin.cjs +32 -3
- package/runtime/vercel/agentbox-setup-skill.md +9 -8
- package/runtime/vercel/ctl.cjs +32 -3
- package/runtime/vercel/custom-system-CLAUDE.md +1 -4
- package/runtime/vercel/scripts/provision.sh +40 -0
- package/share/agentbox-setup/SKILL.md +9 -8
- package/dist/chunk-BXQMIEHC.js.map +0 -1
- package/dist/chunk-GU5LW4B5.js.map +0 -1
- package/dist/chunk-NCJP5MTN.js.map +0 -1
- package/dist/dist-GDHP34ZK.js.map +0 -1
- package/dist/dist-XML54CNB.js.map +0 -1
- /package/dist/{_cloud-attach-ZXBCNWJX.js.map → _cloud-attach-O6NYTLES.js.map} +0 -0
- /package/dist/{dist-32EZBYG4.js.map → dist-BQNX7RQE.js.map} +0 -0
- /package/dist/{dist-CX5CGVEB.js.map → dist-TMHSUVTP.js.map} +0 -0
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
stageOpencodeCredentialsForUpload,
|
|
28
28
|
stageOpencodeStateForUpload,
|
|
29
29
|
stageOpencodeStaticForUpload
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-7UIAO7PC.js";
|
|
31
31
|
import {
|
|
32
32
|
allocateProjectIndex,
|
|
33
33
|
detectGitRepos,
|
|
@@ -334,6 +334,27 @@ async function removeCloudCheckpointDir(projectRoot, backend, name) {
|
|
|
334
334
|
await rm(dir, { recursive: true, force: true });
|
|
335
335
|
return true;
|
|
336
336
|
}
|
|
337
|
+
async function probeCloudCheckpoint(backend, projectRoot, ref) {
|
|
338
|
+
const found = await resolveCloudCheckpoint(projectRoot, backend.name, ref);
|
|
339
|
+
if (!found) return { live: false, pruned: false };
|
|
340
|
+
if (!backend.snapshotExists) return { live: true, pruned: false };
|
|
341
|
+
const live = await backend.snapshotExists(found.manifest.snapshotName);
|
|
342
|
+
if (live) return { live: true, pruned: false };
|
|
343
|
+
await removeCloudCheckpointDir(projectRoot, backend.name, ref);
|
|
344
|
+
return { live: false, pruned: true };
|
|
345
|
+
}
|
|
346
|
+
function isSnapshotGoneError(err) {
|
|
347
|
+
if (err === null || typeof err !== "object") return false;
|
|
348
|
+
const e = err;
|
|
349
|
+
const status = e.response?.status ?? e.status;
|
|
350
|
+
if (status === 410) return true;
|
|
351
|
+
const parts = [
|
|
352
|
+
typeof e.json?.error?.message === "string" ? e.json.error.message : "",
|
|
353
|
+
typeof e.message === "string" ? e.message : ""
|
|
354
|
+
];
|
|
355
|
+
const msg = parts.join(" ").toLowerCase();
|
|
356
|
+
return /snapshot[^.]*\b(expired|deleted|gone|not[ -]?found)\b/.test(msg) || msg.includes("expired or deleted");
|
|
357
|
+
}
|
|
337
358
|
var WORKSPACE_DIR_DEFAULT = "/workspace";
|
|
338
359
|
var REMOTE_TAR_PATH = "/tmp/agentbox-envfiles.tar";
|
|
339
360
|
async function uploadEnvFiles(args) {
|
|
@@ -642,6 +663,8 @@ async function launchCloudCtlDaemon(args) {
|
|
|
642
663
|
if (args.relayUrl) env.push(`AGENTBOX_RELAY_URL=${quoteShellArgv([args.relayUrl])}`);
|
|
643
664
|
if (args.relayToken) env.push(`AGENTBOX_RELAY_TOKEN=${quoteShellArgv([args.relayToken])}`);
|
|
644
665
|
if (args.bridgeToken) env.push(`AGENTBOX_BRIDGE_TOKEN=${quoteShellArgv([args.bridgeToken])}`);
|
|
666
|
+
if (args.webProxyPort !== void 0)
|
|
667
|
+
env.push(`AGENTBOX_WEB_PROXY_PORT=${quoteShellArgv([String(args.webProxyPort)])}`);
|
|
645
668
|
const script = [
|
|
646
669
|
`set -e`,
|
|
647
670
|
`if command -v sudo >/dev/null 2>&1; then SUDO='sudo -n'; else SUDO=''; fi`,
|
|
@@ -1048,6 +1071,141 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
1048
1071
|
return "missing";
|
|
1049
1072
|
}
|
|
1050
1073
|
}
|
|
1074
|
+
async function persistLastState(box, lastState) {
|
|
1075
|
+
if (!box.cloud) return;
|
|
1076
|
+
try {
|
|
1077
|
+
await recordBox({ ...box, cloud: { ...box.cloud, lastState } });
|
|
1078
|
+
} catch {
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
async function reEnsureCloudBox(box, h) {
|
|
1082
|
+
const webPort = box.cloud?.webPort ?? backend.webProxyPort ?? CLOUD_WEB_PROXY_PORT;
|
|
1083
|
+
let webPreview;
|
|
1084
|
+
try {
|
|
1085
|
+
webPreview = await backend.previewUrl(h, webPort);
|
|
1086
|
+
} catch {
|
|
1087
|
+
const cached = box.cloud?.previewUrls?.[webPort];
|
|
1088
|
+
webPreview = cached ? { url: cached } : void 0;
|
|
1089
|
+
}
|
|
1090
|
+
const servicePreviews = {};
|
|
1091
|
+
try {
|
|
1092
|
+
const ports = await readExposedServicePorts(box.workspacePath);
|
|
1093
|
+
for (const port of ports) {
|
|
1094
|
+
if (port === webPort) continue;
|
|
1095
|
+
try {
|
|
1096
|
+
const p = await backend.previewUrl(h, port);
|
|
1097
|
+
servicePreviews[port] = p.url;
|
|
1098
|
+
} catch {
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
} catch {
|
|
1102
|
+
}
|
|
1103
|
+
let relayPreview;
|
|
1104
|
+
try {
|
|
1105
|
+
relayPreview = await backend.previewUrl(h, 8788);
|
|
1106
|
+
} catch {
|
|
1107
|
+
relayPreview = box.cloud?.relayPreviewUrl ? { url: box.cloud.relayPreviewUrl, token: box.cloud.relayPreviewToken } : void 0;
|
|
1108
|
+
}
|
|
1109
|
+
const mergedPreviews = {
|
|
1110
|
+
...box.cloud?.previewUrls ?? {},
|
|
1111
|
+
...servicePreviews
|
|
1112
|
+
};
|
|
1113
|
+
if (webPreview !== void 0) mergedPreviews[webPort] = webPreview.url;
|
|
1114
|
+
let portlessAliasName = box.portlessAlias;
|
|
1115
|
+
let portlessUrlResolved = box.portlessUrl;
|
|
1116
|
+
if (box.portlessAlias && webPreview) {
|
|
1117
|
+
const r = await bootstrapPortlessForCloudBox(backend, h, {
|
|
1118
|
+
boxName: box.name,
|
|
1119
|
+
webPreviewUrl: webPreview.url,
|
|
1120
|
+
webPort,
|
|
1121
|
+
onLog: () => {
|
|
1122
|
+
}
|
|
1123
|
+
});
|
|
1124
|
+
if (r) {
|
|
1125
|
+
portlessAliasName = r.alias;
|
|
1126
|
+
portlessUrlResolved = r.url;
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
let portlessVncAliasName = box.portlessVncAlias;
|
|
1130
|
+
let portlessVncUrlResolved = box.portlessVncUrl;
|
|
1131
|
+
if (box.portlessVncAlias && box.vncEnabled) {
|
|
1132
|
+
try {
|
|
1133
|
+
const vncPreview = await backend.previewUrl(h, CLOUD_VNC_PORT);
|
|
1134
|
+
const url = await registerHostPortlessAlias({
|
|
1135
|
+
alias: box.portlessVncAlias,
|
|
1136
|
+
previewUrl: vncPreview.url,
|
|
1137
|
+
label: "vnc",
|
|
1138
|
+
onLog: () => {
|
|
1139
|
+
}
|
|
1140
|
+
});
|
|
1141
|
+
if (url) {
|
|
1142
|
+
portlessVncAliasName = box.portlessVncAlias;
|
|
1143
|
+
portlessVncUrlResolved = url;
|
|
1144
|
+
}
|
|
1145
|
+
} catch {
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
const next = {
|
|
1149
|
+
...box,
|
|
1150
|
+
portlessAlias: portlessAliasName,
|
|
1151
|
+
portlessUrl: portlessUrlResolved,
|
|
1152
|
+
portlessVncAlias: portlessVncAliasName,
|
|
1153
|
+
portlessVncUrl: portlessVncUrlResolved,
|
|
1154
|
+
cloud: {
|
|
1155
|
+
...box.cloud ?? { backend: providerName, sandboxId: h.sandboxId },
|
|
1156
|
+
webPort,
|
|
1157
|
+
previewUrls: Object.keys(mergedPreviews).length > 0 ? mergedPreviews : void 0,
|
|
1158
|
+
relayPreviewUrl: relayPreview?.url ?? box.cloud?.relayPreviewUrl,
|
|
1159
|
+
relayPreviewToken: relayPreview?.token ?? box.cloud?.relayPreviewToken,
|
|
1160
|
+
// reEnsureCloudBox only runs on a freshly-woken box (start/resume), so
|
|
1161
|
+
// the box is now running — persist it for the fast `agentbox list` path.
|
|
1162
|
+
lastState: "running"
|
|
1163
|
+
}
|
|
1164
|
+
};
|
|
1165
|
+
await recordBox(next);
|
|
1166
|
+
await launchCloudCtlDaemon({
|
|
1167
|
+
backend,
|
|
1168
|
+
handle: h,
|
|
1169
|
+
boxId: box.id,
|
|
1170
|
+
boxName: box.name,
|
|
1171
|
+
relayUrl: `http://127.0.0.1:${String(8788)}`,
|
|
1172
|
+
relayToken: box.relayToken ?? "",
|
|
1173
|
+
bridgeToken: box.cloud?.bridgeToken,
|
|
1174
|
+
webProxyPort: backend.webProxyPort
|
|
1175
|
+
});
|
|
1176
|
+
if (opts.launchDockerd !== false) {
|
|
1177
|
+
try {
|
|
1178
|
+
const dockerd = await launchCloudDockerdDaemon({ backend, handle: h, timeoutMs: 6e4 });
|
|
1179
|
+
if (!dockerd.up) {
|
|
1180
|
+
}
|
|
1181
|
+
} catch {
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
if (box.vncEnabled && box.vncPassword) {
|
|
1185
|
+
try {
|
|
1186
|
+
await launchCloudVncDaemon({ backend, handle: h, vncPassword: box.vncPassword });
|
|
1187
|
+
} catch {
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
if (relayPreview && box.relayToken && box.cloud?.bridgeToken) {
|
|
1191
|
+
try {
|
|
1192
|
+
await registerBoxWithRelay({
|
|
1193
|
+
boxId: box.id,
|
|
1194
|
+
token: box.relayToken,
|
|
1195
|
+
name: box.name,
|
|
1196
|
+
kind: "cloud",
|
|
1197
|
+
backend: backend.name,
|
|
1198
|
+
previewUrl: relayPreview.url,
|
|
1199
|
+
previewToken: relayPreview.token,
|
|
1200
|
+
bridgeToken: box.cloud.bridgeToken,
|
|
1201
|
+
createdAt: box.createdAt,
|
|
1202
|
+
projectIndex: box.projectIndex
|
|
1203
|
+
});
|
|
1204
|
+
} catch {
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
return next;
|
|
1208
|
+
}
|
|
1051
1209
|
return {
|
|
1052
1210
|
name: providerName,
|
|
1053
1211
|
async create(req) {
|
|
@@ -1085,32 +1243,56 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
1085
1243
|
}
|
|
1086
1244
|
const agentVolumes = await ensureAgentVolumesForCloud(backend, { onLog: log });
|
|
1087
1245
|
const exposeServicePorts = await readExposedServicePorts(req.workspacePath);
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1246
|
+
const provisionEnv = {
|
|
1247
|
+
AGENTBOX_BOX_ID: id,
|
|
1248
|
+
AGENTBOX_BOX_NAME: name,
|
|
1249
|
+
AGENTBOX_BOX_KIND: "cloud",
|
|
1250
|
+
// In-sandbox relay is on the box's loopback at the in-box port.
|
|
1251
|
+
// 8788 is distinct from the host relay's 8787 so a nested agentbox
|
|
1252
|
+
// run inside the box can claim :8787 without colliding.
|
|
1253
|
+
AGENTBOX_RELAY_URL: `http://127.0.0.1:${String(8788)}`,
|
|
1254
|
+
AGENTBOX_RELAY_TOKEN: relayToken,
|
|
1255
|
+
AGENTBOX_BRIDGE_TOKEN: bridgeToken,
|
|
1256
|
+
...agentVolumes.env
|
|
1257
|
+
};
|
|
1258
|
+
const provisionFrom = async (snapshot) => {
|
|
1259
|
+
log(
|
|
1260
|
+
snapshot ? `provisioning ${providerName} sandbox from snapshot` : `provisioning ${providerName} sandbox`
|
|
1261
|
+
);
|
|
1262
|
+
return backend.provision({
|
|
1263
|
+
name,
|
|
1264
|
+
image,
|
|
1265
|
+
snapshot,
|
|
1266
|
+
resources,
|
|
1267
|
+
timeoutMs,
|
|
1268
|
+
exposePorts: exposeServicePorts,
|
|
1269
|
+
networkPolicy,
|
|
1270
|
+
env: provisionEnv,
|
|
1271
|
+
volumes: agentVolumes.mounts,
|
|
1272
|
+
onLog: log
|
|
1273
|
+
});
|
|
1274
|
+
};
|
|
1275
|
+
let handle;
|
|
1276
|
+
try {
|
|
1277
|
+
handle = await provisionFrom(snapshotName);
|
|
1278
|
+
} catch (err) {
|
|
1279
|
+
if (snapshotName && isSnapshotGoneError(err)) {
|
|
1280
|
+
log(
|
|
1281
|
+
`checkpoint snapshot '${resolvedCheckpointRef ?? snapshotName}' has expired or been deleted; starting a fresh box from the base image instead`
|
|
1282
|
+
);
|
|
1283
|
+
if (req.projectRoot && resolvedCheckpointRef) {
|
|
1284
|
+
try {
|
|
1285
|
+
await removeCloudCheckpointDir(req.projectRoot, backend.name, resolvedCheckpointRef);
|
|
1286
|
+
} catch {
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
snapshotName = void 0;
|
|
1290
|
+
resolvedCheckpointRef = void 0;
|
|
1291
|
+
handle = await provisionFrom(void 0);
|
|
1292
|
+
} else {
|
|
1293
|
+
throw err;
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1114
1296
|
try {
|
|
1115
1297
|
if (snapshotName) {
|
|
1116
1298
|
log("skipping workspace seed \u2014 snapshot already contains /workspace");
|
|
@@ -1169,7 +1351,8 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
1169
1351
|
boxName: name,
|
|
1170
1352
|
relayUrl: `http://127.0.0.1:${String(8788)}`,
|
|
1171
1353
|
relayToken,
|
|
1172
|
-
bridgeToken
|
|
1354
|
+
bridgeToken,
|
|
1355
|
+
webProxyPort: backend.webProxyPort
|
|
1173
1356
|
});
|
|
1174
1357
|
if (opts.launchDockerd !== false) {
|
|
1175
1358
|
log("launching in-box dockerd");
|
|
@@ -1192,9 +1375,10 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
1192
1375
|
);
|
|
1193
1376
|
}
|
|
1194
1377
|
}
|
|
1378
|
+
const wp = backend.webProxyPort ?? CLOUD_WEB_PROXY_PORT;
|
|
1195
1379
|
let webPreview;
|
|
1196
1380
|
try {
|
|
1197
|
-
webPreview = await backend.previewUrl(handle,
|
|
1381
|
+
webPreview = await backend.previewUrl(handle, wp);
|
|
1198
1382
|
} catch {
|
|
1199
1383
|
webPreview = void 0;
|
|
1200
1384
|
}
|
|
@@ -1205,7 +1389,7 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
1205
1389
|
const r = await bootstrapPortlessForCloudBox(backend, handle, {
|
|
1206
1390
|
boxName: name,
|
|
1207
1391
|
webPreviewUrl: webPreview.url,
|
|
1208
|
-
webPort:
|
|
1392
|
+
webPort: wp,
|
|
1209
1393
|
onLog: log
|
|
1210
1394
|
});
|
|
1211
1395
|
if (r) {
|
|
@@ -1239,7 +1423,7 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
1239
1423
|
const servicePorts = exposeServicePorts;
|
|
1240
1424
|
const servicePreviews = {};
|
|
1241
1425
|
for (const port of servicePorts) {
|
|
1242
|
-
if (port ===
|
|
1426
|
+
if (port === wp) continue;
|
|
1243
1427
|
try {
|
|
1244
1428
|
const p = await backend.previewUrl(handle, port);
|
|
1245
1429
|
servicePreviews[port] = p.url;
|
|
@@ -1310,16 +1494,17 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
1310
1494
|
backend: backend.name,
|
|
1311
1495
|
sandboxId: handle.sandboxId,
|
|
1312
1496
|
image,
|
|
1313
|
-
webPort:
|
|
1497
|
+
webPort: wp,
|
|
1314
1498
|
previewUrls: (() => {
|
|
1315
1499
|
const m = { ...servicePreviews };
|
|
1316
|
-
if (webPreview) m[
|
|
1500
|
+
if (webPreview) m[wp] = webPreview.url;
|
|
1317
1501
|
return Object.keys(m).length > 0 ? m : void 0;
|
|
1318
1502
|
})(),
|
|
1319
1503
|
relayPreviewUrl: relayPreview?.url,
|
|
1320
1504
|
relayPreviewToken: relayPreview?.token,
|
|
1321
1505
|
bridgeToken,
|
|
1322
|
-
snapshotRef: resolvedCheckpointRef
|
|
1506
|
+
snapshotRef: resolvedCheckpointRef,
|
|
1507
|
+
lastState: "running"
|
|
1323
1508
|
},
|
|
1324
1509
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1325
1510
|
};
|
|
@@ -1336,137 +1521,20 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
1336
1521
|
async start(box) {
|
|
1337
1522
|
const h = handleFor(box);
|
|
1338
1523
|
await backend.start(h);
|
|
1339
|
-
|
|
1340
|
-
let webPreview;
|
|
1341
|
-
try {
|
|
1342
|
-
webPreview = await backend.previewUrl(h, webPort);
|
|
1343
|
-
} catch {
|
|
1344
|
-
const cached = box.cloud?.previewUrls?.[webPort];
|
|
1345
|
-
webPreview = cached ? { url: cached } : void 0;
|
|
1346
|
-
}
|
|
1347
|
-
const servicePreviews = {};
|
|
1348
|
-
try {
|
|
1349
|
-
const ports = await readExposedServicePorts(box.workspacePath);
|
|
1350
|
-
for (const port of ports) {
|
|
1351
|
-
if (port === webPort) continue;
|
|
1352
|
-
try {
|
|
1353
|
-
const p = await backend.previewUrl(h, port);
|
|
1354
|
-
servicePreviews[port] = p.url;
|
|
1355
|
-
} catch {
|
|
1356
|
-
}
|
|
1357
|
-
}
|
|
1358
|
-
} catch {
|
|
1359
|
-
}
|
|
1360
|
-
let relayPreview;
|
|
1361
|
-
try {
|
|
1362
|
-
relayPreview = await backend.previewUrl(h, 8788);
|
|
1363
|
-
} catch {
|
|
1364
|
-
relayPreview = box.cloud?.relayPreviewUrl ? { url: box.cloud.relayPreviewUrl, token: box.cloud.relayPreviewToken } : void 0;
|
|
1365
|
-
}
|
|
1366
|
-
const mergedPreviews = {
|
|
1367
|
-
...box.cloud?.previewUrls ?? {},
|
|
1368
|
-
...servicePreviews
|
|
1369
|
-
};
|
|
1370
|
-
if (webPreview !== void 0) mergedPreviews[webPort] = webPreview.url;
|
|
1371
|
-
let portlessAliasName = box.portlessAlias;
|
|
1372
|
-
let portlessUrlResolved = box.portlessUrl;
|
|
1373
|
-
if (box.portlessAlias && webPreview) {
|
|
1374
|
-
const r = await bootstrapPortlessForCloudBox(backend, h, {
|
|
1375
|
-
boxName: box.name,
|
|
1376
|
-
webPreviewUrl: webPreview.url,
|
|
1377
|
-
webPort,
|
|
1378
|
-
onLog: () => {
|
|
1379
|
-
}
|
|
1380
|
-
});
|
|
1381
|
-
if (r) {
|
|
1382
|
-
portlessAliasName = r.alias;
|
|
1383
|
-
portlessUrlResolved = r.url;
|
|
1384
|
-
}
|
|
1385
|
-
}
|
|
1386
|
-
let portlessVncAliasName = box.portlessVncAlias;
|
|
1387
|
-
let portlessVncUrlResolved = box.portlessVncUrl;
|
|
1388
|
-
if (box.portlessVncAlias && box.vncEnabled) {
|
|
1389
|
-
try {
|
|
1390
|
-
const vncPreview = await backend.previewUrl(h, CLOUD_VNC_PORT);
|
|
1391
|
-
const url = await registerHostPortlessAlias({
|
|
1392
|
-
alias: box.portlessVncAlias,
|
|
1393
|
-
previewUrl: vncPreview.url,
|
|
1394
|
-
label: "vnc",
|
|
1395
|
-
onLog: () => {
|
|
1396
|
-
}
|
|
1397
|
-
});
|
|
1398
|
-
if (url) {
|
|
1399
|
-
portlessVncAliasName = box.portlessVncAlias;
|
|
1400
|
-
portlessVncUrlResolved = url;
|
|
1401
|
-
}
|
|
1402
|
-
} catch {
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
const next = {
|
|
1406
|
-
...box,
|
|
1407
|
-
portlessAlias: portlessAliasName,
|
|
1408
|
-
portlessUrl: portlessUrlResolved,
|
|
1409
|
-
portlessVncAlias: portlessVncAliasName,
|
|
1410
|
-
portlessVncUrl: portlessVncUrlResolved,
|
|
1411
|
-
cloud: {
|
|
1412
|
-
...box.cloud ?? { backend: providerName, sandboxId: h.sandboxId },
|
|
1413
|
-
webPort,
|
|
1414
|
-
previewUrls: Object.keys(mergedPreviews).length > 0 ? mergedPreviews : void 0,
|
|
1415
|
-
relayPreviewUrl: relayPreview?.url ?? box.cloud?.relayPreviewUrl,
|
|
1416
|
-
relayPreviewToken: relayPreview?.token ?? box.cloud?.relayPreviewToken
|
|
1417
|
-
}
|
|
1418
|
-
};
|
|
1419
|
-
await recordBox(next);
|
|
1420
|
-
await launchCloudCtlDaemon({
|
|
1421
|
-
backend,
|
|
1422
|
-
handle: h,
|
|
1423
|
-
boxId: box.id,
|
|
1424
|
-
boxName: box.name,
|
|
1425
|
-
relayUrl: `http://127.0.0.1:${String(8788)}`,
|
|
1426
|
-
relayToken: box.relayToken ?? "",
|
|
1427
|
-
bridgeToken: box.cloud?.bridgeToken
|
|
1428
|
-
});
|
|
1429
|
-
if (opts.launchDockerd !== false) {
|
|
1430
|
-
try {
|
|
1431
|
-
const dockerd = await launchCloudDockerdDaemon({ backend, handle: h, timeoutMs: 6e4 });
|
|
1432
|
-
if (!dockerd.up) {
|
|
1433
|
-
}
|
|
1434
|
-
} catch {
|
|
1435
|
-
}
|
|
1436
|
-
}
|
|
1437
|
-
if (box.vncEnabled && box.vncPassword) {
|
|
1438
|
-
try {
|
|
1439
|
-
await launchCloudVncDaemon({ backend, handle: h, vncPassword: box.vncPassword });
|
|
1440
|
-
} catch {
|
|
1441
|
-
}
|
|
1442
|
-
}
|
|
1443
|
-
if (relayPreview && box.relayToken && box.cloud?.bridgeToken) {
|
|
1444
|
-
try {
|
|
1445
|
-
await registerBoxWithRelay({
|
|
1446
|
-
boxId: box.id,
|
|
1447
|
-
token: box.relayToken,
|
|
1448
|
-
name: box.name,
|
|
1449
|
-
kind: "cloud",
|
|
1450
|
-
backend: backend.name,
|
|
1451
|
-
previewUrl: relayPreview.url,
|
|
1452
|
-
previewToken: relayPreview.token,
|
|
1453
|
-
bridgeToken: box.cloud.bridgeToken,
|
|
1454
|
-
createdAt: box.createdAt,
|
|
1455
|
-
projectIndex: box.projectIndex
|
|
1456
|
-
});
|
|
1457
|
-
} catch {
|
|
1458
|
-
}
|
|
1459
|
-
}
|
|
1460
|
-
return next;
|
|
1524
|
+
return reEnsureCloudBox(box, h);
|
|
1461
1525
|
},
|
|
1462
1526
|
async pause(box) {
|
|
1463
1527
|
await backend.pause(handleFor(box));
|
|
1528
|
+
await persistLastState(box, "paused");
|
|
1464
1529
|
},
|
|
1465
1530
|
async resume(box) {
|
|
1466
|
-
|
|
1531
|
+
const h = handleFor(box);
|
|
1532
|
+
await backend.resume(h);
|
|
1533
|
+
await reEnsureCloudBox(box, h);
|
|
1467
1534
|
},
|
|
1468
1535
|
async stop(box) {
|
|
1469
1536
|
await backend.stop(handleFor(box));
|
|
1537
|
+
await persistLastState(box, "paused");
|
|
1470
1538
|
},
|
|
1471
1539
|
async destroy(box) {
|
|
1472
1540
|
try {
|
|
@@ -1498,7 +1566,7 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
1498
1566
|
},
|
|
1499
1567
|
async inspect(box) {
|
|
1500
1568
|
const state = await probe(box);
|
|
1501
|
-
const webPort = box.cloud?.webPort ?? CLOUD_WEB_PROXY_PORT;
|
|
1569
|
+
const webPort = box.cloud?.webPort ?? backend.webProxyPort ?? CLOUD_WEB_PROXY_PORT;
|
|
1502
1570
|
const portlessWebUrl = box.portlessAlias !== void 0 ? box.portlessUrl ?? `https://${box.portlessAlias}.localhost` : void 0;
|
|
1503
1571
|
const cachedWebUrl = box.cloud?.previewUrls?.[webPort];
|
|
1504
1572
|
const webUrl = portlessWebUrl ?? cachedWebUrl;
|
|
@@ -1578,11 +1646,22 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
1578
1646
|
return box.portlessVncUrl ?? `https://${box.portlessVncAlias}.localhost`;
|
|
1579
1647
|
}
|
|
1580
1648
|
}
|
|
1581
|
-
const port = kind === "vnc" ? CLOUD_VNC_PORT : box.cloud?.webPort ?? CLOUD_WEB_PROXY_PORT;
|
|
1649
|
+
const port = kind === "vnc" ? CLOUD_VNC_PORT : box.cloud?.webPort ?? backend.webProxyPort ?? CLOUD_WEB_PROXY_PORT;
|
|
1582
1650
|
if (backend.signedPreviewUrl) {
|
|
1583
1651
|
const ttl = opts2?.ttl ?? DEFAULT_SIGNED_URL_TTL_SECONDS;
|
|
1584
|
-
|
|
1585
|
-
|
|
1652
|
+
try {
|
|
1653
|
+
const signed = await backend.signedPreviewUrl(h, port, ttl);
|
|
1654
|
+
return signed.url;
|
|
1655
|
+
} catch (err) {
|
|
1656
|
+
if (kind === "web") {
|
|
1657
|
+
const fallbackPort = await firstExposedServicePort(box);
|
|
1658
|
+
if (fallbackPort !== void 0 && fallbackPort !== port) {
|
|
1659
|
+
const signed = await backend.signedPreviewUrl(h, fallbackPort, ttl);
|
|
1660
|
+
return signed.url;
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
throw err;
|
|
1664
|
+
}
|
|
1586
1665
|
}
|
|
1587
1666
|
const p = await backend.previewUrl(h, port);
|
|
1588
1667
|
throw new Error(
|
|
@@ -1607,6 +1686,18 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
1607
1686
|
// omit it. Backends that have one can decorate the returned provider.
|
|
1608
1687
|
};
|
|
1609
1688
|
}
|
|
1689
|
+
var RESERVED_CLOUD_PORTS = /* @__PURE__ */ new Set([CLOUD_WEB_PROXY_PORT, CLOUD_VNC_PORT, 8788]);
|
|
1690
|
+
async function firstExposedServicePort(box) {
|
|
1691
|
+
const reserved = (p) => RESERVED_CLOUD_PORTS.has(p) || p === box.cloud?.webPort;
|
|
1692
|
+
const fromRecord = Object.keys(box.cloud?.previewUrls ?? {}).map(Number).filter((p) => Number.isInteger(p) && !reserved(p));
|
|
1693
|
+
if (fromRecord.length > 0) return Math.min(...fromRecord);
|
|
1694
|
+
try {
|
|
1695
|
+
const fromYaml = (await readExposedServicePorts(box.workspacePath)).filter((p) => !reserved(p));
|
|
1696
|
+
if (fromYaml.length > 0) return Math.min(...fromYaml);
|
|
1697
|
+
} catch {
|
|
1698
|
+
}
|
|
1699
|
+
return void 0;
|
|
1700
|
+
}
|
|
1610
1701
|
function makeCloudCheckpoint(backend) {
|
|
1611
1702
|
return {
|
|
1612
1703
|
async create(box, name) {
|
|
@@ -1709,7 +1800,8 @@ export {
|
|
|
1709
1800
|
resolveCloudCheckpoint,
|
|
1710
1801
|
writeCloudCheckpointManifest,
|
|
1711
1802
|
removeCloudCheckpointDir,
|
|
1803
|
+
probeCloudCheckpoint,
|
|
1712
1804
|
createCloudProvider,
|
|
1713
1805
|
renderInnerCommand
|
|
1714
1806
|
};
|
|
1715
|
-
//# sourceMappingURL=chunk-
|
|
1807
|
+
//# sourceMappingURL=chunk-2GPORKYF.js.map
|