typescript-virtual-container 1.2.7 → 1.2.9
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 +457 -42
- package/dist/SSHMimic/executor.js +3 -5
- package/dist/VirtualFileSystem/binaryPack.d.ts +49 -0
- package/dist/VirtualFileSystem/binaryPack.d.ts.map +1 -0
- package/dist/VirtualFileSystem/binaryPack.js +193 -0
- package/dist/VirtualFileSystem/index.d.ts +7 -5
- package/dist/VirtualFileSystem/index.d.ts.map +1 -1
- package/dist/VirtualFileSystem/index.js +20 -9
- package/dist/VirtualPackageManager/index.d.ts +202 -0
- package/dist/VirtualPackageManager/index.d.ts.map +1 -0
- package/dist/VirtualPackageManager/index.js +676 -0
- package/dist/VirtualShell/index.d.ts +87 -12
- package/dist/VirtualShell/index.d.ts.map +1 -1
- package/dist/VirtualShell/index.js +83 -12
- 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/alias.d.ts +4 -0
- package/dist/commands/alias.d.ts.map +1 -0
- package/dist/commands/alias.js +58 -0
- package/dist/commands/apt.d.ts +4 -0
- package/dist/commands/apt.d.ts.map +1 -0
- package/dist/commands/apt.js +182 -0
- package/dist/commands/cat.d.ts.map +1 -1
- package/dist/commands/cat.js +27 -8
- package/dist/commands/chmod.d.ts.map +1 -1
- package/dist/commands/chmod.js +52 -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/curl.d.ts.map +1 -1
- package/dist/commands/curl.js +81 -29
- package/dist/commands/dpkg.d.ts +4 -0
- package/dist/commands/dpkg.d.ts.map +1 -0
- package/dist/commands/dpkg.js +144 -0
- package/dist/commands/echo.d.ts.map +1 -1
- package/dist/commands/echo.js +24 -12
- package/dist/commands/free.d.ts +3 -0
- package/dist/commands/free.d.ts.map +1 -0
- package/dist/commands/free.js +38 -0
- 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 +3 -0
- package/dist/commands/history.d.ts.map +1 -0
- package/dist/commands/history.js +21 -0
- package/dist/commands/index.d.ts +8 -1
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +120 -11
- package/dist/commands/ls.d.ts.map +1 -1
- package/dist/commands/ls.js +4 -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 +50 -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/neofetch.d.ts.map +1 -1
- package/dist/commands/neofetch.js +5 -0
- package/dist/commands/ping.d.ts.map +1 -1
- package/dist/commands/ping.js +5 -2
- package/dist/commands/ps.d.ts.map +1 -1
- package/dist/commands/ps.js +27 -6
- package/dist/commands/sh.d.ts.map +1 -1
- package/dist/commands/sh.js +29 -11
- package/dist/commands/source.d.ts +3 -0
- package/dist/commands/source.d.ts.map +1 -0
- package/dist/commands/source.js +31 -0
- package/dist/commands/test.d.ts +3 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +92 -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/uptime.d.ts +3 -0
- package/dist/commands/uptime.d.ts.map +1 -0
- package/dist/commands/uptime.js +40 -0
- package/dist/commands/wget.d.ts.map +1 -1
- package/dist/commands/wget.js +71 -100
- 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/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/modules/linuxRootfs.d.ts +24 -0
- package/dist/modules/linuxRootfs.d.ts.map +1 -0
- package/dist/modules/linuxRootfs.js +297 -0
- package/dist/modules/neofetch.d.ts.map +1 -1
- package/dist/modules/neofetch.js +1 -0
- package/dist/standalone.js +4 -1
- package/package.json +2 -1
- package/src/SSHMimic/executor.ts +3 -5
- package/src/VirtualFileSystem/binaryPack.ts +219 -0
- package/src/VirtualFileSystem/index.ts +21 -11
- package/src/VirtualPackageManager/index.ts +820 -0
- package/src/VirtualShell/index.ts +104 -13
- package/src/VirtualUserManager/index.ts +55 -20
- package/src/commands/alias.ts +60 -0
- package/src/commands/apt.ts +198 -0
- package/src/commands/cat.ts +32 -8
- package/src/commands/chmod.ts +48 -3
- package/src/commands/command-helpers.ts +78 -4
- package/src/commands/curl.ts +78 -37
- package/src/commands/dpkg.ts +158 -0
- package/src/commands/echo.ts +30 -14
- package/src/commands/free.ts +40 -0
- package/src/commands/helpers.ts +8 -0
- package/src/commands/history.ts +29 -0
- package/src/commands/index.ts +116 -11
- package/src/commands/ls.ts +5 -4
- package/src/commands/lsb-release.ts +52 -0
- package/src/commands/man.ts +166 -0
- package/src/commands/neofetch.ts +5 -0
- package/src/commands/ping.ts +5 -2
- package/src/commands/ps.ts +28 -6
- package/src/commands/sh.ts +33 -11
- package/src/commands/source.ts +35 -0
- package/src/commands/test.ts +100 -0
- package/src/commands/type.ts +40 -0
- package/src/commands/uptime.ts +46 -0
- package/src/commands/wget.ts +70 -123
- package/src/commands/which.ts +34 -0
- package/src/index.ts +10 -0
- package/src/modules/linuxRootfs.ts +439 -0
- package/src/modules/neofetch.ts +1 -0
- package/src/standalone.ts +4 -1
- package/standalone.js +418 -103
- package/standalone.js.map +4 -4
- package/tests/new-features.test.ts +626 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ifFlag } from "./command-helpers";
|
|
2
|
+
export const aliasCommand = {
|
|
3
|
+
name: "alias",
|
|
4
|
+
description: "Define or display aliases",
|
|
5
|
+
category: "shell",
|
|
6
|
+
params: ["[name[=value] ...]"],
|
|
7
|
+
run: ({ args, env }) => {
|
|
8
|
+
if (!env)
|
|
9
|
+
return { exitCode: 0 };
|
|
10
|
+
// Aliases stored in env.vars under prefix __alias_
|
|
11
|
+
if (args.length === 0) {
|
|
12
|
+
const aliases = Object.entries(env.vars)
|
|
13
|
+
.filter(([k]) => k.startsWith("__alias_"))
|
|
14
|
+
.map(([k, v]) => `alias ${k.slice("__alias_".length)}='${v}'`);
|
|
15
|
+
return { stdout: aliases.join("\n") || "", exitCode: 0 };
|
|
16
|
+
}
|
|
17
|
+
const lines = [];
|
|
18
|
+
for (const arg of args) {
|
|
19
|
+
const eq = arg.indexOf("=");
|
|
20
|
+
if (eq === -1) {
|
|
21
|
+
// Display single alias
|
|
22
|
+
const val = env.vars[`__alias_${arg}`];
|
|
23
|
+
if (val)
|
|
24
|
+
lines.push(`alias ${arg}='${val}'`);
|
|
25
|
+
else
|
|
26
|
+
return { stderr: `alias: ${arg}: not found`, exitCode: 1 };
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
// Set alias
|
|
30
|
+
const name = arg.slice(0, eq);
|
|
31
|
+
const val = arg.slice(eq + 1).replace(/^['"]|['"]$/g, "");
|
|
32
|
+
env.vars[`__alias_${name}`] = val;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return { stdout: lines.join("\n") || undefined, exitCode: 0 };
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
export const unaliasCommand = {
|
|
39
|
+
name: "unalias",
|
|
40
|
+
description: "Remove alias definitions",
|
|
41
|
+
category: "shell",
|
|
42
|
+
params: ["<name...> | -a"],
|
|
43
|
+
run: ({ args, env }) => {
|
|
44
|
+
if (!env)
|
|
45
|
+
return { exitCode: 0 };
|
|
46
|
+
if (ifFlag(args, ["-a"])) {
|
|
47
|
+
for (const k of Object.keys(env.vars)) {
|
|
48
|
+
if (k.startsWith("__alias_"))
|
|
49
|
+
delete env.vars[k];
|
|
50
|
+
}
|
|
51
|
+
return { exitCode: 0 };
|
|
52
|
+
}
|
|
53
|
+
for (const name of args) {
|
|
54
|
+
delete env.vars[`__alias_${name}`];
|
|
55
|
+
}
|
|
56
|
+
return { exitCode: 0 };
|
|
57
|
+
},
|
|
58
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apt.d.ts","sourceRoot":"","sources":["../../src/commands/apt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,UAAU,EAAE,WA2IxB,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,WAoD7B,CAAC"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { ifFlag, } from "./command-helpers";
|
|
2
|
+
import { getPackageManager } from "./helpers";
|
|
3
|
+
export const aptCommand = {
|
|
4
|
+
name: "apt",
|
|
5
|
+
aliases: ["apt-get"],
|
|
6
|
+
description: "Package manager",
|
|
7
|
+
category: "system",
|
|
8
|
+
params: ["<install|remove|update|upgrade|search|show|list> [pkg...]"],
|
|
9
|
+
run: ({ args, shell, authUser }) => {
|
|
10
|
+
const pm = getPackageManager(shell);
|
|
11
|
+
if (!pm)
|
|
12
|
+
return { stderr: "apt: package manager not initialised", exitCode: 1 };
|
|
13
|
+
const sub = args[0]?.toLowerCase();
|
|
14
|
+
const rest = args.slice(1);
|
|
15
|
+
const quiet = ifFlag(rest, ["-q", "--quiet", "-qq"]);
|
|
16
|
+
const purge = ifFlag(rest, ["--purge"]);
|
|
17
|
+
const pkgs = rest.filter((a) => !a.startsWith("-"));
|
|
18
|
+
// Non-root check
|
|
19
|
+
const restricted = ["install", "remove", "purge", "upgrade", "update"];
|
|
20
|
+
if (restricted.includes(sub ?? "") && authUser !== "root") {
|
|
21
|
+
return {
|
|
22
|
+
stderr: "E: Could not open lock file /var/lib/dpkg/lock-frontend - open (13: Permission denied)\nE: Unable to acquire the dpkg frontend lock, are you root?",
|
|
23
|
+
exitCode: 100,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
switch (sub) {
|
|
27
|
+
case "install": {
|
|
28
|
+
if (pkgs.length === 0)
|
|
29
|
+
return { stderr: "apt: no packages specified", exitCode: 1 };
|
|
30
|
+
const { output, exitCode } = pm.install(pkgs, { quiet });
|
|
31
|
+
return { stdout: output || undefined, exitCode };
|
|
32
|
+
}
|
|
33
|
+
case "remove":
|
|
34
|
+
case "purge": {
|
|
35
|
+
if (pkgs.length === 0)
|
|
36
|
+
return { stderr: "apt: no packages specified", exitCode: 1 };
|
|
37
|
+
const { output, exitCode } = pm.remove(pkgs, {
|
|
38
|
+
purge: sub === "purge" || purge,
|
|
39
|
+
quiet,
|
|
40
|
+
});
|
|
41
|
+
return { stdout: output || undefined, exitCode };
|
|
42
|
+
}
|
|
43
|
+
case "update": {
|
|
44
|
+
return {
|
|
45
|
+
stdout: [
|
|
46
|
+
"Hit:1 fortune://packages.fortune.local aurora InRelease",
|
|
47
|
+
"Hit:2 fortune://security.fortune.local aurora-security InRelease",
|
|
48
|
+
"Reading package lists... Done",
|
|
49
|
+
"Building dependency tree... Done",
|
|
50
|
+
"Reading state information... Done",
|
|
51
|
+
`All packages are up to date.`,
|
|
52
|
+
].join("\n"),
|
|
53
|
+
exitCode: 0,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
case "upgrade": {
|
|
57
|
+
return {
|
|
58
|
+
stdout: [
|
|
59
|
+
"Reading package lists... Done",
|
|
60
|
+
"Building dependency tree... Done",
|
|
61
|
+
"Reading state information... Done",
|
|
62
|
+
"Calculating upgrade... Done",
|
|
63
|
+
"0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.",
|
|
64
|
+
].join("\n"),
|
|
65
|
+
exitCode: 0,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
case "search": {
|
|
69
|
+
const term = pkgs[0];
|
|
70
|
+
if (!term)
|
|
71
|
+
return { stderr: "apt: search requires a term", exitCode: 1 };
|
|
72
|
+
const results = pm.search(term);
|
|
73
|
+
if (results.length === 0)
|
|
74
|
+
return {
|
|
75
|
+
stdout: `Sorting... Done\nFull Text Search... Done\n(no results)`,
|
|
76
|
+
exitCode: 0,
|
|
77
|
+
};
|
|
78
|
+
const lines = results.map((p) => `${p.name}/${p.section ?? "misc"} ${p.version} amd64\n ${p.shortDesc ?? p.description}`);
|
|
79
|
+
return {
|
|
80
|
+
stdout: `Sorting... Done\nFull Text Search... Done\n${lines.join("\n")}`,
|
|
81
|
+
exitCode: 0,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
case "show": {
|
|
85
|
+
const name = pkgs[0];
|
|
86
|
+
if (!name)
|
|
87
|
+
return { stderr: "apt: show requires a package name", exitCode: 1 };
|
|
88
|
+
const info = pm.show(name);
|
|
89
|
+
if (!info)
|
|
90
|
+
return { stderr: `N: Unable to locate package ${name}`, exitCode: 100 };
|
|
91
|
+
return { stdout: info, exitCode: 0 };
|
|
92
|
+
}
|
|
93
|
+
case "list": {
|
|
94
|
+
const installedFlag = ifFlag(rest, ["--installed"]);
|
|
95
|
+
if (installedFlag) {
|
|
96
|
+
const pkgList = pm.listInstalled();
|
|
97
|
+
if (pkgList.length === 0)
|
|
98
|
+
return { stdout: "Listing... Done\n(no packages installed)", exitCode: 0 };
|
|
99
|
+
const lines = pkgList.map((p) => `${p.name}/${p.section} ${p.version} ${p.architecture} [installed]`);
|
|
100
|
+
return { stdout: `Listing... Done\n${lines.join("\n")}`, exitCode: 0 };
|
|
101
|
+
}
|
|
102
|
+
// all available
|
|
103
|
+
const all = pm.listAvailable();
|
|
104
|
+
const lines = all.map((p) => `${p.name}/${p.section ?? "misc"} ${p.version} amd64`);
|
|
105
|
+
return { stdout: `Listing... Done\n${lines.join("\n")}`, exitCode: 0 };
|
|
106
|
+
}
|
|
107
|
+
default: {
|
|
108
|
+
return {
|
|
109
|
+
stdout: [
|
|
110
|
+
"Usage: apt [options] command",
|
|
111
|
+
"",
|
|
112
|
+
"Commands:",
|
|
113
|
+
" install <pkg...> Install packages",
|
|
114
|
+
" remove <pkg...> Remove packages",
|
|
115
|
+
" purge <pkg...> Remove packages and config files",
|
|
116
|
+
" update Refresh package index",
|
|
117
|
+
" upgrade Upgrade all packages",
|
|
118
|
+
" search <term> Search in package descriptions",
|
|
119
|
+
" show <pkg> Show package details",
|
|
120
|
+
" list [--installed] List packages",
|
|
121
|
+
].join("\n"),
|
|
122
|
+
exitCode: 0,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
export const aptCacheCommand = {
|
|
129
|
+
name: "apt-cache",
|
|
130
|
+
description: "Query the package cache",
|
|
131
|
+
category: "system",
|
|
132
|
+
params: ["<search|show|policy> [pkg]"],
|
|
133
|
+
run: ({ args, shell }) => {
|
|
134
|
+
const pm = getPackageManager(shell);
|
|
135
|
+
if (!pm)
|
|
136
|
+
return { stderr: "apt-cache: package manager not initialised", exitCode: 1 };
|
|
137
|
+
const sub = args[0]?.toLowerCase();
|
|
138
|
+
const pkgName = args[1];
|
|
139
|
+
switch (sub) {
|
|
140
|
+
case "search": {
|
|
141
|
+
if (!pkgName)
|
|
142
|
+
return { stderr: "Need a search term", exitCode: 1 };
|
|
143
|
+
const results = pm.search(pkgName);
|
|
144
|
+
return {
|
|
145
|
+
stdout: results
|
|
146
|
+
.map((p) => `${p.name} - ${p.shortDesc ?? p.description}`)
|
|
147
|
+
.join("\n") || "(no results)",
|
|
148
|
+
exitCode: 0,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
case "show": {
|
|
152
|
+
if (!pkgName)
|
|
153
|
+
return { stderr: "Need a package name", exitCode: 1 };
|
|
154
|
+
const info = pm.show(pkgName);
|
|
155
|
+
return info
|
|
156
|
+
? { stdout: info, exitCode: 0 }
|
|
157
|
+
: { stderr: `N: Unable to locate package ${pkgName}`, exitCode: 100 };
|
|
158
|
+
}
|
|
159
|
+
case "policy": {
|
|
160
|
+
if (!pkgName)
|
|
161
|
+
return { stderr: "Need a package name", exitCode: 1 };
|
|
162
|
+
const def = pm.findInRegistry(pkgName);
|
|
163
|
+
if (!def)
|
|
164
|
+
return { stderr: `N: Unable to locate package ${pkgName}`, exitCode: 100 };
|
|
165
|
+
const inst = pm.isInstalled(pkgName);
|
|
166
|
+
return {
|
|
167
|
+
stdout: [
|
|
168
|
+
`${pkgName}:`,
|
|
169
|
+
` Installed: ${inst ? def.version : "(none)"}`,
|
|
170
|
+
` Candidate: ${def.version}`,
|
|
171
|
+
` Version table:`,
|
|
172
|
+
` ${def.version} 500`,
|
|
173
|
+
` 500 fortune://packages.fortune.local aurora/main amd64 Packages`,
|
|
174
|
+
].join("\n"),
|
|
175
|
+
exitCode: 0,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
default:
|
|
179
|
+
return { stderr: `apt-cache: unknown command '${sub ?? ""}'`, exitCode: 1 };
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cat.d.ts","sourceRoot":"","sources":["../../src/commands/cat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"cat.d.ts","sourceRoot":"","sources":["../../src/commands/cat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,UAAU,EAAE,WAuCxB,CAAC"}
|
package/dist/commands/cat.js
CHANGED
|
@@ -1,17 +1,36 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ifFlag } from "./command-helpers";
|
|
2
2
|
import { assertPathAccess, resolveReadablePath } from "./helpers";
|
|
3
3
|
export const catCommand = {
|
|
4
4
|
name: "cat",
|
|
5
5
|
description: "Concatenate and print files",
|
|
6
6
|
category: "files",
|
|
7
|
-
params: ["<file
|
|
8
|
-
run: ({ authUser, shell, cwd, args }) => {
|
|
9
|
-
const
|
|
10
|
-
|
|
7
|
+
params: ["[-n] [-b] <file...>"],
|
|
8
|
+
run: ({ authUser, shell, cwd, args, stdin }) => {
|
|
9
|
+
const numberAll = ifFlag(args, ["-n", "--number"]);
|
|
10
|
+
const numberNonBlank = ifFlag(args, ["-b", "--number-nonblank"]);
|
|
11
|
+
const fileArgs = args.filter((a) => !a.startsWith("-"));
|
|
12
|
+
if (fileArgs.length === 0 && stdin !== undefined) {
|
|
13
|
+
return { stdout: stdin, exitCode: 0 };
|
|
14
|
+
}
|
|
15
|
+
if (fileArgs.length === 0) {
|
|
11
16
|
return { stderr: "cat: missing file operand", exitCode: 1 };
|
|
12
17
|
}
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
18
|
+
const parts = [];
|
|
19
|
+
for (const fileArg of fileArgs) {
|
|
20
|
+
const target = resolveReadablePath(shell.vfs, cwd, fileArg);
|
|
21
|
+
assertPathAccess(authUser, target, "cat");
|
|
22
|
+
parts.push(shell.vfs.readFile(target));
|
|
23
|
+
}
|
|
24
|
+
const combined = parts.join("");
|
|
25
|
+
if (!numberAll && !numberNonBlank) {
|
|
26
|
+
return { stdout: combined, exitCode: 0 };
|
|
27
|
+
}
|
|
28
|
+
let lineNum = 1;
|
|
29
|
+
const numbered = combined.split("\n").map((line) => {
|
|
30
|
+
if (numberNonBlank && line.trim() === "")
|
|
31
|
+
return line;
|
|
32
|
+
return `${String(lineNum++).padStart(6)}\t${line}`;
|
|
33
|
+
}).join("\n");
|
|
34
|
+
return { stdout: numbered, exitCode: 0 };
|
|
16
35
|
},
|
|
17
36
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chmod.d.ts","sourceRoot":"","sources":["../../src/commands/chmod.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"chmod.d.ts","sourceRoot":"","sources":["../../src/commands/chmod.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAuCrD,eAAO,MAAM,YAAY,EAAE,WAwC1B,CAAC"}
|
package/dist/commands/chmod.js
CHANGED
|
@@ -1,4 +1,43 @@
|
|
|
1
1
|
import { assertPathAccess, resolvePath } from "./helpers";
|
|
2
|
+
/**
|
|
3
|
+
* Parse a symbolic chmod mode string (e.g. "+x", "u+x", "go-w", "a+rx")
|
|
4
|
+
* and apply it to the existing mode bits.
|
|
5
|
+
* Returns null if the string is not a valid symbolic mode.
|
|
6
|
+
*/
|
|
7
|
+
function applySymbolicMode(existing, modeStr) {
|
|
8
|
+
const pattern = /^([ugoa]*)([+\-=])([rwx]*)$/;
|
|
9
|
+
const parts = modeStr.split(",");
|
|
10
|
+
let mode = existing;
|
|
11
|
+
for (const part of parts) {
|
|
12
|
+
const m = part.trim().match(pattern);
|
|
13
|
+
if (!m)
|
|
14
|
+
return null;
|
|
15
|
+
const [, who = "a", op, perms = ""] = m;
|
|
16
|
+
const targets = who === "" || who === "a" ? ["u", "g", "o"] : who.split("");
|
|
17
|
+
const bits = {
|
|
18
|
+
u: { r: 0o400, w: 0o200, x: 0o100 },
|
|
19
|
+
g: { r: 0o040, w: 0o020, x: 0o010 },
|
|
20
|
+
o: { r: 0o004, w: 0o002, x: 0o001 },
|
|
21
|
+
};
|
|
22
|
+
for (const t of targets) {
|
|
23
|
+
for (const p of perms.split("")) {
|
|
24
|
+
const bit = bits[t]?.[p];
|
|
25
|
+
if (bit === undefined)
|
|
26
|
+
continue;
|
|
27
|
+
if (op === "+")
|
|
28
|
+
mode |= bit;
|
|
29
|
+
else if (op === "-")
|
|
30
|
+
mode &= ~bit;
|
|
31
|
+
else if (op === "=") {
|
|
32
|
+
// clear all bits for this target, then set requested
|
|
33
|
+
const mask = Object.values(bits[t] ?? {}).reduce((a, b) => a | b, 0);
|
|
34
|
+
mode = (mode & ~mask) | bit;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return mode;
|
|
40
|
+
}
|
|
2
41
|
export const chmodCommand = {
|
|
3
42
|
name: "chmod",
|
|
4
43
|
description: "Change file permissions",
|
|
@@ -18,9 +57,19 @@ export const chmodCommand = {
|
|
|
18
57
|
exitCode: 1,
|
|
19
58
|
};
|
|
20
59
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
60
|
+
let mode;
|
|
61
|
+
const octal = parseInt(modeArg, 8);
|
|
62
|
+
if (!Number.isNaN(octal) && /^[0-7]+$/.test(modeArg)) {
|
|
63
|
+
mode = octal;
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
// symbolic mode
|
|
67
|
+
const existing = shell.vfs.stat(filePath).mode;
|
|
68
|
+
const result = applySymbolicMode(existing, modeArg);
|
|
69
|
+
if (result === null) {
|
|
70
|
+
return { stderr: `chmod: invalid mode: ${modeArg}`, exitCode: 1 };
|
|
71
|
+
}
|
|
72
|
+
mode = result;
|
|
24
73
|
}
|
|
25
74
|
shell.vfs.chmod(filePath, mode);
|
|
26
75
|
return { exitCode: 0 };
|
|
@@ -2,14 +2,88 @@ type ArgParseOptions = {
|
|
|
2
2
|
flags?: string[];
|
|
3
3
|
flagsWithValue?: string[];
|
|
4
4
|
};
|
|
5
|
+
/**
|
|
6
|
+
* Returns `true` when any of the given flags appear in `args`.
|
|
7
|
+
*
|
|
8
|
+
* Matches both standalone tokens (`-s`, `--silent`) and inline forms
|
|
9
|
+
* (`--output=file`). Useful for simple boolean flag checks inside command
|
|
10
|
+
* `run` handlers.
|
|
11
|
+
*
|
|
12
|
+
* @param args Tokenized argument array from `CommandContext.args`.
|
|
13
|
+
* @param flags Single flag string or array of equivalent flag strings.
|
|
14
|
+
* @returns `true` if at least one flag is present, otherwise `false`.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* ifFlag(args, "-r") // single flag
|
|
19
|
+
* ifFlag(args, ["-r", "--recursive"]) // aliases
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
5
22
|
export declare function ifFlag(args: string[], flags: string | string[]): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Returns the value associated with a flag, or `true` if the flag is present
|
|
25
|
+
* but has no associated value, or `undefined` if the flag is absent.
|
|
26
|
+
*
|
|
27
|
+
* Handles three forms:
|
|
28
|
+
* - `--output file` → returns `"file"` (next token)
|
|
29
|
+
* - `--output=file` → returns `"file"` (inline `=` form)
|
|
30
|
+
* - `--verbose` → returns `true` (flag with no value)
|
|
31
|
+
*
|
|
32
|
+
* @param args Tokenized argument array from `CommandContext.args`.
|
|
33
|
+
* @param flags Single flag string or array of equivalent flag strings.
|
|
34
|
+
* @returns The flag value string, `true` when valueless, or `undefined`.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* const output = getFlag(args, ["-o", "--output"]);
|
|
39
|
+
* if (typeof output === "string") { /* use path *\/ }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
6
42
|
export declare function getFlag(args: string[], flags: string | string[]): string | true | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Returns the positional argument at the given zero-based index, skipping
|
|
45
|
+
* known flags and their values.
|
|
46
|
+
*
|
|
47
|
+
* Flags declared in `options.flags` are treated as boolean and skipped.
|
|
48
|
+
* Flags declared in `options.flagsWithValue` consume the next token too.
|
|
49
|
+
* Tokens after `--` are always treated as positionals.
|
|
50
|
+
*
|
|
51
|
+
* @param args Tokenized argument array from `CommandContext.args`.
|
|
52
|
+
* @param index Zero-based positional index to retrieve.
|
|
53
|
+
* @param options Optional flag declarations to skip during positional collection.
|
|
54
|
+
* @returns The positional value, or `undefined` if the index is out of range.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* // args = ["-r", "src", "dest"]
|
|
59
|
+
* getArg(args, 0, { flags: ["-r"] }) // "src"
|
|
60
|
+
* getArg(args, 1, { flags: ["-r"] }) // "dest"
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
7
63
|
export declare function getArg(args: string[], index: number, options?: ArgParseOptions): string | undefined;
|
|
8
64
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
65
|
+
* Parses an argument array into structured flags, flag values, and positionals.
|
|
66
|
+
*
|
|
67
|
+
* - `options.flags` — boolean flags (e.g. `["-r", "--recursive"]`); collected
|
|
68
|
+
* into a `Set<string>` and not treated as positionals.
|
|
69
|
+
* - `options.flagsWithValue` — flags that consume the next token or an inline
|
|
70
|
+
* `=value`; collected into a `Map<string, string>`.
|
|
71
|
+
* - All remaining tokens are positionals.
|
|
72
|
+
* - Tokens after `--` are always positionals, regardless of `-` prefix.
|
|
73
|
+
*
|
|
74
|
+
* @param args Tokenized argument array from `CommandContext.args`.
|
|
75
|
+
* @param options Flag declaration lists.
|
|
76
|
+
* @returns `{ flags, flagsWithValues, positionals }`.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* const { flags, flagsWithValues, positionals } = parseArgs(args, {
|
|
81
|
+
* flags: ["-r", "--recursive"],
|
|
82
|
+
* flagsWithValue: ["-o", "--output"],
|
|
83
|
+
* });
|
|
84
|
+
* const recursive = flags.has("-r");
|
|
85
|
+
* const output = flagsWithValues.get("-o");
|
|
86
|
+
* ```
|
|
13
87
|
*/
|
|
14
88
|
export declare function parseArgs(args: string[], options?: {
|
|
15
89
|
flags?: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-helpers.d.ts","sourceRoot":"","sources":["../../src/commands/command-helpers.ts"],"names":[],"mappings":"AAAA,KAAK,eAAe,GAAG;IACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B,CAAC;AA+EF,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAYxE;AAED,wBAAgB,OAAO,CACtB,IAAI,EAAE,MAAM,EAAE,EACd,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GACtB,MAAM,GAAG,IAAI,GAAG,SAAS,CA0B3B;AAED,wBAAgB,MAAM,CACrB,IAAI,EAAE,MAAM,EAAE,EACd,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,eAAoB,GAC3B,MAAM,GAAG,SAAS,CAGpB;AAED
|
|
1
|
+
{"version":3,"file":"command-helpers.d.ts","sourceRoot":"","sources":["../../src/commands/command-helpers.ts"],"names":[],"mappings":"AAAA,KAAK,eAAe,GAAG;IACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B,CAAC;AA+EF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAYxE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,OAAO,CACtB,IAAI,EAAE,MAAM,EAAE,EACd,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GACtB,MAAM,GAAG,IAAI,GAAG,SAAS,CA0B3B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,MAAM,CACrB,IAAI,EAAE,MAAM,EAAE,EACd,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,eAAoB,GAC3B,MAAM,GAAG,SAAS,CAGpB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,SAAS,CACxB,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;CAAO,GAC3D;IACF,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACnB,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,WAAW,EAAE,MAAM,EAAE,CAAC;CACtB,CAiDA"}
|
|
@@ -54,6 +54,23 @@ function collectPositionals(args, options = {}) {
|
|
|
54
54
|
}
|
|
55
55
|
return positionals;
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Returns `true` when any of the given flags appear in `args`.
|
|
59
|
+
*
|
|
60
|
+
* Matches both standalone tokens (`-s`, `--silent`) and inline forms
|
|
61
|
+
* (`--output=file`). Useful for simple boolean flag checks inside command
|
|
62
|
+
* `run` handlers.
|
|
63
|
+
*
|
|
64
|
+
* @param args Tokenized argument array from `CommandContext.args`.
|
|
65
|
+
* @param flags Single flag string or array of equivalent flag strings.
|
|
66
|
+
* @returns `true` if at least one flag is present, otherwise `false`.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* ifFlag(args, "-r") // single flag
|
|
71
|
+
* ifFlag(args, ["-r", "--recursive"]) // aliases
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
57
74
|
export function ifFlag(args, flags) {
|
|
58
75
|
const allFlags = toFlagList(flags);
|
|
59
76
|
for (const arg of args) {
|
|
@@ -65,6 +82,25 @@ export function ifFlag(args, flags) {
|
|
|
65
82
|
}
|
|
66
83
|
return false;
|
|
67
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Returns the value associated with a flag, or `true` if the flag is present
|
|
87
|
+
* but has no associated value, or `undefined` if the flag is absent.
|
|
88
|
+
*
|
|
89
|
+
* Handles three forms:
|
|
90
|
+
* - `--output file` → returns `"file"` (next token)
|
|
91
|
+
* - `--output=file` → returns `"file"` (inline `=` form)
|
|
92
|
+
* - `--verbose` → returns `true` (flag with no value)
|
|
93
|
+
*
|
|
94
|
+
* @param args Tokenized argument array from `CommandContext.args`.
|
|
95
|
+
* @param flags Single flag string or array of equivalent flag strings.
|
|
96
|
+
* @returns The flag value string, `true` when valueless, or `undefined`.
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```ts
|
|
100
|
+
* const output = getFlag(args, ["-o", "--output"]);
|
|
101
|
+
* if (typeof output === "string") { /* use path *\/ }
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
68
104
|
export function getFlag(args, flags) {
|
|
69
105
|
const allFlags = toFlagList(flags);
|
|
70
106
|
for (let index = 0; index < args.length; index += 1) {
|
|
@@ -86,15 +122,53 @@ export function getFlag(args, flags) {
|
|
|
86
122
|
}
|
|
87
123
|
return undefined;
|
|
88
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* Returns the positional argument at the given zero-based index, skipping
|
|
127
|
+
* known flags and their values.
|
|
128
|
+
*
|
|
129
|
+
* Flags declared in `options.flags` are treated as boolean and skipped.
|
|
130
|
+
* Flags declared in `options.flagsWithValue` consume the next token too.
|
|
131
|
+
* Tokens after `--` are always treated as positionals.
|
|
132
|
+
*
|
|
133
|
+
* @param args Tokenized argument array from `CommandContext.args`.
|
|
134
|
+
* @param index Zero-based positional index to retrieve.
|
|
135
|
+
* @param options Optional flag declarations to skip during positional collection.
|
|
136
|
+
* @returns The positional value, or `undefined` if the index is out of range.
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```ts
|
|
140
|
+
* // args = ["-r", "src", "dest"]
|
|
141
|
+
* getArg(args, 0, { flags: ["-r"] }) // "src"
|
|
142
|
+
* getArg(args, 1, { flags: ["-r"] }) // "dest"
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
89
145
|
export function getArg(args, index, options = {}) {
|
|
90
146
|
const positionals = collectPositionals(args, options);
|
|
91
147
|
return positionals[index];
|
|
92
148
|
}
|
|
93
149
|
/**
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
150
|
+
* Parses an argument array into structured flags, flag values, and positionals.
|
|
151
|
+
*
|
|
152
|
+
* - `options.flags` — boolean flags (e.g. `["-r", "--recursive"]`); collected
|
|
153
|
+
* into a `Set<string>` and not treated as positionals.
|
|
154
|
+
* - `options.flagsWithValue` — flags that consume the next token or an inline
|
|
155
|
+
* `=value`; collected into a `Map<string, string>`.
|
|
156
|
+
* - All remaining tokens are positionals.
|
|
157
|
+
* - Tokens after `--` are always positionals, regardless of `-` prefix.
|
|
158
|
+
*
|
|
159
|
+
* @param args Tokenized argument array from `CommandContext.args`.
|
|
160
|
+
* @param options Flag declaration lists.
|
|
161
|
+
* @returns `{ flags, flagsWithValues, positionals }`.
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```ts
|
|
165
|
+
* const { flags, flagsWithValues, positionals } = parseArgs(args, {
|
|
166
|
+
* flags: ["-r", "--recursive"],
|
|
167
|
+
* flagsWithValue: ["-o", "--output"],
|
|
168
|
+
* });
|
|
169
|
+
* const recursive = flags.has("-r");
|
|
170
|
+
* const output = flagsWithValues.get("-o");
|
|
171
|
+
* ```
|
|
98
172
|
*/
|
|
99
173
|
export function parseArgs(args, options = {}) {
|
|
100
174
|
const flags = new Set();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"curl.d.ts","sourceRoot":"","sources":["../../src/commands/curl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"curl.d.ts","sourceRoot":"","sources":["../../src/commands/curl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,WAAW,EAAE,WAiGzB,CAAC"}
|