@computesdk/workbench 0.1.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -10
- package/dist/bin/workbench.js +299 -117
- package/dist/bin/workbench.js.map +1 -1
- package/dist/index.js +274 -113
- package/dist/index.js.map +1 -1
- package/package.json +12 -12
- package/src/bin/workbench-ts.ts +16 -2
package/dist/index.js
CHANGED
|
@@ -5,7 +5,8 @@ function createState() {
|
|
|
5
5
|
currentSandbox: null,
|
|
6
6
|
sandboxCreatedAt: null,
|
|
7
7
|
availableProviders: [],
|
|
8
|
-
|
|
8
|
+
useDirectMode: false,
|
|
9
|
+
// Default to gateway mode
|
|
9
10
|
verbose: false
|
|
10
11
|
};
|
|
11
12
|
}
|
|
@@ -74,16 +75,22 @@ var c = {
|
|
|
74
75
|
blue: (text) => `${colors.blue}${text}${colors.reset}`,
|
|
75
76
|
magenta: (text) => `${colors.magenta}${text}${colors.reset}`
|
|
76
77
|
};
|
|
77
|
-
function showWelcome(availableProviders, currentProvider) {
|
|
78
|
+
function showWelcome(availableProviders, currentProvider, useDirectMode) {
|
|
78
79
|
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")));
|
|
79
80
|
console.log(c.bold(c.cyan("\u2551 ComputeSDK Workbench \u2551")));
|
|
80
81
|
console.log(c.bold(c.cyan("\u255A\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\u255D\n")));
|
|
81
82
|
if (availableProviders.length > 0) {
|
|
82
|
-
|
|
83
|
+
const backendProviders = availableProviders.filter((p) => p !== "gateway");
|
|
84
|
+
console.log(`Providers available: ${backendProviders.join(", ")}`);
|
|
83
85
|
if (currentProvider) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
+
if (useDirectMode) {
|
|
87
|
+
console.log(`Current provider: ${c.green(currentProvider)} (\u{1F517} direct mode)
|
|
86
88
|
`);
|
|
89
|
+
} else {
|
|
90
|
+
const backendProvider = currentProvider === "gateway" ? backendProviders[0] || "auto" : currentProvider;
|
|
91
|
+
console.log(`Current provider: ${c.green(backendProvider)} (\u{1F310} via gateway)
|
|
92
|
+
`);
|
|
93
|
+
}
|
|
87
94
|
} else {
|
|
88
95
|
console.log(`
|
|
89
96
|
${c.dim('Tip: Use "provider <name>" to select a provider')}
|
|
@@ -99,58 +106,6 @@ ${c.dim('Tip: Use "provider <name>" to select a provider')}
|
|
|
99
106
|
}
|
|
100
107
|
console.log(c.dim('Type "help" for available commands\n'));
|
|
101
108
|
}
|
|
102
|
-
function showHelp() {
|
|
103
|
-
console.log(`
|
|
104
|
-
${c.bold("Workbench Commands:")}
|
|
105
|
-
${c.cyan("provider <name>")} Switch provider (gateway, e2b, railway, etc.)
|
|
106
|
-
${c.cyan("providers")} List all providers with status
|
|
107
|
-
${c.cyan("mode")} Show current mode (gateway vs direct)
|
|
108
|
-
${c.cyan("mode gateway")} Force gateway mode
|
|
109
|
-
${c.cyan("mode direct")} Force direct mode (auto-detect provider)
|
|
110
|
-
${c.cyan("restart")} Restart current sandbox
|
|
111
|
-
${c.cyan("destroy")} Destroy current sandbox
|
|
112
|
-
${c.cyan("info")} Show sandbox info
|
|
113
|
-
${c.cyan("env")} Show environment/credentials status
|
|
114
|
-
${c.cyan("verbose")} Toggle verbose output (show full results)
|
|
115
|
-
${c.cyan("help")} Show this help
|
|
116
|
-
${c.cyan("exit")} or ${c.cyan(".exit")} Exit workbench
|
|
117
|
-
|
|
118
|
-
${c.bold("Provider Modes:")}
|
|
119
|
-
${c.cyan("gateway")} \u{1F310} Routes through ComputeSDK API (COMPUTESDK_API_KEY)
|
|
120
|
-
${c.cyan("e2b, railway, etc.")} \u{1F517} Direct connection to provider (requires provider package)
|
|
121
|
-
|
|
122
|
-
${c.bold("Running Commands:")}
|
|
123
|
-
Just type any ${c.cyan("@computesdk/cmd")} function:
|
|
124
|
-
${c.dim('npm.install("express")')}
|
|
125
|
-
${c.dim('git.clone("https://github.com/user/repo")')}
|
|
126
|
-
${c.dim('python("script.py")')}
|
|
127
|
-
${c.dim('mkdir("/app/src")')}
|
|
128
|
-
${c.dim('ls("/home")')}
|
|
129
|
-
|
|
130
|
-
${c.green("\u2728 Tab autocomplete works for all functions!")}
|
|
131
|
-
|
|
132
|
-
${c.bold("Background Execution:")}
|
|
133
|
-
Run commands in the background (returns immediately):
|
|
134
|
-
${c.dim('sh("sleep 10", { background: true })')}
|
|
135
|
-
${c.dim('sh("npm start", { background: true })')}
|
|
136
|
-
|
|
137
|
-
${c.bold("Examples:")}
|
|
138
|
-
${c.dim("# Install a package")}
|
|
139
|
-
${c.cyan('npm.install("express")')}
|
|
140
|
-
|
|
141
|
-
${c.dim("# Clone a repo")}
|
|
142
|
-
${c.cyan('git.clone("https://github.com/user/repo")')}
|
|
143
|
-
|
|
144
|
-
${c.dim("# Run Python code")}
|
|
145
|
-
${c.cyan(`python("-c", "print('hello')")`)}
|
|
146
|
-
|
|
147
|
-
${c.dim("# Start a server in background")}
|
|
148
|
-
${c.cyan('sh("python -m http.server 8000", { background: true })')}
|
|
149
|
-
|
|
150
|
-
${c.dim("# Switch providers")}
|
|
151
|
-
${c.cyan("provider railway")}
|
|
152
|
-
`);
|
|
153
|
-
}
|
|
154
109
|
function showInfo(state) {
|
|
155
110
|
if (!state.currentSandbox) {
|
|
156
111
|
console.log(c.yellow("\nNo active sandbox\n"));
|
|
@@ -209,6 +164,64 @@ function logSuccess(message, duration) {
|
|
|
209
164
|
const durationStr = duration ? ` (${formatDuration(duration)})` : "";
|
|
210
165
|
console.log(c.green(`\u2705 ${message}${durationStr}`));
|
|
211
166
|
}
|
|
167
|
+
function showHelp() {
|
|
168
|
+
console.log(`
|
|
169
|
+
${c.bold("ComputeSDK Workbench Commands")}
|
|
170
|
+
|
|
171
|
+
${c.bold("Provider Management:")}
|
|
172
|
+
${c.cyan("provider <name>")} Switch to provider via gateway (default)
|
|
173
|
+
${c.dim("Example: provider e2b")}
|
|
174
|
+
${c.cyan("provider direct <name>")} Connect directly to provider
|
|
175
|
+
${c.dim("Example: provider direct e2b")}
|
|
176
|
+
${c.cyan("providers")} List all providers with status
|
|
177
|
+
${c.cyan("mode <gateway|direct>")} Toggle default mode for next sandbox
|
|
178
|
+
|
|
179
|
+
${c.bold("Provider Modes:")}
|
|
180
|
+
${c.bold("Gateway (default)")}: Routes through ComputeSDK API, zero-config
|
|
181
|
+
\u2022 Requires: COMPUTESDK_API_KEY + provider credentials
|
|
182
|
+
\u2022 Usage: ${c.cyan("provider e2b")}
|
|
183
|
+
|
|
184
|
+
${c.bold("Direct")}: Connects directly to provider, requires packages
|
|
185
|
+
\u2022 Requires: Provider package installed + credentials
|
|
186
|
+
\u2022 Usage: ${c.cyan("provider direct e2b")}
|
|
187
|
+
|
|
188
|
+
${c.bold("Sandbox Management:")}
|
|
189
|
+
${c.cyan("restart")} Restart current sandbox
|
|
190
|
+
${c.cyan("destroy")} Destroy current sandbox
|
|
191
|
+
${c.cyan("info")} Show sandbox info (provider, uptime)
|
|
192
|
+
|
|
193
|
+
${c.bold("Environment:")}
|
|
194
|
+
${c.cyan("env")} Show environment/credentials status
|
|
195
|
+
${c.cyan("verbose")} Toggle verbose output mode
|
|
196
|
+
|
|
197
|
+
${c.bold("Help:")}
|
|
198
|
+
${c.cyan("help")} Show this help message
|
|
199
|
+
${c.cyan("exit")} or ${c.cyan(".exit")} Exit workbench
|
|
200
|
+
|
|
201
|
+
${c.bold("Running Commands:")}
|
|
202
|
+
Type any @computesdk/cmd function and it will run automatically:
|
|
203
|
+
|
|
204
|
+
${c.dim("Package Managers:")}
|
|
205
|
+
${c.cyan('npm.install("express")')}
|
|
206
|
+
${c.cyan('pip.install("requests")')}
|
|
207
|
+
|
|
208
|
+
${c.dim("Git:")}
|
|
209
|
+
${c.cyan('git.clone("https://github.com/user/repo")')}
|
|
210
|
+
${c.cyan("git.status()")}
|
|
211
|
+
|
|
212
|
+
${c.dim("Filesystem:")}
|
|
213
|
+
${c.cyan('ls("/home")')}
|
|
214
|
+
${c.cyan('cat("/etc/hosts")')}
|
|
215
|
+
${c.cyan('rm.rf("/tmp")')} ${c.dim("// Force remove")}
|
|
216
|
+
${c.cyan('rm.auto("/path")')} ${c.dim("// Smart remove")}
|
|
217
|
+
|
|
218
|
+
${c.bold("Background Execution:")}
|
|
219
|
+
${c.cyan('sh("npm start", { background: true })')}
|
|
220
|
+
${c.cyan('sh("python -m http.server 8000", { background: true })')}
|
|
221
|
+
|
|
222
|
+
${c.dim("Press Tab for autocomplete on all commands!")}
|
|
223
|
+
`);
|
|
224
|
+
}
|
|
212
225
|
function logError(message) {
|
|
213
226
|
console.log(c.red(`\u274C ${message}`));
|
|
214
227
|
}
|
|
@@ -390,12 +403,44 @@ async function loadProvider(providerName) {
|
|
|
390
403
|
}
|
|
391
404
|
function getProviderConfig(providerName) {
|
|
392
405
|
const config = {};
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
406
|
+
switch (providerName) {
|
|
407
|
+
case "e2b":
|
|
408
|
+
if (process.env.E2B_API_KEY) config.apiKey = process.env.E2B_API_KEY;
|
|
409
|
+
break;
|
|
410
|
+
case "railway":
|
|
411
|
+
if (process.env.RAILWAY_API_KEY) config.apiKey = process.env.RAILWAY_API_KEY;
|
|
412
|
+
if (process.env.RAILWAY_PROJECT_ID) config.projectId = process.env.RAILWAY_PROJECT_ID;
|
|
413
|
+
if (process.env.RAILWAY_ENVIRONMENT_ID) config.environmentId = process.env.RAILWAY_ENVIRONMENT_ID;
|
|
414
|
+
break;
|
|
415
|
+
case "daytona":
|
|
416
|
+
if (process.env.DAYTONA_API_KEY) config.apiKey = process.env.DAYTONA_API_KEY;
|
|
417
|
+
break;
|
|
418
|
+
case "modal":
|
|
419
|
+
if (process.env.MODAL_TOKEN_ID) config.tokenId = process.env.MODAL_TOKEN_ID;
|
|
420
|
+
if (process.env.MODAL_TOKEN_SECRET) config.tokenSecret = process.env.MODAL_TOKEN_SECRET;
|
|
421
|
+
break;
|
|
422
|
+
case "runloop":
|
|
423
|
+
if (process.env.RUNLOOP_API_KEY) config.apiKey = process.env.RUNLOOP_API_KEY;
|
|
424
|
+
break;
|
|
425
|
+
case "vercel":
|
|
426
|
+
if (process.env.VERCEL_TOKEN) config.token = process.env.VERCEL_TOKEN;
|
|
427
|
+
if (process.env.VERCEL_TEAM_ID) config.teamId = process.env.VERCEL_TEAM_ID;
|
|
428
|
+
if (process.env.VERCEL_PROJECT_ID) config.projectId = process.env.VERCEL_PROJECT_ID;
|
|
429
|
+
break;
|
|
430
|
+
case "cloudflare":
|
|
431
|
+
if (process.env.CLOUDFLARE_API_TOKEN) config.apiToken = process.env.CLOUDFLARE_API_TOKEN;
|
|
432
|
+
if (process.env.CLOUDFLARE_ACCOUNT_ID) config.accountId = process.env.CLOUDFLARE_ACCOUNT_ID;
|
|
433
|
+
break;
|
|
434
|
+
case "codesandbox":
|
|
435
|
+
if (process.env.CSB_API_KEY) config.apiKey = process.env.CSB_API_KEY;
|
|
436
|
+
break;
|
|
437
|
+
case "blaxel":
|
|
438
|
+
if (process.env.BL_API_KEY) config.apiKey = process.env.BL_API_KEY;
|
|
439
|
+
if (process.env.BL_WORKSPACE) config.workspace = process.env.BL_WORKSPACE;
|
|
440
|
+
break;
|
|
441
|
+
case "gateway":
|
|
442
|
+
if (process.env.COMPUTESDK_API_KEY) config.apiKey = process.env.COMPUTESDK_API_KEY;
|
|
443
|
+
break;
|
|
399
444
|
}
|
|
400
445
|
return config;
|
|
401
446
|
}
|
|
@@ -423,23 +468,36 @@ async function ensureSandbox(state) {
|
|
|
423
468
|
await createSandbox(state);
|
|
424
469
|
}
|
|
425
470
|
async function createSandbox(state) {
|
|
426
|
-
const providerName = state.currentProvider || autoDetectProvider(
|
|
471
|
+
const providerName = state.currentProvider || autoDetectProvider(false);
|
|
472
|
+
const useDirect = state.useDirectMode;
|
|
427
473
|
if (!providerName) {
|
|
428
474
|
logError('No provider configured. Run "env" to see setup instructions.');
|
|
429
475
|
throw new Error("No provider available");
|
|
430
476
|
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
477
|
+
let modeLabel;
|
|
478
|
+
let actualProviderName;
|
|
479
|
+
if (useDirect) {
|
|
480
|
+
modeLabel = `${providerName} (direct)`;
|
|
481
|
+
actualProviderName = providerName;
|
|
482
|
+
if (!isProviderReady(providerName)) {
|
|
483
|
+
logError(`Provider ${providerName} is not fully configured for direct mode.`);
|
|
484
|
+
console.log(getProviderSetupHelp(providerName));
|
|
485
|
+
throw new Error("Provider not ready");
|
|
486
|
+
}
|
|
487
|
+
} else {
|
|
488
|
+
modeLabel = `${providerName} (via gateway)`;
|
|
489
|
+
actualProviderName = "gateway";
|
|
490
|
+
if (!isProviderReady("gateway")) {
|
|
491
|
+
logError("Gateway mode requires COMPUTESDK_API_KEY");
|
|
492
|
+
console.log(getProviderSetupHelp("gateway"));
|
|
493
|
+
throw new Error("Gateway not ready");
|
|
494
|
+
}
|
|
435
495
|
}
|
|
436
|
-
const spinner = new Spinner(`Creating sandbox with ${
|
|
496
|
+
const spinner = new Spinner(`Creating sandbox with ${modeLabel}...`).start();
|
|
437
497
|
const startTime = Date.now();
|
|
438
498
|
try {
|
|
439
499
|
let compute;
|
|
440
|
-
if (
|
|
441
|
-
compute = createCompute();
|
|
442
|
-
} else {
|
|
500
|
+
if (useDirect) {
|
|
443
501
|
const providerModule = await loadProvider(providerName);
|
|
444
502
|
const providerFactory = providerModule[providerName];
|
|
445
503
|
if (!providerFactory) {
|
|
@@ -449,6 +507,43 @@ async function createSandbox(state) {
|
|
|
449
507
|
compute = createCompute({
|
|
450
508
|
defaultProvider: providerFactory(config)
|
|
451
509
|
});
|
|
510
|
+
} else {
|
|
511
|
+
const gatewayModule = await import("computesdk");
|
|
512
|
+
const gatewayFactory = gatewayModule.gateway;
|
|
513
|
+
const providerConfig = getProviderConfig(providerName);
|
|
514
|
+
const providerHeaders = {};
|
|
515
|
+
switch (providerName) {
|
|
516
|
+
case "e2b":
|
|
517
|
+
if (providerConfig.apiKey) providerHeaders["X-E2B-API-Key"] = providerConfig.apiKey;
|
|
518
|
+
break;
|
|
519
|
+
case "railway":
|
|
520
|
+
if (providerConfig.apiKey) providerHeaders["X-Railway-API-Key"] = providerConfig.apiKey;
|
|
521
|
+
if (providerConfig.projectId) providerHeaders["X-Railway-Project-ID"] = providerConfig.projectId;
|
|
522
|
+
if (providerConfig.environmentId) providerHeaders["X-Railway-Environment-ID"] = providerConfig.environmentId;
|
|
523
|
+
break;
|
|
524
|
+
case "daytona":
|
|
525
|
+
if (providerConfig.apiKey) providerHeaders["X-Daytona-API-Key"] = providerConfig.apiKey;
|
|
526
|
+
break;
|
|
527
|
+
case "modal":
|
|
528
|
+
if (providerConfig.tokenId) providerHeaders["X-Modal-Token-ID"] = providerConfig.tokenId;
|
|
529
|
+
if (providerConfig.tokenSecret) providerHeaders["X-Modal-Token-Secret"] = providerConfig.tokenSecret;
|
|
530
|
+
break;
|
|
531
|
+
case "vercel":
|
|
532
|
+
if (providerConfig.token) providerHeaders["X-Vercel-Token"] = providerConfig.token;
|
|
533
|
+
if (providerConfig.teamId) providerHeaders["X-Vercel-Team-ID"] = providerConfig.teamId;
|
|
534
|
+
if (providerConfig.projectId) providerHeaders["X-Vercel-Project-ID"] = providerConfig.projectId;
|
|
535
|
+
break;
|
|
536
|
+
}
|
|
537
|
+
const config = {
|
|
538
|
+
apiKey: process.env.COMPUTESDK_API_KEY,
|
|
539
|
+
provider: providerName,
|
|
540
|
+
// Tell gateway which backend to use
|
|
541
|
+
providerHeaders
|
|
542
|
+
// Pass provider credentials via headers
|
|
543
|
+
};
|
|
544
|
+
compute = createCompute({
|
|
545
|
+
defaultProvider: gatewayFactory(config)
|
|
546
|
+
});
|
|
452
547
|
}
|
|
453
548
|
const result = await compute.sandbox.create();
|
|
454
549
|
const duration = Date.now() - startTime;
|
|
@@ -463,6 +558,12 @@ async function createSandbox(state) {
|
|
|
463
558
|
Install it with: ${c.cyan(`npm install @computesdk/${providerName}`)}
|
|
464
559
|
`);
|
|
465
560
|
}
|
|
561
|
+
if (error instanceof Error) {
|
|
562
|
+
logError(`Error: ${error.message}`);
|
|
563
|
+
if (error.stack) {
|
|
564
|
+
console.log(c.dim(error.stack));
|
|
565
|
+
}
|
|
566
|
+
}
|
|
466
567
|
throw error;
|
|
467
568
|
}
|
|
468
569
|
}
|
|
@@ -518,68 +619,100 @@ async function runCommand(state, command) {
|
|
|
518
619
|
throw error;
|
|
519
620
|
}
|
|
520
621
|
}
|
|
521
|
-
async function switchProvider(state,
|
|
522
|
-
|
|
523
|
-
|
|
622
|
+
async function switchProvider(state, mode, providerName) {
|
|
623
|
+
let useDirect = false;
|
|
624
|
+
let actualProvider = mode;
|
|
625
|
+
if (mode === "direct") {
|
|
626
|
+
if (!providerName) {
|
|
627
|
+
logError("Usage: provider direct <name>");
|
|
628
|
+
console.log("Example: provider direct e2b");
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
useDirect = true;
|
|
632
|
+
actualProvider = providerName;
|
|
633
|
+
} else if (mode === "gateway") {
|
|
634
|
+
if (!providerName) {
|
|
635
|
+
logError("Usage: provider gateway <name>");
|
|
636
|
+
console.log("Example: provider gateway e2b");
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
useDirect = false;
|
|
640
|
+
actualProvider = providerName;
|
|
641
|
+
}
|
|
642
|
+
if (actualProvider === "gateway") {
|
|
643
|
+
actualProvider = autoDetectProvider(false) || "e2b";
|
|
644
|
+
}
|
|
645
|
+
if (!isValidProvider(actualProvider)) {
|
|
646
|
+
logError(`Unknown provider: ${actualProvider}`);
|
|
524
647
|
console.log(`Available providers: e2b, railway, daytona, modal, runloop, vercel, cloudflare, codesandbox, blaxel`);
|
|
525
648
|
return;
|
|
526
649
|
}
|
|
527
|
-
if (!isProviderReady(
|
|
528
|
-
logError(
|
|
529
|
-
console.log(getProviderSetupHelp(
|
|
650
|
+
if (!useDirect && !isProviderReady("gateway")) {
|
|
651
|
+
logError("Gateway mode requires COMPUTESDK_API_KEY");
|
|
652
|
+
console.log(getProviderSetupHelp("gateway"));
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
if (useDirect && !isProviderReady(actualProvider)) {
|
|
656
|
+
logError(`Provider ${actualProvider} is not fully configured for direct mode.`);
|
|
657
|
+
console.log(getProviderSetupHelp(actualProvider));
|
|
530
658
|
return;
|
|
531
659
|
}
|
|
532
660
|
if (hasSandbox(state)) {
|
|
533
661
|
const shouldDestroy = await confirm("Destroy current sandbox?");
|
|
534
662
|
if (shouldDestroy) {
|
|
535
663
|
await destroySandbox(state);
|
|
536
|
-
state.currentProvider =
|
|
537
|
-
|
|
664
|
+
state.currentProvider = actualProvider;
|
|
665
|
+
state.useDirectMode = useDirect;
|
|
666
|
+
const modeStr = useDirect ? `${actualProvider} (direct)` : `${actualProvider} (via gateway)`;
|
|
667
|
+
logSuccess(`Switched to ${modeStr}`);
|
|
538
668
|
} else {
|
|
539
669
|
logWarning("Keeping current sandbox. Provider remains unchanged.");
|
|
540
670
|
}
|
|
541
671
|
} else {
|
|
542
|
-
state.currentProvider =
|
|
543
|
-
|
|
672
|
+
state.currentProvider = actualProvider;
|
|
673
|
+
state.useDirectMode = useDirect;
|
|
674
|
+
const modeStr = useDirect ? `${actualProvider} (direct)` : `${actualProvider} (via gateway)`;
|
|
675
|
+
logSuccess(`Switched to ${modeStr}`);
|
|
544
676
|
}
|
|
545
677
|
}
|
|
546
678
|
function createProviderCommand(state) {
|
|
547
|
-
return async function provider(
|
|
548
|
-
if (!
|
|
679
|
+
return async function provider(mode, providerName) {
|
|
680
|
+
if (!mode) {
|
|
549
681
|
if (state.currentProvider) {
|
|
682
|
+
const modeStr = state.useDirectMode ? "direct" : "via gateway";
|
|
550
683
|
console.log(`
|
|
551
|
-
Current provider: ${c.green(state.currentProvider)}
|
|
684
|
+
Current provider: ${c.green(state.currentProvider)} (${modeStr})
|
|
552
685
|
`);
|
|
553
686
|
} else {
|
|
554
687
|
console.log(c.yellow("\nNo provider selected\n"));
|
|
555
688
|
}
|
|
556
689
|
return;
|
|
557
690
|
}
|
|
558
|
-
await switchProvider(state,
|
|
691
|
+
await switchProvider(state, mode, providerName);
|
|
559
692
|
};
|
|
560
693
|
}
|
|
561
694
|
async function toggleMode(state, mode) {
|
|
562
|
-
const newMode = mode || (state.
|
|
563
|
-
if (newMode === "
|
|
564
|
-
state.
|
|
565
|
-
logSuccess("Switched to gateway mode \u{1F310}");
|
|
566
|
-
console.log(c.dim("Next sandbox will use gateway (requires COMPUTESDK_API_KEY)\n"));
|
|
567
|
-
if (hasSandbox(state) && state.currentProvider !== "gateway") {
|
|
568
|
-
console.log(c.yellow("Current sandbox is in direct mode."));
|
|
569
|
-
console.log(c.dim('Run "restart" to switch to gateway mode\n'));
|
|
570
|
-
}
|
|
571
|
-
} else {
|
|
572
|
-
state.forceGatewayMode = false;
|
|
695
|
+
const newMode = mode || (state.useDirectMode ? "gateway" : "direct");
|
|
696
|
+
if (newMode === "direct") {
|
|
697
|
+
state.useDirectMode = true;
|
|
573
698
|
logSuccess("Switched to direct mode \u{1F517}");
|
|
574
699
|
console.log(c.dim("Next sandbox will use direct provider packages\n"));
|
|
575
|
-
if (hasSandbox(state) && state.
|
|
700
|
+
if (hasSandbox(state) && !state.useDirectMode) {
|
|
576
701
|
console.log(c.yellow("Current sandbox is in gateway mode."));
|
|
577
702
|
console.log(c.dim('Run "restart" to switch to direct mode\n'));
|
|
578
703
|
}
|
|
704
|
+
} else {
|
|
705
|
+
state.useDirectMode = false;
|
|
706
|
+
logSuccess("Switched to gateway mode \u{1F310}");
|
|
707
|
+
console.log(c.dim("Next sandbox will use gateway (requires COMPUTESDK_API_KEY)\n"));
|
|
708
|
+
if (hasSandbox(state) && state.useDirectMode) {
|
|
709
|
+
console.log(c.yellow("Current sandbox is in direct mode."));
|
|
710
|
+
console.log(c.dim('Run "restart" to switch to gateway mode\n'));
|
|
711
|
+
}
|
|
579
712
|
}
|
|
580
713
|
}
|
|
581
714
|
function showMode(state) {
|
|
582
|
-
const mode = state.
|
|
715
|
+
const mode = state.useDirectMode ? "direct" : "gateway";
|
|
583
716
|
const icon = mode === "gateway" ? "\u{1F310}" : "\u{1F517}";
|
|
584
717
|
console.log(`
|
|
585
718
|
Current mode: ${c.green(mode)} ${icon}`);
|
|
@@ -589,7 +722,7 @@ Current mode: ${c.green(mode)} ${icon}`);
|
|
|
589
722
|
console.log(c.dim("Direct connection to providers (requires provider packages)"));
|
|
590
723
|
}
|
|
591
724
|
console.log(`
|
|
592
|
-
|
|
725
|
+
Switch with: ${c.cyan("provider e2b")} (gateway) or ${c.cyan("provider direct e2b")} (direct)
|
|
593
726
|
`);
|
|
594
727
|
}
|
|
595
728
|
function toggleVerbose(state) {
|
|
@@ -764,10 +897,18 @@ function setupSmartEvaluator(replServer, state) {
|
|
|
764
897
|
const workbenchCommands = /* @__PURE__ */ new Set(["help", "providers", "info", "env", "restart", "destroy", "mode", "verbose"]);
|
|
765
898
|
replServer.eval = function(cmd3, context, filename, callback) {
|
|
766
899
|
const trimmedCmd = cmd3.trim();
|
|
767
|
-
const providerMatch = trimmedCmd.match(/^provider
|
|
900
|
+
const providerMatch = trimmedCmd.match(/^provider(?:\s+(direct|gateway))?\s+(\w+)$/);
|
|
768
901
|
if (providerMatch) {
|
|
769
|
-
const
|
|
770
|
-
const
|
|
902
|
+
const mode = providerMatch[1] || null;
|
|
903
|
+
const providerName = providerMatch[2];
|
|
904
|
+
const providerCmd = mode ? `await provider('${mode}', '${providerName}')` : `await provider('${providerName}')`;
|
|
905
|
+
originalEval.call(this, providerCmd, context, filename, callback);
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
const providerOnlyMatch = trimmedCmd.match(/^provider\s+(direct|gateway)$/);
|
|
909
|
+
if (providerOnlyMatch) {
|
|
910
|
+
const mode = providerOnlyMatch[1];
|
|
911
|
+
const providerCmd = `await provider('${mode}')`;
|
|
771
912
|
originalEval.call(this, providerCmd, context, filename, callback);
|
|
772
913
|
return;
|
|
773
914
|
}
|
|
@@ -823,12 +964,17 @@ function setupAutocomplete(replServer, state) {
|
|
|
823
964
|
};
|
|
824
965
|
replServer.completer = function(line, callback) {
|
|
825
966
|
const trimmed = line.trim();
|
|
826
|
-
if (!
|
|
967
|
+
if (!line.includes(" ") && !line.includes(".")) {
|
|
827
968
|
const commands = Object.keys(workbenchCommands);
|
|
828
969
|
const hits = commands.filter((cmd3) => cmd3.startsWith(trimmed));
|
|
829
970
|
if (originalCompleter) {
|
|
830
|
-
originalCompleter.call(replServer, line, (err,
|
|
831
|
-
if (err) {
|
|
971
|
+
originalCompleter.call(replServer, line, (err, result) => {
|
|
972
|
+
if (err || !result) {
|
|
973
|
+
callback(null, [hits, trimmed]);
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
976
|
+
const [contextHits, partial] = result;
|
|
977
|
+
if (!Array.isArray(contextHits)) {
|
|
832
978
|
callback(null, [hits, trimmed]);
|
|
833
979
|
return;
|
|
834
980
|
}
|
|
@@ -840,18 +986,25 @@ function setupAutocomplete(replServer, state) {
|
|
|
840
986
|
callback(null, [hits.length ? hits : commands, trimmed]);
|
|
841
987
|
return;
|
|
842
988
|
}
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
const
|
|
989
|
+
if (line.includes(" ") && !line.includes(".")) {
|
|
990
|
+
const parts = line.split(" ");
|
|
991
|
+
const command = parts[0].trim();
|
|
992
|
+
const partial = parts.slice(1).join(" ").trim();
|
|
846
993
|
const suggestions = workbenchCommands[command];
|
|
847
994
|
if (suggestions && suggestions.length > 0) {
|
|
848
995
|
const hits = suggestions.filter((s) => s.startsWith(partial)).map((s) => `${command} ${s}`);
|
|
849
|
-
callback(null, [hits.length ? hits : suggestions.map((s) => `${command} ${s}`),
|
|
996
|
+
callback(null, [hits.length ? hits : suggestions.map((s) => `${command} ${s}`), line]);
|
|
850
997
|
return;
|
|
851
998
|
}
|
|
852
999
|
}
|
|
853
1000
|
if (originalCompleter) {
|
|
854
|
-
originalCompleter.call(replServer, line,
|
|
1001
|
+
originalCompleter.call(replServer, line, (err, result) => {
|
|
1002
|
+
if (err || !result) {
|
|
1003
|
+
callback(null, [[], line]);
|
|
1004
|
+
return;
|
|
1005
|
+
}
|
|
1006
|
+
callback(null, result);
|
|
1007
|
+
});
|
|
855
1008
|
} else {
|
|
856
1009
|
callback(null, [[], line]);
|
|
857
1010
|
}
|
|
@@ -869,8 +1022,16 @@ function setupHistory(replServer) {
|
|
|
869
1022
|
async function startWorkbench() {
|
|
870
1023
|
const state = createState();
|
|
871
1024
|
state.availableProviders = getAvailableProviders();
|
|
872
|
-
|
|
873
|
-
|
|
1025
|
+
const detectedProvider = autoDetectProvider();
|
|
1026
|
+
if (detectedProvider === "gateway") {
|
|
1027
|
+
const backendProviders = state.availableProviders.filter((p) => p !== "gateway");
|
|
1028
|
+
state.currentProvider = backendProviders[0] || "e2b";
|
|
1029
|
+
state.useDirectMode = false;
|
|
1030
|
+
} else {
|
|
1031
|
+
state.currentProvider = detectedProvider;
|
|
1032
|
+
state.useDirectMode = false;
|
|
1033
|
+
}
|
|
1034
|
+
showWelcome(state.availableProviders, state.currentProvider, state.useDirectMode);
|
|
874
1035
|
const replServer = createREPL(state);
|
|
875
1036
|
replServer.on("exit", async () => {
|
|
876
1037
|
await cleanupOnExit(state, replServer);
|