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
@@ -1,3 +1,9 @@
1
1
  import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * Add a new user to the virtual user database.
4
+ * @category users
5
+ * @params ["<username> <password>"]
6
+ * @returns ShellModule
7
+ */
2
8
  export declare const adduserCommand: ShellModule;
3
9
  //# sourceMappingURL=adduser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"adduser.d.ts","sourceRoot":"","sources":["../../src/commands/adduser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,eAAO,MAAM,cAAc,EAAE,WAqB5B,CAAC"}
1
+ {"version":3,"file":"adduser.d.ts","sourceRoot":"","sources":["../../src/commands/adduser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;;;GAKG;AACH,eAAO,MAAM,cAAc,EAAE,WAqB5B,CAAC"}
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Add a new user to the virtual user database.
3
+ * @category users
4
+ * @params ["<username> <password>"]
5
+ * @returns ShellModule
6
+ */
1
7
  export const adduserCommand = {
2
8
  name: "adduser",
3
9
  description: "Add a new user",
@@ -0,0 +1,9 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * Manage shell aliases (list / set / remove).
4
+ * @category shell
5
+ * @params ["[name[=value] ...]"]
6
+ */
7
+ export declare const aliasCommand: ShellModule;
8
+ export declare const unaliasCommand: ShellModule;
9
+ //# sourceMappingURL=alias.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alias.d.ts","sourceRoot":"","sources":["../../src/commands/alias.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,WAkC1B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,WAoB5B,CAAC"}
@@ -0,0 +1,63 @@
1
+ import { ifFlag } from "./command-helpers";
2
+ /**
3
+ * Manage shell aliases (list / set / remove).
4
+ * @category shell
5
+ * @params ["[name[=value] ...]"]
6
+ */
7
+ export const aliasCommand = {
8
+ name: "alias",
9
+ description: "Define or display aliases",
10
+ category: "shell",
11
+ params: ["[name[=value] ...]"],
12
+ run: ({ args, env }) => {
13
+ if (!env)
14
+ return { exitCode: 0 };
15
+ // Aliases stored in env.vars under prefix __alias_
16
+ if (args.length === 0) {
17
+ const aliases = Object.entries(env.vars)
18
+ .filter(([k]) => k.startsWith("__alias_"))
19
+ .map(([k, v]) => `alias ${k.slice("__alias_".length)}='${v}'`);
20
+ return { stdout: aliases.join("\n") || "", exitCode: 0 };
21
+ }
22
+ const lines = [];
23
+ for (const arg of args) {
24
+ const eq = arg.indexOf("=");
25
+ if (eq === -1) {
26
+ // Display single alias
27
+ const val = env.vars[`__alias_${arg}`];
28
+ if (val)
29
+ lines.push(`alias ${arg}='${val}'`);
30
+ else
31
+ return { stderr: `alias: ${arg}: not found`, exitCode: 1 };
32
+ }
33
+ else {
34
+ // Set alias
35
+ const name = arg.slice(0, eq);
36
+ const val = arg.slice(eq + 1).replace(/^['"]|['"]$/g, "");
37
+ env.vars[`__alias_${name}`] = val;
38
+ }
39
+ }
40
+ return { stdout: lines.join("\n") || undefined, exitCode: 0 };
41
+ },
42
+ };
43
+ export const unaliasCommand = {
44
+ name: "unalias",
45
+ description: "Remove alias definitions",
46
+ category: "shell",
47
+ params: ["<name...> | -a"],
48
+ run: ({ args, env }) => {
49
+ if (!env)
50
+ return { exitCode: 0 };
51
+ if (ifFlag(args, ["-a"])) {
52
+ for (const k of Object.keys(env.vars)) {
53
+ if (k.startsWith("__alias_"))
54
+ delete env.vars[k];
55
+ }
56
+ return { exitCode: 0 };
57
+ }
58
+ for (const name of args) {
59
+ delete env.vars[`__alias_${name}`];
60
+ }
61
+ return { exitCode: 0 };
62
+ },
63
+ };
@@ -0,0 +1,9 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * APT package manager front-end (simulated).
4
+ * @category package
5
+ * @params ["<install|remove|update|upgrade|search|show|list> [pkg...]"]
6
+ */
7
+ export declare const aptCommand: ShellModule;
8
+ export declare const aptCacheCommand: ShellModule;
9
+ //# sourceMappingURL=apt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apt.d.ts","sourceRoot":"","sources":["../../src/commands/apt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD;;;;GAIG;AACH,eAAO,MAAM,UAAU,EAAE,WAyJxB,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,WA+D7B,CAAC"}
@@ -0,0 +1,205 @@
1
+ import { ifFlag } from "./command-helpers";
2
+ import { getPackageManager } from "./helpers";
3
+ /**
4
+ * APT package manager front-end (simulated).
5
+ * @category package
6
+ * @params ["<install|remove|update|upgrade|search|show|list> [pkg...]"]
7
+ */
8
+ export const aptCommand = {
9
+ name: "apt",
10
+ aliases: ["apt-get"],
11
+ description: "Package manager",
12
+ category: "package",
13
+ params: ["<install|remove|update|upgrade|search|show|list> [pkg...]"],
14
+ run: ({ args, shell, authUser }) => {
15
+ const pm = getPackageManager(shell);
16
+ if (!pm)
17
+ return { stderr: "apt: package manager not initialised", exitCode: 1 };
18
+ const sub = args[0]?.toLowerCase();
19
+ const rest = args.slice(1);
20
+ const quiet = ifFlag(rest, ["-q", "--quiet", "-qq"]);
21
+ const purge = ifFlag(rest, ["--purge"]);
22
+ const pkgs = rest.filter((a) => !a.startsWith("-"));
23
+ // Non-root check
24
+ const restricted = ["install", "remove", "purge", "upgrade", "update"];
25
+ if (restricted.includes(sub ?? "") && authUser !== "root") {
26
+ return {
27
+ stderr: "E: Could not open lock file /var/lib/dpkg/lock-frontend - open (13: Permission denied)\nE: Unable to acquire the dpkg frontend lock, are you root?",
28
+ exitCode: 100,
29
+ };
30
+ }
31
+ switch (sub) {
32
+ case "install": {
33
+ if (pkgs.length === 0)
34
+ return { stderr: "apt: no packages specified", exitCode: 1 };
35
+ const { output, exitCode } = pm.install(pkgs, { quiet });
36
+ return { stdout: output || undefined, exitCode };
37
+ }
38
+ case "remove":
39
+ case "purge": {
40
+ if (pkgs.length === 0)
41
+ return { stderr: "apt: no packages specified", exitCode: 1 };
42
+ const { output, exitCode } = pm.remove(pkgs, {
43
+ purge: sub === "purge" || purge,
44
+ quiet,
45
+ });
46
+ return { stdout: output || undefined, exitCode };
47
+ }
48
+ case "update": {
49
+ return {
50
+ stdout: [
51
+ "Hit:1 fortune://packages.fortune.local aurora InRelease",
52
+ "Hit:2 fortune://security.fortune.local aurora-security InRelease",
53
+ "Reading package lists... Done",
54
+ "Building dependency tree... Done",
55
+ "Reading state information... Done",
56
+ `All packages are up to date.`,
57
+ ].join("\n"),
58
+ exitCode: 0,
59
+ };
60
+ }
61
+ case "upgrade": {
62
+ return {
63
+ stdout: [
64
+ "Reading package lists... Done",
65
+ "Building dependency tree... Done",
66
+ "Reading state information... Done",
67
+ "Calculating upgrade... Done",
68
+ "0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.",
69
+ ].join("\n"),
70
+ exitCode: 0,
71
+ };
72
+ }
73
+ case "search": {
74
+ const term = pkgs[0];
75
+ if (!term)
76
+ return { stderr: "apt: search requires a term", exitCode: 1 };
77
+ const results = pm.search(term);
78
+ if (results.length === 0)
79
+ return {
80
+ stdout: `Sorting... Done\nFull Text Search... Done\n(no results)`,
81
+ exitCode: 0,
82
+ };
83
+ const lines = results.map((p) => `${p.name}/${p.section ?? "misc"} ${p.version} amd64\n ${p.shortDesc ?? p.description}`);
84
+ return {
85
+ stdout: `Sorting... Done\nFull Text Search... Done\n${lines.join("\n")}`,
86
+ exitCode: 0,
87
+ };
88
+ }
89
+ case "show": {
90
+ const name = pkgs[0];
91
+ if (!name)
92
+ return { stderr: "apt: show requires a package name", exitCode: 1 };
93
+ const info = pm.show(name);
94
+ if (!info)
95
+ return {
96
+ stderr: `N: Unable to locate package ${name}`,
97
+ exitCode: 100,
98
+ };
99
+ return { stdout: info, exitCode: 0 };
100
+ }
101
+ case "list": {
102
+ const installedFlag = ifFlag(rest, ["--installed"]);
103
+ if (installedFlag) {
104
+ const pkgList = pm.listInstalled();
105
+ if (pkgList.length === 0)
106
+ return {
107
+ stdout: "Listing... Done\n(no packages installed)",
108
+ exitCode: 0,
109
+ };
110
+ const lines = pkgList.map((p) => `${p.name}/${p.section} ${p.version} ${p.architecture} [installed]`);
111
+ return {
112
+ stdout: `Listing... Done\n${lines.join("\n")}`,
113
+ exitCode: 0,
114
+ };
115
+ }
116
+ // all available
117
+ const all = pm.listAvailable();
118
+ const lines = all.map((p) => `${p.name}/${p.section ?? "misc"} ${p.version} amd64`);
119
+ return { stdout: `Listing... Done\n${lines.join("\n")}`, exitCode: 0 };
120
+ }
121
+ default: {
122
+ return {
123
+ stdout: [
124
+ "Usage: apt [options] command",
125
+ "",
126
+ "Commands:",
127
+ " install <pkg...> Install packages",
128
+ " remove <pkg...> Remove packages",
129
+ " purge <pkg...> Remove packages and config files",
130
+ " update Refresh package index",
131
+ " upgrade Upgrade all packages",
132
+ " search <term> Search in package descriptions",
133
+ " show <pkg> Show package details",
134
+ " list [--installed] List packages",
135
+ ].join("\n"),
136
+ exitCode: 0,
137
+ };
138
+ }
139
+ }
140
+ },
141
+ };
142
+ export const aptCacheCommand = {
143
+ name: "apt-cache",
144
+ description: "Query the package cache",
145
+ category: "package",
146
+ params: ["<search|show|policy> [pkg]"],
147
+ run: ({ args, shell }) => {
148
+ const pm = getPackageManager(shell);
149
+ if (!pm)
150
+ return {
151
+ stderr: "apt-cache: package manager not initialised",
152
+ exitCode: 1,
153
+ };
154
+ const sub = args[0]?.toLowerCase();
155
+ const pkgName = args[1];
156
+ switch (sub) {
157
+ case "search": {
158
+ if (!pkgName)
159
+ return { stderr: "Need a search term", exitCode: 1 };
160
+ const results = pm.search(pkgName);
161
+ return {
162
+ stdout: results
163
+ .map((p) => `${p.name} - ${p.shortDesc ?? p.description}`)
164
+ .join("\n") || "(no results)",
165
+ exitCode: 0,
166
+ };
167
+ }
168
+ case "show": {
169
+ if (!pkgName)
170
+ return { stderr: "Need a package name", exitCode: 1 };
171
+ const info = pm.show(pkgName);
172
+ return info
173
+ ? { stdout: info, exitCode: 0 }
174
+ : { stderr: `N: Unable to locate package ${pkgName}`, exitCode: 100 };
175
+ }
176
+ case "policy": {
177
+ if (!pkgName)
178
+ return { stderr: "Need a package name", exitCode: 1 };
179
+ const def = pm.findInRegistry(pkgName);
180
+ if (!def)
181
+ return {
182
+ stderr: `N: Unable to locate package ${pkgName}`,
183
+ exitCode: 100,
184
+ };
185
+ const inst = pm.isInstalled(pkgName);
186
+ return {
187
+ stdout: [
188
+ `${pkgName}:`,
189
+ ` Installed: ${inst ? def.version : "(none)"}`,
190
+ ` Candidate: ${def.version}`,
191
+ ` Version table:`,
192
+ ` ${def.version} 500`,
193
+ ` 500 fortune://packages.fortune.local aurora/main amd64 Packages`,
194
+ ].join("\n"),
195
+ exitCode: 0,
196
+ };
197
+ }
198
+ default:
199
+ return {
200
+ stderr: `apt-cache: unknown command '${sub ?? ""}'`,
201
+ exitCode: 1,
202
+ };
203
+ }
204
+ },
205
+ };
@@ -1,3 +1,14 @@
1
1
  import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * Minimal `awk`-like pattern scanner (supports simple print patterns).
4
+ * @category text
5
+ * @params ["[-F <sep>] '<program>' [file]"]
6
+ *
7
+ * Supported program patterns:
8
+ * - `print $N` (e.g. `print $1`, `print $2, $3`, `print $0`)
9
+ * - `{print $N}` (e.g. `{print $1}`, `{print $2, $3}`, `{print $0}`)
10
+ *
11
+ * The field separator can be set with `-F` (default is space, which splits on any whitespace).
12
+ */
2
13
  export declare const awkCommand: ShellModule;
3
14
  //# sourceMappingURL=awk.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"awk.d.ts","sourceRoot":"","sources":["../../src/commands/awk.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,UAAU,EAAE,WA0BxB,CAAC"}
1
+ {"version":3,"file":"awk.d.ts","sourceRoot":"","sources":["../../src/commands/awk.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,UAAU,EAAE,WA6BxB,CAAC"}
@@ -1,4 +1,15 @@
1
1
  import { getFlag } from "./command-helpers";
2
+ /**
3
+ * Minimal `awk`-like pattern scanner (supports simple print patterns).
4
+ * @category text
5
+ * @params ["[-F <sep>] '<program>' [file]"]
6
+ *
7
+ * Supported program patterns:
8
+ * - `print $N` (e.g. `print $1`, `print $2, $3`, `print $0`)
9
+ * - `{print $N}` (e.g. `{print $1}`, `{print $2, $3}`, `{print $0}`)
10
+ *
11
+ * The field separator can be set with `-F` (default is space, which splits on any whitespace).
12
+ */
2
13
  export const awkCommand = {
3
14
  name: "awk",
4
15
  description: "Pattern scanning and processing language (minimal)",
@@ -17,12 +28,14 @@ export const awkCommand = {
17
28
  const lines = (stdin ?? "").split("\n").filter(Boolean);
18
29
  const out = lines.map((line) => {
19
30
  const parts = line.split(sep === " " ? /\s+/ : sep);
20
- return fields.map((f) => {
31
+ return fields
32
+ .map((f) => {
21
33
  if (f === "$0")
22
34
  return line;
23
35
  const n = parseInt(f.replace("$", ""), 10);
24
36
  return Number.isNaN(n) ? f.replace(/"/g, "") : (parts[n - 1] ?? "");
25
- }).join(sep === " " ? "\t" : sep);
37
+ })
38
+ .join(sep === " " ? "\t" : sep);
26
39
  });
27
40
  return { stdout: out.join("\n"), exitCode: 0 };
28
41
  },
@@ -1,3 +1,8 @@
1
1
  import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * Encode or decode base64 data.
4
+ * @category text
5
+ * @params ["[-d] [file]"]
6
+ */
2
7
  export declare const base64Command: ShellModule;
3
8
  //# sourceMappingURL=base64.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"base64.d.ts","sourceRoot":"","sources":["../../src/commands/base64.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,aAAa,EAAE,WAc3B,CAAC"}
1
+ {"version":3,"file":"base64.d.ts","sourceRoot":"","sources":["../../src/commands/base64.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,WAoB3B,CAAC"}
@@ -1,4 +1,9 @@
1
1
  import { ifFlag } from "./command-helpers";
2
+ /**
3
+ * Encode or decode base64 data.
4
+ * @category text
5
+ * @params ["[-d] [file]"]
6
+ */
2
7
  export const base64Command = {
3
8
  name: "base64",
4
9
  description: "Encode/decode base64",
@@ -9,7 +14,10 @@ export const base64Command = {
9
14
  const input = stdin ?? "";
10
15
  if (decode) {
11
16
  try {
12
- return { stdout: Buffer.from(input.trim(), "base64").toString("utf8"), exitCode: 0 };
17
+ return {
18
+ stdout: Buffer.from(input.trim(), "base64").toString("utf8"),
19
+ exitCode: 0,
20
+ };
13
21
  }
14
22
  catch {
15
23
  return { stderr: "base64: invalid input", exitCode: 1 };
@@ -1,3 +1,8 @@
1
1
  import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * Concatenate and print files to stdout.
4
+ * @category files
5
+ * @params ["[-n] [-b] <file...>"]
6
+ */
2
7
  export declare const catCommand: ShellModule;
3
8
  //# sourceMappingURL=cat.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cat.d.ts","sourceRoot":"","sources":["../../src/commands/cat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,UAAU,EAAE,WAexB,CAAC"}
1
+ {"version":3,"file":"cat.d.ts","sourceRoot":"","sources":["../../src/commands/cat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD;;;;GAIG;AACH,eAAO,MAAM,UAAU,EAAE,WA0CxB,CAAC"}
@@ -1,17 +1,44 @@
1
- import { getArg } from "./command-helpers";
1
+ import { ifFlag } from "./command-helpers";
2
2
  import { assertPathAccess, resolveReadablePath } from "./helpers";
3
+ /**
4
+ * Concatenate and print files to stdout.
5
+ * @category files
6
+ * @params ["[-n] [-b] <file...>"]
7
+ */
3
8
  export const catCommand = {
4
9
  name: "cat",
5
10
  description: "Concatenate and print files",
6
11
  category: "files",
7
- params: ["<file>"],
8
- run: ({ authUser, shell, cwd, args }) => {
9
- const fileArg = getArg(args, 0);
10
- if (!fileArg) {
12
+ params: ["[-n] [-b] <file...>"],
13
+ run: ({ authUser, shell, cwd, args, stdin }) => {
14
+ const numberAll = ifFlag(args, ["-n", "--number"]);
15
+ const numberNonBlank = ifFlag(args, ["-b", "--number-nonblank"]);
16
+ const fileArgs = args.filter((a) => !a.startsWith("-"));
17
+ if (fileArgs.length === 0 && stdin !== undefined) {
18
+ return { stdout: stdin, exitCode: 0 };
19
+ }
20
+ if (fileArgs.length === 0) {
11
21
  return { stderr: "cat: missing file operand", exitCode: 1 };
12
22
  }
13
- const target = resolveReadablePath(shell.vfs, cwd, fileArg);
14
- assertPathAccess(authUser, target, "cat");
15
- return { stdout: shell.vfs.readFile(target), exitCode: 0 };
23
+ const parts = [];
24
+ for (const fileArg of fileArgs) {
25
+ const target = resolveReadablePath(shell.vfs, cwd, fileArg);
26
+ assertPathAccess(authUser, target, "cat");
27
+ parts.push(shell.vfs.readFile(target));
28
+ }
29
+ const combined = parts.join("");
30
+ if (!numberAll && !numberNonBlank) {
31
+ return { stdout: combined, exitCode: 0 };
32
+ }
33
+ let lineNum = 1;
34
+ const numbered = combined
35
+ .split("\n")
36
+ .map((line) => {
37
+ if (numberNonBlank && line.trim() === "")
38
+ return line;
39
+ return `${String(lineNum++).padStart(6)}\t${line}`;
40
+ })
41
+ .join("\n");
42
+ return { stdout: numbered, exitCode: 0 };
16
43
  },
17
44
  };
@@ -1,3 +1,8 @@
1
1
  import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * Change current working directory.
4
+ * @category navigation
5
+ * @params ["[path]"]
6
+ */
2
7
  export declare const cdCommand: ShellModule;
3
8
  //# sourceMappingURL=cd.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cd.d.ts","sourceRoot":"","sources":["../../src/commands/cd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,SAAS,EAAE,WAmBvB,CAAC"}
1
+ {"version":3,"file":"cd.d.ts","sourceRoot":"","sources":["../../src/commands/cd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD;;;;GAIG;AACH,eAAO,MAAM,SAAS,EAAE,WAmBvB,CAAC"}
@@ -1,4 +1,9 @@
1
1
  import { assertPathAccess, resolvePath } from "./helpers";
2
+ /**
3
+ * Change current working directory.
4
+ * @category navigation
5
+ * @params ["[path]"]
6
+ */
2
7
  export const cdCommand = {
3
8
  name: "cd",
4
9
  description: "Change directory",
@@ -1,3 +1,8 @@
1
1
  import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * Change file permissions (octal or symbolic).
4
+ * @category files
5
+ * @params ["<mode> <file>"]
6
+ */
2
7
  export declare const chmodCommand: ShellModule;
3
8
  //# sourceMappingURL=chmod.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"chmod.d.ts","sourceRoot":"","sources":["../../src/commands/chmod.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,YAAY,EAAE,WA+B1B,CAAC"}
1
+ {"version":3,"file":"chmod.d.ts","sourceRoot":"","sources":["../../src/commands/chmod.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAuCrD;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,WAwC1B,CAAC"}
@@ -1,4 +1,48 @@
1
1
  import { assertPathAccess, resolvePath } from "./helpers";
2
+ /**
3
+ * Parse a symbolic chmod mode string (e.g. "+x", "u+x", "go-w", "a+rx")
4
+ * and apply it to the existing mode bits.
5
+ * Returns null if the string is not a valid symbolic mode.
6
+ */
7
+ function applySymbolicMode(existing, modeStr) {
8
+ const pattern = /^([ugoa]*)([+\-=])([rwx]*)$/;
9
+ const parts = modeStr.split(",");
10
+ let mode = existing;
11
+ for (const part of parts) {
12
+ const m = part.trim().match(pattern);
13
+ if (!m)
14
+ return null;
15
+ const [, who = "a", op, perms = ""] = m;
16
+ const targets = who === "" || who === "a" ? ["u", "g", "o"] : who.split("");
17
+ const bits = {
18
+ u: { r: 0o400, w: 0o200, x: 0o100 },
19
+ g: { r: 0o040, w: 0o020, x: 0o010 },
20
+ o: { r: 0o004, w: 0o002, x: 0o001 },
21
+ };
22
+ for (const t of targets) {
23
+ for (const p of perms.split("")) {
24
+ const bit = bits[t]?.[p];
25
+ if (bit === undefined)
26
+ continue;
27
+ if (op === "+")
28
+ mode |= bit;
29
+ else if (op === "-")
30
+ mode &= ~bit;
31
+ else if (op === "=") {
32
+ // clear all bits for this target, then set requested
33
+ const mask = Object.values(bits[t] ?? {}).reduce((a, b) => a | b, 0);
34
+ mode = (mode & ~mask) | bit;
35
+ }
36
+ }
37
+ }
38
+ }
39
+ return mode;
40
+ }
41
+ /**
42
+ * Change file permissions (octal or symbolic).
43
+ * @category files
44
+ * @params ["<mode> <file>"]
45
+ */
2
46
  export const chmodCommand = {
3
47
  name: "chmod",
4
48
  description: "Change file permissions",
@@ -18,9 +62,19 @@ export const chmodCommand = {
18
62
  exitCode: 1,
19
63
  };
20
64
  }
21
- const mode = parseInt(modeArg, 8);
22
- if (Number.isNaN(mode)) {
23
- return { stderr: `chmod: invalid mode: ${modeArg}`, exitCode: 1 };
65
+ let mode;
66
+ const octal = parseInt(modeArg, 8);
67
+ if (!Number.isNaN(octal) && /^[0-7]+$/.test(modeArg)) {
68
+ mode = octal;
69
+ }
70
+ else {
71
+ // symbolic mode
72
+ const existing = shell.vfs.stat(filePath).mode;
73
+ const result = applySymbolicMode(existing, modeArg);
74
+ if (result === null) {
75
+ return { stderr: `chmod: invalid mode: ${modeArg}`, exitCode: 1 };
76
+ }
77
+ mode = result;
24
78
  }
25
79
  shell.vfs.chmod(filePath, mode);
26
80
  return { exitCode: 0 };