@computesdk/workbench 3.0.0 → 3.1.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/README.md +64 -0
- package/dist/bin/workbench.js +484 -129
- package/dist/bin/workbench.js.map +1 -1
- package/dist/index.js +495 -137
- package/dist/index.js.map +1 -1
- package/package.json +13 -11
package/dist/bin/workbench.js
CHANGED
|
@@ -1,16 +1,38 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __esm = (fn, res) => function __init() {
|
|
5
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
+
};
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
2
11
|
|
|
3
12
|
// ../../node_modules/.pnpm/tsup@8.5.0_jiti@2.6.1_postcss@8.5.6_tsx@4.20.3_typescript@5.8.3_yaml@2.8.0/node_modules/tsup/assets/esm_shims.js
|
|
4
13
|
import path from "path";
|
|
5
14
|
import { fileURLToPath } from "url";
|
|
6
|
-
var getFilename
|
|
7
|
-
var
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
15
|
+
var getFilename, getDirname, __dirname;
|
|
16
|
+
var init_esm_shims = __esm({
|
|
17
|
+
"../../node_modules/.pnpm/tsup@8.5.0_jiti@2.6.1_postcss@8.5.6_tsx@4.20.3_typescript@5.8.3_yaml@2.8.0/node_modules/tsup/assets/esm_shims.js"() {
|
|
18
|
+
"use strict";
|
|
19
|
+
getFilename = () => fileURLToPath(import.meta.url);
|
|
20
|
+
getDirname = () => path.dirname(getFilename());
|
|
21
|
+
__dirname = /* @__PURE__ */ getDirname();
|
|
22
|
+
}
|
|
23
|
+
});
|
|
12
24
|
|
|
13
25
|
// src/cli/state.ts
|
|
26
|
+
var state_exports = {};
|
|
27
|
+
__export(state_exports, {
|
|
28
|
+
clearSandbox: () => clearSandbox,
|
|
29
|
+
createState: () => createState,
|
|
30
|
+
formatUptime: () => formatUptime,
|
|
31
|
+
getCurrentSandbox: () => getCurrentSandbox,
|
|
32
|
+
getUptimeSeconds: () => getUptimeSeconds,
|
|
33
|
+
hasSandbox: () => hasSandbox,
|
|
34
|
+
setSandbox: () => setSandbox
|
|
35
|
+
});
|
|
14
36
|
function createState() {
|
|
15
37
|
return {
|
|
16
38
|
currentProvider: null,
|
|
@@ -19,7 +41,8 @@ function createState() {
|
|
|
19
41
|
availableProviders: [],
|
|
20
42
|
useDirectMode: false,
|
|
21
43
|
// Default to gateway mode
|
|
22
|
-
verbose: false
|
|
44
|
+
verbose: false,
|
|
45
|
+
compute: null
|
|
23
46
|
};
|
|
24
47
|
}
|
|
25
48
|
function getCurrentSandbox(state) {
|
|
@@ -73,36 +96,28 @@ function formatUptime(state) {
|
|
|
73
96
|
const remainingMinutes = minutes % 60;
|
|
74
97
|
return `${hours}h ${remainingMinutes}m`;
|
|
75
98
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
import { createCompute } from "computesdk";
|
|
99
|
+
var init_state = __esm({
|
|
100
|
+
"src/cli/state.ts"() {
|
|
101
|
+
"use strict";
|
|
102
|
+
init_esm_shims();
|
|
103
|
+
}
|
|
104
|
+
});
|
|
83
105
|
|
|
84
106
|
// src/cli/output.ts
|
|
85
|
-
var
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
cyan: (text) => `${colors.cyan}${text}${colors.reset}`,
|
|
100
|
-
green: (text) => `${colors.green}${text}${colors.reset}`,
|
|
101
|
-
yellow: (text) => `${colors.yellow}${text}${colors.reset}`,
|
|
102
|
-
red: (text) => `${colors.red}${text}${colors.reset}`,
|
|
103
|
-
blue: (text) => `${colors.blue}${text}${colors.reset}`,
|
|
104
|
-
magenta: (text) => `${colors.magenta}${text}${colors.reset}`
|
|
105
|
-
};
|
|
107
|
+
var output_exports = {};
|
|
108
|
+
__export(output_exports, {
|
|
109
|
+
Spinner: () => Spinner,
|
|
110
|
+
c: () => c,
|
|
111
|
+
formatDuration: () => formatDuration,
|
|
112
|
+
logCommand: () => logCommand,
|
|
113
|
+
logError: () => logError,
|
|
114
|
+
logInfo: () => logInfo,
|
|
115
|
+
logSuccess: () => logSuccess,
|
|
116
|
+
logWarning: () => logWarning,
|
|
117
|
+
showHelp: () => showHelp,
|
|
118
|
+
showInfo: () => showInfo,
|
|
119
|
+
showWelcome: () => showWelcome
|
|
120
|
+
});
|
|
106
121
|
function showWelcome(availableProviders, currentProvider, useDirectMode) {
|
|
107
122
|
console.log(c.bold(c.cyan("\n\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557")));
|
|
108
123
|
console.log(c.bold(c.cyan("\u2551 ComputeSDK Workbench \u2551")));
|
|
@@ -151,39 +166,6 @@ function showInfo(state) {
|
|
|
151
166
|
console.log(` Uptime: ${formatUptime(state)}`);
|
|
152
167
|
console.log("");
|
|
153
168
|
}
|
|
154
|
-
var Spinner = class {
|
|
155
|
-
constructor(text) {
|
|
156
|
-
this.interval = null;
|
|
157
|
-
this.frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
158
|
-
this.currentFrame = 0;
|
|
159
|
-
this.text = text;
|
|
160
|
-
}
|
|
161
|
-
start() {
|
|
162
|
-
process.stdout.write("\x1B[?25l");
|
|
163
|
-
this.interval = setInterval(() => {
|
|
164
|
-
const frame = this.frames[this.currentFrame];
|
|
165
|
-
process.stdout.write(`\r${c.cyan(frame)} ${this.text}`);
|
|
166
|
-
this.currentFrame = (this.currentFrame + 1) % this.frames.length;
|
|
167
|
-
}, 80);
|
|
168
|
-
return this;
|
|
169
|
-
}
|
|
170
|
-
succeed(text) {
|
|
171
|
-
this.stop();
|
|
172
|
-
console.log(`${c.green("\u2705")} ${text || this.text}`);
|
|
173
|
-
}
|
|
174
|
-
fail(text) {
|
|
175
|
-
this.stop();
|
|
176
|
-
console.log(`${c.red("\u274C")} ${text || this.text}`);
|
|
177
|
-
}
|
|
178
|
-
stop() {
|
|
179
|
-
if (this.interval) {
|
|
180
|
-
clearInterval(this.interval);
|
|
181
|
-
this.interval = null;
|
|
182
|
-
}
|
|
183
|
-
process.stdout.write("\r\x1B[K");
|
|
184
|
-
process.stdout.write("\x1B[?25h");
|
|
185
|
-
}
|
|
186
|
-
};
|
|
187
169
|
function formatDuration(ms) {
|
|
188
170
|
const seconds = ms / 1e3;
|
|
189
171
|
if (seconds < 1) {
|
|
@@ -222,6 +204,9 @@ ${c.bold("Provider Modes:")}
|
|
|
222
204
|
${c.bold("Sandbox Management:")}
|
|
223
205
|
${c.cyan("restart")} Restart current sandbox
|
|
224
206
|
${c.cyan("destroy")} Destroy current sandbox
|
|
207
|
+
${c.cyan("connect <url> [token]")} Connect to existing sandbox via URL
|
|
208
|
+
${c.dim("Example: connect https://sandbox-123.localhost:8080")}
|
|
209
|
+
${c.dim("Example: connect https://sandbox-123.localhost:8080 your_token")}
|
|
225
210
|
${c.cyan("info")} Show sandbox info (provider, uptime)
|
|
226
211
|
|
|
227
212
|
${c.bold("Environment:")}
|
|
@@ -257,6 +242,20 @@ ${c.bold("Running Commands:")}
|
|
|
257
242
|
${c.cyan('filesystem.exists("/path")')}
|
|
258
243
|
${c.cyan('filesystem.remove("/file")')}
|
|
259
244
|
|
|
245
|
+
${c.dim("Named Sandboxes (gateway mode only):")}
|
|
246
|
+
${c.cyan("create()")} ${c.dim("// Create & switch to new sandbox")}
|
|
247
|
+
${c.cyan('create({ namespace: "h" })')} ${c.dim("// Create with namespace & switch")}
|
|
248
|
+
${c.cyan('findOrCreate({ name: "my-app" })')} ${c.dim("// Find or create & switch")}
|
|
249
|
+
${c.cyan('find({ name: "my-app" })')} ${c.dim("// Find existing & switch")}
|
|
250
|
+
|
|
251
|
+
${c.dim("Note: Prompts before switching if you already have an active sandbox")}
|
|
252
|
+
|
|
253
|
+
${c.dim("Child Sandboxes (gateway mode only):")}
|
|
254
|
+
${c.cyan("child.create()")} ${c.dim("// Create child sandbox")}
|
|
255
|
+
${c.cyan("child.list()")} ${c.dim("// List all children")}
|
|
256
|
+
${c.cyan('child.retrieve("sandbox-id")')} ${c.dim("// Get child info")}
|
|
257
|
+
${c.cyan('child.destroy("sandbox-id")')} ${c.dim("// Delete child")}
|
|
258
|
+
|
|
260
259
|
${c.dim("Sandbox Methods:")}
|
|
261
260
|
${c.cyan("getUrl({ port: 3000 })")} ${c.dim("// Get public URL")}
|
|
262
261
|
${c.cyan(`runCode("console.log('hi')", "node")`)}
|
|
@@ -292,6 +291,71 @@ function logError(message) {
|
|
|
292
291
|
function logWarning(message) {
|
|
293
292
|
console.log(c.yellow(`\u26A0\uFE0F ${message}`));
|
|
294
293
|
}
|
|
294
|
+
function logInfo(message) {
|
|
295
|
+
console.log(c.blue(`\u2139\uFE0F ${message}`));
|
|
296
|
+
}
|
|
297
|
+
var colors, c, Spinner;
|
|
298
|
+
var init_output = __esm({
|
|
299
|
+
"src/cli/output.ts"() {
|
|
300
|
+
"use strict";
|
|
301
|
+
init_esm_shims();
|
|
302
|
+
init_state();
|
|
303
|
+
colors = {
|
|
304
|
+
reset: "\x1B[0m",
|
|
305
|
+
bright: "\x1B[1m",
|
|
306
|
+
dim: "\x1B[2m",
|
|
307
|
+
cyan: "\x1B[36m",
|
|
308
|
+
green: "\x1B[32m",
|
|
309
|
+
yellow: "\x1B[33m",
|
|
310
|
+
red: "\x1B[31m",
|
|
311
|
+
blue: "\x1B[34m",
|
|
312
|
+
magenta: "\x1B[35m"
|
|
313
|
+
};
|
|
314
|
+
c = {
|
|
315
|
+
bold: (text) => `${colors.bright}${text}${colors.reset}`,
|
|
316
|
+
dim: (text) => `${colors.dim}${text}${colors.reset}`,
|
|
317
|
+
cyan: (text) => `${colors.cyan}${text}${colors.reset}`,
|
|
318
|
+
green: (text) => `${colors.green}${text}${colors.reset}`,
|
|
319
|
+
yellow: (text) => `${colors.yellow}${text}${colors.reset}`,
|
|
320
|
+
red: (text) => `${colors.red}${text}${colors.reset}`,
|
|
321
|
+
blue: (text) => `${colors.blue}${text}${colors.reset}`,
|
|
322
|
+
magenta: (text) => `${colors.magenta}${text}${colors.reset}`
|
|
323
|
+
};
|
|
324
|
+
Spinner = class {
|
|
325
|
+
constructor(text) {
|
|
326
|
+
this.interval = null;
|
|
327
|
+
this.frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
328
|
+
this.currentFrame = 0;
|
|
329
|
+
this.text = text;
|
|
330
|
+
}
|
|
331
|
+
start() {
|
|
332
|
+
process.stdout.write("\x1B[?25l");
|
|
333
|
+
this.interval = setInterval(() => {
|
|
334
|
+
const frame = this.frames[this.currentFrame];
|
|
335
|
+
process.stdout.write(`\r${c.cyan(frame)} ${this.text}`);
|
|
336
|
+
this.currentFrame = (this.currentFrame + 1) % this.frames.length;
|
|
337
|
+
}, 80);
|
|
338
|
+
return this;
|
|
339
|
+
}
|
|
340
|
+
succeed(text) {
|
|
341
|
+
this.stop();
|
|
342
|
+
console.log(`${c.green("\u2705")} ${text || this.text}`);
|
|
343
|
+
}
|
|
344
|
+
fail(text) {
|
|
345
|
+
this.stop();
|
|
346
|
+
console.log(`${c.red("\u274C")} ${text || this.text}`);
|
|
347
|
+
}
|
|
348
|
+
stop() {
|
|
349
|
+
if (this.interval) {
|
|
350
|
+
clearInterval(this.interval);
|
|
351
|
+
this.interval = null;
|
|
352
|
+
}
|
|
353
|
+
process.stdout.write("\r\x1B[K");
|
|
354
|
+
process.stdout.write("\x1B[?25h");
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
});
|
|
295
359
|
|
|
296
360
|
// src/cli/providers.ts
|
|
297
361
|
import {
|
|
@@ -299,14 +363,6 @@ import {
|
|
|
299
363
|
PROVIDER_NAMES as SHARED_PROVIDER_NAMES,
|
|
300
364
|
getProviderConfigFromEnv
|
|
301
365
|
} from "computesdk";
|
|
302
|
-
var PROVIDER_NAMES = [
|
|
303
|
-
"gateway",
|
|
304
|
-
...SHARED_PROVIDER_NAMES
|
|
305
|
-
];
|
|
306
|
-
var PROVIDER_AUTH = {
|
|
307
|
-
gateway: [["COMPUTESDK_API_KEY"]],
|
|
308
|
-
...SHARED_PROVIDER_AUTH
|
|
309
|
-
};
|
|
310
366
|
function getProviderStatus(provider) {
|
|
311
367
|
const authOptions = PROVIDER_AUTH[provider];
|
|
312
368
|
if (typeof process === "undefined") {
|
|
@@ -488,29 +544,136 @@ function getProviderConfig(providerName) {
|
|
|
488
544
|
}
|
|
489
545
|
return getProviderConfigFromEnv(providerName);
|
|
490
546
|
}
|
|
547
|
+
var PROVIDER_NAMES, PROVIDER_AUTH;
|
|
548
|
+
var init_providers = __esm({
|
|
549
|
+
"src/cli/providers.ts"() {
|
|
550
|
+
"use strict";
|
|
551
|
+
init_esm_shims();
|
|
552
|
+
init_output();
|
|
553
|
+
PROVIDER_NAMES = [
|
|
554
|
+
"gateway",
|
|
555
|
+
...SHARED_PROVIDER_NAMES
|
|
556
|
+
];
|
|
557
|
+
PROVIDER_AUTH = {
|
|
558
|
+
gateway: [["COMPUTESDK_API_KEY"]],
|
|
559
|
+
...SHARED_PROVIDER_AUTH
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
});
|
|
491
563
|
|
|
492
564
|
// src/cli/commands.ts
|
|
565
|
+
var commands_exports = {};
|
|
566
|
+
__export(commands_exports, {
|
|
567
|
+
cleanupOnExit: () => cleanupOnExit,
|
|
568
|
+
confirmSandboxSwitch: () => confirmSandboxSwitch,
|
|
569
|
+
connectToSandbox: () => connectToSandbox,
|
|
570
|
+
createProviderCommand: () => createProviderCommand,
|
|
571
|
+
createSandbox: () => createSandbox,
|
|
572
|
+
destroySandbox: () => destroySandbox,
|
|
573
|
+
ensureSandbox: () => ensureSandbox,
|
|
574
|
+
getComputeInstance: () => getComputeInstance,
|
|
575
|
+
restartSandbox: () => restartSandbox,
|
|
576
|
+
runCommand: () => runCommand,
|
|
577
|
+
showMode: () => showMode,
|
|
578
|
+
showVerbose: () => showVerbose,
|
|
579
|
+
switchProvider: () => switchProvider,
|
|
580
|
+
toggleMode: () => toggleMode,
|
|
581
|
+
toggleVerbose: () => toggleVerbose
|
|
582
|
+
});
|
|
583
|
+
import { createCompute } from "computesdk";
|
|
493
584
|
import * as readline from "readline";
|
|
494
|
-
async function confirm(question) {
|
|
585
|
+
async function confirm(question, defaultYes = false) {
|
|
495
586
|
return new Promise((resolve) => {
|
|
496
587
|
const rl = readline.createInterface({
|
|
497
588
|
input: process.stdin,
|
|
498
589
|
output: process.stdout
|
|
499
590
|
});
|
|
500
591
|
process.stdin.resume();
|
|
501
|
-
|
|
592
|
+
const promptSuffix = defaultYes ? "(Y/n)" : "(y/N)";
|
|
593
|
+
rl.question(`${question} ${promptSuffix}: `, (answer) => {
|
|
502
594
|
rl.close();
|
|
503
595
|
const trimmed = answer.trim().toLowerCase();
|
|
504
|
-
|
|
596
|
+
if (trimmed === "") {
|
|
597
|
+
resolve(defaultYes);
|
|
598
|
+
} else {
|
|
599
|
+
resolve(trimmed === "y" || trimmed === "yes");
|
|
600
|
+
}
|
|
505
601
|
});
|
|
506
602
|
});
|
|
507
603
|
}
|
|
604
|
+
async function confirmSandboxSwitch(state) {
|
|
605
|
+
if (!hasSandbox(state)) {
|
|
606
|
+
return true;
|
|
607
|
+
}
|
|
608
|
+
return await confirm("Switch to new sandbox?", true);
|
|
609
|
+
}
|
|
508
610
|
async function ensureSandbox(state) {
|
|
509
611
|
if (hasSandbox(state)) {
|
|
510
612
|
return;
|
|
511
613
|
}
|
|
512
614
|
await createSandbox(state);
|
|
513
615
|
}
|
|
616
|
+
async function getComputeInstance(state) {
|
|
617
|
+
if (state.compute) {
|
|
618
|
+
return state.compute;
|
|
619
|
+
}
|
|
620
|
+
const providerName = state.currentProvider || autoDetectProvider(false);
|
|
621
|
+
const useDirect = state.useDirectMode;
|
|
622
|
+
if (!providerName) {
|
|
623
|
+
throw new Error("No provider configured.");
|
|
624
|
+
}
|
|
625
|
+
let compute2;
|
|
626
|
+
if (useDirect) {
|
|
627
|
+
const providerModule = await loadProvider(providerName);
|
|
628
|
+
const providerFactory = providerModule[providerName];
|
|
629
|
+
if (!providerFactory) {
|
|
630
|
+
throw new Error(`Provider ${providerName} does not export a factory function`);
|
|
631
|
+
}
|
|
632
|
+
const config2 = getProviderConfig(providerName);
|
|
633
|
+
compute2 = createCompute({
|
|
634
|
+
defaultProvider: providerFactory(config2)
|
|
635
|
+
});
|
|
636
|
+
} else {
|
|
637
|
+
const gatewayModule = await import("computesdk");
|
|
638
|
+
const gatewayFactory = gatewayModule.gateway;
|
|
639
|
+
const providerConfig = getProviderConfig(providerName);
|
|
640
|
+
const providerHeaders = {};
|
|
641
|
+
switch (providerName) {
|
|
642
|
+
case "e2b":
|
|
643
|
+
if (providerConfig.apiKey) providerHeaders["X-E2B-API-Key"] = providerConfig.apiKey;
|
|
644
|
+
break;
|
|
645
|
+
case "railway":
|
|
646
|
+
if (providerConfig.apiKey) providerHeaders["X-Railway-API-Key"] = providerConfig.apiKey;
|
|
647
|
+
if (providerConfig.projectId) providerHeaders["X-Railway-Project-ID"] = providerConfig.projectId;
|
|
648
|
+
if (providerConfig.environmentId) providerHeaders["X-Railway-Environment-ID"] = providerConfig.environmentId;
|
|
649
|
+
break;
|
|
650
|
+
case "daytona":
|
|
651
|
+
if (providerConfig.apiKey) providerHeaders["X-Daytona-API-Key"] = providerConfig.apiKey;
|
|
652
|
+
break;
|
|
653
|
+
case "modal":
|
|
654
|
+
if (providerConfig.tokenId) providerHeaders["X-Modal-Token-ID"] = providerConfig.tokenId;
|
|
655
|
+
if (providerConfig.tokenSecret) providerHeaders["X-Modal-Token-Secret"] = providerConfig.tokenSecret;
|
|
656
|
+
break;
|
|
657
|
+
case "vercel":
|
|
658
|
+
if (providerConfig.token) providerHeaders["X-Vercel-Token"] = providerConfig.token;
|
|
659
|
+
if (providerConfig.teamId) providerHeaders["X-Vercel-Team-ID"] = providerConfig.teamId;
|
|
660
|
+
if (providerConfig.projectId) providerHeaders["X-Vercel-Project-ID"] = providerConfig.projectId;
|
|
661
|
+
break;
|
|
662
|
+
}
|
|
663
|
+
const config2 = {
|
|
664
|
+
apiKey: process.env.COMPUTESDK_API_KEY,
|
|
665
|
+
provider: providerName,
|
|
666
|
+
// Tell gateway which backend to use
|
|
667
|
+
providerHeaders
|
|
668
|
+
// Pass provider credentials via headers
|
|
669
|
+
};
|
|
670
|
+
compute2 = createCompute({
|
|
671
|
+
defaultProvider: gatewayFactory(config2)
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
state.compute = compute2;
|
|
675
|
+
return compute2;
|
|
676
|
+
}
|
|
514
677
|
async function createSandbox(state) {
|
|
515
678
|
const providerName = state.currentProvider || autoDetectProvider(false);
|
|
516
679
|
const useDirect = state.useDirectMode;
|
|
@@ -540,55 +703,7 @@ async function createSandbox(state) {
|
|
|
540
703
|
const spinner = new Spinner(`Creating sandbox with ${modeLabel}...`).start();
|
|
541
704
|
const startTime = Date.now();
|
|
542
705
|
try {
|
|
543
|
-
|
|
544
|
-
if (useDirect) {
|
|
545
|
-
const providerModule = await loadProvider(providerName);
|
|
546
|
-
const providerFactory = providerModule[providerName];
|
|
547
|
-
if (!providerFactory) {
|
|
548
|
-
throw new Error(`Provider ${providerName} does not export a factory function`);
|
|
549
|
-
}
|
|
550
|
-
const config2 = getProviderConfig(providerName);
|
|
551
|
-
compute2 = createCompute({
|
|
552
|
-
defaultProvider: providerFactory(config2)
|
|
553
|
-
});
|
|
554
|
-
} else {
|
|
555
|
-
const gatewayModule = await import("computesdk");
|
|
556
|
-
const gatewayFactory = gatewayModule.gateway;
|
|
557
|
-
const providerConfig = getProviderConfig(providerName);
|
|
558
|
-
const providerHeaders = {};
|
|
559
|
-
switch (providerName) {
|
|
560
|
-
case "e2b":
|
|
561
|
-
if (providerConfig.apiKey) providerHeaders["X-E2B-API-Key"] = providerConfig.apiKey;
|
|
562
|
-
break;
|
|
563
|
-
case "railway":
|
|
564
|
-
if (providerConfig.apiKey) providerHeaders["X-Railway-API-Key"] = providerConfig.apiKey;
|
|
565
|
-
if (providerConfig.projectId) providerHeaders["X-Railway-Project-ID"] = providerConfig.projectId;
|
|
566
|
-
if (providerConfig.environmentId) providerHeaders["X-Railway-Environment-ID"] = providerConfig.environmentId;
|
|
567
|
-
break;
|
|
568
|
-
case "daytona":
|
|
569
|
-
if (providerConfig.apiKey) providerHeaders["X-Daytona-API-Key"] = providerConfig.apiKey;
|
|
570
|
-
break;
|
|
571
|
-
case "modal":
|
|
572
|
-
if (providerConfig.tokenId) providerHeaders["X-Modal-Token-ID"] = providerConfig.tokenId;
|
|
573
|
-
if (providerConfig.tokenSecret) providerHeaders["X-Modal-Token-Secret"] = providerConfig.tokenSecret;
|
|
574
|
-
break;
|
|
575
|
-
case "vercel":
|
|
576
|
-
if (providerConfig.token) providerHeaders["X-Vercel-Token"] = providerConfig.token;
|
|
577
|
-
if (providerConfig.teamId) providerHeaders["X-Vercel-Team-ID"] = providerConfig.teamId;
|
|
578
|
-
if (providerConfig.projectId) providerHeaders["X-Vercel-Project-ID"] = providerConfig.projectId;
|
|
579
|
-
break;
|
|
580
|
-
}
|
|
581
|
-
const config2 = {
|
|
582
|
-
apiKey: process.env.COMPUTESDK_API_KEY,
|
|
583
|
-
provider: providerName,
|
|
584
|
-
// Tell gateway which backend to use
|
|
585
|
-
providerHeaders
|
|
586
|
-
// Pass provider credentials via headers
|
|
587
|
-
};
|
|
588
|
-
compute2 = createCompute({
|
|
589
|
-
defaultProvider: gatewayFactory(config2)
|
|
590
|
-
});
|
|
591
|
-
}
|
|
706
|
+
const compute2 = await getComputeInstance(state);
|
|
592
707
|
const result = await compute2.sandbox.create();
|
|
593
708
|
const duration = Date.now() - startTime;
|
|
594
709
|
setSandbox(state, result, providerName);
|
|
@@ -732,6 +847,7 @@ async function switchProvider(state, mode, providerName) {
|
|
|
732
847
|
await destroySandbox(state);
|
|
733
848
|
state.currentProvider = actualProvider;
|
|
734
849
|
state.useDirectMode = useDirect;
|
|
850
|
+
state.compute = null;
|
|
735
851
|
const modeStr = useDirect ? `${actualProvider} (direct)` : `${actualProvider} (via gateway)`;
|
|
736
852
|
logSuccess(`Switched to ${modeStr}`);
|
|
737
853
|
} else {
|
|
@@ -740,6 +856,7 @@ async function switchProvider(state, mode, providerName) {
|
|
|
740
856
|
} else {
|
|
741
857
|
state.currentProvider = actualProvider;
|
|
742
858
|
state.useDirectMode = useDirect;
|
|
859
|
+
state.compute = null;
|
|
743
860
|
const modeStr = useDirect ? `${actualProvider} (direct)` : `${actualProvider} (via gateway)`;
|
|
744
861
|
logSuccess(`Switched to ${modeStr}`);
|
|
745
862
|
}
|
|
@@ -817,6 +934,62 @@ Verbose mode: ${status}`);
|
|
|
817
934
|
Toggle with: ${c.cyan("verbose")}
|
|
818
935
|
`);
|
|
819
936
|
}
|
|
937
|
+
async function connectToSandbox(state, sandboxUrl, token) {
|
|
938
|
+
if (!sandboxUrl) {
|
|
939
|
+
logError("Usage: connect <sandbox_url> [token]");
|
|
940
|
+
console.log("Example: connect https://sandbox-123.localhost:8080");
|
|
941
|
+
console.log("Example: connect https://sandbox-123.localhost:8080 your_access_token");
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
const cleanUrl = sandboxUrl.replace(/\/$/, "");
|
|
945
|
+
if (hasSandbox(state)) {
|
|
946
|
+
const shouldDestroy = await confirm("Disconnect from current sandbox?");
|
|
947
|
+
if (!shouldDestroy) {
|
|
948
|
+
logWarning("Keeping current sandbox. Connection cancelled.");
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
clearSandbox(state);
|
|
952
|
+
}
|
|
953
|
+
const spinner = new Spinner(`Connecting to ${cleanUrl}...`).start();
|
|
954
|
+
const startTime = Date.now();
|
|
955
|
+
try {
|
|
956
|
+
const { Sandbox } = await import("@computesdk/client");
|
|
957
|
+
let WebSocket;
|
|
958
|
+
try {
|
|
959
|
+
const wsModule = await import("ws");
|
|
960
|
+
WebSocket = wsModule.default;
|
|
961
|
+
} catch {
|
|
962
|
+
logError('Failed to import "ws" module. Please install it: pnpm add ws');
|
|
963
|
+
throw new Error('Missing "ws" dependency');
|
|
964
|
+
}
|
|
965
|
+
const sandbox = new Sandbox({
|
|
966
|
+
sandboxUrl: cleanUrl,
|
|
967
|
+
sandboxId: "",
|
|
968
|
+
// Will be populated when we get info
|
|
969
|
+
provider: "connected",
|
|
970
|
+
// Mark as directly connected
|
|
971
|
+
token,
|
|
972
|
+
// Optional access token
|
|
973
|
+
WebSocket
|
|
974
|
+
});
|
|
975
|
+
const info = await sandbox.getInfo();
|
|
976
|
+
const duration = Date.now() - startTime;
|
|
977
|
+
setSandbox(state, sandbox, "connected");
|
|
978
|
+
spinner.succeed(`Connected to sandbox ${c.dim(`(${formatDuration(duration)})`)}`);
|
|
979
|
+
console.log(c.dim(`Provider: ${info.provider || "unknown"}`));
|
|
980
|
+
console.log(c.dim(`Sandbox ID: ${info.id || "unknown"}`));
|
|
981
|
+
} catch (error) {
|
|
982
|
+
const duration = Date.now() - startTime;
|
|
983
|
+
spinner.fail(`Failed to connect ${c.dim(`(${formatDuration(duration)})`)}`);
|
|
984
|
+
if (error instanceof Error) {
|
|
985
|
+
logError(`Error: ${error.message}`);
|
|
986
|
+
if (error.stack) {
|
|
987
|
+
console.log(c.dim(error.stack));
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
throw error;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
820
993
|
async function cleanupOnExit(state, replServer) {
|
|
821
994
|
if (!hasSandbox(state)) {
|
|
822
995
|
return;
|
|
@@ -825,6 +998,10 @@ async function cleanupOnExit(state, replServer) {
|
|
|
825
998
|
replServer.pause();
|
|
826
999
|
}
|
|
827
1000
|
console.log("");
|
|
1001
|
+
if (state.currentProvider === "connected") {
|
|
1002
|
+
logWarning("Disconnecting from external sandbox (not destroying).");
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
828
1005
|
const shouldDestroy = await confirm("Destroy active sandbox?");
|
|
829
1006
|
if (shouldDestroy) {
|
|
830
1007
|
await destroySandbox(state);
|
|
@@ -832,8 +1009,34 @@ async function cleanupOnExit(state, replServer) {
|
|
|
832
1009
|
logWarning("Sandbox left running. It may incur costs.");
|
|
833
1010
|
}
|
|
834
1011
|
}
|
|
1012
|
+
var init_commands = __esm({
|
|
1013
|
+
"src/cli/commands.ts"() {
|
|
1014
|
+
"use strict";
|
|
1015
|
+
init_esm_shims();
|
|
1016
|
+
init_state();
|
|
1017
|
+
init_output();
|
|
1018
|
+
init_providers();
|
|
1019
|
+
}
|
|
1020
|
+
});
|
|
1021
|
+
|
|
1022
|
+
// src/bin/workbench.ts
|
|
1023
|
+
init_esm_shims();
|
|
1024
|
+
import { config } from "dotenv";
|
|
1025
|
+
|
|
1026
|
+
// src/cli/index.ts
|
|
1027
|
+
init_esm_shims();
|
|
1028
|
+
init_state();
|
|
1029
|
+
|
|
1030
|
+
// src/cli/repl.ts
|
|
1031
|
+
init_esm_shims();
|
|
1032
|
+
init_commands();
|
|
1033
|
+
init_output();
|
|
1034
|
+
init_providers();
|
|
1035
|
+
import * as repl from "repl";
|
|
1036
|
+
import * as cmd from "@computesdk/cmd";
|
|
835
1037
|
|
|
836
1038
|
// src/cli/types.ts
|
|
1039
|
+
init_esm_shims();
|
|
837
1040
|
function isCommand(value) {
|
|
838
1041
|
return Array.isArray(value) && value.length > 0 && typeof value[0] === "string";
|
|
839
1042
|
}
|
|
@@ -952,6 +1155,9 @@ function injectWorkbenchCommands(replServer, state) {
|
|
|
952
1155
|
replServer.context.destroy = async () => {
|
|
953
1156
|
await destroySandbox(state);
|
|
954
1157
|
};
|
|
1158
|
+
replServer.context.connect = async (url, token) => {
|
|
1159
|
+
await connectToSandbox(state, url, token);
|
|
1160
|
+
};
|
|
955
1161
|
replServer.context.info = () => showInfo(state);
|
|
956
1162
|
replServer.context.verbose = () => {
|
|
957
1163
|
toggleVerbose(state);
|
|
@@ -984,6 +1190,96 @@ function injectWorkbenchCommands(replServer, state) {
|
|
|
984
1190
|
}
|
|
985
1191
|
return sandbox.runCode(code, runtime);
|
|
986
1192
|
};
|
|
1193
|
+
replServer.context.create = async (options) => {
|
|
1194
|
+
if (state.useDirectMode) {
|
|
1195
|
+
throw new Error('Named sandboxes are only available in gateway mode. Use "mode gateway" to switch.');
|
|
1196
|
+
}
|
|
1197
|
+
const { getComputeInstance: getComputeInstance2, confirmSandboxSwitch: confirmSandboxSwitch2 } = await Promise.resolve().then(() => (init_commands(), commands_exports));
|
|
1198
|
+
const { setSandbox: setSandbox2 } = await Promise.resolve().then(() => (init_state(), state_exports));
|
|
1199
|
+
const { logSuccess: logSuccess2 } = await Promise.resolve().then(() => (init_output(), output_exports));
|
|
1200
|
+
const shouldSwitch = await confirmSandboxSwitch2(state);
|
|
1201
|
+
if (!shouldSwitch) {
|
|
1202
|
+
const compute3 = await getComputeInstance2(state);
|
|
1203
|
+
const sandbox2 = await compute3.sandbox.create(options);
|
|
1204
|
+
return {
|
|
1205
|
+
sandboxId: sandbox2.sandboxId,
|
|
1206
|
+
provider: sandbox2.provider,
|
|
1207
|
+
metadata: sandbox2.getInstance().config.metadata || {}
|
|
1208
|
+
};
|
|
1209
|
+
}
|
|
1210
|
+
const compute2 = await getComputeInstance2(state);
|
|
1211
|
+
const sandbox = await compute2.sandbox.create(options);
|
|
1212
|
+
setSandbox2(state, sandbox, sandbox.provider);
|
|
1213
|
+
logSuccess2(`Switched to sandbox ${sandbox.sandboxId}`);
|
|
1214
|
+
return {
|
|
1215
|
+
sandboxId: sandbox.sandboxId,
|
|
1216
|
+
provider: sandbox.provider,
|
|
1217
|
+
metadata: sandbox.getInstance().config.metadata || {}
|
|
1218
|
+
};
|
|
1219
|
+
};
|
|
1220
|
+
replServer.context.findOrCreate = async (options) => {
|
|
1221
|
+
if (state.useDirectMode) {
|
|
1222
|
+
throw new Error('Named sandboxes (findOrCreate) are only available in gateway mode. Use "mode gateway" to switch.');
|
|
1223
|
+
}
|
|
1224
|
+
const { getComputeInstance: getComputeInstance2, confirmSandboxSwitch: confirmSandboxSwitch2 } = await Promise.resolve().then(() => (init_commands(), commands_exports));
|
|
1225
|
+
const { setSandbox: setSandbox2 } = await Promise.resolve().then(() => (init_state(), state_exports));
|
|
1226
|
+
const { logSuccess: logSuccess2 } = await Promise.resolve().then(() => (init_output(), output_exports));
|
|
1227
|
+
const shouldSwitch = await confirmSandboxSwitch2(state);
|
|
1228
|
+
if (!shouldSwitch) {
|
|
1229
|
+
const compute3 = await getComputeInstance2(state);
|
|
1230
|
+
const sandbox2 = await compute3.sandbox.findOrCreate(options);
|
|
1231
|
+
return {
|
|
1232
|
+
sandboxId: sandbox2.sandboxId,
|
|
1233
|
+
provider: sandbox2.provider,
|
|
1234
|
+
name: options.name,
|
|
1235
|
+
namespace: options.namespace || "default",
|
|
1236
|
+
metadata: sandbox2.getInstance().config.metadata || {}
|
|
1237
|
+
};
|
|
1238
|
+
}
|
|
1239
|
+
const compute2 = await getComputeInstance2(state);
|
|
1240
|
+
const sandbox = await compute2.sandbox.findOrCreate(options);
|
|
1241
|
+
setSandbox2(state, sandbox, sandbox.provider);
|
|
1242
|
+
logSuccess2(`Switched to sandbox ${sandbox.sandboxId}`);
|
|
1243
|
+
return {
|
|
1244
|
+
sandboxId: sandbox.sandboxId,
|
|
1245
|
+
provider: sandbox.provider,
|
|
1246
|
+
name: options.name,
|
|
1247
|
+
namespace: options.namespace || "default",
|
|
1248
|
+
metadata: sandbox.getInstance().config.metadata || {}
|
|
1249
|
+
};
|
|
1250
|
+
};
|
|
1251
|
+
replServer.context.find = async (options) => {
|
|
1252
|
+
if (state.useDirectMode) {
|
|
1253
|
+
throw new Error('Named sandboxes (find) are only available in gateway mode. Use "mode gateway" to switch.');
|
|
1254
|
+
}
|
|
1255
|
+
const { getComputeInstance: getComputeInstance2, confirmSandboxSwitch: confirmSandboxSwitch2 } = await Promise.resolve().then(() => (init_commands(), commands_exports));
|
|
1256
|
+
const { setSandbox: setSandbox2 } = await Promise.resolve().then(() => (init_state(), state_exports));
|
|
1257
|
+
const { logSuccess: logSuccess2 } = await Promise.resolve().then(() => (init_output(), output_exports));
|
|
1258
|
+
const compute2 = await getComputeInstance2(state);
|
|
1259
|
+
const sandbox = await compute2.sandbox.find(options);
|
|
1260
|
+
if (!sandbox) {
|
|
1261
|
+
return null;
|
|
1262
|
+
}
|
|
1263
|
+
const shouldSwitch = await confirmSandboxSwitch2(state);
|
|
1264
|
+
if (!shouldSwitch) {
|
|
1265
|
+
return {
|
|
1266
|
+
sandboxId: sandbox.sandboxId,
|
|
1267
|
+
provider: sandbox.provider,
|
|
1268
|
+
name: options.name,
|
|
1269
|
+
namespace: options.namespace || "default",
|
|
1270
|
+
metadata: sandbox.getInstance().config.metadata || {}
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1273
|
+
setSandbox2(state, sandbox, sandbox.provider);
|
|
1274
|
+
logSuccess2(`Switched to sandbox ${sandbox.sandboxId}`);
|
|
1275
|
+
return {
|
|
1276
|
+
sandboxId: sandbox.sandboxId,
|
|
1277
|
+
provider: sandbox.provider,
|
|
1278
|
+
name: options.name,
|
|
1279
|
+
namespace: options.namespace || "default",
|
|
1280
|
+
metadata: sandbox.getInstance().config.metadata || {}
|
|
1281
|
+
};
|
|
1282
|
+
};
|
|
987
1283
|
replServer.context.filesystem = {
|
|
988
1284
|
get readFile() {
|
|
989
1285
|
return async (path4) => {
|
|
@@ -1040,6 +1336,60 @@ function injectWorkbenchCommands(replServer, state) {
|
|
|
1040
1336
|
};
|
|
1041
1337
|
}
|
|
1042
1338
|
};
|
|
1339
|
+
replServer.context.child = {
|
|
1340
|
+
get create() {
|
|
1341
|
+
return async () => {
|
|
1342
|
+
if (state.useDirectMode) {
|
|
1343
|
+
throw new Error('Child sandboxes are only available in gateway mode. Use "mode gateway" to switch.');
|
|
1344
|
+
}
|
|
1345
|
+
const sandbox = state.currentSandbox;
|
|
1346
|
+
if (!sandbox) {
|
|
1347
|
+
throw new Error("No active sandbox. Run a command to auto-create one.");
|
|
1348
|
+
}
|
|
1349
|
+
const instance = sandbox.getInstance();
|
|
1350
|
+
return instance.child.create();
|
|
1351
|
+
};
|
|
1352
|
+
},
|
|
1353
|
+
get list() {
|
|
1354
|
+
return async () => {
|
|
1355
|
+
if (state.useDirectMode) {
|
|
1356
|
+
throw new Error('Child sandboxes are only available in gateway mode. Use "mode gateway" to switch.');
|
|
1357
|
+
}
|
|
1358
|
+
const sandbox = state.currentSandbox;
|
|
1359
|
+
if (!sandbox) {
|
|
1360
|
+
throw new Error("No active sandbox. Run a command to auto-create one.");
|
|
1361
|
+
}
|
|
1362
|
+
const instance = sandbox.getInstance();
|
|
1363
|
+
return instance.child.list();
|
|
1364
|
+
};
|
|
1365
|
+
},
|
|
1366
|
+
get retrieve() {
|
|
1367
|
+
return async (subdomain) => {
|
|
1368
|
+
if (state.useDirectMode) {
|
|
1369
|
+
throw new Error('Child sandboxes are only available in gateway mode. Use "mode gateway" to switch.');
|
|
1370
|
+
}
|
|
1371
|
+
const sandbox = state.currentSandbox;
|
|
1372
|
+
if (!sandbox) {
|
|
1373
|
+
throw new Error("No active sandbox. Run a command to auto-create one.");
|
|
1374
|
+
}
|
|
1375
|
+
const instance = sandbox.getInstance();
|
|
1376
|
+
return instance.child.retrieve(subdomain);
|
|
1377
|
+
};
|
|
1378
|
+
},
|
|
1379
|
+
get destroy() {
|
|
1380
|
+
return async (subdomain, options) => {
|
|
1381
|
+
if (state.useDirectMode) {
|
|
1382
|
+
throw new Error('Child sandboxes are only available in gateway mode. Use "mode gateway" to switch.');
|
|
1383
|
+
}
|
|
1384
|
+
const sandbox = state.currentSandbox;
|
|
1385
|
+
if (!sandbox) {
|
|
1386
|
+
throw new Error("No active sandbox. Run a command to auto-create one.");
|
|
1387
|
+
}
|
|
1388
|
+
const instance = sandbox.getInstance();
|
|
1389
|
+
return instance.child.destroy(subdomain, options);
|
|
1390
|
+
};
|
|
1391
|
+
}
|
|
1392
|
+
};
|
|
1043
1393
|
replServer.context.getInstance = () => {
|
|
1044
1394
|
const sandbox = state.currentSandbox;
|
|
1045
1395
|
if (!sandbox) {
|
|
@@ -1050,7 +1400,7 @@ function injectWorkbenchCommands(replServer, state) {
|
|
|
1050
1400
|
}
|
|
1051
1401
|
function setupSmartEvaluator(replServer, state) {
|
|
1052
1402
|
const originalEval = replServer.eval;
|
|
1053
|
-
const workbenchCommands = /* @__PURE__ */ new Set(["help", "providers", "info", "env", "restart", "destroy", "mode", "verbose", "sandboxInfo"]);
|
|
1403
|
+
const workbenchCommands = /* @__PURE__ */ new Set(["help", "providers", "info", "env", "restart", "destroy", "mode", "verbose", "sandboxInfo", "connect"]);
|
|
1054
1404
|
replServer.eval = function(cmd3, context, filename, callback) {
|
|
1055
1405
|
const trimmedCmd = cmd3.trim();
|
|
1056
1406
|
const providerMatch = trimmedCmd.match(/^provider(?:\s+(direct|gateway))?\s+(\w+)$/);
|
|
@@ -1131,6 +1481,8 @@ function setupAutocomplete(replServer, state) {
|
|
|
1131
1481
|
"providers": [],
|
|
1132
1482
|
"restart": [],
|
|
1133
1483
|
"destroy": [],
|
|
1484
|
+
"connect": [],
|
|
1485
|
+
// Connect takes a URL argument
|
|
1134
1486
|
"info": [],
|
|
1135
1487
|
"env": [],
|
|
1136
1488
|
"help": [],
|
|
@@ -1224,6 +1576,9 @@ function setupHistory(replServer) {
|
|
|
1224
1576
|
}
|
|
1225
1577
|
|
|
1226
1578
|
// src/cli/index.ts
|
|
1579
|
+
init_output();
|
|
1580
|
+
init_providers();
|
|
1581
|
+
init_commands();
|
|
1227
1582
|
async function startWorkbench() {
|
|
1228
1583
|
const state = createState();
|
|
1229
1584
|
state.availableProviders = getAvailableProviders();
|