typescript-virtual-container 1.5.2 → 1.5.3
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 +17 -17
- package/builds/{fortune-nyx-v1.5.1-directbash-k6.1.0.mjs → fortune-nyx-v1.5.3-directbash-k6.1.0.mjs} +374 -378
- package/builds/{fortune-nyx-v1.5.1-ssh-nosftp.js → fortune-nyx-v1.5.3-ssh-nosftp.js} +138 -142
- package/builds/{fortune-nyx-v1.5.1-ssh.cjs → fortune-nyx-v1.5.3-ssh.cjs} +139 -143
- package/builds/{fortune-nyx-v1.5.1-web.min.js → fortune-nyx-v1.5.3-web.min.js} +134 -120
- package/dist/VirtualPackageManager/index.js +0 -10
- package/dist/commands/runtime.js +139 -106
- package/docs/app.js +145 -149
- package/examples/app.js +145 -149
- package/examples/demo.html +1 -1
- package/package.json +1 -1
- package/src/VirtualPackageManager/index.ts +0 -10
- package/src/commands/runtime.ts +44 -1
|
@@ -2277,7 +2277,21 @@ function resolveVfsBinary(name, env, shell, authUser) {
|
|
|
2277
2277
|
}
|
|
2278
2278
|
return null;
|
|
2279
2279
|
}
|
|
2280
|
+
var MAX_CALL_DEPTH = 8;
|
|
2281
|
+
var _callDepth = 0;
|
|
2280
2282
|
async function runCommandDirect(name, args, authUser, hostname, mode, cwd, shell, stdin, env) {
|
|
2283
|
+
_callDepth++;
|
|
2284
|
+
if (_callDepth > MAX_CALL_DEPTH) {
|
|
2285
|
+
_callDepth--;
|
|
2286
|
+
return { stderr: `${name}: maximum call depth (${MAX_CALL_DEPTH}) exceeded`, exitCode: 126 };
|
|
2287
|
+
}
|
|
2288
|
+
try {
|
|
2289
|
+
return await _runCommandDirectInner(name, args, authUser, hostname, mode, cwd, shell, stdin, env);
|
|
2290
|
+
} finally {
|
|
2291
|
+
_callDepth--;
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
async function _runCommandDirectInner(name, args, authUser, hostname, mode, cwd, shell, stdin, env) {
|
|
2281
2295
|
const assignRe = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/;
|
|
2282
2296
|
const invocation = [name, ...args];
|
|
2283
2297
|
let assignCount = 0;
|
|
@@ -2350,6 +2364,7 @@ async function runCommandDirect(name, args, authUser, hostname, mode, cwd, shell
|
|
|
2350
2364
|
env
|
|
2351
2365
|
});
|
|
2352
2366
|
}
|
|
2367
|
+
return { stderr: `${name}: exec builtin '${builtinMatch[1]}' not found`, exitCode: 127 };
|
|
2353
2368
|
}
|
|
2354
2369
|
const shMod = resolveModule("sh");
|
|
2355
2370
|
if (shMod) {
|
|
@@ -2393,100 +2408,122 @@ async function runCommand(rawInput, authUser, hostname, mode, cwd, shell, stdin,
|
|
|
2393
2408
|
const trimmed = rawInput.trim();
|
|
2394
2409
|
if (trimmed.length === 0) return { exitCode: 0 };
|
|
2395
2410
|
const shellEnv = env ?? makeDefaultEnv(authUser, hostname);
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2411
|
+
_callDepth++;
|
|
2412
|
+
if (_callDepth > MAX_CALL_DEPTH) {
|
|
2413
|
+
_callDepth--;
|
|
2414
|
+
return { stderr: `${trimmed.split(" ")[0]}: maximum call depth (${MAX_CALL_DEPTH}) exceeded`, exitCode: 126 };
|
|
2415
|
+
}
|
|
2416
|
+
try {
|
|
2417
|
+
const rawTokens = tokenizeCommand(trimmed);
|
|
2418
|
+
const rawFirstWord = rawTokens[0]?.toLowerCase() ?? "";
|
|
2419
|
+
const aliasVal = shellEnv.vars[`__alias_${rawFirstWord}`];
|
|
2420
|
+
const aliasExpanded = aliasVal ? trimmed.replace(rawFirstWord, aliasVal) : trimmed;
|
|
2421
|
+
const isShScript = /\bfor\s+\w+\s+in\b/.test(aliasExpanded) || /\bwhile\s+/.test(aliasExpanded) || /\bif\s+/.test(aliasExpanded) || /\w+\s*\(\s*\)\s*\{/.test(aliasExpanded) || /\bfunction\s+\w+/.test(aliasExpanded) || /\(\(\s*.+\s*\)\)/.test(aliasExpanded);
|
|
2422
|
+
const hasOperators = /(?<![|&])[|](?![|])/.test(aliasExpanded) || aliasExpanded.includes(">") || aliasExpanded.includes("<") || aliasExpanded.includes("&&") || aliasExpanded.includes("||") || aliasExpanded.includes(";");
|
|
2423
|
+
if (isShScript && rawFirstWord !== "sh" && rawFirstWord !== "bash" || hasOperators) {
|
|
2424
|
+
if (isShScript && rawFirstWord !== "sh" && rawFirstWord !== "bash") {
|
|
2425
|
+
const shMod = resolveModule("sh");
|
|
2426
|
+
if (shMod) {
|
|
2427
|
+
return await shMod.run({
|
|
2428
|
+
authUser,
|
|
2429
|
+
hostname,
|
|
2430
|
+
activeSessions: shell.users.listActiveSessions(),
|
|
2431
|
+
rawInput: aliasExpanded,
|
|
2432
|
+
mode,
|
|
2433
|
+
args: ["-c", aliasExpanded],
|
|
2434
|
+
stdin: void 0,
|
|
2435
|
+
cwd,
|
|
2436
|
+
shell,
|
|
2437
|
+
env: shellEnv
|
|
2438
|
+
});
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
const script = parseScript(aliasExpanded);
|
|
2442
|
+
if (!script.isValid)
|
|
2443
|
+
return { stderr: script.error || "Syntax error", exitCode: 1 };
|
|
2444
|
+
try {
|
|
2445
|
+
return await executeStatements(
|
|
2446
|
+
script.statements,
|
|
2407
2447
|
authUser,
|
|
2408
2448
|
hostname,
|
|
2409
|
-
activeSessions: shell.users.listActiveSessions(),
|
|
2410
|
-
rawInput: aliasExpanded,
|
|
2411
2449
|
mode,
|
|
2412
|
-
args: ["-c", aliasExpanded],
|
|
2413
|
-
stdin: void 0,
|
|
2414
2450
|
cwd,
|
|
2415
2451
|
shell,
|
|
2416
|
-
|
|
2417
|
-
|
|
2452
|
+
shellEnv
|
|
2453
|
+
);
|
|
2454
|
+
} catch (error) {
|
|
2455
|
+
return {
|
|
2456
|
+
stderr: error instanceof Error ? error.message : "Execution failed",
|
|
2457
|
+
exitCode: 1
|
|
2458
|
+
};
|
|
2418
2459
|
}
|
|
2419
2460
|
}
|
|
2420
|
-
const
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2461
|
+
const expanded = await expandAsync(
|
|
2462
|
+
aliasExpanded,
|
|
2463
|
+
shellEnv.vars,
|
|
2464
|
+
shellEnv.lastExitCode,
|
|
2465
|
+
(sub) => runCommand(
|
|
2466
|
+
sub,
|
|
2426
2467
|
authUser,
|
|
2427
2468
|
hostname,
|
|
2428
2469
|
mode,
|
|
2429
2470
|
cwd,
|
|
2430
2471
|
shell,
|
|
2472
|
+
void 0,
|
|
2473
|
+
shellEnv
|
|
2474
|
+
).then((r) => r.stdout ?? "")
|
|
2475
|
+
);
|
|
2476
|
+
const parts = tokenizeCommand(expanded.trim());
|
|
2477
|
+
if (parts.length === 0) return { exitCode: 0 };
|
|
2478
|
+
const assignRe = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/;
|
|
2479
|
+
if (assignRe.test(parts[0])) {
|
|
2480
|
+
return runCommandDirect(
|
|
2481
|
+
parts[0],
|
|
2482
|
+
parts.slice(1),
|
|
2483
|
+
authUser,
|
|
2484
|
+
hostname,
|
|
2485
|
+
mode,
|
|
2486
|
+
cwd,
|
|
2487
|
+
shell,
|
|
2488
|
+
stdin,
|
|
2431
2489
|
shellEnv
|
|
2432
2490
|
);
|
|
2433
|
-
} catch (error) {
|
|
2434
|
-
return {
|
|
2435
|
-
stderr: error instanceof Error ? error.message : "Execution failed",
|
|
2436
|
-
exitCode: 1
|
|
2437
|
-
};
|
|
2438
2491
|
}
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
shellEnv
|
|
2469
|
-
);
|
|
2470
|
-
}
|
|
2471
|
-
const commandName = parts[0]?.toLowerCase() ?? "";
|
|
2472
|
-
const args = parts.slice(1).flatMap(expandBraces);
|
|
2473
|
-
const mod = resolveModule(commandName);
|
|
2474
|
-
if (!mod) {
|
|
2475
|
-
const vfsBinary = resolveVfsBinary(commandName, shellEnv, shell, authUser);
|
|
2476
|
-
if (vfsBinary) {
|
|
2477
|
-
const stubContent = shell.vfs.readFile(vfsBinary);
|
|
2478
|
-
const builtinMatch = stubContent.match(/exec\s+builtin\s+(\S+)/);
|
|
2479
|
-
if (builtinMatch) {
|
|
2480
|
-
const builtinName = builtinMatch[1];
|
|
2481
|
-
const builtinMod = resolveModule(builtinName);
|
|
2482
|
-
if (builtinMod) {
|
|
2483
|
-
return await builtinMod.run({
|
|
2492
|
+
const commandName = parts[0]?.toLowerCase() ?? "";
|
|
2493
|
+
const args = parts.slice(1).flatMap(expandBraces);
|
|
2494
|
+
const mod = resolveModule(commandName);
|
|
2495
|
+
if (!mod) {
|
|
2496
|
+
const vfsBinary = resolveVfsBinary(commandName, shellEnv, shell, authUser);
|
|
2497
|
+
if (vfsBinary) {
|
|
2498
|
+
const stubContent = shell.vfs.readFile(vfsBinary);
|
|
2499
|
+
const builtinMatch = stubContent.match(/exec\s+builtin\s+(\S+)/);
|
|
2500
|
+
if (builtinMatch) {
|
|
2501
|
+
const builtinName = builtinMatch[1];
|
|
2502
|
+
const builtinMod = resolveModule(builtinName);
|
|
2503
|
+
if (builtinMod) {
|
|
2504
|
+
return await builtinMod.run({
|
|
2505
|
+
authUser,
|
|
2506
|
+
hostname,
|
|
2507
|
+
activeSessions: shell.users.listActiveSessions(),
|
|
2508
|
+
rawInput: [commandName, ...args].join(" "),
|
|
2509
|
+
mode,
|
|
2510
|
+
args,
|
|
2511
|
+
stdin,
|
|
2512
|
+
cwd,
|
|
2513
|
+
shell,
|
|
2514
|
+
env: shellEnv
|
|
2515
|
+
});
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
2518
|
+
const shMod = resolveModule("sh");
|
|
2519
|
+
if (shMod) {
|
|
2520
|
+
return await shMod.run({
|
|
2484
2521
|
authUser,
|
|
2485
2522
|
hostname,
|
|
2486
2523
|
activeSessions: shell.users.listActiveSessions(),
|
|
2487
|
-
rawInput:
|
|
2524
|
+
rawInput: `sh -c ${JSON.stringify(stubContent)}`,
|
|
2488
2525
|
mode,
|
|
2489
|
-
args,
|
|
2526
|
+
args: ["-c", stubContent, "--", ...args],
|
|
2490
2527
|
stdin,
|
|
2491
2528
|
cwd,
|
|
2492
2529
|
shell,
|
|
@@ -2494,42 +2531,29 @@ async function runCommand(rawInput, authUser, hostname, mode, cwd, shell, stdin,
|
|
|
2494
2531
|
});
|
|
2495
2532
|
}
|
|
2496
2533
|
}
|
|
2497
|
-
|
|
2498
|
-
if (shMod) {
|
|
2499
|
-
return await shMod.run({
|
|
2500
|
-
authUser,
|
|
2501
|
-
hostname,
|
|
2502
|
-
activeSessions: shell.users.listActiveSessions(),
|
|
2503
|
-
rawInput: `sh -c ${JSON.stringify(stubContent)}`,
|
|
2504
|
-
mode,
|
|
2505
|
-
args: ["-c", stubContent, "--", ...args],
|
|
2506
|
-
stdin,
|
|
2507
|
-
cwd,
|
|
2508
|
-
shell,
|
|
2509
|
-
env: shellEnv
|
|
2510
|
-
});
|
|
2511
|
-
}
|
|
2534
|
+
return { stderr: `${commandName}: command not found`, exitCode: 127 };
|
|
2512
2535
|
}
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2536
|
+
try {
|
|
2537
|
+
return await mod.run({
|
|
2538
|
+
authUser,
|
|
2539
|
+
hostname,
|
|
2540
|
+
activeSessions: shell.users.listActiveSessions(),
|
|
2541
|
+
rawInput: expanded,
|
|
2542
|
+
mode,
|
|
2543
|
+
args,
|
|
2544
|
+
stdin,
|
|
2545
|
+
cwd,
|
|
2546
|
+
shell,
|
|
2547
|
+
env: shellEnv
|
|
2548
|
+
});
|
|
2549
|
+
} catch (error) {
|
|
2550
|
+
return {
|
|
2551
|
+
stderr: error instanceof Error ? error.message : "Command failed",
|
|
2552
|
+
exitCode: 1
|
|
2553
|
+
};
|
|
2554
|
+
}
|
|
2555
|
+
} finally {
|
|
2556
|
+
_callDepth--;
|
|
2533
2557
|
}
|
|
2534
2558
|
}
|
|
2535
2559
|
|
|
@@ -13279,16 +13303,6 @@ var PACKAGE_REGISTRY = [
|
|
|
13279
13303
|
shortDesc: "Vi IMproved",
|
|
13280
13304
|
installedSizeKb: 3812,
|
|
13281
13305
|
files: [
|
|
13282
|
-
{
|
|
13283
|
-
path: "/usr/bin/vim",
|
|
13284
|
-
content: '#!/bin/sh\nexec builtin nano "$@"\n',
|
|
13285
|
-
mode: 493
|
|
13286
|
-
},
|
|
13287
|
-
{
|
|
13288
|
-
path: "/usr/bin/vi",
|
|
13289
|
-
content: '#!/bin/sh\nexec builtin nano "$@"\n',
|
|
13290
|
-
mode: 493
|
|
13291
|
-
},
|
|
13292
13306
|
{
|
|
13293
13307
|
path: "/usr/share/doc/vim/README",
|
|
13294
13308
|
content: "Vim editor \u2014 virtual package.\n"
|
|
@@ -8,16 +8,6 @@ const PACKAGE_REGISTRY = [
|
|
|
8
8
|
shortDesc: "Vi IMproved",
|
|
9
9
|
installedSizeKb: 3812,
|
|
10
10
|
files: [
|
|
11
|
-
{
|
|
12
|
-
path: "/usr/bin/vim",
|
|
13
|
-
content: "#!/bin/sh\nexec builtin nano \"$@\"\n",
|
|
14
|
-
mode: 0o755,
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
path: "/usr/bin/vi",
|
|
18
|
-
content: "#!/bin/sh\nexec builtin nano \"$@\"\n",
|
|
19
|
-
mode: 0o755,
|
|
20
|
-
},
|
|
21
11
|
{
|
|
22
12
|
path: "/usr/share/doc/vim/README",
|
|
23
13
|
content: "Vim editor — virtual package.\n",
|
package/dist/commands/runtime.js
CHANGED
|
@@ -61,7 +61,25 @@ function resolveVfsBinary(name, env, shell, authUser) {
|
|
|
61
61
|
}
|
|
62
62
|
return null;
|
|
63
63
|
}
|
|
64
|
+
const MAX_CALL_DEPTH = 8;
|
|
65
|
+
let _callDepth = 0;
|
|
64
66
|
export async function runCommandDirect(name, args, authUser, hostname, mode, cwd, shell, stdin, env) {
|
|
67
|
+
// Anti-loop guard: track call depth via env to avoid infinite recursion
|
|
68
|
+
_callDepth++;
|
|
69
|
+
// console.debug(`[depth=${_callDepth}] runCommandDirect: ${name}`);
|
|
70
|
+
if (_callDepth > MAX_CALL_DEPTH) {
|
|
71
|
+
_callDepth--;
|
|
72
|
+
// console.debug(`[LOOP DETECTED] runCommandDirect blocked: ${name}`);
|
|
73
|
+
return { stderr: `${name}: maximum call depth (${MAX_CALL_DEPTH}) exceeded`, exitCode: 126 };
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
return await _runCommandDirectInner(name, args, authUser, hostname, mode, cwd, shell, stdin, env);
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
_callDepth--;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async function _runCommandDirectInner(name, args, authUser, hostname, mode, cwd, shell, stdin, env) {
|
|
65
83
|
const assignRe = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/;
|
|
66
84
|
const invocation = [name, ...args];
|
|
67
85
|
let assignCount = 0;
|
|
@@ -118,6 +136,8 @@ export async function runCommandDirect(name, args, authUser, hostname, mode, cwd
|
|
|
118
136
|
env,
|
|
119
137
|
});
|
|
120
138
|
}
|
|
139
|
+
// builtin not found — stop here, don't fall through to sh -c (avoids infinite loop)
|
|
140
|
+
return { stderr: `${name}: exec builtin '${builtinMatch[1]}' not found`, exitCode: 127 };
|
|
121
141
|
}
|
|
122
142
|
const shMod = resolveModule("sh");
|
|
123
143
|
if (shMod) {
|
|
@@ -163,84 +183,109 @@ export async function runCommand(rawInput, authUser, hostname, mode, cwd, shell,
|
|
|
163
183
|
if (trimmed.length === 0)
|
|
164
184
|
return { exitCode: 0 };
|
|
165
185
|
const shellEnv = env ?? makeDefaultEnv(authUser, hostname);
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
: trimmed;
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
aliasExpanded
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
186
|
+
// Anti-loop guard: check depth here too — catches sh -c recursive calls
|
|
187
|
+
_callDepth++;
|
|
188
|
+
// console.debug(`[depth=${_callDepth}] runCommand: ${trimmed.slice(0, 60)}`);
|
|
189
|
+
if (_callDepth > MAX_CALL_DEPTH) {
|
|
190
|
+
_callDepth--;
|
|
191
|
+
// console.debug(`[LOOP DETECTED] runCommand blocked: ${trimmed.slice(0, 60)}`);
|
|
192
|
+
return { stderr: `${trimmed.split(" ")[0]}: maximum call depth (${MAX_CALL_DEPTH}) exceeded`, exitCode: 126 };
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
const rawTokens = tokenizeCommand(trimmed);
|
|
196
|
+
const rawFirstWord = rawTokens[0]?.toLowerCase() ?? "";
|
|
197
|
+
const aliasVal = shellEnv.vars[`__alias_${rawFirstWord}`];
|
|
198
|
+
const aliasExpanded = aliasVal
|
|
199
|
+
? trimmed.replace(rawFirstWord, aliasVal)
|
|
200
|
+
: trimmed;
|
|
201
|
+
// Detect sh-syntax constructs that must be handled by the sh interpreter
|
|
202
|
+
const isShScript = /\bfor\s+\w+\s+in\b/.test(aliasExpanded) ||
|
|
203
|
+
/\bwhile\s+/.test(aliasExpanded) ||
|
|
204
|
+
/\bif\s+/.test(aliasExpanded) ||
|
|
205
|
+
/\w+\s*\(\s*\)\s*\{/.test(aliasExpanded) ||
|
|
206
|
+
/\bfunction\s+\w+/.test(aliasExpanded) ||
|
|
207
|
+
/\(\(\s*.+\s*\)\)/.test(aliasExpanded);
|
|
208
|
+
const hasOperators = /(?<![|&])[|](?![|])/.test(aliasExpanded) ||
|
|
209
|
+
aliasExpanded.includes(">") ||
|
|
210
|
+
aliasExpanded.includes("<") ||
|
|
211
|
+
aliasExpanded.includes("&&") ||
|
|
212
|
+
aliasExpanded.includes("||") ||
|
|
213
|
+
aliasExpanded.includes(";");
|
|
214
|
+
if ((isShScript && rawFirstWord !== "sh" && rawFirstWord !== "bash") || hasOperators) {
|
|
215
|
+
// sh-syntax: route through sh interpreter to handle for/while/functions
|
|
216
|
+
if (isShScript && rawFirstWord !== "sh" && rawFirstWord !== "bash") {
|
|
217
|
+
const shMod = resolveModule("sh");
|
|
218
|
+
if (shMod) {
|
|
219
|
+
return await shMod.run({
|
|
220
|
+
authUser, hostname,
|
|
221
|
+
activeSessions: shell.users.listActiveSessions(),
|
|
222
|
+
rawInput: aliasExpanded,
|
|
223
|
+
mode,
|
|
224
|
+
args: ["-c", aliasExpanded],
|
|
225
|
+
stdin: undefined,
|
|
226
|
+
cwd,
|
|
227
|
+
shell,
|
|
228
|
+
env: shellEnv,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const script = parseScript(aliasExpanded);
|
|
233
|
+
if (!script.isValid)
|
|
234
|
+
return { stderr: script.error || "Syntax error", exitCode: 1 };
|
|
235
|
+
try {
|
|
236
|
+
return await executeStatements(script.statements, authUser, hostname, mode, cwd, shell, shellEnv);
|
|
237
|
+
}
|
|
238
|
+
catch (error) {
|
|
239
|
+
return {
|
|
240
|
+
stderr: error instanceof Error ? error.message : "Execution failed",
|
|
241
|
+
exitCode: 1,
|
|
242
|
+
};
|
|
201
243
|
}
|
|
202
244
|
}
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
return {
|
|
211
|
-
stderr: error instanceof Error ? error.message : "Execution failed",
|
|
212
|
-
exitCode: 1,
|
|
213
|
-
};
|
|
245
|
+
const expanded = await expandAsync(aliasExpanded, shellEnv.vars, shellEnv.lastExitCode, (sub) => runCommand(sub, authUser, hostname, mode, cwd, shell, undefined, shellEnv).then((r) => r.stdout ?? ""));
|
|
246
|
+
const parts = tokenizeCommand(expanded.trim());
|
|
247
|
+
if (parts.length === 0)
|
|
248
|
+
return { exitCode: 0 };
|
|
249
|
+
const assignRe = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/;
|
|
250
|
+
if (assignRe.test(parts[0])) {
|
|
251
|
+
return runCommandDirect(parts[0], parts.slice(1), authUser, hostname, mode, cwd, shell, stdin, shellEnv);
|
|
214
252
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
253
|
+
const commandName = parts[0]?.toLowerCase() ?? "";
|
|
254
|
+
// Apply brace expansion to each arg token
|
|
255
|
+
const args = parts.slice(1).flatMap(expandBraces);
|
|
256
|
+
const mod = resolveModule(commandName);
|
|
257
|
+
if (!mod) {
|
|
258
|
+
const vfsBinary = resolveVfsBinary(commandName, shellEnv, shell, authUser);
|
|
259
|
+
if (vfsBinary) {
|
|
260
|
+
const stubContent = shell.vfs.readFile(vfsBinary);
|
|
261
|
+
const builtinMatch = stubContent.match(/exec\s+builtin\s+(\S+)/);
|
|
262
|
+
if (builtinMatch) {
|
|
263
|
+
const builtinName = builtinMatch[1];
|
|
264
|
+
const builtinMod = resolveModule(builtinName);
|
|
265
|
+
if (builtinMod) {
|
|
266
|
+
return await builtinMod.run({
|
|
267
|
+
authUser,
|
|
268
|
+
hostname,
|
|
269
|
+
activeSessions: shell.users.listActiveSessions(),
|
|
270
|
+
rawInput: [commandName, ...args].join(" "),
|
|
271
|
+
mode,
|
|
272
|
+
args,
|
|
273
|
+
stdin,
|
|
274
|
+
cwd,
|
|
275
|
+
shell,
|
|
276
|
+
env: shellEnv,
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
const shMod = resolveModule("sh");
|
|
281
|
+
if (shMod) {
|
|
282
|
+
return await shMod.run({
|
|
238
283
|
authUser,
|
|
239
284
|
hostname,
|
|
240
285
|
activeSessions: shell.users.listActiveSessions(),
|
|
241
|
-
rawInput:
|
|
286
|
+
rawInput: `sh -c ${JSON.stringify(stubContent)}`,
|
|
242
287
|
mode,
|
|
243
|
-
args,
|
|
288
|
+
args: ["-c", stubContent, "--", ...args],
|
|
244
289
|
stdin,
|
|
245
290
|
cwd,
|
|
246
291
|
shell,
|
|
@@ -248,42 +293,30 @@ export async function runCommand(rawInput, authUser, hostname, mode, cwd, shell,
|
|
|
248
293
|
});
|
|
249
294
|
}
|
|
250
295
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
}
|
|
296
|
+
return { stderr: `${commandName}: command not found`, exitCode: 127 };
|
|
297
|
+
}
|
|
298
|
+
try {
|
|
299
|
+
return await mod.run({
|
|
300
|
+
authUser,
|
|
301
|
+
hostname,
|
|
302
|
+
activeSessions: shell.users.listActiveSessions(),
|
|
303
|
+
rawInput: expanded,
|
|
304
|
+
mode,
|
|
305
|
+
args,
|
|
306
|
+
stdin,
|
|
307
|
+
cwd,
|
|
308
|
+
shell,
|
|
309
|
+
env: shellEnv,
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
catch (error) {
|
|
313
|
+
return {
|
|
314
|
+
stderr: error instanceof Error ? error.message : "Command failed",
|
|
315
|
+
exitCode: 1,
|
|
316
|
+
};
|
|
266
317
|
}
|
|
267
|
-
return { stderr: `${commandName}: command not found`, exitCode: 127 };
|
|
268
|
-
}
|
|
269
|
-
try {
|
|
270
|
-
return await mod.run({
|
|
271
|
-
authUser,
|
|
272
|
-
hostname,
|
|
273
|
-
activeSessions: shell.users.listActiveSessions(),
|
|
274
|
-
rawInput: expanded,
|
|
275
|
-
mode,
|
|
276
|
-
args,
|
|
277
|
-
stdin,
|
|
278
|
-
cwd,
|
|
279
|
-
shell,
|
|
280
|
-
env: shellEnv,
|
|
281
|
-
});
|
|
282
318
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
stderr: error instanceof Error ? error.message : "Command failed",
|
|
286
|
-
exitCode: 1,
|
|
287
|
-
};
|
|
319
|
+
finally {
|
|
320
|
+
_callDepth--;
|
|
288
321
|
}
|
|
289
322
|
}
|