typescript-virtual-container 1.2.5 → 1.2.7
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 +387 -193
- package/benchmark-results.txt +21 -21
- package/biome.json +1 -1
- package/bun.lock +15 -41
- package/dist/SSHMimic/exec.js +2 -2
- package/dist/SSHMimic/executor.d.ts +6 -7
- package/dist/SSHMimic/executor.d.ts.map +1 -1
- package/dist/SSHMimic/executor.js +77 -60
- package/dist/SSHMimic/index.d.ts.map +1 -1
- package/dist/SSHMimic/index.js +6 -20
- package/dist/SSHMimic/sftp.d.ts.map +1 -1
- package/dist/SSHMimic/sftp.js +14 -0
- package/dist/VirtualFileSystem/index.d.ts.map +1 -1
- package/dist/VirtualFileSystem/index.js +13 -36
- package/dist/VirtualShell/shell.d.ts.map +1 -1
- package/dist/VirtualShell/shell.js +19 -2
- package/dist/VirtualShell/shellParser.d.ts +20 -2
- package/dist/VirtualShell/shellParser.d.ts.map +1 -1
- package/dist/VirtualShell/shellParser.js +229 -120
- package/dist/VirtualUserManager/index.d.ts.map +1 -1
- package/dist/commands/adduser.d.ts.map +1 -1
- package/dist/commands/adduser.js +2 -0
- package/dist/commands/awk.d.ts +3 -0
- package/dist/commands/awk.d.ts.map +1 -0
- package/dist/commands/awk.js +29 -0
- package/dist/commands/base64.d.ts +3 -0
- package/dist/commands/base64.d.ts.map +1 -0
- package/dist/commands/base64.js +20 -0
- package/dist/commands/cat.d.ts.map +1 -1
- package/dist/commands/cat.js +2 -0
- package/dist/commands/cd.d.ts.map +1 -1
- package/dist/commands/cd.js +2 -0
- package/dist/commands/chmod.d.ts.map +1 -1
- package/dist/commands/chmod.js +2 -0
- package/dist/commands/clear.d.ts.map +1 -1
- package/dist/commands/clear.js +4 -1
- package/dist/commands/cp.d.ts.map +1 -1
- package/dist/commands/cp.js +2 -0
- package/dist/commands/curl.d.ts.map +1 -1
- package/dist/commands/curl.js +2 -0
- package/dist/commands/cut.d.ts +3 -0
- package/dist/commands/cut.d.ts.map +1 -0
- package/dist/commands/cut.js +27 -0
- package/dist/commands/date.d.ts +3 -0
- package/dist/commands/date.d.ts.map +1 -0
- package/dist/commands/date.js +22 -0
- package/dist/commands/deluser.d.ts.map +1 -1
- package/dist/commands/deluser.js +2 -0
- package/dist/commands/df.d.ts +3 -0
- package/dist/commands/df.d.ts.map +1 -0
- package/dist/commands/df.js +16 -0
- package/dist/commands/diff.d.ts +3 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +40 -0
- package/dist/commands/du.d.ts +3 -0
- package/dist/commands/du.d.ts.map +1 -0
- package/dist/commands/du.js +39 -0
- package/dist/commands/echo.d.ts.map +1 -1
- package/dist/commands/echo.js +2 -0
- package/dist/commands/env.d.ts +1 -0
- package/dist/commands/env.d.ts.map +1 -1
- package/dist/commands/env.js +6 -14
- package/dist/commands/export.d.ts.map +1 -1
- package/dist/commands/export.js +11 -21
- package/dist/commands/find.d.ts.map +1 -1
- package/dist/commands/find.js +2 -0
- package/dist/commands/grep.d.ts.map +1 -1
- package/dist/commands/grep.js +4 -7
- package/dist/commands/groups.d.ts +3 -0
- package/dist/commands/groups.d.ts.map +1 -0
- package/dist/commands/groups.js +12 -0
- package/dist/commands/gzip.d.ts +4 -0
- package/dist/commands/gzip.d.ts.map +1 -0
- package/dist/commands/gzip.js +40 -0
- package/dist/commands/head.d.ts.map +1 -1
- package/dist/commands/head.js +2 -0
- package/dist/commands/help.d.ts +1 -1
- package/dist/commands/help.d.ts.map +1 -1
- package/dist/commands/help.js +66 -3
- package/dist/commands/hostname.d.ts.map +1 -1
- package/dist/commands/hostname.js +2 -0
- package/dist/commands/htop.d.ts.map +1 -1
- package/dist/commands/htop.js +2 -0
- package/dist/commands/id.d.ts +3 -0
- package/dist/commands/id.d.ts.map +1 -0
- package/dist/commands/id.js +14 -0
- package/dist/commands/index.d.ts +5 -2
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +89 -62
- package/dist/commands/kill.d.ts +3 -0
- package/dist/commands/kill.d.ts.map +1 -0
- package/dist/commands/kill.js +13 -0
- package/dist/commands/ln.d.ts.map +1 -1
- package/dist/commands/ln.js +2 -0
- package/dist/commands/ls.d.ts.map +1 -1
- package/dist/commands/ls.js +2 -0
- package/dist/commands/mkdir.d.ts.map +1 -1
- package/dist/commands/mkdir.js +2 -0
- package/dist/commands/mv.d.ts.map +1 -1
- package/dist/commands/mv.js +2 -0
- package/dist/commands/nano.d.ts.map +1 -1
- package/dist/commands/nano.js +2 -0
- package/dist/commands/neofetch.d.ts.map +1 -1
- package/dist/commands/neofetch.js +2 -0
- package/dist/commands/passwd.d.ts.map +1 -1
- package/dist/commands/passwd.js +2 -0
- package/dist/commands/ping.d.ts +3 -0
- package/dist/commands/ping.d.ts.map +1 -0
- package/dist/commands/ping.js +18 -0
- package/dist/commands/ps.d.ts +3 -0
- package/dist/commands/ps.d.ts.map +1 -0
- package/dist/commands/ps.js +17 -0
- package/dist/commands/pwd.d.ts.map +1 -1
- package/dist/commands/pwd.js +2 -0
- package/dist/commands/rm.d.ts.map +1 -1
- package/dist/commands/rm.js +2 -0
- package/dist/commands/sed.d.ts +3 -0
- package/dist/commands/sed.d.ts.map +1 -0
- package/dist/commands/sed.js +47 -0
- package/dist/commands/set.d.ts +3 -0
- package/dist/commands/set.d.ts.map +1 -1
- package/dist/commands/set.js +19 -46
- package/dist/commands/sh.d.ts +0 -1
- package/dist/commands/sh.d.ts.map +1 -1
- package/dist/commands/sh.js +229 -35
- package/dist/commands/sleep.d.ts +3 -0
- package/dist/commands/sleep.d.ts.map +1 -0
- package/dist/commands/sleep.js +13 -0
- package/dist/commands/sort.d.ts +3 -0
- package/dist/commands/sort.d.ts.map +1 -0
- package/dist/commands/sort.js +37 -0
- package/dist/commands/su.d.ts.map +1 -1
- package/dist/commands/su.js +2 -0
- package/dist/commands/sudo.d.ts.map +1 -1
- package/dist/commands/sudo.js +2 -0
- package/dist/commands/tail.d.ts.map +1 -1
- package/dist/commands/tail.js +2 -0
- package/dist/commands/tar.d.ts +3 -0
- package/dist/commands/tar.d.ts.map +1 -0
- package/dist/commands/tar.js +64 -0
- package/dist/commands/tee.d.ts +3 -0
- package/dist/commands/tee.d.ts.map +1 -0
- package/dist/commands/tee.js +29 -0
- package/dist/commands/touch.d.ts.map +1 -1
- package/dist/commands/touch.js +2 -0
- package/dist/commands/tr.d.ts +3 -0
- package/dist/commands/tr.d.ts.map +1 -0
- package/dist/commands/tr.js +24 -0
- package/dist/commands/tree.d.ts.map +1 -1
- package/dist/commands/tree.js +2 -0
- package/dist/commands/uname.d.ts +3 -0
- package/dist/commands/uname.d.ts.map +1 -0
- package/dist/commands/uname.js +21 -0
- package/dist/commands/uniq.d.ts +3 -0
- package/dist/commands/uniq.d.ts.map +1 -0
- package/dist/commands/uniq.js +33 -0
- package/dist/commands/unset.d.ts.map +1 -1
- package/dist/commands/unset.js +6 -10
- package/dist/commands/wc.d.ts.map +1 -1
- package/dist/commands/wc.js +2 -0
- package/dist/commands/wget.d.ts.map +1 -1
- package/dist/commands/wget.js +2 -0
- package/dist/commands/who.d.ts.map +1 -1
- package/dist/commands/who.js +2 -0
- package/dist/commands/whoami.d.ts.map +1 -1
- package/dist/commands/whoami.js +2 -0
- package/dist/commands/xargs.d.ts +3 -0
- package/dist/commands/xargs.d.ts.map +1 -0
- package/dist/commands/xargs.js +16 -0
- package/dist/types/commands.d.ts +13 -0
- package/dist/types/commands.d.ts.map +1 -1
- package/dist/types/pipeline.d.ts +20 -0
- package/dist/types/pipeline.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/SSHMimic/exec.ts +2 -2
- package/src/SSHMimic/executor.ts +95 -98
- package/src/SSHMimic/index.ts +15 -49
- package/src/SSHMimic/sftp.ts +15 -0
- package/src/VirtualFileSystem/index.ts +27 -75
- package/src/VirtualShell/shell.ts +19 -2
- package/src/VirtualShell/shellParser.ts +202 -168
- package/src/VirtualUserManager/index.ts +2 -7
- package/src/commands/adduser.ts +2 -0
- package/src/commands/awk.ts +30 -0
- package/src/commands/base64.ts +18 -0
- package/src/commands/cat.ts +2 -0
- package/src/commands/cd.ts +2 -0
- package/src/commands/chmod.ts +2 -0
- package/src/commands/clear.ts +4 -1
- package/src/commands/cp.ts +2 -0
- package/src/commands/curl.ts +2 -0
- package/src/commands/cut.ts +29 -0
- package/src/commands/date.ts +24 -0
- package/src/commands/deluser.ts +2 -0
- package/src/commands/df.ts +18 -0
- package/src/commands/diff.ts +29 -0
- package/src/commands/du.ts +39 -0
- package/src/commands/echo.ts +2 -0
- package/src/commands/env.ts +7 -16
- package/src/commands/export.ts +11 -24
- package/src/commands/find.ts +2 -0
- package/src/commands/grep.ts +4 -7
- package/src/commands/groups.ts +14 -0
- package/src/commands/gzip.ts +31 -0
- package/src/commands/head.ts +2 -0
- package/src/commands/help.ts +72 -3
- package/src/commands/hostname.ts +2 -0
- package/src/commands/htop.ts +2 -0
- package/src/commands/id.ts +16 -0
- package/src/commands/index.ts +98 -99
- package/src/commands/kill.ts +14 -0
- package/src/commands/ln.ts +2 -0
- package/src/commands/ls.ts +2 -0
- package/src/commands/mkdir.ts +2 -0
- package/src/commands/mv.ts +2 -0
- package/src/commands/nano.ts +2 -0
- package/src/commands/neofetch.ts +2 -0
- package/src/commands/passwd.ts +2 -0
- package/src/commands/ping.ts +20 -0
- package/src/commands/ps.ts +19 -0
- package/src/commands/pwd.ts +2 -0
- package/src/commands/rm.ts +2 -0
- package/src/commands/sed.ts +45 -0
- package/src/commands/set.ts +19 -50
- package/src/commands/sh.ts +193 -43
- package/src/commands/sleep.ts +14 -0
- package/src/commands/sort.ts +37 -0
- package/src/commands/su.ts +2 -0
- package/src/commands/sudo.ts +2 -0
- package/src/commands/tail.ts +2 -0
- package/src/commands/tar.ts +58 -0
- package/src/commands/tee.ts +25 -0
- package/src/commands/touch.ts +2 -0
- package/src/commands/tr.ts +24 -0
- package/src/commands/tree.ts +2 -0
- package/src/commands/uname.ts +20 -0
- package/src/commands/uniq.ts +28 -0
- package/src/commands/unset.ts +5 -12
- package/src/commands/wc.ts +2 -0
- package/src/commands/wget.ts +2 -0
- package/src/commands/who.ts +2 -0
- package/src/commands/whoami.ts +2 -0
- package/src/commands/xargs.ts +17 -0
- package/src/types/commands.ts +14 -0
- package/src/types/pipeline.ts +23 -0
- package/standalone.js +92 -64
- package/standalone.js.map +4 -4
- package/tests/users.test.ts +5 -34
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { getFlag, ifFlag } from "./command-helpers";
|
|
2
|
+
import { resolvePath } from "./helpers";
|
|
3
|
+
export const sedCommand = {
|
|
4
|
+
name: "sed",
|
|
5
|
+
description: "Stream editor for filtering and transforming text",
|
|
6
|
+
category: "text",
|
|
7
|
+
params: ["-e <expr> [file]", "s/pattern/replace/[g]"],
|
|
8
|
+
run: ({ authUser, shell, cwd, args, stdin }) => {
|
|
9
|
+
const inPlace = ifFlag(args, ["-i"]);
|
|
10
|
+
const expr = getFlag(args, ["-e"]) ?? args.find((a) => !a.startsWith("-"));
|
|
11
|
+
const fileArg = args.filter((a) => !a.startsWith("-") && a !== expr).pop();
|
|
12
|
+
if (!expr)
|
|
13
|
+
return { stderr: "sed: no expression", exitCode: 1 };
|
|
14
|
+
let content = stdin ?? "";
|
|
15
|
+
if (fileArg) {
|
|
16
|
+
const p = resolvePath(cwd, fileArg);
|
|
17
|
+
try {
|
|
18
|
+
content = shell.vfs.readFile(p);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return { stderr: `sed: ${fileArg}: No such file or directory`, exitCode: 1 };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// Parse s/from/to/[g]
|
|
25
|
+
const sMatch = expr.match(/^s([^a-zA-Z0-9])(.+?)\1(.*?)\1([gi]*)$/);
|
|
26
|
+
if (!sMatch)
|
|
27
|
+
return { stderr: `sed: unrecognized command: ${expr}`, exitCode: 1 };
|
|
28
|
+
const [, , from, to, flags] = sMatch;
|
|
29
|
+
const regexFlags = (flags ?? "").includes("i") ? "gi" : (flags ?? "").includes("g") ? "g" : "";
|
|
30
|
+
let regex;
|
|
31
|
+
try {
|
|
32
|
+
regex = new RegExp(from, regexFlags || "");
|
|
33
|
+
}
|
|
34
|
+
catch (_e) {
|
|
35
|
+
return { stderr: `sed: invalid regex: ${from}`, exitCode: 1 };
|
|
36
|
+
}
|
|
37
|
+
const result = (flags ?? "").includes("g") || regexFlags.includes("g")
|
|
38
|
+
? content.replace(regex, to ?? "")
|
|
39
|
+
: content.replace(regex, to ?? "");
|
|
40
|
+
if (inPlace && fileArg) {
|
|
41
|
+
const p = resolvePath(cwd, fileArg);
|
|
42
|
+
shell.writeFileAsUser(authUser, p, result);
|
|
43
|
+
return { exitCode: 0 };
|
|
44
|
+
}
|
|
45
|
+
return { stdout: result, exitCode: 0 };
|
|
46
|
+
},
|
|
47
|
+
};
|
package/dist/commands/set.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/** biome-ignore-all lint/style/useNamingConvention: env variables */
|
|
2
2
|
import type { ShellModule } from "../types/commands";
|
|
3
|
+
/** @deprecated use env.vars from CommandContext */
|
|
3
4
|
export declare function getEnvVar(name: string): string | undefined;
|
|
5
|
+
/** @deprecated use env.vars from CommandContext */
|
|
4
6
|
export declare function setEnvVar(name: string, value: string): void;
|
|
7
|
+
/** @deprecated use env.vars from CommandContext */
|
|
5
8
|
export declare function getAllEnvVars(authUser: string): Record<string, string>;
|
|
6
9
|
export declare const setCommand: ShellModule;
|
|
7
10
|
//# sourceMappingURL=set.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"set.d.ts","sourceRoot":"","sources":["../../src/commands/set.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"set.d.ts","sourceRoot":"","sources":["../../src/commands/set.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAWrD,mDAAmD;AACnD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAA6B;AACxF,mDAAmD;AACnD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAA8B;AAC1F,mDAAmD;AACnD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAItE;AAED,eAAO,MAAM,UAAU,EAAE,WAkBxB,CAAC"}
|
package/dist/commands/set.js
CHANGED
|
@@ -1,64 +1,37 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
// In a real implementation, this would be per-session/per-user
|
|
4
|
-
const envVars = {
|
|
1
|
+
// Legacy global store kept for compatibility with older callers
|
|
2
|
+
const _globalEnv = {
|
|
5
3
|
PATH: "/usr/local/bin:/usr/bin:/bin",
|
|
6
4
|
HOME: "/home/user",
|
|
7
5
|
SHELL: "/bin/sh",
|
|
8
6
|
TERM: "xterm-256color",
|
|
9
7
|
USER: "user",
|
|
10
8
|
};
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export function setEnvVar(name, value) {
|
|
15
|
-
|
|
16
|
-
}
|
|
9
|
+
/** @deprecated use env.vars from CommandContext */
|
|
10
|
+
export function getEnvVar(name) { return _globalEnv[name]; }
|
|
11
|
+
/** @deprecated use env.vars from CommandContext */
|
|
12
|
+
export function setEnvVar(name, value) { _globalEnv[name] = value; }
|
|
13
|
+
/** @deprecated use env.vars from CommandContext */
|
|
17
14
|
export function getAllEnvVars(authUser) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return { ...
|
|
15
|
+
_globalEnv.USER = authUser;
|
|
16
|
+
_globalEnv.HOME = `/home/${authUser}`;
|
|
17
|
+
return { ..._globalEnv };
|
|
21
18
|
}
|
|
22
19
|
export const setCommand = {
|
|
23
20
|
name: "set",
|
|
21
|
+
description: "Display or set shell variables",
|
|
22
|
+
category: "shell",
|
|
24
23
|
params: ["[VAR=value]"],
|
|
25
|
-
run: ({ args }) => {
|
|
26
|
-
// No arguments: display all environment variables
|
|
24
|
+
run: ({ args, env }) => {
|
|
27
25
|
if (args.length === 0) {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
.sort()
|
|
31
|
-
.join("\n");
|
|
32
|
-
return { stdout: output, exitCode: 0 };
|
|
26
|
+
const out = Object.entries(env.vars).map(([k, v]) => `${k}=${v}`).join("\n");
|
|
27
|
+
return { stdout: out, exitCode: 0 };
|
|
33
28
|
}
|
|
34
|
-
|
|
35
|
-
const assignments = [];
|
|
36
|
-
for (let index = 0;; index += 1) {
|
|
37
|
-
const arg = getArg(args, index);
|
|
38
|
-
if (!arg) {
|
|
39
|
-
break;
|
|
40
|
-
}
|
|
29
|
+
for (const arg of args) {
|
|
41
30
|
if (arg.includes("=")) {
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
setEnvVar(varName, varValue);
|
|
45
|
-
assignments.push(arg);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
// If no '=' present, display that specific variable
|
|
50
|
-
const value = getEnvVar(arg);
|
|
51
|
-
if (value !== undefined) {
|
|
52
|
-
assignments.push(`${arg}=${value}`);
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
assignments.push(`${arg}: not set`);
|
|
56
|
-
}
|
|
31
|
+
const eq = arg.indexOf("=");
|
|
32
|
+
env.vars[arg.slice(0, eq)] = arg.slice(eq + 1);
|
|
57
33
|
}
|
|
58
34
|
}
|
|
59
|
-
return {
|
|
60
|
-
stdout: assignments.length > 0 ? assignments.join("\n") : "",
|
|
61
|
-
exitCode: 0,
|
|
62
|
-
};
|
|
35
|
+
return { exitCode: 0 };
|
|
63
36
|
},
|
|
64
37
|
};
|
package/dist/commands/sh.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sh.d.ts","sourceRoot":"","sources":["../../src/commands/sh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"sh.d.ts","sourceRoot":"","sources":["../../src/commands/sh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiC,WAAW,EAAE,MAAM,mBAAmB,CAAC;AA+KpF,eAAO,MAAM,SAAS,EAAE,WA+BvB,CAAC"}
|
package/dist/commands/sh.js
CHANGED
|
@@ -1,45 +1,239 @@
|
|
|
1
|
-
import { getArg,
|
|
1
|
+
import { getArg, ifFlag } from "./command-helpers";
|
|
2
|
+
import { resolvePath } from "./helpers";
|
|
2
3
|
import { runCommand } from "./index";
|
|
3
|
-
/**
|
|
4
|
+
/** Expand $VAR and ${VAR:-default} in a line using the current env */
|
|
5
|
+
function expandVars(line, env, lastExit) {
|
|
6
|
+
return line
|
|
7
|
+
.replace(/\$\?/g, String(lastExit))
|
|
8
|
+
.replace(/\$\{([^}:]+):-([^}]*)\}/g, (_, n, d) => env[n] ?? d)
|
|
9
|
+
.replace(/\$\{([^}]+)\}/g, (_, n) => env[n] ?? "")
|
|
10
|
+
.replace(/\$([A-Za-z_][A-Za-z0-9_]*)/g, (_, n) => env[n] ?? "")
|
|
11
|
+
.replace(/^~(\/|$)/, `${env.HOME ?? "/home/user"}$1`);
|
|
12
|
+
}
|
|
13
|
+
/** Very small shell interpreter: supports if/elif/else/fi, for/do/done, while/do/done */
|
|
14
|
+
function parseBlocks(lines) {
|
|
15
|
+
const blocks = [];
|
|
16
|
+
let i = 0;
|
|
17
|
+
while (i < lines.length) {
|
|
18
|
+
const line = lines[i].trim();
|
|
19
|
+
if (!line || line.startsWith("#")) {
|
|
20
|
+
i++;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (line.startsWith("if ") || line === "if") {
|
|
24
|
+
const cond = line.replace(/^if\s+/, "").replace(/;\s*then\s*$/, "").trim();
|
|
25
|
+
const thenLines = [];
|
|
26
|
+
const elifBlocks = [];
|
|
27
|
+
const elseLines = [];
|
|
28
|
+
let section = "then";
|
|
29
|
+
let elifCond = "";
|
|
30
|
+
i++;
|
|
31
|
+
while (i < lines.length && lines[i]?.trim() !== "fi") {
|
|
32
|
+
const l = lines[i].trim();
|
|
33
|
+
if (l.startsWith("elif ")) {
|
|
34
|
+
section = "elif";
|
|
35
|
+
elifCond = l.replace(/^elif\s+/, "").replace(/;\s*then\s*$/, "").trim();
|
|
36
|
+
elifBlocks.push({ cond: elifCond, body: [] });
|
|
37
|
+
}
|
|
38
|
+
else if (l === "else") {
|
|
39
|
+
section = "else";
|
|
40
|
+
}
|
|
41
|
+
else if (l !== "then") {
|
|
42
|
+
if (section === "then")
|
|
43
|
+
thenLines.push(l);
|
|
44
|
+
else if (section === "elif" && elifBlocks.length > 0)
|
|
45
|
+
elifBlocks[elifBlocks.length - 1].body.push(l);
|
|
46
|
+
else
|
|
47
|
+
elseLines.push(l);
|
|
48
|
+
}
|
|
49
|
+
i++;
|
|
50
|
+
}
|
|
51
|
+
// biome-ignore lint/suspicious/noThenProperty: expected behavior for if/elif parsing
|
|
52
|
+
blocks.push({ type: "if", cond, then: thenLines, elif: elifBlocks, else_: elseLines });
|
|
53
|
+
}
|
|
54
|
+
else if (line.startsWith("for ")) {
|
|
55
|
+
const m = line.match(/^for\s+(\w+)\s+in\s+(.+?)(?:\s*;\s*do)?$/);
|
|
56
|
+
if (m) {
|
|
57
|
+
const body = [];
|
|
58
|
+
i++;
|
|
59
|
+
while (i < lines.length && lines[i]?.trim() !== "done") {
|
|
60
|
+
const l = lines[i].trim();
|
|
61
|
+
if (l !== "do")
|
|
62
|
+
body.push(l);
|
|
63
|
+
i++;
|
|
64
|
+
}
|
|
65
|
+
blocks.push({ type: "for", var: m[1], list: m[2], body });
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
blocks.push({ type: "cmd", line });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else if (line.startsWith("while ")) {
|
|
72
|
+
const cond = line.replace(/^while\s+/, "").replace(/;\s*do\s*$/, "").trim();
|
|
73
|
+
const body = [];
|
|
74
|
+
i++;
|
|
75
|
+
while (i < lines.length && lines[i]?.trim() !== "done") {
|
|
76
|
+
const l = lines[i].trim();
|
|
77
|
+
if (l !== "do")
|
|
78
|
+
body.push(l);
|
|
79
|
+
i++;
|
|
80
|
+
}
|
|
81
|
+
blocks.push({ type: "while", cond, body });
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
blocks.push({ type: "cmd", line });
|
|
85
|
+
}
|
|
86
|
+
i++;
|
|
87
|
+
}
|
|
88
|
+
return blocks;
|
|
89
|
+
}
|
|
90
|
+
async function evalCondition(cond, ctx) {
|
|
91
|
+
const expanded = expandVars(cond, ctx.env.vars, ctx.env.lastExitCode);
|
|
92
|
+
// test -f / test -d / [ ... ]
|
|
93
|
+
const testMatch = expanded.match(/^\[?\s*(.+?)\s*\]?$/);
|
|
94
|
+
if (testMatch) {
|
|
95
|
+
const expr = testMatch[1];
|
|
96
|
+
// -f file
|
|
97
|
+
const fTest = expr.match(/^-([fdeznr])\s+(.+)$/);
|
|
98
|
+
if (fTest) {
|
|
99
|
+
const [, flag, arg] = fTest;
|
|
100
|
+
const p = resolvePath(ctx.cwd, arg);
|
|
101
|
+
if (flag === "f")
|
|
102
|
+
return ctx.shell.vfs.exists(p) && ctx.shell.vfs.stat(p).type === "file";
|
|
103
|
+
if (flag === "d")
|
|
104
|
+
return ctx.shell.vfs.exists(p) && ctx.shell.vfs.stat(p).type === "directory";
|
|
105
|
+
if (flag === "e")
|
|
106
|
+
return ctx.shell.vfs.exists(p);
|
|
107
|
+
if (flag === "z")
|
|
108
|
+
return (arg ?? "").length === 0;
|
|
109
|
+
if (flag === "n")
|
|
110
|
+
return (arg ?? "").length > 0;
|
|
111
|
+
}
|
|
112
|
+
// string comparison
|
|
113
|
+
const cmpMatch = expr.match(/^"?([^"]*)"?\s*(==|!=|=|<|>)\s*"?([^"]*)"?$/);
|
|
114
|
+
if (cmpMatch) {
|
|
115
|
+
const [, a, op, b] = cmpMatch;
|
|
116
|
+
if (op === "==" || op === "=")
|
|
117
|
+
return a === b;
|
|
118
|
+
if (op === "!=")
|
|
119
|
+
return a !== b;
|
|
120
|
+
}
|
|
121
|
+
// numeric
|
|
122
|
+
const numMatch = expr.match(/^(\S+)\s+(-eq|-ne|-lt|-le|-gt|-ge)\s+(\S+)$/);
|
|
123
|
+
if (numMatch) {
|
|
124
|
+
const [, a, op, b] = numMatch;
|
|
125
|
+
const na = Number(a), nb = Number(b);
|
|
126
|
+
if (op === "-eq")
|
|
127
|
+
return na === nb;
|
|
128
|
+
if (op === "-ne")
|
|
129
|
+
return na !== nb;
|
|
130
|
+
if (op === "-lt")
|
|
131
|
+
return na < nb;
|
|
132
|
+
if (op === "-le")
|
|
133
|
+
return na <= nb;
|
|
134
|
+
if (op === "-gt")
|
|
135
|
+
return na > nb;
|
|
136
|
+
if (op === "-ge")
|
|
137
|
+
return na >= nb;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// fallback: run command and check exit code
|
|
141
|
+
const r = await runCommand(expanded, ctx.authUser, ctx.hostname, ctx.mode, ctx.cwd, ctx.shell, undefined, ctx.env);
|
|
142
|
+
return (r.exitCode ?? 0) === 0;
|
|
143
|
+
}
|
|
144
|
+
async function runBlocks(blocks, ctx) {
|
|
145
|
+
let lastResult = { exitCode: 0 };
|
|
146
|
+
let output = "";
|
|
147
|
+
for (const block of blocks) {
|
|
148
|
+
if (block.type === "cmd") {
|
|
149
|
+
const expanded = expandVars(block.line, ctx.env.vars, ctx.env.lastExitCode);
|
|
150
|
+
const r = await runCommand(expanded, ctx.authUser, ctx.hostname, ctx.mode, ctx.cwd, ctx.shell, undefined, ctx.env);
|
|
151
|
+
ctx.env.lastExitCode = r.exitCode ?? 0;
|
|
152
|
+
if (r.stdout)
|
|
153
|
+
output += `${r.stdout}\n`;
|
|
154
|
+
if (r.stderr)
|
|
155
|
+
return { ...r, stdout: output.trim() };
|
|
156
|
+
lastResult = r;
|
|
157
|
+
}
|
|
158
|
+
else if (block.type === "if") {
|
|
159
|
+
let ran = false;
|
|
160
|
+
if (await evalCondition(block.cond, ctx)) {
|
|
161
|
+
const sub = await runBlocks(parseBlocks(block.then), ctx);
|
|
162
|
+
if (sub.stdout)
|
|
163
|
+
output += `${sub.stdout}\n`;
|
|
164
|
+
ran = true;
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
for (const elif of block.elif) {
|
|
168
|
+
if (await evalCondition(elif.cond, ctx)) {
|
|
169
|
+
const sub = await runBlocks(parseBlocks(elif.body), ctx);
|
|
170
|
+
if (sub.stdout)
|
|
171
|
+
output += `${sub.stdout}\n`;
|
|
172
|
+
ran = true;
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (!ran && block.else_.length > 0) {
|
|
177
|
+
const sub = await runBlocks(parseBlocks(block.else_), ctx);
|
|
178
|
+
if (sub.stdout)
|
|
179
|
+
output += `${sub.stdout}\n`;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
else if (block.type === "for") {
|
|
184
|
+
const listExpanded = expandVars(block.list, ctx.env.vars, ctx.env.lastExitCode);
|
|
185
|
+
const items = listExpanded.trim().split(/\s+/);
|
|
186
|
+
for (const item of items) {
|
|
187
|
+
ctx.env.vars[block.var] = item;
|
|
188
|
+
const sub = await runBlocks(parseBlocks(block.body), ctx);
|
|
189
|
+
if (sub.stdout)
|
|
190
|
+
output += `${sub.stdout}\n`;
|
|
191
|
+
if (sub.closeSession)
|
|
192
|
+
return sub;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else if (block.type === "while") {
|
|
196
|
+
let iterations = 0;
|
|
197
|
+
while (iterations < 1000 && await evalCondition(block.cond, ctx)) {
|
|
198
|
+
const sub = await runBlocks(parseBlocks(block.body), ctx);
|
|
199
|
+
if (sub.stdout)
|
|
200
|
+
output += `${sub.stdout}\n`;
|
|
201
|
+
if (sub.closeSession)
|
|
202
|
+
return sub;
|
|
203
|
+
iterations++;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return { ...lastResult, stdout: output.trim() || lastResult.stdout };
|
|
208
|
+
}
|
|
4
209
|
export const shCommand = {
|
|
5
210
|
name: "sh",
|
|
6
|
-
params: ["-c <script>", "[<file>]"],
|
|
7
211
|
aliases: ["bash"],
|
|
212
|
+
description: "Execute shell script or command",
|
|
213
|
+
category: "shell",
|
|
214
|
+
params: ["-c <script>", "[<file>]"],
|
|
8
215
|
run: async (ctx) => {
|
|
9
|
-
const { args,
|
|
10
|
-
//
|
|
11
|
-
if (
|
|
216
|
+
const { args, shell, cwd } = ctx;
|
|
217
|
+
// sh -c "inline script"
|
|
218
|
+
if (ifFlag(args, "-c")) {
|
|
12
219
|
const script = getArg(args, 1) ?? "";
|
|
13
|
-
if (!script)
|
|
220
|
+
if (!script)
|
|
14
221
|
return { stderr: "sh: -c requires a script", exitCode: 1 };
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
command = command.replaceAll(`$${i}`, arg);
|
|
30
|
-
}
|
|
31
|
-
command = command.replaceAll("$@", scriptArgs.join(" "));
|
|
32
|
-
// Execute the command
|
|
33
|
-
const result = await Promise.resolve(runCommand(command, authUser, hostname, mode, cwd, ctx.shell));
|
|
34
|
-
if (result.stdout) {
|
|
35
|
-
output += `${result.stdout}\n`;
|
|
36
|
-
}
|
|
37
|
-
if (result.stderr) {
|
|
38
|
-
return { stderr: result.stderr, exitCode: result.exitCode ?? 1 };
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return { stdout: output.trim(), exitCode };
|
|
222
|
+
const lines = script.split(/[;\n]/).map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
|
|
223
|
+
const blocks = parseBlocks(lines);
|
|
224
|
+
return runBlocks(blocks, ctx);
|
|
225
|
+
}
|
|
226
|
+
// sh <file>
|
|
227
|
+
const fileArg = args[0];
|
|
228
|
+
if (fileArg) {
|
|
229
|
+
const p = resolvePath(cwd, fileArg);
|
|
230
|
+
if (!shell.vfs.exists(p))
|
|
231
|
+
return { stderr: `sh: ${fileArg}: No such file or directory`, exitCode: 1 };
|
|
232
|
+
const content = shell.vfs.readFile(p);
|
|
233
|
+
const lines = content.split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
|
|
234
|
+
const blocks = parseBlocks(lines);
|
|
235
|
+
return runBlocks(blocks, ctx);
|
|
42
236
|
}
|
|
43
|
-
return { stderr: "sh: invalid usage", exitCode: 1 };
|
|
237
|
+
return { stderr: "sh: invalid usage. Use: sh -c 'cmd' or sh <file>", exitCode: 1 };
|
|
44
238
|
},
|
|
45
239
|
};
|
|
@@ -0,0 +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,WAW1B,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const sleepCommand = {
|
|
2
|
+
name: "sleep",
|
|
3
|
+
description: "Delay execution",
|
|
4
|
+
category: "system",
|
|
5
|
+
params: ["<seconds>"],
|
|
6
|
+
run: async ({ args }) => {
|
|
7
|
+
const secs = parseFloat(args[0] ?? "1");
|
|
8
|
+
if (Number.isNaN(secs) || secs < 0)
|
|
9
|
+
return { stderr: "sleep: invalid time", exitCode: 1 };
|
|
10
|
+
await new Promise((r) => setTimeout(r, secs * 1000));
|
|
11
|
+
return { exitCode: 0 };
|
|
12
|
+
},
|
|
13
|
+
};
|
|
@@ -0,0 +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,WAgCzB,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ifFlag } from "./command-helpers";
|
|
2
|
+
import { assertPathAccess, resolvePath } from "./helpers";
|
|
3
|
+
export const sortCommand = {
|
|
4
|
+
name: "sort",
|
|
5
|
+
description: "Sort lines of text",
|
|
6
|
+
category: "text",
|
|
7
|
+
params: ["[-r] [-n] [-u] [-k <col>] [file...]"],
|
|
8
|
+
run: ({ authUser, shell, cwd, args, stdin }) => {
|
|
9
|
+
const reverse = ifFlag(args, ["-r"]);
|
|
10
|
+
const numeric = ifFlag(args, ["-n"]);
|
|
11
|
+
const unique = ifFlag(args, ["-u"]);
|
|
12
|
+
const files = args.filter((a) => !a.startsWith("-"));
|
|
13
|
+
const getContent = () => {
|
|
14
|
+
if (files.length > 0) {
|
|
15
|
+
return files.map((f) => {
|
|
16
|
+
try {
|
|
17
|
+
assertPathAccess(authUser, resolvePath(cwd, f), "sort");
|
|
18
|
+
return shell.vfs.readFile(resolvePath(cwd, f));
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return "";
|
|
22
|
+
}
|
|
23
|
+
}).join("\n");
|
|
24
|
+
}
|
|
25
|
+
return stdin ?? "";
|
|
26
|
+
};
|
|
27
|
+
const lines = getContent().split("\n").filter(Boolean);
|
|
28
|
+
const sorted = [...lines].sort((a, b) => {
|
|
29
|
+
if (numeric)
|
|
30
|
+
return Number(a) - Number(b);
|
|
31
|
+
return a.localeCompare(b);
|
|
32
|
+
});
|
|
33
|
+
const result = reverse ? sorted.reverse() : sorted;
|
|
34
|
+
const out = unique ? [...new Set(result)] : result;
|
|
35
|
+
return { stdout: out.join("\n"), exitCode: 0 };
|
|
36
|
+
},
|
|
37
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"su.d.ts","sourceRoot":"","sources":["../../src/commands/su.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"su.d.ts","sourceRoot":"","sources":["../../src/commands/su.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,SAAS,EAAE,WA8BvB,CAAC"}
|
package/dist/commands/su.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sudo.d.ts","sourceRoot":"","sources":["../../src/commands/sudo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAqBrD,eAAO,MAAM,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"sudo.d.ts","sourceRoot":"","sources":["../../src/commands/sudo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAqBrD,eAAO,MAAM,WAAW,EAAE,WAiDzB,CAAC"}
|
package/dist/commands/sudo.js
CHANGED
|
@@ -12,6 +12,8 @@ function parseSudoArgs(args) {
|
|
|
12
12
|
}
|
|
13
13
|
export const sudoCommand = {
|
|
14
14
|
name: "sudo",
|
|
15
|
+
description: "Execute as superuser",
|
|
16
|
+
category: "users",
|
|
15
17
|
params: ["<command...>"],
|
|
16
18
|
run: async ({ authUser, hostname, mode, cwd, shell, args }) => {
|
|
17
19
|
const { targetUser, loginShell, commandLine } = parseSudoArgs(args);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tail.d.ts","sourceRoot":"","sources":["../../src/commands/tail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"tail.d.ts","sourceRoot":"","sources":["../../src/commands/tail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,WAAW,EAAE,WAkCzB,CAAC"}
|
package/dist/commands/tail.js
CHANGED
|
@@ -2,6 +2,8 @@ import { getFlag } from "./command-helpers";
|
|
|
2
2
|
import { assertPathAccess, resolvePath } from "./helpers";
|
|
3
3
|
export const tailCommand = {
|
|
4
4
|
name: "tail",
|
|
5
|
+
description: "Output last lines",
|
|
6
|
+
category: "text",
|
|
5
7
|
params: ["[-n <lines>] [file...]"],
|
|
6
8
|
run: ({ authUser, shell, cwd, args, stdin }) => {
|
|
7
9
|
const nArg = getFlag(args, ["-n"]);
|
|
@@ -0,0 +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,WAqDxB,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { ifFlag } from "./command-helpers";
|
|
2
|
+
import { resolvePath } from "./helpers";
|
|
3
|
+
export const tarCommand = {
|
|
4
|
+
name: "tar",
|
|
5
|
+
description: "Archive utility",
|
|
6
|
+
category: "archive",
|
|
7
|
+
params: ["[-czf|-xzf|-tf] <archive> [files...]"],
|
|
8
|
+
run: ({ authUser, shell, cwd, args }) => {
|
|
9
|
+
const create = ifFlag(args, ["-c"]);
|
|
10
|
+
const extract = ifFlag(args, ["-x"]);
|
|
11
|
+
const list = ifFlag(args, ["-t"]);
|
|
12
|
+
const fFlag = args.findIndex((a) => a.includes("f"));
|
|
13
|
+
const archiveName = fFlag !== -1 ? args[fFlag + 1] : args.find((a) => a.endsWith(".tar") || a.endsWith(".tar.gz") || a.endsWith(".tgz"));
|
|
14
|
+
if (!archiveName)
|
|
15
|
+
return { stderr: "tar: no archive specified", exitCode: 1 };
|
|
16
|
+
const archivePath = resolvePath(cwd, archiveName);
|
|
17
|
+
if (create) {
|
|
18
|
+
const fileArgs = args.filter((a) => !a.startsWith("-") && a !== archiveName);
|
|
19
|
+
const entries = {};
|
|
20
|
+
for (const f of fileArgs) {
|
|
21
|
+
const p = resolvePath(cwd, f);
|
|
22
|
+
try {
|
|
23
|
+
const stat = shell.vfs.stat(p);
|
|
24
|
+
if (stat.type === "file")
|
|
25
|
+
entries[f] = shell.vfs.readFile(p);
|
|
26
|
+
else {
|
|
27
|
+
const walk = (dir, prefix) => {
|
|
28
|
+
for (const e of shell.vfs.list(dir)) {
|
|
29
|
+
const full = `${dir}/${e}`, rel = `${prefix}/${e}`;
|
|
30
|
+
const s = shell.vfs.stat(full);
|
|
31
|
+
if (s.type === "file")
|
|
32
|
+
entries[rel] = shell.vfs.readFile(full);
|
|
33
|
+
else
|
|
34
|
+
walk(full, rel);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
walk(p, f);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return { stderr: `tar: ${f}: No such file or directory`, exitCode: 1 };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
shell.writeFileAsUser(authUser, archivePath, JSON.stringify(entries));
|
|
45
|
+
return { exitCode: 0 };
|
|
46
|
+
}
|
|
47
|
+
if (list || extract) {
|
|
48
|
+
let entries;
|
|
49
|
+
try {
|
|
50
|
+
entries = JSON.parse(shell.vfs.readFile(archivePath));
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return { stderr: `tar: ${archiveName}: cannot open archive`, exitCode: 1 };
|
|
54
|
+
}
|
|
55
|
+
if (list)
|
|
56
|
+
return { stdout: Object.keys(entries).join("\n"), exitCode: 0 };
|
|
57
|
+
for (const [name, content] of Object.entries(entries)) {
|
|
58
|
+
shell.writeFileAsUser(authUser, resolvePath(cwd, name), content);
|
|
59
|
+
}
|
|
60
|
+
return { exitCode: 0 };
|
|
61
|
+
}
|
|
62
|
+
return { stderr: "tar: must specify -c, -x, or -t", exitCode: 1 };
|
|
63
|
+
},
|
|
64
|
+
};
|
|
@@ -0,0 +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,WAoBxB,CAAC"}
|