typescript-virtual-container 1.5.3 → 1.5.5
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 +44 -532
- package/dist/.tsbuildinfo +1 -0
- package/dist/SSHMimic/executor.js +23 -5
- package/dist/VirtualPackageManager/index.js +10 -0
- package/dist/VirtualShell/shell.js +158 -11
- package/dist/commands/basename.d.ts +13 -0
- package/dist/commands/basename.js +45 -0
- package/dist/commands/bc.d.ts +2 -0
- package/dist/commands/bc.js +28 -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/ip.d.ts +7 -0
- package/dist/commands/ip.js +52 -0
- package/dist/commands/jobs.d.ts +4 -0
- package/dist/commands/jobs.js +27 -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 +30 -2
- package/dist/commands/runtime.js +24 -3
- package/dist/commands/set.js +20 -0
- package/dist/commands/sh.js +74 -1
- 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 +87 -1
- 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
|
@@ -3,6 +3,8 @@ import { aliasCommand, unaliasCommand } from "./alias";
|
|
|
3
3
|
import { aptCacheCommand, aptCommand } from "./apt";
|
|
4
4
|
import { awkCommand } from "./awk";
|
|
5
5
|
import { base64Command } from "./base64";
|
|
6
|
+
import { basenameCommand, dirnameCommand } from "./basename";
|
|
7
|
+
import { bcCommand } from "./bc";
|
|
6
8
|
import { catCommand } from "./cat";
|
|
7
9
|
import { cdCommand } from "./cd";
|
|
8
10
|
import { chmodCommand } from "./chmod";
|
|
@@ -21,8 +23,10 @@ import { echoCommand } from "./echo";
|
|
|
21
23
|
import { envCommand } from "./env";
|
|
22
24
|
import { exitCommand } from "./exit";
|
|
23
25
|
import { exportCommand } from "./export";
|
|
26
|
+
import { fileCommand } from "./file";
|
|
24
27
|
import { findCommand } from "./find";
|
|
25
28
|
import { freeCommand } from "./free";
|
|
29
|
+
import { cmatrixCommand, cowsayCommand, cowthinkCommand, fortuneCommand, slCommand, yesCommand } from "./fun";
|
|
26
30
|
import { grepCommand } from "./grep";
|
|
27
31
|
import { groupsCommand } from "./groups";
|
|
28
32
|
import { gunzipCommand, gzipCommand } from "./gzip";
|
|
@@ -32,10 +36,11 @@ import { historyCommand } from "./history";
|
|
|
32
36
|
import { hostnameCommand } from "./hostname";
|
|
33
37
|
import { htopCommand } from "./htop";
|
|
34
38
|
import { idCommand } from "./id";
|
|
39
|
+
import { ipCommand } from "./ip";
|
|
40
|
+
import { bgCommand, fgCommand, jobsCommand } from "./jobs";
|
|
35
41
|
import { killCommand } from "./kill";
|
|
42
|
+
import { dmesgCommand, lastCommand } from "./last";
|
|
36
43
|
import { lnCommand, readlinkCommand } from "./ln";
|
|
37
|
-
import { seqCommand } from "./seq";
|
|
38
|
-
import { statCommand } from "./stat";
|
|
39
44
|
import { lsCommand } from "./ls";
|
|
40
45
|
import { lsbReleaseCommand } from "./lsb-release";
|
|
41
46
|
import { manCommand } from "./man";
|
|
@@ -54,12 +59,14 @@ import { python3Command } from "./python";
|
|
|
54
59
|
import { readCommand } from "./read";
|
|
55
60
|
import { rmCommand } from "./rm";
|
|
56
61
|
import { sedCommand } from "./sed";
|
|
62
|
+
import { seqCommand } from "./seq";
|
|
57
63
|
import { setCommand } from "./set";
|
|
58
64
|
import { shCommand } from "./sh";
|
|
59
65
|
import { returnCommand, shiftCommand, trapCommand } from "./shift";
|
|
60
66
|
import { sleepCommand } from "./sleep";
|
|
61
67
|
import { sortCommand } from "./sort";
|
|
62
68
|
import { sourceCommand } from "./source";
|
|
69
|
+
import { statCommand } from "./stat";
|
|
63
70
|
import { suCommand } from "./su";
|
|
64
71
|
import { sudoCommand } from "./sudo";
|
|
65
72
|
import { tailCommand } from "./tail";
|
|
@@ -67,6 +74,7 @@ import { tarCommand } from "./tar";
|
|
|
67
74
|
import { teeCommand } from "./tee";
|
|
68
75
|
import { testCommand } from "./test";
|
|
69
76
|
import { touchCommand } from "./touch";
|
|
77
|
+
import { sttyCommand, tputCommand } from "./tput";
|
|
70
78
|
import { trCommand } from "./tr";
|
|
71
79
|
import { treeCommand } from "./tree";
|
|
72
80
|
import { falseCommand, trueCommand } from "./true";
|
|
@@ -75,6 +83,7 @@ import { unameCommand } from "./uname";
|
|
|
75
83
|
import { uniqCommand } from "./uniq";
|
|
76
84
|
import { unsetCommand } from "./unset";
|
|
77
85
|
import { uptimeCommand } from "./uptime";
|
|
86
|
+
import { wCommand } from "./w";
|
|
78
87
|
import { wcCommand } from "./wc";
|
|
79
88
|
import { wgetCommand } from "./wget";
|
|
80
89
|
import { whichCommand } from "./which";
|
|
@@ -144,6 +153,21 @@ const BASE_COMMANDS = [
|
|
|
144
153
|
exitCommand,
|
|
145
154
|
// Editors
|
|
146
155
|
nanoCommand,
|
|
156
|
+
wCommand,
|
|
157
|
+
basenameCommand,
|
|
158
|
+
dirnameCommand,
|
|
159
|
+
fileCommand,
|
|
160
|
+
tputCommand,
|
|
161
|
+
sttyCommand,
|
|
162
|
+
lastCommand,
|
|
163
|
+
dmesgCommand,
|
|
164
|
+
ipCommand,
|
|
165
|
+
yesCommand,
|
|
166
|
+
fortuneCommand,
|
|
167
|
+
cowsayCommand,
|
|
168
|
+
cowthinkCommand,
|
|
169
|
+
cmatrixCommand,
|
|
170
|
+
slCommand,
|
|
147
171
|
htopCommand,
|
|
148
172
|
// Network
|
|
149
173
|
curlCommand,
|
|
@@ -162,6 +186,10 @@ const BASE_COMMANDS = [
|
|
|
162
186
|
dpkgCommand,
|
|
163
187
|
dpkgQueryCommand,
|
|
164
188
|
// Shell (extended)
|
|
189
|
+
jobsCommand,
|
|
190
|
+
bgCommand,
|
|
191
|
+
fgCommand,
|
|
192
|
+
bcCommand,
|
|
165
193
|
whichCommand,
|
|
166
194
|
typeCommand,
|
|
167
195
|
manCommand,
|
package/dist/commands/runtime.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** biome-ignore-all lint/style/useNamingConvention: ENV VARIABLES */
|
|
2
2
|
import { executeStatements } from "../SSHMimic/executor";
|
|
3
3
|
import { parseScript } from "../VirtualShell/shellParser";
|
|
4
|
-
import { expandAsync, expandBraces } from "../utils/expand";
|
|
4
|
+
import { expandAsync, expandBraces, expandGlob } from "../utils/expand";
|
|
5
5
|
import { tokenizeCommand } from "../utils/tokenize";
|
|
6
6
|
import { resolveModule } from "./registry";
|
|
7
7
|
/** Returns the home directory path for a given user. Root lives at /root. */
|
|
@@ -15,10 +15,11 @@ export function makeDefaultEnv(authUser, hostname) {
|
|
|
15
15
|
HOME: userHome(authUser),
|
|
16
16
|
USER: authUser,
|
|
17
17
|
LOGNAME: authUser,
|
|
18
|
-
SHELL: "/bin/
|
|
18
|
+
SHELL: "/bin/bash",
|
|
19
19
|
TERM: "xterm-256color",
|
|
20
20
|
HOSTNAME: hostname,
|
|
21
21
|
PS1: "\\u@\\h:\\w\\$ ",
|
|
22
|
+
"0": "/bin/bash",
|
|
22
23
|
},
|
|
23
24
|
lastExitCode: 0,
|
|
24
25
|
};
|
|
@@ -192,6 +193,26 @@ export async function runCommand(rawInput, authUser, hostname, mode, cwd, shell,
|
|
|
192
193
|
return { stderr: `${trimmed.split(" ")[0]}: maximum call depth (${MAX_CALL_DEPTH}) exceeded`, exitCode: 126 };
|
|
193
194
|
}
|
|
194
195
|
try {
|
|
196
|
+
// History expansion: !! and !n
|
|
197
|
+
if (trimmed === '!!' || /^!-?\d+$/.test(trimmed) || trimmed.startsWith('!! ')) {
|
|
198
|
+
const histPath = `${shellEnv.vars.HOME ?? `/home/${authUser}`}/.bash_history`;
|
|
199
|
+
if (shell.vfs.exists(histPath)) {
|
|
200
|
+
const lines = shell.vfs.readFile(histPath).split('\n').filter(Boolean);
|
|
201
|
+
let cmd;
|
|
202
|
+
if (trimmed === '!!' || trimmed.startsWith('!! ')) {
|
|
203
|
+
cmd = lines[lines.length - 1];
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
const n = parseInt(trimmed.slice(1), 10);
|
|
207
|
+
cmd = n > 0 ? lines[n - 1] : lines[lines.length + n];
|
|
208
|
+
}
|
|
209
|
+
if (cmd) {
|
|
210
|
+
const suffix = trimmed.startsWith('!! ') ? trimmed.slice(3) : '';
|
|
211
|
+
return runCommand(`${cmd}${suffix ? ` ${suffix}` : ''}`, authUser, hostname, mode, cwd, shell, stdin, shellEnv);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return { stderr: `${trimmed}: event not found`, exitCode: 1 };
|
|
215
|
+
}
|
|
195
216
|
const rawTokens = tokenizeCommand(trimmed);
|
|
196
217
|
const rawFirstWord = rawTokens[0]?.toLowerCase() ?? "";
|
|
197
218
|
const aliasVal = shellEnv.vars[`__alias_${rawFirstWord}`];
|
|
@@ -252,7 +273,7 @@ export async function runCommand(rawInput, authUser, hostname, mode, cwd, shell,
|
|
|
252
273
|
}
|
|
253
274
|
const commandName = parts[0]?.toLowerCase() ?? "";
|
|
254
275
|
// Apply brace expansion to each arg token
|
|
255
|
-
const args = parts.slice(1).flatMap(expandBraces);
|
|
276
|
+
const args = parts.slice(1).flatMap(expandBraces).flatMap(token => expandGlob(token, cwd, shell.vfs));
|
|
256
277
|
const mod = resolveModule(commandName);
|
|
257
278
|
if (!mod) {
|
|
258
279
|
const vfsBinary = resolveVfsBinary(commandName, shellEnv, shell, authUser);
|
package/dist/commands/set.js
CHANGED
|
@@ -11,11 +11,31 @@ export const setCommand = {
|
|
|
11
11
|
run: ({ args, env }) => {
|
|
12
12
|
if (args.length === 0) {
|
|
13
13
|
const out = Object.entries(env.vars)
|
|
14
|
+
.filter(([k]) => !k.startsWith("__"))
|
|
14
15
|
.map(([k, v]) => `${k}=${v}`)
|
|
15
16
|
.join("\n");
|
|
16
17
|
return { stdout: out, exitCode: 0 };
|
|
17
18
|
}
|
|
18
19
|
for (const arg of args) {
|
|
20
|
+
const flagMatch = arg.match(/^([+-])([a-zA-Z]+)$/);
|
|
21
|
+
if (flagMatch) {
|
|
22
|
+
const on = flagMatch[1] === "-";
|
|
23
|
+
for (const flag of flagMatch[2]) {
|
|
24
|
+
if (flag === "e") {
|
|
25
|
+
if (on)
|
|
26
|
+
env.vars.__errexit = "1";
|
|
27
|
+
else
|
|
28
|
+
delete env.vars.__errexit;
|
|
29
|
+
}
|
|
30
|
+
if (flag === "x") {
|
|
31
|
+
if (on)
|
|
32
|
+
env.vars.__xtrace = "1";
|
|
33
|
+
else
|
|
34
|
+
delete env.vars.__xtrace;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
19
39
|
if (arg.includes("=")) {
|
|
20
40
|
const eq = arg.indexOf("=");
|
|
21
41
|
env.vars[arg.slice(0, eq)] = arg.slice(eq + 1);
|
package/dist/commands/sh.js
CHANGED
|
@@ -125,6 +125,43 @@ function parseBlocks(lines) {
|
|
|
125
125
|
}
|
|
126
126
|
blocks.push({ type: "while", cond, body });
|
|
127
127
|
}
|
|
128
|
+
else if (line.startsWith("case ") && line.endsWith(" in") || line.match(/^case\s+.+\s+in$/)) {
|
|
129
|
+
const caseExpr = line.replace(/^case\s+/, "").replace(/\s+in$/, "").trim();
|
|
130
|
+
const patterns = [];
|
|
131
|
+
i++;
|
|
132
|
+
while (i < lines.length && lines[i]?.trim() !== "esac") {
|
|
133
|
+
const pl = lines[i].trim();
|
|
134
|
+
if (!pl || pl === "esac") {
|
|
135
|
+
i++;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
// pattern) or pattern1|pattern2)
|
|
139
|
+
const patMatch = pl.match(/^(.+?)\)\s*(.*)$/);
|
|
140
|
+
if (patMatch) {
|
|
141
|
+
const pat = patMatch[1].trim();
|
|
142
|
+
const body = [];
|
|
143
|
+
if (patMatch[2]?.trim() && patMatch[2].trim() !== ";;") {
|
|
144
|
+
body.push(patMatch[2].trim());
|
|
145
|
+
}
|
|
146
|
+
i++;
|
|
147
|
+
while (i < lines.length) {
|
|
148
|
+
const bl = lines[i].trim();
|
|
149
|
+
if (bl === ";;" || bl === "esac")
|
|
150
|
+
break;
|
|
151
|
+
if (bl)
|
|
152
|
+
body.push(bl);
|
|
153
|
+
i++;
|
|
154
|
+
}
|
|
155
|
+
if (lines[i]?.trim() === ";;")
|
|
156
|
+
i++; // skip ;;
|
|
157
|
+
patterns.push({ pattern: pat, body });
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
i++;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
blocks.push({ type: "case", expr: caseExpr, patterns });
|
|
164
|
+
}
|
|
128
165
|
else {
|
|
129
166
|
blocks.push({ type: "cmd", line });
|
|
130
167
|
}
|
|
@@ -189,9 +226,12 @@ async function evalCondition(cond, ctx) {
|
|
|
189
226
|
async function runBlocks(blocks, ctx) {
|
|
190
227
|
let lastResult = { exitCode: 0 };
|
|
191
228
|
let output = "";
|
|
229
|
+
let traceOutput = "";
|
|
192
230
|
for (const block of blocks) {
|
|
193
231
|
if (block.type === "cmd") {
|
|
194
232
|
const expanded = await expandVars(block.line, ctx.env.vars, ctx.env.lastExitCode, ctx);
|
|
233
|
+
if (ctx.env.vars.__xtrace)
|
|
234
|
+
traceOutput += `+ ${expanded}\n`;
|
|
195
235
|
// Bare VAR=val assignment(s) — handle before dispatching to runCommand
|
|
196
236
|
const assignRe = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)/;
|
|
197
237
|
const tokens = expanded.trim().split(/\s+/);
|
|
@@ -231,6 +271,8 @@ async function runBlocks(blocks, ctx) {
|
|
|
231
271
|
output += `${r.stdout}\n`;
|
|
232
272
|
if (r.stderr)
|
|
233
273
|
return { ...r, stdout: output.trim() };
|
|
274
|
+
if (ctx.env.vars.__errexit && (r.exitCode ?? 0) !== 0)
|
|
275
|
+
return { ...r, stdout: output.trim() };
|
|
234
276
|
lastResult = r;
|
|
235
277
|
}
|
|
236
278
|
else if (block.type === "if") {
|
|
@@ -311,8 +353,34 @@ async function runBlocks(blocks, ctx) {
|
|
|
311
353
|
iterations++;
|
|
312
354
|
}
|
|
313
355
|
}
|
|
356
|
+
else if (block.type === "case") {
|
|
357
|
+
const expanded = await expandVars(block.expr, ctx.env.vars, ctx.env.lastExitCode, ctx);
|
|
358
|
+
for (const pat of block.patterns) {
|
|
359
|
+
const alts = pat.pattern.split("|").map((p) => p.trim());
|
|
360
|
+
const matched = alts.some((p) => {
|
|
361
|
+
if (p === "*")
|
|
362
|
+
return true;
|
|
363
|
+
if (p.includes("*") || p.includes("?")) {
|
|
364
|
+
const re = new RegExp(`^${p.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".")}$`);
|
|
365
|
+
return re.test(expanded);
|
|
366
|
+
}
|
|
367
|
+
return p === expanded;
|
|
368
|
+
});
|
|
369
|
+
if (matched) {
|
|
370
|
+
const sub = await runBlocks(parseBlocks(pat.body), ctx);
|
|
371
|
+
if (sub.stdout)
|
|
372
|
+
output += `${sub.stdout}\n`;
|
|
373
|
+
break;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
314
377
|
}
|
|
315
|
-
|
|
378
|
+
const finalStdout = output.trim() || lastResult.stdout;
|
|
379
|
+
if (traceOutput) {
|
|
380
|
+
const traceStderr = (lastResult.stderr ? `${lastResult.stderr}\n` : "") + traceOutput.trim();
|
|
381
|
+
return { ...lastResult, stdout: finalStdout, stderr: traceStderr || lastResult.stderr };
|
|
382
|
+
}
|
|
383
|
+
return { ...lastResult, stdout: finalStdout };
|
|
316
384
|
}
|
|
317
385
|
/**
|
|
318
386
|
* Execute shell scripts or commands with a minimal shell interpreter.
|
|
@@ -369,6 +437,11 @@ function splitShScript(script) {
|
|
|
369
437
|
}
|
|
370
438
|
continue;
|
|
371
439
|
}
|
|
440
|
+
// Backslash-newline continuation: join lines
|
|
441
|
+
if (!inSingleQ && ch === '\\' && i + 1 < script.length && script[i + 1] === '\n') {
|
|
442
|
+
i += 2; // skip \ and \n
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
372
445
|
if (depth === 0 && (ch === ";" || ch === "\n")) {
|
|
373
446
|
const t = current.trim();
|
|
374
447
|
if (t && !t.startsWith("#"))
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ShellModule } from "../types/commands";
|
|
2
|
+
/**
|
|
3
|
+
* Terminal control.
|
|
4
|
+
* @category shell
|
|
5
|
+
* @params ["<cap> [args...]"]
|
|
6
|
+
*/
|
|
7
|
+
export declare const tputCommand: ShellModule;
|
|
8
|
+
/**
|
|
9
|
+
* Print or set terminal line settings.
|
|
10
|
+
* @category shell
|
|
11
|
+
* @params ["[args...]"]
|
|
12
|
+
*/
|
|
13
|
+
export declare const sttyCommand: ShellModule;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const CAPS = {
|
|
2
|
+
cols: 220, lines: 50, colors: 256,
|
|
3
|
+
bold: "\x1b[1m", dim: "\x1b[2m", smul: "\x1b[4m", rmul: "\x1b[24m",
|
|
4
|
+
rev: "\x1b[7m", smso: "\x1b[7m", rmso: "\x1b[27m",
|
|
5
|
+
sgr0: "\x1b[0m", el: "\x1b[K", ed: "\x1b[J",
|
|
6
|
+
clear: "\x1b[2J\x1b[H", cup: "", setaf: "", setab: "",
|
|
7
|
+
};
|
|
8
|
+
const ANSI_COLORS = [
|
|
9
|
+
"30", "31", "32", "33", "34", "35", "36", "37",
|
|
10
|
+
"90", "91", "92", "93", "94", "95", "96", "97",
|
|
11
|
+
];
|
|
12
|
+
/**
|
|
13
|
+
* Terminal control.
|
|
14
|
+
* @category shell
|
|
15
|
+
* @params ["<cap> [args...]"]
|
|
16
|
+
*/
|
|
17
|
+
export const tputCommand = {
|
|
18
|
+
name: "tput",
|
|
19
|
+
description: "Query terminfo database",
|
|
20
|
+
category: "shell",
|
|
21
|
+
params: ["<cap> [args...]"],
|
|
22
|
+
run: ({ args }) => {
|
|
23
|
+
const cap = args[0];
|
|
24
|
+
if (!cap)
|
|
25
|
+
return { stderr: "tput: missing capability", exitCode: 1 };
|
|
26
|
+
if (cap === "setaf" && args[1] !== undefined) {
|
|
27
|
+
const n = parseInt(args[1], 10);
|
|
28
|
+
const code = ANSI_COLORS[n] ?? "39";
|
|
29
|
+
return { stdout: `\x1b[${code}m`, exitCode: 0 };
|
|
30
|
+
}
|
|
31
|
+
if (cap === "setab" && args[1] !== undefined) {
|
|
32
|
+
const n = parseInt(args[1], 10);
|
|
33
|
+
const code = ANSI_COLORS[n]?.replace(/3/, "4").replace(/9/, "10") ?? "49";
|
|
34
|
+
return { stdout: `\x1b[${code}m`, exitCode: 0 };
|
|
35
|
+
}
|
|
36
|
+
if (cap === "cup" && args[1] !== undefined && args[2] !== undefined) {
|
|
37
|
+
return { stdout: `\x1b[${parseInt(args[1], 10) + 1};${parseInt(args[2], 10) + 1}H`, exitCode: 0 };
|
|
38
|
+
}
|
|
39
|
+
const val = CAPS[cap];
|
|
40
|
+
if (val === undefined)
|
|
41
|
+
return { stderr: `tput: unknown terminal capability '${cap}'`, exitCode: 1 };
|
|
42
|
+
return { stdout: String(val), exitCode: 0 };
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Print or set terminal line settings.
|
|
47
|
+
* @category shell
|
|
48
|
+
* @params ["[args...]"]
|
|
49
|
+
*/
|
|
50
|
+
export const sttyCommand = {
|
|
51
|
+
name: "stty",
|
|
52
|
+
description: "Change and print terminal line settings",
|
|
53
|
+
category: "shell",
|
|
54
|
+
params: ["[args...]"],
|
|
55
|
+
run: ({ args }) => {
|
|
56
|
+
if (args.includes("-a") || args.includes("--all")) {
|
|
57
|
+
return {
|
|
58
|
+
stdout: [
|
|
59
|
+
"speed 38400 baud; rows 50; columns 220; line = 0;",
|
|
60
|
+
"intr = ^C; quit = ^\\; erase = ^?; kill = ^U; eof = ^D;",
|
|
61
|
+
"eol = M-^?; eol2 = M-^?; swtch = <undef>; start = ^Q; stop = ^S;",
|
|
62
|
+
"-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts",
|
|
63
|
+
"brkint -icrnl ixon -ixoff -iuclc ixany imaxbel -iutf8",
|
|
64
|
+
"opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0",
|
|
65
|
+
"isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke",
|
|
66
|
+
].join("\n"),
|
|
67
|
+
exitCode: 0,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
if (args.includes("size")) {
|
|
71
|
+
return { stdout: "50 220", exitCode: 0 };
|
|
72
|
+
}
|
|
73
|
+
// silently accept set operations
|
|
74
|
+
return { exitCode: 0 };
|
|
75
|
+
},
|
|
76
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { userHome } from "./runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Show who is logged on and what they are doing.
|
|
4
|
+
* @category system
|
|
5
|
+
* @params ["[user]"]
|
|
6
|
+
*/
|
|
7
|
+
export const wCommand = {
|
|
8
|
+
name: "w",
|
|
9
|
+
description: "Show who is logged on and what they are doing",
|
|
10
|
+
category: "system",
|
|
11
|
+
params: ["[user]"],
|
|
12
|
+
run: ({ shell, authUser }) => {
|
|
13
|
+
const now = new Date();
|
|
14
|
+
const upSecs = Math.floor(performance.now() / 1000);
|
|
15
|
+
const upMins = Math.floor(upSecs / 60);
|
|
16
|
+
const upHours = Math.floor(upMins / 60);
|
|
17
|
+
const uptimeStr = upHours > 0
|
|
18
|
+
? `${upHours}:${String(upMins % 60).padStart(2, "0")}`
|
|
19
|
+
: `${upMins} min`;
|
|
20
|
+
const timeStr = now.toTimeString().slice(0, 5);
|
|
21
|
+
// Read active sessions
|
|
22
|
+
shell.users.listActiveSessions?.();
|
|
23
|
+
const logPath = `${userHome(authUser)}/.lastlog`;
|
|
24
|
+
let loginTime = timeStr;
|
|
25
|
+
if (shell.vfs.exists(logPath)) {
|
|
26
|
+
try {
|
|
27
|
+
const log = JSON.parse(shell.vfs.readFile(logPath));
|
|
28
|
+
loginTime = new Date(log.at).toTimeString().slice(0, 5);
|
|
29
|
+
}
|
|
30
|
+
catch { }
|
|
31
|
+
}
|
|
32
|
+
const header = ` ${timeStr} up ${uptimeStr}, 1 user, load average: 0.${Math.floor(Math.random() * 30).toString().padStart(2, "0")}, 0.${Math.floor(Math.random() * 15).toString().padStart(2, "0")}, 0.${Math.floor(Math.random() * 10).toString().padStart(2, "0")}`;
|
|
33
|
+
const colHeader = "USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT";
|
|
34
|
+
const idle = "0.00s";
|
|
35
|
+
const row = `${authUser.padEnd(8)} pts/0 browser ${loginTime} ${idle} 0.01s 0.00s -bash`;
|
|
36
|
+
return { stdout: [header, colHeader, row].join("\n"), exitCode: 0 };
|
|
37
|
+
},
|
|
38
|
+
};
|
package/dist/utils/expand.d.ts
CHANGED
|
@@ -56,3 +56,15 @@ export declare function expandSync(input: string, env: Record<string, string>, l
|
|
|
56
56
|
* @param runCmd Async callback to execute a command and return its stdout.
|
|
57
57
|
*/
|
|
58
58
|
export declare function expandAsync(input: string, env: Record<string, string>, lastExit: number, runCmd: (cmd: string) => Promise<string>): Promise<string>;
|
|
59
|
+
/**
|
|
60
|
+
* Expand a glob pattern against a VirtualShell VFS.
|
|
61
|
+
* Supports * (any chars in segment) and ** (any path).
|
|
62
|
+
* Returns the original pattern if no matches found (bash behavior).
|
|
63
|
+
*/
|
|
64
|
+
export declare function expandGlob(pattern: string, cwd: string, vfs: {
|
|
65
|
+
list: (p: string) => string[];
|
|
66
|
+
exists: (p: string) => boolean;
|
|
67
|
+
stat: (p: string) => {
|
|
68
|
+
type: string;
|
|
69
|
+
};
|
|
70
|
+
}): string[];
|
package/dist/utils/expand.js
CHANGED
|
@@ -369,10 +369,12 @@ export function expandSync(input, env, lastExit = 0, home) {
|
|
|
369
369
|
let s = chunk;
|
|
370
370
|
// Tilde expansion — only at start of token or after `:` or whitespace
|
|
371
371
|
s = s.replace(/(^|[\s:])~(\/|$)/g, (_, pre, post) => `${pre}${homePath}${post}`);
|
|
372
|
-
// $? $$ $#
|
|
372
|
+
// $? $$ $# $RANDOM $LINENO
|
|
373
373
|
s = s.replace(/\$\?/g, String(lastExit));
|
|
374
374
|
s = s.replace(/\$\$/g, "1");
|
|
375
375
|
s = s.replace(/\$#/g, "0");
|
|
376
|
+
s = s.replace(/\$RANDOM\b/g, () => String(Math.floor(Math.random() * 32768)));
|
|
377
|
+
s = s.replace(/\$LINENO\b/g, "1");
|
|
376
378
|
// $(( arithmetic )) — must come before ${ and $VAR to avoid conflicts
|
|
377
379
|
s = expandArithmeticChunks(s, env);
|
|
378
380
|
// ${#VAR} — string length
|
|
@@ -474,3 +476,87 @@ export async function expandAsync(input, env, lastExit, runCmd) {
|
|
|
474
476
|
env[depthKey] = String(currentDepth);
|
|
475
477
|
}
|
|
476
478
|
}
|
|
479
|
+
// ─── Glob expansion ──────────────────────────────────────────────────────────
|
|
480
|
+
/**
|
|
481
|
+
* Expand a glob pattern against a VirtualShell VFS.
|
|
482
|
+
* Supports * (any chars in segment) and ** (any path).
|
|
483
|
+
* Returns the original pattern if no matches found (bash behavior).
|
|
484
|
+
*/
|
|
485
|
+
export function expandGlob(pattern, cwd, vfs) {
|
|
486
|
+
// No glob chars → return as-is
|
|
487
|
+
if (!pattern.includes('*') && !pattern.includes('?'))
|
|
488
|
+
return [pattern];
|
|
489
|
+
const isAbsolute = pattern.startsWith('/');
|
|
490
|
+
const base = isAbsolute ? '/' : cwd;
|
|
491
|
+
const relPattern = isAbsolute ? pattern.slice(1) : pattern;
|
|
492
|
+
const results = matchGlob(base, relPattern.split('/'), vfs);
|
|
493
|
+
if (results.length === 0)
|
|
494
|
+
return [pattern]; // no match → literal
|
|
495
|
+
return results.sort();
|
|
496
|
+
}
|
|
497
|
+
function matchGlob(dir, segments, vfs) {
|
|
498
|
+
if (segments.length === 0)
|
|
499
|
+
return [dir];
|
|
500
|
+
const [seg, ...rest] = segments;
|
|
501
|
+
if (!seg)
|
|
502
|
+
return [dir];
|
|
503
|
+
// ** matches zero or more path segments
|
|
504
|
+
if (seg === '**') {
|
|
505
|
+
const all = walkAll(dir, vfs);
|
|
506
|
+
return rest.length === 0 ? all : all.flatMap(d => {
|
|
507
|
+
try {
|
|
508
|
+
if (vfs.stat(d).type === 'directory')
|
|
509
|
+
return matchGlob(d, rest, vfs);
|
|
510
|
+
}
|
|
511
|
+
catch { }
|
|
512
|
+
return [];
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
let entries = [];
|
|
516
|
+
try {
|
|
517
|
+
entries = vfs.list(dir);
|
|
518
|
+
}
|
|
519
|
+
catch {
|
|
520
|
+
return [];
|
|
521
|
+
}
|
|
522
|
+
const re = globToRegex(seg);
|
|
523
|
+
return entries
|
|
524
|
+
.filter(e => !e.startsWith('.') || seg.startsWith('.'))
|
|
525
|
+
.filter(e => re.test(e))
|
|
526
|
+
.flatMap(e => {
|
|
527
|
+
const full = dir === '/' ? `/${e}` : `${dir}/${e}`;
|
|
528
|
+
if (rest.length === 0)
|
|
529
|
+
return [full];
|
|
530
|
+
try {
|
|
531
|
+
if (vfs.stat(full).type === 'directory')
|
|
532
|
+
return matchGlob(full, rest, vfs);
|
|
533
|
+
}
|
|
534
|
+
catch { }
|
|
535
|
+
return [];
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
function walkAll(dir, vfs) {
|
|
539
|
+
const results = [dir];
|
|
540
|
+
let entries = [];
|
|
541
|
+
try {
|
|
542
|
+
entries = vfs.list(dir);
|
|
543
|
+
}
|
|
544
|
+
catch {
|
|
545
|
+
return results;
|
|
546
|
+
}
|
|
547
|
+
for (const e of entries) {
|
|
548
|
+
const full = dir === '/' ? `/${e}` : `${dir}/${e}`;
|
|
549
|
+
try {
|
|
550
|
+
if (vfs.stat(full).type === 'directory')
|
|
551
|
+
results.push(...walkAll(full, vfs));
|
|
552
|
+
}
|
|
553
|
+
catch { }
|
|
554
|
+
}
|
|
555
|
+
return results;
|
|
556
|
+
}
|
|
557
|
+
function globToRegex(pattern) {
|
|
558
|
+
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
559
|
+
.replace(/\*/g, '.*')
|
|
560
|
+
.replace(/\?/g, '.');
|
|
561
|
+
return new RegExp(`^${escaped}$`);
|
|
562
|
+
}
|
package/package.json
CHANGED
|
@@ -4,7 +4,13 @@
|
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"version": "1.5.
|
|
7
|
+
"version": "1.5.5",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist/",
|
|
10
|
+
"README.md",
|
|
11
|
+
"LICENSE",
|
|
12
|
+
"CHANGELOG.md"
|
|
13
|
+
],
|
|
8
14
|
"license": "MIT",
|
|
9
15
|
"repository": {
|
|
10
16
|
"type": "git",
|
|
@@ -26,7 +32,7 @@
|
|
|
26
32
|
"lint:write": "bunx --bun @biomejs/biome lint --write ./src",
|
|
27
33
|
"test": "bun run test-salve",
|
|
28
34
|
"test-battery": "bun test tests/",
|
|
29
|
-
"test-salve": "for f in tests/*.test.ts; do echo \"\\n
|
|
35
|
+
"test-salve": "for f in tests/*.test.ts; do echo \"\\n\ud83e\uddea Testing $f...\"; bun test \"$f\" --timeout 10000; sleep 0.25; done",
|
|
30
36
|
"build": "tsc --project tsconfig.json",
|
|
31
37
|
"deploy:npm": "bun publish --access public",
|
|
32
38
|
"bench": "rm -rf .benchmark-shells/ && bun benchmark-virtualshell.ts",
|
|
@@ -59,4 +65,4 @@
|
|
|
59
65
|
"dependencies": {
|
|
60
66
|
"ssh2": "^1.17.0"
|
|
61
67
|
}
|
|
62
|
-
}
|
|
68
|
+
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
name: Bug report
|
|
2
|
-
description: Report a reproducible problem
|
|
3
|
-
labels: [bug]
|
|
4
|
-
body:
|
|
5
|
-
- type: markdown
|
|
6
|
-
attributes:
|
|
7
|
-
value: |
|
|
8
|
-
Thanks for reporting a bug. Please fill out the details below.
|
|
9
|
-
- type: input
|
|
10
|
-
id: version
|
|
11
|
-
attributes:
|
|
12
|
-
label: Package version
|
|
13
|
-
placeholder: 1.0.0
|
|
14
|
-
validations:
|
|
15
|
-
required: true
|
|
16
|
-
- type: input
|
|
17
|
-
id: runtime
|
|
18
|
-
attributes:
|
|
19
|
-
label: Runtime and version
|
|
20
|
-
description: Node or Bun
|
|
21
|
-
placeholder: Node 20.12.0
|
|
22
|
-
validations:
|
|
23
|
-
required: true
|
|
24
|
-
- type: textarea
|
|
25
|
-
id: reproduction
|
|
26
|
-
attributes:
|
|
27
|
-
label: Reproduction steps
|
|
28
|
-
placeholder: |
|
|
29
|
-
1. Start server with ...
|
|
30
|
-
2. Run command ...
|
|
31
|
-
3. Observe error ...
|
|
32
|
-
validations:
|
|
33
|
-
required: true
|
|
34
|
-
- type: textarea
|
|
35
|
-
id: expected
|
|
36
|
-
attributes:
|
|
37
|
-
label: Expected behavior
|
|
38
|
-
validations:
|
|
39
|
-
required: true
|
|
40
|
-
- type: textarea
|
|
41
|
-
id: actual
|
|
42
|
-
attributes:
|
|
43
|
-
label: Actual behavior
|
|
44
|
-
validations:
|
|
45
|
-
required: true
|
|
46
|
-
- type: textarea
|
|
47
|
-
id: logs
|
|
48
|
-
attributes:
|
|
49
|
-
label: Logs or stack trace
|
|
50
|
-
render: shell
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
name: Feature request
|
|
2
|
-
description: Suggest an improvement
|
|
3
|
-
labels: [enhancement]
|
|
4
|
-
body:
|
|
5
|
-
- type: markdown
|
|
6
|
-
attributes:
|
|
7
|
-
value: |
|
|
8
|
-
Thanks for proposing an improvement.
|
|
9
|
-
- type: textarea
|
|
10
|
-
id: problem
|
|
11
|
-
attributes:
|
|
12
|
-
label: Problem statement
|
|
13
|
-
description: What problem are you trying to solve?
|
|
14
|
-
validations:
|
|
15
|
-
required: true
|
|
16
|
-
- type: textarea
|
|
17
|
-
id: proposal
|
|
18
|
-
attributes:
|
|
19
|
-
label: Proposed solution
|
|
20
|
-
description: Describe the API or behavior you want.
|
|
21
|
-
validations:
|
|
22
|
-
required: true
|
|
23
|
-
- type: textarea
|
|
24
|
-
id: alternatives
|
|
25
|
-
attributes:
|
|
26
|
-
label: Alternatives considered
|
|
27
|
-
- type: textarea
|
|
28
|
-
id: impact
|
|
29
|
-
attributes:
|
|
30
|
-
label: Breaking change impact
|
|
31
|
-
description: Does this change public API behavior?
|