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,440 @@
1
+ /** biome-ignore-all lint/style/useNamingConvention: ENV VAR KEYS */
2
+ /**
3
+ * linuxRootfs.ts
4
+ *
5
+ * Bootstraps a realistic Linux directory hierarchy in the VFS.
6
+ * Called once during VirtualShell initialization. Idempotent — skips
7
+ * paths that already exist so FS-mode snapshots survive restarts.
8
+ */
9
+ import * as os from "node:os";
10
+ // ─── helpers ────────────────────────────────────────────────────────────────
11
+ function ensureDir(vfs, path, mode = 0o755) {
12
+ if (!vfs.exists(path))
13
+ vfs.mkdir(path, mode);
14
+ }
15
+ function ensureFile(vfs, path, content, mode = 0o644) {
16
+ if (!vfs.exists(path))
17
+ vfs.writeFile(path, content, { mode });
18
+ }
19
+ // ─── /etc ────────────────────────────────────────────────────────────────────
20
+ function bootstrapEtc(vfs, hostname, props) {
21
+ ensureDir(vfs, "/etc");
22
+ // os-release — authoritative distro identity used by neofetch, lsb_release
23
+ ensureFile(vfs, "/etc/os-release", `${[
24
+ `NAME="Fortune GNU/Linux"`,
25
+ `PRETTY_NAME="${props.os}"`,
26
+ `ID=fortune`,
27
+ `ID_LIKE=debian`,
28
+ `HOME_URL="https://github.com/itsrealfortune/typescript-virtual-container"`,
29
+ `VERSION_CODENAME=aurora`,
30
+ `VERSION_ID="1.0"`,
31
+ ].join("\n")}\n`);
32
+ ensureFile(vfs, "/etc/debian_version", "12.0\n");
33
+ ensureFile(vfs, "/etc/hostname", `${hostname}\n`);
34
+ ensureFile(vfs, "/etc/shells", "/bin/sh\n/bin/bash\n/usr/bin/bash\n");
35
+ ensureFile(vfs, "/etc/profile", `${[
36
+ "export PATH=/usr/local/bin:/usr/bin:/bin",
37
+ "export PS1='\\u@\\h:\\w\\$ '",
38
+ ].join("\n")}\n`);
39
+ ensureFile(vfs, "/etc/issue", `Fortune GNU/Linux 1.0 \\n \\l\n`);
40
+ ensureFile(vfs, "/etc/motd", ["", `Welcome to ${props.os}`, `Kernel: ${props.kernel}`, ""].join("\n"));
41
+ // APT sources
42
+ ensureDir(vfs, "/etc/apt");
43
+ ensureDir(vfs, "/etc/apt/sources.list.d");
44
+ ensureFile(vfs, "/etc/apt/sources.list", `${[
45
+ "# Fortune GNU/Linux package sources",
46
+ "deb [virtual] fortune://packages.fortune.local aurora main contrib",
47
+ "deb [virtual] fortune://security.fortune.local aurora-security main",
48
+ ].join("\n")}\n`);
49
+ // network stubs
50
+ ensureDir(vfs, "/etc/network");
51
+ ensureFile(vfs, "/etc/network/interfaces", `${[
52
+ "auto lo",
53
+ "iface lo inet loopback",
54
+ "",
55
+ "auto eth0",
56
+ "iface eth0 inet dhcp",
57
+ ].join("\n")}\n`);
58
+ ensureFile(vfs, "/etc/resolv.conf", "nameserver 1.1.1.1\nnameserver 8.8.8.8\n");
59
+ ensureFile(vfs, "/etc/hosts", `${[
60
+ "127.0.0.1 localhost",
61
+ `127.0.1.1 ${hostname}`,
62
+ "::1 localhost ip6-localhost ip6-loopback",
63
+ ].join("\n")}\n`);
64
+ ensureDir(vfs, "/etc/cron.d");
65
+ ensureDir(vfs, "/etc/init.d");
66
+ ensureDir(vfs, "/etc/systemd");
67
+ ensureDir(vfs, "/etc/systemd/system");
68
+ }
69
+ // ─── /etc/passwd + /etc/group + /etc/shadow ─────────────────────────────────
70
+ /**
71
+ * Sync `/etc/passwd`, `/etc/group`, and `/etc/shadow` from the
72
+ * VirtualUserManager's current user list into the VFS.
73
+ * @param vfs VirtualFileSystem instance to write files into
74
+ * @param users VirtualUserManager to source users from
75
+ */
76
+ export function syncEtcPasswd(vfs, users) {
77
+ const userList = users.listUsers();
78
+ const passwdLines = [
79
+ "root:x:0:0:root:/root:/bin/bash",
80
+ "daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin",
81
+ "www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin",
82
+ "nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin",
83
+ ];
84
+ let uid = 1000;
85
+ for (const u of userList) {
86
+ if (u === "root")
87
+ continue;
88
+ passwdLines.push(`${u}:x:${uid}:${uid}::/home/${u}:/bin/bash`);
89
+ uid++;
90
+ }
91
+ vfs.writeFile("/etc/passwd", `${passwdLines.join("\n")}\n`);
92
+ const groupLines = [
93
+ "root:x:0:",
94
+ "daemon:x:1:",
95
+ `sudo:x:27:${userList.filter((u) => users.isSudoer(u)).join(",")}`,
96
+ `users:x:100:${userList.filter((u) => u !== "root").join(",")}`,
97
+ "nogroup:x:65534:",
98
+ ];
99
+ vfs.writeFile("/etc/group", `${groupLines.join("\n")}\n`);
100
+ // shadow — fake hashes, never real
101
+ const shadowLines = [
102
+ "root:*:19000:0:99999:7:::",
103
+ "daemon:*:19000:0:99999:7:::",
104
+ ];
105
+ for (const u of userList) {
106
+ if (u === "root")
107
+ continue;
108
+ shadowLines.push(`${u}:!:19000:0:99999:7:::`);
109
+ }
110
+ vfs.writeFile("/etc/shadow", `${shadowLines.join("\n")}\n`, { mode: 0o640 });
111
+ }
112
+ // ─── /proc ───────────────────────────────────────────────────────────────────
113
+ /** Derive a stable virtual PID from a tty string like "pts/0" → 1000, "pts/1" → 1001 */
114
+ function ttyToPid(tty) {
115
+ const match = tty.match(/(\d+)$/);
116
+ return 1000 + (match?.[1] ? parseInt(match[1], 10) : 0);
117
+ }
118
+ /** Write /proc/<pid>/ subtree for a single virtual process */
119
+ function writeProcPid(vfs, pid, username, _tty, cmdline, startedAt, env) {
120
+ const dir = `/proc/${pid}`;
121
+ ensureDir(vfs, dir);
122
+ ensureDir(vfs, `${dir}/fd`);
123
+ ensureDir(vfs, `${dir}/fdinfo`);
124
+ const uptimeSec = Math.floor((Date.now() - new Date(startedAt).getTime()) / 1000);
125
+ vfs.writeFile(`${dir}/cmdline`, `${cmdline.replace(/\s+/g, "\0")}\0`);
126
+ vfs.writeFile(`${dir}/comm`, cmdline.split(/\s+/)[0] ?? "bash");
127
+ vfs.writeFile(`${dir}/status`, `${[
128
+ `Name: ${cmdline.split(/\s+/)[0] ?? "bash"}`,
129
+ `State: S (sleeping)`,
130
+ `Pid: ${pid}`,
131
+ `PPid: 1`,
132
+ `Uid: 0\t0\t0\t0`,
133
+ `Gid: 0\t0\t0\t0`,
134
+ `VmRSS: 4096 kB`,
135
+ `VmSize: 16384 kB`,
136
+ `Threads: 1`,
137
+ ].join("\n")}\n`);
138
+ vfs.writeFile(`${dir}/stat`, `${pid} (${cmdline.split(/\s+/)[0] ?? "bash"}) S 1 ${pid} ${pid} 0 -1 4194304 0 0 0 0 ${uptimeSec} 0 0 0 20 0 1 0 0 16384 4096 0\n`);
139
+ vfs.writeFile(`${dir}/environ`, `${Object.entries(env)
140
+ .map(([k, v]) => `${k}=${v}`)
141
+ .join("\0")}\0`);
142
+ vfs.writeFile(`${dir}/cwd`, `/home/${username}\0`);
143
+ vfs.writeFile(`${dir}/exe`, "/bin/bash\0");
144
+ // Standard fd entries
145
+ vfs.writeFile(`${dir}/fd/0`, "");
146
+ vfs.writeFile(`${dir}/fd/1`, "");
147
+ vfs.writeFile(`${dir}/fd/2`, "");
148
+ }
149
+ /**
150
+ * Populate and refresh `/proc` virtual entries based on host stats and
151
+ * provided active sessions. Rewrites `/proc/uptime`, `/proc/meminfo`,
152
+ * `/proc/cpuinfo`, `/proc/<pid>` entries and `/proc/self` content.
153
+ * @param vfs VirtualFileSystem instance
154
+ * @param props ShellProperties used for version strings
155
+ * @param hostname Hostname to write into /proc/hostname
156
+ * @param shellStartTime Start time used to compute uptime
157
+ * @param sessions Optional active sessions list to populate per-pid entries
158
+ */
159
+ export function refreshProc(vfs, props, hostname, shellStartTime, sessions) {
160
+ ensureDir(vfs, "/proc");
161
+ const uptimeSec = Math.floor((Date.now() - shellStartTime) / 1000);
162
+ vfs.writeFile("/proc/uptime", `${uptimeSec}.00 ${Math.floor(uptimeSec * 0.9)}.00\n`);
163
+ const totalMemKb = Math.floor(os.totalmem() / 1024);
164
+ const freeMemKb = Math.floor(os.freemem() / 1024);
165
+ const availMemKb = Math.floor(freeMemKb * 0.95);
166
+ vfs.writeFile("/proc/meminfo", `${[
167
+ `MemTotal: ${String(totalMemKb).padStart(10)} kB`,
168
+ `MemFree: ${String(freeMemKb).padStart(10)} kB`,
169
+ `MemAvailable: ${String(availMemKb).padStart(10)} kB`,
170
+ `Buffers: ${String(Math.floor(totalMemKb * 0.02)).padStart(10)} kB`,
171
+ `Cached: ${String(Math.floor(totalMemKb * 0.15)).padStart(10)} kB`,
172
+ `SwapTotal: ${String(Math.floor(totalMemKb * 0.5)).padStart(10)} kB`,
173
+ `SwapFree: ${String(Math.floor(totalMemKb * 0.5)).padStart(10)} kB`,
174
+ ].join("\n")}\n`);
175
+ const cpus = os.cpus();
176
+ const cpuLines = [];
177
+ for (let i = 0; i < cpus.length; i++) {
178
+ const c = cpus[i];
179
+ if (!c)
180
+ continue;
181
+ const mhz = c.speed.toFixed(3);
182
+ cpuLines.push(`processor\t: ${i}`, `model name\t: ${c.model}`, `cpu MHz\t\t: ${mhz}`, `cache size\t: 8192 KB`, "");
183
+ }
184
+ vfs.writeFile("/proc/cpuinfo", `${cpuLines.join("\n")}\n`);
185
+ vfs.writeFile("/proc/version", `Linux version ${props.kernel} (fortune@build) (gcc version 12.2.0) #1 SMP\n`);
186
+ vfs.writeFile("/proc/hostname", `${hostname}\n`);
187
+ // /proc/loadavg
188
+ const load = (Math.random() * 0.5).toFixed(2);
189
+ const numProcs = 1 + (sessions?.length ?? 0);
190
+ vfs.writeFile("/proc/loadavg", `${load} ${load} ${load} ${numProcs}/${numProcs} 1\n`);
191
+ // /proc/net stubs
192
+ ensureDir(vfs, "/proc/net");
193
+ ensureFile(vfs, "/proc/net/dev", `${[
194
+ "Inter-| Receive | Transmit",
195
+ " face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed",
196
+ " lo: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0",
197
+ " eth0: 131072 1024 0 0 0 0 0 0 65536 512 0 0 0 0 0 0",
198
+ ].join("\n")}\n`);
199
+ // ── /proc/1 — init process ────────────────────────────────────────────────
200
+ writeProcPid(vfs, 1, "root", "pts/0", "/sbin/init", new Date(shellStartTime).toISOString(), {});
201
+ // ── /proc/<pid> per session ───────────────────────────────────────────────
202
+ const activeSessions = sessions ?? [];
203
+ for (const session of activeSessions) {
204
+ const pid = ttyToPid(session.tty);
205
+ writeProcPid(vfs, pid, session.username, session.tty, "bash", session.startedAt, {
206
+ USER: session.username,
207
+ HOME: `/home/${session.username}`,
208
+ TERM: "xterm-256color",
209
+ SHELL: "/bin/bash",
210
+ });
211
+ }
212
+ // ── /proc/self — symlink to current session PID or 1 ────────────────────
213
+ // We can't know which session is "current" at populate time,
214
+ // so /proc/self is a directory that mirrors the most recent session,
215
+ // or init if no sessions. Commands that read /proc/self get consistent data.
216
+ const selfPid = activeSessions.length > 0
217
+ ? ttyToPid(activeSessions[activeSessions.length - 1].tty)
218
+ : 1;
219
+ // Remove existing /proc/self and recreate as content copy
220
+ if (vfs.exists("/proc/self")) {
221
+ try {
222
+ vfs.remove("/proc/self");
223
+ }
224
+ catch { }
225
+ }
226
+ // /proc/self is a real directory (not a symlink, which VFS may not support for dirs)
227
+ const selfSrc = `/proc/${selfPid}`;
228
+ if (vfs.exists(selfSrc)) {
229
+ ensureDir(vfs, "/proc/self");
230
+ ensureDir(vfs, "/proc/self/fd");
231
+ for (const entry of vfs.list(selfSrc)) {
232
+ const srcPath = `${selfSrc}/${entry}`;
233
+ const dstPath = `/proc/self/${entry}`;
234
+ try {
235
+ const st = vfs.stat(srcPath);
236
+ if (st.type === "file") {
237
+ vfs.writeFile(dstPath, vfs.readFile(srcPath));
238
+ }
239
+ }
240
+ catch { }
241
+ }
242
+ vfs.writeFile("/proc/self/status", vfs.exists(`${selfSrc}/status`) ? vfs.readFile(`${selfSrc}/status`) : "");
243
+ }
244
+ else {
245
+ // Fallback minimal /proc/self
246
+ ensureDir(vfs, "/proc/self");
247
+ vfs.writeFile("/proc/self/cmdline", "bash\0");
248
+ vfs.writeFile("/proc/self/comm", "bash");
249
+ vfs.writeFile("/proc/self/status", "Name:\tbash\nState:\tS (sleeping)\nPid:\t1\nPPid:\t0\n");
250
+ vfs.writeFile("/proc/self/environ", "");
251
+ vfs.writeFile("/proc/self/cwd", "/root\0");
252
+ vfs.writeFile("/proc/self/exe", "/bin/bash\0");
253
+ }
254
+ }
255
+ // ─── /sys ─────────────────────────────────────────────────────────────────────
256
+ function bootstrapSys(vfs, props) {
257
+ ensureDir(vfs, "/sys");
258
+ ensureDir(vfs, "/sys/devices");
259
+ ensureDir(vfs, "/sys/devices/virtual");
260
+ ensureDir(vfs, "/sys/devices/virtual/dmi");
261
+ ensureDir(vfs, "/sys/devices/virtual/dmi/id");
262
+ ensureFile(vfs, "/sys/devices/virtual/dmi/id/sys_vendor", "Fortune Systems\n");
263
+ ensureFile(vfs, "/sys/devices/virtual/dmi/id/product_name", "VirtualContainer v1\n");
264
+ ensureFile(vfs, "/sys/devices/virtual/dmi/id/board_name", "fortune-board\n");
265
+ ensureDir(vfs, "/sys/class");
266
+ ensureDir(vfs, "/sys/class/net");
267
+ ensureDir(vfs, "/sys/kernel");
268
+ ensureFile(vfs, "/sys/kernel/hostname", "fortune-vm\n");
269
+ ensureFile(vfs, "/sys/kernel/osrelease", `${props.kernel}\n`);
270
+ ensureFile(vfs, "/sys/kernel/ostype", "Linux\n");
271
+ }
272
+ // ─── /dev ─────────────────────────────────────────────────────────────────────
273
+ function bootstrapDev(vfs) {
274
+ ensureDir(vfs, "/dev");
275
+ ensureFile(vfs, "/dev/null", "", 0o666);
276
+ ensureFile(vfs, "/dev/zero", "", 0o666);
277
+ ensureFile(vfs, "/dev/random", "", 0o444);
278
+ ensureFile(vfs, "/dev/urandom", "", 0o444);
279
+ ensureDir(vfs, "/dev/pts");
280
+ ensureDir(vfs, "/dev/shm");
281
+ }
282
+ // ─── /usr ─────────────────────────────────────────────────────────────────────
283
+ function bootstrapUsr(vfs) {
284
+ ensureDir(vfs, "/usr");
285
+ ensureDir(vfs, "/usr/bin");
286
+ ensureDir(vfs, "/usr/sbin");
287
+ ensureDir(vfs, "/usr/local");
288
+ ensureDir(vfs, "/usr/local/bin");
289
+ ensureDir(vfs, "/usr/local/lib");
290
+ ensureDir(vfs, "/usr/local/share");
291
+ ensureDir(vfs, "/usr/share");
292
+ ensureDir(vfs, "/usr/share/doc");
293
+ ensureDir(vfs, "/usr/share/man");
294
+ ensureDir(vfs, "/usr/share/man/man1");
295
+ ensureDir(vfs, "/usr/lib");
296
+ // Stub binaries so `which` can find built-in commands
297
+ const builtins = [
298
+ "sh",
299
+ "bash",
300
+ "ls",
301
+ "cat",
302
+ "echo",
303
+ "grep",
304
+ "find",
305
+ "sort",
306
+ "head",
307
+ "tail",
308
+ "cut",
309
+ "tr",
310
+ "sed",
311
+ "awk",
312
+ "wc",
313
+ "tee",
314
+ "tar",
315
+ "gzip",
316
+ "gunzip",
317
+ "touch",
318
+ "mkdir",
319
+ "rm",
320
+ "mv",
321
+ "cp",
322
+ "chmod",
323
+ "ln",
324
+ "pwd",
325
+ "env",
326
+ "date",
327
+ "sleep",
328
+ "id",
329
+ "whoami",
330
+ "hostname",
331
+ "uname",
332
+ "ps",
333
+ "kill",
334
+ "df",
335
+ "du",
336
+ "curl",
337
+ "wget",
338
+ "nano",
339
+ "diff",
340
+ "uniq",
341
+ "xargs",
342
+ "base64",
343
+ ];
344
+ for (const bin of builtins) {
345
+ ensureFile(vfs, `/usr/bin/${bin}`, `#!/bin/sh\nexec builtin ${bin} "$@"\n`, 0o755);
346
+ }
347
+ // lsb_release script
348
+ ensureFile(vfs, "/usr/bin/lsb_release", '#!/bin/sh\nexec lsb_release "$@"\n', 0o755);
349
+ }
350
+ // ─── /var ─────────────────────────────────────────────────────────────────────
351
+ function bootstrapVar(vfs) {
352
+ ensureDir(vfs, "/var");
353
+ ensureDir(vfs, "/var/log");
354
+ ensureDir(vfs, "/var/tmp");
355
+ ensureDir(vfs, "/var/run");
356
+ ensureDir(vfs, "/var/cache");
357
+ ensureDir(vfs, "/var/cache/apt");
358
+ ensureDir(vfs, "/var/cache/apt/archives");
359
+ ensureDir(vfs, "/var/lib");
360
+ ensureDir(vfs, "/var/lib/apt");
361
+ ensureDir(vfs, "/var/lib/apt/lists");
362
+ ensureDir(vfs, "/var/lib/dpkg");
363
+ ensureDir(vfs, "/var/lib/dpkg/info");
364
+ // dpkg status — starts empty, apt install populates it
365
+ ensureFile(vfs, "/var/lib/dpkg/status", "");
366
+ ensureFile(vfs, "/var/lib/dpkg/available", "");
367
+ // syslog stub
368
+ ensureFile(vfs, "/var/log/syslog", `${new Date().toUTCString()} fortune kernel: Virtual container started\n`);
369
+ ensureFile(vfs, "/var/log/auth.log", "");
370
+ ensureFile(vfs, "/var/log/dpkg.log", "");
371
+ ensureFile(vfs, "/var/log/apt/history.log", "");
372
+ ensureFile(vfs, "/var/log/apt/term.log", "");
373
+ }
374
+ // ─── /bin + /sbin symlinks ────────────────────────────────────────────────────
375
+ function bootstrapBin(vfs) {
376
+ // On modern Debian/Ubuntu /bin is a symlink to /usr/bin
377
+ if (!vfs.exists("/bin")) {
378
+ vfs.symlink("/usr/bin", "/bin");
379
+ }
380
+ if (!vfs.exists("/sbin")) {
381
+ vfs.symlink("/usr/sbin", "/sbin");
382
+ }
383
+ if (!vfs.exists("/lib")) {
384
+ ensureDir(vfs, "/lib");
385
+ }
386
+ if (!vfs.exists("/lib64")) {
387
+ ensureDir(vfs, "/lib64");
388
+ }
389
+ }
390
+ // ─── /tmp ─────────────────────────────────────────────────────────────────────
391
+ function bootstrapTmp(vfs) {
392
+ ensureDir(vfs, "/tmp", 0o1777);
393
+ }
394
+ // ─── /root ────────────────────────────────────────────────────────────────────
395
+ function bootstrapRoot(vfs) {
396
+ ensureDir(vfs, "/root", 0o700);
397
+ ensureFile(vfs, "/root/.bashrc", `${[
398
+ "# root .bashrc",
399
+ "export PS1='\\[\\033[0;31m\\]\\u@\\h\\[\\033[0m\\]:\\[\\033[0;34m\\]\\w\\[\\033[0m\\]# '",
400
+ "export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
401
+ "alias ll='ls -la'",
402
+ "alias la='ls -A'",
403
+ ].join("\n")}\n`);
404
+ ensureFile(vfs, "/root/.profile", "[ -f ~/.bashrc ] && . ~/.bashrc\n");
405
+ // Fix: /home/root should map to /root for root user
406
+ if (!vfs.exists("/home/root")) {
407
+ vfs.symlink("/root", "/home/root");
408
+ }
409
+ }
410
+ // ─── /opt + /srv + /mnt + /media ─────────────────────────────────────────────
411
+ function bootstrapMisc(vfs) {
412
+ ensureDir(vfs, "/opt");
413
+ ensureDir(vfs, "/srv");
414
+ ensureDir(vfs, "/mnt");
415
+ ensureDir(vfs, "/media");
416
+ }
417
+ // ─── main entry point ─────────────────────────────────────────────────────────
418
+ /**
419
+ * Bootstraps the full Linux rootfs hierarchy in the VFS.
420
+ * Safe to call multiple times — idempotent.
421
+ *
422
+ * @param vfs Target virtual filesystem.
423
+ * @param users User manager (for /etc/passwd sync).
424
+ * @param hostname Virtual hostname.
425
+ * @param props Shell properties (kernel, os, arch).
426
+ * @param shellStartTime Unix ms of shell creation (for uptime).
427
+ */
428
+ export function bootstrapLinuxRootfs(vfs, users, hostname, props, shellStartTime) {
429
+ bootstrapEtc(vfs, hostname, props);
430
+ bootstrapSys(vfs, props);
431
+ bootstrapDev(vfs);
432
+ bootstrapUsr(vfs);
433
+ bootstrapVar(vfs);
434
+ bootstrapBin(vfs);
435
+ bootstrapTmp(vfs);
436
+ bootstrapRoot(vfs);
437
+ bootstrapMisc(vfs);
438
+ refreshProc(vfs, props, hostname, shellStartTime, []);
439
+ syncEtcPasswd(vfs, users);
440
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"neofetch.d.ts","sourceRoot":"","sources":["../../src/modules/neofetch.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAsGvD,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAkKD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CA0E9D"}
1
+ {"version":3,"file":"neofetch.d.ts","sourceRoot":"","sources":["../../src/modules/neofetch.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAsGvD,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAkKD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CA2E9D"}
@@ -255,6 +255,7 @@ export function buildNeofetchOutput(info) {
255
255
  `Kernel: ${fields.kernel}`,
256
256
  `Uptime: ${uptime}`,
257
257
  // `Packages: ${fields.packages}`,
258
+ `Packages: ${fields.packages}`,
258
259
  `Shell: ${fields.shell}`,
259
260
  // `Shell Props: ${fields.shellProps}`,
260
261
  `Resolution: ${fields.resolution}`,
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=standalone-wo-sftp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"standalone-wo-sftp.d.ts","sourceRoot":"","sources":["../src/standalone-wo-sftp.ts"],"names":[],"mappings":""}
@@ -0,0 +1,30 @@
1
+ import { SshMimic } from "./SSHMimic/index";
2
+ import { VirtualShell } from "./VirtualShell";
3
+ const hostname = process.env.SSH_MIMIC_HOSTNAME ?? "typescript-vm";
4
+ const virtualShell = new VirtualShell(hostname, undefined, {
5
+ mode: "fs",
6
+ snapshotPath: ".vfs",
7
+ });
8
+ virtualShell.addCommand("demo", [], () => {
9
+ return {
10
+ stdout: "This is a demo command. It does nothing useful.",
11
+ exitCode: 0,
12
+ };
13
+ });
14
+ new SshMimic({
15
+ port: 2222,
16
+ hostname,
17
+ shell: virtualShell,
18
+ })
19
+ .start()
20
+ .catch((error) => {
21
+ console.error("Failed to start SSH Mimic:", error);
22
+ process.exit(1);
23
+ });
24
+ process.on("uncaughtException", (error) => {
25
+ console.log("Oh my god, something terrible happened: ", error);
26
+ });
27
+ process.on("unhandledRejection", (error, promise) => {
28
+ console.log(" Oh Lord! We forgot to handle a promise rejection here: ", promise);
29
+ console.log(" The error was: ", error);
30
+ });
@@ -0,0 +1,50 @@
1
+ /**
2
+ * expand.ts
3
+ *
4
+ * Centralised shell variable and expression expansion.
5
+ * Used by `runCommand` (index.ts), `echo`, and `sh.ts`.
6
+ *
7
+ * Handles (in order):
8
+ * ~ tilde to $HOME
9
+ * $? last exit code
10
+ * $$ mock PID
11
+ * $# argument count (0 outside scripts)
12
+ * ${#VAR} string length
13
+ * ${VAR:-def} default if unset/empty
14
+ * ${VAR:=def} assign default if unset/empty
15
+ * ${VAR:+val} alternate value if set
16
+ * ${VAR} simple braced reference
17
+ * $VAR simple reference
18
+ * $((expr)) arithmetic (integer)
19
+ */
20
+ /**
21
+ * Evaluate a simple integer arithmetic expression.
22
+ * Supports: + - * / % ** unary- ( )
23
+ * Variables are resolved from `env` before evaluation.
24
+ * Returns NaN on syntax error.
25
+ */
26
+ export declare function evalArith(expr: string, env: Record<string, string>): number;
27
+ /**
28
+ * Expand all shell variable and expression forms synchronously.
29
+ * Does NOT handle `$(cmd)` — that requires async; see `expandAsync`.
30
+ * Content inside single quotes is left verbatim per POSIX sh rules.
31
+ *
32
+ * @param input Raw string possibly containing `$VAR`, `${...}`, `$((...))`.
33
+ * @param env Current session env vars.
34
+ * @param lastExit Last command exit code (for `$?`).
35
+ * @param home Home directory path (for `~`).
36
+ */
37
+ export declare function expandSync(input: string, env: Record<string, string>, lastExit?: number, home?: string): string;
38
+ /**
39
+ * Expand all shell forms including `$(cmd)` command substitution.
40
+ *
41
+ * Processes `$(...)` blocks depth-first, respecting single-quote boundaries.
42
+ * Then delegates to `expandSync` for the remaining forms.
43
+ *
44
+ * @param input Raw string.
45
+ * @param env Current session env vars.
46
+ * @param lastExit Last exit code.
47
+ * @param runCmd Async callback to execute a command and return its stdout.
48
+ */
49
+ export declare function expandAsync(input: string, env: Record<string, string>, lastExit: number, runCmd: (cmd: string) => Promise<string>): Promise<string>;
50
+ //# sourceMappingURL=expand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expand.d.ts","sourceRoot":"","sources":["../../src/utils/expand.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAuB3E;AAoCD;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CACzB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC3B,QAAQ,SAAI,EACZ,IAAI,CAAC,EAAE,MAAM,GACX,MAAM,CA4DR;AAID;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAChC,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC3B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GACtC,OAAO,CAAC,MAAM,CAAC,CAuDjB"}