@computesdk/workbench 0.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/LICENSE +21 -0
- package/README.md +225 -0
- package/dist/bin/workbench.d.ts +1 -0
- package/dist/bin/workbench.js +893 -0
- package/dist/bin/workbench.js.map +1 -0
- package/dist/helpers.d.ts +42 -0
- package/dist/helpers.js +26 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +883 -0
- package/dist/index.js.map +1 -0
- package/package.json +105 -0
- package/src/bin/workbench-ts.ts +19 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,883 @@
|
|
|
1
|
+
// src/cli/state.ts
|
|
2
|
+
function createState() {
|
|
3
|
+
return {
|
|
4
|
+
currentProvider: null,
|
|
5
|
+
currentSandbox: null,
|
|
6
|
+
sandboxCreatedAt: null,
|
|
7
|
+
availableProviders: [],
|
|
8
|
+
forceGatewayMode: false,
|
|
9
|
+
verbose: false
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function getCurrentSandbox(state) {
|
|
13
|
+
if (!state.currentSandbox) {
|
|
14
|
+
throw new Error("No active sandbox");
|
|
15
|
+
}
|
|
16
|
+
return state.currentSandbox;
|
|
17
|
+
}
|
|
18
|
+
function setSandbox(state, sandbox, provider) {
|
|
19
|
+
state.currentSandbox = sandbox;
|
|
20
|
+
state.currentProvider = provider;
|
|
21
|
+
state.sandboxCreatedAt = /* @__PURE__ */ new Date();
|
|
22
|
+
}
|
|
23
|
+
function clearSandbox(state) {
|
|
24
|
+
state.currentSandbox = null;
|
|
25
|
+
state.sandboxCreatedAt = null;
|
|
26
|
+
}
|
|
27
|
+
function hasSandbox(state) {
|
|
28
|
+
return state.currentSandbox !== null;
|
|
29
|
+
}
|
|
30
|
+
function getUptimeSeconds(state) {
|
|
31
|
+
if (!state.sandboxCreatedAt) return 0;
|
|
32
|
+
return Math.floor((Date.now() - state.sandboxCreatedAt.getTime()) / 1e3);
|
|
33
|
+
}
|
|
34
|
+
function formatUptime(state) {
|
|
35
|
+
const seconds = getUptimeSeconds(state);
|
|
36
|
+
if (seconds < 60) {
|
|
37
|
+
return `${seconds} second${seconds === 1 ? "" : "s"}`;
|
|
38
|
+
}
|
|
39
|
+
const minutes = Math.floor(seconds / 60);
|
|
40
|
+
if (minutes < 60) {
|
|
41
|
+
return `${minutes} minute${minutes === 1 ? "" : "s"}`;
|
|
42
|
+
}
|
|
43
|
+
const hours = Math.floor(minutes / 60);
|
|
44
|
+
const remainingMinutes = minutes % 60;
|
|
45
|
+
return `${hours}h ${remainingMinutes}m`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/cli/repl.ts
|
|
49
|
+
import * as repl from "repl";
|
|
50
|
+
import * as cmd from "@computesdk/cmd";
|
|
51
|
+
|
|
52
|
+
// src/cli/commands.ts
|
|
53
|
+
import { createCompute } from "computesdk";
|
|
54
|
+
|
|
55
|
+
// src/cli/output.ts
|
|
56
|
+
var colors = {
|
|
57
|
+
reset: "\x1B[0m",
|
|
58
|
+
bright: "\x1B[1m",
|
|
59
|
+
dim: "\x1B[2m",
|
|
60
|
+
cyan: "\x1B[36m",
|
|
61
|
+
green: "\x1B[32m",
|
|
62
|
+
yellow: "\x1B[33m",
|
|
63
|
+
red: "\x1B[31m",
|
|
64
|
+
blue: "\x1B[34m",
|
|
65
|
+
magenta: "\x1B[35m"
|
|
66
|
+
};
|
|
67
|
+
var c = {
|
|
68
|
+
bold: (text) => `${colors.bright}${text}${colors.reset}`,
|
|
69
|
+
dim: (text) => `${colors.dim}${text}${colors.reset}`,
|
|
70
|
+
cyan: (text) => `${colors.cyan}${text}${colors.reset}`,
|
|
71
|
+
green: (text) => `${colors.green}${text}${colors.reset}`,
|
|
72
|
+
yellow: (text) => `${colors.yellow}${text}${colors.reset}`,
|
|
73
|
+
red: (text) => `${colors.red}${text}${colors.reset}`,
|
|
74
|
+
blue: (text) => `${colors.blue}${text}${colors.reset}`,
|
|
75
|
+
magenta: (text) => `${colors.magenta}${text}${colors.reset}`
|
|
76
|
+
};
|
|
77
|
+
function showWelcome(availableProviders, currentProvider) {
|
|
78
|
+
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
|
+
console.log(c.bold(c.cyan("\u2551 ComputeSDK Workbench \u2551")));
|
|
80
|
+
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
|
+
if (availableProviders.length > 0) {
|
|
82
|
+
console.log(`Providers available: ${availableProviders.join(", ")}`);
|
|
83
|
+
if (currentProvider) {
|
|
84
|
+
const mode = currentProvider === "gateway" ? "\u{1F310} gateway mode" : "\u{1F517} direct mode";
|
|
85
|
+
console.log(`Current provider: ${c.green(currentProvider)} (${mode})
|
|
86
|
+
`);
|
|
87
|
+
} else {
|
|
88
|
+
console.log(`
|
|
89
|
+
${c.dim('Tip: Use "provider <name>" to select a provider')}
|
|
90
|
+
`);
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
console.log(c.yellow("\u26A0\uFE0F No providers detected.\n"));
|
|
94
|
+
console.log("To get started:");
|
|
95
|
+
console.log(" 1. Copy .env.example to .env");
|
|
96
|
+
console.log(" 2. Add your provider credentials");
|
|
97
|
+
console.log(" 3. Restart workbench\n");
|
|
98
|
+
console.log(c.dim('Type "env" to see required environment variables\n'));
|
|
99
|
+
}
|
|
100
|
+
console.log(c.dim('Type "help" for available commands\n'));
|
|
101
|
+
}
|
|
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
|
+
function showInfo(state) {
|
|
155
|
+
if (!state.currentSandbox) {
|
|
156
|
+
console.log(c.yellow("\nNo active sandbox\n"));
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
console.log("\n" + c.bold("Current Sandbox:"));
|
|
160
|
+
console.log(` Provider: ${c.green(state.currentProvider || "unknown")}`);
|
|
161
|
+
console.log(` Created: ${state.sandboxCreatedAt?.toLocaleString() || "unknown"}`);
|
|
162
|
+
console.log(` Uptime: ${formatUptime(state)}`);
|
|
163
|
+
console.log("");
|
|
164
|
+
}
|
|
165
|
+
var Spinner = class {
|
|
166
|
+
constructor(text) {
|
|
167
|
+
this.interval = null;
|
|
168
|
+
this.frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
169
|
+
this.currentFrame = 0;
|
|
170
|
+
this.text = text;
|
|
171
|
+
}
|
|
172
|
+
start() {
|
|
173
|
+
process.stdout.write("\x1B[?25l");
|
|
174
|
+
this.interval = setInterval(() => {
|
|
175
|
+
const frame = this.frames[this.currentFrame];
|
|
176
|
+
process.stdout.write(`\r${c.cyan(frame)} ${this.text}`);
|
|
177
|
+
this.currentFrame = (this.currentFrame + 1) % this.frames.length;
|
|
178
|
+
}, 80);
|
|
179
|
+
return this;
|
|
180
|
+
}
|
|
181
|
+
succeed(text) {
|
|
182
|
+
this.stop();
|
|
183
|
+
console.log(`${c.green("\u2705")} ${text || this.text}`);
|
|
184
|
+
}
|
|
185
|
+
fail(text) {
|
|
186
|
+
this.stop();
|
|
187
|
+
console.log(`${c.red("\u274C")} ${text || this.text}`);
|
|
188
|
+
}
|
|
189
|
+
stop() {
|
|
190
|
+
if (this.interval) {
|
|
191
|
+
clearInterval(this.interval);
|
|
192
|
+
this.interval = null;
|
|
193
|
+
}
|
|
194
|
+
process.stdout.write("\r\x1B[K");
|
|
195
|
+
process.stdout.write("\x1B[?25h");
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
function formatDuration(ms) {
|
|
199
|
+
const seconds = ms / 1e3;
|
|
200
|
+
if (seconds < 1) {
|
|
201
|
+
return `${ms}ms`;
|
|
202
|
+
}
|
|
203
|
+
return `${seconds.toFixed(1)}s`;
|
|
204
|
+
}
|
|
205
|
+
function logCommand(command) {
|
|
206
|
+
console.log(c.dim(`Running: ${command.join(" ")}`));
|
|
207
|
+
}
|
|
208
|
+
function logSuccess(message, duration) {
|
|
209
|
+
const durationStr = duration ? ` (${formatDuration(duration)})` : "";
|
|
210
|
+
console.log(c.green(`\u2705 ${message}${durationStr}`));
|
|
211
|
+
}
|
|
212
|
+
function logError(message) {
|
|
213
|
+
console.log(c.red(`\u274C ${message}`));
|
|
214
|
+
}
|
|
215
|
+
function logWarning(message) {
|
|
216
|
+
console.log(c.yellow(`\u26A0\uFE0F ${message}`));
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// src/cli/providers.ts
|
|
220
|
+
var PROVIDER_NAMES = [
|
|
221
|
+
"gateway",
|
|
222
|
+
"e2b",
|
|
223
|
+
"railway",
|
|
224
|
+
"daytona",
|
|
225
|
+
"modal",
|
|
226
|
+
"runloop",
|
|
227
|
+
"vercel",
|
|
228
|
+
"cloudflare",
|
|
229
|
+
"codesandbox",
|
|
230
|
+
"blaxel"
|
|
231
|
+
];
|
|
232
|
+
var PROVIDER_ENV_VARS = {
|
|
233
|
+
gateway: ["COMPUTESDK_API_KEY"],
|
|
234
|
+
e2b: ["E2B_API_KEY"],
|
|
235
|
+
railway: ["RAILWAY_API_KEY", "RAILWAY_PROJECT_ID", "RAILWAY_ENVIRONMENT_ID"],
|
|
236
|
+
daytona: ["DAYTONA_API_KEY"],
|
|
237
|
+
modal: ["MODAL_TOKEN_ID", "MODAL_TOKEN_SECRET"],
|
|
238
|
+
runloop: ["RUNLOOP_API_KEY"],
|
|
239
|
+
vercel: ["VERCEL_TOKEN", "VERCEL_TEAM_ID", "VERCEL_PROJECT_ID"],
|
|
240
|
+
cloudflare: ["CLOUDFLARE_API_TOKEN", "CLOUDFLARE_ACCOUNT_ID"],
|
|
241
|
+
codesandbox: ["CSB_API_KEY"],
|
|
242
|
+
blaxel: ["BL_API_KEY", "BL_WORKSPACE"]
|
|
243
|
+
};
|
|
244
|
+
function getProviderStatus(provider) {
|
|
245
|
+
if (typeof process === "undefined") {
|
|
246
|
+
return {
|
|
247
|
+
name: provider,
|
|
248
|
+
isComplete: false,
|
|
249
|
+
present: [],
|
|
250
|
+
missing: [...PROVIDER_ENV_VARS[provider]]
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
const requiredVars = PROVIDER_ENV_VARS[provider];
|
|
254
|
+
const present = requiredVars.filter((varName) => !!process.env?.[varName]);
|
|
255
|
+
const missing = requiredVars.filter((varName) => !process.env?.[varName]);
|
|
256
|
+
return {
|
|
257
|
+
name: provider,
|
|
258
|
+
isComplete: missing.length === 0,
|
|
259
|
+
present: [...present],
|
|
260
|
+
missing: [...missing]
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
function getAvailableProviders() {
|
|
264
|
+
return PROVIDER_NAMES.filter((provider) => {
|
|
265
|
+
const status = getProviderStatus(provider);
|
|
266
|
+
return status.isComplete;
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
function showProviders() {
|
|
270
|
+
console.log("\n" + c.bold("Provider Status:"));
|
|
271
|
+
for (const provider of PROVIDER_NAMES) {
|
|
272
|
+
const status = getProviderStatus(provider);
|
|
273
|
+
if (status.isComplete) {
|
|
274
|
+
console.log(` ${c.green("\u2705")} ${provider} - Ready`);
|
|
275
|
+
} else if (status.present.length > 0) {
|
|
276
|
+
const ratio = `${status.present.length}/${status.present.length + status.missing.length}`;
|
|
277
|
+
console.log(` ${c.yellow("\u26A0\uFE0F ")} ${provider} - Incomplete (${ratio} credentials)`);
|
|
278
|
+
console.log(` ${c.dim("Missing:")} ${status.missing.join(", ")}`);
|
|
279
|
+
} else {
|
|
280
|
+
console.log(` ${c.dim("\u274C")} ${c.dim(provider)} - Not configured`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
console.log("");
|
|
284
|
+
}
|
|
285
|
+
function showEnv() {
|
|
286
|
+
console.log("\n" + c.bold("Environment Configuration:"));
|
|
287
|
+
console.log("");
|
|
288
|
+
for (const provider of PROVIDER_NAMES) {
|
|
289
|
+
const status = getProviderStatus(provider);
|
|
290
|
+
console.log(c.bold(`${provider}:`));
|
|
291
|
+
if (status.isComplete) {
|
|
292
|
+
console.log(` ${c.green("\u2705")} All credentials present`);
|
|
293
|
+
status.present.forEach((varName) => {
|
|
294
|
+
console.log(` ${c.dim("\u2022")} ${varName}`);
|
|
295
|
+
});
|
|
296
|
+
} else {
|
|
297
|
+
if (status.present.length > 0) {
|
|
298
|
+
console.log(c.dim(" Present:"));
|
|
299
|
+
status.present.forEach((varName) => {
|
|
300
|
+
console.log(` ${c.green("\u2713")} ${varName}`);
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
if (status.missing.length > 0) {
|
|
304
|
+
console.log(c.dim(" Missing:"));
|
|
305
|
+
status.missing.forEach((varName) => {
|
|
306
|
+
console.log(` ${c.red("\u2717")} ${varName}`);
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
console.log("");
|
|
311
|
+
}
|
|
312
|
+
console.log(c.dim("Tip: Set credentials in your .env file"));
|
|
313
|
+
console.log("");
|
|
314
|
+
}
|
|
315
|
+
function autoDetectProvider(forceGatewayMode = false) {
|
|
316
|
+
const explicit = process.env.COMPUTESDK_PROVIDER?.toLowerCase();
|
|
317
|
+
if (explicit && isValidProvider(explicit) && isProviderReady(explicit)) {
|
|
318
|
+
return explicit;
|
|
319
|
+
}
|
|
320
|
+
if (forceGatewayMode) {
|
|
321
|
+
return isProviderReady("gateway") ? "gateway" : null;
|
|
322
|
+
}
|
|
323
|
+
for (const provider of PROVIDER_NAMES) {
|
|
324
|
+
if (isProviderReady(provider)) {
|
|
325
|
+
return provider;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
function isValidProvider(name) {
|
|
331
|
+
return PROVIDER_NAMES.includes(name);
|
|
332
|
+
}
|
|
333
|
+
function isProviderReady(provider) {
|
|
334
|
+
if (!isValidProvider(provider)) return false;
|
|
335
|
+
const status = getProviderStatus(provider);
|
|
336
|
+
return status.isComplete;
|
|
337
|
+
}
|
|
338
|
+
function getProviderSetupHelp(provider) {
|
|
339
|
+
if (!isValidProvider(provider)) {
|
|
340
|
+
return `Unknown provider: ${provider}
|
|
341
|
+
Available: ${PROVIDER_NAMES.join(", ")}`;
|
|
342
|
+
}
|
|
343
|
+
const status = getProviderStatus(provider);
|
|
344
|
+
if (status.isComplete) {
|
|
345
|
+
return `Provider ${provider} is already configured`;
|
|
346
|
+
}
|
|
347
|
+
const lines = [
|
|
348
|
+
`Provider ${provider} requires these environment variables:`,
|
|
349
|
+
"",
|
|
350
|
+
...status.missing.map((varName) => ` ${varName}`),
|
|
351
|
+
"",
|
|
352
|
+
"Add them to your .env file or export them in your shell."
|
|
353
|
+
];
|
|
354
|
+
return lines.join("\n");
|
|
355
|
+
}
|
|
356
|
+
async function loadProvider(providerName) {
|
|
357
|
+
try {
|
|
358
|
+
switch (providerName) {
|
|
359
|
+
case "gateway":
|
|
360
|
+
return await import("computesdk");
|
|
361
|
+
case "e2b":
|
|
362
|
+
return await import("@computesdk/e2b");
|
|
363
|
+
case "railway":
|
|
364
|
+
return await import("@computesdk/railway");
|
|
365
|
+
case "daytona":
|
|
366
|
+
return await import("@computesdk/daytona");
|
|
367
|
+
case "modal":
|
|
368
|
+
return await import("@computesdk/modal");
|
|
369
|
+
case "runloop":
|
|
370
|
+
return await import("@computesdk/runloop");
|
|
371
|
+
case "vercel":
|
|
372
|
+
return await import("@computesdk/vercel");
|
|
373
|
+
case "cloudflare":
|
|
374
|
+
return await import("@computesdk/cloudflare");
|
|
375
|
+
case "codesandbox":
|
|
376
|
+
return await import("@computesdk/codesandbox");
|
|
377
|
+
case "blaxel":
|
|
378
|
+
return await import("@computesdk/blaxel");
|
|
379
|
+
default:
|
|
380
|
+
throw new Error(`Unknown provider: ${providerName}`);
|
|
381
|
+
}
|
|
382
|
+
} catch (error) {
|
|
383
|
+
if (providerName === "gateway") {
|
|
384
|
+
throw new Error(`Failed to load gateway provider from computesdk package.`);
|
|
385
|
+
}
|
|
386
|
+
throw new Error(
|
|
387
|
+
`Failed to load provider ${providerName}. Make sure to install it: npm install @computesdk/${providerName}`
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
function getProviderConfig(providerName) {
|
|
392
|
+
const config = {};
|
|
393
|
+
const requiredVars = PROVIDER_ENV_VARS[providerName];
|
|
394
|
+
for (const varName of requiredVars) {
|
|
395
|
+
const value = process.env[varName];
|
|
396
|
+
if (value) {
|
|
397
|
+
config[varName] = value;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return config;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// src/cli/commands.ts
|
|
404
|
+
import * as readline from "readline";
|
|
405
|
+
async function confirm(question) {
|
|
406
|
+
return new Promise((resolve) => {
|
|
407
|
+
const rl = readline.createInterface({
|
|
408
|
+
input: process.stdin,
|
|
409
|
+
output: process.stdout
|
|
410
|
+
});
|
|
411
|
+
process.stdin.resume();
|
|
412
|
+
rl.question(`${question} (y/N): `, (answer) => {
|
|
413
|
+
rl.close();
|
|
414
|
+
const trimmed = answer.trim().toLowerCase();
|
|
415
|
+
resolve(trimmed === "y" || trimmed === "yes");
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
async function ensureSandbox(state) {
|
|
420
|
+
if (hasSandbox(state)) {
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
await createSandbox(state);
|
|
424
|
+
}
|
|
425
|
+
async function createSandbox(state) {
|
|
426
|
+
const providerName = state.currentProvider || autoDetectProvider(state.forceGatewayMode);
|
|
427
|
+
if (!providerName) {
|
|
428
|
+
logError('No provider configured. Run "env" to see setup instructions.');
|
|
429
|
+
throw new Error("No provider available");
|
|
430
|
+
}
|
|
431
|
+
if (!isProviderReady(providerName)) {
|
|
432
|
+
logError(`Provider ${providerName} is not fully configured.`);
|
|
433
|
+
console.log(getProviderSetupHelp(providerName));
|
|
434
|
+
throw new Error("Provider not ready");
|
|
435
|
+
}
|
|
436
|
+
const spinner = new Spinner(`Creating sandbox with ${providerName}...`).start();
|
|
437
|
+
const startTime = Date.now();
|
|
438
|
+
try {
|
|
439
|
+
let compute;
|
|
440
|
+
if (providerName === "gateway") {
|
|
441
|
+
compute = createCompute();
|
|
442
|
+
} else {
|
|
443
|
+
const providerModule = await loadProvider(providerName);
|
|
444
|
+
const providerFactory = providerModule[providerName];
|
|
445
|
+
if (!providerFactory) {
|
|
446
|
+
throw new Error(`Provider ${providerName} does not export a factory function`);
|
|
447
|
+
}
|
|
448
|
+
const config = getProviderConfig(providerName);
|
|
449
|
+
compute = createCompute({
|
|
450
|
+
defaultProvider: providerFactory(config)
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
const result = await compute.sandbox.create();
|
|
454
|
+
const duration = Date.now() - startTime;
|
|
455
|
+
setSandbox(state, result, providerName);
|
|
456
|
+
spinner.succeed(`Sandbox ready ${c.dim(`(${formatDuration(duration)})`)}`);
|
|
457
|
+
} catch (error) {
|
|
458
|
+
const duration = Date.now() - startTime;
|
|
459
|
+
spinner.fail(`Failed to create sandbox ${c.dim(`(${formatDuration(duration)})`)}`);
|
|
460
|
+
if (error instanceof Error && error.message.includes("Cannot find module")) {
|
|
461
|
+
logError(`Provider package @computesdk/${providerName} is not installed.`);
|
|
462
|
+
console.log(`
|
|
463
|
+
Install it with: ${c.cyan(`npm install @computesdk/${providerName}`)}
|
|
464
|
+
`);
|
|
465
|
+
}
|
|
466
|
+
throw error;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
async function destroySandbox(state) {
|
|
470
|
+
if (!hasSandbox(state)) {
|
|
471
|
+
logWarning("No active sandbox");
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
const spinner = new Spinner("Destroying sandbox...").start();
|
|
475
|
+
try {
|
|
476
|
+
const sandbox = getCurrentSandbox(state);
|
|
477
|
+
await sandbox.destroy();
|
|
478
|
+
clearSandbox(state);
|
|
479
|
+
spinner.succeed("Destroyed");
|
|
480
|
+
} catch (error) {
|
|
481
|
+
spinner.fail(`Failed to destroy: ${error instanceof Error ? error.message : String(error)}`);
|
|
482
|
+
throw error;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
async function restartSandbox(state) {
|
|
486
|
+
const provider = state.currentProvider;
|
|
487
|
+
if (hasSandbox(state)) {
|
|
488
|
+
await destroySandbox(state);
|
|
489
|
+
}
|
|
490
|
+
if (provider) {
|
|
491
|
+
state.currentProvider = provider;
|
|
492
|
+
}
|
|
493
|
+
await createSandbox(state);
|
|
494
|
+
}
|
|
495
|
+
async function runCommand(state, command) {
|
|
496
|
+
await ensureSandbox(state);
|
|
497
|
+
const sandbox = getCurrentSandbox(state);
|
|
498
|
+
const startTime = Date.now();
|
|
499
|
+
logCommand(command);
|
|
500
|
+
try {
|
|
501
|
+
const result = await sandbox.runCommand(command[0], command.slice(1));
|
|
502
|
+
const duration = Date.now() - startTime;
|
|
503
|
+
if (result.stdout) {
|
|
504
|
+
console.log(result.stdout.trimEnd());
|
|
505
|
+
}
|
|
506
|
+
if (result.stderr) {
|
|
507
|
+
console.error(c.red(result.stderr.trimEnd()));
|
|
508
|
+
}
|
|
509
|
+
const exitCodeInfo = result.exitCode !== 0 ? c.yellow(` (exit ${result.exitCode})`) : "";
|
|
510
|
+
logSuccess(`${c.dim(`${formatDuration(duration)}`)}${exitCodeInfo}`);
|
|
511
|
+
if (state.verbose) {
|
|
512
|
+
return result;
|
|
513
|
+
}
|
|
514
|
+
return void 0;
|
|
515
|
+
} catch (error) {
|
|
516
|
+
const duration = Date.now() - startTime;
|
|
517
|
+
logError(`Failed ${c.dim(`(${formatDuration(duration)})`)} - ${error instanceof Error ? error.message : String(error)}`);
|
|
518
|
+
throw error;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
async function switchProvider(state, newProvider) {
|
|
522
|
+
if (!isValidProvider(newProvider)) {
|
|
523
|
+
logError(`Unknown provider: ${newProvider}`);
|
|
524
|
+
console.log(`Available providers: e2b, railway, daytona, modal, runloop, vercel, cloudflare, codesandbox, blaxel`);
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
if (!isProviderReady(newProvider)) {
|
|
528
|
+
logError(`Provider ${newProvider} is not fully configured.`);
|
|
529
|
+
console.log(getProviderSetupHelp(newProvider));
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
if (hasSandbox(state)) {
|
|
533
|
+
const shouldDestroy = await confirm("Destroy current sandbox?");
|
|
534
|
+
if (shouldDestroy) {
|
|
535
|
+
await destroySandbox(state);
|
|
536
|
+
state.currentProvider = newProvider;
|
|
537
|
+
logSuccess(`Switched to ${newProvider}`);
|
|
538
|
+
} else {
|
|
539
|
+
logWarning("Keeping current sandbox. Provider remains unchanged.");
|
|
540
|
+
}
|
|
541
|
+
} else {
|
|
542
|
+
state.currentProvider = newProvider;
|
|
543
|
+
logSuccess(`Switched to ${newProvider}`);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
function createProviderCommand(state) {
|
|
547
|
+
return async function provider(name) {
|
|
548
|
+
if (!name) {
|
|
549
|
+
if (state.currentProvider) {
|
|
550
|
+
console.log(`
|
|
551
|
+
Current provider: ${c.green(state.currentProvider)}
|
|
552
|
+
`);
|
|
553
|
+
} else {
|
|
554
|
+
console.log(c.yellow("\nNo provider selected\n"));
|
|
555
|
+
}
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
await switchProvider(state, name);
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
async function toggleMode(state, mode) {
|
|
562
|
+
const newMode = mode || (state.forceGatewayMode ? "direct" : "gateway");
|
|
563
|
+
if (newMode === "gateway") {
|
|
564
|
+
state.forceGatewayMode = true;
|
|
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;
|
|
573
|
+
logSuccess("Switched to direct mode \u{1F517}");
|
|
574
|
+
console.log(c.dim("Next sandbox will use direct provider packages\n"));
|
|
575
|
+
if (hasSandbox(state) && state.currentProvider === "gateway") {
|
|
576
|
+
console.log(c.yellow("Current sandbox is in gateway mode."));
|
|
577
|
+
console.log(c.dim('Run "restart" to switch to direct mode\n'));
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
function showMode(state) {
|
|
582
|
+
const mode = state.forceGatewayMode || state.currentProvider === "gateway" ? "gateway" : "direct";
|
|
583
|
+
const icon = mode === "gateway" ? "\u{1F310}" : "\u{1F517}";
|
|
584
|
+
console.log(`
|
|
585
|
+
Current mode: ${c.green(mode)} ${icon}`);
|
|
586
|
+
if (mode === "gateway") {
|
|
587
|
+
console.log(c.dim("Routes through ComputeSDK API (requires COMPUTESDK_API_KEY)"));
|
|
588
|
+
} else {
|
|
589
|
+
console.log(c.dim("Direct connection to providers (requires provider packages)"));
|
|
590
|
+
}
|
|
591
|
+
console.log(`
|
|
592
|
+
Toggle with: ${c.cyan("mode gateway")} or ${c.cyan("mode direct")}
|
|
593
|
+
`);
|
|
594
|
+
}
|
|
595
|
+
function toggleVerbose(state) {
|
|
596
|
+
state.verbose = !state.verbose;
|
|
597
|
+
if (state.verbose) {
|
|
598
|
+
logSuccess("Verbose mode enabled - will show full command results");
|
|
599
|
+
console.log(c.dim("Commands will return full result objects with metadata\n"));
|
|
600
|
+
} else {
|
|
601
|
+
logSuccess("Verbose mode disabled - showing clean output only");
|
|
602
|
+
console.log(c.dim("Commands will only show stdout/stderr\n"));
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
function showVerbose(state) {
|
|
606
|
+
const status = state.verbose ? c.green("enabled") : c.dim("disabled");
|
|
607
|
+
console.log(`
|
|
608
|
+
Verbose mode: ${status}`);
|
|
609
|
+
if (state.verbose) {
|
|
610
|
+
console.log(c.dim("Commands return full result objects with metadata"));
|
|
611
|
+
} else {
|
|
612
|
+
console.log(c.dim("Commands show only stdout/stderr"));
|
|
613
|
+
}
|
|
614
|
+
console.log(`
|
|
615
|
+
Toggle with: ${c.cyan("verbose")}
|
|
616
|
+
`);
|
|
617
|
+
}
|
|
618
|
+
async function cleanupOnExit(state, replServer) {
|
|
619
|
+
if (!hasSandbox(state)) {
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
if (replServer) {
|
|
623
|
+
replServer.pause();
|
|
624
|
+
}
|
|
625
|
+
console.log("");
|
|
626
|
+
const shouldDestroy = await confirm("Destroy active sandbox?");
|
|
627
|
+
if (shouldDestroy) {
|
|
628
|
+
await destroySandbox(state);
|
|
629
|
+
} else {
|
|
630
|
+
logWarning("Sandbox left running. It may incur costs.");
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// src/cli/types.ts
|
|
635
|
+
function isCommand(value) {
|
|
636
|
+
return Array.isArray(value) && value.length > 0 && typeof value[0] === "string";
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// src/cli/repl.ts
|
|
640
|
+
import * as path from "path";
|
|
641
|
+
import * as os from "os";
|
|
642
|
+
function createREPL(state) {
|
|
643
|
+
const replServer = repl.start({
|
|
644
|
+
prompt: "workbench> ",
|
|
645
|
+
useColors: true,
|
|
646
|
+
terminal: true,
|
|
647
|
+
useGlobal: false,
|
|
648
|
+
ignoreUndefined: true
|
|
649
|
+
});
|
|
650
|
+
injectCmdContext(replServer);
|
|
651
|
+
injectWorkbenchCommands(replServer, state);
|
|
652
|
+
setupSmartEvaluator(replServer, state);
|
|
653
|
+
setupAutocomplete(replServer, state);
|
|
654
|
+
setupHistory(replServer);
|
|
655
|
+
return replServer;
|
|
656
|
+
}
|
|
657
|
+
function injectCmdContext(replServer) {
|
|
658
|
+
replServer.context.npm = cmd.npm;
|
|
659
|
+
replServer.context.pnpm = cmd.pnpm;
|
|
660
|
+
replServer.context.yarn = cmd.yarn;
|
|
661
|
+
replServer.context.bun = cmd.bun;
|
|
662
|
+
replServer.context.pip = cmd.pip;
|
|
663
|
+
replServer.context.uv = cmd.uv;
|
|
664
|
+
replServer.context.poetry = cmd.poetry;
|
|
665
|
+
replServer.context.pipx = cmd.pipx;
|
|
666
|
+
replServer.context.npx = cmd.npx;
|
|
667
|
+
replServer.context.bunx = cmd.bunx;
|
|
668
|
+
replServer.context.deno = cmd.deno;
|
|
669
|
+
replServer.context.git = cmd.git;
|
|
670
|
+
replServer.context.mkdir = cmd.mkdir;
|
|
671
|
+
replServer.context.rm = cmd.rm;
|
|
672
|
+
replServer.context.cp = cmd.cp;
|
|
673
|
+
replServer.context.mv = cmd.mv;
|
|
674
|
+
replServer.context.ls = cmd.ls;
|
|
675
|
+
replServer.context.pwd = cmd.pwd;
|
|
676
|
+
replServer.context.chmod = cmd.chmod;
|
|
677
|
+
replServer.context.chown = cmd.chown;
|
|
678
|
+
replServer.context.touch = cmd.touch;
|
|
679
|
+
replServer.context.cat = cmd.cat;
|
|
680
|
+
replServer.context.ln = cmd.ln;
|
|
681
|
+
replServer.context.readlink = cmd.readlink;
|
|
682
|
+
replServer.context.test = cmd.test;
|
|
683
|
+
replServer.context.rsync = cmd.rsync;
|
|
684
|
+
replServer.context.node = cmd.node;
|
|
685
|
+
replServer.context.python = cmd.python;
|
|
686
|
+
replServer.context.kill = cmd.kill;
|
|
687
|
+
replServer.context.pkill = cmd.pkill;
|
|
688
|
+
replServer.context.ps = cmd.ps;
|
|
689
|
+
replServer.context.timeout = cmd.timeout;
|
|
690
|
+
replServer.context.curl = cmd.curl;
|
|
691
|
+
replServer.context.wget = cmd.wget;
|
|
692
|
+
replServer.context.port = cmd.port;
|
|
693
|
+
replServer.context.net = cmd.net;
|
|
694
|
+
replServer.context.grep = cmd.grep;
|
|
695
|
+
replServer.context.sed = cmd.sed;
|
|
696
|
+
replServer.context.head = cmd.head;
|
|
697
|
+
replServer.context.tail = cmd.tail;
|
|
698
|
+
replServer.context.wc = cmd.wc;
|
|
699
|
+
replServer.context.sort = cmd.sort;
|
|
700
|
+
replServer.context.uniq = cmd.uniq;
|
|
701
|
+
replServer.context.jq = cmd.jq;
|
|
702
|
+
replServer.context.xargs = cmd.xargs;
|
|
703
|
+
replServer.context.awk = cmd.awk;
|
|
704
|
+
replServer.context.cut = cmd.cut;
|
|
705
|
+
replServer.context.tr = cmd.tr;
|
|
706
|
+
replServer.context.tar = cmd.tar;
|
|
707
|
+
replServer.context.unzip = cmd.unzip;
|
|
708
|
+
replServer.context.echo = cmd.echo;
|
|
709
|
+
replServer.context.env = cmd.env;
|
|
710
|
+
replServer.context.printenv = cmd.printenv;
|
|
711
|
+
replServer.context.which = cmd.which;
|
|
712
|
+
replServer.context.whoami = cmd.whoami;
|
|
713
|
+
replServer.context.uname = cmd.uname;
|
|
714
|
+
replServer.context.hostname = cmd.hostname;
|
|
715
|
+
replServer.context.df = cmd.df;
|
|
716
|
+
replServer.context.du = cmd.du;
|
|
717
|
+
replServer.context.sleep = cmd.sleep;
|
|
718
|
+
replServer.context.date = cmd.date;
|
|
719
|
+
replServer.context.find = cmd.find;
|
|
720
|
+
replServer.context.tee = cmd.tee;
|
|
721
|
+
replServer.context.diff = cmd.diff;
|
|
722
|
+
replServer.context.parallel = cmd.parallel;
|
|
723
|
+
replServer.context.raw = cmd.raw;
|
|
724
|
+
replServer.context.base64 = cmd.base64;
|
|
725
|
+
replServer.context.md5sum = cmd.md5sum;
|
|
726
|
+
replServer.context.sha256sum = cmd.sha256sum;
|
|
727
|
+
replServer.context.sha1sum = cmd.sha1sum;
|
|
728
|
+
replServer.context.cmd = cmd.cmd;
|
|
729
|
+
replServer.context.shell = cmd.shell;
|
|
730
|
+
replServer.context.sh = cmd.sh;
|
|
731
|
+
replServer.context.bash = cmd.bash;
|
|
732
|
+
replServer.context.zsh = cmd.zsh;
|
|
733
|
+
}
|
|
734
|
+
function injectWorkbenchCommands(replServer, state) {
|
|
735
|
+
replServer.context.provider = createProviderCommand(state);
|
|
736
|
+
replServer.context.providers = () => showProviders();
|
|
737
|
+
replServer.context.mode = async (modeName) => {
|
|
738
|
+
if (!modeName) {
|
|
739
|
+
showMode(state);
|
|
740
|
+
} else {
|
|
741
|
+
await toggleMode(state, modeName);
|
|
742
|
+
}
|
|
743
|
+
};
|
|
744
|
+
replServer.context.restart = async () => {
|
|
745
|
+
await restartSandbox(state);
|
|
746
|
+
};
|
|
747
|
+
replServer.context.destroy = async () => {
|
|
748
|
+
await destroySandbox(state);
|
|
749
|
+
};
|
|
750
|
+
replServer.context.info = () => showInfo(state);
|
|
751
|
+
replServer.context.verbose = () => {
|
|
752
|
+
toggleVerbose(state);
|
|
753
|
+
showVerbose(state);
|
|
754
|
+
};
|
|
755
|
+
replServer.context.bg = (command) => {
|
|
756
|
+
const cmdArray = typeof command === "string" ? ["sh", "-c", command] : command;
|
|
757
|
+
return cmd.sh(cmdArray, { background: true });
|
|
758
|
+
};
|
|
759
|
+
replServer.context.env = () => showEnv();
|
|
760
|
+
replServer.context.help = showHelp;
|
|
761
|
+
}
|
|
762
|
+
function setupSmartEvaluator(replServer, state) {
|
|
763
|
+
const originalEval = replServer.eval;
|
|
764
|
+
const workbenchCommands = /* @__PURE__ */ new Set(["help", "providers", "info", "env", "restart", "destroy", "mode", "verbose"]);
|
|
765
|
+
replServer.eval = function(cmd3, context, filename, callback) {
|
|
766
|
+
const trimmedCmd = cmd3.trim();
|
|
767
|
+
const providerMatch = trimmedCmd.match(/^provider\s+(\w+)$/);
|
|
768
|
+
if (providerMatch) {
|
|
769
|
+
const providerName = providerMatch[1];
|
|
770
|
+
const providerCmd = `await provider('${providerName}')`;
|
|
771
|
+
originalEval.call(this, providerCmd, context, filename, callback);
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
const modeMatch = trimmedCmd.match(/^mode\s+(gateway|direct)$/);
|
|
775
|
+
if (modeMatch) {
|
|
776
|
+
const modeName = modeMatch[1];
|
|
777
|
+
const modeCmd = `await mode('${modeName}')`;
|
|
778
|
+
originalEval.call(this, modeCmd, context, filename, callback);
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
originalEval.call(this, cmd3, context, filename, async (err, result) => {
|
|
782
|
+
if (err) {
|
|
783
|
+
callback(err, void 0);
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
if (isCommand(result)) {
|
|
787
|
+
try {
|
|
788
|
+
const output = await runCommand(state, result);
|
|
789
|
+
callback(null, output);
|
|
790
|
+
} catch (error) {
|
|
791
|
+
callback(error, void 0);
|
|
792
|
+
}
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
if (typeof result === "function" && workbenchCommands.has(trimmedCmd)) {
|
|
796
|
+
try {
|
|
797
|
+
const output = await result();
|
|
798
|
+
callback(null, output);
|
|
799
|
+
} catch (error) {
|
|
800
|
+
callback(error, void 0);
|
|
801
|
+
}
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
callback(null, result);
|
|
805
|
+
});
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
function setupAutocomplete(replServer, state) {
|
|
809
|
+
const originalCompleter = replServer.completer;
|
|
810
|
+
const workbenchCommands = {
|
|
811
|
+
"provider": [...PROVIDER_NAMES],
|
|
812
|
+
// Use actual provider names from config
|
|
813
|
+
"mode": ["gateway", "direct"],
|
|
814
|
+
"providers": [],
|
|
815
|
+
"restart": [],
|
|
816
|
+
"destroy": [],
|
|
817
|
+
"info": [],
|
|
818
|
+
"env": [],
|
|
819
|
+
"help": [],
|
|
820
|
+
"verbose": [],
|
|
821
|
+
"exit": [],
|
|
822
|
+
".exit": []
|
|
823
|
+
};
|
|
824
|
+
replServer.completer = function(line, callback) {
|
|
825
|
+
const trimmed = line.trim();
|
|
826
|
+
if (!trimmed.includes(" ") && !trimmed.includes(".")) {
|
|
827
|
+
const commands = Object.keys(workbenchCommands);
|
|
828
|
+
const hits = commands.filter((cmd3) => cmd3.startsWith(trimmed));
|
|
829
|
+
if (originalCompleter) {
|
|
830
|
+
originalCompleter.call(replServer, line, (err, [contextHits, partial]) => {
|
|
831
|
+
if (err) {
|
|
832
|
+
callback(null, [hits, trimmed]);
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
const allHits = [.../* @__PURE__ */ new Set([...hits, ...contextHits])].sort();
|
|
836
|
+
callback(null, [allHits, partial]);
|
|
837
|
+
});
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
callback(null, [hits.length ? hits : commands, trimmed]);
|
|
841
|
+
return;
|
|
842
|
+
}
|
|
843
|
+
const parts = trimmed.split(/\s+/);
|
|
844
|
+
if (parts.length === 2 && !trimmed.includes(".")) {
|
|
845
|
+
const [command, partial] = parts;
|
|
846
|
+
const suggestions = workbenchCommands[command];
|
|
847
|
+
if (suggestions && suggestions.length > 0) {
|
|
848
|
+
const hits = suggestions.filter((s) => s.startsWith(partial)).map((s) => `${command} ${s}`);
|
|
849
|
+
callback(null, [hits.length ? hits : suggestions.map((s) => `${command} ${s}`), trimmed]);
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
if (originalCompleter) {
|
|
854
|
+
originalCompleter.call(replServer, line, callback);
|
|
855
|
+
} else {
|
|
856
|
+
callback(null, [[], line]);
|
|
857
|
+
}
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
function setupHistory(replServer) {
|
|
861
|
+
const historyFile = path.join(os.homedir(), ".computesdk_workbench_history");
|
|
862
|
+
replServer.setupHistory(historyFile, (err) => {
|
|
863
|
+
if (err) {
|
|
864
|
+
}
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
// src/cli/index.ts
|
|
869
|
+
async function startWorkbench() {
|
|
870
|
+
const state = createState();
|
|
871
|
+
state.availableProviders = getAvailableProviders();
|
|
872
|
+
state.currentProvider = autoDetectProvider();
|
|
873
|
+
showWelcome(state.availableProviders, state.currentProvider);
|
|
874
|
+
const replServer = createREPL(state);
|
|
875
|
+
replServer.on("exit", async () => {
|
|
876
|
+
await cleanupOnExit(state, replServer);
|
|
877
|
+
process.exit(0);
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
export {
|
|
881
|
+
startWorkbench
|
|
882
|
+
};
|
|
883
|
+
//# sourceMappingURL=index.js.map
|