typescript-virtual-container 1.2.8 → 1.3.0

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 (307) hide show
  1. package/.vscode/settings.json +0 -1
  2. package/README.md +462 -44
  3. package/biome.json +7 -0
  4. package/dist/SSHMimic/exec.d.ts.map +1 -1
  5. package/dist/SSHMimic/executor.d.ts.map +1 -1
  6. package/dist/SSHMimic/executor.js +35 -21
  7. package/dist/SSHMimic/index.d.ts.map +1 -1
  8. package/dist/SSHMimic/index.js +20 -6
  9. package/dist/VirtualFileSystem/binaryPack.d.ts.map +1 -1
  10. package/dist/VirtualFileSystem/binaryPack.js +29 -6
  11. package/dist/VirtualFileSystem/index.d.ts.map +1 -1
  12. package/dist/VirtualFileSystem/index.js +36 -13
  13. package/dist/VirtualPackageManager/index.d.ts +202 -0
  14. package/dist/VirtualPackageManager/index.d.ts.map +1 -0
  15. package/dist/VirtualPackageManager/index.js +825 -0
  16. package/dist/VirtualShell/index.d.ts +93 -12
  17. package/dist/VirtualShell/index.d.ts.map +1 -1
  18. package/dist/VirtualShell/index.js +95 -13
  19. package/dist/VirtualShell/shell.d.ts.map +1 -1
  20. package/dist/VirtualShell/shell.js +3 -1
  21. package/dist/VirtualShell/shellParser.d.ts.map +1 -1
  22. package/dist/VirtualUserManager/index.d.ts +52 -20
  23. package/dist/VirtualUserManager/index.d.ts.map +1 -1
  24. package/dist/VirtualUserManager/index.js +54 -20
  25. package/dist/commands/adduser.d.ts +6 -0
  26. package/dist/commands/adduser.d.ts.map +1 -1
  27. package/dist/commands/adduser.js +6 -0
  28. package/dist/commands/alias.d.ts +9 -0
  29. package/dist/commands/alias.d.ts.map +1 -0
  30. package/dist/commands/alias.js +63 -0
  31. package/dist/commands/apt.d.ts +9 -0
  32. package/dist/commands/apt.d.ts.map +1 -0
  33. package/dist/commands/apt.js +205 -0
  34. package/dist/commands/awk.d.ts +11 -0
  35. package/dist/commands/awk.d.ts.map +1 -1
  36. package/dist/commands/awk.js +15 -2
  37. package/dist/commands/base64.d.ts +5 -0
  38. package/dist/commands/base64.d.ts.map +1 -1
  39. package/dist/commands/base64.js +9 -1
  40. package/dist/commands/cat.d.ts +5 -0
  41. package/dist/commands/cat.d.ts.map +1 -1
  42. package/dist/commands/cat.js +35 -8
  43. package/dist/commands/cd.d.ts +5 -0
  44. package/dist/commands/cd.d.ts.map +1 -1
  45. package/dist/commands/cd.js +5 -0
  46. package/dist/commands/chmod.d.ts +5 -0
  47. package/dist/commands/chmod.d.ts.map +1 -1
  48. package/dist/commands/chmod.js +57 -3
  49. package/dist/commands/command-helpers.d.ts +78 -4
  50. package/dist/commands/command-helpers.d.ts.map +1 -1
  51. package/dist/commands/command-helpers.js +78 -4
  52. package/dist/commands/cp.d.ts +5 -0
  53. package/dist/commands/cp.d.ts.map +1 -1
  54. package/dist/commands/cp.js +5 -0
  55. package/dist/commands/curl.d.ts +5 -0
  56. package/dist/commands/curl.d.ts.map +1 -1
  57. package/dist/commands/curl.js +106 -26
  58. package/dist/commands/cut.d.ts +5 -0
  59. package/dist/commands/cut.d.ts.map +1 -1
  60. package/dist/commands/cut.js +8 -1
  61. package/dist/commands/date.d.ts +5 -0
  62. package/dist/commands/date.d.ts.map +1 -1
  63. package/dist/commands/date.js +7 -1
  64. package/dist/commands/declare.d.ts +3 -0
  65. package/dist/commands/declare.d.ts.map +1 -0
  66. package/dist/commands/declare.js +39 -0
  67. package/dist/commands/diff.d.ts +5 -0
  68. package/dist/commands/diff.d.ts.map +1 -1
  69. package/dist/commands/diff.js +5 -0
  70. package/dist/commands/dpkg.d.ts +9 -0
  71. package/dist/commands/dpkg.d.ts.map +1 -0
  72. package/dist/commands/dpkg.js +161 -0
  73. package/dist/commands/du.d.ts.map +1 -1
  74. package/dist/commands/du.js +8 -2
  75. package/dist/commands/echo.d.ts +5 -0
  76. package/dist/commands/echo.d.ts.map +1 -1
  77. package/dist/commands/echo.js +33 -12
  78. package/dist/commands/env.d.ts +5 -0
  79. package/dist/commands/env.d.ts.map +1 -1
  80. package/dist/commands/env.js +11 -1
  81. package/dist/commands/exit.d.ts +5 -0
  82. package/dist/commands/exit.d.ts.map +1 -1
  83. package/dist/commands/exit.js +12 -2
  84. package/dist/commands/export.d.ts.map +1 -1
  85. package/dist/commands/export.js +3 -1
  86. package/dist/commands/find.d.ts +5 -0
  87. package/dist/commands/find.d.ts.map +1 -1
  88. package/dist/commands/find.js +5 -0
  89. package/dist/commands/free.d.ts +8 -0
  90. package/dist/commands/free.d.ts.map +1 -0
  91. package/dist/commands/free.js +43 -0
  92. package/dist/commands/grep.d.ts +5 -0
  93. package/dist/commands/grep.d.ts.map +1 -1
  94. package/dist/commands/grep.js +12 -2
  95. package/dist/commands/gzip.d.ts +5 -0
  96. package/dist/commands/gzip.d.ts.map +1 -1
  97. package/dist/commands/gzip.js +18 -2
  98. package/dist/commands/head.d.ts +5 -0
  99. package/dist/commands/head.d.ts.map +1 -1
  100. package/dist/commands/head.js +5 -0
  101. package/dist/commands/help.d.ts.map +1 -1
  102. package/dist/commands/help.js +98 -45
  103. package/dist/commands/helpers.d.ts +3 -0
  104. package/dist/commands/helpers.d.ts.map +1 -1
  105. package/dist/commands/helpers.js +3 -0
  106. package/dist/commands/history.d.ts +8 -0
  107. package/dist/commands/history.d.ts.map +1 -0
  108. package/dist/commands/history.js +26 -0
  109. package/dist/commands/hostname.d.ts +5 -0
  110. package/dist/commands/hostname.d.ts.map +1 -1
  111. package/dist/commands/hostname.js +5 -0
  112. package/dist/commands/id.d.ts.map +1 -1
  113. package/dist/commands/id.js +4 -1
  114. package/dist/commands/index.d.ts +2 -10
  115. package/dist/commands/index.d.ts.map +1 -1
  116. package/dist/commands/index.js +2 -231
  117. package/dist/commands/ls.d.ts.map +1 -1
  118. package/dist/commands/ls.js +6 -3
  119. package/dist/commands/lsb-release.d.ts +3 -0
  120. package/dist/commands/lsb-release.d.ts.map +1 -0
  121. package/dist/commands/lsb-release.js +56 -0
  122. package/dist/commands/man.d.ts +3 -0
  123. package/dist/commands/man.d.ts.map +1 -0
  124. package/dist/commands/man.js +155 -0
  125. package/dist/commands/nano.js +1 -1
  126. package/dist/commands/neofetch.d.ts.map +1 -1
  127. package/dist/commands/neofetch.js +6 -1
  128. package/dist/commands/node.d.ts +9 -0
  129. package/dist/commands/node.d.ts.map +1 -0
  130. package/dist/commands/node.js +316 -0
  131. package/dist/commands/npm.d.ts +19 -0
  132. package/dist/commands/npm.d.ts.map +1 -0
  133. package/dist/commands/npm.js +109 -0
  134. package/dist/commands/ping.d.ts.map +1 -1
  135. package/dist/commands/ping.js +7 -2
  136. package/dist/commands/printf.d.ts +3 -0
  137. package/dist/commands/printf.d.ts.map +1 -0
  138. package/dist/commands/printf.js +113 -0
  139. package/dist/commands/ps.d.ts.map +1 -1
  140. package/dist/commands/ps.js +30 -6
  141. package/dist/commands/python.d.ts +30 -0
  142. package/dist/commands/python.d.ts.map +1 -0
  143. package/dist/commands/python.js +2058 -0
  144. package/dist/commands/read.d.ts +3 -0
  145. package/dist/commands/read.d.ts.map +1 -0
  146. package/dist/commands/read.js +34 -0
  147. package/dist/commands/registry.d.ts +8 -0
  148. package/dist/commands/registry.d.ts.map +1 -0
  149. package/dist/commands/registry.js +229 -0
  150. package/dist/commands/runtime.d.ts +6 -0
  151. package/dist/commands/runtime.d.ts.map +1 -0
  152. package/dist/commands/runtime.js +280 -0
  153. package/dist/commands/sed.d.ts.map +1 -1
  154. package/dist/commands/sed.js +11 -3
  155. package/dist/commands/set.d.ts.map +1 -1
  156. package/dist/commands/set.js +9 -3
  157. package/dist/commands/sh.d.ts.map +1 -1
  158. package/dist/commands/sh.js +69 -30
  159. package/dist/commands/shift.d.ts +5 -0
  160. package/dist/commands/shift.d.ts.map +1 -0
  161. package/dist/commands/shift.js +52 -0
  162. package/dist/commands/sleep.d.ts.map +1 -1
  163. package/dist/commands/sort.d.ts.map +1 -1
  164. package/dist/commands/sort.js +4 -2
  165. package/dist/commands/source.d.ts +3 -0
  166. package/dist/commands/source.d.ts.map +1 -0
  167. package/dist/commands/source.js +34 -0
  168. package/dist/commands/sudo.js +1 -1
  169. package/dist/commands/tar.d.ts.map +1 -1
  170. package/dist/commands/tar.js +11 -3
  171. package/dist/commands/tee.d.ts.map +1 -1
  172. package/dist/commands/tee.js +8 -6
  173. package/dist/commands/test.d.ts +3 -0
  174. package/dist/commands/test.d.ts.map +1 -0
  175. package/dist/commands/test.js +114 -0
  176. package/dist/commands/tr.d.ts.map +1 -1
  177. package/dist/commands/tr.js +3 -1
  178. package/dist/commands/true.d.ts +4 -0
  179. package/dist/commands/true.d.ts.map +1 -0
  180. package/dist/commands/true.js +14 -0
  181. package/dist/commands/type.d.ts +3 -0
  182. package/dist/commands/type.d.ts.map +1 -0
  183. package/dist/commands/type.js +34 -0
  184. package/dist/commands/uname.d.ts.map +1 -1
  185. package/dist/commands/uname.js +4 -1
  186. package/dist/commands/uniq.d.ts.map +1 -1
  187. package/dist/commands/uptime.d.ts +3 -0
  188. package/dist/commands/uptime.d.ts.map +1 -0
  189. package/dist/commands/uptime.js +43 -0
  190. package/dist/commands/wget.d.ts.map +1 -1
  191. package/dist/commands/wget.js +92 -96
  192. package/dist/commands/which.d.ts +3 -0
  193. package/dist/commands/which.d.ts.map +1 -0
  194. package/dist/commands/which.js +32 -0
  195. package/dist/commands/xargs.d.ts.map +1 -1
  196. package/dist/commands/xargs.js +1 -1
  197. package/dist/index.d.ts +15 -11
  198. package/dist/index.d.ts.map +1 -1
  199. package/dist/index.js +9 -8
  200. package/dist/modules/linuxRootfs.d.ts +41 -0
  201. package/dist/modules/linuxRootfs.d.ts.map +1 -0
  202. package/dist/modules/linuxRootfs.js +440 -0
  203. package/dist/modules/neofetch.d.ts.map +1 -1
  204. package/dist/modules/neofetch.js +1 -0
  205. package/dist/standalone-wo-sftp.d.ts +2 -0
  206. package/dist/standalone-wo-sftp.d.ts.map +1 -0
  207. package/dist/standalone-wo-sftp.js +30 -0
  208. package/dist/utils/expand.d.ts +50 -0
  209. package/dist/utils/expand.d.ts.map +1 -0
  210. package/dist/utils/expand.js +183 -0
  211. package/dist/utils/vfsDiff.d.ts +90 -0
  212. package/dist/utils/vfsDiff.d.ts.map +1 -0
  213. package/dist/utils/vfsDiff.js +177 -0
  214. package/package.json +3 -1
  215. package/src/SSHMimic/exec.ts +10 -1
  216. package/src/SSHMimic/executor.ts +105 -21
  217. package/src/SSHMimic/index.ts +49 -15
  218. package/src/VirtualFileSystem/binaryPack.ts +35 -8
  219. package/src/VirtualFileSystem/index.ts +78 -28
  220. package/src/VirtualPackageManager/index.ts +979 -0
  221. package/src/VirtualShell/index.ts +133 -14
  222. package/src/VirtualShell/shell.ts +23 -3
  223. package/src/VirtualShell/shellParser.ts +134 -36
  224. package/src/VirtualUserManager/index.ts +62 -22
  225. package/src/commands/adduser.ts +6 -0
  226. package/src/commands/alias.ts +64 -0
  227. package/src/commands/apt.ts +228 -0
  228. package/src/commands/awk.ts +20 -6
  229. package/src/commands/base64.ts +13 -2
  230. package/src/commands/cat.ts +40 -8
  231. package/src/commands/cd.ts +5 -0
  232. package/src/commands/chmod.ts +53 -3
  233. package/src/commands/command-helpers.ts +78 -4
  234. package/src/commands/cp.ts +5 -0
  235. package/src/commands/curl.ts +118 -33
  236. package/src/commands/cut.ts +8 -1
  237. package/src/commands/date.ts +7 -1
  238. package/src/commands/declare.ts +44 -0
  239. package/src/commands/diff.ts +17 -3
  240. package/src/commands/dpkg.ts +180 -0
  241. package/src/commands/du.ts +17 -5
  242. package/src/commands/echo.ts +41 -12
  243. package/src/commands/env.ts +11 -1
  244. package/src/commands/exit.ts +12 -2
  245. package/src/commands/export.ts +3 -1
  246. package/src/commands/find.ts +5 -0
  247. package/src/commands/free.ts +47 -0
  248. package/src/commands/grep.ts +12 -2
  249. package/src/commands/gzip.ts +28 -4
  250. package/src/commands/head.ts +5 -0
  251. package/src/commands/help.ts +121 -47
  252. package/src/commands/helpers.ts +8 -0
  253. package/src/commands/history.ts +34 -0
  254. package/src/commands/hostname.ts +5 -0
  255. package/src/commands/id.ts +4 -1
  256. package/src/commands/index.ts +9 -255
  257. package/src/commands/ls.ts +6 -3
  258. package/src/commands/lsb-release.ts +58 -0
  259. package/src/commands/man.ts +166 -0
  260. package/src/commands/nano.ts +1 -1
  261. package/src/commands/neofetch.ts +6 -1
  262. package/src/commands/node.ts +341 -0
  263. package/src/commands/npm.ts +132 -0
  264. package/src/commands/ping.ts +10 -3
  265. package/src/commands/printf.ts +112 -0
  266. package/src/commands/ps.ts +40 -6
  267. package/src/commands/python.ts +2229 -0
  268. package/src/commands/read.ts +41 -0
  269. package/src/commands/registry.ts +244 -0
  270. package/src/commands/runtime.ts +353 -0
  271. package/src/commands/sed.ts +27 -9
  272. package/src/commands/set.ts +9 -3
  273. package/src/commands/sh.ts +170 -44
  274. package/src/commands/shift.ts +53 -0
  275. package/src/commands/sleep.ts +2 -1
  276. package/src/commands/sort.ts +10 -6
  277. package/src/commands/source.ts +47 -0
  278. package/src/commands/sudo.ts +1 -1
  279. package/src/commands/tar.ts +28 -7
  280. package/src/commands/tee.ts +7 -1
  281. package/src/commands/test.ts +135 -0
  282. package/src/commands/tr.ts +3 -1
  283. package/src/commands/true.ts +17 -0
  284. package/src/commands/type.ts +43 -0
  285. package/src/commands/uname.ts +5 -1
  286. package/src/commands/uniq.ts +8 -2
  287. package/src/commands/uptime.ts +49 -0
  288. package/src/commands/wget.ts +105 -119
  289. package/src/commands/which.ts +37 -0
  290. package/src/commands/xargs.ts +11 -2
  291. package/src/index.ts +27 -18
  292. package/src/modules/linuxRootfs.ts +642 -0
  293. package/src/modules/neofetch.ts +1 -0
  294. package/src/standalone-wo-sftp.ts +38 -0
  295. package/src/utils/expand.ts +238 -0
  296. package/src/utils/vfsDiff.ts +275 -0
  297. package/standalone-wo-sftp.js +507 -0
  298. package/standalone-wo-sftp.js.map +7 -0
  299. package/standalone.js +486 -109
  300. package/standalone.js.map +4 -4
  301. package/tests/bun-test-shim.ts +9 -1
  302. package/tests/command-helpers.test.ts +1 -5
  303. package/tests/new-features.test.ts +1036 -0
  304. package/tests/parser-executor.test.ts +27 -27
  305. package/tests/sftp.test.ts +122 -42
  306. package/tests/users.test.ts +23 -5
  307. package/CHANGELOG.md +0 -150
@@ -0,0 +1,132 @@
1
+ /**
2
+ * npm.ts — Virtual npm command.
3
+ * Gated behind `apt install npm`. Provides version info and informative
4
+ * stubs for common subcommands.
5
+ */
6
+ import type { ShellModule } from "../types/commands";
7
+ import { ifFlag } from "./command-helpers";
8
+
9
+ const NPM_VERSION = "9.2.0";
10
+ const NODE_VERSION = "18.19.0";
11
+
12
+ /**
13
+ * `npm` virtual CLI. Requires `apt install npm` in the virtual package manager.
14
+ * @category system
15
+ * @params ["<command> [args]"]
16
+ */
17
+ export const npmCommand: ShellModule = {
18
+ name: "npm",
19
+ description: "Node.js package manager (virtual)",
20
+ category: "system",
21
+ params: ["<command> [args]"],
22
+ run: ({ args, shell }) => {
23
+ // Require explicit installation
24
+ if (!shell.packageManager.isInstalled("npm")) {
25
+ return {
26
+ stderr:
27
+ "bash: npm: command not found\nHint: install it with: apt install npm\n",
28
+ exitCode: 127,
29
+ };
30
+ }
31
+
32
+ if (ifFlag(args, ["--version", "-v"])) {
33
+ return { stdout: `${NPM_VERSION}\n`, exitCode: 0 };
34
+ }
35
+
36
+ const sub = args[0]?.toLowerCase();
37
+
38
+ switch (sub) {
39
+ case "version":
40
+ case "-version":
41
+ return {
42
+ stdout: `{ npm: '${NPM_VERSION}', node: '${NODE_VERSION}', v8: '10.2.154.26' }\n`,
43
+ exitCode: 0,
44
+ };
45
+
46
+ case "install":
47
+ case "i":
48
+ case "add":
49
+ return {
50
+ stderr:
51
+ "npm warn: package installation is not available in the virtual runtime.\nnpm warn: This environment simulates npm CLI behaviour only.\n",
52
+ exitCode: 1,
53
+ };
54
+
55
+ case "run":
56
+ case "exec":
57
+ case "x":
58
+ return {
59
+ stderr: `npm error: script execution is not available in the virtual runtime.\n`,
60
+ exitCode: 1,
61
+ };
62
+
63
+ case "init":
64
+ return {
65
+ stdout: "Wrote to /home/user/package.json\n",
66
+ exitCode: 0,
67
+ };
68
+
69
+ case "list":
70
+ case "ls":
71
+ return {
72
+ stdout: `${sub === "ls" || sub === "list" ? "virtual-env@1.0.0" : ""}\n└── (empty)\n`,
73
+ exitCode: 0,
74
+ };
75
+
76
+ case "help":
77
+ case undefined:
78
+ return {
79
+ stdout: `${[
80
+ `npm ${NPM_VERSION}`,
81
+ "",
82
+ "Usage: npm <command>",
83
+ "",
84
+ "Commands:",
85
+ " install (not available in virtual runtime)",
86
+ " run (not available in virtual runtime)",
87
+ " exec (not available in virtual runtime)",
88
+ " list List installed packages",
89
+ " version Print versions",
90
+ " --version Print npm version",
91
+ ].join("\n")}\n`,
92
+ exitCode: 0,
93
+ };
94
+
95
+ default:
96
+ return {
97
+ stderr: `npm error: unknown command: ${sub}\n`,
98
+ exitCode: 1,
99
+ };
100
+ }
101
+ },
102
+ };
103
+
104
+ /**
105
+ * `npx` virtual runner. Requires `apt install npm` in the virtual package manager.
106
+ * @category system
107
+ * @params ["<package> [args]"]
108
+ */
109
+ export const npxCommand: ShellModule = {
110
+ name: "npx",
111
+ description: "Node.js package runner (virtual)",
112
+ category: "system",
113
+ params: ["<package> [args]"],
114
+ run: ({ args, shell }) => {
115
+ if (!shell.packageManager.isInstalled("npm")) {
116
+ return {
117
+ stderr:
118
+ "bash: npx: command not found\nHint: install it with: apt install npm\n",
119
+ exitCode: 127,
120
+ };
121
+ }
122
+
123
+ if (ifFlag(args, ["--version"])) {
124
+ return { stdout: `${NPM_VERSION}\n`, exitCode: 0 };
125
+ }
126
+
127
+ return {
128
+ stderr: `npx: package execution is not available in the virtual runtime.\n`,
129
+ exitCode: 1,
130
+ };
131
+ },
132
+ };
@@ -1,4 +1,5 @@
1
1
  import type { ShellModule } from "../types/commands";
2
+ import { parseArgs } from "./command-helpers";
2
3
 
3
4
  export const pingCommand: ShellModule = {
4
5
  name: "ping",
@@ -6,15 +7,21 @@ export const pingCommand: ShellModule = {
6
7
  category: "network",
7
8
  params: ["[-c <count>] <host>"],
8
9
  run: ({ args }) => {
9
- const host = args.find((a) => !a.startsWith("-")) ?? "localhost";
10
- const count = 4;
10
+ const { flagsWithValues, positionals } = parseArgs(args, {
11
+ flagsWithValue: ["-c", "-i", "-W"],
12
+ });
13
+ const host = positionals[0] ?? "localhost";
14
+ const countArg = flagsWithValues.get("-c");
15
+ const count = countArg ? Math.max(1, parseInt(countArg, 10) || 4) : 4;
11
16
  const lines = [`PING ${host}: 56 data bytes`];
12
17
  for (let i = 0; i < count; i++) {
13
18
  const ms = (Math.random() * 10 + 1).toFixed(3);
14
19
  lines.push(`64 bytes from ${host}: icmp_seq=${i} ttl=64 time=${ms} ms`);
15
20
  }
16
21
  lines.push(`--- ${host} ping statistics ---`);
17
- lines.push(`${count} packets transmitted, ${count} received, 0% packet loss`);
22
+ lines.push(
23
+ `${count} packets transmitted, ${count} received, 0% packet loss`,
24
+ );
18
25
  return { stdout: lines.join("\n"), exitCode: 0 };
19
26
  },
20
27
  };
@@ -0,0 +1,112 @@
1
+ import type { ShellModule } from "../types/commands";
2
+
3
+ /**
4
+ * Render a printf format string with given arguments.
5
+ * Supports: %s %d %i %f %o %x %X %% \n \t \r \\
6
+ */
7
+ function renderPrintf(fmt: string, args: string[]): string {
8
+ let argIdx = 0;
9
+ let out = "";
10
+ let i = 0;
11
+ while (i < fmt.length) {
12
+ if (fmt[i] === "\\" && i + 1 < fmt.length) {
13
+ switch (fmt[i + 1]) {
14
+ case "n":
15
+ out += "\n";
16
+ i += 2;
17
+ continue;
18
+ case "t":
19
+ out += "\t";
20
+ i += 2;
21
+ continue;
22
+ case "r":
23
+ out += "\r";
24
+ i += 2;
25
+ continue;
26
+ case "\\":
27
+ out += "\\";
28
+ i += 2;
29
+ continue;
30
+ case "a":
31
+ out += "\x07";
32
+ i += 2;
33
+ continue;
34
+ case "b":
35
+ out += "\x08";
36
+ i += 2;
37
+ continue;
38
+ case "f":
39
+ out += "\x0C";
40
+ i += 2;
41
+ continue;
42
+ case "v":
43
+ out += "\x0B";
44
+ i += 2;
45
+ continue;
46
+ default:
47
+ out += fmt[i]!;
48
+ i++;
49
+ continue;
50
+ }
51
+ }
52
+ if (fmt[i] === "%" && i + 1 < fmt.length) {
53
+ // Optional width/precision: %[-][width][.prec]spec
54
+ let j = i + 1;
55
+ if (fmt[j] === "-") j++;
56
+ while (j < fmt.length && /\d/.test(fmt[j]!)) j++;
57
+ if (fmt[j] === ".") {
58
+ j++;
59
+ while (j < fmt.length && /\d/.test(fmt[j]!)) j++;
60
+ }
61
+ const spec = fmt[j];
62
+ const arg = args[argIdx++] ?? "";
63
+ switch (spec) {
64
+ case "s":
65
+ out += arg;
66
+ break;
67
+ case "d":
68
+ case "i":
69
+ out += String(parseInt(arg, 10) || 0);
70
+ break;
71
+ case "f":
72
+ out += String(parseFloat(arg) || 0);
73
+ break;
74
+ case "o":
75
+ out += (parseInt(arg, 10) || 0).toString(8);
76
+ break;
77
+ case "x":
78
+ out += (parseInt(arg, 10) || 0).toString(16);
79
+ break;
80
+ case "X":
81
+ out += (parseInt(arg, 10) || 0).toString(16).toUpperCase();
82
+ break;
83
+ case "%":
84
+ out += "%";
85
+ argIdx--;
86
+ break;
87
+ default:
88
+ out += fmt[i]!;
89
+ i++;
90
+ continue;
91
+ }
92
+ i = j + 1;
93
+ continue;
94
+ }
95
+ out += fmt[i]!;
96
+ i++;
97
+ }
98
+ return out;
99
+ }
100
+
101
+ export const printfCommand: ShellModule = {
102
+ name: "printf",
103
+ description: "Format and print data",
104
+ category: "shell",
105
+ params: ["<format> [args...]"],
106
+ run: ({ args }) => {
107
+ const fmt = args[0];
108
+ if (!fmt) return { stderr: "printf: missing format string", exitCode: 1 };
109
+ const output = renderPrintf(fmt, args.slice(1));
110
+ return { stdout: output, exitCode: 0 };
111
+ },
112
+ };
@@ -1,19 +1,53 @@
1
1
  import type { ShellModule } from "../types/commands";
2
+ import { ifFlag } from "./command-helpers";
2
3
 
3
4
  export const psCommand: ShellModule = {
4
5
  name: "ps",
5
6
  description: "Report process status",
6
7
  category: "system",
7
- params: ["[-a] [-u] [-x]"],
8
- run: ({ authUser, shell }) => {
8
+ params: ["[-a] [-u] [-x] [aux]"],
9
+ run: ({ authUser, shell, args }) => {
9
10
  const sessions = shell.users.listActiveSessions();
10
- const lines = [" PID TTY TIME CMD"];
11
+ const showUser =
12
+ ifFlag(args, ["-u"]) ||
13
+ args.includes("u") ||
14
+ args.includes("aux") ||
15
+ args.includes("au");
16
+ const showAll =
17
+ ifFlag(args, ["-a", "-x"]) || args.includes("a") || args.includes("aux");
18
+
19
+ if (showUser) {
20
+ const header =
21
+ "USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND";
22
+ const rows: string[] = [header];
23
+ let pid = 1000;
24
+ for (const s of sessions) {
25
+ const user = s.username.padEnd(10).slice(0, 10);
26
+ const mem = (Math.random() * 0.5).toFixed(1);
27
+ const vsz = Math.floor(Math.random() * 20000 + 5000);
28
+ const rss = Math.floor(Math.random() * 5000 + 1000);
29
+ rows.push(
30
+ `${user} ${String(pid).padStart(6)} 0.0 ${mem.padStart(4)} ${String(vsz).padStart(6)} ${String(rss).padStart(5)} ${s.tty.padEnd(8)} Ss 00:00 0:00 bash`,
31
+ );
32
+ pid++;
33
+ }
34
+ rows.push(
35
+ `root ${String(pid).padStart(6)} 0.0 0.0 0 0 ? S 00:00 0:00 ps`,
36
+ );
37
+ return { stdout: rows.join("\n"), exitCode: 0 };
38
+ }
39
+
40
+ const header = " PID TTY TIME CMD";
41
+ const rows: string[] = [header];
11
42
  let pid = 1000;
12
43
  for (const s of sessions) {
13
- lines.push(`${String(pid).padStart(5)} ${s.tty.padEnd(12)} 00:00:00 ${s.username === authUser ? "bash" : `bash (${s.username})`}`);
44
+ if (!showAll && s.username !== authUser) continue;
45
+ rows.push(
46
+ `${String(pid).padStart(5)} ${s.tty.padEnd(12)} 00:00:00 ${s.username === authUser ? "bash" : `bash (${s.username})`}`,
47
+ );
14
48
  pid++;
15
49
  }
16
- lines.push(`${String(pid).padStart(5)} pts/0 00:00:00 ps`);
17
- return { stdout: lines.join("\n"), exitCode: 0 };
50
+ rows.push(`${String(pid).padStart(5)} pts/0 00:00:00 ps`);
51
+ return { stdout: rows.join("\n"), exitCode: 0 };
18
52
  },
19
53
  };