@computesdk/workbench 3.1.4 → 3.1.6
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 +61 -0
- package/dist/bin/workbench.js +304 -42
- package/dist/bin/workbench.js.map +1 -1
- package/dist/index.js +304 -42
- package/dist/index.js.map +1 -1
- package/package.json +13 -13
package/dist/index.js
CHANGED
|
@@ -37,6 +37,7 @@ function createState() {
|
|
|
37
37
|
useDirectMode: false,
|
|
38
38
|
// Default to gateway mode
|
|
39
39
|
verbose: false,
|
|
40
|
+
// Enabled automatically for local provider
|
|
40
41
|
compute: null
|
|
41
42
|
};
|
|
42
43
|
}
|
|
@@ -113,21 +114,27 @@ __export(output_exports, {
|
|
|
113
114
|
showInfo: () => showInfo,
|
|
114
115
|
showWelcome: () => showWelcome
|
|
115
116
|
});
|
|
116
|
-
function showWelcome(availableProviders, currentProvider, useDirectMode) {
|
|
117
|
+
function showWelcome(availableProviders, currentProvider, useDirectMode, localDaemonRunning = false) {
|
|
117
118
|
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")));
|
|
118
119
|
console.log(c.bold(c.cyan("\u2551 ComputeSDK Workbench \u2551")));
|
|
119
120
|
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")));
|
|
120
121
|
console.log(c.dim("Prompt shows connection status: > (disconnected) or provider:sandbox> (connected)\n"));
|
|
122
|
+
if (localDaemonRunning) {
|
|
123
|
+
console.log(c.green("Local daemon detected - auto-connecting...\n"));
|
|
124
|
+
}
|
|
121
125
|
if (availableProviders.length > 0) {
|
|
122
126
|
const backendProviders = availableProviders.filter((p) => p !== "gateway");
|
|
123
127
|
console.log(`Providers available: ${backendProviders.join(", ")}`);
|
|
124
128
|
if (currentProvider) {
|
|
125
|
-
if (
|
|
126
|
-
console.log(`Current provider: ${c.green(
|
|
129
|
+
if (currentProvider === "local") {
|
|
130
|
+
console.log(`Current provider: ${c.green("local")} (local daemon)
|
|
131
|
+
`);
|
|
132
|
+
} else if (useDirectMode) {
|
|
133
|
+
console.log(`Current provider: ${c.green(currentProvider)} (direct mode)
|
|
127
134
|
`);
|
|
128
135
|
} else {
|
|
129
136
|
const backendProvider = currentProvider === "gateway" ? backendProviders[0] || "auto" : currentProvider;
|
|
130
|
-
console.log(`Current provider: ${c.green(backendProvider)} (
|
|
137
|
+
console.log(`Current provider: ${c.green(backendProvider)} (via gateway)
|
|
131
138
|
`);
|
|
132
139
|
}
|
|
133
140
|
} else {
|
|
@@ -136,7 +143,7 @@ ${c.dim('Tip: Use "provider <name>" to select a provider')}
|
|
|
136
143
|
`);
|
|
137
144
|
}
|
|
138
145
|
} else {
|
|
139
|
-
console.log(c.yellow("
|
|
146
|
+
console.log(c.yellow("No providers detected.\n"));
|
|
140
147
|
console.log("To get started:");
|
|
141
148
|
console.log(" 1. Copy .env.example to .env");
|
|
142
149
|
console.log(" 2. Add your provider credentials");
|
|
@@ -199,10 +206,14 @@ ${c.bold("Provider Modes:")}
|
|
|
199
206
|
${c.bold("Sandbox Management:")}
|
|
200
207
|
${c.cyan("restart")} Restart current sandbox
|
|
201
208
|
${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")}
|
|
205
209
|
${c.cyan("info")} Show sandbox info (provider, uptime)
|
|
210
|
+
${c.cyan("connect <url> [token]")} Connect to sandbox via URL
|
|
211
|
+
|
|
212
|
+
${c.bold("Local Daemon:")}
|
|
213
|
+
${c.cyan("provider local")} Connect to local daemon's main sandbox
|
|
214
|
+
${c.cyan("provider local list")} List local sandboxes
|
|
215
|
+
${c.cyan("provider local <subdomain>")} Connect to specific local sandbox
|
|
216
|
+
${c.dim("Example: provider local separate-snail-qkktux")}
|
|
206
217
|
|
|
207
218
|
${c.bold("Environment:")}
|
|
208
219
|
${c.cyan("env")} Show environment/credentials status
|
|
@@ -257,6 +268,24 @@ ${c.bold("Running Commands:")}
|
|
|
257
268
|
${c.cyan("sandboxInfo()")} ${c.dim("// Get sandbox details")}
|
|
258
269
|
${c.cyan("getInstance()")} ${c.dim("// Get native instance")}
|
|
259
270
|
|
|
271
|
+
${c.dim("Terminal (PTY & Exec):")}
|
|
272
|
+
${c.cyan("terminal.create({ pty: true })")} ${c.dim("// Create PTY terminal")}
|
|
273
|
+
${c.cyan("terminal.create({ pty: false })")} ${c.dim("// Create exec terminal")}
|
|
274
|
+
${c.cyan("terminal.list()")} ${c.dim("// List all terminals")}
|
|
275
|
+
${c.cyan("terminal.retrieve(id)")} ${c.dim("// Get terminal by ID")}
|
|
276
|
+
${c.cyan("terminal.destroy(id)")} ${c.dim("// Close terminal by ID")}
|
|
277
|
+
|
|
278
|
+
${c.dim("PTY Terminal:")}
|
|
279
|
+
${c.cyan("term = terminal.create({ pty: true })")}
|
|
280
|
+
${c.cyan('term.on("output", (data) => console.log(data))')}
|
|
281
|
+
${c.cyan('term.write("echo hello\\n")')}
|
|
282
|
+
${c.cyan("term.destroy()")}
|
|
283
|
+
|
|
284
|
+
${c.dim("Exec Terminal:")}
|
|
285
|
+
${c.cyan("exec = terminal.create({ pty: false })")}
|
|
286
|
+
${c.cyan('cmd = exec.command.run("ls -la")')}
|
|
287
|
+
${c.cyan("cmd.stdout")} ${c.dim("// view output")}
|
|
288
|
+
|
|
260
289
|
${c.dim('Note: No need to use "await" - promises are auto-awaited!')}
|
|
261
290
|
|
|
262
291
|
${c.dim("Compute CLI:")}
|
|
@@ -561,12 +590,15 @@ var commands_exports = {};
|
|
|
561
590
|
__export(commands_exports, {
|
|
562
591
|
cleanupOnExit: () => cleanupOnExit,
|
|
563
592
|
confirmSandboxSwitch: () => confirmSandboxSwitch,
|
|
593
|
+
connectToLocal: () => connectToLocal,
|
|
564
594
|
connectToSandbox: () => connectToSandbox,
|
|
565
595
|
createSandbox: () => createSandbox,
|
|
566
596
|
defineProviderCommand: () => defineProviderCommand,
|
|
567
597
|
destroySandbox: () => destroySandbox,
|
|
568
598
|
ensureSandbox: () => ensureSandbox,
|
|
569
599
|
getComputeInstance: () => getComputeInstance,
|
|
600
|
+
isLocalDaemonRunning: () => isLocalDaemonRunning,
|
|
601
|
+
listLocalSandboxes: () => listLocalSandboxes,
|
|
570
602
|
restartSandbox: () => restartSandbox,
|
|
571
603
|
runCommand: () => runCommand,
|
|
572
604
|
showMode: () => showMode,
|
|
@@ -577,31 +609,58 @@ __export(commands_exports, {
|
|
|
577
609
|
});
|
|
578
610
|
import { createCompute } from "@computesdk/provider";
|
|
579
611
|
import { escapeArgs } from "@computesdk/cmd";
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
input: process.stdin,
|
|
585
|
-
output: process.stdout
|
|
586
|
-
});
|
|
612
|
+
async function confirm(question, defaultYes = false, _state) {
|
|
613
|
+
const promptSuffix = defaultYes ? "(Y/n)" : "(y/N)";
|
|
614
|
+
process.stdout.write(`${question} ${promptSuffix}: `);
|
|
615
|
+
if (process.stdin.isPaused()) {
|
|
587
616
|
process.stdin.resume();
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
617
|
+
}
|
|
618
|
+
return new Promise((resolve) => {
|
|
619
|
+
const wasRaw = process.stdin.isRaw;
|
|
620
|
+
if (process.stdin.isTTY) {
|
|
621
|
+
process.stdin.setRawMode(true);
|
|
622
|
+
}
|
|
623
|
+
const cleanup = (restoreRaw) => {
|
|
624
|
+
process.stdin.removeListener("data", onData);
|
|
625
|
+
if (process.stdin.isTTY && restoreRaw) {
|
|
626
|
+
process.stdin.setRawMode(wasRaw || false);
|
|
627
|
+
}
|
|
628
|
+
};
|
|
629
|
+
const onData = (key) => {
|
|
630
|
+
const char = key.toString();
|
|
631
|
+
if (char === "") {
|
|
632
|
+
process.stdout.write("^C\n");
|
|
633
|
+
cleanup(true);
|
|
634
|
+
resolve(false);
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
if (char === "\r" || char === "\n") {
|
|
638
|
+
process.stdout.write(defaultYes ? "Y\n" : "N\n");
|
|
639
|
+
cleanup(true);
|
|
593
640
|
resolve(defaultYes);
|
|
594
|
-
|
|
595
|
-
resolve(trimmed === "y" || trimmed === "yes");
|
|
641
|
+
return;
|
|
596
642
|
}
|
|
597
|
-
|
|
643
|
+
if (char === "y" || char === "Y") {
|
|
644
|
+
process.stdout.write("y\n");
|
|
645
|
+
cleanup(true);
|
|
646
|
+
resolve(true);
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
if (char === "n" || char === "N") {
|
|
650
|
+
process.stdout.write("n\n");
|
|
651
|
+
cleanup(true);
|
|
652
|
+
resolve(false);
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
process.stdin.on("data", onData);
|
|
598
657
|
});
|
|
599
658
|
}
|
|
600
659
|
async function confirmSandboxSwitch(state) {
|
|
601
660
|
if (!hasSandbox(state)) {
|
|
602
661
|
return true;
|
|
603
662
|
}
|
|
604
|
-
return await confirm("Switch to new sandbox?", true);
|
|
663
|
+
return await confirm("Switch to new sandbox?", true, state);
|
|
605
664
|
}
|
|
606
665
|
async function ensureSandbox(state) {
|
|
607
666
|
if (hasSandbox(state)) {
|
|
@@ -763,6 +822,14 @@ function isStaleConnectionError(error) {
|
|
|
763
822
|
return stalePhrases.some((phrase) => message.includes(phrase));
|
|
764
823
|
}
|
|
765
824
|
async function switchProvider(state, mode, providerName) {
|
|
825
|
+
if (mode === "local") {
|
|
826
|
+
if (providerName === "list") {
|
|
827
|
+
await listLocalSandboxes();
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
await connectToLocal(state, providerName);
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
766
833
|
let useDirect = false;
|
|
767
834
|
let actualProvider = mode;
|
|
768
835
|
if (mode === "direct") {
|
|
@@ -787,7 +854,7 @@ async function switchProvider(state, mode, providerName) {
|
|
|
787
854
|
}
|
|
788
855
|
if (!isValidProvider(actualProvider)) {
|
|
789
856
|
logError(`Unknown provider: ${actualProvider}`);
|
|
790
|
-
console.log(`Available providers: e2b, railway, daytona, modal, runloop, vercel, cloudflare, codesandbox, blaxel`);
|
|
857
|
+
console.log(`Available providers: e2b, railway, daytona, modal, runloop, vercel, cloudflare, codesandbox, blaxel, local`);
|
|
791
858
|
return;
|
|
792
859
|
}
|
|
793
860
|
if (!useDirect && !isProviderReady("gateway")) {
|
|
@@ -801,7 +868,7 @@ async function switchProvider(state, mode, providerName) {
|
|
|
801
868
|
return;
|
|
802
869
|
}
|
|
803
870
|
if (hasSandbox(state)) {
|
|
804
|
-
const shouldDestroy = await confirm("Destroy current sandbox?");
|
|
871
|
+
const shouldDestroy = await confirm("Destroy current sandbox?", false, state);
|
|
805
872
|
if (shouldDestroy) {
|
|
806
873
|
await destroySandbox(state);
|
|
807
874
|
state.currentProvider = actualProvider;
|
|
@@ -824,7 +891,7 @@ function defineProviderCommand(state) {
|
|
|
824
891
|
return async function provider(mode, providerName) {
|
|
825
892
|
if (!mode) {
|
|
826
893
|
if (state.currentProvider) {
|
|
827
|
-
const modeStr = state.useDirectMode ? "direct" : "via gateway";
|
|
894
|
+
const modeStr = state.useDirectMode ? "direct" : state.currentProvider === "local" ? "local daemon" : "via gateway";
|
|
828
895
|
console.log(`
|
|
829
896
|
Current provider: ${c.green(state.currentProvider)} (${modeStr})
|
|
830
897
|
`);
|
|
@@ -902,8 +969,8 @@ async function connectToSandbox(state, sandboxUrl, token) {
|
|
|
902
969
|
}
|
|
903
970
|
const cleanUrl = sandboxUrl.replace(/\/$/, "");
|
|
904
971
|
if (hasSandbox(state)) {
|
|
905
|
-
const
|
|
906
|
-
if (!
|
|
972
|
+
const shouldDisconnect = await confirm("Disconnect from current sandbox?", false, state);
|
|
973
|
+
if (!shouldDisconnect) {
|
|
907
974
|
logWarning("Keeping current sandbox. Connection cancelled.");
|
|
908
975
|
return;
|
|
909
976
|
}
|
|
@@ -949,6 +1016,125 @@ async function connectToSandbox(state, sandboxUrl, token) {
|
|
|
949
1016
|
throw error;
|
|
950
1017
|
}
|
|
951
1018
|
}
|
|
1019
|
+
async function readLocalConfig() {
|
|
1020
|
+
const os2 = await import("os");
|
|
1021
|
+
const fs = await import("fs/promises");
|
|
1022
|
+
const path3 = await import("path");
|
|
1023
|
+
const configPath = path3.join(os2.homedir(), ".compute", "config.json");
|
|
1024
|
+
try {
|
|
1025
|
+
const content = await fs.readFile(configPath, "utf-8");
|
|
1026
|
+
return JSON.parse(content);
|
|
1027
|
+
} catch {
|
|
1028
|
+
return null;
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
async function isLocalDaemonRunning() {
|
|
1032
|
+
const os2 = await import("os");
|
|
1033
|
+
const fs = await import("fs/promises");
|
|
1034
|
+
const path3 = await import("path");
|
|
1035
|
+
const pidPath = path3.join(os2.homedir(), ".compute", "compute.pid");
|
|
1036
|
+
try {
|
|
1037
|
+
const pidContent = await fs.readFile(pidPath, "utf-8");
|
|
1038
|
+
const pid = parseInt(pidContent.trim(), 10);
|
|
1039
|
+
process.kill(pid, 0);
|
|
1040
|
+
return true;
|
|
1041
|
+
} catch {
|
|
1042
|
+
return false;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
async function listLocalSandboxes() {
|
|
1046
|
+
const config = await readLocalConfig();
|
|
1047
|
+
if (!config) {
|
|
1048
|
+
logError("No local daemon config found at ~/.compute/config.json");
|
|
1049
|
+
console.log(c.dim('Run "compute start" to start the local daemon'));
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
const isRunning = await isLocalDaemonRunning();
|
|
1053
|
+
console.log("");
|
|
1054
|
+
console.log(c.bold("Local Daemon Status:"), isRunning ? c.green("Running") : c.red("Stopped"));
|
|
1055
|
+
console.log("");
|
|
1056
|
+
if (!config.sandboxes || config.sandboxes.length === 0) {
|
|
1057
|
+
console.log(c.dim("No sandboxes found"));
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
console.log(c.bold("Sandboxes:"));
|
|
1061
|
+
for (const sandbox of config.sandboxes) {
|
|
1062
|
+
const isMain = sandbox.subdomain === config.main_subdomain;
|
|
1063
|
+
const mainLabel = isMain ? c.green(" (main)") : "";
|
|
1064
|
+
console.log(` ${c.cyan(sandbox.subdomain)}${mainLabel}`);
|
|
1065
|
+
console.log(c.dim(` https://${sandbox.subdomain}.sandbox.computesdk.com`));
|
|
1066
|
+
}
|
|
1067
|
+
console.log("");
|
|
1068
|
+
console.log(c.dim(`Connect with: local ${config.main_subdomain}`));
|
|
1069
|
+
console.log("");
|
|
1070
|
+
}
|
|
1071
|
+
async function connectToLocal(state, subdomain) {
|
|
1072
|
+
const config = await readLocalConfig();
|
|
1073
|
+
if (!config) {
|
|
1074
|
+
logError("No local daemon config found at ~/.compute/config.json");
|
|
1075
|
+
console.log(c.dim('Run "compute start" to start the local daemon'));
|
|
1076
|
+
return;
|
|
1077
|
+
}
|
|
1078
|
+
const isRunning = await isLocalDaemonRunning();
|
|
1079
|
+
if (!isRunning) {
|
|
1080
|
+
logError("Local daemon is not running");
|
|
1081
|
+
console.log(c.dim('Run "compute start" to start the local daemon'));
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1084
|
+
const targetSubdomain = subdomain || config.main_subdomain;
|
|
1085
|
+
const sandbox = config.sandboxes.find((s) => s.subdomain === targetSubdomain);
|
|
1086
|
+
if (!sandbox) {
|
|
1087
|
+
logError(`Sandbox "${targetSubdomain}" not found`);
|
|
1088
|
+
console.log(c.dim('Run "local list" to see available sandboxes'));
|
|
1089
|
+
return;
|
|
1090
|
+
}
|
|
1091
|
+
const sandboxUrl = `https://${targetSubdomain}.sandbox.computesdk.com`;
|
|
1092
|
+
const token = config.access_token;
|
|
1093
|
+
if (hasSandbox(state)) {
|
|
1094
|
+
const shouldDisconnect = await confirm("Disconnect from current sandbox?", false, state);
|
|
1095
|
+
if (!shouldDisconnect) {
|
|
1096
|
+
logWarning("Keeping current sandbox. Connection cancelled.");
|
|
1097
|
+
return;
|
|
1098
|
+
}
|
|
1099
|
+
clearSandbox(state);
|
|
1100
|
+
}
|
|
1101
|
+
const spinner = new Spinner(`Connecting to local sandbox ${targetSubdomain}...`).start();
|
|
1102
|
+
const startTime = Date.now();
|
|
1103
|
+
try {
|
|
1104
|
+
const { Sandbox } = await import("computesdk");
|
|
1105
|
+
let WebSocket;
|
|
1106
|
+
try {
|
|
1107
|
+
const wsModule = await import("ws");
|
|
1108
|
+
WebSocket = wsModule.default;
|
|
1109
|
+
} catch {
|
|
1110
|
+
spinner.fail('Failed to import "ws" module');
|
|
1111
|
+
logError("Please install ws: pnpm add ws");
|
|
1112
|
+
throw new Error('Missing "ws" dependency');
|
|
1113
|
+
}
|
|
1114
|
+
const sandboxInstance = new Sandbox({
|
|
1115
|
+
sandboxUrl,
|
|
1116
|
+
sandboxId: targetSubdomain,
|
|
1117
|
+
provider: "local",
|
|
1118
|
+
token,
|
|
1119
|
+
WebSocket
|
|
1120
|
+
});
|
|
1121
|
+
const info = await sandboxInstance.getInfo();
|
|
1122
|
+
const duration = Date.now() - startTime;
|
|
1123
|
+
setSandbox(state, sandboxInstance, "local");
|
|
1124
|
+
state.verbose = true;
|
|
1125
|
+
spinner.succeed(`Connected to local sandbox ${c.dim(`(${formatDuration(duration)})`)}`);
|
|
1126
|
+
console.log(c.dim(`Sandbox: ${targetSubdomain}`));
|
|
1127
|
+
console.log(c.dim(`URL: ${sandboxUrl}`));
|
|
1128
|
+
console.log(c.dim(`Verbose mode: enabled (for debugging)`));
|
|
1129
|
+
} catch (error) {
|
|
1130
|
+
const duration = Date.now() - startTime;
|
|
1131
|
+
spinner.fail(`Failed to connect ${c.dim(`(${formatDuration(duration)})`)}`);
|
|
1132
|
+
if (error instanceof Error) {
|
|
1133
|
+
logError(`Error: ${error.message}`);
|
|
1134
|
+
}
|
|
1135
|
+
throw error;
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
952
1138
|
async function cleanupOnExit(state, replServer) {
|
|
953
1139
|
if (!hasSandbox(state)) {
|
|
954
1140
|
return;
|
|
@@ -961,7 +1147,7 @@ async function cleanupOnExit(state, replServer) {
|
|
|
961
1147
|
logWarning("Disconnecting from external sandbox (not destroying).");
|
|
962
1148
|
return;
|
|
963
1149
|
}
|
|
964
|
-
const shouldDestroy = await confirm("Destroy active sandbox?");
|
|
1150
|
+
const shouldDestroy = await confirm("Destroy active sandbox?", false, state);
|
|
965
1151
|
if (shouldDestroy) {
|
|
966
1152
|
await destroySandbox(state);
|
|
967
1153
|
} else {
|
|
@@ -1351,6 +1537,59 @@ function injectWorkbenchCommands(replServer, state) {
|
|
|
1351
1537
|
};
|
|
1352
1538
|
}
|
|
1353
1539
|
};
|
|
1540
|
+
replServer.context.terminal = {
|
|
1541
|
+
get create() {
|
|
1542
|
+
return async (options) => {
|
|
1543
|
+
const sandbox = state.currentSandbox;
|
|
1544
|
+
if (!sandbox) {
|
|
1545
|
+
throw new Error("No active sandbox. Run a command to auto-create one.");
|
|
1546
|
+
}
|
|
1547
|
+
const term = await sandbox.terminal.create(options);
|
|
1548
|
+
if (state.verbose) {
|
|
1549
|
+
if (term._ws) {
|
|
1550
|
+
term._ws.config.debug = true;
|
|
1551
|
+
}
|
|
1552
|
+
term.on("output", (data) => {
|
|
1553
|
+
console.log("[terminal:output]", JSON.stringify(data));
|
|
1554
|
+
});
|
|
1555
|
+
term.on("error", (error) => {
|
|
1556
|
+
console.log("[terminal:error]", error);
|
|
1557
|
+
});
|
|
1558
|
+
term.on("destroyed", () => {
|
|
1559
|
+
console.log("[terminal:destroyed]");
|
|
1560
|
+
});
|
|
1561
|
+
}
|
|
1562
|
+
return term;
|
|
1563
|
+
};
|
|
1564
|
+
},
|
|
1565
|
+
get list() {
|
|
1566
|
+
return async () => {
|
|
1567
|
+
const sandbox = state.currentSandbox;
|
|
1568
|
+
if (!sandbox) {
|
|
1569
|
+
throw new Error("No active sandbox. Run a command to auto-create one.");
|
|
1570
|
+
}
|
|
1571
|
+
return sandbox.terminal.list();
|
|
1572
|
+
};
|
|
1573
|
+
},
|
|
1574
|
+
get retrieve() {
|
|
1575
|
+
return async (id) => {
|
|
1576
|
+
const sandbox = state.currentSandbox;
|
|
1577
|
+
if (!sandbox) {
|
|
1578
|
+
throw new Error("No active sandbox. Run a command to auto-create one.");
|
|
1579
|
+
}
|
|
1580
|
+
return sandbox.terminal.retrieve(id);
|
|
1581
|
+
};
|
|
1582
|
+
},
|
|
1583
|
+
get destroy() {
|
|
1584
|
+
return async (id) => {
|
|
1585
|
+
const sandbox = state.currentSandbox;
|
|
1586
|
+
if (!sandbox) {
|
|
1587
|
+
throw new Error("No active sandbox. Run a command to auto-create one.");
|
|
1588
|
+
}
|
|
1589
|
+
return sandbox.terminal.destroy(id);
|
|
1590
|
+
};
|
|
1591
|
+
}
|
|
1592
|
+
};
|
|
1354
1593
|
replServer.context.getInstance = () => {
|
|
1355
1594
|
const sandbox = state.currentSandbox;
|
|
1356
1595
|
if (!sandbox) {
|
|
@@ -1364,6 +1603,13 @@ function setupSmartEvaluator(replServer, state) {
|
|
|
1364
1603
|
const workbenchCommands = /* @__PURE__ */ new Set(["help", "providers", "info", "env", "restart", "destroy", "mode", "verbose", "sandboxInfo", "connect"]);
|
|
1365
1604
|
replServer.eval = function(cmd2, context, filename, callback) {
|
|
1366
1605
|
const trimmedCmd = cmd2.trim();
|
|
1606
|
+
const providerLocalMatch = trimmedCmd.match(/^provider\s+local(?:\s+(\S+))?$/);
|
|
1607
|
+
if (providerLocalMatch) {
|
|
1608
|
+
const arg = providerLocalMatch[1];
|
|
1609
|
+
const providerCmd = arg ? `await provider('local', '${arg}')` : `await provider('local')`;
|
|
1610
|
+
originalEval.call(this, providerCmd, context, filename, callback);
|
|
1611
|
+
return;
|
|
1612
|
+
}
|
|
1367
1613
|
const providerMatch = trimmedCmd.match(/^provider(?:\s+(direct|gateway))?\s+(\w+)$/);
|
|
1368
1614
|
if (providerMatch) {
|
|
1369
1615
|
const mode = providerMatch[1] || null;
|
|
@@ -1436,8 +1682,8 @@ function setupSmartEvaluator(replServer, state) {
|
|
|
1436
1682
|
function setupAutocomplete(replServer, state) {
|
|
1437
1683
|
const originalCompleter = replServer.completer;
|
|
1438
1684
|
const workbenchCommands = {
|
|
1439
|
-
"provider": [...PROVIDER_NAMES],
|
|
1440
|
-
//
|
|
1685
|
+
"provider": [...PROVIDER_NAMES, "local"],
|
|
1686
|
+
// Include 'local' as a provider option
|
|
1441
1687
|
"mode": ["gateway", "direct"],
|
|
1442
1688
|
"providers": [],
|
|
1443
1689
|
"restart": [],
|
|
@@ -1542,22 +1788,38 @@ init_providers();
|
|
|
1542
1788
|
init_commands();
|
|
1543
1789
|
async function startWorkbench() {
|
|
1544
1790
|
const state = createState();
|
|
1791
|
+
const localDaemonRunning = await isLocalDaemonRunning();
|
|
1545
1792
|
state.availableProviders = getAvailableProviders();
|
|
1793
|
+
if (localDaemonRunning) {
|
|
1794
|
+
state.availableProviders.push("local");
|
|
1795
|
+
}
|
|
1546
1796
|
const detectedProvider = autoDetectProvider();
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
if (hasGateway && backendProviders.length > 0) {
|
|
1550
|
-
state.currentProvider = backendProviders[0] || "e2b";
|
|
1797
|
+
if (localDaemonRunning) {
|
|
1798
|
+
state.currentProvider = "local";
|
|
1551
1799
|
state.useDirectMode = false;
|
|
1552
|
-
|
|
1553
|
-
state.currentProvider = backendProviders[0];
|
|
1554
|
-
state.useDirectMode = true;
|
|
1800
|
+
state.verbose = true;
|
|
1555
1801
|
} else {
|
|
1556
|
-
|
|
1557
|
-
state.
|
|
1802
|
+
const hasGateway = state.availableProviders.includes("gateway");
|
|
1803
|
+
const backendProviders = state.availableProviders.filter((p) => p !== "gateway" && p !== "local");
|
|
1804
|
+
if (hasGateway && backendProviders.length > 0) {
|
|
1805
|
+
state.currentProvider = backendProviders[0] || "e2b";
|
|
1806
|
+
state.useDirectMode = false;
|
|
1807
|
+
} else if (backendProviders.length > 0) {
|
|
1808
|
+
state.currentProvider = backendProviders[0];
|
|
1809
|
+
state.useDirectMode = true;
|
|
1810
|
+
} else {
|
|
1811
|
+
state.currentProvider = detectedProvider;
|
|
1812
|
+
state.useDirectMode = false;
|
|
1813
|
+
}
|
|
1558
1814
|
}
|
|
1559
|
-
showWelcome(state.availableProviders, state.currentProvider, state.useDirectMode);
|
|
1815
|
+
showWelcome(state.availableProviders, state.currentProvider, state.useDirectMode, localDaemonRunning);
|
|
1560
1816
|
const replServer = createREPL(state);
|
|
1817
|
+
if (localDaemonRunning) {
|
|
1818
|
+
try {
|
|
1819
|
+
await connectToLocal(state);
|
|
1820
|
+
} catch {
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1561
1823
|
replServer.on("exit", async () => {
|
|
1562
1824
|
await cleanupOnExit(state, replServer);
|
|
1563
1825
|
process.exit(0);
|