@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/dist/index.js CHANGED
@@ -1,4 +1,33 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __esm = (fn, res) => function __init() {
4
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
+ };
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+
11
+ // ../../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
12
+ import path from "path";
13
+ import { fileURLToPath } from "url";
14
+ var init_esm_shims = __esm({
15
+ "../../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"() {
16
+ "use strict";
17
+ }
18
+ });
19
+
1
20
  // src/cli/state.ts
21
+ var state_exports = {};
22
+ __export(state_exports, {
23
+ clearSandbox: () => clearSandbox,
24
+ createState: () => createState,
25
+ formatUptime: () => formatUptime,
26
+ getCurrentSandbox: () => getCurrentSandbox,
27
+ getUptimeSeconds: () => getUptimeSeconds,
28
+ hasSandbox: () => hasSandbox,
29
+ setSandbox: () => setSandbox
30
+ });
2
31
  function createState() {
3
32
  return {
4
33
  currentProvider: null,
@@ -7,7 +36,8 @@ function createState() {
7
36
  availableProviders: [],
8
37
  useDirectMode: false,
9
38
  // Default to gateway mode
10
- verbose: false
39
+ verbose: false,
40
+ compute: null
11
41
  };
12
42
  }
13
43
  function getCurrentSandbox(state) {
@@ -61,36 +91,28 @@ function formatUptime(state) {
61
91
  const remainingMinutes = minutes % 60;
62
92
  return `${hours}h ${remainingMinutes}m`;
63
93
  }
64
-
65
- // src/cli/repl.ts
66
- import * as repl from "repl";
67
- import * as cmd from "@computesdk/cmd";
68
-
69
- // src/cli/commands.ts
70
- import { createCompute } from "computesdk";
94
+ var init_state = __esm({
95
+ "src/cli/state.ts"() {
96
+ "use strict";
97
+ init_esm_shims();
98
+ }
99
+ });
71
100
 
72
101
  // src/cli/output.ts
73
- var colors = {
74
- reset: "\x1B[0m",
75
- bright: "\x1B[1m",
76
- dim: "\x1B[2m",
77
- cyan: "\x1B[36m",
78
- green: "\x1B[32m",
79
- yellow: "\x1B[33m",
80
- red: "\x1B[31m",
81
- blue: "\x1B[34m",
82
- magenta: "\x1B[35m"
83
- };
84
- var c = {
85
- bold: (text) => `${colors.bright}${text}${colors.reset}`,
86
- dim: (text) => `${colors.dim}${text}${colors.reset}`,
87
- cyan: (text) => `${colors.cyan}${text}${colors.reset}`,
88
- green: (text) => `${colors.green}${text}${colors.reset}`,
89
- yellow: (text) => `${colors.yellow}${text}${colors.reset}`,
90
- red: (text) => `${colors.red}${text}${colors.reset}`,
91
- blue: (text) => `${colors.blue}${text}${colors.reset}`,
92
- magenta: (text) => `${colors.magenta}${text}${colors.reset}`
93
- };
102
+ var output_exports = {};
103
+ __export(output_exports, {
104
+ Spinner: () => Spinner,
105
+ c: () => c,
106
+ formatDuration: () => formatDuration,
107
+ logCommand: () => logCommand,
108
+ logError: () => logError,
109
+ logInfo: () => logInfo,
110
+ logSuccess: () => logSuccess,
111
+ logWarning: () => logWarning,
112
+ showHelp: () => showHelp,
113
+ showInfo: () => showInfo,
114
+ showWelcome: () => showWelcome
115
+ });
94
116
  function showWelcome(availableProviders, currentProvider, useDirectMode) {
95
117
  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")));
96
118
  console.log(c.bold(c.cyan("\u2551 ComputeSDK Workbench \u2551")));
@@ -139,39 +161,6 @@ function showInfo(state) {
139
161
  console.log(` Uptime: ${formatUptime(state)}`);
140
162
  console.log("");
141
163
  }
142
- var Spinner = class {
143
- constructor(text) {
144
- this.interval = null;
145
- this.frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
146
- this.currentFrame = 0;
147
- this.text = text;
148
- }
149
- start() {
150
- process.stdout.write("\x1B[?25l");
151
- this.interval = setInterval(() => {
152
- const frame = this.frames[this.currentFrame];
153
- process.stdout.write(`\r${c.cyan(frame)} ${this.text}`);
154
- this.currentFrame = (this.currentFrame + 1) % this.frames.length;
155
- }, 80);
156
- return this;
157
- }
158
- succeed(text) {
159
- this.stop();
160
- console.log(`${c.green("\u2705")} ${text || this.text}`);
161
- }
162
- fail(text) {
163
- this.stop();
164
- console.log(`${c.red("\u274C")} ${text || this.text}`);
165
- }
166
- stop() {
167
- if (this.interval) {
168
- clearInterval(this.interval);
169
- this.interval = null;
170
- }
171
- process.stdout.write("\r\x1B[K");
172
- process.stdout.write("\x1B[?25h");
173
- }
174
- };
175
164
  function formatDuration(ms) {
176
165
  const seconds = ms / 1e3;
177
166
  if (seconds < 1) {
@@ -210,6 +199,9 @@ ${c.bold("Provider Modes:")}
210
199
  ${c.bold("Sandbox Management:")}
211
200
  ${c.cyan("restart")} Restart current sandbox
212
201
  ${c.cyan("destroy")} Destroy current sandbox
202
+ ${c.cyan("connect <url> [token]")} Connect to existing sandbox via URL
203
+ ${c.dim("Example: connect https://sandbox-123.localhost:8080")}
204
+ ${c.dim("Example: connect https://sandbox-123.localhost:8080 your_token")}
213
205
  ${c.cyan("info")} Show sandbox info (provider, uptime)
214
206
 
215
207
  ${c.bold("Environment:")}
@@ -245,6 +237,20 @@ ${c.bold("Running Commands:")}
245
237
  ${c.cyan('filesystem.exists("/path")')}
246
238
  ${c.cyan('filesystem.remove("/file")')}
247
239
 
240
+ ${c.dim("Named Sandboxes (gateway mode only):")}
241
+ ${c.cyan("create()")} ${c.dim("// Create & switch to new sandbox")}
242
+ ${c.cyan('create({ namespace: "h" })')} ${c.dim("// Create with namespace & switch")}
243
+ ${c.cyan('findOrCreate({ name: "my-app" })')} ${c.dim("// Find or create & switch")}
244
+ ${c.cyan('find({ name: "my-app" })')} ${c.dim("// Find existing & switch")}
245
+
246
+ ${c.dim("Note: Prompts before switching if you already have an active sandbox")}
247
+
248
+ ${c.dim("Child Sandboxes (gateway mode only):")}
249
+ ${c.cyan("child.create()")} ${c.dim("// Create child sandbox")}
250
+ ${c.cyan("child.list()")} ${c.dim("// List all children")}
251
+ ${c.cyan('child.retrieve("sandbox-id")')} ${c.dim("// Get child info")}
252
+ ${c.cyan('child.destroy("sandbox-id")')} ${c.dim("// Delete child")}
253
+
248
254
  ${c.dim("Sandbox Methods:")}
249
255
  ${c.cyan("getUrl({ port: 3000 })")} ${c.dim("// Get public URL")}
250
256
  ${c.cyan(`runCode("console.log('hi')", "node")`)}
@@ -280,6 +286,71 @@ function logError(message) {
280
286
  function logWarning(message) {
281
287
  console.log(c.yellow(`\u26A0\uFE0F ${message}`));
282
288
  }
289
+ function logInfo(message) {
290
+ console.log(c.blue(`\u2139\uFE0F ${message}`));
291
+ }
292
+ var colors, c, Spinner;
293
+ var init_output = __esm({
294
+ "src/cli/output.ts"() {
295
+ "use strict";
296
+ init_esm_shims();
297
+ init_state();
298
+ colors = {
299
+ reset: "\x1B[0m",
300
+ bright: "\x1B[1m",
301
+ dim: "\x1B[2m",
302
+ cyan: "\x1B[36m",
303
+ green: "\x1B[32m",
304
+ yellow: "\x1B[33m",
305
+ red: "\x1B[31m",
306
+ blue: "\x1B[34m",
307
+ magenta: "\x1B[35m"
308
+ };
309
+ c = {
310
+ bold: (text) => `${colors.bright}${text}${colors.reset}`,
311
+ dim: (text) => `${colors.dim}${text}${colors.reset}`,
312
+ cyan: (text) => `${colors.cyan}${text}${colors.reset}`,
313
+ green: (text) => `${colors.green}${text}${colors.reset}`,
314
+ yellow: (text) => `${colors.yellow}${text}${colors.reset}`,
315
+ red: (text) => `${colors.red}${text}${colors.reset}`,
316
+ blue: (text) => `${colors.blue}${text}${colors.reset}`,
317
+ magenta: (text) => `${colors.magenta}${text}${colors.reset}`
318
+ };
319
+ Spinner = class {
320
+ constructor(text) {
321
+ this.interval = null;
322
+ this.frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
323
+ this.currentFrame = 0;
324
+ this.text = text;
325
+ }
326
+ start() {
327
+ process.stdout.write("\x1B[?25l");
328
+ this.interval = setInterval(() => {
329
+ const frame = this.frames[this.currentFrame];
330
+ process.stdout.write(`\r${c.cyan(frame)} ${this.text}`);
331
+ this.currentFrame = (this.currentFrame + 1) % this.frames.length;
332
+ }, 80);
333
+ return this;
334
+ }
335
+ succeed(text) {
336
+ this.stop();
337
+ console.log(`${c.green("\u2705")} ${text || this.text}`);
338
+ }
339
+ fail(text) {
340
+ this.stop();
341
+ console.log(`${c.red("\u274C")} ${text || this.text}`);
342
+ }
343
+ stop() {
344
+ if (this.interval) {
345
+ clearInterval(this.interval);
346
+ this.interval = null;
347
+ }
348
+ process.stdout.write("\r\x1B[K");
349
+ process.stdout.write("\x1B[?25h");
350
+ }
351
+ };
352
+ }
353
+ });
283
354
 
284
355
  // src/cli/providers.ts
285
356
  import {
@@ -287,14 +358,6 @@ import {
287
358
  PROVIDER_NAMES as SHARED_PROVIDER_NAMES,
288
359
  getProviderConfigFromEnv
289
360
  } from "computesdk";
290
- var PROVIDER_NAMES = [
291
- "gateway",
292
- ...SHARED_PROVIDER_NAMES
293
- ];
294
- var PROVIDER_AUTH = {
295
- gateway: [["COMPUTESDK_API_KEY"]],
296
- ...SHARED_PROVIDER_AUTH
297
- };
298
361
  function getProviderStatus(provider) {
299
362
  const authOptions = PROVIDER_AUTH[provider];
300
363
  if (typeof process === "undefined") {
@@ -476,29 +539,136 @@ function getProviderConfig(providerName) {
476
539
  }
477
540
  return getProviderConfigFromEnv(providerName);
478
541
  }
542
+ var PROVIDER_NAMES, PROVIDER_AUTH;
543
+ var init_providers = __esm({
544
+ "src/cli/providers.ts"() {
545
+ "use strict";
546
+ init_esm_shims();
547
+ init_output();
548
+ PROVIDER_NAMES = [
549
+ "gateway",
550
+ ...SHARED_PROVIDER_NAMES
551
+ ];
552
+ PROVIDER_AUTH = {
553
+ gateway: [["COMPUTESDK_API_KEY"]],
554
+ ...SHARED_PROVIDER_AUTH
555
+ };
556
+ }
557
+ });
479
558
 
480
559
  // src/cli/commands.ts
560
+ var commands_exports = {};
561
+ __export(commands_exports, {
562
+ cleanupOnExit: () => cleanupOnExit,
563
+ confirmSandboxSwitch: () => confirmSandboxSwitch,
564
+ connectToSandbox: () => connectToSandbox,
565
+ createProviderCommand: () => createProviderCommand,
566
+ createSandbox: () => createSandbox,
567
+ destroySandbox: () => destroySandbox,
568
+ ensureSandbox: () => ensureSandbox,
569
+ getComputeInstance: () => getComputeInstance,
570
+ restartSandbox: () => restartSandbox,
571
+ runCommand: () => runCommand,
572
+ showMode: () => showMode,
573
+ showVerbose: () => showVerbose,
574
+ switchProvider: () => switchProvider,
575
+ toggleMode: () => toggleMode,
576
+ toggleVerbose: () => toggleVerbose
577
+ });
578
+ import { createCompute } from "computesdk";
481
579
  import * as readline from "readline";
482
- async function confirm(question) {
580
+ async function confirm(question, defaultYes = false) {
483
581
  return new Promise((resolve) => {
484
582
  const rl = readline.createInterface({
485
583
  input: process.stdin,
486
584
  output: process.stdout
487
585
  });
488
586
  process.stdin.resume();
489
- rl.question(`${question} (y/N): `, (answer) => {
587
+ const promptSuffix = defaultYes ? "(Y/n)" : "(y/N)";
588
+ rl.question(`${question} ${promptSuffix}: `, (answer) => {
490
589
  rl.close();
491
590
  const trimmed = answer.trim().toLowerCase();
492
- resolve(trimmed === "y" || trimmed === "yes");
591
+ if (trimmed === "") {
592
+ resolve(defaultYes);
593
+ } else {
594
+ resolve(trimmed === "y" || trimmed === "yes");
595
+ }
493
596
  });
494
597
  });
495
598
  }
599
+ async function confirmSandboxSwitch(state) {
600
+ if (!hasSandbox(state)) {
601
+ return true;
602
+ }
603
+ return await confirm("Switch to new sandbox?", true);
604
+ }
496
605
  async function ensureSandbox(state) {
497
606
  if (hasSandbox(state)) {
498
607
  return;
499
608
  }
500
609
  await createSandbox(state);
501
610
  }
611
+ async function getComputeInstance(state) {
612
+ if (state.compute) {
613
+ return state.compute;
614
+ }
615
+ const providerName = state.currentProvider || autoDetectProvider(false);
616
+ const useDirect = state.useDirectMode;
617
+ if (!providerName) {
618
+ throw new Error("No provider configured.");
619
+ }
620
+ let compute2;
621
+ if (useDirect) {
622
+ const providerModule = await loadProvider(providerName);
623
+ const providerFactory = providerModule[providerName];
624
+ if (!providerFactory) {
625
+ throw new Error(`Provider ${providerName} does not export a factory function`);
626
+ }
627
+ const config = getProviderConfig(providerName);
628
+ compute2 = createCompute({
629
+ defaultProvider: providerFactory(config)
630
+ });
631
+ } else {
632
+ const gatewayModule = await import("computesdk");
633
+ const gatewayFactory = gatewayModule.gateway;
634
+ const providerConfig = getProviderConfig(providerName);
635
+ const providerHeaders = {};
636
+ switch (providerName) {
637
+ case "e2b":
638
+ if (providerConfig.apiKey) providerHeaders["X-E2B-API-Key"] = providerConfig.apiKey;
639
+ break;
640
+ case "railway":
641
+ if (providerConfig.apiKey) providerHeaders["X-Railway-API-Key"] = providerConfig.apiKey;
642
+ if (providerConfig.projectId) providerHeaders["X-Railway-Project-ID"] = providerConfig.projectId;
643
+ if (providerConfig.environmentId) providerHeaders["X-Railway-Environment-ID"] = providerConfig.environmentId;
644
+ break;
645
+ case "daytona":
646
+ if (providerConfig.apiKey) providerHeaders["X-Daytona-API-Key"] = providerConfig.apiKey;
647
+ break;
648
+ case "modal":
649
+ if (providerConfig.tokenId) providerHeaders["X-Modal-Token-ID"] = providerConfig.tokenId;
650
+ if (providerConfig.tokenSecret) providerHeaders["X-Modal-Token-Secret"] = providerConfig.tokenSecret;
651
+ break;
652
+ case "vercel":
653
+ if (providerConfig.token) providerHeaders["X-Vercel-Token"] = providerConfig.token;
654
+ if (providerConfig.teamId) providerHeaders["X-Vercel-Team-ID"] = providerConfig.teamId;
655
+ if (providerConfig.projectId) providerHeaders["X-Vercel-Project-ID"] = providerConfig.projectId;
656
+ break;
657
+ }
658
+ const config = {
659
+ apiKey: process.env.COMPUTESDK_API_KEY,
660
+ provider: providerName,
661
+ // Tell gateway which backend to use
662
+ providerHeaders
663
+ // Pass provider credentials via headers
664
+ };
665
+ compute2 = createCompute({
666
+ defaultProvider: gatewayFactory(config)
667
+ });
668
+ }
669
+ state.compute = compute2;
670
+ return compute2;
671
+ }
502
672
  async function createSandbox(state) {
503
673
  const providerName = state.currentProvider || autoDetectProvider(false);
504
674
  const useDirect = state.useDirectMode;
@@ -528,55 +698,7 @@ async function createSandbox(state) {
528
698
  const spinner = new Spinner(`Creating sandbox with ${modeLabel}...`).start();
529
699
  const startTime = Date.now();
530
700
  try {
531
- let compute2;
532
- if (useDirect) {
533
- const providerModule = await loadProvider(providerName);
534
- const providerFactory = providerModule[providerName];
535
- if (!providerFactory) {
536
- throw new Error(`Provider ${providerName} does not export a factory function`);
537
- }
538
- const config = getProviderConfig(providerName);
539
- compute2 = createCompute({
540
- defaultProvider: providerFactory(config)
541
- });
542
- } else {
543
- const gatewayModule = await import("computesdk");
544
- const gatewayFactory = gatewayModule.gateway;
545
- const providerConfig = getProviderConfig(providerName);
546
- const providerHeaders = {};
547
- switch (providerName) {
548
- case "e2b":
549
- if (providerConfig.apiKey) providerHeaders["X-E2B-API-Key"] = providerConfig.apiKey;
550
- break;
551
- case "railway":
552
- if (providerConfig.apiKey) providerHeaders["X-Railway-API-Key"] = providerConfig.apiKey;
553
- if (providerConfig.projectId) providerHeaders["X-Railway-Project-ID"] = providerConfig.projectId;
554
- if (providerConfig.environmentId) providerHeaders["X-Railway-Environment-ID"] = providerConfig.environmentId;
555
- break;
556
- case "daytona":
557
- if (providerConfig.apiKey) providerHeaders["X-Daytona-API-Key"] = providerConfig.apiKey;
558
- break;
559
- case "modal":
560
- if (providerConfig.tokenId) providerHeaders["X-Modal-Token-ID"] = providerConfig.tokenId;
561
- if (providerConfig.tokenSecret) providerHeaders["X-Modal-Token-Secret"] = providerConfig.tokenSecret;
562
- break;
563
- case "vercel":
564
- if (providerConfig.token) providerHeaders["X-Vercel-Token"] = providerConfig.token;
565
- if (providerConfig.teamId) providerHeaders["X-Vercel-Team-ID"] = providerConfig.teamId;
566
- if (providerConfig.projectId) providerHeaders["X-Vercel-Project-ID"] = providerConfig.projectId;
567
- break;
568
- }
569
- const config = {
570
- apiKey: process.env.COMPUTESDK_API_KEY,
571
- provider: providerName,
572
- // Tell gateway which backend to use
573
- providerHeaders
574
- // Pass provider credentials via headers
575
- };
576
- compute2 = createCompute({
577
- defaultProvider: gatewayFactory(config)
578
- });
579
- }
701
+ const compute2 = await getComputeInstance(state);
580
702
  const result = await compute2.sandbox.create();
581
703
  const duration = Date.now() - startTime;
582
704
  setSandbox(state, result, providerName);
@@ -720,6 +842,7 @@ async function switchProvider(state, mode, providerName) {
720
842
  await destroySandbox(state);
721
843
  state.currentProvider = actualProvider;
722
844
  state.useDirectMode = useDirect;
845
+ state.compute = null;
723
846
  const modeStr = useDirect ? `${actualProvider} (direct)` : `${actualProvider} (via gateway)`;
724
847
  logSuccess(`Switched to ${modeStr}`);
725
848
  } else {
@@ -728,6 +851,7 @@ async function switchProvider(state, mode, providerName) {
728
851
  } else {
729
852
  state.currentProvider = actualProvider;
730
853
  state.useDirectMode = useDirect;
854
+ state.compute = null;
731
855
  const modeStr = useDirect ? `${actualProvider} (direct)` : `${actualProvider} (via gateway)`;
732
856
  logSuccess(`Switched to ${modeStr}`);
733
857
  }
@@ -805,6 +929,62 @@ Verbose mode: ${status}`);
805
929
  Toggle with: ${c.cyan("verbose")}
806
930
  `);
807
931
  }
932
+ async function connectToSandbox(state, sandboxUrl, token) {
933
+ if (!sandboxUrl) {
934
+ logError("Usage: connect <sandbox_url> [token]");
935
+ console.log("Example: connect https://sandbox-123.localhost:8080");
936
+ console.log("Example: connect https://sandbox-123.localhost:8080 your_access_token");
937
+ return;
938
+ }
939
+ const cleanUrl = sandboxUrl.replace(/\/$/, "");
940
+ if (hasSandbox(state)) {
941
+ const shouldDestroy = await confirm("Disconnect from current sandbox?");
942
+ if (!shouldDestroy) {
943
+ logWarning("Keeping current sandbox. Connection cancelled.");
944
+ return;
945
+ }
946
+ clearSandbox(state);
947
+ }
948
+ const spinner = new Spinner(`Connecting to ${cleanUrl}...`).start();
949
+ const startTime = Date.now();
950
+ try {
951
+ const { Sandbox } = await import("@computesdk/client");
952
+ let WebSocket;
953
+ try {
954
+ const wsModule = await import("ws");
955
+ WebSocket = wsModule.default;
956
+ } catch {
957
+ logError('Failed to import "ws" module. Please install it: pnpm add ws');
958
+ throw new Error('Missing "ws" dependency');
959
+ }
960
+ const sandbox = new Sandbox({
961
+ sandboxUrl: cleanUrl,
962
+ sandboxId: "",
963
+ // Will be populated when we get info
964
+ provider: "connected",
965
+ // Mark as directly connected
966
+ token,
967
+ // Optional access token
968
+ WebSocket
969
+ });
970
+ const info = await sandbox.getInfo();
971
+ const duration = Date.now() - startTime;
972
+ setSandbox(state, sandbox, "connected");
973
+ spinner.succeed(`Connected to sandbox ${c.dim(`(${formatDuration(duration)})`)}`);
974
+ console.log(c.dim(`Provider: ${info.provider || "unknown"}`));
975
+ console.log(c.dim(`Sandbox ID: ${info.id || "unknown"}`));
976
+ } catch (error) {
977
+ const duration = Date.now() - startTime;
978
+ spinner.fail(`Failed to connect ${c.dim(`(${formatDuration(duration)})`)}`);
979
+ if (error instanceof Error) {
980
+ logError(`Error: ${error.message}`);
981
+ if (error.stack) {
982
+ console.log(c.dim(error.stack));
983
+ }
984
+ }
985
+ throw error;
986
+ }
987
+ }
808
988
  async function cleanupOnExit(state, replServer) {
809
989
  if (!hasSandbox(state)) {
810
990
  return;
@@ -813,6 +993,10 @@ async function cleanupOnExit(state, replServer) {
813
993
  replServer.pause();
814
994
  }
815
995
  console.log("");
996
+ if (state.currentProvider === "connected") {
997
+ logWarning("Disconnecting from external sandbox (not destroying).");
998
+ return;
999
+ }
816
1000
  const shouldDestroy = await confirm("Destroy active sandbox?");
817
1001
  if (shouldDestroy) {
818
1002
  await destroySandbox(state);
@@ -820,14 +1004,36 @@ async function cleanupOnExit(state, replServer) {
820
1004
  logWarning("Sandbox left running. It may incur costs.");
821
1005
  }
822
1006
  }
1007
+ var init_commands = __esm({
1008
+ "src/cli/commands.ts"() {
1009
+ "use strict";
1010
+ init_esm_shims();
1011
+ init_state();
1012
+ init_output();
1013
+ init_providers();
1014
+ }
1015
+ });
1016
+
1017
+ // src/cli/index.ts
1018
+ init_esm_shims();
1019
+ init_state();
1020
+
1021
+ // src/cli/repl.ts
1022
+ init_esm_shims();
1023
+ init_commands();
1024
+ init_output();
1025
+ init_providers();
1026
+ import * as repl from "repl";
1027
+ import * as cmd from "@computesdk/cmd";
823
1028
 
824
1029
  // src/cli/types.ts
1030
+ init_esm_shims();
825
1031
  function isCommand(value) {
826
1032
  return Array.isArray(value) && value.length > 0 && typeof value[0] === "string";
827
1033
  }
828
1034
 
829
1035
  // src/cli/repl.ts
830
- import * as path from "path";
1036
+ import * as path2 from "path";
831
1037
  import * as os from "os";
832
1038
  function createREPL(state) {
833
1039
  const replServer = repl.start({
@@ -940,6 +1146,9 @@ function injectWorkbenchCommands(replServer, state) {
940
1146
  replServer.context.destroy = async () => {
941
1147
  await destroySandbox(state);
942
1148
  };
1149
+ replServer.context.connect = async (url, token) => {
1150
+ await connectToSandbox(state, url, token);
1151
+ };
943
1152
  replServer.context.info = () => showInfo(state);
944
1153
  replServer.context.verbose = () => {
945
1154
  toggleVerbose(state);
@@ -972,59 +1181,203 @@ function injectWorkbenchCommands(replServer, state) {
972
1181
  }
973
1182
  return sandbox.runCode(code, runtime);
974
1183
  };
1184
+ replServer.context.create = async (options) => {
1185
+ if (state.useDirectMode) {
1186
+ throw new Error('Named sandboxes are only available in gateway mode. Use "mode gateway" to switch.');
1187
+ }
1188
+ const { getComputeInstance: getComputeInstance2, confirmSandboxSwitch: confirmSandboxSwitch2 } = await Promise.resolve().then(() => (init_commands(), commands_exports));
1189
+ const { setSandbox: setSandbox2 } = await Promise.resolve().then(() => (init_state(), state_exports));
1190
+ const { logSuccess: logSuccess2 } = await Promise.resolve().then(() => (init_output(), output_exports));
1191
+ const shouldSwitch = await confirmSandboxSwitch2(state);
1192
+ if (!shouldSwitch) {
1193
+ const compute3 = await getComputeInstance2(state);
1194
+ const sandbox2 = await compute3.sandbox.create(options);
1195
+ return {
1196
+ sandboxId: sandbox2.sandboxId,
1197
+ provider: sandbox2.provider,
1198
+ metadata: sandbox2.getInstance().config.metadata || {}
1199
+ };
1200
+ }
1201
+ const compute2 = await getComputeInstance2(state);
1202
+ const sandbox = await compute2.sandbox.create(options);
1203
+ setSandbox2(state, sandbox, sandbox.provider);
1204
+ logSuccess2(`Switched to sandbox ${sandbox.sandboxId}`);
1205
+ return {
1206
+ sandboxId: sandbox.sandboxId,
1207
+ provider: sandbox.provider,
1208
+ metadata: sandbox.getInstance().config.metadata || {}
1209
+ };
1210
+ };
1211
+ replServer.context.findOrCreate = async (options) => {
1212
+ if (state.useDirectMode) {
1213
+ throw new Error('Named sandboxes (findOrCreate) are only available in gateway mode. Use "mode gateway" to switch.');
1214
+ }
1215
+ const { getComputeInstance: getComputeInstance2, confirmSandboxSwitch: confirmSandboxSwitch2 } = await Promise.resolve().then(() => (init_commands(), commands_exports));
1216
+ const { setSandbox: setSandbox2 } = await Promise.resolve().then(() => (init_state(), state_exports));
1217
+ const { logSuccess: logSuccess2 } = await Promise.resolve().then(() => (init_output(), output_exports));
1218
+ const shouldSwitch = await confirmSandboxSwitch2(state);
1219
+ if (!shouldSwitch) {
1220
+ const compute3 = await getComputeInstance2(state);
1221
+ const sandbox2 = await compute3.sandbox.findOrCreate(options);
1222
+ return {
1223
+ sandboxId: sandbox2.sandboxId,
1224
+ provider: sandbox2.provider,
1225
+ name: options.name,
1226
+ namespace: options.namespace || "default",
1227
+ metadata: sandbox2.getInstance().config.metadata || {}
1228
+ };
1229
+ }
1230
+ const compute2 = await getComputeInstance2(state);
1231
+ const sandbox = await compute2.sandbox.findOrCreate(options);
1232
+ setSandbox2(state, sandbox, sandbox.provider);
1233
+ logSuccess2(`Switched to sandbox ${sandbox.sandboxId}`);
1234
+ return {
1235
+ sandboxId: sandbox.sandboxId,
1236
+ provider: sandbox.provider,
1237
+ name: options.name,
1238
+ namespace: options.namespace || "default",
1239
+ metadata: sandbox.getInstance().config.metadata || {}
1240
+ };
1241
+ };
1242
+ replServer.context.find = async (options) => {
1243
+ if (state.useDirectMode) {
1244
+ throw new Error('Named sandboxes (find) are only available in gateway mode. Use "mode gateway" to switch.');
1245
+ }
1246
+ const { getComputeInstance: getComputeInstance2, confirmSandboxSwitch: confirmSandboxSwitch2 } = await Promise.resolve().then(() => (init_commands(), commands_exports));
1247
+ const { setSandbox: setSandbox2 } = await Promise.resolve().then(() => (init_state(), state_exports));
1248
+ const { logSuccess: logSuccess2 } = await Promise.resolve().then(() => (init_output(), output_exports));
1249
+ const compute2 = await getComputeInstance2(state);
1250
+ const sandbox = await compute2.sandbox.find(options);
1251
+ if (!sandbox) {
1252
+ return null;
1253
+ }
1254
+ const shouldSwitch = await confirmSandboxSwitch2(state);
1255
+ if (!shouldSwitch) {
1256
+ return {
1257
+ sandboxId: sandbox.sandboxId,
1258
+ provider: sandbox.provider,
1259
+ name: options.name,
1260
+ namespace: options.namespace || "default",
1261
+ metadata: sandbox.getInstance().config.metadata || {}
1262
+ };
1263
+ }
1264
+ setSandbox2(state, sandbox, sandbox.provider);
1265
+ logSuccess2(`Switched to sandbox ${sandbox.sandboxId}`);
1266
+ return {
1267
+ sandboxId: sandbox.sandboxId,
1268
+ provider: sandbox.provider,
1269
+ name: options.name,
1270
+ namespace: options.namespace || "default",
1271
+ metadata: sandbox.getInstance().config.metadata || {}
1272
+ };
1273
+ };
975
1274
  replServer.context.filesystem = {
976
1275
  get readFile() {
977
- return async (path2) => {
1276
+ return async (path3) => {
978
1277
  const sandbox = state.currentSandbox;
979
1278
  if (!sandbox) {
980
1279
  throw new Error("No active sandbox. Run a command to auto-create one.");
981
1280
  }
982
- return sandbox.filesystem.readFile(path2);
1281
+ return sandbox.filesystem.readFile(path3);
983
1282
  };
984
1283
  },
985
1284
  get writeFile() {
986
- return async (path2, content) => {
1285
+ return async (path3, content) => {
987
1286
  const sandbox = state.currentSandbox;
988
1287
  if (!sandbox) {
989
1288
  throw new Error("No active sandbox. Run a command to auto-create one.");
990
1289
  }
991
- return sandbox.filesystem.writeFile(path2, content);
1290
+ return sandbox.filesystem.writeFile(path3, content);
992
1291
  };
993
1292
  },
994
1293
  get mkdir() {
995
- return async (path2) => {
1294
+ return async (path3) => {
996
1295
  const sandbox = state.currentSandbox;
997
1296
  if (!sandbox) {
998
1297
  throw new Error("No active sandbox. Run a command to auto-create one.");
999
1298
  }
1000
- return sandbox.filesystem.mkdir(path2);
1299
+ return sandbox.filesystem.mkdir(path3);
1001
1300
  };
1002
1301
  },
1003
1302
  get readdir() {
1004
- return async (path2) => {
1303
+ return async (path3) => {
1005
1304
  const sandbox = state.currentSandbox;
1006
1305
  if (!sandbox) {
1007
1306
  throw new Error("No active sandbox. Run a command to auto-create one.");
1008
1307
  }
1009
- return sandbox.filesystem.readdir(path2);
1308
+ return sandbox.filesystem.readdir(path3);
1010
1309
  };
1011
1310
  },
1012
1311
  get exists() {
1013
- return async (path2) => {
1312
+ return async (path3) => {
1014
1313
  const sandbox = state.currentSandbox;
1015
1314
  if (!sandbox) {
1016
1315
  throw new Error("No active sandbox. Run a command to auto-create one.");
1017
1316
  }
1018
- return sandbox.filesystem.exists(path2);
1317
+ return sandbox.filesystem.exists(path3);
1019
1318
  };
1020
1319
  },
1021
1320
  get remove() {
1022
- return async (path2) => {
1321
+ return async (path3) => {
1322
+ const sandbox = state.currentSandbox;
1323
+ if (!sandbox) {
1324
+ throw new Error("No active sandbox. Run a command to auto-create one.");
1325
+ }
1326
+ return sandbox.filesystem.remove(path3);
1327
+ };
1328
+ }
1329
+ };
1330
+ replServer.context.child = {
1331
+ get create() {
1332
+ return async () => {
1333
+ if (state.useDirectMode) {
1334
+ throw new Error('Child sandboxes are only available in gateway mode. Use "mode gateway" to switch.');
1335
+ }
1336
+ const sandbox = state.currentSandbox;
1337
+ if (!sandbox) {
1338
+ throw new Error("No active sandbox. Run a command to auto-create one.");
1339
+ }
1340
+ const instance = sandbox.getInstance();
1341
+ return instance.child.create();
1342
+ };
1343
+ },
1344
+ get list() {
1345
+ return async () => {
1346
+ if (state.useDirectMode) {
1347
+ throw new Error('Child sandboxes are only available in gateway mode. Use "mode gateway" to switch.');
1348
+ }
1349
+ const sandbox = state.currentSandbox;
1350
+ if (!sandbox) {
1351
+ throw new Error("No active sandbox. Run a command to auto-create one.");
1352
+ }
1353
+ const instance = sandbox.getInstance();
1354
+ return instance.child.list();
1355
+ };
1356
+ },
1357
+ get retrieve() {
1358
+ return async (subdomain) => {
1359
+ if (state.useDirectMode) {
1360
+ throw new Error('Child sandboxes are only available in gateway mode. Use "mode gateway" to switch.');
1361
+ }
1362
+ const sandbox = state.currentSandbox;
1363
+ if (!sandbox) {
1364
+ throw new Error("No active sandbox. Run a command to auto-create one.");
1365
+ }
1366
+ const instance = sandbox.getInstance();
1367
+ return instance.child.retrieve(subdomain);
1368
+ };
1369
+ },
1370
+ get destroy() {
1371
+ return async (subdomain, options) => {
1372
+ if (state.useDirectMode) {
1373
+ throw new Error('Child sandboxes are only available in gateway mode. Use "mode gateway" to switch.');
1374
+ }
1023
1375
  const sandbox = state.currentSandbox;
1024
1376
  if (!sandbox) {
1025
1377
  throw new Error("No active sandbox. Run a command to auto-create one.");
1026
1378
  }
1027
- return sandbox.filesystem.remove(path2);
1379
+ const instance = sandbox.getInstance();
1380
+ return instance.child.destroy(subdomain, options);
1028
1381
  };
1029
1382
  }
1030
1383
  };
@@ -1038,7 +1391,7 @@ function injectWorkbenchCommands(replServer, state) {
1038
1391
  }
1039
1392
  function setupSmartEvaluator(replServer, state) {
1040
1393
  const originalEval = replServer.eval;
1041
- const workbenchCommands = /* @__PURE__ */ new Set(["help", "providers", "info", "env", "restart", "destroy", "mode", "verbose", "sandboxInfo"]);
1394
+ const workbenchCommands = /* @__PURE__ */ new Set(["help", "providers", "info", "env", "restart", "destroy", "mode", "verbose", "sandboxInfo", "connect"]);
1042
1395
  replServer.eval = function(cmd3, context, filename, callback) {
1043
1396
  const trimmedCmd = cmd3.trim();
1044
1397
  const providerMatch = trimmedCmd.match(/^provider(?:\s+(direct|gateway))?\s+(\w+)$/);
@@ -1119,6 +1472,8 @@ function setupAutocomplete(replServer, state) {
1119
1472
  "providers": [],
1120
1473
  "restart": [],
1121
1474
  "destroy": [],
1475
+ "connect": [],
1476
+ // Connect takes a URL argument
1122
1477
  "info": [],
1123
1478
  "env": [],
1124
1479
  "help": [],
@@ -1204,7 +1559,7 @@ function setupAutocomplete(replServer, state) {
1204
1559
  };
1205
1560
  }
1206
1561
  function setupHistory(replServer) {
1207
- const historyFile = path.join(os.homedir(), ".computesdk_workbench_history");
1562
+ const historyFile = path2.join(os.homedir(), ".computesdk_workbench_history");
1208
1563
  replServer.setupHistory(historyFile, (err) => {
1209
1564
  if (err) {
1210
1565
  }
@@ -1212,6 +1567,9 @@ function setupHistory(replServer) {
1212
1567
  }
1213
1568
 
1214
1569
  // src/cli/index.ts
1570
+ init_output();
1571
+ init_providers();
1572
+ init_commands();
1215
1573
  async function startWorkbench() {
1216
1574
  const state = createState();
1217
1575
  state.availableProviders = getAvailableProviders();