@computesdk/workbench 2.0.0 → 2.0.2
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/bin/workbench.js +272 -105
- package/dist/bin/workbench.js.map +1 -1
- package/dist/index.js +272 -105
- package/dist/index.js.map +1 -1
- package/package.json +13 -13
- package/src/bin/workbench-ts.ts +0 -1
package/dist/bin/workbench.js
CHANGED
|
@@ -32,10 +32,26 @@ function setSandbox(state, sandbox, provider) {
|
|
|
32
32
|
state.currentSandbox = sandbox;
|
|
33
33
|
state.currentProvider = provider;
|
|
34
34
|
state.sandboxCreatedAt = /* @__PURE__ */ new Date();
|
|
35
|
+
updatePromptIfNeeded(state);
|
|
35
36
|
}
|
|
36
37
|
function clearSandbox(state) {
|
|
37
38
|
state.currentSandbox = null;
|
|
38
39
|
state.sandboxCreatedAt = null;
|
|
40
|
+
updatePromptIfNeeded(state);
|
|
41
|
+
}
|
|
42
|
+
function updatePromptIfNeeded(state) {
|
|
43
|
+
if (state._replServer) {
|
|
44
|
+
const prompt = getPrompt(state);
|
|
45
|
+
state._replServer.setPrompt(prompt);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function getPrompt(state) {
|
|
49
|
+
if (!state.currentSandbox) {
|
|
50
|
+
return "> ";
|
|
51
|
+
}
|
|
52
|
+
const provider = state.currentProvider || "unknown";
|
|
53
|
+
const sandboxId = state.currentSandbox.sandboxId || "";
|
|
54
|
+
return `${provider}:${sandboxId}> `;
|
|
39
55
|
}
|
|
40
56
|
function hasSandbox(state) {
|
|
41
57
|
return state.currentSandbox !== null;
|
|
@@ -91,6 +107,7 @@ function showWelcome(availableProviders, currentProvider, useDirectMode) {
|
|
|
91
107
|
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")));
|
|
92
108
|
console.log(c.bold(c.cyan("\u2551 ComputeSDK Workbench \u2551")));
|
|
93
109
|
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")));
|
|
110
|
+
console.log(c.dim("Prompt shows connection status: > (disconnected) or provider:sandbox> (connected)\n"));
|
|
94
111
|
if (availableProviders.length > 0) {
|
|
95
112
|
const backendProviders = availableProviders.filter((p) => p !== "gateway");
|
|
96
113
|
console.log(`Providers available: ${backendProviders.join(", ")}`);
|
|
@@ -124,7 +141,12 @@ function showInfo(state) {
|
|
|
124
141
|
return;
|
|
125
142
|
}
|
|
126
143
|
console.log("\n" + c.bold("Current Sandbox:"));
|
|
144
|
+
if (state.currentSandbox.sandboxId) {
|
|
145
|
+
console.log(` Sandbox ID: ${c.cyan(state.currentSandbox.sandboxId)}`);
|
|
146
|
+
}
|
|
127
147
|
console.log(` Provider: ${c.green(state.currentProvider || "unknown")}`);
|
|
148
|
+
const modeLabel = state.useDirectMode ? "direct \u{1F517}" : "gateway \u{1F310}";
|
|
149
|
+
console.log(` Mode: ${c.blue(modeLabel)}`);
|
|
128
150
|
console.log(` Created: ${state.sandboxCreatedAt?.toLocaleString() || "unknown"}`);
|
|
129
151
|
console.log(` Uptime: ${formatUptime(state)}`);
|
|
130
152
|
console.log("");
|
|
@@ -221,12 +243,28 @@ ${c.bold("Running Commands:")}
|
|
|
221
243
|
${c.cyan('git.clone("https://github.com/user/repo")')}
|
|
222
244
|
${c.cyan("git.status()")}
|
|
223
245
|
|
|
224
|
-
${c.dim("Filesystem:")}
|
|
246
|
+
${c.dim("Filesystem (via commands):")}
|
|
225
247
|
${c.cyan('ls("/home")')}
|
|
226
248
|
${c.cyan('cat("/etc/hosts")')}
|
|
227
249
|
${c.cyan('rm.rf("/tmp")')} ${c.dim("// Force remove")}
|
|
228
250
|
${c.cyan('rm.auto("/path")')} ${c.dim("// Smart remove")}
|
|
229
251
|
|
|
252
|
+
${c.dim("Filesystem (direct API):")}
|
|
253
|
+
${c.cyan('filesystem.readFile("/etc/hosts")')}
|
|
254
|
+
${c.cyan('filesystem.writeFile("/app/server.js", code)')}
|
|
255
|
+
${c.cyan('filesystem.mkdir("/app")')}
|
|
256
|
+
${c.cyan('filesystem.readdir("/home")')}
|
|
257
|
+
${c.cyan('filesystem.exists("/path")')}
|
|
258
|
+
${c.cyan('filesystem.remove("/file")')}
|
|
259
|
+
|
|
260
|
+
${c.dim("Sandbox Methods:")}
|
|
261
|
+
${c.cyan("getUrl({ port: 3000 })")} ${c.dim("// Get public URL")}
|
|
262
|
+
${c.cyan(`runCode("console.log('hi')", "node")`)}
|
|
263
|
+
${c.cyan("sandboxInfo()")} ${c.dim("// Get sandbox details")}
|
|
264
|
+
${c.cyan("getInstance()")} ${c.dim("// Get native instance")}
|
|
265
|
+
|
|
266
|
+
${c.dim('Note: No need to use "await" - promises are auto-awaited!')}
|
|
267
|
+
|
|
230
268
|
${c.dim("Compute CLI:")}
|
|
231
269
|
${c.cyan("compute.isSetup()")} ${c.dim("// Check if daemon is running")}
|
|
232
270
|
${c.cyan("compute.setup()")} ${c.dim("// Install + start daemon")}
|
|
@@ -256,47 +294,62 @@ function logWarning(message) {
|
|
|
256
294
|
}
|
|
257
295
|
|
|
258
296
|
// src/cli/providers.ts
|
|
297
|
+
import {
|
|
298
|
+
PROVIDER_AUTH as SHARED_PROVIDER_AUTH,
|
|
299
|
+
PROVIDER_NAMES as SHARED_PROVIDER_NAMES,
|
|
300
|
+
getProviderConfigFromEnv
|
|
301
|
+
} from "computesdk";
|
|
259
302
|
var PROVIDER_NAMES = [
|
|
260
303
|
"gateway",
|
|
261
|
-
|
|
262
|
-
"railway",
|
|
263
|
-
"daytona",
|
|
264
|
-
"modal",
|
|
265
|
-
"runloop",
|
|
266
|
-
"vercel",
|
|
267
|
-
"cloudflare",
|
|
268
|
-
"codesandbox",
|
|
269
|
-
"blaxel"
|
|
304
|
+
...SHARED_PROVIDER_NAMES
|
|
270
305
|
];
|
|
271
|
-
var
|
|
272
|
-
gateway: ["COMPUTESDK_API_KEY"],
|
|
273
|
-
|
|
274
|
-
railway: ["RAILWAY_API_KEY", "RAILWAY_PROJECT_ID", "RAILWAY_ENVIRONMENT_ID"],
|
|
275
|
-
daytona: ["DAYTONA_API_KEY"],
|
|
276
|
-
modal: ["MODAL_TOKEN_ID", "MODAL_TOKEN_SECRET"],
|
|
277
|
-
runloop: ["RUNLOOP_API_KEY"],
|
|
278
|
-
vercel: ["VERCEL_TOKEN", "VERCEL_TEAM_ID", "VERCEL_PROJECT_ID"],
|
|
279
|
-
cloudflare: ["CLOUDFLARE_API_TOKEN", "CLOUDFLARE_ACCOUNT_ID"],
|
|
280
|
-
codesandbox: ["CSB_API_KEY"],
|
|
281
|
-
blaxel: ["BL_API_KEY", "BL_WORKSPACE"]
|
|
306
|
+
var PROVIDER_AUTH = {
|
|
307
|
+
gateway: [["COMPUTESDK_API_KEY"]],
|
|
308
|
+
...SHARED_PROVIDER_AUTH
|
|
282
309
|
};
|
|
283
310
|
function getProviderStatus(provider) {
|
|
311
|
+
const authOptions = PROVIDER_AUTH[provider];
|
|
284
312
|
if (typeof process === "undefined") {
|
|
285
313
|
return {
|
|
286
314
|
name: provider,
|
|
287
315
|
isComplete: false,
|
|
288
316
|
present: [],
|
|
289
|
-
missing: [...
|
|
317
|
+
missing: [...authOptions[0]]
|
|
290
318
|
};
|
|
291
319
|
}
|
|
292
|
-
const
|
|
293
|
-
const
|
|
294
|
-
const
|
|
320
|
+
const allVars = new Set(authOptions.flat());
|
|
321
|
+
const presentSet = /* @__PURE__ */ new Set();
|
|
322
|
+
for (const v of allVars) {
|
|
323
|
+
if (process.env?.[v]) presentSet.add(v);
|
|
324
|
+
}
|
|
325
|
+
let bestOption = null;
|
|
326
|
+
for (const option of authOptions) {
|
|
327
|
+
const missing = [];
|
|
328
|
+
let presentCount = 0;
|
|
329
|
+
for (const v of option) {
|
|
330
|
+
if (presentSet.has(v)) {
|
|
331
|
+
presentCount++;
|
|
332
|
+
} else {
|
|
333
|
+
missing.push(v);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
if (missing.length === 0) {
|
|
337
|
+
return {
|
|
338
|
+
name: provider,
|
|
339
|
+
isComplete: true,
|
|
340
|
+
present: [...presentSet],
|
|
341
|
+
missing: []
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
if (!bestOption || presentCount > bestOption.presentCount) {
|
|
345
|
+
bestOption = { presentCount, missing };
|
|
346
|
+
}
|
|
347
|
+
}
|
|
295
348
|
return {
|
|
296
349
|
name: provider,
|
|
297
|
-
isComplete:
|
|
298
|
-
present: [...
|
|
299
|
-
missing: [
|
|
350
|
+
isComplete: false,
|
|
351
|
+
present: [...presentSet],
|
|
352
|
+
missing: bestOption?.missing ?? []
|
|
300
353
|
};
|
|
301
354
|
}
|
|
302
355
|
function getAvailableProviders() {
|
|
@@ -428,47 +481,12 @@ async function loadProvider(providerName) {
|
|
|
428
481
|
}
|
|
429
482
|
}
|
|
430
483
|
function getProviderConfig(providerName) {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
break;
|
|
436
|
-
case "railway":
|
|
437
|
-
if (process.env.RAILWAY_API_KEY) config2.apiKey = process.env.RAILWAY_API_KEY;
|
|
438
|
-
if (process.env.RAILWAY_PROJECT_ID) config2.projectId = process.env.RAILWAY_PROJECT_ID;
|
|
439
|
-
if (process.env.RAILWAY_ENVIRONMENT_ID) config2.environmentId = process.env.RAILWAY_ENVIRONMENT_ID;
|
|
440
|
-
break;
|
|
441
|
-
case "daytona":
|
|
442
|
-
if (process.env.DAYTONA_API_KEY) config2.apiKey = process.env.DAYTONA_API_KEY;
|
|
443
|
-
break;
|
|
444
|
-
case "modal":
|
|
445
|
-
if (process.env.MODAL_TOKEN_ID) config2.tokenId = process.env.MODAL_TOKEN_ID;
|
|
446
|
-
if (process.env.MODAL_TOKEN_SECRET) config2.tokenSecret = process.env.MODAL_TOKEN_SECRET;
|
|
447
|
-
break;
|
|
448
|
-
case "runloop":
|
|
449
|
-
if (process.env.RUNLOOP_API_KEY) config2.apiKey = process.env.RUNLOOP_API_KEY;
|
|
450
|
-
break;
|
|
451
|
-
case "vercel":
|
|
452
|
-
if (process.env.VERCEL_TOKEN) config2.token = process.env.VERCEL_TOKEN;
|
|
453
|
-
if (process.env.VERCEL_TEAM_ID) config2.teamId = process.env.VERCEL_TEAM_ID;
|
|
454
|
-
if (process.env.VERCEL_PROJECT_ID) config2.projectId = process.env.VERCEL_PROJECT_ID;
|
|
455
|
-
break;
|
|
456
|
-
case "cloudflare":
|
|
457
|
-
if (process.env.CLOUDFLARE_API_TOKEN) config2.apiToken = process.env.CLOUDFLARE_API_TOKEN;
|
|
458
|
-
if (process.env.CLOUDFLARE_ACCOUNT_ID) config2.accountId = process.env.CLOUDFLARE_ACCOUNT_ID;
|
|
459
|
-
break;
|
|
460
|
-
case "codesandbox":
|
|
461
|
-
if (process.env.CSB_API_KEY) config2.apiKey = process.env.CSB_API_KEY;
|
|
462
|
-
break;
|
|
463
|
-
case "blaxel":
|
|
464
|
-
if (process.env.BL_API_KEY) config2.apiKey = process.env.BL_API_KEY;
|
|
465
|
-
if (process.env.BL_WORKSPACE) config2.workspace = process.env.BL_WORKSPACE;
|
|
466
|
-
break;
|
|
467
|
-
case "gateway":
|
|
468
|
-
if (process.env.COMPUTESDK_API_KEY) config2.apiKey = process.env.COMPUTESDK_API_KEY;
|
|
469
|
-
break;
|
|
484
|
+
if (providerName === "gateway") {
|
|
485
|
+
const config2 = {};
|
|
486
|
+
if (process.env.COMPUTESDK_API_KEY) config2.apiKey = process.env.COMPUTESDK_API_KEY;
|
|
487
|
+
return config2;
|
|
470
488
|
}
|
|
471
|
-
return
|
|
489
|
+
return getProviderConfigFromEnv(providerName);
|
|
472
490
|
}
|
|
473
491
|
|
|
474
492
|
// src/cli/commands.ts
|
|
@@ -642,9 +660,34 @@ async function runCommand(state, command) {
|
|
|
642
660
|
} catch (error) {
|
|
643
661
|
const duration = Date.now() - startTime;
|
|
644
662
|
logError(`Failed ${c.dim(`(${formatDuration(duration)})`)} - ${error instanceof Error ? error.message : String(error)}`);
|
|
663
|
+
if (isStaleConnectionError(error)) {
|
|
664
|
+
clearSandbox(state);
|
|
665
|
+
logWarning("Sandbox connection lost. Next command will create a new sandbox.");
|
|
666
|
+
}
|
|
645
667
|
throw error;
|
|
646
668
|
}
|
|
647
669
|
}
|
|
670
|
+
function isStaleConnectionError(error) {
|
|
671
|
+
if (!(error instanceof Error)) return false;
|
|
672
|
+
const message = error.message.toLowerCase();
|
|
673
|
+
const stalePhrases = [
|
|
674
|
+
"websocket",
|
|
675
|
+
"connection refused",
|
|
676
|
+
"connection reset",
|
|
677
|
+
"connection closed",
|
|
678
|
+
"socket hang up",
|
|
679
|
+
"econnrefused",
|
|
680
|
+
"econnreset",
|
|
681
|
+
"etimedout",
|
|
682
|
+
"not found",
|
|
683
|
+
"sandbox not found",
|
|
684
|
+
"unauthorized",
|
|
685
|
+
"401",
|
|
686
|
+
"403",
|
|
687
|
+
"404"
|
|
688
|
+
];
|
|
689
|
+
return stalePhrases.some((phrase) => message.includes(phrase));
|
|
690
|
+
}
|
|
648
691
|
async function switchProvider(state, mode, providerName) {
|
|
649
692
|
let useDirect = false;
|
|
650
693
|
let actualProvider = mode;
|
|
@@ -800,7 +843,8 @@ import * as path2 from "path";
|
|
|
800
843
|
import * as os from "os";
|
|
801
844
|
function createREPL(state) {
|
|
802
845
|
const replServer = repl.start({
|
|
803
|
-
prompt: "
|
|
846
|
+
prompt: "> ",
|
|
847
|
+
// Initial prompt, will be updated by state management
|
|
804
848
|
useColors: true,
|
|
805
849
|
terminal: true,
|
|
806
850
|
useGlobal: false,
|
|
@@ -811,6 +855,7 @@ function createREPL(state) {
|
|
|
811
855
|
setupSmartEvaluator(replServer, state);
|
|
812
856
|
setupAutocomplete(replServer, state);
|
|
813
857
|
setupHistory(replServer);
|
|
858
|
+
state._replServer = replServer;
|
|
814
859
|
return replServer;
|
|
815
860
|
}
|
|
816
861
|
function injectCmdContext(replServer) {
|
|
@@ -918,10 +963,94 @@ function injectWorkbenchCommands(replServer, state) {
|
|
|
918
963
|
};
|
|
919
964
|
replServer.context.env = () => showEnv();
|
|
920
965
|
replServer.context.help = showHelp;
|
|
966
|
+
replServer.context.getUrl = async (options) => {
|
|
967
|
+
const sandbox = state.currentSandbox;
|
|
968
|
+
if (!sandbox) {
|
|
969
|
+
throw new Error("No active sandbox. Run a command to auto-create one.");
|
|
970
|
+
}
|
|
971
|
+
return sandbox.getUrl(options);
|
|
972
|
+
};
|
|
973
|
+
replServer.context.sandboxInfo = async () => {
|
|
974
|
+
const sandbox = state.currentSandbox;
|
|
975
|
+
if (!sandbox) {
|
|
976
|
+
throw new Error("No active sandbox. Run a command to auto-create one.");
|
|
977
|
+
}
|
|
978
|
+
return sandbox.getInfo();
|
|
979
|
+
};
|
|
980
|
+
replServer.context.runCode = async (code, runtime) => {
|
|
981
|
+
const sandbox = state.currentSandbox;
|
|
982
|
+
if (!sandbox) {
|
|
983
|
+
throw new Error("No active sandbox. Run a command to auto-create one.");
|
|
984
|
+
}
|
|
985
|
+
return sandbox.runCode(code, runtime);
|
|
986
|
+
};
|
|
987
|
+
replServer.context.filesystem = {
|
|
988
|
+
get readFile() {
|
|
989
|
+
return async (path4) => {
|
|
990
|
+
const sandbox = state.currentSandbox;
|
|
991
|
+
if (!sandbox) {
|
|
992
|
+
throw new Error("No active sandbox. Run a command to auto-create one.");
|
|
993
|
+
}
|
|
994
|
+
return sandbox.filesystem.readFile(path4);
|
|
995
|
+
};
|
|
996
|
+
},
|
|
997
|
+
get writeFile() {
|
|
998
|
+
return async (path4, content) => {
|
|
999
|
+
const sandbox = state.currentSandbox;
|
|
1000
|
+
if (!sandbox) {
|
|
1001
|
+
throw new Error("No active sandbox. Run a command to auto-create one.");
|
|
1002
|
+
}
|
|
1003
|
+
return sandbox.filesystem.writeFile(path4, content);
|
|
1004
|
+
};
|
|
1005
|
+
},
|
|
1006
|
+
get mkdir() {
|
|
1007
|
+
return async (path4) => {
|
|
1008
|
+
const sandbox = state.currentSandbox;
|
|
1009
|
+
if (!sandbox) {
|
|
1010
|
+
throw new Error("No active sandbox. Run a command to auto-create one.");
|
|
1011
|
+
}
|
|
1012
|
+
return sandbox.filesystem.mkdir(path4);
|
|
1013
|
+
};
|
|
1014
|
+
},
|
|
1015
|
+
get readdir() {
|
|
1016
|
+
return async (path4) => {
|
|
1017
|
+
const sandbox = state.currentSandbox;
|
|
1018
|
+
if (!sandbox) {
|
|
1019
|
+
throw new Error("No active sandbox. Run a command to auto-create one.");
|
|
1020
|
+
}
|
|
1021
|
+
return sandbox.filesystem.readdir(path4);
|
|
1022
|
+
};
|
|
1023
|
+
},
|
|
1024
|
+
get exists() {
|
|
1025
|
+
return async (path4) => {
|
|
1026
|
+
const sandbox = state.currentSandbox;
|
|
1027
|
+
if (!sandbox) {
|
|
1028
|
+
throw new Error("No active sandbox. Run a command to auto-create one.");
|
|
1029
|
+
}
|
|
1030
|
+
return sandbox.filesystem.exists(path4);
|
|
1031
|
+
};
|
|
1032
|
+
},
|
|
1033
|
+
get remove() {
|
|
1034
|
+
return async (path4) => {
|
|
1035
|
+
const sandbox = state.currentSandbox;
|
|
1036
|
+
if (!sandbox) {
|
|
1037
|
+
throw new Error("No active sandbox. Run a command to auto-create one.");
|
|
1038
|
+
}
|
|
1039
|
+
return sandbox.filesystem.remove(path4);
|
|
1040
|
+
};
|
|
1041
|
+
}
|
|
1042
|
+
};
|
|
1043
|
+
replServer.context.getInstance = () => {
|
|
1044
|
+
const sandbox = state.currentSandbox;
|
|
1045
|
+
if (!sandbox) {
|
|
1046
|
+
throw new Error("No active sandbox. Run a command to auto-create one.");
|
|
1047
|
+
}
|
|
1048
|
+
return sandbox.getInstance();
|
|
1049
|
+
};
|
|
921
1050
|
}
|
|
922
1051
|
function setupSmartEvaluator(replServer, state) {
|
|
923
1052
|
const originalEval = replServer.eval;
|
|
924
|
-
const workbenchCommands = /* @__PURE__ */ new Set(["help", "providers", "info", "env", "restart", "destroy", "mode", "verbose"]);
|
|
1053
|
+
const workbenchCommands = /* @__PURE__ */ new Set(["help", "providers", "info", "env", "restart", "destroy", "mode", "verbose", "sandboxInfo"]);
|
|
925
1054
|
replServer.eval = function(cmd3, context, filename, callback) {
|
|
926
1055
|
const trimmedCmd = cmd3.trim();
|
|
927
1056
|
const providerMatch = trimmedCmd.match(/^provider(?:\s+(direct|gateway))?\s+(\w+)$/);
|
|
@@ -980,6 +1109,15 @@ function setupSmartEvaluator(replServer, state) {
|
|
|
980
1109
|
}
|
|
981
1110
|
return;
|
|
982
1111
|
}
|
|
1112
|
+
if (result && typeof result.then === "function") {
|
|
1113
|
+
try {
|
|
1114
|
+
const output = await result;
|
|
1115
|
+
callback(null, output);
|
|
1116
|
+
} catch (error) {
|
|
1117
|
+
callback(error, void 0);
|
|
1118
|
+
}
|
|
1119
|
+
return;
|
|
1120
|
+
}
|
|
983
1121
|
callback(null, result);
|
|
984
1122
|
});
|
|
985
1123
|
};
|
|
@@ -998,52 +1136,81 @@ function setupAutocomplete(replServer, state) {
|
|
|
998
1136
|
"help": [],
|
|
999
1137
|
"verbose": [],
|
|
1000
1138
|
"exit": [],
|
|
1001
|
-
".exit": []
|
|
1139
|
+
".exit": [],
|
|
1140
|
+
// Sandbox methods
|
|
1141
|
+
"getUrl": [],
|
|
1142
|
+
"runCode": [],
|
|
1143
|
+
"sandboxInfo": [],
|
|
1144
|
+
"getInstance": []
|
|
1145
|
+
// Filesystem is an object, so it gets dot notation autocomplete automatically
|
|
1002
1146
|
};
|
|
1003
1147
|
replServer.completer = function(line, callback) {
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1148
|
+
try {
|
|
1149
|
+
const trimmed = line.trim();
|
|
1150
|
+
if (!line.includes(" ") && !line.includes(".")) {
|
|
1151
|
+
const commands = Object.keys(workbenchCommands);
|
|
1152
|
+
const hits = commands.filter((cmd3) => cmd3.startsWith(trimmed));
|
|
1153
|
+
if (originalCompleter) {
|
|
1154
|
+
originalCompleter.call(replServer, line, (err, result) => {
|
|
1155
|
+
if (err || !result) {
|
|
1156
|
+
callback(null, [hits, trimmed]);
|
|
1157
|
+
return;
|
|
1158
|
+
}
|
|
1159
|
+
if (!Array.isArray(result) || result.length !== 2) {
|
|
1160
|
+
callback(null, [hits, trimmed]);
|
|
1161
|
+
return;
|
|
1162
|
+
}
|
|
1163
|
+
const [contextHits, partial] = result;
|
|
1164
|
+
if (!Array.isArray(contextHits)) {
|
|
1165
|
+
callback(null, [hits, trimmed]);
|
|
1166
|
+
return;
|
|
1167
|
+
}
|
|
1168
|
+
const allHits = [.../* @__PURE__ */ new Set([...hits, ...contextHits])].sort();
|
|
1169
|
+
const completionPrefix = typeof partial === "string" ? partial : trimmed;
|
|
1170
|
+
callback(null, [allHits, completionPrefix]);
|
|
1171
|
+
});
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
callback(null, [hits.length ? hits : commands, trimmed]);
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
if (line.includes(" ") && !line.includes(".")) {
|
|
1178
|
+
const parts = line.split(" ");
|
|
1179
|
+
const command = parts[0].trim();
|
|
1180
|
+
const partial = parts.slice(1).join(" ").trim();
|
|
1181
|
+
const suggestions = workbenchCommands[command];
|
|
1182
|
+
if (suggestions !== void 0) {
|
|
1183
|
+
if (suggestions.length > 0) {
|
|
1184
|
+
const hits = suggestions.filter((s) => s.startsWith(partial)).map((s) => `${command} ${s}`);
|
|
1185
|
+
callback(null, [hits.length ? hits : suggestions.map((s) => `${command} ${s}`), line]);
|
|
1186
|
+
} else {
|
|
1187
|
+
callback(null, [[], line]);
|
|
1188
|
+
}
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1008
1192
|
if (originalCompleter) {
|
|
1009
1193
|
originalCompleter.call(replServer, line, (err, result) => {
|
|
1010
1194
|
if (err || !result) {
|
|
1011
|
-
callback(null, [
|
|
1195
|
+
callback(null, [[], line]);
|
|
1012
1196
|
return;
|
|
1013
1197
|
}
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
callback(null, [hits, trimmed]);
|
|
1198
|
+
if (!Array.isArray(result) || result.length !== 2) {
|
|
1199
|
+
callback(null, [[], line]);
|
|
1017
1200
|
return;
|
|
1018
1201
|
}
|
|
1019
|
-
const
|
|
1020
|
-
|
|
1202
|
+
const [completions, partial] = result;
|
|
1203
|
+
if (!Array.isArray(completions) || typeof partial !== "string") {
|
|
1204
|
+
callback(null, [[], line]);
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1207
|
+
callback(null, [completions, partial]);
|
|
1021
1208
|
});
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
callback(null, [hits.length ? hits : commands, trimmed]);
|
|
1025
|
-
return;
|
|
1026
|
-
}
|
|
1027
|
-
if (line.includes(" ") && !line.includes(".")) {
|
|
1028
|
-
const parts = line.split(" ");
|
|
1029
|
-
const command = parts[0].trim();
|
|
1030
|
-
const partial = parts.slice(1).join(" ").trim();
|
|
1031
|
-
const suggestions = workbenchCommands[command];
|
|
1032
|
-
if (suggestions && suggestions.length > 0) {
|
|
1033
|
-
const hits = suggestions.filter((s) => s.startsWith(partial)).map((s) => `${command} ${s}`);
|
|
1034
|
-
callback(null, [hits.length ? hits : suggestions.map((s) => `${command} ${s}`), line]);
|
|
1035
|
-
return;
|
|
1209
|
+
} else {
|
|
1210
|
+
callback(null, [[], line]);
|
|
1036
1211
|
}
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
originalCompleter.call(replServer, line, (err, result) => {
|
|
1040
|
-
if (err || !result) {
|
|
1041
|
-
callback(null, [[], line]);
|
|
1042
|
-
return;
|
|
1043
|
-
}
|
|
1044
|
-
callback(null, result);
|
|
1045
|
-
});
|
|
1046
|
-
} else {
|
|
1212
|
+
} catch (error) {
|
|
1213
|
+
console.error("Autocomplete error:", error);
|
|
1047
1214
|
callback(null, [[], line]);
|
|
1048
1215
|
}
|
|
1049
1216
|
};
|