typescript-virtual-container 1.5.2 → 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.
Files changed (364) hide show
  1. package/README.md +43 -23
  2. package/dist/.tsbuildinfo +1 -0
  3. package/dist/SSHMimic/executor.js +23 -5
  4. package/dist/commands/basename.d.ts +13 -0
  5. package/dist/commands/basename.js +45 -0
  6. package/dist/commands/file.d.ts +8 -0
  7. package/dist/commands/file.js +57 -0
  8. package/dist/commands/fun.d.ts +32 -0
  9. package/dist/commands/fun.js +172 -0
  10. package/dist/commands/ifconfig.d.ts +7 -0
  11. package/dist/commands/ifconfig.js +52 -0
  12. package/dist/commands/last.d.ts +13 -0
  13. package/dist/commands/last.js +68 -0
  14. package/dist/commands/manuals-bundle.js +598 -6
  15. package/dist/commands/registry.js +24 -2
  16. package/dist/commands/runtime.js +159 -106
  17. package/dist/commands/sh.js +5 -0
  18. package/dist/commands/tput.d.ts +13 -0
  19. package/dist/commands/tput.js +76 -0
  20. package/dist/commands/w.d.ts +7 -0
  21. package/dist/commands/w.js +38 -0
  22. package/dist/utils/expand.d.ts +12 -0
  23. package/dist/utils/expand.js +84 -0
  24. package/package.json +9 -3
  25. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -50
  26. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -31
  27. package/.github/dependabot.yml +0 -27
  28. package/.github/pull_request_template.md +0 -21
  29. package/.github/workflows/create-pull-request.yml +0 -85
  30. package/.github/workflows/publish.yml +0 -25
  31. package/.github/workflows/test-battery.yml +0 -102
  32. package/.vscode/settings.json +0 -20
  33. package/CODE_OF_CONDUCT.md +0 -39
  34. package/CONTRIBUTING.md +0 -59
  35. package/HONEYPOT.md +0 -358
  36. package/SECURITY.md +0 -33
  37. package/benchmark-results.txt +0 -40
  38. package/benchmark-virtualshell.ts +0 -88
  39. package/biome.json +0 -37
  40. package/build.js +0 -22
  41. package/builds/fortune-nyx-v1.5.1-directbash-k6.1.0.mjs +0 -1768
  42. package/builds/fortune-nyx-v1.5.1-ssh-nosftp.js +0 -1768
  43. package/builds/fortune-nyx-v1.5.1-ssh.cjs +0 -1769
  44. package/builds/fortune-nyx-v1.5.1-web.min.js +0 -17022
  45. package/bun.lock +0 -244
  46. package/docs/.nojekyll +0 -1
  47. package/docs/app.js +0 -1755
  48. package/docs/assets/hierarchy.js +0 -1
  49. package/docs/assets/highlight.css +0 -162
  50. package/docs/assets/icons.js +0 -18
  51. package/docs/assets/icons.svg +0 -1
  52. package/docs/assets/main.js +0 -60
  53. package/docs/assets/navigation.js +0 -1
  54. package/docs/assets/search.js +0 -1
  55. package/docs/assets/style.css +0 -1633
  56. package/docs/classes/HoneyPot.html +0 -31
  57. package/docs/classes/IdleManager.html +0 -162
  58. package/docs/classes/SshClient.html +0 -66
  59. package/docs/classes/VirtualFileSystem.html +0 -279
  60. package/docs/classes/VirtualPackageManager.html +0 -63
  61. package/docs/classes/VirtualSftpServer.html +0 -169
  62. package/docs/classes/VirtualShell.html +0 -285
  63. package/docs/classes/VirtualSshServer.html +0 -182
  64. package/docs/classes/VirtualUserManager.html +0 -276
  65. package/docs/demo.html +0 -82
  66. package/docs/functions/assertDiff.html +0 -6
  67. package/docs/functions/diffSnapshots.html +0 -7
  68. package/docs/functions/formatDiff.html +0 -6
  69. package/docs/functions/getArg.html +0 -13
  70. package/docs/functions/getFlag.html +0 -15
  71. package/docs/functions/ifFlag.html +0 -11
  72. package/docs/hierarchy.html +0 -1
  73. package/docs/index.html +0 -1869
  74. package/docs/interfaces/AuditLogEntry.html +0 -6
  75. package/docs/interfaces/CommandContext.html +0 -22
  76. package/docs/interfaces/CommandResult.html +0 -26
  77. package/docs/interfaces/ExecStream.html +0 -11
  78. package/docs/interfaces/HoneyPotStats.html +0 -16
  79. package/docs/interfaces/IdleManagerOptions.html +0 -7
  80. package/docs/interfaces/InstalledPackage.html +0 -20
  81. package/docs/interfaces/NanoEditorSession.html +0 -8
  82. package/docs/interfaces/PackageDefinition.html +0 -30
  83. package/docs/interfaces/PackageFile.html +0 -8
  84. package/docs/interfaces/PasswordChallenge.html +0 -16
  85. package/docs/interfaces/RemoveOptions.html +0 -4
  86. package/docs/interfaces/ShellEnv.html +0 -6
  87. package/docs/interfaces/ShellModule.html +0 -14
  88. package/docs/interfaces/ShellProperties.html +0 -14
  89. package/docs/interfaces/ShellStream.html +0 -11
  90. package/docs/interfaces/SudoChallenge.html +0 -24
  91. package/docs/interfaces/VfsBaseNode.html +0 -12
  92. package/docs/interfaces/VfsDiff.html +0 -10
  93. package/docs/interfaces/VfsDiffEntry.html +0 -6
  94. package/docs/interfaces/VfsDiffModified.html +0 -10
  95. package/docs/interfaces/VfsDirectoryNode.html +0 -15
  96. package/docs/interfaces/VfsFileNode.html +0 -17
  97. package/docs/interfaces/VfsOptions.html +0 -26
  98. package/docs/interfaces/VfsSnapshot.html +0 -3
  99. package/docs/interfaces/VfsSnapshotBaseNode.html +0 -8
  100. package/docs/interfaces/VfsSnapshotDirectoryNode.html +0 -10
  101. package/docs/interfaces/VfsSnapshotFileNode.html +0 -12
  102. package/docs/interfaces/VirtualActiveSession.html +0 -12
  103. package/docs/interfaces/VirtualSftpServerOptions.html +0 -7
  104. package/docs/interfaces/VirtualShellVfsLike.html +0 -15
  105. package/docs/interfaces/VirtualShellVfsOptions.html +0 -3
  106. package/docs/interfaces/WriteFileOptions.html +0 -6
  107. package/docs/media/LICENSE +0 -21
  108. package/docs/modules.html +0 -1
  109. package/docs/types/ArgParseOptions.html +0 -4
  110. package/docs/types/CommandMode.html +0 -2
  111. package/docs/types/CommandOutcome.html +0 -2
  112. package/docs/types/IdleState.html +0 -1
  113. package/docs/types/VfsNodeStats.html +0 -2
  114. package/docs/types/VfsNodeType.html +0 -2
  115. package/docs/types/VfsPersistenceMode.html +0 -5
  116. package/docs/types/VfsSnapshotNode.html +0 -2
  117. package/examples/README.md +0 -288
  118. package/examples/app.js +0 -1755
  119. package/examples/app.ts +0 -299
  120. package/examples/build.js +0 -27
  121. package/examples/demo.html +0 -33
  122. package/examples/honeypot-audit.ts +0 -180
  123. package/examples/honeypot-export.ts +0 -253
  124. package/examples/honeypot-quickstart.ts +0 -110
  125. package/examples/index.html +0 -82
  126. package/examples/server.js +0 -55
  127. package/polyfills/buffer.js +0 -117
  128. package/polyfills/node_child_process/index.js +0 -2
  129. package/polyfills/node_crypto/index.js +0 -167
  130. package/polyfills/node_events/index.js +0 -9
  131. package/polyfills/node_fs/index.js +0 -202
  132. package/polyfills/node_fs/promises.js +0 -4
  133. package/polyfills/node_os/index.js +0 -9
  134. package/polyfills/node_path/index.js +0 -28
  135. package/polyfills/node_vm/index.js +0 -7
  136. package/polyfills/node_zlib/index.js +0 -3
  137. package/polyfills/process.js +0 -14
  138. package/polyfills/ssh2/index.js +0 -75
  139. package/scripts/build-all.mjs +0 -226
  140. package/scripts/build-names.mjs +0 -43
  141. package/scripts/generate-manuals-bundle.mjs +0 -49
  142. package/scripts/postinstall.js +0 -42
  143. package/scripts/publish-package.sh +0 -70
  144. package/src/Honeypot/index.ts +0 -457
  145. package/src/SSHClient/index.ts +0 -270
  146. package/src/SSHMimic/exec.ts +0 -49
  147. package/src/SSHMimic/executor.ts +0 -251
  148. package/src/SSHMimic/hostKey.ts +0 -21
  149. package/src/SSHMimic/index.ts +0 -337
  150. package/src/SSHMimic/loginBanner.ts +0 -36
  151. package/src/SSHMimic/loginFormat.ts +0 -10
  152. package/src/SSHMimic/prompt.ts +0 -14
  153. package/src/SSHMimic/sftp.ts +0 -883
  154. package/src/VirtualFileSystem/binaryPack.ts +0 -258
  155. package/src/VirtualFileSystem/index.ts +0 -1193
  156. package/src/VirtualFileSystem/internalTypes.ts +0 -43
  157. package/src/VirtualFileSystem/journal.ts +0 -171
  158. package/src/VirtualFileSystem/path.ts +0 -74
  159. package/src/VirtualPackageManager/index.ts +0 -1006
  160. package/src/VirtualShell/idleManager.ts +0 -137
  161. package/src/VirtualShell/index.ts +0 -475
  162. package/src/VirtualShell/shell.ts +0 -700
  163. package/src/VirtualShell/shellParser.ts +0 -285
  164. package/src/VirtualUserManager/index.ts +0 -758
  165. package/src/bun.d.ts +0 -1
  166. package/src/commands/adduser.ts +0 -103
  167. package/src/commands/alias.ts +0 -69
  168. package/src/commands/apt.ts +0 -233
  169. package/src/commands/awk.ts +0 -168
  170. package/src/commands/base64.ts +0 -29
  171. package/src/commands/cat.ts +0 -52
  172. package/src/commands/cd.ts +0 -25
  173. package/src/commands/chmod.ts +0 -85
  174. package/src/commands/clear.ts +0 -15
  175. package/src/commands/command-helpers.ts +0 -286
  176. package/src/commands/cp.ts +0 -83
  177. package/src/commands/curl.ts +0 -147
  178. package/src/commands/cut.ts +0 -36
  179. package/src/commands/date.ts +0 -30
  180. package/src/commands/declare.ts +0 -49
  181. package/src/commands/deluser.ts +0 -98
  182. package/src/commands/df.ts +0 -23
  183. package/src/commands/diff.ts +0 -43
  184. package/src/commands/dpkg.ts +0 -180
  185. package/src/commands/du.ts +0 -56
  186. package/src/commands/echo.ts +0 -58
  187. package/src/commands/env.ts +0 -23
  188. package/src/commands/exit.ts +0 -18
  189. package/src/commands/export.ts +0 -34
  190. package/src/commands/find.ts +0 -68
  191. package/src/commands/free.ts +0 -47
  192. package/src/commands/grep.ts +0 -116
  193. package/src/commands/groups.ts +0 -19
  194. package/src/commands/gzip.ts +0 -88
  195. package/src/commands/head.ts +0 -52
  196. package/src/commands/help.ts +0 -152
  197. package/src/commands/helpers.ts +0 -234
  198. package/src/commands/history.ts +0 -34
  199. package/src/commands/hostname.ts +0 -14
  200. package/src/commands/htop.ts +0 -20
  201. package/src/commands/id.ts +0 -19
  202. package/src/commands/index.ts +0 -9
  203. package/src/commands/kill.ts +0 -19
  204. package/src/commands/ln.ts +0 -71
  205. package/src/commands/ls.ts +0 -243
  206. package/src/commands/lsb-release.ts +0 -63
  207. package/src/commands/man.ts +0 -31
  208. package/src/commands/manuals/adduser.txt +0 -11
  209. package/src/commands/manuals/apt-cache.txt +0 -12
  210. package/src/commands/manuals/apt.txt +0 -20
  211. package/src/commands/manuals/awk.txt +0 -13
  212. package/src/commands/manuals/cat.txt +0 -14
  213. package/src/commands/manuals/cd.txt +0 -16
  214. package/src/commands/manuals/chmod.txt +0 -16
  215. package/src/commands/manuals/clear.txt +0 -10
  216. package/src/commands/manuals/cp.txt +0 -10
  217. package/src/commands/manuals/curl.txt +0 -20
  218. package/src/commands/manuals/date.txt +0 -14
  219. package/src/commands/manuals/declare.txt +0 -12
  220. package/src/commands/manuals/deluser.txt +0 -10
  221. package/src/commands/manuals/df.txt +0 -10
  222. package/src/commands/manuals/dpkg-query.txt +0 -11
  223. package/src/commands/manuals/dpkg.txt +0 -14
  224. package/src/commands/manuals/du.txt +0 -11
  225. package/src/commands/manuals/echo.txt +0 -11
  226. package/src/commands/manuals/false.txt +0 -10
  227. package/src/commands/manuals/find.txt +0 -11
  228. package/src/commands/manuals/free.txt +0 -12
  229. package/src/commands/manuals/grep.txt +0 -13
  230. package/src/commands/manuals/groups.txt +0 -10
  231. package/src/commands/manuals/gzip.txt +0 -11
  232. package/src/commands/manuals/head.txt +0 -10
  233. package/src/commands/manuals/help.txt +0 -11
  234. package/src/commands/manuals/history.txt +0 -11
  235. package/src/commands/manuals/hostname.txt +0 -10
  236. package/src/commands/manuals/id.txt +0 -10
  237. package/src/commands/manuals/kill.txt +0 -13
  238. package/src/commands/manuals/ls.txt +0 -20
  239. package/src/commands/manuals/lsb_release.txt +0 -14
  240. package/src/commands/manuals/mkdir.txt +0 -10
  241. package/src/commands/manuals/mv.txt +0 -10
  242. package/src/commands/manuals/nano.txt +0 -11
  243. package/src/commands/manuals/neofetch.txt +0 -10
  244. package/src/commands/manuals/node.txt +0 -13
  245. package/src/commands/manuals/npm.txt +0 -13
  246. package/src/commands/manuals/npx.txt +0 -13
  247. package/src/commands/manuals/passwd.txt +0 -11
  248. package/src/commands/manuals/ping.txt +0 -10
  249. package/src/commands/manuals/printf.txt +0 -11
  250. package/src/commands/manuals/ps.txt +0 -10
  251. package/src/commands/manuals/pwd.txt +0 -10
  252. package/src/commands/manuals/python3.txt +0 -13
  253. package/src/commands/manuals/readlink.txt +0 -10
  254. package/src/commands/manuals/return.txt +0 -10
  255. package/src/commands/manuals/rm.txt +0 -10
  256. package/src/commands/manuals/sed.txt +0 -11
  257. package/src/commands/manuals/set.txt +0 -11
  258. package/src/commands/manuals/shift.txt +0 -10
  259. package/src/commands/manuals/sleep.txt +0 -10
  260. package/src/commands/manuals/sort.txt +0 -12
  261. package/src/commands/manuals/source.txt +0 -11
  262. package/src/commands/manuals/ssh.txt +0 -11
  263. package/src/commands/manuals/stat.txt +0 -10
  264. package/src/commands/manuals/su.txt +0 -13
  265. package/src/commands/manuals/sudo.txt +0 -11
  266. package/src/commands/manuals/tail.txt +0 -10
  267. package/src/commands/manuals/tar.txt +0 -19
  268. package/src/commands/manuals/tee.txt +0 -10
  269. package/src/commands/manuals/test.txt +0 -11
  270. package/src/commands/manuals/touch.txt +0 -11
  271. package/src/commands/manuals/tr.txt +0 -10
  272. package/src/commands/manuals/trap.txt +0 -10
  273. package/src/commands/manuals/true.txt +0 -10
  274. package/src/commands/manuals/type.txt +0 -10
  275. package/src/commands/manuals/uname.txt +0 -12
  276. package/src/commands/manuals/uniq.txt +0 -12
  277. package/src/commands/manuals/unset.txt +0 -10
  278. package/src/commands/manuals/uptime.txt +0 -11
  279. package/src/commands/manuals/wc.txt +0 -12
  280. package/src/commands/manuals/wget.txt +0 -12
  281. package/src/commands/manuals/which.txt +0 -10
  282. package/src/commands/manuals/whoami.txt +0 -10
  283. package/src/commands/manuals/xargs.txt +0 -10
  284. package/src/commands/manuals-bundle.ts +0 -898
  285. package/src/commands/mkdir.ts +0 -31
  286. package/src/commands/mv.ts +0 -50
  287. package/src/commands/nano.ts +0 -38
  288. package/src/commands/neofetch.ts +0 -53
  289. package/src/commands/node.ts +0 -341
  290. package/src/commands/npm.ts +0 -132
  291. package/src/commands/passwd.ts +0 -50
  292. package/src/commands/ping.ts +0 -32
  293. package/src/commands/printf.ts +0 -129
  294. package/src/commands/ps.ts +0 -58
  295. package/src/commands/pwd.ts +0 -9
  296. package/src/commands/python.ts +0 -2229
  297. package/src/commands/read.ts +0 -46
  298. package/src/commands/registry.ts +0 -249
  299. package/src/commands/rm.ts +0 -42
  300. package/src/commands/runtime.ts +0 -378
  301. package/src/commands/sed.ts +0 -68
  302. package/src/commands/seq.ts +0 -43
  303. package/src/commands/set.ts +0 -29
  304. package/src/commands/sh.ts +0 -467
  305. package/src/commands/shift.ts +0 -63
  306. package/src/commands/sleep.ts +0 -20
  307. package/src/commands/sort.ts +0 -46
  308. package/src/commands/source.ts +0 -52
  309. package/src/commands/stat.ts +0 -61
  310. package/src/commands/su.ts +0 -72
  311. package/src/commands/sudo.ts +0 -76
  312. package/src/commands/tail.ts +0 -53
  313. package/src/commands/tar.ts +0 -102
  314. package/src/commands/tee.ts +0 -36
  315. package/src/commands/test.ts +0 -137
  316. package/src/commands/touch.ts +0 -28
  317. package/src/commands/tr.ts +0 -70
  318. package/src/commands/tree.ts +0 -20
  319. package/src/commands/true.ts +0 -27
  320. package/src/commands/type.ts +0 -48
  321. package/src/commands/uname.ts +0 -29
  322. package/src/commands/uniq.ts +0 -39
  323. package/src/commands/unset.ts +0 -17
  324. package/src/commands/uptime.ts +0 -54
  325. package/src/commands/wc.ts +0 -55
  326. package/src/commands/wget.ts +0 -148
  327. package/src/commands/which.ts +0 -37
  328. package/src/commands/who.ts +0 -25
  329. package/src/commands/whoami.ts +0 -14
  330. package/src/commands/xargs.ts +0 -31
  331. package/src/index.ts +0 -67
  332. package/src/modules/linuxRootfs.ts +0 -1961
  333. package/src/modules/neofetch.ts +0 -358
  334. package/src/modules/shellInteractive.ts +0 -57
  335. package/src/modules/shellRuntime.ts +0 -76
  336. package/src/self-standalone.ts +0 -542
  337. package/src/standalone-wo-sftp.ts +0 -38
  338. package/src/standalone.ts +0 -72
  339. package/src/types/commands.ts +0 -146
  340. package/src/types/pipeline.ts +0 -52
  341. package/src/types/streams.ts +0 -32
  342. package/src/types/tar-stream.d.ts +0 -38
  343. package/src/types/vfs.ts +0 -98
  344. package/src/utils/expand.ts +0 -491
  345. package/src/utils/perfLogger.ts +0 -72
  346. package/src/utils/tokenize.ts +0 -98
  347. package/src/utils/vfsDiff.ts +0 -275
  348. package/tests/command-helpers.test.ts +0 -116
  349. package/tests/commands-admin-net.test.ts +0 -441
  350. package/tests/commands-advanced.test.ts +0 -456
  351. package/tests/commands-core.test.ts +0 -562
  352. package/tests/commands-missing.test.ts +0 -570
  353. package/tests/commands-specific-units.test.ts +0 -327
  354. package/tests/commands-text-sys.test.ts +0 -445
  355. package/tests/expand.test.ts +0 -170
  356. package/tests/helpers.test.ts +0 -97
  357. package/tests/new-features.test.ts +0 -1036
  358. package/tests/parser-executor.test.ts +0 -37
  359. package/tests/sftp.test.ts +0 -323
  360. package/tests/ssh-exec.test.ts +0 -45
  361. package/tests/test-helper.ts +0 -79
  362. package/tests/users.test.ts +0 -86
  363. package/tsconfig.json +0 -49
  364. package/typedoc.json +0 -47
@@ -1,47 +0,0 @@
1
- import * as os from "node:os";
2
- import type { ShellModule } from "../types/commands";
3
- import { ifFlag } from "./command-helpers";
4
-
5
- /**
6
- * Display memory usage information (human / MB / GB options).
7
- * @category system
8
- * @params ["[-h] [-m] [-g]"]
9
- */
10
- export const freeCommand: ShellModule = {
11
- name: "free",
12
- description: "Display amount of free and used memory",
13
- category: "system",
14
- params: ["[-h] [-m] [-g]"],
15
- run: ({ args }) => {
16
- const human = ifFlag(args, ["-h", "--human"]);
17
- const mb = ifFlag(args, ["-m"]);
18
- const gb = ifFlag(args, ["-g"]);
19
-
20
- const osTotalB = os.totalmem();
21
- const osFreeB = os.freemem();
22
- const usedB = osTotalB - osFreeB;
23
- const sharedB = Math.floor(osTotalB * 0.02);
24
- const buffersB = Math.floor(osTotalB * 0.05);
25
- const availableB = Math.floor(osFreeB * 0.95);
26
- const swapB = Math.floor(osTotalB * 0.5);
27
-
28
- const fmt = (bytes: number): string => {
29
- if (human) {
30
- if (bytes >= 1024 * 1024 * 1024)
31
- return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)}G`;
32
- if (bytes >= 1024 * 1024)
33
- return `${(bytes / (1024 * 1024)).toFixed(1)}M`;
34
- return `${(bytes / 1024).toFixed(1)}K`;
35
- }
36
- if (gb) return String(Math.floor(bytes / (1024 * 1024 * 1024)));
37
- if (mb) return String(Math.floor(bytes / (1024 * 1024)));
38
- return String(Math.floor(bytes / 1024));
39
- };
40
-
41
- const header = ` total used free shared buff/cache available`;
42
- const memRow = `Mem: ${fmt(osTotalB).padStart(12)} ${fmt(usedB).padStart(11)} ${fmt(osFreeB).padStart(11)} ${fmt(sharedB).padStart(11)} ${fmt(buffersB).padStart(11)} ${fmt(availableB).padStart(11)}`;
43
- const swapRow = `Swap: ${fmt(swapB).padStart(12)} ${fmt(0).padStart(11)} ${fmt(swapB).padStart(11)}`;
44
-
45
- return { stdout: [header, memRow, swapRow].join("\n"), exitCode: 0 };
46
- },
47
- };
@@ -1,116 +0,0 @@
1
- import type { ShellModule } from "../types/commands";
2
- import { parseArgs } from "./command-helpers";
3
- import { assertPathAccess, resolvePath } from "./helpers";
4
-
5
- /**
6
- * Search for a regex pattern in files or stdin with common flags.
7
- * @category text
8
- * @params ["[-i] [-v] [-n] [-r] <pattern> [file...]"]
9
- */
10
- export const grepCommand: ShellModule = {
11
- name: "grep",
12
- description: "Search text patterns",
13
- category: "text",
14
- params: ["[-i] [-v] [-n] [-r] <pattern> [file...]"],
15
- run: ({ authUser, shell, cwd, args, stdin }) => {
16
- const { flags, positionals } = parseArgs(args, {
17
- flags: ["-i", "-v", "-n", "-r", "-c", "-l", "-L", "-q", "--quiet", "--silent"],
18
- });
19
- const caseInsensitive = flags.has("-i");
20
- const invertMatch = flags.has("-v");
21
- const showLineNumbers = flags.has("-n");
22
- const recursive = flags.has("-r");
23
- const countOnly = flags.has("-c");
24
- const filesWithMatches = flags.has("-l");
25
- const quiet = flags.has("-q") || flags.has("--quiet") || flags.has("--silent");
26
- const pattern = positionals[0];
27
- const files = positionals.slice(1);
28
-
29
- if (!pattern) {
30
- return { stderr: "grep: no pattern specified", exitCode: 1 };
31
- }
32
-
33
- let regex: RegExp;
34
- try {
35
- // No "g" flag — avoids the stateful lastIndex problem with regex.test()
36
- const regexFlags = caseInsensitive ? "mi" : "m";
37
- regex = new RegExp(pattern, regexFlags);
38
- } catch {
39
- return { stderr: `grep: invalid regex: ${pattern}`, exitCode: 1 };
40
- }
41
-
42
- const matchLines = (content: string, prefix = ""): string[] => {
43
- const lines = content.split("\n");
44
- const out: string[] = [];
45
- for (let i = 0; i < lines.length; i++) {
46
- const line = lines[i] ?? "";
47
- const matches = regex.test(line);
48
- const shouldInclude = invertMatch ? !matches : matches;
49
- if (shouldInclude) {
50
- const lineLabel = showLineNumbers ? `${i + 1}:` : "";
51
- out.push(`${prefix}${lineLabel}${line}`);
52
- }
53
- }
54
- return out;
55
- };
56
-
57
- const readPaths = (base: string): string[] => {
58
- if (!shell.vfs.exists(base)) return [];
59
- const stat = shell.vfs.stat(base);
60
- if (stat.type === "file") return [base];
61
- if (!recursive) return [];
62
- const paths: string[] = [];
63
- const walk = (dir: string) => {
64
- for (const entry of shell.vfs.list(dir)) {
65
- const full = `${dir}/${entry}`;
66
- const s = shell.vfs.stat(full);
67
- if (s.type === "file") paths.push(full);
68
- else walk(full);
69
- }
70
- };
71
- walk(base);
72
- return paths;
73
- };
74
-
75
- const results: string[] = [];
76
-
77
- if (files.length === 0) {
78
- if (!stdin) return { stdout: "", exitCode: 1 };
79
- const matched = matchLines(stdin);
80
- if (countOnly) return { stdout: `${matched.length}\n`, exitCode: matched.length > 0 ? 0 : 1 };
81
- if (quiet) return { exitCode: matched.length > 0 ? 0 : 1 };
82
- results.push(...matched);
83
- } else {
84
- const resolvedPaths = files.flatMap((f) => {
85
- const target = resolvePath(cwd, f);
86
- return readPaths(target).map((p) => ({ file: f, path: p }));
87
- });
88
-
89
- for (const { file, path: filePath } of resolvedPaths) {
90
- try {
91
- assertPathAccess(authUser, filePath, "grep");
92
- const content = shell.vfs.readFile(filePath);
93
- const prefix = resolvedPaths.length > 1 ? `${file}:` : "";
94
- const matched = matchLines(content, prefix);
95
- if (countOnly) {
96
- results.push(resolvedPaths.length > 1 ? `${file}:${matched.length}` : String(matched.length));
97
- } else if (filesWithMatches) {
98
- if (matched.length > 0) results.push(file);
99
- } else {
100
- results.push(...matched);
101
- }
102
- } catch {
103
- return {
104
- stderr: `grep: ${file}: No such file or directory`,
105
- exitCode: 1,
106
- };
107
- }
108
- }
109
- }
110
-
111
- return {
112
- stdout: results.length > 0 ? `${results.join("\n")}\n` : "",
113
- exitCode: results.length > 0 ? 0 : 1,
114
- };
115
- },
116
- };
@@ -1,19 +0,0 @@
1
- import type { ShellModule } from "../types/commands";
2
-
3
- /**
4
- * Print group memberships for a user.
5
- * @category system
6
- * @params ["[user]"]
7
- */
8
- export const groupsCommand: ShellModule = {
9
- name: "groups",
10
- description: "Print group memberships",
11
- category: "system",
12
- params: ["[user]"],
13
- run: ({ authUser, shell, args }) => {
14
- const target = args[0] ?? authUser;
15
- const isSudo = shell.users.isSudoer(target);
16
- const grps = isSudo ? `${target} sudo root` : target;
17
- return { stdout: grps, exitCode: 0 };
18
- },
19
- };
@@ -1,88 +0,0 @@
1
- import type { ShellModule } from "../types/commands";
2
- import { resolvePath } from "./helpers";
3
-
4
- /**
5
- * Compress files using gzip — renames file to `<file>.gz`, removes original.
6
- * @category archive
7
- */
8
- export const gzipCommand: ShellModule = {
9
- name: "gzip",
10
- description: "Compress files",
11
- category: "archive",
12
- params: ["[-k] [-d] <file>"],
13
- run: ({ shell, cwd, args }) => {
14
- if (!shell.packageManager.isInstalled("gzip")) {
15
- return {
16
- stderr:
17
- "bash: gzip: command not found\nHint: install it with: apt install gzip\n",
18
- exitCode: 127,
19
- };
20
- }
21
- const keepOrig = args.includes("-k") || args.includes("--keep");
22
- const decompress = args.includes("-d");
23
- const file = args.find((a) => !a.startsWith("-"));
24
- if (!file) return { stderr: "gzip: no file specified\n", exitCode: 1 };
25
-
26
- const p = resolvePath(cwd, file);
27
-
28
- if (decompress) {
29
- // gzip -d = gunzip
30
- if (!file.endsWith(".gz")) {
31
- return { stderr: `gzip: ${file}: unknown suffix -- ignored\n`, exitCode: 1 };
32
- }
33
- if (!shell.vfs.exists(p)) {
34
- return { stderr: `gzip: ${file}: No such file or directory\n`, exitCode: 1 };
35
- }
36
- const content = shell.vfs.readFile(p);
37
- const dest = p.slice(0, -3);
38
- shell.vfs.writeFile(dest, content);
39
- if (!keepOrig) shell.vfs.remove(p);
40
- return { exitCode: 0 };
41
- }
42
-
43
- if (!shell.vfs.exists(p)) {
44
- return { stderr: `gzip: ${file}: No such file or directory\n`, exitCode: 1 };
45
- }
46
- if (file.endsWith(".gz")) {
47
- return { stderr: `gzip: ${file}: already has .gz suffix -- unchanged\n`, exitCode: 1 };
48
- }
49
-
50
- const rawContent = shell.vfs.readFileRaw(p);
51
- const gzPath = `${p}.gz`;
52
- shell.vfs.writeFile(gzPath, rawContent, { compress: true });
53
- if (!keepOrig) shell.vfs.remove(p);
54
- return { exitCode: 0 };
55
- },
56
- };
57
-
58
- /**
59
- * Decompress gzip files — renames `<file>.gz` to `<file>`, removes original.
60
- * @category archive
61
- */
62
- export const gunzipCommand: ShellModule = {
63
- name: "gunzip",
64
- description: "Decompress files",
65
- category: "archive",
66
- aliases: ["zcat"],
67
- params: ["[-k] <file>"],
68
- run: ({ shell, cwd, args }) => {
69
- const keepOrig = args.includes("-k") || args.includes("--keep");
70
- const file = args.find((a) => !a.startsWith("-"));
71
- if (!file) return { stderr: "gunzip: no file specified\n", exitCode: 1 };
72
-
73
- const p = resolvePath(cwd, file);
74
-
75
- if (!shell.vfs.exists(p)) {
76
- return { stderr: `gunzip: ${file}: No such file or directory\n`, exitCode: 1 };
77
- }
78
- if (!file.endsWith(".gz")) {
79
- return { stderr: `gunzip: ${file}: unknown suffix -- ignored\n`, exitCode: 1 };
80
- }
81
-
82
- const content = shell.vfs.readFile(p);
83
- const dest = p.slice(0, -3);
84
- shell.vfs.writeFile(dest, content);
85
- if (!keepOrig) shell.vfs.remove(p);
86
- return { exitCode: 0 };
87
- },
88
- };
@@ -1,52 +0,0 @@
1
- import type { ShellModule } from "../types/commands";
2
- import { getFlag } from "./command-helpers";
3
- import { assertPathAccess, resolvePath } from "./helpers";
4
-
5
- /**
6
- * Output the first part of files or stdin (head).
7
- * @category text
8
- * @params ["[-n <lines>] [file...]"]
9
- */
10
- export const headCommand: ShellModule = {
11
- name: "head",
12
- description: "Output first lines",
13
- category: "text",
14
- params: ["[-n <lines>] [file...]"],
15
- run: ({ authUser, shell, cwd, args, stdin }) => {
16
- const nArg = getFlag(args, ["-n"]);
17
- // Support both -n N and -N shorthand (head -2, head -10)
18
- const shortN = args.find((a) => /^-\d+$/.test(a));
19
- const n = typeof nArg === "string"
20
- ? parseInt(nArg, 10)
21
- : shortN ? parseInt(shortN.slice(1), 10) : 10;
22
- const positionals = args.filter(
23
- (a) => !a.startsWith("-") && a !== nArg && a !== String(n),
24
- );
25
-
26
- const take = (content: string) => {
27
- const lines = content.split("\n");
28
- // Preserve trailing newline
29
- const sliced = lines.slice(0, n);
30
- return sliced.join("\n") + (content.endsWith("\n") && sliced.length === lines.slice(0, n).length ? "\n" : "");
31
- };
32
-
33
- if (positionals.length === 0) {
34
- return { stdout: take(stdin ?? ""), exitCode: 0 };
35
- }
36
-
37
- const results: string[] = [];
38
- for (const file of positionals) {
39
- const filePath = resolvePath(cwd, file);
40
- try {
41
- assertPathAccess(authUser, filePath, "head");
42
- results.push(take(shell.vfs.readFile(filePath)));
43
- } catch {
44
- return {
45
- stderr: `head: ${file}: No such file or directory`,
46
- exitCode: 1,
47
- };
48
- }
49
- }
50
- return { stdout: results.join("\n"), exitCode: 0 };
51
- },
52
- };
@@ -1,152 +0,0 @@
1
- import type { ShellModule } from "../types/commands";
2
- import { getCommandModulesPublic } from "./registry";
3
-
4
- // ─── category config ──────────────────────────────────────────────────────────
5
-
6
- const CATEGORY_ORDER = [
7
- "navigation",
8
- "files",
9
- "text",
10
- "archive",
11
- "system",
12
- "package",
13
- "network",
14
- "shell",
15
- "users",
16
- "misc",
17
- ];
18
-
19
- const CATEGORY_LABELS: Record<string, string> = {
20
- navigation: "Navigation",
21
- files: "Files & Filesystem",
22
- text: "Text Processing",
23
- archive: "Archive & Compression",
24
- system: "System",
25
- package: "Package Management",
26
- network: "Network",
27
- shell: "Shell & Scripting",
28
- users: "Users & Permissions",
29
- misc: "Miscellaneous",
30
- };
31
-
32
- // ─── formatting helpers ───────────────────────────────────────────────────────
33
-
34
- const BOLD = "\x1b[1m";
35
- const RESET = "\x1b[0m";
36
- const CYAN = "\x1b[36m";
37
- const YLW = "\x1b[33m";
38
- const DIM = "\x1b[2m";
39
- const GREEN = "\x1b[32m";
40
-
41
- function pad(s: string, n: number): string {
42
- return s.length >= n ? s : s + " ".repeat(n - s.length);
43
- }
44
-
45
- function formatCmdLine(mod: ShellModule): string {
46
- const aliases = mod.aliases?.length
47
- ? ` ${DIM}(${mod.aliases.join(", ")})${RESET}`
48
- : "";
49
- return ` ${CYAN}${pad(mod.name, 16)}${RESET}${aliases}${pad("", mod.aliases?.length ? 0 : 0)} ${mod.description ?? ""}`;
50
- }
51
-
52
- // ─── full grouped listing ─────────────────────────────────────────────────────
53
-
54
- function renderFull(modules: ShellModule[]): string {
55
- const grouped: Record<string, ShellModule[]> = {};
56
- for (const mod of modules) {
57
- const cat = mod.category ?? "misc";
58
- if (!grouped[cat]) grouped[cat] = [];
59
- grouped[cat]!.push(mod);
60
- }
61
-
62
- const lines: string[] = [
63
- `${BOLD}Available commands${RESET}`,
64
- `${DIM}Type 'help <command>' for detailed usage.${RESET}`,
65
- "",
66
- ];
67
-
68
- const cats = [
69
- ...CATEGORY_ORDER.filter((c) => grouped[c]),
70
- ...Object.keys(grouped)
71
- .filter((c) => !CATEGORY_ORDER.includes(c))
72
- .sort(),
73
- ];
74
-
75
- for (const cat of cats) {
76
- const mods = grouped[cat];
77
- if (!mods?.length) continue;
78
-
79
- lines.push(`${YLW}${CATEGORY_LABELS[cat] ?? cat}${RESET}`);
80
- const sorted = [...mods].sort((a, b) => a.name.localeCompare(b.name));
81
- for (const mod of sorted) {
82
- lines.push(formatCmdLine(mod));
83
- }
84
- lines.push("");
85
- }
86
-
87
- const total = modules.length;
88
- lines.push(`${DIM}${total} commands available.${RESET}`);
89
-
90
- return lines.join("\n");
91
- }
92
-
93
- // ─── single-command detail ────────────────────────────────────────────────────
94
-
95
- function renderDetail(mod: ShellModule): string {
96
- const lines: string[] = [];
97
-
98
- lines.push(
99
- `${BOLD}${mod.name}${RESET} — ${mod.description ?? "no description"}`,
100
- );
101
-
102
- if (mod.aliases?.length) {
103
- lines.push(`${DIM}Aliases: ${mod.aliases.join(", ")}${RESET}`);
104
- }
105
-
106
- lines.push("");
107
- lines.push(`${GREEN}Usage:${RESET}`);
108
- if (mod.params.length) {
109
- for (const p of mod.params) {
110
- lines.push(` ${mod.name} ${p}`);
111
- }
112
- } else {
113
- lines.push(` ${mod.name}`);
114
- }
115
-
116
- const catLabel =
117
- CATEGORY_LABELS[mod.category ?? "misc"] ?? mod.category ?? "misc";
118
- lines.push("");
119
- lines.push(`${DIM}Category: ${catLabel}${RESET}`);
120
-
121
- return lines.join("\n");
122
- }
123
-
124
- // ─── export ───────────────────────────────────────────────────────────────────
125
-
126
- export function createHelpCommand(_getNames: () => string[]): ShellModule {
127
- return {
128
- name: "help",
129
- description: "List all commands, or show usage for a specific command",
130
- category: "shell",
131
- params: ["[command]"],
132
- run: ({ args }) => {
133
- const modules = getCommandModulesPublic();
134
-
135
- if (args[0]) {
136
- const target = args[0].toLowerCase();
137
- const mod = modules.find(
138
- (m) => m.name === target || m.aliases?.includes(target),
139
- );
140
- if (!mod) {
141
- return {
142
- stderr: `help: no help entry for '${args[0]}'`,
143
- exitCode: 1,
144
- };
145
- }
146
- return { stdout: renderDetail(mod), exitCode: 0 };
147
- }
148
-
149
- return { stdout: renderFull(modules), exitCode: 0 };
150
- },
151
- };
152
- }