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.
Files changed (365) 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/VirtualPackageManager/index.js +10 -0
  5. package/dist/commands/basename.d.ts +13 -0
  6. package/dist/commands/basename.js +45 -0
  7. package/dist/commands/file.d.ts +8 -0
  8. package/dist/commands/file.js +57 -0
  9. package/dist/commands/fun.d.ts +32 -0
  10. package/dist/commands/fun.js +172 -0
  11. package/dist/commands/ifconfig.d.ts +7 -0
  12. package/dist/commands/ifconfig.js +52 -0
  13. package/dist/commands/last.d.ts +13 -0
  14. package/dist/commands/last.js +68 -0
  15. package/dist/commands/manuals-bundle.js +598 -6
  16. package/dist/commands/registry.js +24 -2
  17. package/dist/commands/runtime.js +22 -2
  18. package/dist/commands/sh.js +5 -0
  19. package/dist/commands/tput.d.ts +13 -0
  20. package/dist/commands/tput.js +76 -0
  21. package/dist/commands/w.d.ts +7 -0
  22. package/dist/commands/w.js +38 -0
  23. package/dist/utils/expand.d.ts +12 -0
  24. package/dist/utils/expand.js +84 -0
  25. package/package.json +9 -3
  26. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -50
  27. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -31
  28. package/.github/dependabot.yml +0 -27
  29. package/.github/pull_request_template.md +0 -21
  30. package/.github/workflows/create-pull-request.yml +0 -85
  31. package/.github/workflows/publish.yml +0 -25
  32. package/.github/workflows/test-battery.yml +0 -102
  33. package/.vscode/settings.json +0 -20
  34. package/CODE_OF_CONDUCT.md +0 -39
  35. package/CONTRIBUTING.md +0 -59
  36. package/HONEYPOT.md +0 -358
  37. package/SECURITY.md +0 -33
  38. package/benchmark-results.txt +0 -40
  39. package/benchmark-virtualshell.ts +0 -88
  40. package/biome.json +0 -37
  41. package/build.js +0 -22
  42. package/builds/fortune-nyx-v1.5.3-directbash-k6.1.0.mjs +0 -1764
  43. package/builds/fortune-nyx-v1.5.3-ssh-nosftp.js +0 -1764
  44. package/builds/fortune-nyx-v1.5.3-ssh.cjs +0 -1765
  45. package/builds/fortune-nyx-v1.5.3-web.min.js +0 -17036
  46. package/bun.lock +0 -244
  47. package/docs/.nojekyll +0 -1
  48. package/docs/app.js +0 -1751
  49. package/docs/assets/hierarchy.js +0 -1
  50. package/docs/assets/highlight.css +0 -162
  51. package/docs/assets/icons.js +0 -18
  52. package/docs/assets/icons.svg +0 -1
  53. package/docs/assets/main.js +0 -60
  54. package/docs/assets/navigation.js +0 -1
  55. package/docs/assets/search.js +0 -1
  56. package/docs/assets/style.css +0 -1633
  57. package/docs/classes/HoneyPot.html +0 -31
  58. package/docs/classes/IdleManager.html +0 -162
  59. package/docs/classes/SshClient.html +0 -66
  60. package/docs/classes/VirtualFileSystem.html +0 -279
  61. package/docs/classes/VirtualPackageManager.html +0 -63
  62. package/docs/classes/VirtualSftpServer.html +0 -169
  63. package/docs/classes/VirtualShell.html +0 -285
  64. package/docs/classes/VirtualSshServer.html +0 -182
  65. package/docs/classes/VirtualUserManager.html +0 -276
  66. package/docs/demo.html +0 -82
  67. package/docs/functions/assertDiff.html +0 -6
  68. package/docs/functions/diffSnapshots.html +0 -7
  69. package/docs/functions/formatDiff.html +0 -6
  70. package/docs/functions/getArg.html +0 -13
  71. package/docs/functions/getFlag.html +0 -15
  72. package/docs/functions/ifFlag.html +0 -11
  73. package/docs/hierarchy.html +0 -1
  74. package/docs/index.html +0 -1869
  75. package/docs/interfaces/AuditLogEntry.html +0 -6
  76. package/docs/interfaces/CommandContext.html +0 -22
  77. package/docs/interfaces/CommandResult.html +0 -26
  78. package/docs/interfaces/ExecStream.html +0 -11
  79. package/docs/interfaces/HoneyPotStats.html +0 -16
  80. package/docs/interfaces/IdleManagerOptions.html +0 -7
  81. package/docs/interfaces/InstalledPackage.html +0 -20
  82. package/docs/interfaces/NanoEditorSession.html +0 -8
  83. package/docs/interfaces/PackageDefinition.html +0 -30
  84. package/docs/interfaces/PackageFile.html +0 -8
  85. package/docs/interfaces/PasswordChallenge.html +0 -16
  86. package/docs/interfaces/RemoveOptions.html +0 -4
  87. package/docs/interfaces/ShellEnv.html +0 -6
  88. package/docs/interfaces/ShellModule.html +0 -14
  89. package/docs/interfaces/ShellProperties.html +0 -14
  90. package/docs/interfaces/ShellStream.html +0 -11
  91. package/docs/interfaces/SudoChallenge.html +0 -24
  92. package/docs/interfaces/VfsBaseNode.html +0 -12
  93. package/docs/interfaces/VfsDiff.html +0 -10
  94. package/docs/interfaces/VfsDiffEntry.html +0 -6
  95. package/docs/interfaces/VfsDiffModified.html +0 -10
  96. package/docs/interfaces/VfsDirectoryNode.html +0 -15
  97. package/docs/interfaces/VfsFileNode.html +0 -17
  98. package/docs/interfaces/VfsOptions.html +0 -26
  99. package/docs/interfaces/VfsSnapshot.html +0 -3
  100. package/docs/interfaces/VfsSnapshotBaseNode.html +0 -8
  101. package/docs/interfaces/VfsSnapshotDirectoryNode.html +0 -10
  102. package/docs/interfaces/VfsSnapshotFileNode.html +0 -12
  103. package/docs/interfaces/VirtualActiveSession.html +0 -12
  104. package/docs/interfaces/VirtualSftpServerOptions.html +0 -7
  105. package/docs/interfaces/VirtualShellVfsLike.html +0 -15
  106. package/docs/interfaces/VirtualShellVfsOptions.html +0 -3
  107. package/docs/interfaces/WriteFileOptions.html +0 -6
  108. package/docs/media/LICENSE +0 -21
  109. package/docs/modules.html +0 -1
  110. package/docs/types/ArgParseOptions.html +0 -4
  111. package/docs/types/CommandMode.html +0 -2
  112. package/docs/types/CommandOutcome.html +0 -2
  113. package/docs/types/IdleState.html +0 -1
  114. package/docs/types/VfsNodeStats.html +0 -2
  115. package/docs/types/VfsNodeType.html +0 -2
  116. package/docs/types/VfsPersistenceMode.html +0 -5
  117. package/docs/types/VfsSnapshotNode.html +0 -2
  118. package/examples/README.md +0 -288
  119. package/examples/app.js +0 -1751
  120. package/examples/app.ts +0 -299
  121. package/examples/build.js +0 -27
  122. package/examples/demo.html +0 -33
  123. package/examples/honeypot-audit.ts +0 -180
  124. package/examples/honeypot-export.ts +0 -253
  125. package/examples/honeypot-quickstart.ts +0 -110
  126. package/examples/index.html +0 -82
  127. package/examples/server.js +0 -55
  128. package/polyfills/buffer.js +0 -117
  129. package/polyfills/node_child_process/index.js +0 -2
  130. package/polyfills/node_crypto/index.js +0 -167
  131. package/polyfills/node_events/index.js +0 -9
  132. package/polyfills/node_fs/index.js +0 -202
  133. package/polyfills/node_fs/promises.js +0 -4
  134. package/polyfills/node_os/index.js +0 -9
  135. package/polyfills/node_path/index.js +0 -28
  136. package/polyfills/node_vm/index.js +0 -7
  137. package/polyfills/node_zlib/index.js +0 -3
  138. package/polyfills/process.js +0 -14
  139. package/polyfills/ssh2/index.js +0 -75
  140. package/scripts/build-all.mjs +0 -226
  141. package/scripts/build-names.mjs +0 -43
  142. package/scripts/generate-manuals-bundle.mjs +0 -49
  143. package/scripts/postinstall.js +0 -42
  144. package/scripts/publish-package.sh +0 -70
  145. package/src/Honeypot/index.ts +0 -457
  146. package/src/SSHClient/index.ts +0 -270
  147. package/src/SSHMimic/exec.ts +0 -49
  148. package/src/SSHMimic/executor.ts +0 -251
  149. package/src/SSHMimic/hostKey.ts +0 -21
  150. package/src/SSHMimic/index.ts +0 -337
  151. package/src/SSHMimic/loginBanner.ts +0 -36
  152. package/src/SSHMimic/loginFormat.ts +0 -10
  153. package/src/SSHMimic/prompt.ts +0 -14
  154. package/src/SSHMimic/sftp.ts +0 -883
  155. package/src/VirtualFileSystem/binaryPack.ts +0 -258
  156. package/src/VirtualFileSystem/index.ts +0 -1193
  157. package/src/VirtualFileSystem/internalTypes.ts +0 -43
  158. package/src/VirtualFileSystem/journal.ts +0 -171
  159. package/src/VirtualFileSystem/path.ts +0 -74
  160. package/src/VirtualPackageManager/index.ts +0 -996
  161. package/src/VirtualShell/idleManager.ts +0 -137
  162. package/src/VirtualShell/index.ts +0 -475
  163. package/src/VirtualShell/shell.ts +0 -700
  164. package/src/VirtualShell/shellParser.ts +0 -285
  165. package/src/VirtualUserManager/index.ts +0 -758
  166. package/src/bun.d.ts +0 -1
  167. package/src/commands/adduser.ts +0 -103
  168. package/src/commands/alias.ts +0 -69
  169. package/src/commands/apt.ts +0 -233
  170. package/src/commands/awk.ts +0 -168
  171. package/src/commands/base64.ts +0 -29
  172. package/src/commands/cat.ts +0 -52
  173. package/src/commands/cd.ts +0 -25
  174. package/src/commands/chmod.ts +0 -85
  175. package/src/commands/clear.ts +0 -15
  176. package/src/commands/command-helpers.ts +0 -286
  177. package/src/commands/cp.ts +0 -83
  178. package/src/commands/curl.ts +0 -147
  179. package/src/commands/cut.ts +0 -36
  180. package/src/commands/date.ts +0 -30
  181. package/src/commands/declare.ts +0 -49
  182. package/src/commands/deluser.ts +0 -98
  183. package/src/commands/df.ts +0 -23
  184. package/src/commands/diff.ts +0 -43
  185. package/src/commands/dpkg.ts +0 -180
  186. package/src/commands/du.ts +0 -56
  187. package/src/commands/echo.ts +0 -58
  188. package/src/commands/env.ts +0 -23
  189. package/src/commands/exit.ts +0 -18
  190. package/src/commands/export.ts +0 -34
  191. package/src/commands/find.ts +0 -68
  192. package/src/commands/free.ts +0 -47
  193. package/src/commands/grep.ts +0 -116
  194. package/src/commands/groups.ts +0 -19
  195. package/src/commands/gzip.ts +0 -88
  196. package/src/commands/head.ts +0 -52
  197. package/src/commands/help.ts +0 -152
  198. package/src/commands/helpers.ts +0 -234
  199. package/src/commands/history.ts +0 -34
  200. package/src/commands/hostname.ts +0 -14
  201. package/src/commands/htop.ts +0 -20
  202. package/src/commands/id.ts +0 -19
  203. package/src/commands/index.ts +0 -9
  204. package/src/commands/kill.ts +0 -19
  205. package/src/commands/ln.ts +0 -71
  206. package/src/commands/ls.ts +0 -243
  207. package/src/commands/lsb-release.ts +0 -63
  208. package/src/commands/man.ts +0 -31
  209. package/src/commands/manuals/adduser.txt +0 -11
  210. package/src/commands/manuals/apt-cache.txt +0 -12
  211. package/src/commands/manuals/apt.txt +0 -20
  212. package/src/commands/manuals/awk.txt +0 -13
  213. package/src/commands/manuals/cat.txt +0 -14
  214. package/src/commands/manuals/cd.txt +0 -16
  215. package/src/commands/manuals/chmod.txt +0 -16
  216. package/src/commands/manuals/clear.txt +0 -10
  217. package/src/commands/manuals/cp.txt +0 -10
  218. package/src/commands/manuals/curl.txt +0 -20
  219. package/src/commands/manuals/date.txt +0 -14
  220. package/src/commands/manuals/declare.txt +0 -12
  221. package/src/commands/manuals/deluser.txt +0 -10
  222. package/src/commands/manuals/df.txt +0 -10
  223. package/src/commands/manuals/dpkg-query.txt +0 -11
  224. package/src/commands/manuals/dpkg.txt +0 -14
  225. package/src/commands/manuals/du.txt +0 -11
  226. package/src/commands/manuals/echo.txt +0 -11
  227. package/src/commands/manuals/false.txt +0 -10
  228. package/src/commands/manuals/find.txt +0 -11
  229. package/src/commands/manuals/free.txt +0 -12
  230. package/src/commands/manuals/grep.txt +0 -13
  231. package/src/commands/manuals/groups.txt +0 -10
  232. package/src/commands/manuals/gzip.txt +0 -11
  233. package/src/commands/manuals/head.txt +0 -10
  234. package/src/commands/manuals/help.txt +0 -11
  235. package/src/commands/manuals/history.txt +0 -11
  236. package/src/commands/manuals/hostname.txt +0 -10
  237. package/src/commands/manuals/id.txt +0 -10
  238. package/src/commands/manuals/kill.txt +0 -13
  239. package/src/commands/manuals/ls.txt +0 -20
  240. package/src/commands/manuals/lsb_release.txt +0 -14
  241. package/src/commands/manuals/mkdir.txt +0 -10
  242. package/src/commands/manuals/mv.txt +0 -10
  243. package/src/commands/manuals/nano.txt +0 -11
  244. package/src/commands/manuals/neofetch.txt +0 -10
  245. package/src/commands/manuals/node.txt +0 -13
  246. package/src/commands/manuals/npm.txt +0 -13
  247. package/src/commands/manuals/npx.txt +0 -13
  248. package/src/commands/manuals/passwd.txt +0 -11
  249. package/src/commands/manuals/ping.txt +0 -10
  250. package/src/commands/manuals/printf.txt +0 -11
  251. package/src/commands/manuals/ps.txt +0 -10
  252. package/src/commands/manuals/pwd.txt +0 -10
  253. package/src/commands/manuals/python3.txt +0 -13
  254. package/src/commands/manuals/readlink.txt +0 -10
  255. package/src/commands/manuals/return.txt +0 -10
  256. package/src/commands/manuals/rm.txt +0 -10
  257. package/src/commands/manuals/sed.txt +0 -11
  258. package/src/commands/manuals/set.txt +0 -11
  259. package/src/commands/manuals/shift.txt +0 -10
  260. package/src/commands/manuals/sleep.txt +0 -10
  261. package/src/commands/manuals/sort.txt +0 -12
  262. package/src/commands/manuals/source.txt +0 -11
  263. package/src/commands/manuals/ssh.txt +0 -11
  264. package/src/commands/manuals/stat.txt +0 -10
  265. package/src/commands/manuals/su.txt +0 -13
  266. package/src/commands/manuals/sudo.txt +0 -11
  267. package/src/commands/manuals/tail.txt +0 -10
  268. package/src/commands/manuals/tar.txt +0 -19
  269. package/src/commands/manuals/tee.txt +0 -10
  270. package/src/commands/manuals/test.txt +0 -11
  271. package/src/commands/manuals/touch.txt +0 -11
  272. package/src/commands/manuals/tr.txt +0 -10
  273. package/src/commands/manuals/trap.txt +0 -10
  274. package/src/commands/manuals/true.txt +0 -10
  275. package/src/commands/manuals/type.txt +0 -10
  276. package/src/commands/manuals/uname.txt +0 -12
  277. package/src/commands/manuals/uniq.txt +0 -12
  278. package/src/commands/manuals/unset.txt +0 -10
  279. package/src/commands/manuals/uptime.txt +0 -11
  280. package/src/commands/manuals/wc.txt +0 -12
  281. package/src/commands/manuals/wget.txt +0 -12
  282. package/src/commands/manuals/which.txt +0 -10
  283. package/src/commands/manuals/whoami.txt +0 -10
  284. package/src/commands/manuals/xargs.txt +0 -10
  285. package/src/commands/manuals-bundle.ts +0 -898
  286. package/src/commands/mkdir.ts +0 -31
  287. package/src/commands/mv.ts +0 -50
  288. package/src/commands/nano.ts +0 -38
  289. package/src/commands/neofetch.ts +0 -53
  290. package/src/commands/node.ts +0 -341
  291. package/src/commands/npm.ts +0 -132
  292. package/src/commands/passwd.ts +0 -50
  293. package/src/commands/ping.ts +0 -32
  294. package/src/commands/printf.ts +0 -129
  295. package/src/commands/ps.ts +0 -58
  296. package/src/commands/pwd.ts +0 -9
  297. package/src/commands/python.ts +0 -2229
  298. package/src/commands/read.ts +0 -46
  299. package/src/commands/registry.ts +0 -249
  300. package/src/commands/rm.ts +0 -42
  301. package/src/commands/runtime.ts +0 -421
  302. package/src/commands/sed.ts +0 -68
  303. package/src/commands/seq.ts +0 -43
  304. package/src/commands/set.ts +0 -29
  305. package/src/commands/sh.ts +0 -467
  306. package/src/commands/shift.ts +0 -63
  307. package/src/commands/sleep.ts +0 -20
  308. package/src/commands/sort.ts +0 -46
  309. package/src/commands/source.ts +0 -52
  310. package/src/commands/stat.ts +0 -61
  311. package/src/commands/su.ts +0 -72
  312. package/src/commands/sudo.ts +0 -76
  313. package/src/commands/tail.ts +0 -53
  314. package/src/commands/tar.ts +0 -102
  315. package/src/commands/tee.ts +0 -36
  316. package/src/commands/test.ts +0 -137
  317. package/src/commands/touch.ts +0 -28
  318. package/src/commands/tr.ts +0 -70
  319. package/src/commands/tree.ts +0 -20
  320. package/src/commands/true.ts +0 -27
  321. package/src/commands/type.ts +0 -48
  322. package/src/commands/uname.ts +0 -29
  323. package/src/commands/uniq.ts +0 -39
  324. package/src/commands/unset.ts +0 -17
  325. package/src/commands/uptime.ts +0 -54
  326. package/src/commands/wc.ts +0 -55
  327. package/src/commands/wget.ts +0 -148
  328. package/src/commands/which.ts +0 -37
  329. package/src/commands/who.ts +0 -25
  330. package/src/commands/whoami.ts +0 -14
  331. package/src/commands/xargs.ts +0 -31
  332. package/src/index.ts +0 -67
  333. package/src/modules/linuxRootfs.ts +0 -1961
  334. package/src/modules/neofetch.ts +0 -358
  335. package/src/modules/shellInteractive.ts +0 -57
  336. package/src/modules/shellRuntime.ts +0 -76
  337. package/src/self-standalone.ts +0 -542
  338. package/src/standalone-wo-sftp.ts +0 -38
  339. package/src/standalone.ts +0 -72
  340. package/src/types/commands.ts +0 -146
  341. package/src/types/pipeline.ts +0 -52
  342. package/src/types/streams.ts +0 -32
  343. package/src/types/tar-stream.d.ts +0 -38
  344. package/src/types/vfs.ts +0 -98
  345. package/src/utils/expand.ts +0 -491
  346. package/src/utils/perfLogger.ts +0 -72
  347. package/src/utils/tokenize.ts +0 -98
  348. package/src/utils/vfsDiff.ts +0 -275
  349. package/tests/command-helpers.test.ts +0 -116
  350. package/tests/commands-admin-net.test.ts +0 -441
  351. package/tests/commands-advanced.test.ts +0 -456
  352. package/tests/commands-core.test.ts +0 -562
  353. package/tests/commands-missing.test.ts +0 -570
  354. package/tests/commands-specific-units.test.ts +0 -327
  355. package/tests/commands-text-sys.test.ts +0 -445
  356. package/tests/expand.test.ts +0 -170
  357. package/tests/helpers.test.ts +0 -97
  358. package/tests/new-features.test.ts +0 -1036
  359. package/tests/parser-executor.test.ts +0 -37
  360. package/tests/sftp.test.ts +0 -323
  361. package/tests/ssh-exec.test.ts +0 -45
  362. package/tests/test-helper.ts +0 -79
  363. package/tests/users.test.ts +0 -86
  364. package/tsconfig.json +0 -49
  365. 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
- }