typescript-virtual-container 1.2.8 → 1.3.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/.vscode/settings.json +0 -1
- package/README.md +462 -44
- package/biome.json +7 -0
- package/dist/SSHMimic/exec.d.ts.map +1 -1
- package/dist/SSHMimic/executor.d.ts.map +1 -1
- package/dist/SSHMimic/executor.js +35 -21
- package/dist/SSHMimic/index.d.ts.map +1 -1
- package/dist/SSHMimic/index.js +20 -6
- package/dist/VirtualFileSystem/binaryPack.d.ts.map +1 -1
- package/dist/VirtualFileSystem/binaryPack.js +29 -6
- package/dist/VirtualFileSystem/index.d.ts.map +1 -1
- package/dist/VirtualFileSystem/index.js +36 -13
- package/dist/VirtualPackageManager/index.d.ts +202 -0
- package/dist/VirtualPackageManager/index.d.ts.map +1 -0
- package/dist/VirtualPackageManager/index.js +825 -0
- package/dist/VirtualShell/index.d.ts +93 -12
- package/dist/VirtualShell/index.d.ts.map +1 -1
- package/dist/VirtualShell/index.js +95 -13
- package/dist/VirtualShell/shell.d.ts.map +1 -1
- package/dist/VirtualShell/shell.js +3 -1
- package/dist/VirtualShell/shellParser.d.ts.map +1 -1
- package/dist/VirtualUserManager/index.d.ts +52 -20
- package/dist/VirtualUserManager/index.d.ts.map +1 -1
- package/dist/VirtualUserManager/index.js +54 -20
- package/dist/commands/adduser.d.ts +6 -0
- package/dist/commands/adduser.d.ts.map +1 -1
- package/dist/commands/adduser.js +6 -0
- package/dist/commands/alias.d.ts +9 -0
- package/dist/commands/alias.d.ts.map +1 -0
- package/dist/commands/alias.js +63 -0
- package/dist/commands/apt.d.ts +9 -0
- package/dist/commands/apt.d.ts.map +1 -0
- package/dist/commands/apt.js +205 -0
- package/dist/commands/awk.d.ts +11 -0
- package/dist/commands/awk.d.ts.map +1 -1
- package/dist/commands/awk.js +15 -2
- package/dist/commands/base64.d.ts +5 -0
- package/dist/commands/base64.d.ts.map +1 -1
- package/dist/commands/base64.js +9 -1
- package/dist/commands/cat.d.ts +5 -0
- package/dist/commands/cat.d.ts.map +1 -1
- package/dist/commands/cat.js +35 -8
- package/dist/commands/cd.d.ts +5 -0
- package/dist/commands/cd.d.ts.map +1 -1
- package/dist/commands/cd.js +5 -0
- package/dist/commands/chmod.d.ts +5 -0
- package/dist/commands/chmod.d.ts.map +1 -1
- package/dist/commands/chmod.js +57 -3
- package/dist/commands/command-helpers.d.ts +78 -4
- package/dist/commands/command-helpers.d.ts.map +1 -1
- package/dist/commands/command-helpers.js +78 -4
- package/dist/commands/cp.d.ts +5 -0
- package/dist/commands/cp.d.ts.map +1 -1
- package/dist/commands/cp.js +5 -0
- package/dist/commands/curl.d.ts +5 -0
- package/dist/commands/curl.d.ts.map +1 -1
- package/dist/commands/curl.js +106 -26
- package/dist/commands/cut.d.ts +5 -0
- package/dist/commands/cut.d.ts.map +1 -1
- package/dist/commands/cut.js +8 -1
- package/dist/commands/date.d.ts +5 -0
- package/dist/commands/date.d.ts.map +1 -1
- package/dist/commands/date.js +7 -1
- package/dist/commands/declare.d.ts +3 -0
- package/dist/commands/declare.d.ts.map +1 -0
- package/dist/commands/declare.js +39 -0
- package/dist/commands/diff.d.ts +5 -0
- package/dist/commands/diff.d.ts.map +1 -1
- package/dist/commands/diff.js +5 -0
- package/dist/commands/dpkg.d.ts +9 -0
- package/dist/commands/dpkg.d.ts.map +1 -0
- package/dist/commands/dpkg.js +161 -0
- package/dist/commands/du.d.ts.map +1 -1
- package/dist/commands/du.js +8 -2
- package/dist/commands/echo.d.ts +5 -0
- package/dist/commands/echo.d.ts.map +1 -1
- package/dist/commands/echo.js +33 -12
- package/dist/commands/env.d.ts +5 -0
- package/dist/commands/env.d.ts.map +1 -1
- package/dist/commands/env.js +11 -1
- package/dist/commands/exit.d.ts +5 -0
- package/dist/commands/exit.d.ts.map +1 -1
- package/dist/commands/exit.js +12 -2
- package/dist/commands/export.d.ts.map +1 -1
- package/dist/commands/export.js +3 -1
- package/dist/commands/find.d.ts +5 -0
- package/dist/commands/find.d.ts.map +1 -1
- package/dist/commands/find.js +5 -0
- package/dist/commands/free.d.ts +8 -0
- package/dist/commands/free.d.ts.map +1 -0
- package/dist/commands/free.js +43 -0
- package/dist/commands/grep.d.ts +5 -0
- package/dist/commands/grep.d.ts.map +1 -1
- package/dist/commands/grep.js +12 -2
- package/dist/commands/gzip.d.ts +5 -0
- package/dist/commands/gzip.d.ts.map +1 -1
- package/dist/commands/gzip.js +18 -2
- package/dist/commands/head.d.ts +5 -0
- package/dist/commands/head.d.ts.map +1 -1
- package/dist/commands/head.js +5 -0
- package/dist/commands/help.d.ts.map +1 -1
- package/dist/commands/help.js +98 -45
- package/dist/commands/helpers.d.ts +3 -0
- package/dist/commands/helpers.d.ts.map +1 -1
- package/dist/commands/helpers.js +3 -0
- package/dist/commands/history.d.ts +8 -0
- package/dist/commands/history.d.ts.map +1 -0
- package/dist/commands/history.js +26 -0
- package/dist/commands/hostname.d.ts +5 -0
- package/dist/commands/hostname.d.ts.map +1 -1
- package/dist/commands/hostname.js +5 -0
- package/dist/commands/id.d.ts.map +1 -1
- package/dist/commands/id.js +4 -1
- package/dist/commands/index.d.ts +2 -10
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +2 -231
- package/dist/commands/ls.d.ts.map +1 -1
- package/dist/commands/ls.js +6 -3
- package/dist/commands/lsb-release.d.ts +3 -0
- package/dist/commands/lsb-release.d.ts.map +1 -0
- package/dist/commands/lsb-release.js +56 -0
- package/dist/commands/man.d.ts +3 -0
- package/dist/commands/man.d.ts.map +1 -0
- package/dist/commands/man.js +155 -0
- package/dist/commands/nano.js +1 -1
- package/dist/commands/neofetch.d.ts.map +1 -1
- package/dist/commands/neofetch.js +6 -1
- package/dist/commands/node.d.ts +9 -0
- package/dist/commands/node.d.ts.map +1 -0
- package/dist/commands/node.js +316 -0
- package/dist/commands/npm.d.ts +19 -0
- package/dist/commands/npm.d.ts.map +1 -0
- package/dist/commands/npm.js +109 -0
- package/dist/commands/ping.d.ts.map +1 -1
- package/dist/commands/ping.js +7 -2
- package/dist/commands/printf.d.ts +3 -0
- package/dist/commands/printf.d.ts.map +1 -0
- package/dist/commands/printf.js +113 -0
- package/dist/commands/ps.d.ts.map +1 -1
- package/dist/commands/ps.js +30 -6
- package/dist/commands/python.d.ts +30 -0
- package/dist/commands/python.d.ts.map +1 -0
- package/dist/commands/python.js +2058 -0
- package/dist/commands/read.d.ts +3 -0
- package/dist/commands/read.d.ts.map +1 -0
- package/dist/commands/read.js +34 -0
- package/dist/commands/registry.d.ts +8 -0
- package/dist/commands/registry.d.ts.map +1 -0
- package/dist/commands/registry.js +229 -0
- package/dist/commands/runtime.d.ts +6 -0
- package/dist/commands/runtime.d.ts.map +1 -0
- package/dist/commands/runtime.js +280 -0
- package/dist/commands/sed.d.ts.map +1 -1
- package/dist/commands/sed.js +11 -3
- package/dist/commands/set.d.ts.map +1 -1
- package/dist/commands/set.js +9 -3
- package/dist/commands/sh.d.ts.map +1 -1
- package/dist/commands/sh.js +69 -30
- package/dist/commands/shift.d.ts +5 -0
- package/dist/commands/shift.d.ts.map +1 -0
- package/dist/commands/shift.js +52 -0
- package/dist/commands/sleep.d.ts.map +1 -1
- package/dist/commands/sort.d.ts.map +1 -1
- package/dist/commands/sort.js +4 -2
- package/dist/commands/source.d.ts +3 -0
- package/dist/commands/source.d.ts.map +1 -0
- package/dist/commands/source.js +34 -0
- package/dist/commands/sudo.js +1 -1
- package/dist/commands/tar.d.ts.map +1 -1
- package/dist/commands/tar.js +11 -3
- package/dist/commands/tee.d.ts.map +1 -1
- package/dist/commands/tee.js +8 -6
- package/dist/commands/test.d.ts +3 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +114 -0
- package/dist/commands/tr.d.ts.map +1 -1
- package/dist/commands/tr.js +3 -1
- package/dist/commands/true.d.ts +4 -0
- package/dist/commands/true.d.ts.map +1 -0
- package/dist/commands/true.js +14 -0
- package/dist/commands/type.d.ts +3 -0
- package/dist/commands/type.d.ts.map +1 -0
- package/dist/commands/type.js +34 -0
- package/dist/commands/uname.d.ts.map +1 -1
- package/dist/commands/uname.js +4 -1
- package/dist/commands/uniq.d.ts.map +1 -1
- package/dist/commands/uptime.d.ts +3 -0
- package/dist/commands/uptime.d.ts.map +1 -0
- package/dist/commands/uptime.js +43 -0
- package/dist/commands/wget.d.ts.map +1 -1
- package/dist/commands/wget.js +92 -96
- package/dist/commands/which.d.ts +3 -0
- package/dist/commands/which.d.ts.map +1 -0
- package/dist/commands/which.js +32 -0
- package/dist/commands/xargs.d.ts.map +1 -1
- package/dist/commands/xargs.js +1 -1
- package/dist/index.d.ts +15 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -8
- package/dist/modules/linuxRootfs.d.ts +41 -0
- package/dist/modules/linuxRootfs.d.ts.map +1 -0
- package/dist/modules/linuxRootfs.js +440 -0
- package/dist/modules/neofetch.d.ts.map +1 -1
- package/dist/modules/neofetch.js +1 -0
- package/dist/standalone-wo-sftp.d.ts +2 -0
- package/dist/standalone-wo-sftp.d.ts.map +1 -0
- package/dist/standalone-wo-sftp.js +30 -0
- package/dist/utils/expand.d.ts +50 -0
- package/dist/utils/expand.d.ts.map +1 -0
- package/dist/utils/expand.js +183 -0
- package/dist/utils/vfsDiff.d.ts +90 -0
- package/dist/utils/vfsDiff.d.ts.map +1 -0
- package/dist/utils/vfsDiff.js +177 -0
- package/package.json +3 -1
- package/src/SSHMimic/exec.ts +10 -1
- package/src/SSHMimic/executor.ts +105 -21
- package/src/SSHMimic/index.ts +49 -15
- package/src/VirtualFileSystem/binaryPack.ts +35 -8
- package/src/VirtualFileSystem/index.ts +78 -28
- package/src/VirtualPackageManager/index.ts +979 -0
- package/src/VirtualShell/index.ts +133 -14
- package/src/VirtualShell/shell.ts +23 -3
- package/src/VirtualShell/shellParser.ts +134 -36
- package/src/VirtualUserManager/index.ts +62 -22
- package/src/commands/adduser.ts +6 -0
- package/src/commands/alias.ts +64 -0
- package/src/commands/apt.ts +228 -0
- package/src/commands/awk.ts +20 -6
- package/src/commands/base64.ts +13 -2
- package/src/commands/cat.ts +40 -8
- package/src/commands/cd.ts +5 -0
- package/src/commands/chmod.ts +53 -3
- package/src/commands/command-helpers.ts +78 -4
- package/src/commands/cp.ts +5 -0
- package/src/commands/curl.ts +118 -33
- package/src/commands/cut.ts +8 -1
- package/src/commands/date.ts +7 -1
- package/src/commands/declare.ts +44 -0
- package/src/commands/diff.ts +17 -3
- package/src/commands/dpkg.ts +180 -0
- package/src/commands/du.ts +17 -5
- package/src/commands/echo.ts +41 -12
- package/src/commands/env.ts +11 -1
- package/src/commands/exit.ts +12 -2
- package/src/commands/export.ts +3 -1
- package/src/commands/find.ts +5 -0
- package/src/commands/free.ts +47 -0
- package/src/commands/grep.ts +12 -2
- package/src/commands/gzip.ts +28 -4
- package/src/commands/head.ts +5 -0
- package/src/commands/help.ts +121 -47
- package/src/commands/helpers.ts +8 -0
- package/src/commands/history.ts +34 -0
- package/src/commands/hostname.ts +5 -0
- package/src/commands/id.ts +4 -1
- package/src/commands/index.ts +9 -255
- package/src/commands/ls.ts +6 -3
- package/src/commands/lsb-release.ts +58 -0
- package/src/commands/man.ts +166 -0
- package/src/commands/nano.ts +1 -1
- package/src/commands/neofetch.ts +6 -1
- package/src/commands/node.ts +341 -0
- package/src/commands/npm.ts +132 -0
- package/src/commands/ping.ts +10 -3
- package/src/commands/printf.ts +112 -0
- package/src/commands/ps.ts +40 -6
- package/src/commands/python.ts +2229 -0
- package/src/commands/read.ts +41 -0
- package/src/commands/registry.ts +244 -0
- package/src/commands/runtime.ts +353 -0
- package/src/commands/sed.ts +27 -9
- package/src/commands/set.ts +9 -3
- package/src/commands/sh.ts +170 -44
- package/src/commands/shift.ts +53 -0
- package/src/commands/sleep.ts +2 -1
- package/src/commands/sort.ts +10 -6
- package/src/commands/source.ts +47 -0
- package/src/commands/sudo.ts +1 -1
- package/src/commands/tar.ts +28 -7
- package/src/commands/tee.ts +7 -1
- package/src/commands/test.ts +135 -0
- package/src/commands/tr.ts +3 -1
- package/src/commands/true.ts +17 -0
- package/src/commands/type.ts +43 -0
- package/src/commands/uname.ts +5 -1
- package/src/commands/uniq.ts +8 -2
- package/src/commands/uptime.ts +49 -0
- package/src/commands/wget.ts +105 -119
- package/src/commands/which.ts +37 -0
- package/src/commands/xargs.ts +11 -2
- package/src/index.ts +27 -18
- package/src/modules/linuxRootfs.ts +642 -0
- package/src/modules/neofetch.ts +1 -0
- package/src/standalone-wo-sftp.ts +38 -0
- package/src/utils/expand.ts +238 -0
- package/src/utils/vfsDiff.ts +275 -0
- package/standalone-wo-sftp.js +507 -0
- package/standalone-wo-sftp.js.map +7 -0
- package/standalone.js +486 -109
- package/standalone.js.map +4 -4
- package/tests/bun-test-shim.ts +9 -1
- package/tests/command-helpers.test.ts +1 -5
- package/tests/new-features.test.ts +1036 -0
- package/tests/parser-executor.test.ts +27 -27
- package/tests/sftp.test.ts +122 -42
- package/tests/users.test.ts +23 -5
- package/CHANGELOG.md +0 -150
package/dist/commands/sh.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { expandAsync } from "../utils/expand";
|
|
2
|
+
import { ifFlag } from "./command-helpers";
|
|
2
3
|
import { resolvePath } from "./helpers";
|
|
3
|
-
import { runCommand } from "./
|
|
4
|
-
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
.replace(/\$([A-Za-z_][A-Za-z0-9_]*)/g, (_, n) => env[n] ?? "")
|
|
11
|
-
.replace(/^~(\/|$)/, `${env.HOME ?? "/home/user"}$1`);
|
|
4
|
+
import { runCommand } from "./runtime";
|
|
5
|
+
/**
|
|
6
|
+
* Expand all shell forms including $(cmd) substitution.
|
|
7
|
+
* Delegates to centralised expandAsync (single-quote-aware, depth-tracked).
|
|
8
|
+
*/
|
|
9
|
+
async function expandVars(line, env, lastExit, ctx) {
|
|
10
|
+
return expandAsync(line, env, lastExit, (sub) => runCommand(sub, ctx.authUser, ctx.hostname, ctx.mode, ctx.cwd, ctx.shell, undefined, ctx.env).then((r) => r.stdout ?? ""));
|
|
12
11
|
}
|
|
13
12
|
/** Very small shell interpreter: supports if/elif/else/fi, for/do/done, while/do/done */
|
|
14
13
|
function parseBlocks(lines) {
|
|
@@ -21,7 +20,10 @@ function parseBlocks(lines) {
|
|
|
21
20
|
continue;
|
|
22
21
|
}
|
|
23
22
|
if (line.startsWith("if ") || line === "if") {
|
|
24
|
-
const cond = line
|
|
23
|
+
const cond = line
|
|
24
|
+
.replace(/^if\s+/, "")
|
|
25
|
+
.replace(/;\s*then\s*$/, "")
|
|
26
|
+
.trim();
|
|
25
27
|
const thenLines = [];
|
|
26
28
|
const elifBlocks = [];
|
|
27
29
|
const elseLines = [];
|
|
@@ -32,7 +34,10 @@ function parseBlocks(lines) {
|
|
|
32
34
|
const l = lines[i].trim();
|
|
33
35
|
if (l.startsWith("elif ")) {
|
|
34
36
|
section = "elif";
|
|
35
|
-
elifCond = l
|
|
37
|
+
elifCond = l
|
|
38
|
+
.replace(/^elif\s+/, "")
|
|
39
|
+
.replace(/;\s*then\s*$/, "")
|
|
40
|
+
.trim();
|
|
36
41
|
elifBlocks.push({ cond: elifCond, body: [] });
|
|
37
42
|
}
|
|
38
43
|
else if (l === "else") {
|
|
@@ -48,8 +53,13 @@ function parseBlocks(lines) {
|
|
|
48
53
|
}
|
|
49
54
|
i++;
|
|
50
55
|
}
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
blocks.push({
|
|
57
|
+
type: "if",
|
|
58
|
+
cond,
|
|
59
|
+
then_: thenLines,
|
|
60
|
+
elif: elifBlocks,
|
|
61
|
+
else_: elseLines,
|
|
62
|
+
});
|
|
53
63
|
}
|
|
54
64
|
else if (line.startsWith("for ")) {
|
|
55
65
|
const m = line.match(/^for\s+(\w+)\s+in\s+(.+?)(?:\s*;\s*do)?$/);
|
|
@@ -57,8 +67,8 @@ function parseBlocks(lines) {
|
|
|
57
67
|
const body = [];
|
|
58
68
|
i++;
|
|
59
69
|
while (i < lines.length && lines[i]?.trim() !== "done") {
|
|
60
|
-
const l = lines[i].trim();
|
|
61
|
-
if (l !== "do")
|
|
70
|
+
const l = lines[i].trim().replace(/^do\s+/, "");
|
|
71
|
+
if (l && l !== "do")
|
|
62
72
|
body.push(l);
|
|
63
73
|
i++;
|
|
64
74
|
}
|
|
@@ -69,12 +79,15 @@ function parseBlocks(lines) {
|
|
|
69
79
|
}
|
|
70
80
|
}
|
|
71
81
|
else if (line.startsWith("while ")) {
|
|
72
|
-
const cond = line
|
|
82
|
+
const cond = line
|
|
83
|
+
.replace(/^while\s+/, "")
|
|
84
|
+
.replace(/;\s*do\s*$/, "")
|
|
85
|
+
.trim();
|
|
73
86
|
const body = [];
|
|
74
87
|
i++;
|
|
75
88
|
while (i < lines.length && lines[i]?.trim() !== "done") {
|
|
76
|
-
const l = lines[i].trim();
|
|
77
|
-
if (l !== "do")
|
|
89
|
+
const l = lines[i].trim().replace(/^do\s+/, "");
|
|
90
|
+
if (l && l !== "do")
|
|
78
91
|
body.push(l);
|
|
79
92
|
i++;
|
|
80
93
|
}
|
|
@@ -88,7 +101,7 @@ function parseBlocks(lines) {
|
|
|
88
101
|
return blocks;
|
|
89
102
|
}
|
|
90
103
|
async function evalCondition(cond, ctx) {
|
|
91
|
-
const expanded = expandVars(cond, ctx.env.vars, ctx.env.lastExitCode);
|
|
104
|
+
const expanded = await expandVars(cond, ctx.env.vars, ctx.env.lastExitCode, ctx);
|
|
92
105
|
// test -f / test -d / [ ... ]
|
|
93
106
|
const testMatch = expanded.match(/^\[?\s*(.+?)\s*\]?$/);
|
|
94
107
|
if (testMatch) {
|
|
@@ -101,7 +114,7 @@ async function evalCondition(cond, ctx) {
|
|
|
101
114
|
if (flag === "f")
|
|
102
115
|
return ctx.shell.vfs.exists(p) && ctx.shell.vfs.stat(p).type === "file";
|
|
103
116
|
if (flag === "d")
|
|
104
|
-
return ctx.shell.vfs.exists(p) && ctx.shell.vfs.stat(p).type === "directory";
|
|
117
|
+
return (ctx.shell.vfs.exists(p) && ctx.shell.vfs.stat(p).type === "directory");
|
|
105
118
|
if (flag === "e")
|
|
106
119
|
return ctx.shell.vfs.exists(p);
|
|
107
120
|
if (flag === "z")
|
|
@@ -146,7 +159,21 @@ async function runBlocks(blocks, ctx) {
|
|
|
146
159
|
let output = "";
|
|
147
160
|
for (const block of blocks) {
|
|
148
161
|
if (block.type === "cmd") {
|
|
149
|
-
const expanded = expandVars(block.line, ctx.env.vars, ctx.env.lastExitCode);
|
|
162
|
+
const expanded = await expandVars(block.line, ctx.env.vars, ctx.env.lastExitCode, ctx);
|
|
163
|
+
// Bare VAR=val assignment(s) — handle before dispatching to runCommand
|
|
164
|
+
const assignRe = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)/;
|
|
165
|
+
const tokens = expanded.trim().split(/\s+/);
|
|
166
|
+
if (tokens.length > 0 && assignRe.test(tokens[0])) {
|
|
167
|
+
const allAssign = tokens.every((t) => assignRe.test(t));
|
|
168
|
+
if (allAssign) {
|
|
169
|
+
for (const tok of tokens) {
|
|
170
|
+
const m = tok.match(assignRe);
|
|
171
|
+
ctx.env.vars[m[1]] = m[2];
|
|
172
|
+
}
|
|
173
|
+
ctx.env.lastExitCode = 0;
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
150
177
|
const r = await runCommand(expanded, ctx.authUser, ctx.hostname, ctx.mode, ctx.cwd, ctx.shell, undefined, ctx.env);
|
|
151
178
|
ctx.env.lastExitCode = r.exitCode ?? 0;
|
|
152
179
|
if (r.stdout)
|
|
@@ -158,7 +185,7 @@ async function runBlocks(blocks, ctx) {
|
|
|
158
185
|
else if (block.type === "if") {
|
|
159
186
|
let ran = false;
|
|
160
187
|
if (await evalCondition(block.cond, ctx)) {
|
|
161
|
-
const sub = await runBlocks(parseBlocks(block.
|
|
188
|
+
const sub = await runBlocks(parseBlocks(block.then_), ctx);
|
|
162
189
|
if (sub.stdout)
|
|
163
190
|
output += `${sub.stdout}\n`;
|
|
164
191
|
ran = true;
|
|
@@ -181,7 +208,7 @@ async function runBlocks(blocks, ctx) {
|
|
|
181
208
|
}
|
|
182
209
|
}
|
|
183
210
|
else if (block.type === "for") {
|
|
184
|
-
const listExpanded = expandVars(block.list, ctx.env.vars, ctx.env.lastExitCode);
|
|
211
|
+
const listExpanded = await expandVars(block.list, ctx.env.vars, ctx.env.lastExitCode, ctx);
|
|
185
212
|
const items = listExpanded.trim().split(/\s+/);
|
|
186
213
|
for (const item of items) {
|
|
187
214
|
ctx.env.vars[block.var] = item;
|
|
@@ -194,7 +221,7 @@ async function runBlocks(blocks, ctx) {
|
|
|
194
221
|
}
|
|
195
222
|
else if (block.type === "while") {
|
|
196
223
|
let iterations = 0;
|
|
197
|
-
while (iterations < 1000 && await evalCondition(block.cond, ctx)) {
|
|
224
|
+
while (iterations < 1000 && (await evalCondition(block.cond, ctx))) {
|
|
198
225
|
const sub = await runBlocks(parseBlocks(block.body), ctx);
|
|
199
226
|
if (sub.stdout)
|
|
200
227
|
output += `${sub.stdout}\n`;
|
|
@@ -216,10 +243,13 @@ export const shCommand = {
|
|
|
216
243
|
const { args, shell, cwd } = ctx;
|
|
217
244
|
// sh -c "inline script"
|
|
218
245
|
if (ifFlag(args, "-c")) {
|
|
219
|
-
const script =
|
|
246
|
+
const script = args[args.indexOf("-c") + 1] ?? "";
|
|
220
247
|
if (!script)
|
|
221
248
|
return { stderr: "sh: -c requires a script", exitCode: 1 };
|
|
222
|
-
const lines = script
|
|
249
|
+
const lines = script
|
|
250
|
+
.split(/[;\n]/)
|
|
251
|
+
.map((l) => l.trim())
|
|
252
|
+
.filter((l) => l && !l.startsWith("#"));
|
|
223
253
|
const blocks = parseBlocks(lines);
|
|
224
254
|
return runBlocks(blocks, ctx);
|
|
225
255
|
}
|
|
@@ -228,12 +258,21 @@ export const shCommand = {
|
|
|
228
258
|
if (fileArg) {
|
|
229
259
|
const p = resolvePath(cwd, fileArg);
|
|
230
260
|
if (!shell.vfs.exists(p))
|
|
231
|
-
return {
|
|
261
|
+
return {
|
|
262
|
+
stderr: `sh: ${fileArg}: No such file or directory`,
|
|
263
|
+
exitCode: 1,
|
|
264
|
+
};
|
|
232
265
|
const content = shell.vfs.readFile(p);
|
|
233
|
-
const lines = content
|
|
266
|
+
const lines = content
|
|
267
|
+
.split("\n")
|
|
268
|
+
.map((l) => l.trim())
|
|
269
|
+
.filter((l) => l && !l.startsWith("#"));
|
|
234
270
|
const blocks = parseBlocks(lines);
|
|
235
271
|
return runBlocks(blocks, ctx);
|
|
236
272
|
}
|
|
237
|
-
return {
|
|
273
|
+
return {
|
|
274
|
+
stderr: "sh: invalid usage. Use: sh -c 'cmd' or sh <file>",
|
|
275
|
+
exitCode: 1,
|
|
276
|
+
};
|
|
238
277
|
},
|
|
239
278
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shift.d.ts","sourceRoot":"","sources":["../../src/commands/shift.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,eAAO,MAAM,YAAY,EAAE,WAoB1B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,WAezB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,WAW3B,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export const shiftCommand = {
|
|
2
|
+
name: "shift",
|
|
3
|
+
description: "Shift positional parameters",
|
|
4
|
+
category: "shell",
|
|
5
|
+
params: ["[n]"],
|
|
6
|
+
// shift is meaningful only inside sh scripts where positional params exist.
|
|
7
|
+
// In the current impl, positional params ($1 $2 …) aren't tracked in env by default.
|
|
8
|
+
// We store them under env.vars.__argv and shift there if present.
|
|
9
|
+
run: ({ args, env }) => {
|
|
10
|
+
if (!env)
|
|
11
|
+
return { exitCode: 0 };
|
|
12
|
+
const n = parseInt(args[0] ?? "1", 10) || 1;
|
|
13
|
+
const argv = env.vars.__argv?.split("\x00").filter(Boolean) ?? [];
|
|
14
|
+
env.vars.__argv = argv.slice(n).join("\x00");
|
|
15
|
+
// Update $1 $2 … in env
|
|
16
|
+
const shifted = argv.slice(n);
|
|
17
|
+
for (let i = 1; i <= 9; i++) {
|
|
18
|
+
env.vars[String(i)] = shifted[i - 1] ?? "";
|
|
19
|
+
}
|
|
20
|
+
return { exitCode: 0 };
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
export const trapCommand = {
|
|
24
|
+
name: "trap",
|
|
25
|
+
description: "Trap signals and events",
|
|
26
|
+
category: "shell",
|
|
27
|
+
params: ["[action] [signal...]"],
|
|
28
|
+
// Store trap handlers in env for EXIT signal support
|
|
29
|
+
run: ({ args, env }) => {
|
|
30
|
+
if (!env || args.length === 0)
|
|
31
|
+
return { exitCode: 0 };
|
|
32
|
+
const action = args[0] ?? "";
|
|
33
|
+
const signals = args.slice(1);
|
|
34
|
+
for (const sig of signals) {
|
|
35
|
+
env.vars[`__trap_${sig.toUpperCase()}`] = action;
|
|
36
|
+
}
|
|
37
|
+
return { exitCode: 0 };
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
export const returnCommand = {
|
|
41
|
+
name: "return",
|
|
42
|
+
description: "Return from a shell function",
|
|
43
|
+
category: "shell",
|
|
44
|
+
params: ["[n]"],
|
|
45
|
+
run: ({ args, env }) => {
|
|
46
|
+
const code = parseInt(args[0] ?? "0", 10);
|
|
47
|
+
if (env)
|
|
48
|
+
env.lastExitCode = code;
|
|
49
|
+
// Signal the caller via exitCode; function return is handled by runBlocks
|
|
50
|
+
return { exitCode: code };
|
|
51
|
+
},
|
|
52
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sleep.d.ts","sourceRoot":"","sources":["../../src/commands/sleep.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,eAAO,MAAM,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"sleep.d.ts","sourceRoot":"","sources":["../../src/commands/sleep.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,eAAO,MAAM,YAAY,EAAE,WAY1B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sort.d.ts","sourceRoot":"","sources":["../../src/commands/sort.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"sort.d.ts","sourceRoot":"","sources":["../../src/commands/sort.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,WAAW,EAAE,WAoCzB,CAAC"}
|
package/dist/commands/sort.js
CHANGED
|
@@ -12,7 +12,8 @@ export const sortCommand = {
|
|
|
12
12
|
const files = args.filter((a) => !a.startsWith("-"));
|
|
13
13
|
const getContent = () => {
|
|
14
14
|
if (files.length > 0) {
|
|
15
|
-
return files
|
|
15
|
+
return files
|
|
16
|
+
.map((f) => {
|
|
16
17
|
try {
|
|
17
18
|
assertPathAccess(authUser, resolvePath(cwd, f), "sort");
|
|
18
19
|
return shell.vfs.readFile(resolvePath(cwd, f));
|
|
@@ -20,7 +21,8 @@ export const sortCommand = {
|
|
|
20
21
|
catch {
|
|
21
22
|
return "";
|
|
22
23
|
}
|
|
23
|
-
})
|
|
24
|
+
})
|
|
25
|
+
.join("\n");
|
|
24
26
|
}
|
|
25
27
|
return stdin ?? "";
|
|
26
28
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/commands/source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,aAAa,EAAE,WA0C3B,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { resolvePath } from "./helpers";
|
|
2
|
+
import { runCommand } from "./runtime";
|
|
3
|
+
export const sourceCommand = {
|
|
4
|
+
name: "source",
|
|
5
|
+
aliases: ["."],
|
|
6
|
+
description: "Execute commands from a file in the current shell environment",
|
|
7
|
+
category: "shell",
|
|
8
|
+
params: ["<file> [args...]"],
|
|
9
|
+
run: async ({ args, authUser, hostname, cwd, shell, env }) => {
|
|
10
|
+
const fileArg = args[0];
|
|
11
|
+
if (!fileArg) {
|
|
12
|
+
return { stderr: "source: missing filename", exitCode: 1 };
|
|
13
|
+
}
|
|
14
|
+
const filePath = resolvePath(cwd, fileArg);
|
|
15
|
+
if (!shell.vfs.exists(filePath)) {
|
|
16
|
+
return {
|
|
17
|
+
stderr: `source: ${fileArg}: No such file or directory`,
|
|
18
|
+
exitCode: 1,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const content = shell.vfs.readFile(filePath);
|
|
22
|
+
let lastExitCode = 0;
|
|
23
|
+
for (const line of content.split("\n")) {
|
|
24
|
+
const l = line.trim();
|
|
25
|
+
if (!l || l.startsWith("#"))
|
|
26
|
+
continue;
|
|
27
|
+
const result = await runCommand(l, authUser, hostname, "shell", cwd, shell, undefined, env);
|
|
28
|
+
lastExitCode = result.exitCode ?? 0;
|
|
29
|
+
if (result.closeSession || result.switchUser)
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
return { exitCode: lastExitCode };
|
|
33
|
+
},
|
|
34
|
+
};
|
package/dist/commands/sudo.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tar.d.ts","sourceRoot":"","sources":["../../src/commands/tar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"tar.d.ts","sourceRoot":"","sources":["../../src/commands/tar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,UAAU,EAAE,WA0ExB,CAAC"}
|
package/dist/commands/tar.js
CHANGED
|
@@ -10,7 +10,9 @@ export const tarCommand = {
|
|
|
10
10
|
const extract = ifFlag(args, ["-x"]);
|
|
11
11
|
const list = ifFlag(args, ["-t"]);
|
|
12
12
|
const fFlag = args.findIndex((a) => a.includes("f"));
|
|
13
|
-
const archiveName = fFlag !== -1
|
|
13
|
+
const archiveName = fFlag !== -1
|
|
14
|
+
? args[fFlag + 1]
|
|
15
|
+
: args.find((a) => a.endsWith(".tar") || a.endsWith(".tar.gz") || a.endsWith(".tgz"));
|
|
14
16
|
if (!archiveName)
|
|
15
17
|
return { stderr: "tar: no archive specified", exitCode: 1 };
|
|
16
18
|
const archivePath = resolvePath(cwd, archiveName);
|
|
@@ -38,7 +40,10 @@ export const tarCommand = {
|
|
|
38
40
|
}
|
|
39
41
|
}
|
|
40
42
|
catch {
|
|
41
|
-
return {
|
|
43
|
+
return {
|
|
44
|
+
stderr: `tar: ${f}: No such file or directory`,
|
|
45
|
+
exitCode: 1,
|
|
46
|
+
};
|
|
42
47
|
}
|
|
43
48
|
}
|
|
44
49
|
shell.writeFileAsUser(authUser, archivePath, JSON.stringify(entries));
|
|
@@ -50,7 +55,10 @@ export const tarCommand = {
|
|
|
50
55
|
entries = JSON.parse(shell.vfs.readFile(archivePath));
|
|
51
56
|
}
|
|
52
57
|
catch {
|
|
53
|
-
return {
|
|
58
|
+
return {
|
|
59
|
+
stderr: `tar: ${archiveName}: cannot open archive`,
|
|
60
|
+
exitCode: 1,
|
|
61
|
+
};
|
|
54
62
|
}
|
|
55
63
|
if (list)
|
|
56
64
|
return { stdout: Object.keys(entries).join("\n"), exitCode: 0 };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tee.d.ts","sourceRoot":"","sources":["../../src/commands/tee.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"tee.d.ts","sourceRoot":"","sources":["../../src/commands/tee.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,UAAU,EAAE,WA0BxB,CAAC"}
|
package/dist/commands/tee.js
CHANGED
|
@@ -12,12 +12,14 @@ export const teeCommand = {
|
|
|
12
12
|
for (const f of files) {
|
|
13
13
|
const p = resolvePath(cwd, f);
|
|
14
14
|
if (append) {
|
|
15
|
-
const existing = (() => {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
const existing = (() => {
|
|
16
|
+
try {
|
|
17
|
+
return shell.vfs.readFile(p);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return "";
|
|
21
|
+
}
|
|
22
|
+
})();
|
|
21
23
|
shell.writeFileAsUser(authUser, p, existing + input);
|
|
22
24
|
}
|
|
23
25
|
else {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../src/commands/test.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAwHrD,eAAO,MAAM,WAAW,EAAE,WAczB,CAAC"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Evaluate a POSIX test expression.
|
|
3
|
+
* Supports: -f, -d, -e, -r, -w, -x, -s, -z, -n,
|
|
4
|
+
* string =, !=, numeric -eq -ne -lt -le -gt -ge,
|
|
5
|
+
* ! (negate), -a (and), -o (or).
|
|
6
|
+
*/
|
|
7
|
+
function evalTest(tokens, shell, cwd) {
|
|
8
|
+
// When called via [ command, ] is the last arg — strip it
|
|
9
|
+
// When called via test command, no brackets present
|
|
10
|
+
if (tokens[tokens.length - 1] === "]") {
|
|
11
|
+
tokens = tokens.slice(0, -1);
|
|
12
|
+
}
|
|
13
|
+
// Also strip leading [ if present (shouldn't normally happen but be safe)
|
|
14
|
+
if (tokens[0] === "[") {
|
|
15
|
+
tokens = tokens.slice(1);
|
|
16
|
+
}
|
|
17
|
+
if (tokens.length === 0)
|
|
18
|
+
return false;
|
|
19
|
+
// Negation
|
|
20
|
+
if (tokens[0] === "!")
|
|
21
|
+
return !evalTest(tokens.slice(1), shell, cwd);
|
|
22
|
+
// Boolean -a / -o (simple left-right, no precedence)
|
|
23
|
+
const andIdx = tokens.indexOf("-a");
|
|
24
|
+
if (andIdx !== -1) {
|
|
25
|
+
return (evalTest(tokens.slice(0, andIdx), shell, cwd) &&
|
|
26
|
+
evalTest(tokens.slice(andIdx + 1), shell, cwd));
|
|
27
|
+
}
|
|
28
|
+
const orIdx = tokens.indexOf("-o");
|
|
29
|
+
if (orIdx !== -1) {
|
|
30
|
+
return (evalTest(tokens.slice(0, orIdx), shell, cwd) ||
|
|
31
|
+
evalTest(tokens.slice(orIdx + 1), shell, cwd));
|
|
32
|
+
}
|
|
33
|
+
// Unary file tests
|
|
34
|
+
if (tokens.length === 2) {
|
|
35
|
+
const [flag, operand = ""] = tokens;
|
|
36
|
+
const resolvePath = (p) => p.startsWith("/") ? p : `${cwd}/${p}`.replace(/\/+/g, "/");
|
|
37
|
+
const path = resolvePath(operand);
|
|
38
|
+
switch (flag) {
|
|
39
|
+
case "-e":
|
|
40
|
+
return shell.vfs.exists(path);
|
|
41
|
+
case "-f":
|
|
42
|
+
return shell.vfs.exists(path) && shell.vfs.stat(path).type === "file";
|
|
43
|
+
case "-d":
|
|
44
|
+
return (shell.vfs.exists(path) && shell.vfs.stat(path).type === "directory");
|
|
45
|
+
case "-r":
|
|
46
|
+
return shell.vfs.exists(path); // all readable in virtual env
|
|
47
|
+
case "-w":
|
|
48
|
+
return shell.vfs.exists(path);
|
|
49
|
+
case "-x":
|
|
50
|
+
return shell.vfs.exists(path) && !!(shell.vfs.stat(path).mode & 0o111);
|
|
51
|
+
case "-s":
|
|
52
|
+
return (shell.vfs.exists(path) &&
|
|
53
|
+
shell.vfs.stat(path).type === "file" &&
|
|
54
|
+
shell.vfs.stat(path).size > 0);
|
|
55
|
+
case "-z":
|
|
56
|
+
return operand.length === 0;
|
|
57
|
+
case "-n":
|
|
58
|
+
return operand.length > 0;
|
|
59
|
+
case "-L":
|
|
60
|
+
return shell.vfs.isSymlink(path);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Binary comparisons
|
|
64
|
+
if (tokens.length === 3) {
|
|
65
|
+
const [left = "", op, right = ""] = tokens;
|
|
66
|
+
const leftN = Number(left);
|
|
67
|
+
const rightN = Number(right);
|
|
68
|
+
switch (op) {
|
|
69
|
+
// String
|
|
70
|
+
case "=":
|
|
71
|
+
case "==":
|
|
72
|
+
return left === right;
|
|
73
|
+
case "!=":
|
|
74
|
+
return left !== right;
|
|
75
|
+
case "<":
|
|
76
|
+
return left < right;
|
|
77
|
+
case ">":
|
|
78
|
+
return left > right;
|
|
79
|
+
// Numeric
|
|
80
|
+
case "-eq":
|
|
81
|
+
return leftN === rightN;
|
|
82
|
+
case "-ne":
|
|
83
|
+
return leftN !== rightN;
|
|
84
|
+
case "-lt":
|
|
85
|
+
return leftN < rightN;
|
|
86
|
+
case "-le":
|
|
87
|
+
return leftN <= rightN;
|
|
88
|
+
case "-gt":
|
|
89
|
+
return leftN > rightN;
|
|
90
|
+
case "-ge":
|
|
91
|
+
return leftN >= rightN;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Single string (truthy if non-empty)
|
|
95
|
+
if (tokens.length === 1)
|
|
96
|
+
return (tokens[0] ?? "").length > 0;
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
export const testCommand = {
|
|
100
|
+
name: "test",
|
|
101
|
+
aliases: ["["],
|
|
102
|
+
description: "Evaluate conditional expression",
|
|
103
|
+
category: "shell",
|
|
104
|
+
params: ["<expression>"],
|
|
105
|
+
run: ({ args, shell, cwd }) => {
|
|
106
|
+
try {
|
|
107
|
+
const result = evalTest([...args], shell, cwd);
|
|
108
|
+
return { exitCode: result ? 0 : 1 };
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return { stderr: "test: malformed expression", exitCode: 2 };
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tr.d.ts","sourceRoot":"","sources":["../../src/commands/tr.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"tr.d.ts","sourceRoot":"","sources":["../../src/commands/tr.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,SAAS,EAAE,WAsBvB,CAAC"}
|
package/dist/commands/tr.js
CHANGED
|
@@ -16,7 +16,9 @@ export const trCommand = {
|
|
|
16
16
|
}
|
|
17
17
|
else if (set2) {
|
|
18
18
|
for (let i = 0; i < set1.length; i++) {
|
|
19
|
-
input = input
|
|
19
|
+
input = input
|
|
20
|
+
.split(set1[i])
|
|
21
|
+
.join(set2[i] ?? set2[set2.length - 1] ?? "");
|
|
20
22
|
}
|
|
21
23
|
}
|
|
22
24
|
return { stdout: input, exitCode: 0 };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"true.d.ts","sourceRoot":"","sources":["../../src/commands/true.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,eAAO,MAAM,WAAW,EAAE,WAMzB,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,WAM1B,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const trueCommand = {
|
|
2
|
+
name: "true",
|
|
3
|
+
description: "Return success exit code",
|
|
4
|
+
category: "shell",
|
|
5
|
+
params: [],
|
|
6
|
+
run: () => ({ exitCode: 0 }),
|
|
7
|
+
};
|
|
8
|
+
export const falseCommand = {
|
|
9
|
+
name: "false",
|
|
10
|
+
description: "Return failure exit code",
|
|
11
|
+
category: "shell",
|
|
12
|
+
params: [],
|
|
13
|
+
run: () => ({ exitCode: 1 }),
|
|
14
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../../src/commands/type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,WAAW,EAAE,WAuCzB,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { resolveModule } from "./registry";
|
|
2
|
+
export const typeCommand = {
|
|
3
|
+
name: "type",
|
|
4
|
+
description: "Describe how a command would be interpreted",
|
|
5
|
+
category: "shell",
|
|
6
|
+
params: ["<command...>"],
|
|
7
|
+
run: ({ args, shell, env }) => {
|
|
8
|
+
if (args.length === 0)
|
|
9
|
+
return { stderr: "type: missing argument", exitCode: 1 };
|
|
10
|
+
const pathDirs = (env?.vars?.PATH ?? "/usr/local/bin:/usr/bin:/bin").split(":");
|
|
11
|
+
const lines = [];
|
|
12
|
+
let exitCode = 0;
|
|
13
|
+
for (const name of args) {
|
|
14
|
+
if (resolveModule(name)) {
|
|
15
|
+
lines.push(`${name} is a shell builtin`);
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
let found = false;
|
|
19
|
+
for (const dir of pathDirs) {
|
|
20
|
+
const full = `${dir}/${name}`;
|
|
21
|
+
if (shell.vfs.exists(full)) {
|
|
22
|
+
lines.push(`${name} is ${full}`);
|
|
23
|
+
found = true;
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (!found) {
|
|
28
|
+
lines.push(`${name}: not found`);
|
|
29
|
+
exitCode = 1;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return { stdout: lines.join("\n"), exitCode };
|
|
33
|
+
},
|
|
34
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uname.d.ts","sourceRoot":"","sources":["../../src/commands/uname.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"uname.d.ts","sourceRoot":"","sources":["../../src/commands/uname.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,YAAY,EAAE,WAoB1B,CAAC"}
|
package/dist/commands/uname.js
CHANGED
|
@@ -11,7 +11,10 @@ export const unameCommand = {
|
|
|
11
11
|
const machine = shell.properties?.arch ?? "x86_64";
|
|
12
12
|
const hostname = shell.hostname;
|
|
13
13
|
if (all)
|
|
14
|
-
return {
|
|
14
|
+
return {
|
|
15
|
+
stdout: `${sysname} ${hostname} ${release} #1 SMP ${machine} GNU/Linux`,
|
|
16
|
+
exitCode: 0,
|
|
17
|
+
};
|
|
15
18
|
if (ifFlag(args, ["-r"]))
|
|
16
19
|
return { stdout: release, exitCode: 0 };
|
|
17
20
|
if (ifFlag(args, ["-m"]))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uniq.d.ts","sourceRoot":"","sources":["../../src/commands/uniq.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"uniq.d.ts","sourceRoot":"","sources":["../../src/commands/uniq.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,WAAW,EAAE,WA8BzB,CAAC"}
|