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