typescript-virtual-container 1.5.3 → 1.5.4
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 +43 -23
- package/dist/.tsbuildinfo +1 -0
- package/dist/SSHMimic/executor.js +23 -5
- package/dist/VirtualPackageManager/index.js +10 -0
- package/dist/commands/basename.d.ts +13 -0
- package/dist/commands/basename.js +45 -0
- package/dist/commands/file.d.ts +8 -0
- package/dist/commands/file.js +57 -0
- package/dist/commands/fun.d.ts +32 -0
- package/dist/commands/fun.js +172 -0
- package/dist/commands/ifconfig.d.ts +7 -0
- package/dist/commands/ifconfig.js +52 -0
- package/dist/commands/last.d.ts +13 -0
- package/dist/commands/last.js +68 -0
- package/dist/commands/manuals-bundle.js +598 -6
- package/dist/commands/registry.js +24 -2
- package/dist/commands/runtime.js +22 -2
- package/dist/commands/sh.js +5 -0
- package/dist/commands/tput.d.ts +13 -0
- package/dist/commands/tput.js +76 -0
- package/dist/commands/w.d.ts +7 -0
- package/dist/commands/w.js +38 -0
- package/dist/utils/expand.d.ts +12 -0
- package/dist/utils/expand.js +84 -0
- package/package.json +9 -3
- package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -50
- package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -31
- package/.github/dependabot.yml +0 -27
- package/.github/pull_request_template.md +0 -21
- package/.github/workflows/create-pull-request.yml +0 -85
- package/.github/workflows/publish.yml +0 -25
- package/.github/workflows/test-battery.yml +0 -102
- package/.vscode/settings.json +0 -20
- package/CODE_OF_CONDUCT.md +0 -39
- package/CONTRIBUTING.md +0 -59
- package/HONEYPOT.md +0 -358
- package/SECURITY.md +0 -33
- package/benchmark-results.txt +0 -40
- package/benchmark-virtualshell.ts +0 -88
- package/biome.json +0 -37
- package/build.js +0 -22
- package/builds/fortune-nyx-v1.5.3-directbash-k6.1.0.mjs +0 -1764
- package/builds/fortune-nyx-v1.5.3-ssh-nosftp.js +0 -1764
- package/builds/fortune-nyx-v1.5.3-ssh.cjs +0 -1765
- package/builds/fortune-nyx-v1.5.3-web.min.js +0 -17036
- package/bun.lock +0 -244
- package/docs/.nojekyll +0 -1
- package/docs/app.js +0 -1751
- package/docs/assets/hierarchy.js +0 -1
- package/docs/assets/highlight.css +0 -162
- package/docs/assets/icons.js +0 -18
- package/docs/assets/icons.svg +0 -1
- package/docs/assets/main.js +0 -60
- package/docs/assets/navigation.js +0 -1
- package/docs/assets/search.js +0 -1
- package/docs/assets/style.css +0 -1633
- package/docs/classes/HoneyPot.html +0 -31
- package/docs/classes/IdleManager.html +0 -162
- package/docs/classes/SshClient.html +0 -66
- package/docs/classes/VirtualFileSystem.html +0 -279
- package/docs/classes/VirtualPackageManager.html +0 -63
- package/docs/classes/VirtualSftpServer.html +0 -169
- package/docs/classes/VirtualShell.html +0 -285
- package/docs/classes/VirtualSshServer.html +0 -182
- package/docs/classes/VirtualUserManager.html +0 -276
- package/docs/demo.html +0 -82
- package/docs/functions/assertDiff.html +0 -6
- package/docs/functions/diffSnapshots.html +0 -7
- package/docs/functions/formatDiff.html +0 -6
- package/docs/functions/getArg.html +0 -13
- package/docs/functions/getFlag.html +0 -15
- package/docs/functions/ifFlag.html +0 -11
- package/docs/hierarchy.html +0 -1
- package/docs/index.html +0 -1869
- package/docs/interfaces/AuditLogEntry.html +0 -6
- package/docs/interfaces/CommandContext.html +0 -22
- package/docs/interfaces/CommandResult.html +0 -26
- package/docs/interfaces/ExecStream.html +0 -11
- package/docs/interfaces/HoneyPotStats.html +0 -16
- package/docs/interfaces/IdleManagerOptions.html +0 -7
- package/docs/interfaces/InstalledPackage.html +0 -20
- package/docs/interfaces/NanoEditorSession.html +0 -8
- package/docs/interfaces/PackageDefinition.html +0 -30
- package/docs/interfaces/PackageFile.html +0 -8
- package/docs/interfaces/PasswordChallenge.html +0 -16
- package/docs/interfaces/RemoveOptions.html +0 -4
- package/docs/interfaces/ShellEnv.html +0 -6
- package/docs/interfaces/ShellModule.html +0 -14
- package/docs/interfaces/ShellProperties.html +0 -14
- package/docs/interfaces/ShellStream.html +0 -11
- package/docs/interfaces/SudoChallenge.html +0 -24
- package/docs/interfaces/VfsBaseNode.html +0 -12
- package/docs/interfaces/VfsDiff.html +0 -10
- package/docs/interfaces/VfsDiffEntry.html +0 -6
- package/docs/interfaces/VfsDiffModified.html +0 -10
- package/docs/interfaces/VfsDirectoryNode.html +0 -15
- package/docs/interfaces/VfsFileNode.html +0 -17
- package/docs/interfaces/VfsOptions.html +0 -26
- package/docs/interfaces/VfsSnapshot.html +0 -3
- package/docs/interfaces/VfsSnapshotBaseNode.html +0 -8
- package/docs/interfaces/VfsSnapshotDirectoryNode.html +0 -10
- package/docs/interfaces/VfsSnapshotFileNode.html +0 -12
- package/docs/interfaces/VirtualActiveSession.html +0 -12
- package/docs/interfaces/VirtualSftpServerOptions.html +0 -7
- package/docs/interfaces/VirtualShellVfsLike.html +0 -15
- package/docs/interfaces/VirtualShellVfsOptions.html +0 -3
- package/docs/interfaces/WriteFileOptions.html +0 -6
- package/docs/media/LICENSE +0 -21
- package/docs/modules.html +0 -1
- package/docs/types/ArgParseOptions.html +0 -4
- package/docs/types/CommandMode.html +0 -2
- package/docs/types/CommandOutcome.html +0 -2
- package/docs/types/IdleState.html +0 -1
- package/docs/types/VfsNodeStats.html +0 -2
- package/docs/types/VfsNodeType.html +0 -2
- package/docs/types/VfsPersistenceMode.html +0 -5
- package/docs/types/VfsSnapshotNode.html +0 -2
- package/examples/README.md +0 -288
- package/examples/app.js +0 -1751
- package/examples/app.ts +0 -299
- package/examples/build.js +0 -27
- package/examples/demo.html +0 -33
- package/examples/honeypot-audit.ts +0 -180
- package/examples/honeypot-export.ts +0 -253
- package/examples/honeypot-quickstart.ts +0 -110
- package/examples/index.html +0 -82
- package/examples/server.js +0 -55
- package/polyfills/buffer.js +0 -117
- package/polyfills/node_child_process/index.js +0 -2
- package/polyfills/node_crypto/index.js +0 -167
- package/polyfills/node_events/index.js +0 -9
- package/polyfills/node_fs/index.js +0 -202
- package/polyfills/node_fs/promises.js +0 -4
- package/polyfills/node_os/index.js +0 -9
- package/polyfills/node_path/index.js +0 -28
- package/polyfills/node_vm/index.js +0 -7
- package/polyfills/node_zlib/index.js +0 -3
- package/polyfills/process.js +0 -14
- package/polyfills/ssh2/index.js +0 -75
- package/scripts/build-all.mjs +0 -226
- package/scripts/build-names.mjs +0 -43
- package/scripts/generate-manuals-bundle.mjs +0 -49
- package/scripts/postinstall.js +0 -42
- package/scripts/publish-package.sh +0 -70
- package/src/Honeypot/index.ts +0 -457
- package/src/SSHClient/index.ts +0 -270
- package/src/SSHMimic/exec.ts +0 -49
- package/src/SSHMimic/executor.ts +0 -251
- package/src/SSHMimic/hostKey.ts +0 -21
- package/src/SSHMimic/index.ts +0 -337
- package/src/SSHMimic/loginBanner.ts +0 -36
- package/src/SSHMimic/loginFormat.ts +0 -10
- package/src/SSHMimic/prompt.ts +0 -14
- package/src/SSHMimic/sftp.ts +0 -883
- package/src/VirtualFileSystem/binaryPack.ts +0 -258
- package/src/VirtualFileSystem/index.ts +0 -1193
- package/src/VirtualFileSystem/internalTypes.ts +0 -43
- package/src/VirtualFileSystem/journal.ts +0 -171
- package/src/VirtualFileSystem/path.ts +0 -74
- package/src/VirtualPackageManager/index.ts +0 -996
- package/src/VirtualShell/idleManager.ts +0 -137
- package/src/VirtualShell/index.ts +0 -475
- package/src/VirtualShell/shell.ts +0 -700
- package/src/VirtualShell/shellParser.ts +0 -285
- package/src/VirtualUserManager/index.ts +0 -758
- package/src/bun.d.ts +0 -1
- package/src/commands/adduser.ts +0 -103
- package/src/commands/alias.ts +0 -69
- package/src/commands/apt.ts +0 -233
- package/src/commands/awk.ts +0 -168
- package/src/commands/base64.ts +0 -29
- package/src/commands/cat.ts +0 -52
- package/src/commands/cd.ts +0 -25
- package/src/commands/chmod.ts +0 -85
- package/src/commands/clear.ts +0 -15
- package/src/commands/command-helpers.ts +0 -286
- package/src/commands/cp.ts +0 -83
- package/src/commands/curl.ts +0 -147
- package/src/commands/cut.ts +0 -36
- package/src/commands/date.ts +0 -30
- package/src/commands/declare.ts +0 -49
- package/src/commands/deluser.ts +0 -98
- package/src/commands/df.ts +0 -23
- package/src/commands/diff.ts +0 -43
- package/src/commands/dpkg.ts +0 -180
- package/src/commands/du.ts +0 -56
- package/src/commands/echo.ts +0 -58
- package/src/commands/env.ts +0 -23
- package/src/commands/exit.ts +0 -18
- package/src/commands/export.ts +0 -34
- package/src/commands/find.ts +0 -68
- package/src/commands/free.ts +0 -47
- package/src/commands/grep.ts +0 -116
- package/src/commands/groups.ts +0 -19
- package/src/commands/gzip.ts +0 -88
- package/src/commands/head.ts +0 -52
- package/src/commands/help.ts +0 -152
- package/src/commands/helpers.ts +0 -234
- package/src/commands/history.ts +0 -34
- package/src/commands/hostname.ts +0 -14
- package/src/commands/htop.ts +0 -20
- package/src/commands/id.ts +0 -19
- package/src/commands/index.ts +0 -9
- package/src/commands/kill.ts +0 -19
- package/src/commands/ln.ts +0 -71
- package/src/commands/ls.ts +0 -243
- package/src/commands/lsb-release.ts +0 -63
- package/src/commands/man.ts +0 -31
- package/src/commands/manuals/adduser.txt +0 -11
- package/src/commands/manuals/apt-cache.txt +0 -12
- package/src/commands/manuals/apt.txt +0 -20
- package/src/commands/manuals/awk.txt +0 -13
- package/src/commands/manuals/cat.txt +0 -14
- package/src/commands/manuals/cd.txt +0 -16
- package/src/commands/manuals/chmod.txt +0 -16
- package/src/commands/manuals/clear.txt +0 -10
- package/src/commands/manuals/cp.txt +0 -10
- package/src/commands/manuals/curl.txt +0 -20
- package/src/commands/manuals/date.txt +0 -14
- package/src/commands/manuals/declare.txt +0 -12
- package/src/commands/manuals/deluser.txt +0 -10
- package/src/commands/manuals/df.txt +0 -10
- package/src/commands/manuals/dpkg-query.txt +0 -11
- package/src/commands/manuals/dpkg.txt +0 -14
- package/src/commands/manuals/du.txt +0 -11
- package/src/commands/manuals/echo.txt +0 -11
- package/src/commands/manuals/false.txt +0 -10
- package/src/commands/manuals/find.txt +0 -11
- package/src/commands/manuals/free.txt +0 -12
- package/src/commands/manuals/grep.txt +0 -13
- package/src/commands/manuals/groups.txt +0 -10
- package/src/commands/manuals/gzip.txt +0 -11
- package/src/commands/manuals/head.txt +0 -10
- package/src/commands/manuals/help.txt +0 -11
- package/src/commands/manuals/history.txt +0 -11
- package/src/commands/manuals/hostname.txt +0 -10
- package/src/commands/manuals/id.txt +0 -10
- package/src/commands/manuals/kill.txt +0 -13
- package/src/commands/manuals/ls.txt +0 -20
- package/src/commands/manuals/lsb_release.txt +0 -14
- package/src/commands/manuals/mkdir.txt +0 -10
- package/src/commands/manuals/mv.txt +0 -10
- package/src/commands/manuals/nano.txt +0 -11
- package/src/commands/manuals/neofetch.txt +0 -10
- package/src/commands/manuals/node.txt +0 -13
- package/src/commands/manuals/npm.txt +0 -13
- package/src/commands/manuals/npx.txt +0 -13
- package/src/commands/manuals/passwd.txt +0 -11
- package/src/commands/manuals/ping.txt +0 -10
- package/src/commands/manuals/printf.txt +0 -11
- package/src/commands/manuals/ps.txt +0 -10
- package/src/commands/manuals/pwd.txt +0 -10
- package/src/commands/manuals/python3.txt +0 -13
- package/src/commands/manuals/readlink.txt +0 -10
- package/src/commands/manuals/return.txt +0 -10
- package/src/commands/manuals/rm.txt +0 -10
- package/src/commands/manuals/sed.txt +0 -11
- package/src/commands/manuals/set.txt +0 -11
- package/src/commands/manuals/shift.txt +0 -10
- package/src/commands/manuals/sleep.txt +0 -10
- package/src/commands/manuals/sort.txt +0 -12
- package/src/commands/manuals/source.txt +0 -11
- package/src/commands/manuals/ssh.txt +0 -11
- package/src/commands/manuals/stat.txt +0 -10
- package/src/commands/manuals/su.txt +0 -13
- package/src/commands/manuals/sudo.txt +0 -11
- package/src/commands/manuals/tail.txt +0 -10
- package/src/commands/manuals/tar.txt +0 -19
- package/src/commands/manuals/tee.txt +0 -10
- package/src/commands/manuals/test.txt +0 -11
- package/src/commands/manuals/touch.txt +0 -11
- package/src/commands/manuals/tr.txt +0 -10
- package/src/commands/manuals/trap.txt +0 -10
- package/src/commands/manuals/true.txt +0 -10
- package/src/commands/manuals/type.txt +0 -10
- package/src/commands/manuals/uname.txt +0 -12
- package/src/commands/manuals/uniq.txt +0 -12
- package/src/commands/manuals/unset.txt +0 -10
- package/src/commands/manuals/uptime.txt +0 -11
- package/src/commands/manuals/wc.txt +0 -12
- package/src/commands/manuals/wget.txt +0 -12
- package/src/commands/manuals/which.txt +0 -10
- package/src/commands/manuals/whoami.txt +0 -10
- package/src/commands/manuals/xargs.txt +0 -10
- package/src/commands/manuals-bundle.ts +0 -898
- package/src/commands/mkdir.ts +0 -31
- package/src/commands/mv.ts +0 -50
- package/src/commands/nano.ts +0 -38
- package/src/commands/neofetch.ts +0 -53
- package/src/commands/node.ts +0 -341
- package/src/commands/npm.ts +0 -132
- package/src/commands/passwd.ts +0 -50
- package/src/commands/ping.ts +0 -32
- package/src/commands/printf.ts +0 -129
- package/src/commands/ps.ts +0 -58
- package/src/commands/pwd.ts +0 -9
- package/src/commands/python.ts +0 -2229
- package/src/commands/read.ts +0 -46
- package/src/commands/registry.ts +0 -249
- package/src/commands/rm.ts +0 -42
- package/src/commands/runtime.ts +0 -421
- package/src/commands/sed.ts +0 -68
- package/src/commands/seq.ts +0 -43
- package/src/commands/set.ts +0 -29
- package/src/commands/sh.ts +0 -467
- package/src/commands/shift.ts +0 -63
- package/src/commands/sleep.ts +0 -20
- package/src/commands/sort.ts +0 -46
- package/src/commands/source.ts +0 -52
- package/src/commands/stat.ts +0 -61
- package/src/commands/su.ts +0 -72
- package/src/commands/sudo.ts +0 -76
- package/src/commands/tail.ts +0 -53
- package/src/commands/tar.ts +0 -102
- package/src/commands/tee.ts +0 -36
- package/src/commands/test.ts +0 -137
- package/src/commands/touch.ts +0 -28
- package/src/commands/tr.ts +0 -70
- package/src/commands/tree.ts +0 -20
- package/src/commands/true.ts +0 -27
- package/src/commands/type.ts +0 -48
- package/src/commands/uname.ts +0 -29
- package/src/commands/uniq.ts +0 -39
- package/src/commands/unset.ts +0 -17
- package/src/commands/uptime.ts +0 -54
- package/src/commands/wc.ts +0 -55
- package/src/commands/wget.ts +0 -148
- package/src/commands/which.ts +0 -37
- package/src/commands/who.ts +0 -25
- package/src/commands/whoami.ts +0 -14
- package/src/commands/xargs.ts +0 -31
- package/src/index.ts +0 -67
- package/src/modules/linuxRootfs.ts +0 -1961
- package/src/modules/neofetch.ts +0 -358
- package/src/modules/shellInteractive.ts +0 -57
- package/src/modules/shellRuntime.ts +0 -76
- package/src/self-standalone.ts +0 -542
- package/src/standalone-wo-sftp.ts +0 -38
- package/src/standalone.ts +0 -72
- package/src/types/commands.ts +0 -146
- package/src/types/pipeline.ts +0 -52
- package/src/types/streams.ts +0 -32
- package/src/types/tar-stream.d.ts +0 -38
- package/src/types/vfs.ts +0 -98
- package/src/utils/expand.ts +0 -491
- package/src/utils/perfLogger.ts +0 -72
- package/src/utils/tokenize.ts +0 -98
- package/src/utils/vfsDiff.ts +0 -275
- package/tests/command-helpers.test.ts +0 -116
- package/tests/commands-admin-net.test.ts +0 -441
- package/tests/commands-advanced.test.ts +0 -456
- package/tests/commands-core.test.ts +0 -562
- package/tests/commands-missing.test.ts +0 -570
- package/tests/commands-specific-units.test.ts +0 -327
- package/tests/commands-text-sys.test.ts +0 -445
- package/tests/expand.test.ts +0 -170
- package/tests/helpers.test.ts +0 -97
- package/tests/new-features.test.ts +0 -1036
- package/tests/parser-executor.test.ts +0 -37
- package/tests/sftp.test.ts +0 -323
- package/tests/ssh-exec.test.ts +0 -45
- package/tests/test-helper.ts +0 -79
- package/tests/users.test.ts +0 -86
- package/tsconfig.json +0 -49
- package/typedoc.json +0 -47
package/src/bun.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/// <reference types="@types/bun" />
|
package/src/commands/adduser.ts
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import type { CommandResult, ShellModule } from "../types/commands";
|
|
2
|
-
import type { VirtualShell } from "../VirtualShell";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Add a new user interactively.
|
|
6
|
-
*
|
|
7
|
-
* Usage: `adduser <username>`
|
|
8
|
-
*
|
|
9
|
-
* Prompts for:
|
|
10
|
-
* New password: ****
|
|
11
|
-
* Retype new password: ****
|
|
12
|
-
*
|
|
13
|
-
* Mirrors the real `adduser` behaviour — password is never passed on the
|
|
14
|
-
* command line. Root-only.
|
|
15
|
-
*/
|
|
16
|
-
export const adduserCommand: ShellModule = {
|
|
17
|
-
name: "adduser",
|
|
18
|
-
description: "Add a new user",
|
|
19
|
-
category: "users",
|
|
20
|
-
params: ["<username>"],
|
|
21
|
-
run: ({ authUser, shell, args }) => {
|
|
22
|
-
if (authUser !== "root") {
|
|
23
|
-
return { stderr: "adduser: permission denied\n", exitCode: 1 };
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const username = args[0];
|
|
27
|
-
if (!username) {
|
|
28
|
-
return {
|
|
29
|
-
stderr: "Usage: adduser <username>\n",
|
|
30
|
-
exitCode: 1,
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Reject if user already exists
|
|
35
|
-
if (shell.users.listUsers().includes(username)) {
|
|
36
|
-
return {
|
|
37
|
-
stderr: `adduser: user '${username}' already exists\n`,
|
|
38
|
-
exitCode: 1,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
let newPassword = "";
|
|
43
|
-
type Step = "new" | "retype";
|
|
44
|
-
let step: Step = "new";
|
|
45
|
-
|
|
46
|
-
const onPassword = async (
|
|
47
|
-
input: string,
|
|
48
|
-
sh: VirtualShell,
|
|
49
|
-
): Promise<{ result: CommandResult | null; nextPrompt?: string }> => {
|
|
50
|
-
if (step === "new") {
|
|
51
|
-
if (input.length < 1) {
|
|
52
|
-
return {
|
|
53
|
-
result: {
|
|
54
|
-
stderr: "adduser: password cannot be empty\n",
|
|
55
|
-
exitCode: 1,
|
|
56
|
-
},
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
newPassword = input;
|
|
60
|
-
step = "retype";
|
|
61
|
-
return { result: null, nextPrompt: "Retype new password: " };
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// step === "retype"
|
|
65
|
-
if (input !== newPassword) {
|
|
66
|
-
return {
|
|
67
|
-
result: {
|
|
68
|
-
stderr: "adduser: passwords do not match — user not created\n",
|
|
69
|
-
exitCode: 1,
|
|
70
|
-
},
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
await sh.users.addUser(username, newPassword);
|
|
75
|
-
return {
|
|
76
|
-
result: {
|
|
77
|
-
stdout: `${[
|
|
78
|
-
`Adding user '${username}' ...`,
|
|
79
|
-
`Adding new group '${username}' (1001) ...`,
|
|
80
|
-
`Adding new user '${username}' (1001) with group '${username}' ...`,
|
|
81
|
-
`Creating home directory '/home/${username}' ...`,
|
|
82
|
-
`passwd: password set for '${username}'`,
|
|
83
|
-
`adduser: done.`,
|
|
84
|
-
].join("\n")}\n`,
|
|
85
|
-
exitCode: 0,
|
|
86
|
-
},
|
|
87
|
-
};
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
return {
|
|
91
|
-
sudoChallenge: {
|
|
92
|
-
username,
|
|
93
|
-
targetUser: username,
|
|
94
|
-
commandLine: null,
|
|
95
|
-
loginShell: false,
|
|
96
|
-
prompt: "New password: ",
|
|
97
|
-
mode: "passwd",
|
|
98
|
-
onPassword,
|
|
99
|
-
},
|
|
100
|
-
exitCode: 0,
|
|
101
|
-
};
|
|
102
|
-
},
|
|
103
|
-
};
|
package/src/commands/alias.ts
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import type { ShellModule } from "../types/commands";
|
|
2
|
-
import { ifFlag } from "./command-helpers";
|
|
3
|
-
/**
|
|
4
|
-
* Manage shell aliases (list / set / remove).
|
|
5
|
-
* @category shell
|
|
6
|
-
* @params ["[name[=value] ...]"]
|
|
7
|
-
*/
|
|
8
|
-
export const aliasCommand: ShellModule = {
|
|
9
|
-
name: "alias",
|
|
10
|
-
description: "Define or display aliases",
|
|
11
|
-
category: "shell",
|
|
12
|
-
params: ["[name[=value] ...]"],
|
|
13
|
-
run: ({ args, env }) => {
|
|
14
|
-
if (!env) return { exitCode: 0 };
|
|
15
|
-
|
|
16
|
-
// Aliases stored in env.vars under prefix __alias_
|
|
17
|
-
if (args.length === 0) {
|
|
18
|
-
const aliases = Object.entries(env.vars)
|
|
19
|
-
.filter(([k]) => k.startsWith("__alias_"))
|
|
20
|
-
.map(([k, v]) => `alias ${k.slice("__alias_".length)}='${v}'`);
|
|
21
|
-
return { stdout: aliases.join("\n") || "", exitCode: 0 };
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const lines: string[] = [];
|
|
25
|
-
for (const arg of args) {
|
|
26
|
-
const eq = arg.indexOf("=");
|
|
27
|
-
if (eq === -1) {
|
|
28
|
-
// Display single alias
|
|
29
|
-
const val = env.vars[`__alias_${arg}`];
|
|
30
|
-
if (val) lines.push(`alias ${arg}='${val}'`);
|
|
31
|
-
else return { stderr: `alias: ${arg}: not found`, exitCode: 1 };
|
|
32
|
-
} else {
|
|
33
|
-
// Set alias
|
|
34
|
-
const name = arg.slice(0, eq);
|
|
35
|
-
const val = arg.slice(eq + 1).replace(/^['"]|['"]$/g, "");
|
|
36
|
-
env.vars[`__alias_${name}`] = val;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return { stdout: lines.join("\n") || undefined, exitCode: 0 };
|
|
41
|
-
},
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Remove shell aliases.
|
|
46
|
-
* @category shell
|
|
47
|
-
* @params ["<name...>"]
|
|
48
|
-
*/
|
|
49
|
-
export const unaliasCommand: ShellModule = {
|
|
50
|
-
name: "unalias",
|
|
51
|
-
description: "Remove alias definitions",
|
|
52
|
-
category: "shell",
|
|
53
|
-
params: ["<name...> | -a"],
|
|
54
|
-
run: ({ args, env }) => {
|
|
55
|
-
if (!env) return { exitCode: 0 };
|
|
56
|
-
|
|
57
|
-
if (ifFlag(args, ["-a"])) {
|
|
58
|
-
for (const k of Object.keys(env.vars)) {
|
|
59
|
-
if (k.startsWith("__alias_")) delete env.vars[k];
|
|
60
|
-
}
|
|
61
|
-
return { exitCode: 0 };
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
for (const name of args) {
|
|
65
|
-
delete env.vars[`__alias_${name}`];
|
|
66
|
-
}
|
|
67
|
-
return { exitCode: 0 };
|
|
68
|
-
},
|
|
69
|
-
};
|
package/src/commands/apt.ts
DELETED
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
import type { ShellModule } from "../types/commands";
|
|
2
|
-
import { ifFlag } from "./command-helpers";
|
|
3
|
-
import { getPackageManager } from "./helpers";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* APT package manager front-end (simulated).
|
|
7
|
-
* @category package
|
|
8
|
-
* @params ["<install|remove|update|upgrade|search|show|list> [pkg...]"]
|
|
9
|
-
*/
|
|
10
|
-
export const aptCommand: ShellModule = {
|
|
11
|
-
name: "apt",
|
|
12
|
-
aliases: ["apt-get"],
|
|
13
|
-
description: "Package manager",
|
|
14
|
-
category: "package",
|
|
15
|
-
params: ["<install|remove|update|upgrade|search|show|list> [pkg...]"],
|
|
16
|
-
run: ({ args, shell, authUser }) => {
|
|
17
|
-
const pm = getPackageManager(shell);
|
|
18
|
-
if (!pm)
|
|
19
|
-
return { stderr: "apt: package manager not initialised", exitCode: 1 };
|
|
20
|
-
|
|
21
|
-
const sub = args[0]?.toLowerCase();
|
|
22
|
-
const rest = args.slice(1);
|
|
23
|
-
|
|
24
|
-
const quiet = ifFlag(rest, ["-q", "--quiet", "-qq"]);
|
|
25
|
-
const purge = ifFlag(rest, ["--purge"]);
|
|
26
|
-
const pkgs = rest.filter((a) => !a.startsWith("-"));
|
|
27
|
-
|
|
28
|
-
// Non-root check
|
|
29
|
-
const restricted = ["install", "remove", "purge", "upgrade", "update"];
|
|
30
|
-
if (restricted.includes(sub ?? "") && authUser !== "root") {
|
|
31
|
-
return {
|
|
32
|
-
stderr:
|
|
33
|
-
"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?",
|
|
34
|
-
exitCode: 100,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
switch (sub) {
|
|
39
|
-
case "install": {
|
|
40
|
-
if (pkgs.length === 0)
|
|
41
|
-
return { stderr: "apt: no packages specified", exitCode: 1 };
|
|
42
|
-
const { output, exitCode } = pm.install(pkgs, { quiet });
|
|
43
|
-
return { stdout: output || undefined, exitCode };
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
case "remove":
|
|
47
|
-
case "purge": {
|
|
48
|
-
if (pkgs.length === 0)
|
|
49
|
-
return { stderr: "apt: no packages specified", exitCode: 1 };
|
|
50
|
-
const { output, exitCode } = pm.remove(pkgs, {
|
|
51
|
-
purge: sub === "purge" || purge,
|
|
52
|
-
quiet,
|
|
53
|
-
});
|
|
54
|
-
return { stdout: output || undefined, exitCode };
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
case "update": {
|
|
58
|
-
return {
|
|
59
|
-
stdout: [
|
|
60
|
-
"Hit:1 fortune://packages.fortune.local nyx InRelease",
|
|
61
|
-
"Hit:2 fortune://security.fortune.local nyx-security InRelease",
|
|
62
|
-
"Reading package lists... Done",
|
|
63
|
-
"Building dependency tree... Done",
|
|
64
|
-
"Reading state information... Done",
|
|
65
|
-
`All packages are up to date.`,
|
|
66
|
-
].join("\n"),
|
|
67
|
-
exitCode: 0,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
case "upgrade": {
|
|
72
|
-
return {
|
|
73
|
-
stdout: [
|
|
74
|
-
"Reading package lists... Done",
|
|
75
|
-
"Building dependency tree... Done",
|
|
76
|
-
"Reading state information... Done",
|
|
77
|
-
"Calculating upgrade... Done",
|
|
78
|
-
"0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.",
|
|
79
|
-
].join("\n"),
|
|
80
|
-
exitCode: 0,
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
case "search": {
|
|
85
|
-
const term = pkgs[0];
|
|
86
|
-
if (!term)
|
|
87
|
-
return { stderr: "apt: search requires a term", exitCode: 1 };
|
|
88
|
-
const results = pm.search(term);
|
|
89
|
-
if (results.length === 0)
|
|
90
|
-
return {
|
|
91
|
-
stdout: `Sorting... Done\nFull Text Search... Done\n(no results)`,
|
|
92
|
-
exitCode: 0,
|
|
93
|
-
};
|
|
94
|
-
const lines = results.map(
|
|
95
|
-
(p) =>
|
|
96
|
-
`${p.name}/${p.section ?? "misc"} ${p.version} amd64\n ${p.shortDesc ?? p.description}`,
|
|
97
|
-
);
|
|
98
|
-
return {
|
|
99
|
-
stdout: `Sorting... Done\nFull Text Search... Done\n${lines.join("\n")}`,
|
|
100
|
-
exitCode: 0,
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
case "show": {
|
|
105
|
-
const name = pkgs[0];
|
|
106
|
-
if (!name)
|
|
107
|
-
return { stderr: "apt: show requires a package name", exitCode: 1 };
|
|
108
|
-
const info = pm.show(name);
|
|
109
|
-
if (!info)
|
|
110
|
-
return {
|
|
111
|
-
stderr: `N: Unable to locate package ${name}`,
|
|
112
|
-
exitCode: 100,
|
|
113
|
-
};
|
|
114
|
-
return { stdout: info, exitCode: 0 };
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
case "list": {
|
|
118
|
-
const installedFlag = ifFlag(rest, ["--installed"]);
|
|
119
|
-
if (installedFlag) {
|
|
120
|
-
const pkgList = pm.listInstalled();
|
|
121
|
-
if (pkgList.length === 0)
|
|
122
|
-
return {
|
|
123
|
-
stdout: "Listing... Done\n(no packages installed)",
|
|
124
|
-
exitCode: 0,
|
|
125
|
-
};
|
|
126
|
-
const lines = pkgList.map(
|
|
127
|
-
(p) =>
|
|
128
|
-
`${p.name}/${p.section} ${p.version} ${p.architecture} [installed]`,
|
|
129
|
-
);
|
|
130
|
-
return {
|
|
131
|
-
stdout: `Listing... Done\n${lines.join("\n")}`,
|
|
132
|
-
exitCode: 0,
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
// all available
|
|
136
|
-
const all = pm.listAvailable();
|
|
137
|
-
const lines = all.map(
|
|
138
|
-
(p) => `${p.name}/${p.section ?? "misc"} ${p.version} amd64`,
|
|
139
|
-
);
|
|
140
|
-
return { stdout: `Listing... Done\n${lines.join("\n")}`, exitCode: 0 };
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
default: {
|
|
144
|
-
return {
|
|
145
|
-
stdout: [
|
|
146
|
-
"Usage: apt [options] command",
|
|
147
|
-
"",
|
|
148
|
-
"Commands:",
|
|
149
|
-
" install <pkg...> Install packages",
|
|
150
|
-
" remove <pkg...> Remove packages",
|
|
151
|
-
" purge <pkg...> Remove packages and config files",
|
|
152
|
-
" update Refresh package index",
|
|
153
|
-
" upgrade Upgrade all packages",
|
|
154
|
-
" search <term> Search in package descriptions",
|
|
155
|
-
" show <pkg> Show package details",
|
|
156
|
-
" list [--installed] List packages",
|
|
157
|
-
].join("\n"),
|
|
158
|
-
exitCode: 0,
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Query the package cache and retrieve package information.
|
|
167
|
-
* @category package
|
|
168
|
-
* @params ["<search|show|policy> [pkg]"]
|
|
169
|
-
*/
|
|
170
|
-
export const aptCacheCommand: ShellModule = {
|
|
171
|
-
name: "apt-cache",
|
|
172
|
-
description: "Query the package cache",
|
|
173
|
-
category: "package",
|
|
174
|
-
params: ["<search|show|policy> [pkg]"],
|
|
175
|
-
run: ({ args, shell }) => {
|
|
176
|
-
const pm = getPackageManager(shell);
|
|
177
|
-
if (!pm)
|
|
178
|
-
return {
|
|
179
|
-
stderr: "apt-cache: package manager not initialised",
|
|
180
|
-
exitCode: 1,
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
const sub = args[0]?.toLowerCase();
|
|
184
|
-
const pkgName = args[1];
|
|
185
|
-
|
|
186
|
-
switch (sub) {
|
|
187
|
-
case "search": {
|
|
188
|
-
if (!pkgName) return { stderr: "Need a search term", exitCode: 1 };
|
|
189
|
-
const results = pm.search(pkgName);
|
|
190
|
-
return {
|
|
191
|
-
stdout:
|
|
192
|
-
results
|
|
193
|
-
.map((p) => `${p.name} - ${p.shortDesc ?? p.description}`)
|
|
194
|
-
.join("\n") || "(no results)",
|
|
195
|
-
exitCode: 0,
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
case "show": {
|
|
199
|
-
if (!pkgName) return { stderr: "Need a package name", exitCode: 1 };
|
|
200
|
-
const info = pm.show(pkgName);
|
|
201
|
-
return info
|
|
202
|
-
? { stdout: info, exitCode: 0 }
|
|
203
|
-
: { stderr: `N: Unable to locate package ${pkgName}`, exitCode: 100 };
|
|
204
|
-
}
|
|
205
|
-
case "policy": {
|
|
206
|
-
if (!pkgName) return { stderr: "Need a package name", exitCode: 1 };
|
|
207
|
-
const def = pm.findInRegistry(pkgName);
|
|
208
|
-
if (!def)
|
|
209
|
-
return {
|
|
210
|
-
stderr: `N: Unable to locate package ${pkgName}`,
|
|
211
|
-
exitCode: 100,
|
|
212
|
-
};
|
|
213
|
-
const inst = pm.isInstalled(pkgName);
|
|
214
|
-
return {
|
|
215
|
-
stdout: [
|
|
216
|
-
`${pkgName}:`,
|
|
217
|
-
` Installed: ${inst ? def.version : "(none)"}`,
|
|
218
|
-
` Candidate: ${def.version}`,
|
|
219
|
-
` Version table:`,
|
|
220
|
-
` ${def.version} 500`,
|
|
221
|
-
` 500 fortune://packages.fortune.local nyx/main amd64 Packages`,
|
|
222
|
-
].join("\n"),
|
|
223
|
-
exitCode: 0,
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
default:
|
|
227
|
-
return {
|
|
228
|
-
stderr: `apt-cache: unknown command '${sub ?? ""}'`,
|
|
229
|
-
exitCode: 1,
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
},
|
|
233
|
-
};
|
package/src/commands/awk.ts
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import type { ShellModule } from "../types/commands";
|
|
2
|
-
import { getFlag } from "./command-helpers";
|
|
3
|
-
import { assertPathAccess, resolvePath } from "./helpers";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Minimal awk-like pattern scanner.
|
|
7
|
-
*
|
|
8
|
-
* Supported:
|
|
9
|
-
* - `NR==N` pattern (line number condition)
|
|
10
|
-
* - `NF` (number of fields)
|
|
11
|
-
* - `/regex/` pattern
|
|
12
|
-
* - `{ print $N, $M, ... }` action
|
|
13
|
-
* - `{ print }` / `{ print $0 }`
|
|
14
|
-
* - `BEGIN { ... }` and `END { ... }` blocks (no side effects)
|
|
15
|
-
* - `$NF` (last field)
|
|
16
|
-
* - `-F sep` field separator
|
|
17
|
-
*/
|
|
18
|
-
export const awkCommand: ShellModule = {
|
|
19
|
-
name: "awk",
|
|
20
|
-
description: "Pattern scanning and processing language",
|
|
21
|
-
category: "text",
|
|
22
|
-
params: ["[-F <sep>] '<program>' [file]"],
|
|
23
|
-
run: ({ authUser, args, stdin, cwd, shell }) => {
|
|
24
|
-
const sep = (getFlag(args, ["-F"]) as string | undefined) ?? " ";
|
|
25
|
-
const nonFlagArgs = args.filter((a) => !a.startsWith("-") && a !== sep);
|
|
26
|
-
const prog = nonFlagArgs[0];
|
|
27
|
-
const fileArg = nonFlagArgs[1];
|
|
28
|
-
|
|
29
|
-
if (!prog) return { stderr: "awk: no program", exitCode: 1 };
|
|
30
|
-
|
|
31
|
-
let input = stdin ?? "";
|
|
32
|
-
if (fileArg) {
|
|
33
|
-
const filePath = resolvePath(cwd, fileArg);
|
|
34
|
-
try {
|
|
35
|
-
assertPathAccess(authUser, filePath, "awk");
|
|
36
|
-
input = shell.vfs.readFile(filePath);
|
|
37
|
-
} catch {
|
|
38
|
-
return { stderr: `awk: ${fileArg}: No such file or directory`, exitCode: 1 };
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const lines = input.split("\n");
|
|
43
|
-
// Remove empty last element if input ends with \n
|
|
44
|
-
if (lines[lines.length - 1] === "") lines.pop();
|
|
45
|
-
|
|
46
|
-
// Parse program into clauses: [pattern, action]
|
|
47
|
-
type Clause = { pattern: string; action: string };
|
|
48
|
-
const clauses: Clause[] = [];
|
|
49
|
-
|
|
50
|
-
const progTrim = prog.trim();
|
|
51
|
-
|
|
52
|
-
// Handle single unbraced pattern (NR==2, /regex/)
|
|
53
|
-
if (!progTrim.startsWith("{") && !progTrim.includes("{")) {
|
|
54
|
-
clauses.push({ pattern: progTrim, action: "print $0" });
|
|
55
|
-
} else {
|
|
56
|
-
// Parse "pattern { action } pattern2 { action2 }"
|
|
57
|
-
const clauseRe = /([^{]*)\{([^}]*)\}/g;
|
|
58
|
-
let m2 = clauseRe.exec(progTrim);
|
|
59
|
-
while (m2 !== null) {
|
|
60
|
-
clauses.push({ pattern: m2[1]!.trim(), action: m2[2]!.trim() });
|
|
61
|
-
m2 = clauseRe.exec(progTrim);
|
|
62
|
-
}
|
|
63
|
-
if (clauses.length === 0) {
|
|
64
|
-
clauses.push({ pattern: "", action: progTrim.replace(/[{}]/g, "").trim() });
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const out: string[] = [];
|
|
69
|
-
|
|
70
|
-
// BEGIN / END
|
|
71
|
-
const beginClause = clauses.find((c) => c.pattern === "BEGIN");
|
|
72
|
-
const endClause = clauses.find((c) => c.pattern === "END");
|
|
73
|
-
const mainClauses = clauses.filter((c) => c.pattern !== "BEGIN" && c.pattern !== "END");
|
|
74
|
-
|
|
75
|
-
function splitFields(line: string): string[] {
|
|
76
|
-
if (sep === " ") return line.trim().split(/\s+/).filter(Boolean);
|
|
77
|
-
return line.split(sep);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function evalAction(action: string, line: string, nr: number): void {
|
|
81
|
-
const parts = splitFields(line);
|
|
82
|
-
const nf = parts.length;
|
|
83
|
-
|
|
84
|
-
// Expand variables
|
|
85
|
-
const resolve = (expr: string): string => {
|
|
86
|
-
expr = expr.trim();
|
|
87
|
-
if (expr === "NR") return String(nr);
|
|
88
|
-
if (expr === "NF") return String(nf);
|
|
89
|
-
if (expr === "$0") return line;
|
|
90
|
-
if (expr === "$NF") return parts[nf - 1] ?? "";
|
|
91
|
-
if (/^\$\d+$/.test(expr)) return parts[parseInt(expr.slice(1), 10) - 1] ?? "";
|
|
92
|
-
// Arithmetic NR+1, NF-1
|
|
93
|
-
const arith = expr.replace(/\bNR\b/g, String(nr)).replace(/\bNF\b/g, String(nf));
|
|
94
|
-
if (/^[\d\s+\-*/()]+$/.test(arith)) {
|
|
95
|
-
try { return String(Function(`"use strict"; return (${arith});`)()); } catch {} }
|
|
96
|
-
return expr.replace(/"/g, "");
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
const stmts = action.split(";").map((s) => s.trim()).filter(Boolean);
|
|
100
|
-
for (const stmt of stmts) {
|
|
101
|
-
if (stmt === "print" || stmt === "print $0") {
|
|
102
|
-
out.push(line);
|
|
103
|
-
} else if (stmt.startsWith("print ")) {
|
|
104
|
-
const args2 = stmt.slice(6).split(/\s*,\s*/);
|
|
105
|
-
out.push(args2.map(resolve).join("\t"));
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function matchPattern(pattern: string, line: string, nr: number): boolean {
|
|
111
|
-
if (!pattern) return true;
|
|
112
|
-
if (pattern === "1") return true;
|
|
113
|
-
|
|
114
|
-
// NR==N or NR>N etc.
|
|
115
|
-
const nrCond = pattern.match(/^NR\s*([=!<>]=?|==)\s*(\d+)$/);
|
|
116
|
-
if (nrCond) {
|
|
117
|
-
const op = nrCond[1]!;
|
|
118
|
-
const val = parseInt(nrCond[2]!, 10);
|
|
119
|
-
switch (op) {
|
|
120
|
-
case "==": return nr === val;
|
|
121
|
-
case "!=": return nr !== val;
|
|
122
|
-
case ">": return nr > val;
|
|
123
|
-
case ">=": return nr >= val;
|
|
124
|
-
case "<": return nr < val;
|
|
125
|
-
case "<=": return nr <= val;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// NR%N==M
|
|
130
|
-
const nrMod = pattern.match(/^NR%(\d+)==(\d+)$/);
|
|
131
|
-
if (nrMod) {
|
|
132
|
-
return nr % parseInt(nrMod[1]!, 10) === parseInt(nrMod[2]!, 10);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// /regex/ pattern
|
|
136
|
-
if (pattern.startsWith("/") && pattern.endsWith("/")) {
|
|
137
|
-
try {
|
|
138
|
-
return new RegExp(pattern.slice(1, -1)).test(line);
|
|
139
|
-
} catch { return false; }
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// $N~/regex/
|
|
143
|
-
const fieldMatch = pattern.match(/^\$(\d+)~\/(.*)\/$/);
|
|
144
|
-
if (fieldMatch) {
|
|
145
|
-
const parts = splitFields(line);
|
|
146
|
-
const field = parts[parseInt(fieldMatch[1]!, 10) - 1] ?? "";
|
|
147
|
-
try { return new RegExp(fieldMatch[2]!).test(field); } catch { return false; }
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return false;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
if (beginClause) evalAction(beginClause.action, "", 0);
|
|
154
|
-
|
|
155
|
-
for (let nr = 1; nr <= lines.length; nr++) {
|
|
156
|
-
const line = lines[nr - 1]!;
|
|
157
|
-
for (const clause of mainClauses) {
|
|
158
|
-
if (matchPattern(clause.pattern, line, nr)) {
|
|
159
|
-
evalAction(clause.action, line, nr);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
if (endClause) evalAction(endClause.action, "", lines.length + 1);
|
|
165
|
-
|
|
166
|
-
return { stdout: out.join("\n") + (out.length > 0 ? "\n" : ""), exitCode: 0 };
|
|
167
|
-
},
|
|
168
|
-
};
|
package/src/commands/base64.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { ShellModule } from "../types/commands";
|
|
2
|
-
import { ifFlag } from "./command-helpers";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Encode or decode base64 data.
|
|
6
|
-
* @category text
|
|
7
|
-
* @params ["[-d] [file]"]
|
|
8
|
-
*/
|
|
9
|
-
export const base64Command: ShellModule = {
|
|
10
|
-
name: "base64",
|
|
11
|
-
description: "Encode/decode base64",
|
|
12
|
-
category: "text",
|
|
13
|
-
params: ["[-d] [file]"],
|
|
14
|
-
run: ({ args, stdin }) => {
|
|
15
|
-
const decode = ifFlag(args, ["-d", "--decode"]);
|
|
16
|
-
const input = stdin ?? "";
|
|
17
|
-
if (decode) {
|
|
18
|
-
try {
|
|
19
|
-
return {
|
|
20
|
-
stdout: Buffer.from(input.trim(), "base64").toString("utf8"),
|
|
21
|
-
exitCode: 0,
|
|
22
|
-
};
|
|
23
|
-
} catch {
|
|
24
|
-
return { stderr: "base64: invalid input", exitCode: 1 };
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
return { stdout: Buffer.from(input).toString("base64"), exitCode: 0 };
|
|
28
|
-
},
|
|
29
|
-
};
|
package/src/commands/cat.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import type { ShellModule } from "../types/commands";
|
|
2
|
-
import { ifFlag } from "./command-helpers";
|
|
3
|
-
import { assertPathAccess, resolveReadablePath } from "./helpers";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Concatenate and print files to stdout.
|
|
7
|
-
* @category files
|
|
8
|
-
* @params ["[-n] [-b] <file...>"]
|
|
9
|
-
*/
|
|
10
|
-
export const catCommand: ShellModule = {
|
|
11
|
-
name: "cat",
|
|
12
|
-
description: "Concatenate and print files",
|
|
13
|
-
category: "files",
|
|
14
|
-
params: ["[-n] [-b] <file...>"],
|
|
15
|
-
run: ({ authUser, shell, cwd, args, stdin }) => {
|
|
16
|
-
const numberAll = ifFlag(args, ["-n", "--number"]);
|
|
17
|
-
const numberNonBlank = ifFlag(args, ["-b", "--number-nonblank"]);
|
|
18
|
-
const fileArgs = args.filter((a) => !a.startsWith("-"));
|
|
19
|
-
|
|
20
|
-
if (fileArgs.length === 0 && stdin !== undefined) {
|
|
21
|
-
return { stdout: stdin, exitCode: 0 };
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (fileArgs.length === 0) {
|
|
25
|
-
return { stderr: "cat: missing file operand", exitCode: 1 };
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const parts: string[] = [];
|
|
29
|
-
for (const fileArg of fileArgs) {
|
|
30
|
-
const target = resolveReadablePath(shell.vfs, cwd, fileArg);
|
|
31
|
-
assertPathAccess(authUser, target, "cat");
|
|
32
|
-
parts.push(shell.vfs.readFile(target));
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const combined = parts.join("");
|
|
36
|
-
|
|
37
|
-
if (!numberAll && !numberNonBlank) {
|
|
38
|
-
return { stdout: combined, exitCode: 0 };
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
let lineNum = 1;
|
|
42
|
-
const numbered = combined
|
|
43
|
-
.split("\n")
|
|
44
|
-
.map((line) => {
|
|
45
|
-
if (numberNonBlank && line.trim() === "") return line;
|
|
46
|
-
return `${String(lineNum++).padStart(6)}\t${line}`;
|
|
47
|
-
})
|
|
48
|
-
.join("\n");
|
|
49
|
-
|
|
50
|
-
return { stdout: numbered, exitCode: 0 };
|
|
51
|
-
},
|
|
52
|
-
};
|
package/src/commands/cd.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { ShellModule } from "../types/commands";
|
|
2
|
-
import { assertPathAccess, resolvePath } from "./helpers";
|
|
3
|
-
import { userHome } from "./runtime";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Change current working directory.
|
|
7
|
-
* @category navigation
|
|
8
|
-
* @params ["[path]"]
|
|
9
|
-
*/
|
|
10
|
-
export const cdCommand: ShellModule = {
|
|
11
|
-
name: "cd",
|
|
12
|
-
description: "Change directory",
|
|
13
|
-
category: "navigation",
|
|
14
|
-
params: ["[path]"],
|
|
15
|
-
run: ({ authUser, shell, cwd, args }) => {
|
|
16
|
-
const target = resolvePath(cwd, args[0] ?? "~", userHome(authUser));
|
|
17
|
-
assertPathAccess(authUser, target, "cd");
|
|
18
|
-
const stats = shell.vfs.stat(target);
|
|
19
|
-
if (stats.type !== "directory") {
|
|
20
|
-
return { stderr: `cd: not a directory: ${target}`, exitCode: 1 };
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return { nextCwd: target, exitCode: 0 };
|
|
24
|
-
},
|
|
25
|
-
};
|